From 57ba182e81bbed4e500b2049d9a98d2dd30a9b3f Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Fri, 5 Jul 2024 11:30:12 +0200 Subject: [PATCH 001/112] Remove non standard header findings and add deprecated headers findings (#3127) Co-authored-by: Jan Klopper Co-authored-by: ammar92 --- .../kat_finding_types.json | 7 +++ .../bits/missing_headers/missing_headers.py | 52 ++++++++----------- octopoes/tests/test_bit_missing_headers.py | 13 +++++ 3 files changed, 42 insertions(+), 30 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json index 102a0868ebe..ffe75f9f164 100644 --- a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json +++ b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json @@ -473,5 +473,12 @@ "risk": "medium", "impact": "Disallowed domains are domains that are for example 'world writable', this opens up the possibility for an atacker to host malicious files on a csp whitelisted domain.", "recommendation": "Remove the offending hostname from the CSP header." + }, + "KAT-NONSTANDARD-HEADERS": { + "description": "Headers are used that are nonstandard and should not be used anymore.", + "risk": "low", + "source": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers", + "impact": "Nonstandard headers may not be supported by all browsers and may not provide the security that is expected.", + "recommendation": "Remove the nonstandard headers from the response." } } diff --git a/octopoes/bits/missing_headers/missing_headers.py b/octopoes/bits/missing_headers/missing_headers.py index bb8c6575baf..07fe4dcf360 100644 --- a/octopoes/bits/missing_headers/missing_headers.py +++ b/octopoes/bits/missing_headers/missing_headers.py @@ -5,6 +5,16 @@ from octopoes.models.ooi.findings import Finding, KATFindingType from octopoes.models.ooi.web import HTTPHeader, HTTPResource +DEPRECATED_HEADER = { + "x-forwarded-host", + "x-forwarded-proto", + "x-dns-prefetch-control", + "x-forwarded-for", + "x-robots-tag", + "pragma", + "warning", +} + XSS_CAPABLE_TYPES = [ "text/html", "application/xhtml+xml", @@ -50,26 +60,6 @@ def run(resource: HTTPResource, additional_oois: list[HTTPHeader], config: dict[ yield ft yield finding - if "x-permitted-cross-domain-policies" not in header_keys: - ft = KATFindingType(id="KAT-NO-X-PERMITTED-CROSS-DOMAIN-POLICIES") - finding = Finding( - finding_type=ft.reference, - ooi=resource.reference, - description="Header x-permitted-cross-domain-policies is missing or not configured correctly.", - ) - yield ft - yield finding - - if "x-xss-protection" not in header_keys: - ft = KATFindingType(id="KAT-NO-EXPLICIT-XSS-PROTECTION") - finding = Finding( - finding_type=ft.reference, - ooi=resource.reference, - description="Header x-xss-protection is missing or not configured correctly.", - ) - yield ft - yield finding - if "x-frame-options" not in header_keys: ft = KATFindingType(id="KAT-NO-X-FRAME-OPTIONS") finding = Finding( @@ -80,16 +70,6 @@ def run(resource: HTTPResource, additional_oois: list[HTTPHeader], config: dict[ yield ft yield finding - if "x-dns-prefetch-control" not in header_keys: - ft = KATFindingType(id="KAT-NO-X-DNS-PREFETCH-CONTROL") - finding = Finding( - finding_type=ft.reference, - ooi=resource.reference, - description="Header x-dns-prefetch-control is missing or not configured correctly.", - ) - yield ft - yield finding - if "permissions-policy" not in header_keys: ft = KATFindingType(id="KAT-NO-PERMISSIONS-POLICY") finding = Finding( @@ -119,3 +99,15 @@ def run(resource: HTTPResource, additional_oois: list[HTTPHeader], config: dict[ ) yield ft yield finding + + deprecated_headers = set(header_keys) & DEPRECATED_HEADER + if deprecated_headers: + ft = KATFindingType(id="KAT-NONSTANDARD-HEADERS") + finding = Finding( + finding_type=ft.reference, + ooi=resource.reference, + description=f"Nonstandard headers are used. Avoid using the following headers: " + f"{' '.join(deprecated_headers)}", + ) + yield ft + yield finding diff --git a/octopoes/tests/test_bit_missing_headers.py b/octopoes/tests/test_bit_missing_headers.py index e09bc1ee3df..0c4a0517168 100644 --- a/octopoes/tests/test_bit_missing_headers.py +++ b/octopoes/tests/test_bit_missing_headers.py @@ -39,3 +39,16 @@ def test_http_no_hsts(http_resource_http): hsts_findings = [r for r in results if r.object_type == "Finding" and r.finding_type.natural_key == "KAT-NO-HSTS"] assert not hsts_findings + + +def test_deprecated_header(http_resource_https): + headers = [ + HTTPHeader(resource=http_resource_https.reference, key="x-forwarded-for", value="DENY"), + ] + + results = list(run(http_resource_https, headers, {})) + deprecated_headers_findings = [ + r for r in results if r.object_type == "Finding" and r.finding_type.natural_key == "KAT-NONSTANDARD-HEADERS" + ] + + assert len(deprecated_headers_findings) == 1 From 2bbc4c46aadfef7aba502ee053461c3ce9eca3df Mon Sep 17 00:00:00 2001 From: Jeroen Dekkers Date: Mon, 8 Jul 2024 10:00:30 +0200 Subject: [PATCH 002/112] Update 1.16 release notes (#3195) Co-authored-by: Jan Klopper --- docs/source/release_notes/1.16.rst | 73 +++++++++++++++++------------ docs/source/release_notes/index.rst | 1 + 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/docs/source/release_notes/1.16.rst b/docs/source/release_notes/1.16.rst index 49931f5cb38..8cd8c69d472 100644 --- a/docs/source/release_notes/1.16.rst +++ b/docs/source/release_notes/1.16.rst @@ -1,54 +1,65 @@ ============================================ -[DRAFT for: v1.15.1...67f18e3] OpenKAT 1.16 +OpenKAT 1.16 ============================================ -This release includes some big optimizations in the new reporting functionality -that was introduced in 1.14. Measurements show that generating a report on 100 -objects is approximately 20 times faster. The reports in general also got a lot -of improvements and bugfixes. +This release adds saving of reports. When completing the reporting workflow the +report will be saved and can be viewed later. This is a big step towards being +able to schedule automatically generated reports. The reporting also has had a +lot of improvements and fixes. + +Support for running custom OCI images using only a boefje definition +(boefje.json) has been added. This has been applied to nmap and dnssec boefjes. +The boefje.json still needs live in the OpenKAT code directory in this release, +but this is a big step towards being able to add custom boefjes. New Features ============ -* Add xtdb-cli tool to Octopoes -* Update several plugins: Wappalizer, dns-records, ssl-certificates, pdio_subfinder and remove the many-ports-open boefje/normalizer -* Add backup scripts -* Introduce importing/exporting capabilities in xtdb-multinode-tool +* Add xtdb-cli tool to Octopoes. This can be used to easily interact with XTDB + and doing importing/exporting. +* The onboarding workflow uses the new reporting system. +* Add a warning to the CSP validator for 'self' on script-src directives. Ignore + missing CSP if the page is not XSS capable. +* Add bit that checks for disallowed domains in the CSP header. +* Update several plugins: Wappalizer, dns-records, ssl-certificates, pdio_subfinder, nuclei +* The many-ports-open boefje/normalizer has been removed. +* Backup scripts to backup container data when using the development setup. Thanks to @TobiasBDO for contributing the scripts. * More Octopoes Query support for complex path queries +* Optimize queries executed when running bits * Introduce support for running custom built OCI images using only a boefje definition (boefje.json), applied to nmap. -* Improvements of the design, plugin overview and Report titles. -* Improvements of several Reports in terms of performance, styling, OOI selection and configuration. -* More documentation on: Reports, the new OCI image functionality and architecture, IPv6 support in Docker and Octopoes Models. +* Improvements of several reports in terms of performance, styling, OOI selection and configuration. +* Improved documentation about reports, the new OCI image functionality and architecture, IPv6 support in Docker and Octopoes models. +* Added documentation on how to make a boefje, normalizer, model, bit and report with examples. Thanks to @Souf149 for contributing some of these improvements. +* Frysk has been added to the selectable list of languages. Over 30% of OpenKAT has been translated due to the amazing and hard work of `Wim Benes `_. Tige tank! Bug fixes ========= -* Fix OOI Add/Edit form -* Fix version handling when no version is present. -* Fix aggregate plugin overview table -* Fix task api status code response for malformed id in the scheduler -* Fix select all OOIs -* Fix openssl boefje being stuck on port 80 -* Fix pdf alignment -* Fix critical vulnerability counter -* Fix in System Specific Reports -* fix schema errors on empty / missing schemas -* Fix improve error handling -* Fix missing cipher csv in Debian package -* Fix Update nuclei -* Fix and improve running boefjes/normalizer -* Fix the KATalogus plugin API limit +* Fix OOI add/edit form +* Fix version handling when no version is present in wappalyzer normalizer. +* Error handling has been improved in a lot of places. +* Fixed schema errors when plugin schema is empty or missing. +* Fix and improve manually running a boefjes/normalizer. +* The KATalogus plugin API doesn't have a hardcoded limit anymore. +* Missing titles in FastAPI API's have been added. +* Added workaround for broken links to OOIs in the normalizer task list. +* Fix Snyk boefje creating empty CVE ids. Upgrading ========= -It is no longer needed to seed the KATalogus database using `python -m boefjes.seed` on upgrades. -This is because v1.16.0 phases out the `repository` database model in the KATalogus. -The migration could potentially not be backward compatible for each install, -So please read the following carefully before triggering an upgrade. +It is no longer needed to seed the KATalogus database using `python -m +boefjes.seed` on installation or upgrades. This is because v1.16.0 phases out +the `repository` database model in the KATalogus. The migration could +potentially not be backward compatible for each install, so please read the +following carefully before triggering an upgrade. + +All bits all need to be rerun because of model changes. This can be done on the +organization settings page. Checking the KATalogus Migration ================================ + If you are using OpenKAT as a regular user and never called APIs or tweaked the database manually, you can move forward with the normal instructions of upgrading :ref:`Debian packages` or upgrading :ref:`containers `. diff --git a/docs/source/release_notes/index.rst b/docs/source/release_notes/index.rst index 1d51022e0a0..7dfe0b237a8 100644 --- a/docs/source/release_notes/index.rst +++ b/docs/source/release_notes/index.rst @@ -5,6 +5,7 @@ Release notes :maxdepth: 1 :caption: Releases + 1.16 1.15 1.14 1.13 From 7c68d0a5a8ea6eb4417116f7255c1abce3223667 Mon Sep 17 00:00:00 2001 From: Jan Klopper Date: Mon, 8 Jul 2024 10:18:59 +0200 Subject: [PATCH 003/112] Better default list of world writable domains in CSP checker (#3165) Co-authored-by: noamblitz <43830693+noamblitz@users.noreply.github.com> Co-authored-by: ammar92 Co-authored-by: Jeroen Dekkers --- octopoes/bits/ask_disallowed_domains/question_schema.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/octopoes/bits/ask_disallowed_domains/question_schema.json b/octopoes/bits/ask_disallowed_domains/question_schema.json index 523538f53bd..ab7d43d544f 100644 --- a/octopoes/bits/ask_disallowed_domains/question_schema.json +++ b/octopoes/bits/ask_disallowed_domains/question_schema.json @@ -3,14 +3,13 @@ "$id": "/bit/disallowed-csp-hostnames", "type": "object", "default": {}, - "Port Configuration": "Root Schema", "required": [], "properties": { "disallowed_hostnames": { "description": "Comma separated list of disallowed hostnames in CSP headers", "type": "string", "pattern": "^(\\s*(,*)[^,]+,?\\s*)*$", - "default": "github.com,google.com" + "default": "githubpages.com,github.io,jsdelivr.com,cdn.skypack.dev" }, "disallow_url_shorteners": { "description": "Do you want to disallow url shorteners in csp headers?", From fd23a56ad5844a2836cc265b87174a33a94f4c07 Mon Sep 17 00:00:00 2001 From: Jan Klopper Date: Mon, 8 Jul 2024 13:26:33 +0200 Subject: [PATCH 004/112] Update Dockerfile, fix Sonarcloud issue (#3180) --- boefjes/Dockerfile | 4 ++-- bytes/Dockerfile | 4 ++-- keiko/Dockerfile | 4 ++-- mula/Dockerfile | 4 ++-- octopoes/Dockerfile | 4 ++-- rocky/Dockerfile | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/boefjes/Dockerfile b/boefjes/Dockerfile index c0a75319776..86c2df85133 100644 --- a/boefjes/Dockerfile +++ b/boefjes/Dockerfile @@ -6,8 +6,8 @@ ARG USER_GID=1000 ENTRYPOINT ["/app/boefjes/entrypoint.sh"] -RUN groupadd --gid $USER_GID nonroot -RUN adduser --disabled-password --gecos '' --uid $USER_UID --gid $USER_GID nonroot +RUN groupadd --gid "$USER_GID" nonroot +RUN adduser --disabled-password --gecos '' --uid "$USER_UID" --gid "$USER_GID" nonroot WORKDIR /app/boefjes ENV PATH=/home/nonroot/.local/bin:${PATH} diff --git a/bytes/Dockerfile b/bytes/Dockerfile index cca6359d97d..7b159a92a62 100644 --- a/bytes/Dockerfile +++ b/bytes/Dockerfile @@ -8,8 +8,8 @@ ARG USER_GID=1000 ENTRYPOINT ["/app/bytes/entrypoint.sh"] -RUN groupadd --gid $USER_GID bytes -RUN adduser --disabled-password --gecos '' --uid $USER_UID --gid $USER_GID bytes +RUN groupadd --gid "$USER_GID" bytes +RUN adduser --disabled-password --gecos '' --uid "$USER_UID" --gid "$USER_GID" bytes WORKDIR /app/bytes ENV PATH=/home/bytes/.local/bin:${PATH} diff --git a/keiko/Dockerfile b/keiko/Dockerfile index 71ecbee6634..865cfcb3efe 100644 --- a/keiko/Dockerfile +++ b/keiko/Dockerfile @@ -6,8 +6,8 @@ EXPOSE 8000 ARG USER_UID=1000 ARG USER_GID=1000 -RUN groupadd --gid $USER_GID keiko -RUN adduser --disabled-password --gecos '' --uid $USER_UID --gid $USER_GID keiko +RUN groupadd --gid "$USER_GID" keiko +RUN adduser --disabled-password --gecos '' --uid "$USER_UID" --gid "$USER_GID" keiko WORKDIR /app/keiko ENV PATH=/home/keiko/.local/bin:${PATH} diff --git a/mula/Dockerfile b/mula/Dockerfile index 19c314b8200..4ac6ed198ca 100644 --- a/mula/Dockerfile +++ b/mula/Dockerfile @@ -8,8 +8,8 @@ ARG USER_GID=1000 ENTRYPOINT ["/app/scheduler/entrypoint.sh"] -RUN groupadd --gid $USER_GID scheduler -RUN adduser --disabled-password --gecos '' --uid $USER_UID --gid $USER_GID scheduler +RUN groupadd --gid "$USER_GID" scheduler +RUN adduser --disabled-password --gecos '' --uid "$USER_UID" --gid "$USER_GID" scheduler WORKDIR /app/scheduler ENV PATH=/home/scheduler/.local/bin:${PATH} diff --git a/octopoes/Dockerfile b/octopoes/Dockerfile index 4e3afc00791..0eee18583a9 100644 --- a/octopoes/Dockerfile +++ b/octopoes/Dockerfile @@ -10,8 +10,8 @@ WORKDIR /app/octopoes ENTRYPOINT ["/app/octopoes/entrypoint.sh"] -RUN groupadd --gid $USER_GID octopoes -RUN adduser --disabled-password --gecos '' --uid $USER_UID --gid $USER_GID octopoes +RUN groupadd --gid "$USER_GID" octopoes +RUN adduser --disabled-password --gecos '' --uid "$USER_UID" --gid "$USER_GID" octopoes ENV PATH=/home/octopoes/.local/bin:${PATH} diff --git a/rocky/Dockerfile b/rocky/Dockerfile index c16bf4593d7..093e020652e 100644 --- a/rocky/Dockerfile +++ b/rocky/Dockerfile @@ -19,8 +19,8 @@ ARG USER_GID=1000 ENTRYPOINT ["/app/rocky/entrypoint.sh"] -RUN groupadd --gid $USER_GID rocky -RUN adduser --disabled-password --gecos '' --uid $USER_UID --gid $USER_GID rocky +RUN groupadd --gid "$USER_GID" rocky +RUN adduser --disabled-password --gecos '' --uid "$USER_UID" --gid "$USER_GID" rocky WORKDIR /app/rocky From 106f86ee7486794894b2431406b37d268706404b Mon Sep 17 00:00:00 2001 From: Jeroen Dekkers Date: Mon, 8 Jul 2024 20:41:32 +0200 Subject: [PATCH 005/112] Update to Django 5.0 (#2939) --- .pre-commit-config.yaml | 2 +- rocky/poetry.lock | 15 +++++++-------- rocky/pyproject.toml | 2 +- rocky/requirements-dev.txt | 7 +++---- rocky/requirements.txt | 6 +++--- rocky/rocky/locale/django.pot | 10 +++++++++- rocky/rocky/settings.py | 2 ++ rocky/rocky/templates/admin/base.html | 10 +++++----- rocky/rocky/templates/admin/change_list.html | 12 +++++++++--- rocky/rocky/views/ooi_list.py | 6 +++--- rocky/rocky/views/ooi_report.py | 3 +-- rocky/rocky/views/organization_member_list.py | 4 ++-- 12 files changed, 46 insertions(+), 33 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 77f9b918082..447290ba06c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -76,7 +76,7 @@ repos: rev: 1.16.0 hooks: - id: django-upgrade - args: [--target-version, "4.2"] + args: [--target-version, "5.0"] - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.9.0 diff --git a/rocky/poetry.lock b/rocky/poetry.lock index 9f16ad18d20..9846b49b802 100644 --- a/rocky/poetry.lock +++ b/rocky/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "annotated-types" @@ -452,17 +452,17 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] name = "django" -version = "4.2.11" +version = "5.0.6" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "Django-4.2.11-py3-none-any.whl", hash = "sha256:ddc24a0a8280a0430baa37aff11f28574720af05888c62b7cfe71d219f4599d3"}, - {file = "Django-4.2.11.tar.gz", hash = "sha256:6e6ff3db2d8dd0c986b4eec8554c8e4f919b5c1ff62a5b4390c17aff2ed6e5c4"}, + {file = "Django-5.0.6-py3-none-any.whl", hash = "sha256:8363ac062bb4ef7c3f12d078f6fa5d154031d129a15170a1066412af49d30905"}, + {file = "Django-5.0.6.tar.gz", hash = "sha256:ff1b61005004e476e0aeea47c7f79b85864c70124030e95146315396f1e7951f"}, ] [package.dependencies] -asgiref = ">=3.6.0,<4" +asgiref = ">=3.7.0,<4" sqlparse = ">=0.3.1" tzdata = {version = "*", markers = "sys_platform == \"win32\""} @@ -2405,7 +2405,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3351,4 +3350,4 @@ test = ["pytest"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "45b14155e352fd530181532052623c77507cb11ae4596e4c59ba7658856ff3a1" +content-hash = "fd1f8a6cf8caf8216070cb5c9d8e0a2269de42f67011215e232431e262dc2153" diff --git a/rocky/pyproject.toml b/rocky/pyproject.toml index 261a4ad81ac..22a33030ba3 100644 --- a/rocky/pyproject.toml +++ b/rocky/pyproject.toml @@ -8,7 +8,7 @@ license = "EUPL" [tool.poetry.dependencies] python = "^3.10" beautifulsoup4 = "^4.11.2" -Django = "^4.2.11" +Django = "^5.0.6" django-two-factor-auth = "^1.14.0" django-environ = "^0.11.2" jsonschema = "^4.17.0" diff --git a/rocky/requirements-dev.txt b/rocky/requirements-dev.txt index 3b486b969db..aacc86a9fbf 100644 --- a/rocky/requirements-dev.txt +++ b/rocky/requirements-dev.txt @@ -284,9 +284,9 @@ django-two-factor-auth==1.16.0 ; python_version >= "3.10" and python_version < " django-weasyprint==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:605eba0dd3246c0410a60fdaa581139330ad6c637fc273e1bfe90a7a09f53728 \ --hash=sha256:7f554bcc428293aeadc175ab5607b4f3bf30c0e5da3d4aa34453b3d96e0ffd3a -django==4.2.11 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6e6ff3db2d8dd0c986b4eec8554c8e4f919b5c1ff62a5b4390c17aff2ed6e5c4 \ - --hash=sha256:ddc24a0a8280a0430baa37aff11f28574720af05888c62b7cfe71d219f4599d3 +django==5.0.6 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:8363ac062bb4ef7c3f12d078f6fa5d154031d129a15170a1066412af49d30905 \ + --hash=sha256:ff1b61005004e476e0aeea47c7f79b85864c70124030e95146315396f1e7951f djangorestframework==3.15.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20 \ --hash=sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad @@ -996,7 +996,6 @@ pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \ --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ - --hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \ --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \ --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \ diff --git a/rocky/requirements.txt b/rocky/requirements.txt index a27d020d69d..b24453047ab 100644 --- a/rocky/requirements.txt +++ b/rocky/requirements.txt @@ -225,9 +225,9 @@ django-two-factor-auth==1.16.0 ; python_version >= "3.10" and python_version < " django-weasyprint==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:605eba0dd3246c0410a60fdaa581139330ad6c637fc273e1bfe90a7a09f53728 \ --hash=sha256:7f554bcc428293aeadc175ab5607b4f3bf30c0e5da3d4aa34453b3d96e0ffd3a -django==4.2.11 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6e6ff3db2d8dd0c986b4eec8554c8e4f919b5c1ff62a5b4390c17aff2ed6e5c4 \ - --hash=sha256:ddc24a0a8280a0430baa37aff11f28574720af05888c62b7cfe71d219f4599d3 +django==5.0.6 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:8363ac062bb4ef7c3f12d078f6fa5d154031d129a15170a1066412af49d30905 \ + --hash=sha256:ff1b61005004e476e0aeea47c7f79b85864c70124030e95146315396f1e7951f djangorestframework==3.15.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20 \ --hash=sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index cf25faa9d45..ac2591623af 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-27 09:18+0000\n" +"POT-Creation-Date: 2024-07-08 15:27+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -4434,6 +4434,14 @@ msgid_plural "Please correct the errors below." msgstr[0] "" msgstr[1] "" +#: rocky/templates/admin/change_list.html +msgid "Hide counts" +msgstr "" + +#: rocky/templates/admin/change_list.html +msgid "Show counts" +msgstr "" + #: rocky/templates/admin/change_list.html msgid "Clear all filters" msgstr "" diff --git a/rocky/rocky/settings.py b/rocky/rocky/settings.py index b6a278ee9cd..b0298bdd4fd 100644 --- a/rocky/rocky/settings.py +++ b/rocky/rocky/settings.py @@ -463,3 +463,5 @@ def immutable_file_test(path, url): WEASYPRINT_BASEURL = env("WEASYPRINT_BASEURL", default="http://127.0.0.1:8000/") KNOX_TOKEN_MODEL = "account.AuthToken" + +FORMS_URLFIELD_ASSUME_HTTPS = True diff --git a/rocky/rocky/templates/admin/base.html b/rocky/rocky/templates/admin/base.html index 12f9bca1374..37b59d5f4d6 100644 --- a/rocky/rocky/templates/admin/base.html +++ b/rocky/rocky/templates/admin/base.html @@ -16,7 +16,7 @@ {% if LANGUAGE_BIDI %}{% endif %} {% block extrahead %}{% endblock %} {% block responsive %} - + {% if LANGUAGE_BIDI %}{% endif %} {% endblock %} @@ -32,7 +32,7 @@ {% if not is_popup %} {% block header %} - + {% endblock %} {% block nav-breadcrumbs %} @@ -87,7 +87,7 @@ {% include "admin/nav_sidebar.html" %} {% endblock %} {% endif %} -
+
{% block messages %} {% if messages %}
    {% for message in messages %} @@ -109,7 +109,7 @@
{% block footer %}{% endblock %} - + diff --git a/rocky/rocky/templates/admin/change_list.html b/rocky/rocky/templates/admin/change_list.html index 26860757a58..4b9b5e46dcd 100644 --- a/rocky/rocky/templates/admin/change_list.html +++ b/rocky/rocky/templates/admin/change_list.html @@ -75,9 +75,15 @@ {% if cl.has_filters %}

{% translate 'Filter' %}

- {% if cl.has_active_filters %}

- ✖ {% translate "Clear all filters" %} -

{% endif %} + {% if cl.is_facets_optional or cl.has_active_filters %}
+ {% if cl.is_facets_optional %}

+ {% if cl.add_facets %}{% translate "Hide counts" %} + {% else %}{% translate "Show counts" %}{% endif %} +

{% endif %} + {% if cl.has_active_filters %}

+ ✖ {% translate "Clear all filters" %} +

{% endif %} +
{% endif %} {% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
{% endif %} diff --git a/rocky/rocky/views/ooi_list.py b/rocky/rocky/views/ooi_list.py index 0c27d65fc7e..191eab8b2f4 100644 --- a/rocky/rocky/views/ooi_list.py +++ b/rocky/rocky/views/ooi_list.py @@ -97,7 +97,7 @@ def _set_scan_profiles( messages.ERROR, _("Could not raise clearance levels to L%s. Indemnification not present at organization %s.") % ( - level, + level.value, self.organization.name, ), ) @@ -112,7 +112,7 @@ def _set_scan_profiles( "Contact your administrator to receive a higher clearance." ) % ( - level, + level.value, self.organization_member.trusted_clearance_level, ), ) @@ -127,7 +127,7 @@ def _set_scan_profiles( "Please accept the clearance level below to proceed." ) % ( - level, + level.value, self.organization_member.acknowledged_clearance_level, ), ) diff --git a/rocky/rocky/views/ooi_report.py b/rocky/rocky/views/ooi_report.py index 9496d17bc76..3b2c6e98823 100644 --- a/rocky/rocky/views/ooi_report.py +++ b/rocky/rocky/views/ooi_report.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone from typing import Any from account.mixins import OrganizationView @@ -6,7 +6,6 @@ from django.http import FileResponse, HttpRequest, HttpResponse from django.shortcuts import redirect from django.urls import reverse -from django.utils import timezone from django.utils.translation import gettext_lazy as _ from katalogus.client import get_katalogus from tools.forms.ooi import OOIReportSettingsForm diff --git a/rocky/rocky/views/organization_member_list.py b/rocky/rocky/views/organization_member_list.py index 3a53e04b07b..5a04119561a 100644 --- a/rocky/rocky/views/organization_member_list.py +++ b/rocky/rocky/views/organization_member_list.py @@ -14,8 +14,8 @@ class BLOCK_STATUSES(models.TextChoices): - BLOCKED = _("Blocked"), "blocked" - UNBLOCKED = _("Not blocked"), "unblocked" + BLOCKED = "blocked", _("Blocked") + UNBLOCKED = "unblocked", _("Not blocked") class PageActions(Enum): From fb042e99dde8ac91971c61a82cc7f83e9e256f04 Mon Sep 17 00:00:00 2001 From: Madelon Dohmen <99282220+madelondohmen@users.noreply.github.com> Date: Tue, 9 Jul 2024 09:18:48 +0200 Subject: [PATCH 006/112] Add pluginToggler.js to Aggregate Report (#3202) --- rocky/reports/templates/aggregate_report/setup_scan.html | 1 + 1 file changed, 1 insertion(+) diff --git a/rocky/reports/templates/aggregate_report/setup_scan.html b/rocky/reports/templates/aggregate_report/setup_scan.html index c573b7168ed..a6e925c8cb3 100644 --- a/rocky/reports/templates/aggregate_report/setup_scan.html +++ b/rocky/reports/templates/aggregate_report/setup_scan.html @@ -20,4 +20,5 @@ {% block html_at_end_body %} {{ block.super }} + {% endblock html_at_end_body %} From 1ba89832a1b69157e29e4d6824b5c489749ffbc9 Mon Sep 17 00:00:00 2001 From: ammar92 Date: Tue, 9 Jul 2024 15:36:31 +0200 Subject: [PATCH 007/112] Updated `certifi` (#3209) --- boefjes/poetry.lock | 6 +++--- boefjes/requirements-dev.txt | 6 +++--- boefjes/requirements.txt | 6 +++--- bytes/poetry.lock | 6 +++--- bytes/requirements-dev.txt | 6 +++--- bytes/requirements.txt | 6 +++--- cveapi/poetry.lock | 6 +++--- cveapi/requirements.txt | 6 +++--- keiko/poetry.lock | 6 +++--- keiko/requirements-dev.txt | 6 +++--- mula/poetry.lock | 6 +++--- mula/requirements-dev.txt | 6 +++--- mula/requirements.txt | 6 +++--- octopoes/poetry.lock | 6 +++--- octopoes/requirements-dev.txt | 6 +++--- octopoes/requirements.txt | 6 +++--- poetry.lock | 6 +++--- requirements.txt | 6 +++--- rocky/poetry.lock | 6 +++--- rocky/requirements-dev.txt | 6 +++--- rocky/requirements.txt | 6 +++--- 21 files changed, 63 insertions(+), 63 deletions(-) diff --git a/boefjes/poetry.lock b/boefjes/poetry.lock index f720f095c2d..b557c4e7e4c 100644 --- a/boefjes/poetry.lock +++ b/boefjes/poetry.lock @@ -281,13 +281,13 @@ rich = ">=10.16.2" [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] diff --git a/boefjes/requirements-dev.txt b/boefjes/requirements-dev.txt index 1950ae8259e..fee77402b93 100644 --- a/boefjes/requirements-dev.txt +++ b/boefjes/requirements-dev.txt @@ -111,9 +111,9 @@ beautifulsoup4==4.11.1 ; python_version >= "3.10" and python_version < "4.0" \ censys==2.1.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2ddd6d0ee6df70acf15792328df8bb4d0dd5a76b50883adac62989f1641820c1 \ --hash=sha256:665acf8777a871098832527ab8e0c5b1b9f9a548be928239747a6fcde8b613eb -certifi==2024.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 cffi==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ diff --git a/boefjes/requirements.txt b/boefjes/requirements.txt index 6952a91f01e..35ae9ffbaef 100644 --- a/boefjes/requirements.txt +++ b/boefjes/requirements.txt @@ -111,9 +111,9 @@ beautifulsoup4==4.11.1 ; python_version >= "3.10" and python_version < "4.0" \ censys==2.1.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2ddd6d0ee6df70acf15792328df8bb4d0dd5a76b50883adac62989f1641820c1 \ --hash=sha256:665acf8777a871098832527ab8e0c5b1b9f9a548be928239747a6fcde8b613eb -certifi==2024.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 cffi==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ diff --git a/bytes/poetry.lock b/bytes/poetry.lock index da9cffa283f..2a7a6964b8e 100644 --- a/bytes/poetry.lock +++ b/bytes/poetry.lock @@ -122,13 +122,13 @@ files = [ [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] diff --git a/bytes/requirements-dev.txt b/bytes/requirements-dev.txt index 3c98b15ac74..972f11a34e5 100644 --- a/bytes/requirements-dev.txt +++ b/bytes/requirements-dev.txt @@ -41,9 +41,9 @@ bcrypt==4.1.2 ; python_version >= "3.10" and python_version < "4.0" \ cachetools==5.3.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945 \ --hash=sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105 -certifi==2024.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 cffi==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ diff --git a/bytes/requirements.txt b/bytes/requirements.txt index 1f0a94dad5b..11e00e86269 100644 --- a/bytes/requirements.txt +++ b/bytes/requirements.txt @@ -41,9 +41,9 @@ bcrypt==4.1.2 ; python_version >= "3.10" and python_version < "4.0" \ cachetools==5.3.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945 \ --hash=sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105 -certifi==2024.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 cffi==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ diff --git a/cveapi/poetry.lock b/cveapi/poetry.lock index 67728a1c93b..1a6a8b170e0 100644 --- a/cveapi/poetry.lock +++ b/cveapi/poetry.lock @@ -22,13 +22,13 @@ trio = ["trio (>=0.23)"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] diff --git a/cveapi/requirements.txt b/cveapi/requirements.txt index 994cb69ed98..4ecbe5e20a7 100644 --- a/cveapi/requirements.txt +++ b/cveapi/requirements.txt @@ -1,9 +1,9 @@ anyio==4.3.0 ; python_version >= "3.11" and python_version < "4.0" \ --hash=sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8 \ --hash=sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6 -certifi==2024.2.2 ; python_version >= "3.11" and python_version < "4.0" \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 h11==0.14.0 ; python_version >= "3.11" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 diff --git a/keiko/poetry.lock b/keiko/poetry.lock index 8ffbeb175e2..b09845d750b 100644 --- a/keiko/poetry.lock +++ b/keiko/poetry.lock @@ -63,13 +63,13 @@ files = [ [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] diff --git a/keiko/requirements-dev.txt b/keiko/requirements-dev.txt index 8aea7bd2988..ff5b0dfe085 100644 --- a/keiko/requirements-dev.txt +++ b/keiko/requirements-dev.txt @@ -10,9 +10,9 @@ asgiref==3.7.2 ; python_version >= "3.10" and python_version < "4.0" \ backoff==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba \ --hash=sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8 -certifi==2024.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ diff --git a/mula/poetry.lock b/mula/poetry.lock index b5d3f74c2a2..0ddbf59e57a 100644 --- a/mula/poetry.lock +++ b/mula/poetry.lock @@ -71,13 +71,13 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] [[package]] name = "certifi" -version = "2024.6.2" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, - {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] diff --git a/mula/requirements-dev.txt b/mula/requirements-dev.txt index 0dd11b87143..5b102ed95d9 100644 --- a/mula/requirements-dev.txt +++ b/mula/requirements-dev.txt @@ -10,9 +10,9 @@ anyio==4.4.0 ; python_version >= "3.10" and python_version < "4.0" \ asgiref==3.8.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \ --hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590 -certifi==2024.6.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516 \ - --hash=sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de diff --git a/mula/requirements.txt b/mula/requirements.txt index 15c662467bd..e4e2af3d29b 100644 --- a/mula/requirements.txt +++ b/mula/requirements.txt @@ -10,9 +10,9 @@ anyio==4.4.0 ; python_version >= "3.10" and python_version < "4.0" \ asgiref==3.8.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \ --hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590 -certifi==2024.6.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516 \ - --hash=sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de diff --git a/octopoes/poetry.lock b/octopoes/poetry.lock index 4850327c310..51a229e45b3 100644 --- a/octopoes/poetry.lock +++ b/octopoes/poetry.lock @@ -173,13 +173,13 @@ zstd = ["zstandard (==0.22.0)"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] diff --git a/octopoes/requirements-dev.txt b/octopoes/requirements-dev.txt index f34c270219f..ec126a2f54c 100644 --- a/octopoes/requirements-dev.txt +++ b/octopoes/requirements-dev.txt @@ -22,9 +22,9 @@ billiard==4.2.0 ; python_version >= "3.10" and python_version < "4.0" \ celery==5.4.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:369631eb580cf8c51a82721ec538684994f8277637edde2dfc0dacd73ed97f64 \ --hash=sha256:504a19140e8d3029d5acad88330c541d4c3f64c789d85f94756762d8bca7e706 -certifi==2024.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ diff --git a/octopoes/requirements.txt b/octopoes/requirements.txt index 928350d9a41..2d90b56ce3d 100644 --- a/octopoes/requirements.txt +++ b/octopoes/requirements.txt @@ -19,9 +19,9 @@ billiard==4.2.0 ; python_version >= "3.10" and python_version < "4.0" \ celery==5.4.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:369631eb580cf8c51a82721ec538684994f8277637edde2dfc0dacd73ed97f64 \ --hash=sha256:504a19140e8d3029d5acad88330c541d4c3f64c789d85f94756762d8bca7e706 -certifi==2024.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ diff --git a/poetry.lock b/poetry.lock index 560bc332a6a..fdc0838def6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -61,13 +61,13 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] diff --git a/requirements.txt b/requirements.txt index d594303ce0f..6810d572002 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,9 +9,9 @@ autodoc-pydantic==2.2.0 ; python_version >= "3.10" and python_version < "4.0" \ babel==2.15.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb \ --hash=sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413 -certifi==2024.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ diff --git a/rocky/poetry.lock b/rocky/poetry.lock index 9846b49b802..54988ccf071 100644 --- a/rocky/poetry.lock +++ b/rocky/poetry.lock @@ -234,13 +234,13 @@ cffi = ">=1.0.0" [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] diff --git a/rocky/requirements-dev.txt b/rocky/requirements-dev.txt index aacc86a9fbf..974a0434412 100644 --- a/rocky/requirements-dev.txt +++ b/rocky/requirements-dev.txt @@ -128,9 +128,9 @@ brotlicffi==1.1.0.0 ; platform_python_implementation != "CPython" and python_ver --hash=sha256:ce01c7316aebc7fce59da734286148b1d1b9455f89cf2c8a4dfce7d41db55c2d \ --hash=sha256:d9eb71bb1085d996244439154387266fd23d6ad37161f6f52f1cd41dd95a3808 \ --hash=sha256:fa8ca0623b26c94fccc3a1fdd895be1743b838f3917300506d04aa3346fd2a14 -certifi==2024.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 cffi==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ diff --git a/rocky/requirements.txt b/rocky/requirements.txt index b24453047ab..4bddd1a80aa 100644 --- a/rocky/requirements.txt +++ b/rocky/requirements.txt @@ -125,9 +125,9 @@ brotlicffi==1.1.0.0 ; platform_python_implementation != "CPython" and python_ver --hash=sha256:ce01c7316aebc7fce59da734286148b1d1b9455f89cf2c8a4dfce7d41db55c2d \ --hash=sha256:d9eb71bb1085d996244439154387266fd23d6ad37161f6f52f1cd41dd95a3808 \ --hash=sha256:fa8ca0623b26c94fccc3a1fdd895be1743b838f3917300506d04aa3346fd2a14 -certifi==2024.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ - --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 +certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 cffi==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ From 7cbf406714338d1be15497cff59cdc213e5b9cd1 Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Tue, 9 Jul 2024 20:26:34 +0200 Subject: [PATCH 008/112] Feature/boefje normalizer config models (#3118) Signed-off-by: Donny Peeters Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> Co-authored-by: Jan Klopper --- boefjes/.ci/docker-compose.yml | 2 +- boefjes/boefjes/api.py | 2 +- boefjes/boefjes/app.py | 2 +- boefjes/boefjes/config.py | 2 +- .../api => dependencies}/__init__.py | 0 .../dependencies/encryption.py | 0 .../{katalogus => }/dependencies/plugins.py | 96 +++++---- boefjes/boefjes/docker_boefjes_runner.py | 2 +- boefjes/boefjes/job_handler.py | 2 +- .../katalogus/dependencies/organisations.py | 12 -- .../katalogus/{api => }/organisations.py | 6 +- .../boefjes/katalogus/{api => }/plugins.py | 8 +- boefjes/boefjes/katalogus/{api => }/root.py | 14 +- .../boefjes/katalogus/{api => }/settings.py | 4 +- boefjes/boefjes/katalogus/storage/memory.py | 106 ---------- .../katalogus/tests/integration/__init__.py | 0 boefjes/boefjes/local.py | 2 +- .../{katalogus => }/local_repository.py | 2 +- ...fafdaf_json_settings_for_settings_table.py | 2 +- ...de6eb7824b_introduce_boefjeconfig_model.py | 186 ++++++++++++++++++ boefjes/boefjes/{katalogus => }/models.py | 0 boefjes/boefjes/plugins/models.py | 2 +- boefjes/boefjes/sql/config_storage.py | 140 +++++++++++++ boefjes/boefjes/sql/db.py | 3 +- boefjes/boefjes/sql/db_models.py | 29 +-- boefjes/boefjes/sql/organisation_storage.py | 11 +- boefjes/boefjes/sql/plugin_enabled_storage.py | 94 --------- boefjes/boefjes/sql/plugin_storage.py | 22 ++- boefjes/boefjes/sql/session.py | 2 +- boefjes/boefjes/sql/setting_storage.py | 79 -------- .../dependencies => storage}/__init__.py | 0 .../{katalogus => }/storage/interfaces.py | 47 +++-- boefjes/boefjes/storage/memory.py | 125 ++++++++++++ .../debian/kat-boefjes.kat-katalogus.service | 2 +- boefjes/entrypoint.sh | 2 +- .../storage => tests/integration}/__init__.py | 0 .../tests/integration/test_api.py | 27 ++- ...test_json_settings_encryption_migration.py | 35 ++-- .../test_remove_repository_migration.py | 24 +-- ...est_settings_to_boefje_config_migration.py | 102 ++++++++++ .../integration/test_sql_repositories.py | 102 +++++----- .../tests => tests/katalogus}/__init__.py | 0 .../katalogus}/boefjes_test_dir/__init__.py | 0 .../boefjes_test_dir/kat_test/__init__.py | 0 .../boefjes_test_dir/kat_test/boefje.json | 0 .../kat_test/kat_test_2/__init__.py | 0 .../kat_test/kat_test_2/boefje.json | 0 .../kat_test_2/kat_test_3/__init__.py | 0 .../kat_test_2/kat_test_3/normalize.py | 0 .../kat_test_2/kat_test_3/normalizer.json | 0 .../kat_test/kat_test_2/main.py | 0 .../kat_test/kat_test_2/schema.json | 0 .../kat_test/kat_test_4/__init__.py | 0 .../kat_test/kat_test_4/boefje.json | 0 .../kat_test/kat_test_4/schema.json | 0 .../boefjes_test_dir/kat_test/main.py | 0 .../boefjes_test_dir/kat_test/normalize.py | 0 .../boefjes_test_dir/kat_test/normalizer.json | 0 .../boefjes_test_dir/kat_test/schema.json | 0 .../katalogus}/test_organisation_api.py | 8 +- .../katalogus}/test_plugin_service.py | 32 ++- .../katalogus}/test_plugins_api.py | 41 ++-- .../katalogus}/test_settings.py | 2 +- boefjes/tests/test_adr_validator.py | 2 +- boefjes/tests/test_answer_parser.py | 2 +- boefjes/tests/test_bodyimage.py | 2 +- boefjes/tests/test_calvin.py | 2 +- boefjes/tests/test_dns.py | 2 +- boefjes/tests/test_manual.py | 2 +- boefjes/tests/test_report_data.py | 2 +- boefjes/tests/test_scan_profiles.py | 2 +- boefjes/tests/test_tasks.py | 4 +- boefjes/tests/test_wappalyzer_normalizer.py | 2 +- boefjes/tools/run_boefje.py | 2 +- boefjes/tools/run_normalizer.py | 2 +- docker-compose.yml | 2 +- mula/.ci/docker-compose.yml | 2 +- 77 files changed, 870 insertions(+), 541 deletions(-) rename boefjes/boefjes/{katalogus/api => dependencies}/__init__.py (100%) rename boefjes/boefjes/{katalogus => }/dependencies/encryption.py (100%) rename boefjes/boefjes/{katalogus => }/dependencies/plugins.py (69%) delete mode 100644 boefjes/boefjes/katalogus/dependencies/organisations.py rename boefjes/boefjes/katalogus/{api => }/organisations.py (88%) rename boefjes/boefjes/katalogus/{api => }/plugins.py (96%) rename boefjes/boefjes/katalogus/{api => }/root.py (87%) rename boefjes/boefjes/katalogus/{api => }/settings.py (85%) delete mode 100644 boefjes/boefjes/katalogus/storage/memory.py delete mode 100644 boefjes/boefjes/katalogus/tests/integration/__init__.py rename boefjes/boefjes/{katalogus => }/local_repository.py (99%) create mode 100644 boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py rename boefjes/boefjes/{katalogus => }/models.py (100%) create mode 100644 boefjes/boefjes/sql/config_storage.py delete mode 100644 boefjes/boefjes/sql/plugin_enabled_storage.py delete mode 100644 boefjes/boefjes/sql/setting_storage.py rename boefjes/boefjes/{katalogus/dependencies => storage}/__init__.py (100%) rename boefjes/boefjes/{katalogus => }/storage/interfaces.py (78%) create mode 100644 boefjes/boefjes/storage/memory.py rename boefjes/{boefjes/katalogus/storage => tests/integration}/__init__.py (100%) rename boefjes/{boefjes/katalogus => }/tests/integration/test_api.py (90%) rename boefjes/{boefjes/katalogus => }/tests/integration/test_json_settings_encryption_migration.py (69%) rename boefjes/{boefjes/katalogus => }/tests/integration/test_remove_repository_migration.py (81%) create mode 100644 boefjes/tests/integration/test_settings_to_boefje_config_migration.py rename boefjes/{boefjes/katalogus => }/tests/integration/test_sql_repositories.py (72%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/__init__.py (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/__init__.py (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/__init__.py (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/boefje.json (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/kat_test_2/__init__.py (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/kat_test_2/boefje.json (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/__init__.py (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalize.py (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalizer.json (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/kat_test_2/main.py (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/kat_test_2/schema.json (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/kat_test_4/__init__.py (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/kat_test_4/boefje.json (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/kat_test_4/schema.json (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/main.py (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/normalize.py (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/normalizer.json (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/boefjes_test_dir/kat_test/schema.json (100%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/test_organisation_api.py (86%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/test_plugin_service.py (81%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/test_plugins_api.py (81%) rename boefjes/{boefjes/katalogus/tests => tests/katalogus}/test_settings.py (90%) diff --git a/boefjes/.ci/docker-compose.yml b/boefjes/.ci/docker-compose.yml index 0ed9b4c14dc..16d8686e789 100644 --- a/boefjes/.ci/docker-compose.yml +++ b/boefjes/.ci/docker-compose.yml @@ -5,7 +5,7 @@ services: dockerfile: boefjes/Dockerfile args: - ENVIRONMENT=dev - command: sh -c 'python -m pytest -v boefjes/katalogus/tests/integration' + command: sh -c 'python -m pytest -v tests/integration' depends_on: - ci_katalogus-db env_file: diff --git a/boefjes/boefjes/api.py b/boefjes/boefjes/api.py index c26f64e7979..c1fbce49dbe 100644 --- a/boefjes/boefjes/api.py +++ b/boefjes/boefjes/api.py @@ -15,7 +15,7 @@ from boefjes.config import settings from boefjes.job_handler import get_environment_settings, get_octopoes_api_connector, serialize_ooi from boefjes.job_models import BoefjeMeta -from boefjes.katalogus.local_repository import LocalPluginRepository, get_local_repository +from boefjes.local_repository import LocalPluginRepository, get_local_repository from boefjes.plugins.models import _default_mime_types from octopoes.models import Reference from octopoes.models.exception import ObjectNotFoundException diff --git a/boefjes/boefjes/app.py b/boefjes/boefjes/app.py index 6734395a6cd..db725042596 100644 --- a/boefjes/boefjes/app.py +++ b/boefjes/boefjes/app.py @@ -17,8 +17,8 @@ ) from boefjes.config import Settings from boefjes.job_handler import BoefjeHandler, NormalizerHandler, bytes_api_client -from boefjes.katalogus.local_repository import get_local_repository from boefjes.local import LocalBoefjeJobRunner, LocalNormalizerJobRunner +from boefjes.local_repository import get_local_repository from boefjes.runtime_interfaces import Handler, WorkerManager logger = logging.getLogger(__name__) diff --git a/boefjes/boefjes/config.py b/boefjes/boefjes/config.py index 353cfed9368..72a1e02a310 100644 --- a/boefjes/boefjes/config.py +++ b/boefjes/boefjes/config.py @@ -7,7 +7,7 @@ from pydantic_settings import BaseSettings, PydanticBaseSettingsSource, SettingsConfigDict from pydantic_settings.sources import EnvSettingsSource -from boefjes.katalogus.models import EncryptionMiddleware +from boefjes.models import EncryptionMiddleware BASE_DIR: Path = Path(__file__).parent.resolve() diff --git a/boefjes/boefjes/katalogus/api/__init__.py b/boefjes/boefjes/dependencies/__init__.py similarity index 100% rename from boefjes/boefjes/katalogus/api/__init__.py rename to boefjes/boefjes/dependencies/__init__.py diff --git a/boefjes/boefjes/katalogus/dependencies/encryption.py b/boefjes/boefjes/dependencies/encryption.py similarity index 100% rename from boefjes/boefjes/katalogus/dependencies/encryption.py rename to boefjes/boefjes/dependencies/encryption.py diff --git a/boefjes/boefjes/katalogus/dependencies/plugins.py b/boefjes/boefjes/dependencies/plugins.py similarity index 69% rename from boefjes/boefjes/katalogus/dependencies/plugins.py rename to boefjes/boefjes/dependencies/plugins.py index d254afa8ca7..8be80ae70db 100644 --- a/boefjes/boefjes/katalogus/dependencies/plugins.py +++ b/boefjes/boefjes/dependencies/plugins.py @@ -9,20 +9,19 @@ from jsonschema.validators import validate from sqlalchemy.orm import Session -from boefjes.katalogus.local_repository import LocalPluginRepository, get_local_repository -from boefjes.katalogus.models import Boefje, FilterParameters, Normalizer, PaginationParameters, PluginType -from boefjes.katalogus.storage.interfaces import ( +from boefjes.local_repository import LocalPluginRepository, get_local_repository +from boefjes.models import Boefje, FilterParameters, Normalizer, PaginationParameters, PluginType +from boefjes.sql.config_storage import create_config_storage +from boefjes.sql.db import session_managed_iterator +from boefjes.sql.plugin_storage import create_plugin_storage +from boefjes.storage.interfaces import ( + ConfigStorage, ExistingPluginId, NotFound, - PluginEnabledStorage, + PluginNotFound, PluginStorage, SettingsNotConformingToSchema, - SettingsStorage, ) -from boefjes.sql.db import session_managed_iterator -from boefjes.sql.plugin_enabled_storage import create_plugin_enabled_storage -from boefjes.sql.plugin_storage import create_plugin_storage -from boefjes.sql.setting_storage import create_setting_storage logger = logging.getLogger(__name__) @@ -31,33 +30,29 @@ class PluginService: def __init__( self, plugin_storage: PluginStorage, - plugin_enabled_store: PluginEnabledStorage, - settings_storage: SettingsStorage, + config_storage: ConfigStorage, local_repo: LocalPluginRepository, ): self.plugin_storage = plugin_storage - self.plugin_enabled_store = plugin_enabled_store - self.settings_storage = settings_storage + self.config_storage = config_storage self.local_repo = local_repo def __enter__(self): - self.plugin_enabled_store.__enter__() self.plugin_storage.__enter__() - self.settings_storage.__enter__() + self.config_storage.__enter__() return self def __exit__(self, exc_type, exc_val, exc_tb): - self.plugin_enabled_store.__exit__(exc_type, exc_val, exc_tb) self.plugin_storage.__exit__(exc_type, exc_val, exc_tb) - self.settings_storage.__exit__(exc_type, exc_val, exc_tb) + self.config_storage.__exit__(exc_type, exc_val, exc_tb) def get_all(self, organisation_id: str) -> list[PluginType]: - all_plugins = self.get_all_without_enabled() + all_plugins = self._get_all_without_enabled() return [self._set_plugin_enabled(plugin, organisation_id) for plugin in all_plugins.values()] - def get_all_without_enabled(self): + def _get_all_without_enabled(self): all_plugins = {plugin.id: plugin for plugin in self.local_repo.get_all()} for plugin in self.plugin_storage.get_all(): @@ -88,24 +83,25 @@ def by_plugin_ids(self, plugin_ids: list[str], organisation_id: str) -> list[Plu return found_plugins def get_all_settings(self, organisation_id: str, plugin_id: str): - return self.settings_storage.get_all(organisation_id, plugin_id) + return self.config_storage.get_all_settings(organisation_id, plugin_id) def clone_settings_to_organisation(self, from_organisation: str, to_organisation: str): # One requirement is that only boefjes enabled in the from_organisation end up being enabled for the target. - for plugin_id in self.plugin_enabled_store.get_all_enabled(to_organisation): + for plugin_id in self.config_storage.get_enabled_boefjes(to_organisation): self.set_enabled_by_id(plugin_id, to_organisation, enabled=False) for plugin in self.get_all(from_organisation): if all_settings := self.get_all_settings(from_organisation, plugin.id): self.upsert_settings(all_settings, to_organisation, plugin.id) - for plugin_id in self.plugin_enabled_store.get_all_enabled(from_organisation): + for plugin_id in self.config_storage.get_enabled_boefjes(from_organisation): self.set_enabled_by_id(plugin_id, to_organisation, enabled=True) - def upsert_settings(self, values: dict, organisation_id: str, plugin_id: str): - self._assert_settings_match_schema(values, organisation_id, plugin_id) + def upsert_settings(self, settings: dict, organisation_id: str, plugin_id: str): + self._assert_settings_match_schema(settings, organisation_id, plugin_id) + self._put_boefje(plugin_id) - return self.settings_storage.upsert(values, organisation_id, plugin_id) + return self.config_storage.upsert(organisation_id, plugin_id, settings=settings) def create_boefje(self, boefje: Boefje) -> None: try: @@ -121,8 +117,38 @@ def create_normalizer(self, normalizer: Normalizer) -> None: except KeyError: self.plugin_storage.create_normalizer(normalizer) + def _put_boefje(self, boefje_id: str) -> None: + """Check existence of a boefje, and insert a database entry if it concerns a local boefje""" + + try: + self.plugin_storage.boefje_by_id(boefje_id) + except PluginNotFound: + try: + plugin = self.local_repo.by_id(boefje_id) + except KeyError: + raise + + if plugin.type != "boefje": + raise + self.plugin_storage.create_boefje(plugin) + + def _put_normalizer(self, normalizer_id: str) -> None: + """Check existence of a normalizer, and insert a database entry if it concerns a local normalizer""" + + try: + self.plugin_storage.normalizer_by_id(normalizer_id) + except PluginNotFound: + try: + plugin = self.local_repo.by_id(normalizer_id) + except KeyError: + raise + + if plugin.type != "normalizer": + raise + self.plugin_storage.create_normalizer(plugin) + def delete_settings(self, organisation_id: str, plugin_id: str): - self.settings_storage.delete(organisation_id, plugin_id) + self.config_storage.delete(organisation_id, plugin_id) try: self._assert_settings_match_schema({}, organisation_id, plugin_id) @@ -154,14 +180,15 @@ def description(self, plugin_id: str, organisation_id: str) -> str: def set_enabled_by_id(self, plugin_id: str, organisation_id: str, enabled: bool): if enabled: - all_settings = self.settings_storage.get_all(organisation_id, plugin_id) + all_settings = self.get_all_settings(organisation_id, plugin_id) self._assert_settings_match_schema(all_settings, organisation_id, plugin_id) - self.plugin_enabled_store.update_or_create_by_id( - plugin_id, - enabled, - organisation_id, - ) + try: + self._put_boefje(plugin_id) + except PluginNotFound: + self._put_normalizer(plugin_id) + + self.config_storage.upsert(organisation_id, plugin_id, enabled=enabled) def _assert_settings_match_schema(self, all_settings: dict, organisation_id: str, plugin_id: str): schema = self.schema(plugin_id) @@ -174,7 +201,7 @@ def _assert_settings_match_schema(self, all_settings: dict, organisation_id: str def _set_plugin_enabled(self, plugin: PluginType, organisation_id: str) -> PluginType: with contextlib.suppress(KeyError, NotFound): - plugin.enabled = self.plugin_enabled_store.get_by_id(plugin.id, organisation_id) + plugin.enabled = self.config_storage.is_enabled_by_id(plugin.id, organisation_id) return plugin @@ -183,8 +210,7 @@ def get_plugin_service(organisation_id: str) -> Iterator[PluginService]: def closure(session: Session): return PluginService( create_plugin_storage(session), - create_plugin_enabled_storage(session), - create_setting_storage(session), + create_config_storage(session), get_local_repository(), ) diff --git a/boefjes/boefjes/docker_boefjes_runner.py b/boefjes/boefjes/docker_boefjes_runner.py index 8375c57a1be..c52c4d2d0fd 100644 --- a/boefjes/boefjes/docker_boefjes_runner.py +++ b/boefjes/boefjes/docker_boefjes_runner.py @@ -9,7 +9,7 @@ from boefjes.clients.scheduler_client import SchedulerAPIClient, TaskStatus from boefjes.config import settings from boefjes.job_models import BoefjeMeta -from boefjes.katalogus.models import Boefje +from boefjes.models import Boefje logger = logging.getLogger(__name__) diff --git a/boefjes/boefjes/job_handler.py b/boefjes/boefjes/job_handler.py index 54f45052458..eb3cf3715ac 100644 --- a/boefjes/boefjes/job_handler.py +++ b/boefjes/boefjes/job_handler.py @@ -13,7 +13,7 @@ from boefjes.config import settings from boefjes.docker_boefjes_runner import DockerBoefjesRunner from boefjes.job_models import BoefjeMeta, NormalizerMeta, SerializedOOI, SerializedOOIValue -from boefjes.katalogus.local_repository import LocalPluginRepository +from boefjes.local_repository import LocalPluginRepository from boefjes.plugins.models import _default_mime_types from boefjes.runtime_interfaces import BoefjeJobRunner, Handler, NormalizerJobRunner from octopoes.api.models import Affirmation, Declaration, Observation diff --git a/boefjes/boefjes/katalogus/dependencies/organisations.py b/boefjes/boefjes/katalogus/dependencies/organisations.py deleted file mode 100644 index 46c03a936c3..00000000000 --- a/boefjes/boefjes/katalogus/dependencies/organisations.py +++ /dev/null @@ -1,12 +0,0 @@ -import logging -from collections.abc import Iterator - -from boefjes.katalogus.storage.interfaces import OrganisationStorage -from boefjes.sql.db import session_managed_iterator -from boefjes.sql.organisation_storage import create_organisation_storage - -logger = logging.getLogger(__name__) - - -def get_organisations_store() -> Iterator[OrganisationStorage]: - yield from session_managed_iterator(create_organisation_storage) diff --git a/boefjes/boefjes/katalogus/api/organisations.py b/boefjes/boefjes/katalogus/organisations.py similarity index 88% rename from boefjes/boefjes/katalogus/api/organisations.py rename to boefjes/boefjes/katalogus/organisations.py index fcb68e0f99f..3f8d8e6cc84 100644 --- a/boefjes/boefjes/katalogus/api/organisations.py +++ b/boefjes/boefjes/katalogus/organisations.py @@ -1,9 +1,9 @@ from fastapi import APIRouter, Depends, HTTPException, status -from boefjes.katalogus.dependencies.organisations import get_organisations_store -from boefjes.katalogus.models import Organisation -from boefjes.katalogus.storage.interfaces import OrganisationNotFound, OrganisationStorage +from boefjes.models import Organisation from boefjes.sql.db import ObjectNotFoundException +from boefjes.sql.organisation_storage import get_organisations_store +from boefjes.storage.interfaces import OrganisationNotFound, OrganisationStorage router = APIRouter(prefix="/organisations", tags=["organisations"]) diff --git a/boefjes/boefjes/katalogus/api/plugins.py b/boefjes/boefjes/katalogus/plugins.py similarity index 96% rename from boefjes/boefjes/katalogus/api/plugins.py rename to boefjes/boefjes/katalogus/plugins.py index 7b639a88ba0..0928280af4a 100644 --- a/boefjes/boefjes/katalogus/api/plugins.py +++ b/boefjes/boefjes/katalogus/plugins.py @@ -5,16 +5,16 @@ from fastapi.responses import FileResponse, JSONResponse, Response from pydantic import BaseModel, Field -from boefjes.katalogus.api.organisations import check_organisation_exists -from boefjes.katalogus.dependencies.plugins import ( +from boefjes.dependencies.plugins import ( PluginService, get_pagination_parameters, get_plugin_service, get_plugins_filter_parameters, ) -from boefjes.katalogus.models import FilterParameters, PaginationParameters, PluginType -from boefjes.katalogus.storage.interfaces import PluginStorage +from boefjes.katalogus.organisations import check_organisation_exists +from boefjes.models import FilterParameters, PaginationParameters, PluginType from boefjes.sql.plugin_storage import get_plugin_storage +from boefjes.storage.interfaces import PluginStorage router = APIRouter( prefix="/organisations/{organisation_id}", diff --git a/boefjes/boefjes/katalogus/api/root.py b/boefjes/boefjes/katalogus/root.py similarity index 87% rename from boefjes/boefjes/katalogus/api/root.py rename to boefjes/boefjes/katalogus/root.py index 0b3a7ac2bae..6203c850777 100644 --- a/boefjes/boefjes/katalogus/api/root.py +++ b/boefjes/boefjes/katalogus/root.py @@ -15,10 +15,10 @@ from pydantic import BaseModel, Field from boefjes.config import settings -from boefjes.katalogus.api import organisations, plugins -from boefjes.katalogus.api import settings as settings_router -from boefjes.katalogus.storage.interfaces import NotFound, StorageError +from boefjes.katalogus import organisations, plugins +from boefjes.katalogus import settings as settings_router from boefjes.katalogus.version import __version__ +from boefjes.storage.interfaces import NotAllowed, NotFound, StorageError with settings.log_cfg.open() as f: logging.config.dictConfig(json.load(f)) @@ -59,6 +59,14 @@ def entity_not_found_handler(request: Request, exc: NotFound): ) +@app.exception_handler(NotAllowed) +def not_allowed_handler(request: Request, exc: NotAllowed): + return JSONResponse( + status_code=status.HTTP_400_BAD_REQUEST, + content={"message": exc.message}, + ) + + @app.exception_handler(StorageError) def storage_error_handler(request: Request, exc: StorageError): return JSONResponse( diff --git a/boefjes/boefjes/katalogus/api/settings.py b/boefjes/boefjes/katalogus/settings.py similarity index 85% rename from boefjes/boefjes/katalogus/api/settings.py rename to boefjes/boefjes/katalogus/settings.py index 7a710a92711..b40223bbd92 100644 --- a/boefjes/boefjes/katalogus/api/settings.py +++ b/boefjes/boefjes/katalogus/settings.py @@ -1,7 +1,7 @@ from fastapi import APIRouter, Depends -from boefjes.katalogus.api.organisations import check_organisation_exists -from boefjes.katalogus.dependencies.plugins import PluginService, get_plugin_service +from boefjes.dependencies.plugins import PluginService, get_plugin_service +from boefjes.katalogus.organisations import check_organisation_exists router = APIRouter( prefix="/organisations/{organisation_id}/{plugin_id}/settings", diff --git a/boefjes/boefjes/katalogus/storage/memory.py b/boefjes/boefjes/katalogus/storage/memory.py deleted file mode 100644 index d89e972ca32..00000000000 --- a/boefjes/boefjes/katalogus/storage/memory.py +++ /dev/null @@ -1,106 +0,0 @@ -from boefjes.katalogus.models import Boefje, Normalizer, Organisation, PluginType -from boefjes.katalogus.storage.interfaces import ( - OrganisationStorage, - PluginEnabledStorage, - PluginStorage, - SettingsStorage, -) - -# key = organisation id; value = organisation -organisations: dict[str, Organisation] = {} - -# key = organisation, repository/plugin id; value = enabled/ disabled -plugins_state: dict[str, dict[str, bool]] = {} - - -class OrganisationStorageMemory(OrganisationStorage): - def __init__(self, defaults: dict[str, Organisation] | None = None): - self._data = organisations if defaults is None else defaults - - def get_by_id(self, organisation_id: str) -> Organisation: - return self._data[organisation_id] - - def get_all(self) -> dict[str, Organisation]: - return self._data - - def create(self, organisation: Organisation) -> None: - self._data[organisation.id] = organisation - - def delete_by_id(self, organisation_id: str) -> None: - del self._data[organisation_id] - - -class PluginStorageMemory(PluginStorage): - def __init__(self): - self._boefjes = {} - self._normalizers = {} - - def get_all(self) -> list[PluginType]: - return list(self._boefjes.values()) + list(self._normalizers.values()) - - def boefje_by_id(self, boefje_id: str) -> Boefje: - return self._boefjes[boefje_id] - - def normalizer_by_id(self, normalizer_id: str) -> Normalizer: - return self._normalizers[normalizer_id] - - def create_boefje(self, boefje: Boefje) -> None: - self._boefjes[boefje.id] = boefje - - def create_normalizer(self, normalizer: Normalizer) -> None: - self._normalizers[normalizer.id] = normalizer - - def delete_boefje_by_id(self, boefje_id: str) -> None: - del self._boefjes[boefje_id] - - def delete_normalizer_by_id(self, normalizer_id: str) -> None: - del self._normalizers[normalizer_id] - - -class SettingsStorageMemory(SettingsStorage): - def __init__(self): - self._data = {} - - def get_all(self, organisation_id: str, plugin_id: str) -> dict[str, str]: - if organisation_id not in self._data: - return {} - - return self._data[organisation_id].get(plugin_id, {}) - - def upsert(self, values: dict, organisation_id: str, plugin_id: str) -> None: - if organisation_id not in self._data: - self._data[organisation_id] = {} - - if plugin_id not in self._data[organisation_id]: - self._data[organisation_id][plugin_id] = {} - - self._data[organisation_id][plugin_id] = values - - def delete(self, organisation_id: str, plugin_id: str) -> None: - del self._data[organisation_id][plugin_id] - - -class PluginStatesStorageMemory(PluginEnabledStorage): - def __init__( - self, - organisation: str, - defaults: dict[str, bool] | None = None, - ): - self._data = plugins_state.setdefault(organisation, {}) if defaults is None else defaults - self._organisation = organisation - - def get_by_id(self, plugin_id: str, organisation_id: str) -> bool: - return self._data[f"{organisation_id}.{plugin_id}"] - - def get_all_enabled(self, organisation_id: str) -> list[str]: - return [ - key.split(".", maxsplit=1)[1] - for key, value in self._data.items() - if value and key.split(".", maxsplit=1)[0] == organisation_id - ] - - def create(self, plugin_id: str, enabled: bool, organisation_id: str) -> None: - self._data[f"{organisation_id}.{plugin_id}"] = enabled - - def update_or_create_by_id(self, plugin_id: str, enabled: bool, organisation_id: str) -> None: - self._data[f"{organisation_id}.{plugin_id}"] = enabled diff --git a/boefjes/boefjes/katalogus/tests/integration/__init__.py b/boefjes/boefjes/katalogus/tests/integration/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/boefjes/boefjes/local.py b/boefjes/boefjes/local.py index 7581423dbee..adbf662dacf 100644 --- a/boefjes/boefjes/local.py +++ b/boefjes/boefjes/local.py @@ -13,7 +13,7 @@ NormalizerResults, ObservationsWithoutInputOOI, ) -from boefjes.katalogus.local_repository import LocalPluginRepository +from boefjes.local_repository import LocalPluginRepository from boefjes.runtime_interfaces import BoefjeJobRunner, JobRuntimeError, NormalizerJobRunner from octopoes.models import OOI, DeclaredScanProfile diff --git a/boefjes/boefjes/katalogus/local_repository.py b/boefjes/boefjes/local_repository.py similarity index 99% rename from boefjes/boefjes/katalogus/local_repository.py rename to boefjes/boefjes/local_repository.py index 3e9071123f8..ef5b17442b1 100644 --- a/boefjes/boefjes/katalogus/local_repository.py +++ b/boefjes/boefjes/local_repository.py @@ -4,7 +4,7 @@ from pathlib import Path from typing import Any -from boefjes.katalogus.models import PluginType +from boefjes.models import PluginType from boefjes.plugins.models import ( BOEFJE_DEFINITION_FILE, BOEFJES_DIR, diff --git a/boefjes/boefjes/migrations/versions/cd34fdfafdaf_json_settings_for_settings_table.py b/boefjes/boefjes/migrations/versions/cd34fdfafdaf_json_settings_for_settings_table.py index 7351d140501..f76286dee3c 100644 --- a/boefjes/boefjes/migrations/versions/cd34fdfafdaf_json_settings_for_settings_table.py +++ b/boefjes/boefjes/migrations/versions/cd34fdfafdaf_json_settings_for_settings_table.py @@ -13,8 +13,8 @@ from sqlalchemy.engine import Connection from sqlalchemy.orm import sessionmaker +from boefjes.sql.config_storage import create_encrypter from boefjes.sql.db import get_engine -from boefjes.sql.setting_storage import create_encrypter # revision identifiers, used by Alembic. revision = "cd34fdfafdaf" diff --git a/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py b/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py new file mode 100644 index 00000000000..265cb99c499 --- /dev/null +++ b/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py @@ -0,0 +1,186 @@ +"""Introduce BoefjeConfig model + +Revision ID: f9de6eb7824b +Revises: 6f99834a4a5a +Create Date: 2024-05-31 10:45:16.474714 + +""" + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.orm import sessionmaker + +from boefjes.local_repository import get_local_repository +from boefjes.sql.plugin_storage import create_plugin_storage + +# revision identifiers, used by Alembic. +revision = "f9de6eb7824b" +down_revision = "6f99834a4a5a" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "boefje_config", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("settings", sa.String(length=512), nullable=False, server_default="{}"), + sa.Column("enabled", sa.Boolean(), nullable=False, server_default="false"), + sa.Column("boefje_id", sa.Integer(), nullable=False), + sa.Column("organisation_pk", sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(["boefje_id"], ["boefje.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint(["organisation_pk"], ["organisation.pk"], ondelete="CASCADE"), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("organisation_pk", "boefje_id", name="unique_boefje_config_per_organisation_per_boefje"), + ) + op.create_table( + "normalizer_config", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("enabled", sa.Boolean(), server_default="false", nullable=False), + sa.Column("normalizer_id", sa.Integer(), nullable=False), + sa.Column("organisation_pk", sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(["normalizer_id"], ["normalizer.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint(["organisation_pk"], ["organisation.pk"], ondelete="CASCADE"), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint( + "organisation_pk", "normalizer_id", name="unique_normalizer_config_per_organisation_per_normalizer" + ), + ) + + op.add_column("boefje", sa.Column("static", sa.Boolean(), server_default="false", nullable=False)) + op.add_column("normalizer", sa.Column("static", sa.Boolean(), server_default="false", nullable=False)) + + local_plugins = {plugin.id: plugin for plugin in get_local_repository().get_all()} + connection = op.get_bind() + session = sessionmaker(bind=connection)() + + with create_plugin_storage(session) as storage: + # Get unique plugin_ids from the settings table for boefjes that do not exist yet in the database + query = """ + SELECT DISTINCT s.plugin_id FROM settings s left join boefje b on b.plugin_id = s.plugin_id + where b.plugin_id IS NULL + """ + for plugin_id_output in op.get_bind().execute(query).fetchall(): + plugin_id = plugin_id_output[0] + if plugin_id not in local_plugins: + raise ValueError(f"Invalid plugin id found: {plugin_id}") + + # Since settings are boefje-only at this moment + if local_plugins[plugin_id].type != "boefje": + raise ValueError(f"Settings for normalizer or bit found: {plugin_id}. Remove these entries first.") + + storage.create_boefje(local_plugins[plugin_id]) # type: ignore + + query = """ + SELECT DISTINCT p.plugin_id FROM plugin_state p left join boefje b on b.plugin_id = p.plugin_id + where b.plugin_id IS NULL + """ + + for plugin_id_output in op.get_bind().execute(query).fetchall(): + plugin_id = plugin_id_output[0] + if plugin_id not in local_plugins: + raise ValueError(f"Invalid plugin id found: {plugin_id}") + + if local_plugins[plugin_id].type == "boefje": + storage.create_boefje(local_plugins[plugin_id]) # type: ignore + + query = """ + SELECT DISTINCT p.plugin_id FROM plugin_state p left join normalizer n on n.plugin_id = p.plugin_id + where n.plugin_id IS NULL + """ + + for plugin_id_output in op.get_bind().execute(query).fetchall(): + plugin_id = plugin_id_output[0] + if plugin_id not in local_plugins: + raise ValueError(f"Invalid plugin id found: {plugin_id}") + + if local_plugins[plugin_id].type == "normalizer": + storage.create_normalizer(local_plugins[plugin_id]) # type: ignore + + with connection.begin(): + connection.execute(""" + INSERT INTO boefje_config (settings, boefje_id, organisation_pk) + SELECT s.values, b.id, s.organisation_pk from settings s + join boefje b on s.plugin_id = b.plugin_id + """) + + with connection.begin(): + connection.execute(""" + INSERT INTO boefje_config (settings, boefje_id, organisation_pk) + SELECT p.enabled, b.id, p.organisation_pk FROM plugin_state p + JOIN boefje b ON p.plugin_id = b.plugin_id + LEFT JOIN boefje_config bc ON bc.boefje_id = b.id WHERE bc.boefje_id IS NULL + """) + connection.execute(""" + UPDATE boefje_config bc SET enabled = p.enabled from plugin_state p + JOIN boefje b ON p.plugin_id = b.plugin_id + where b.id = bc.boefje_id and p.organisation_pk = bc.organisation_pk + """) + connection.execute(""" + UPDATE normalizer_config nc SET enabled = p.enabled from plugin_state p + JOIN normalizer n ON p.plugin_id = n.plugin_id + where n.id = nc.normalizer_id and p.organisation_pk = nc.organisation_pk + """) + + op.drop_table("settings") + op.drop_table("plugin_state") + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("normalizer", "static") + op.drop_column("boefje", "static") + + op.create_table( + "settings", + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column("values", sa.VARCHAR(length=512), autoincrement=False, nullable=False), + sa.Column("plugin_id", sa.VARCHAR(length=64), autoincrement=False, nullable=False), + sa.Column("organisation_pk", sa.INTEGER(), autoincrement=False, nullable=False), + sa.ForeignKeyConstraint( + ["organisation_pk"], ["organisation.pk"], name="settings_organisation_pk_fkey", ondelete="CASCADE" + ), + sa.PrimaryKeyConstraint("id", name="settings_pkey"), + sa.UniqueConstraint("organisation_pk", "plugin_id", name="unique_settings_per_organisation_per_plugin"), + ) + op.create_table( + "plugin_state", + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column("plugin_id", sa.VARCHAR(length=64), autoincrement=False, nullable=False), + sa.Column("enabled", sa.BOOLEAN(), autoincrement=False, nullable=False), + sa.Column("organisation_pk", sa.INTEGER(), autoincrement=False, nullable=False), + sa.ForeignKeyConstraint( + ["organisation_pk"], ["organisation.pk"], name="plugin_state_organisation_pk_fkey", ondelete="CASCADE" + ), + sa.PrimaryKeyConstraint("id", name="plugin_state_pkey"), + sa.UniqueConstraint("plugin_id", "organisation_pk", name="unique_plugin_id_per_org"), + ) + + connection = op.get_bind() + with connection.begin(): + connection.execute(""" + INSERT INTO settings (values, plugin_id, organisation_pk) + SELECT bc.settings, b.plugin_id, bc.organisation_pk from boefje_config bc + join boefje b on bc.boefje_id = b.id + """) + + with connection.begin(): + connection.execute(""" + INSERT INTO plugin_state (enabled, plugin_id, organisation_pk) + SELECT bc.enabled, b.plugin_id, bc.organisation_pk from boefje_config bc + join boefje b on bc.boefje_id = b.id + """) + + with connection.begin(): + connection.execute(""" + INSERT INTO plugin_state (enabled, plugin_id, organisation_pk) + SELECT nc.enabled, n.plugin_id, nc.organisation_pk from normalizer_config nc + join normalizer n on nc.normalizer_id = n.id + """) + + op.drop_table("boefje_config") + op.drop_table("normalizer_config") + + # ### end Alembic commands ### diff --git a/boefjes/boefjes/katalogus/models.py b/boefjes/boefjes/models.py similarity index 100% rename from boefjes/boefjes/katalogus/models.py rename to boefjes/boefjes/models.py diff --git a/boefjes/boefjes/plugins/models.py b/boefjes/boefjes/plugins/models.py index d02c255fd39..5a2669ffbc4 100644 --- a/boefjes/boefjes/plugins/models.py +++ b/boefjes/boefjes/plugins/models.py @@ -5,7 +5,7 @@ from pathlib import Path from typing import Protocol -from boefjes.katalogus.models import Boefje, Normalizer +from boefjes.models import Boefje, Normalizer BOEFJES_DIR = Path(__file__).parent diff --git a/boefjes/boefjes/sql/config_storage.py b/boefjes/boefjes/sql/config_storage.py new file mode 100644 index 00000000000..15afde54e6e --- /dev/null +++ b/boefjes/boefjes/sql/config_storage.py @@ -0,0 +1,140 @@ +import json +import logging + +from sqlalchemy.orm import Session + +from boefjes.config import settings as config_settings +from boefjes.dependencies.encryption import EncryptMiddleware, IdentityMiddleware, NaclBoxMiddleware +from boefjes.models import EncryptionMiddleware +from boefjes.sql.db import ObjectNotFoundException +from boefjes.sql.db_models import BoefjeConfigInDB, BoefjeInDB, NormalizerConfigInDB, NormalizerInDB, OrganisationInDB +from boefjes.sql.session import SessionMixin +from boefjes.storage.interfaces import ConfigNotFound, ConfigStorage, OrganisationNotFound, PluginNotFound + +logger = logging.getLogger(__name__) + + +class SQLConfigStorage(SessionMixin, ConfigStorage): + def __init__(self, session: Session, encryption: EncryptMiddleware): + self.encryption = encryption + + super().__init__(session) + + def upsert( + self, organisation_id: str, plugin_id: str, settings: dict | None = None, enabled: bool | None = None + ) -> None: + try: + instance = self._db_instance_by_id(organisation_id, plugin_id) + + if settings is not None: + if isinstance(instance, NormalizerConfigInDB): + raise ValueError("Normalizer config does not have settings") + + instance.settings = self.encryption.encode(json.dumps(settings)) + if enabled is not None: + instance.enabled = enabled + except ConfigNotFound: + organisation = self.session.query(OrganisationInDB).filter(OrganisationInDB.id == organisation_id).first() + + if not organisation: + raise OrganisationNotFound(organisation_id) + + boefje = self.session.query(BoefjeInDB).filter(BoefjeInDB.plugin_id == plugin_id).first() + + if boefje: + config = BoefjeConfigInDB(boefje_id=boefje.id, organisation_pk=organisation.pk) + + if settings is not None: + config.settings = self.encryption.encode(json.dumps(settings)) + + if enabled is not None: + config.enabled = enabled + + self.session.add(config) + return + + normalizer = self.session.query(NormalizerInDB).filter(NormalizerInDB.plugin_id == plugin_id).first() + + if not normalizer: + raise PluginNotFound(plugin_id) + + normalizer_config = NormalizerConfigInDB(normalizer_id=normalizer.id, organisation_pk=organisation.pk) + + if enabled is not None: + normalizer_config.enabled = enabled + + self.session.add(normalizer_config) + + def get_all_settings(self, organisation_id: str, plugin_id: str) -> dict: + try: + instance = self._db_instance_by_id(organisation_id, plugin_id) + except ConfigNotFound: + return {} + + return json.loads(self.encryption.decode(instance.settings)) + + def delete(self, organisation_id: str, plugin_id: str) -> None: + instance = self._db_instance_by_id(organisation_id, plugin_id) + + self.session.delete(instance) + + def is_enabled_by_id(self, plugin_id: str, organisation_id: str) -> bool: + instance = self._db_instance_by_id(organisation_id, plugin_id) + + return instance.enabled + + def get_enabled_boefjes(self, organisation_id: str) -> list[str]: + enabled_boefjes = ( + self.session.query(BoefjeInDB) + .join(BoefjeConfigInDB) + .filter(BoefjeConfigInDB.boefje_id == BoefjeInDB.id) + .join(OrganisationInDB) + .filter(BoefjeConfigInDB.organisation_pk == OrganisationInDB.pk) + .filter(OrganisationInDB.id == organisation_id) + .filter(BoefjeConfigInDB.enabled) + ) + + return [x.plugin_id for x in enabled_boefjes.all()] + + def _db_instance_by_id(self, organisation_id: str, plugin_id: str) -> BoefjeConfigInDB | NormalizerConfigInDB: + instance = ( + self.session.query(BoefjeConfigInDB) + .join(OrganisationInDB) + .join(BoefjeInDB) + .filter(BoefjeConfigInDB.organisation_pk == OrganisationInDB.pk) + .filter(BoefjeConfigInDB.boefje_id == BoefjeInDB.id) + .filter(BoefjeInDB.plugin_id == plugin_id) + .filter(OrganisationInDB.id == organisation_id) + .first() + ) + + if instance is None: + instance = ( + self.session.query(NormalizerConfigInDB) + .join(OrganisationInDB) + .join(NormalizerInDB) + .filter(NormalizerConfigInDB.organisation_pk == OrganisationInDB.pk) + .filter(NormalizerConfigInDB.normalizer_id == NormalizerInDB.id) + .filter(NormalizerInDB.plugin_id == plugin_id) + .filter(OrganisationInDB.id == organisation_id) + .first() + ) + + if instance is None: + raise ConfigNotFound(organisation_id, plugin_id) from ObjectNotFoundException( + BoefjeConfigInDB | NormalizerConfigInDB, organisation_id=organisation_id + ) + + return instance + + +def create_config_storage(session) -> ConfigStorage: + encrypter = create_encrypter() + return SQLConfigStorage(session, encrypter) + + +def create_encrypter(): + if config_settings.encryption_middleware == EncryptionMiddleware.NACL_SEALBOX: + return NaclBoxMiddleware(config_settings.katalogus_private_key, config_settings.katalogus_public_key) + + return IdentityMiddleware() diff --git a/boefjes/boefjes/sql/db.py b/boefjes/boefjes/sql/db.py index 90049986a13..6a1ad303574 100644 --- a/boefjes/boefjes/sql/db.py +++ b/boefjes/boefjes/sql/db.py @@ -1,6 +1,7 @@ import logging from collections.abc import Callable, Iterator from functools import cache +from types import UnionType from typing import Any from sqlalchemy import create_engine @@ -46,5 +47,5 @@ def session_managed_iterator(service_factory: Callable[[Session], Any]) -> Itera class ObjectNotFoundException(Exception): - def __init__(self, cls: type[SQL_BASE], **kwargs): # type: ignore + def __init__(self, cls: type | UnionType, **kwargs): # type: ignore super().__init__(f"The object of type {cls} was not found for query parameters {kwargs}") diff --git a/boefjes/boefjes/sql/db_models.py b/boefjes/boefjes/sql/db_models.py index 1a870e84028..1ecd0cc0086 100644 --- a/boefjes/boefjes/sql/db_models.py +++ b/boefjes/boefjes/sql/db_models.py @@ -22,37 +22,38 @@ class OrganisationInDB(SQL_BASE): name = Column(String(length=64), nullable=False) -class SettingsInDB(SQL_BASE): - __tablename__ = "settings" +class BoefjeConfigInDB(SQL_BASE): + __tablename__ = "boefje_config" __table_args__ = ( UniqueConstraint( "organisation_pk", - "plugin_id", - name="unique_settings_per_organisation_per_plugin", + "boefje_id", + name="unique_boefje_config_per_organisation_per_boefje", ), ) id = Column(Integer, primary_key=True, autoincrement=True) - values = Column(String(length=512), nullable=False) - plugin_id = Column(String(length=64), nullable=False) - organisation_pk = Column(Integer, ForeignKey("organisation.pk", ondelete="CASCADE"), nullable=False) + settings = Column(String(length=512), nullable=False, server_default="{}") + enabled = Column(Boolean, nullable=False, server_default="false") + boefje_id = Column(Integer, ForeignKey("boefje.id", ondelete="CASCADE"), nullable=False) + organisation_pk = Column(Integer, ForeignKey("organisation.pk", ondelete="CASCADE"), nullable=False) organisation = relationship("OrganisationInDB") -class PluginStateInDB(SQL_BASE): - __tablename__ = "plugin_state" +class NormalizerConfigInDB(SQL_BASE): + __tablename__ = "normalizer_config" __table_args__ = ( UniqueConstraint( - "plugin_id", "organisation_pk", - name="unique_plugin_id_per_org", + "normalizer_id", + name="unique_normalizer_config_per_organisation_per_normalizer", ), ) id = Column(Integer, primary_key=True, autoincrement=True) - plugin_id = Column(String(length=64), nullable=False) - enabled = Column(Boolean, nullable=False) + enabled = Column(Boolean, nullable=False, server_default="false") + normalizer_id = Column(Integer, ForeignKey("normalizer.id", ondelete="CASCADE"), nullable=False) organisation_pk = Column(Integer, ForeignKey("organisation.pk", ondelete="CASCADE"), nullable=False) organisation = relationship("OrganisationInDB") @@ -64,6 +65,7 @@ class BoefjeInDB(SQL_BASE): id = Column(types.Integer, primary_key=True, autoincrement=True) plugin_id = Column(types.String(length=64), nullable=False, unique=True) created = Column(types.DateTime(timezone=True), nullable=True) + static = Column(Boolean, nullable=False, server_default="false") # Metadata name = Column(String(length=64), nullable=False) @@ -87,6 +89,7 @@ class NormalizerInDB(SQL_BASE): id = Column(types.Integer, primary_key=True, autoincrement=True) plugin_id = Column(types.String(length=64), nullable=False, unique=True) created = Column(types.DateTime(timezone=True), nullable=True) + static = Column(Boolean, nullable=False, server_default="false") # Metadata name = Column(String(length=64), nullable=False) diff --git a/boefjes/boefjes/sql/organisation_storage.py b/boefjes/boefjes/sql/organisation_storage.py index eed914b2538..012d779576f 100644 --- a/boefjes/boefjes/sql/organisation_storage.py +++ b/boefjes/boefjes/sql/organisation_storage.py @@ -1,13 +1,14 @@ import logging +from collections.abc import Iterator from sqlalchemy.orm import Session from boefjes.config import Settings, settings -from boefjes.katalogus.models import Organisation -from boefjes.katalogus.storage.interfaces import OrganisationNotFound, OrganisationStorage -from boefjes.sql.db import ObjectNotFoundException +from boefjes.models import Organisation +from boefjes.sql.db import ObjectNotFoundException, session_managed_iterator from boefjes.sql.db_models import OrganisationInDB from boefjes.sql.session import SessionMixin +from boefjes.storage.interfaces import OrganisationNotFound, OrganisationStorage logger = logging.getLogger(__name__) @@ -66,3 +67,7 @@ def to_organisation(organisation_in_db: OrganisationInDB) -> Organisation: def create_organisation_storage(session) -> SQLOrganisationStorage: return SQLOrganisationStorage(session, settings) + + +def get_organisations_store() -> Iterator[OrganisationStorage]: + yield from session_managed_iterator(create_organisation_storage) diff --git a/boefjes/boefjes/sql/plugin_enabled_storage.py b/boefjes/boefjes/sql/plugin_enabled_storage.py deleted file mode 100644 index 6576a70c3e8..00000000000 --- a/boefjes/boefjes/sql/plugin_enabled_storage.py +++ /dev/null @@ -1,94 +0,0 @@ -import logging - -from sqlalchemy.orm import Session, sessionmaker - -from boefjes.config import Settings, settings -from boefjes.katalogus.storage.interfaces import OrganisationNotFound, PluginEnabledStorage, PluginStateNotFound -from boefjes.sql.db import ObjectNotFoundException, get_engine -from boefjes.sql.db_models import OrganisationInDB, PluginStateInDB -from boefjes.sql.session import SessionMixin - -logger = logging.getLogger(__name__) - - -class SQLPluginEnabledStorage(SessionMixin, PluginEnabledStorage): - def __init__(self, session: Session, app_settings: Settings): - self.app_settings = app_settings - - super().__init__(session) - - def create(self, plugin_id: str, enabled: bool, organisation_id: str) -> None: - logger.info( - "Saving plugin state for plugin %s for organisation %s", - plugin_id, - organisation_id, - ) - - plugin_state_in_db = self.to_plugin_state_in_db(plugin_id, enabled, organisation_id) - self.session.add(plugin_state_in_db) - - def get_by_id(self, plugin_id: str, organisation_id: str) -> bool: - instance = self._db_instance_by_id(plugin_id, organisation_id) - - return instance.enabled - - def get_all_enabled(self, organisation_id: str) -> list[str]: - query = ( - self.session.query(PluginStateInDB) - .join(OrganisationInDB) - .filter(PluginStateInDB.organisation_pk == OrganisationInDB.pk) - .filter(OrganisationInDB.id == organisation_id) - .filter(PluginStateInDB.enabled) - ) - - return [x.plugin_id for x in query.all()] - - def update_or_create_by_id(self, plugin_id: str, enabled: bool, organisation_id: str) -> None: - try: - instance = self._db_instance_by_id(plugin_id, organisation_id) - instance.enabled = enabled - except PluginStateNotFound: - logger.info("Plugin state not found, creating new instance") - self.create(plugin_id, enabled, organisation_id) - - def _db_instance_by_id(self, plugin_id: str, organisation_id: str) -> PluginStateInDB: - instance = ( - self.session.query(PluginStateInDB) - .join(OrganisationInDB) - .filter(PluginStateInDB.organisation_pk == OrganisationInDB.pk) - .filter(PluginStateInDB.plugin_id == plugin_id) - .filter(OrganisationInDB.id == organisation_id) - .first() - ) - - if instance is None: - raise PluginStateNotFound(plugin_id, organisation_id) from ObjectNotFoundException( - PluginStateInDB, - plugin_id=plugin_id, - organisation_id=organisation_id, - ) - - return instance - - def to_plugin_state_in_db(self, plugin_id: str, enabled: bool, organisation_id: str) -> PluginStateInDB: - organisation = self.session.query(OrganisationInDB).filter(OrganisationInDB.id == organisation_id).first() - - if organisation is None: - raise OrganisationNotFound(organisation_id) from ObjectNotFoundException( - OrganisationInDB, id=organisation_id - ) - - return PluginStateInDB( - plugin_id=plugin_id, - enabled=enabled, - organisation_pk=organisation.pk, - ) - - -def create_plugin_enabled_storage( - session: Session | None = None, -) -> SQLPluginEnabledStorage: - if not session: - session = sessionmaker(bind=get_engine())() - - return SQLPluginEnabledStorage(session, settings) diff --git a/boefjes/boefjes/sql/plugin_storage.py b/boefjes/boefjes/sql/plugin_storage.py index 4b76f4c0dc3..df368d92894 100644 --- a/boefjes/boefjes/sql/plugin_storage.py +++ b/boefjes/boefjes/sql/plugin_storage.py @@ -4,11 +4,11 @@ from sqlalchemy.orm import Session from boefjes.config import Settings, settings -from boefjes.katalogus.models import Boefje, Normalizer, PluginType -from boefjes.katalogus.storage.interfaces import PluginNotFound, PluginStorage +from boefjes.models import Boefje, Normalizer, PluginType from boefjes.sql.db import ObjectNotFoundException, session_managed_iterator from boefjes.sql.db_models import BoefjeInDB, NormalizerInDB from boefjes.sql.session import SessionMixin +from boefjes.storage.interfaces import NotAllowed, PluginNotFound, PluginStorage logger = logging.getLogger(__name__) @@ -41,8 +41,14 @@ def create_boefje(self, boefje: Boefje) -> None: self.session.add(boefje_in_db) def update_boefje(self, boefje_id: str, data: dict) -> None: + if not data: + return + instance = self._db_boefje_instance_by_id(boefje_id) + if instance.static: + raise NotAllowed(f"Plugin with id '{boefje_id}' is static, so updating it is not allowed") + for key, value in data.items(): setattr(instance, key, value) @@ -55,8 +61,14 @@ def create_normalizer(self, normalizer: Normalizer) -> None: self.session.add(normalizer_in_db) def update_normalizer(self, normalizer_id: str, data: dict) -> None: + if not data: + return + instance = self._db_normalizer_instance_by_id(normalizer_id) + if instance.static: + raise NotAllowed(f"Plugin with id '{normalizer_id}' is static, so updating it is not allowed") + for key, value in data.items(): setattr(instance, key, value) @@ -102,6 +114,7 @@ def to_boefje_in_db(boefje: Boefje) -> BoefjeInDB: oci_image=boefje.oci_image, oci_arguments=boefje.oci_arguments, version=boefje.version, + static=boefje.static, ) @staticmethod @@ -115,6 +128,7 @@ def to_normalizer_in_db(normalizer: Normalizer) -> NormalizerInDB: produces=normalizer.produces, environment_keys=normalizer.environment_keys, version=normalizer.version, + static=normalizer.static, ) @staticmethod @@ -132,7 +146,7 @@ def to_boefje(boefje_in_db: BoefjeInDB) -> Boefje: oci_image=boefje_in_db.oci_image, oci_arguments=boefje_in_db.oci_arguments, version=boefje_in_db.version, - static=False, + static=boefje_in_db.static, ) @staticmethod @@ -147,7 +161,7 @@ def to_normalizer(normalizer_in_db: NormalizerInDB) -> Normalizer: produces=normalizer_in_db.produces, environment_keys=normalizer_in_db.environment_keys, version=normalizer_in_db.version, - static=False, + static=normalizer_in_db.static, ) diff --git a/boefjes/boefjes/sql/session.py b/boefjes/boefjes/sql/session.py index acce70a827e..79aa1a79d0b 100644 --- a/boefjes/boefjes/sql/session.py +++ b/boefjes/boefjes/sql/session.py @@ -3,7 +3,7 @@ from sqlalchemy.exc import DatabaseError from sqlalchemy.orm import Session -from boefjes.katalogus.storage.interfaces import StorageError +from boefjes.storage.interfaces import StorageError logger = logging.getLogger(__name__) diff --git a/boefjes/boefjes/sql/setting_storage.py b/boefjes/boefjes/sql/setting_storage.py deleted file mode 100644 index cb09e551ad8..00000000000 --- a/boefjes/boefjes/sql/setting_storage.py +++ /dev/null @@ -1,79 +0,0 @@ -import json -import logging - -from sqlalchemy.orm import Session - -from boefjes.config import settings -from boefjes.katalogus.dependencies.encryption import EncryptMiddleware, IdentityMiddleware, NaclBoxMiddleware -from boefjes.katalogus.models import EncryptionMiddleware -from boefjes.katalogus.storage.interfaces import SettingsNotFound, SettingsStorage -from boefjes.sql.db import ObjectNotFoundException -from boefjes.sql.db_models import OrganisationInDB, SettingsInDB -from boefjes.sql.session import SessionMixin - -logger = logging.getLogger(__name__) - - -class SQLSettingsStorage(SessionMixin, SettingsStorage): - def __init__(self, session: Session, encryption: EncryptMiddleware): - self.encryption = encryption - - super().__init__(session) - - def upsert(self, values: dict, organisation_id: str, plugin_id: str) -> None: - encrypted_values = self.encryption.encode(json.dumps(values)) - - try: - instance = self._db_instance_by_id(organisation_id, plugin_id) - instance.values = encrypted_values - except SettingsNotFound: - organisation = self.session.query(OrganisationInDB).filter(OrganisationInDB.id == organisation_id).first() - - setting_in_db = SettingsInDB( - values=encrypted_values, - plugin_id=plugin_id, - organisation_pk=organisation.pk, - ) - self.session.add(setting_in_db) - - def get_all(self, organisation_id: str, plugin_id: str) -> dict: - try: - instance = self._db_instance_by_id(organisation_id, plugin_id) - except SettingsNotFound: - return {} - - return json.loads(self.encryption.decode(instance.values)) - - def delete(self, organisation_id: str, plugin_id: str) -> None: - instance = self._db_instance_by_id(organisation_id, plugin_id) - - self.session.delete(instance) - - def _db_instance_by_id(self, organisation_id: str, plugin_id: str) -> SettingsInDB: - instance = ( - self.session.query(SettingsInDB) - .join(OrganisationInDB) - .filter(SettingsInDB.plugin_id == plugin_id) - .filter(SettingsInDB.organisation_pk == OrganisationInDB.pk) - .filter(OrganisationInDB.id == organisation_id) - .first() - ) - - if instance is None: - raise SettingsNotFound(organisation_id, plugin_id) from ObjectNotFoundException( - SettingsInDB, organisation_id=organisation_id - ) - - return instance - - -def create_setting_storage(session) -> SettingsStorage: - encrypter = create_encrypter() - return SQLSettingsStorage(session, encrypter) - - -def create_encrypter(): - if settings.encryption_middleware == EncryptionMiddleware.NACL_SEALBOX: - return NaclBoxMiddleware(settings.katalogus_private_key, settings.katalogus_public_key) - - return IdentityMiddleware() diff --git a/boefjes/boefjes/katalogus/dependencies/__init__.py b/boefjes/boefjes/storage/__init__.py similarity index 100% rename from boefjes/boefjes/katalogus/dependencies/__init__.py rename to boefjes/boefjes/storage/__init__.py diff --git a/boefjes/boefjes/katalogus/storage/interfaces.py b/boefjes/boefjes/storage/interfaces.py similarity index 78% rename from boefjes/boefjes/katalogus/storage/interfaces.py rename to boefjes/boefjes/storage/interfaces.py index 86bbfaba62b..ff19ca7c9f8 100644 --- a/boefjes/boefjes/katalogus/storage/interfaces.py +++ b/boefjes/boefjes/storage/interfaces.py @@ -1,6 +1,6 @@ from abc import ABC -from boefjes.katalogus.models import Boefje, Normalizer, Organisation, PluginType +from boefjes.models import Boefje, Normalizer, Organisation, PluginType class StorageError(Exception): @@ -37,14 +37,23 @@ def __init__(self, plugin_id: str, organisation_id: str): super().__init__(f"State for plugin with id '{plugin_id}' not found for organisation '{organisation_id}'") -class ExistingPluginId(StorageError): +class ConfigNotFound(NotFound): + def __init__(self, organisation_id: str, plugin_id: str): + super().__init__(f"Setting not found for organisation '{organisation_id}' and plugin '{plugin_id}'") + + +class NotAllowed(StorageError): + """Generic exception for operations that are not allowed at a domain level""" + + +class CannotUpdateStaticPlugin(NotAllowed): def __init__(self, plugin_id: str): - super().__init__(f"Plugin id '{plugin_id}' is already used") + super().__init__(f"Plugin with id '{plugin_id}' is static, so updating it is not allowed") -class SettingsNotFound(NotFound): - def __init__(self, organisation_id: str, plugin_id: str): - super().__init__(f"Setting not found for organisation '{organisation_id}' and plugin '{plugin_id}'") +class ExistingPluginId(NotAllowed): + def __init__(self, plugin_id: str): + super().__init__(f"Plugin id '{plugin_id}' is already used") class OrganisationStorage(ABC): @@ -102,38 +111,26 @@ def delete_normalizer_by_id(self, normalizer_id: str) -> None: raise NotImplementedError -class SettingsStorage(ABC): +class ConfigStorage(ABC): def __enter__(self): return self def __exit__(self, exc_type: type[Exception], exc_value: str, exc_traceback: str) -> None: # noqa: F841 pass - def get_all(self, organisation_id: str, plugin_id: str) -> dict[str, str]: + def get_all_settings(self, organisation_id: str, plugin_id: str) -> dict[str, str]: raise NotImplementedError - def upsert(self, values: dict, organisation_id: str, plugin_id: str) -> None: + def upsert( + self, organisation_id: str, plugin_id: str, settings: dict | None = None, enabled: bool | None = None + ) -> None: raise NotImplementedError def delete(self, organisation_id: str, plugin_id: str) -> None: raise NotImplementedError - -class PluginEnabledStorage(ABC): - def __enter__(self): - return self - - def __exit__(self, exc_type: type[Exception], exc_value: str, exc_traceback: str) -> None: # noqa: F841 - pass - - def get_by_id(self, plugin_id: str, organisation_id: str) -> bool: - raise NotImplementedError - - def get_all_enabled(self, organisation_id: str) -> list[str]: - raise NotImplementedError - - def create(self, plugin_id: str, enabled: bool, organisation_id: str) -> None: + def is_enabled_by_id(self, plugin_id: str, organisation_id: str) -> bool: raise NotImplementedError - def update_or_create_by_id(self, plugin_id: str, enabled: bool, organisation_id: str) -> None: + def get_enabled_boefjes(self, organisation_id: str) -> list[str]: raise NotImplementedError diff --git a/boefjes/boefjes/storage/memory.py b/boefjes/boefjes/storage/memory.py new file mode 100644 index 00000000000..df14785c240 --- /dev/null +++ b/boefjes/boefjes/storage/memory.py @@ -0,0 +1,125 @@ +from boefjes.models import Boefje, Normalizer, Organisation, PluginType +from boefjes.storage.interfaces import ConfigStorage, OrganisationStorage, PluginNotFound, PluginStorage + +# key = organisation id; value = organisation +organisations: dict[str, Organisation] = {} + +# key = organisation, repository/plugin id; value = enabled/ disabled +plugins_state: dict[str, dict[str, bool]] = {} + + +class OrganisationStorageMemory(OrganisationStorage): + def __init__(self, defaults: dict[str, Organisation] | None = None): + self._data = organisations if defaults is None else defaults + + def get_by_id(self, organisation_id: str) -> Organisation: + return self._data[organisation_id] + + def get_all(self) -> dict[str, Organisation]: + return self._data + + def create(self, organisation: Organisation) -> None: + self._data[organisation.id] = organisation + + def delete_by_id(self, organisation_id: str) -> None: + del self._data[organisation_id] + + +class PluginStorageMemory(PluginStorage): + def __init__(self): + self._boefjes = {} + self._normalizers = {} + + def get_all(self) -> list[PluginType]: + return list(self._boefjes.values()) + list(self._normalizers.values()) + + def boefje_by_id(self, boefje_id: str) -> Boefje: + if boefje_id not in self._boefjes: + raise PluginNotFound(boefje_id) + + return self._boefjes[boefje_id] + + def normalizer_by_id(self, normalizer_id: str) -> Normalizer: + if normalizer_id not in self._normalizers: + raise PluginNotFound(normalizer_id) + + return self._normalizers[normalizer_id] + + def create_boefje(self, boefje: Boefje) -> None: + self._boefjes[boefje.id] = boefje + + def create_normalizer(self, normalizer: Normalizer) -> None: + self._normalizers[normalizer.id] = normalizer + + def update_boefje(self, boefje_id: str, data: dict) -> None: + if not data: + return + + if boefje_id not in self._boefjes: + raise PluginNotFound(boefje_id) + + boefje = self._boefjes[boefje_id] + + for key, value in data.items(): + setattr(boefje, key, value) + + def update_normalizer(self, normalizer_id: str, data: dict) -> None: + if not data: + return + + if normalizer_id not in self._normalizers: + raise PluginNotFound(normalizer_id) + + normalizer = self._normalizers[normalizer_id] + + for key, value in data.items(): + setattr(normalizer, key, value) + + def delete_boefje_by_id(self, boefje_id: str) -> None: + del self._boefjes[boefje_id] + + def delete_normalizer_by_id(self, normalizer_id: str) -> None: + del self._normalizers[normalizer_id] + + +class ConfigStorageMemory(ConfigStorage): + def __init__(self): + self._data = {} + self._enabled = {} + + def get_all_settings(self, organisation_id: str, plugin_id: str) -> dict[str, str]: + if organisation_id not in self._data: + return {} + + return self._data[organisation_id].get(plugin_id, {}) + + def upsert( + self, organisation_id: str, plugin_id: str, settings: dict | None = None, enabled: bool | None = None + ) -> None: + self._data.setdefault(organisation_id, {}) + self._data[organisation_id].setdefault(plugin_id, {}) + self._enabled.setdefault(organisation_id, {}) + + if settings is not None: + self._data[organisation_id][plugin_id] = settings + + if enabled is not None: + self._enabled[organisation_id][plugin_id] = enabled + + return + + def delete(self, organisation_id: str, plugin_id: str) -> None: + del self._data[organisation_id][plugin_id] + + def is_enabled_by_id(self, plugin_id: str, organisation_id: str) -> bool: + if organisation_id not in self._enabled or plugin_id not in self._enabled[organisation_id]: + raise PluginNotFound(plugin_id) + + return self._enabled[organisation_id][plugin_id] + + def get_enabled_boefjes(self, organisation_id: str) -> list[str]: + return [ + plugin_id + for plugin_id, enabled in self._enabled.get(organisation_id, {}).items() + if enabled and "norm" not in plugin_id + ] diff --git a/boefjes/debian/kat-boefjes.kat-katalogus.service b/boefjes/debian/kat-boefjes.kat-katalogus.service index 6991822b4c6..2b6a3445898 100644 --- a/boefjes/debian/kat-boefjes.kat-katalogus.service +++ b/boefjes/debian/kat-boefjes.kat-katalogus.service @@ -13,7 +13,7 @@ ExecStart=/opt/venvs/kat-boefjes/bin/python -m gunicorn \ --access-logfile - \ -c /etc/kat/katalogus.gunicorn.conf.py \ -k uvicorn.workers.UvicornWorker \ - boefjes.katalogus.api.root:app + boefjes.katalogus.root:app Restart=on-failure RestartSec=3s KillMode=mixed diff --git a/boefjes/entrypoint.sh b/boefjes/entrypoint.sh index 3068bf3b1d0..eaa8fa66f69 100755 --- a/boefjes/entrypoint.sh +++ b/boefjes/entrypoint.sh @@ -17,7 +17,7 @@ if [ "$DATABASE_MIGRATION" = "1" ] || [[ $DATABASE_MIGRATION == "true" ]]; then fi if [ "$1" = "katalogus" ]; then - exec python -m uvicorn --host 0.0.0.0 boefjes.katalogus.api.root:app + exec python -m uvicorn --host 0.0.0.0 boefjes.katalogus.root:app fi exec "$@" diff --git a/boefjes/boefjes/katalogus/storage/__init__.py b/boefjes/tests/integration/__init__.py similarity index 100% rename from boefjes/boefjes/katalogus/storage/__init__.py rename to boefjes/tests/integration/__init__.py diff --git a/boefjes/boefjes/katalogus/tests/integration/test_api.py b/boefjes/tests/integration/test_api.py similarity index 90% rename from boefjes/boefjes/katalogus/tests/integration/test_api.py rename to boefjes/tests/integration/test_api.py index e54a91514c6..40ec2b35bd0 100644 --- a/boefjes/boefjes/katalogus/tests/integration/test_api.py +++ b/boefjes/tests/integration/test_api.py @@ -6,13 +6,12 @@ from starlette.testclient import TestClient from boefjes.config import settings -from boefjes.katalogus.api.root import app -from boefjes.katalogus.dependencies.encryption import IdentityMiddleware -from boefjes.katalogus.models import Boefje, Normalizer, Organisation +from boefjes.dependencies.encryption import IdentityMiddleware +from boefjes.katalogus.root import app +from boefjes.models import Boefje, Normalizer, Organisation +from boefjes.sql.config_storage import SQLConfigStorage from boefjes.sql.db import SQL_BASE, get_engine from boefjes.sql.organisation_storage import SQLOrganisationStorage -from boefjes.sql.plugin_enabled_storage import SQLPluginEnabledStorage -from boefjes.sql.setting_storage import SQLSettingsStorage @skipIf(os.environ.get("CI") != "1", "Needs a CI database.") @@ -22,8 +21,7 @@ def setUp(self) -> None: session = sessionmaker(bind=get_engine())() self.organisation_storage = SQLOrganisationStorage(session, settings) - self.settings_storage = SQLSettingsStorage(session, IdentityMiddleware()) - self.plugin_state_storage = SQLPluginEnabledStorage(session, settings) + self.settings_storage = SQLConfigStorage(session, IdentityMiddleware()) self.org = Organisation(id="test", name="Test Organisation") self.client = TestClient(app) @@ -59,12 +57,12 @@ def test_filter_plugins(self): def test_cannot_add_plugin_reserved_id(self): boefje = Boefje(id="dns-records", name="My test boefje", static=False) response = self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=boefje.json()) - self.assertEqual(response.status_code, 500) + self.assertEqual(response.status_code, 400) self.assertEqual(response.json(), {"message": "Plugin id 'dns-records' is already used"}) normalizer = Normalizer(id="kat_nmap_normalize", name="My test normalizer", static=False) response = self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=normalizer.json()) - self.assertEqual(response.status_code, 500) + self.assertEqual(response.status_code, 400) self.assertEqual(response.json(), {"message": "Plugin id 'kat_nmap_normalize' is already used"}) def test_add_boefje(self): @@ -144,6 +142,17 @@ def test_update_plugins(self): response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/{normalizer.id}") self.assertEqual(response.json()["version"], "v1.2") + def test_cannot_update_static_plugins(self): + self.client.patch(f"/v1/organisations/{self.org.id}/plugins/dns-records", json={"enabled": True}) + response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/dns-records") + self.assertTrue(response.json()["enabled"]) + + response = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/dns-records", json={"version": "v1.2"}) + self.assertEqual(response.status_code, 400) + + response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/dns-records") + self.assertNotEqual(response.json()["version"], "v1.2") + def test_basic_settings_api(self): plug = "dns-records" diff --git a/boefjes/boefjes/katalogus/tests/integration/test_json_settings_encryption_migration.py b/boefjes/tests/integration/test_json_settings_encryption_migration.py similarity index 69% rename from boefjes/boefjes/katalogus/tests/integration/test_json_settings_encryption_migration.py rename to boefjes/tests/integration/test_json_settings_encryption_migration.py index 063db20e436..a3bb9a336bd 100644 --- a/boefjes/boefjes/katalogus/tests/integration/test_json_settings_encryption_migration.py +++ b/boefjes/tests/integration/test_json_settings_encryption_migration.py @@ -6,11 +6,11 @@ from sqlalchemy.orm import sessionmaker from boefjes.config import settings -from boefjes.katalogus.dependencies.encryption import NaclBoxMiddleware -from boefjes.katalogus.models import Organisation +from boefjes.dependencies.encryption import NaclBoxMiddleware +from boefjes.models import Organisation +from boefjes.sql.config_storage import create_encrypter from boefjes.sql.db import SQL_BASE, get_engine from boefjes.sql.organisation_storage import SQLOrganisationStorage -from boefjes.sql.setting_storage import SQLSettingsStorage, create_encrypter @skipIf(os.environ.get("CI") != "1", "Needs a CI database.") @@ -38,11 +38,16 @@ def test_setting_to_settings_json(self): alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "cd34fdfafdaf"]) - settings_storage = SQLSettingsStorage(session, encrypter) - assert settings_storage.get_all("dev1", "test-plugin1") == {"key1": "val1", "key3": "val3"} - assert settings_storage.get_all("dev1", "test-plugin2") == {"key5": "val5", "key7": "val7"} - assert settings_storage.get_all("dev2", "test-plugin1") == {"key2": "val2"} - assert settings_storage.get_all("dev3", "test-plugin1") == {} + all_settings = list(self.engine.execute(text("select * from settings")).fetchall()) + self.assertSetEqual( + {(encrypter.decode(x[1]), x[2], x[3]) for x in all_settings}, + { + ('{"key2": "val2"}', "dns-records", 2), + ('{"key5": "val5", "key7": "val7"}', "nmap", 1), + ('{"key4": "val4", "key6": "val6"}', "nmap", 2), + ('{"key1": "val1", "key3": "val3"}', "dns-records", 1), + }, + ) session.close() alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "-1"]) @@ -67,11 +72,11 @@ def tearDown(self) -> None: @staticmethod def _collect_entries(encrypter: NaclBoxMiddleware): return [ - ("key1", encrypter.encode("val1"), 1, "test-plugin1"), - ("key2", encrypter.encode("val2"), 2, "test-plugin1"), - ("key3", encrypter.encode("val3"), 1, "test-plugin1"), - ("key4", encrypter.encode("val4"), 2, "test-plugin2"), - ("key5", encrypter.encode("val5"), 1, "test-plugin2"), - ("key6", encrypter.encode("val6"), 2, "test-plugin2"), - ("key7", encrypter.encode("val7"), 1, "test-plugin2"), + ("key1", encrypter.encode("val1"), 1, "dns-records"), + ("key2", encrypter.encode("val2"), 2, "dns-records"), + ("key3", encrypter.encode("val3"), 1, "dns-records"), + ("key4", encrypter.encode("val4"), 2, "nmap"), + ("key5", encrypter.encode("val5"), 1, "nmap"), + ("key6", encrypter.encode("val6"), 2, "nmap"), + ("key7", encrypter.encode("val7"), 1, "nmap"), ] diff --git a/boefjes/boefjes/katalogus/tests/integration/test_remove_repository_migration.py b/boefjes/tests/integration/test_remove_repository_migration.py similarity index 81% rename from boefjes/boefjes/katalogus/tests/integration/test_remove_repository_migration.py rename to boefjes/tests/integration/test_remove_repository_migration.py index 33353cae4a3..dd2ee7c8034 100644 --- a/boefjes/boefjes/katalogus/tests/integration/test_remove_repository_migration.py +++ b/boefjes/tests/integration/test_remove_repository_migration.py @@ -6,10 +6,9 @@ from sqlalchemy.orm import sessionmaker from boefjes.config import settings -from boefjes.katalogus.models import Organisation +from boefjes.models import Organisation from boefjes.sql.db import SQL_BASE, get_engine from boefjes.sql.organisation_storage import SQLOrganisationStorage -from boefjes.sql.plugin_enabled_storage import SQLPluginEnabledStorage @skipIf(os.environ.get("CI") != "1", "Needs a CI database.") @@ -71,10 +70,8 @@ def test_fail_on_non_unique(self): alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "7c88b9cd96aa"]) - with SQLPluginEnabledStorage(session, settings) as storage: - assert storage.get_by_id("test_plugin_id", "dev1") - assert storage.get_all_enabled("dev1") == ["test_plugin_id"] - assert storage.get_all_enabled("dev2") == [] + all_plugin_states = [x[1:] for x in self.engine.execute(text("SELECT * FROM plugin_state")).fetchall()] + assert all_plugin_states == [("test_plugin_id", True, 1)] session.close() @@ -85,18 +82,17 @@ def test_downgrade(self): alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "7c88b9cd96aa"]) alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "-1"]) - # Same checks plus check if a repository exists - with SQLPluginEnabledStorage(session, settings) as storage: - assert storage.get_by_id("test_plugin_id", "dev1") - assert storage.get_all_enabled("dev1") == ["test_plugin_id"] - assert storage.get_all_enabled("dev2") == [] - assert self.engine.execute(text("SELECT * from repository")).fetchall() == [ - (1, "LOCAL", "Local Plugin Repository", "http://dev/null") - ] + all_plugin_states = [x[1:] for x in self.engine.execute(text("SELECT * FROM plugin_state")).fetchall()] + assert all_plugin_states == [("test_plugin_id", True, 1, 1)] + assert self.engine.execute(text("SELECT * from repository")).fetchall() == [ + (1, "LOCAL", "Local Plugin Repository", "http://dev/null") + ] session.close() def tearDown(self) -> None: + self.engine.execute(text("DELETE FROM plugin_state")) # Fix unique constraint fails + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) session = sessionmaker(bind=get_engine())() diff --git a/boefjes/tests/integration/test_settings_to_boefje_config_migration.py b/boefjes/tests/integration/test_settings_to_boefje_config_migration.py new file mode 100644 index 00000000000..a646eae23dd --- /dev/null +++ b/boefjes/tests/integration/test_settings_to_boefje_config_migration.py @@ -0,0 +1,102 @@ +import os +from unittest import TestCase, skipIf + +import alembic.config +from sqlalchemy import text +from sqlalchemy.orm import sessionmaker + +from boefjes.config import settings +from boefjes.models import Organisation +from boefjes.sql.config_storage import SQLConfigStorage, create_encrypter +from boefjes.sql.db import SQL_BASE, get_engine +from boefjes.sql.organisation_storage import SQLOrganisationStorage +from boefjes.sql.plugin_storage import SQLPluginStorage + + +@skipIf(os.environ.get("CI") != "1", "Needs a CI database.") +class TestSettingsToBoefjeConfig(TestCase): + def setUp(self) -> None: + self.engine = get_engine() + + # To reset autoincrement ids + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "base"]) + # Set state to revision 6f99834a4a5a + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "6f99834a4a5a"]) + + session = sessionmaker(bind=self.engine)() + + with SQLOrganisationStorage(session, settings) as storage: + storage.create(Organisation(id="dev1", name="Test 1 ")) + storage.create(Organisation(id="dev2", name="Test 2 ")) + + encrypter = create_encrypter() + entries = [ + (1, encrypter.encode('{"key1": "val1"}'), "dns-records", 1), + (2, encrypter.encode('{"key1": "val1", "key2": "val2"}'), "dns-records", 2), + (3, encrypter.encode('{"key2": "val2", "key3": "val3"}'), "nmap", 1), + ] + query = f"INSERT INTO settings (id, values, plugin_id, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 + self.engine.execute(text(query)) + session.close() + + def test_fail_on_wrong_plugin_ids(self): + session = sessionmaker(bind=self.engine)() + + encrypter = create_encrypter() + entries = [ + (4, encrypter.encode('{"key2": "val2", "key3": "val3"}'), "test-unknown-plugin-id", 1), + (5, encrypter.encode('{"key1": "val1"}'), "kat_nmap_normalize", 2), + ] + query = f"INSERT INTO settings (id, values, plugin_id, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 + self.engine.execute(text(query)) + + with self.assertRaises(Exception) as ctx: + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) + + assert "Settings for normalizer or bit found: kat_nmap_normalize" in str(ctx.exception) + + self.engine.execute(text("DELETE FROM settings WHERE id = 5")) # Fix normalizer setting + + with self.assertRaises(Exception) as ctx: + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) + + assert "Invalid plugin id found: test-unknown-plugin-id" in str(ctx.exception) + + self.engine.execute(text("DELETE FROM settings WHERE id = 4")) # Fix unknown plugin + + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) + + assert SQLPluginStorage(session, settings).boefje_by_id("dns-records").id == "dns-records" + + settings_storage = SQLConfigStorage(session, encrypter) + assert settings_storage.get_all_settings("dev1", "dns-records") == {"key1": "val1"} + assert settings_storage.get_all_settings("dev2", "dns-records") == {"key1": "val1", "key2": "val2"} + + session.close() + + def test_downgrade(self): + # No need to also create a Boefje entry, the seeded settings and migrations take care of that and + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "-1"]) + + encrypter = create_encrypter() + all_settings = list(self.engine.execute(text("select * from settings")).fetchall()) + self.assertSetEqual( + {(encrypter.decode(x[1]), x[2], x[3]) for x in all_settings}, + { + ('{"key1": "val1"}', "dns-records", 1), + ('{"key1": "val1", "key2": "val2"}', "dns-records", 2), + ('{"key2": "val2", "key3": "val3"}', "nmap", 1), + }, + ) + + def tearDown(self) -> None: + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) + + session = sessionmaker(bind=get_engine())() + + for table in SQL_BASE.metadata.tables: + session.execute(f"DELETE FROM {table} CASCADE") # noqa: S608 + + session.commit() + session.close() diff --git a/boefjes/boefjes/katalogus/tests/integration/test_sql_repositories.py b/boefjes/tests/integration/test_sql_repositories.py similarity index 72% rename from boefjes/boefjes/katalogus/tests/integration/test_sql_repositories.py rename to boefjes/tests/integration/test_sql_repositories.py index 319a4ed2f1d..ad4f804ad10 100644 --- a/boefjes/boefjes/katalogus/tests/integration/test_sql_repositories.py +++ b/boefjes/tests/integration/test_sql_repositories.py @@ -6,19 +6,12 @@ from sqlalchemy.orm import sessionmaker from boefjes.config import settings -from boefjes.katalogus.models import Boefje, Normalizer, Organisation -from boefjes.katalogus.storage.interfaces import ( - OrganisationNotFound, - PluginNotFound, - PluginStateNotFound, - SettingsNotFound, - StorageError, -) +from boefjes.models import Boefje, Normalizer, Organisation +from boefjes.sql.config_storage import SQLConfigStorage, create_encrypter from boefjes.sql.db import SQL_BASE, get_engine from boefjes.sql.organisation_storage import SQLOrganisationStorage -from boefjes.sql.plugin_enabled_storage import SQLPluginEnabledStorage from boefjes.sql.plugin_storage import SQLPluginStorage -from boefjes.sql.setting_storage import SQLSettingsStorage, create_encrypter +from boefjes.storage.interfaces import ConfigNotFound, OrganisationNotFound, PluginNotFound, StorageError @skipIf(os.environ.get("CI") != "1", "Needs a CI database.") @@ -28,8 +21,7 @@ def setUp(self) -> None: session = sessionmaker(bind=get_engine())() self.organisation_storage = SQLOrganisationStorage(session, settings) - self.settings_storage = SQLSettingsStorage(session, create_encrypter()) - self.plugin_state_storage = SQLPluginEnabledStorage(session, settings) + self.config_storage = SQLConfigStorage(session, create_encrypter()) self.plugin_storage = SQLPluginStorage(session, settings) def tearDown(self) -> None: @@ -64,45 +56,55 @@ def test_settings_storage(self): organisation_id = "test" plugin_id = 64 * "a" + with self.plugin_storage as storage: + storage.create_boefje(Boefje(id=plugin_id, name="Test")) + org = Organisation(id=organisation_id, name="Test") with self.organisation_storage as storage: storage.create(org) - with self.settings_storage as settings_storage: - settings_storage.upsert({"TEST_SETTING": "123.9", "TEST_SETTING2": 12}, organisation_id, plugin_id) + with self.config_storage as settings_storage: + settings_storage.upsert(organisation_id, plugin_id, {"TEST_SETTING": "123.9", "TEST_SETTING2": 12}) - with self.settings_storage as settings_storage: - settings_storage.upsert({"TEST_SETTING": "123.9", "TEST_SETTING2": 13}, organisation_id, plugin_id) + with self.config_storage as settings_storage: + settings_storage.upsert(organisation_id, plugin_id, {"TEST_SETTING": "123.9", "TEST_SETTING2": 13}) - returned_settings = settings_storage.get_all(organisation_id, plugin_id) + returned_settings = settings_storage.get_all_settings(organisation_id, plugin_id) self.assertEqual("123.9", returned_settings["TEST_SETTING"]) self.assertEqual(13, returned_settings["TEST_SETTING2"]) - with self.assertRaises(SettingsNotFound): + with self.assertRaises(ConfigNotFound): settings_storage.delete("no organisation!", plugin_id) - self.assertEqual({"TEST_SETTING": "123.9", "TEST_SETTING2": 13}, settings_storage.get_all(org.id, plugin_id)) - self.assertEqual(dict(), settings_storage.get_all(org.id, "wrong")) - self.assertEqual(dict(), settings_storage.get_all("wrong", plugin_id)) + self.assertEqual( + {"TEST_SETTING": "123.9", "TEST_SETTING2": 13}, settings_storage.get_all_settings(org.id, plugin_id) + ) + self.assertEqual(dict(), settings_storage.get_all_settings(org.id, "wrong")) + self.assertEqual(dict(), settings_storage.get_all_settings("wrong", plugin_id)) - with self.settings_storage as settings_storage: + with self.config_storage as settings_storage: settings_storage.delete(org.id, plugin_id) - self.assertEqual(dict(), settings_storage.get_all(org.id, plugin_id)) + self.assertEqual(dict(), settings_storage.get_all_settings(org.id, plugin_id)) - with self.assertRaises(StorageError), self.settings_storage as settings_storage: - settings_storage.upsert({"TEST_SETTING": "123.9"}, organisation_id, 65 * "a") + with self.assertRaises(StorageError), self.config_storage as settings_storage: + settings_storage.upsert(organisation_id, 65 * "a", {"TEST_SETTING": "123.9"}) def test_settings_storage_values_field_limits(self): organisation_id = "test" plugin_id = 64 * "a" + with self.plugin_storage as storage: + storage.create_boefje(Boefje(id=plugin_id, name="Test")) + org = Organisation(id=organisation_id, name="Test") with self.organisation_storage as storage: storage.create(org) - with self.settings_storage as settings_storage: + with self.config_storage as settings_storage: settings_storage.upsert( + organisation_id, + plugin_id, { "TEST_SETTING": 12 * "123.9", "TEST_SETTING2": 12000, @@ -111,8 +113,6 @@ def test_settings_storage_values_field_limits(self): "TEST_SETTING5": 10 * "b", "TEST_SETTING6": 123456789, }, - organisation_id, - plugin_id, ) self.assertEqual( @@ -124,7 +124,7 @@ def test_settings_storage_values_field_limits(self): "TEST_SETTING5": 10 * "b", "TEST_SETTING6": 123456789, }, - settings_storage.get_all(org.id, plugin_id), + settings_storage.get_all_settings(org.id, plugin_id), ) def test_plugin_enabled_storage(self): @@ -132,34 +132,38 @@ def test_plugin_enabled_storage(self): org = Organisation(id="test", name="Test") storage.create(org) - with self.plugin_state_storage as plugin_state_storage: - plugin = Boefje( - id="test-boefje-1", - name="Test Boefje 1", - version="0.1", - consumes={"WebPage"}, - produces=["text/html"], - enabled=True, - ) - plugin_state_storage.create(plugin.id, plugin.enabled, org.id) + plugin = Boefje( + id="test-boefje-1", + name="Test Boefje 1", + version="0.1", + consumes={"WebPage"}, + produces=["text/html"], + enabled=True, + ) + + with self.plugin_storage as storage: + storage.create_boefje(plugin) + + with self.config_storage as storage: + storage.upsert(org.id, plugin.id, enabled=plugin.enabled) - returned_state = plugin_state_storage.get_by_id(plugin.id, org.id) + returned_state = storage.is_enabled_by_id(plugin.id, org.id) self.assertTrue(returned_state) - with self.plugin_state_storage as plugin_state_storage: - plugin_state_storage.update_or_create_by_id(plugin.id, False, org.id) + with self.config_storage as storage: + storage.upsert(org.id, plugin.id, enabled=False) - returned_state = plugin_state_storage.get_by_id(plugin.id, org.id) + returned_state = storage.is_enabled_by_id(plugin.id, org.id) self.assertFalse(returned_state) - with self.assertRaises(PluginStateNotFound): - plugin_state_storage.get_by_id("wrong", org.id) + with self.assertRaises(ConfigNotFound): + storage.is_enabled_by_id("wrong", org.id) - with self.assertRaises(PluginStateNotFound): - plugin_state_storage.get_by_id("wrong", org.id) + with self.assertRaises(ConfigNotFound): + storage.is_enabled_by_id("wrong", org.id) - with self.assertRaises(PluginStateNotFound): - plugin_state_storage.get_by_id(plugin.id, "wrong") + with self.assertRaises(ConfigNotFound): + storage.is_enabled_by_id(plugin.id, "wrong") def test_bare_boefje_storage(self): boefje = Boefje(id="test_boefje", name="Test", static=False) diff --git a/boefjes/boefjes/katalogus/tests/__init__.py b/boefjes/tests/katalogus/__init__.py similarity index 100% rename from boefjes/boefjes/katalogus/tests/__init__.py rename to boefjes/tests/katalogus/__init__.py diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/__init__.py b/boefjes/tests/katalogus/boefjes_test_dir/__init__.py similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/__init__.py rename to boefjes/tests/katalogus/boefjes_test_dir/__init__.py diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/__init__.py b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/__init__.py similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/__init__.py rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/__init__.py diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/boefje.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/boefje.json similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/boefje.json rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/boefje.json diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/__init__.py b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/__init__.py similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/__init__.py rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/__init__.py diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/boefje.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/boefje.json similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/boefje.json rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/boefje.json diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/__init__.py b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/__init__.py similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/__init__.py rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/__init__.py diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalize.py b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalize.py similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalize.py rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalize.py diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalizer.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalizer.json similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalizer.json rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalizer.json diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/main.py b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/main.py similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/main.py rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/main.py diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/schema.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/schema.json similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_2/schema.json rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/schema.json diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_4/__init__.py b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/__init__.py similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_4/__init__.py rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/__init__.py diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_4/boefje.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/boefje.json similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_4/boefje.json rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/boefje.json diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_4/schema.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/schema.json similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/kat_test_4/schema.json rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/schema.json diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/main.py b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/main.py similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/main.py rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/main.py diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/normalize.py b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalize.py similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/normalize.py rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalize.py diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/normalizer.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalizer.json similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/normalizer.json rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalizer.json diff --git a/boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/schema.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/schema.json similarity index 100% rename from boefjes/boefjes/katalogus/tests/boefjes_test_dir/kat_test/schema.json rename to boefjes/tests/katalogus/boefjes_test_dir/kat_test/schema.json diff --git a/boefjes/boefjes/katalogus/tests/test_organisation_api.py b/boefjes/tests/katalogus/test_organisation_api.py similarity index 86% rename from boefjes/boefjes/katalogus/tests/test_organisation_api.py rename to boefjes/tests/katalogus/test_organisation_api.py index 54fb7310c61..4f2c7364aa9 100644 --- a/boefjes/boefjes/katalogus/tests/test_organisation_api.py +++ b/boefjes/tests/katalogus/test_organisation_api.py @@ -3,10 +3,10 @@ from fastapi.testclient import TestClient -from boefjes.katalogus.api.root import app -from boefjes.katalogus.dependencies.organisations import get_organisations_store -from boefjes.katalogus.models import Organisation -from boefjes.katalogus.storage.memory import OrganisationStorageMemory +from boefjes.katalogus.root import app +from boefjes.models import Organisation +from boefjes.sql.organisation_storage import get_organisations_store +from boefjes.storage.memory import OrganisationStorageMemory class TestOrganisations(TestCase): diff --git a/boefjes/boefjes/katalogus/tests/test_plugin_service.py b/boefjes/tests/katalogus/test_plugin_service.py similarity index 81% rename from boefjes/boefjes/katalogus/tests/test_plugin_service.py rename to boefjes/tests/katalogus/test_plugin_service.py index 62a6a8c55bb..a86b4aa6fbf 100644 --- a/boefjes/boefjes/katalogus/tests/test_plugin_service.py +++ b/boefjes/tests/katalogus/test_plugin_service.py @@ -1,21 +1,20 @@ from unittest import TestCase from boefjes.config import BASE_DIR -from boefjes.katalogus.dependencies.plugins import PluginService -from boefjes.katalogus.local_repository import LocalPluginRepository -from boefjes.katalogus.storage.interfaces import SettingsNotConformingToSchema -from boefjes.katalogus.storage.memory import PluginStatesStorageMemory, PluginStorageMemory, SettingsStorageMemory +from boefjes.dependencies.plugins import PluginService +from boefjes.local_repository import LocalPluginRepository +from boefjes.storage.interfaces import SettingsNotConformingToSchema +from boefjes.storage.memory import ConfigStorageMemory, PluginStorageMemory def mock_plugin_service(organisation_id: str) -> PluginService: - storage = SettingsStorageMemory() - storage.upsert({"DUMMY_VAR": "123"}, "test", "test_plugin") + storage = ConfigStorageMemory() + storage.upsert("test", "test_plugin", {"DUMMY_VAR": "123"}) - test_boefjes_dir = BASE_DIR / "katalogus" / "tests" / "boefjes_test_dir" + test_boefjes_dir = BASE_DIR.parent / "tests" / "katalogus" / "boefjes_test_dir" return PluginService( PluginStorageMemory(), - PluginStatesStorageMemory(organisation_id), storage, LocalPluginRepository(test_boefjes_dir), ) @@ -65,11 +64,11 @@ def test_update_by_id_bad_schema(self): ) self.assertEqual(ctx.exception.message, msg) - self.service.settings_storage.upsert({"api_key": 128 * "a"}, self.organisation, plugin_id) + self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": 128 * "a"}) self.service.set_enabled_by_id(plugin_id, self.organisation, True) value = 129 * "a" - self.service.settings_storage.upsert({"api_key": 129 * "a"}, self.organisation, plugin_id) + self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": 129 * "a"}) with self.assertRaises(SettingsNotConformingToSchema) as ctx: self.service.set_enabled_by_id(plugin_id, self.organisation, True) @@ -97,7 +96,7 @@ def test_get_schema(self): def test_removing_mandatory_setting_disables_plugin(self): plugin_id = "kat_test" - self.service.settings_storage.upsert({"api_key": 128 * "a"}, self.organisation, plugin_id) + self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": 128 * "a"}) self.service.set_enabled_by_id(plugin_id, self.organisation, True) plugin = self.service.by_plugin_id(plugin_id, self.organisation) @@ -111,14 +110,14 @@ def test_removing_mandatory_setting_disables_plugin(self): def test_adding_integer_settings_within_given_constraints(self): plugin_id = "kat_test_2" - self.service.settings_storage.upsert({"api_key": "24"}, self.organisation, plugin_id) + self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": "24"}) with self.assertRaises(SettingsNotConformingToSchema) as ctx: self.service.set_enabled_by_id(plugin_id, self.organisation, True) self.assertIn("'24' is not of type 'integer'", ctx.exception.message) - self.service.settings_storage.upsert({"api_key": 24}, self.organisation, plugin_id) + self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": 24}) self.service.set_enabled_by_id(plugin_id, self.organisation, True) @@ -129,17 +128,16 @@ def test_adding_integer_settings_within_given_constraints(self): def test_clone_one_setting(self): new_org_id = "org2" plugin_id = "kat_test" - self.service.settings_storage.upsert({"api_key": "24"}, self.organisation, plugin_id) + self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": "24"}) assert self.service.get_all_settings(self.organisation, plugin_id) == {"api_key": "24"} self.service.set_enabled_by_id(plugin_id, self.organisation, True) - self.service.set_enabled_by_id("kat_test_normalize", new_org_id, True) assert "api_key" not in self.service.get_all_settings(new_org_id, plugin_id) new_org_plugins = self.service.get_all(new_org_id) assert len(new_org_plugins) == 5 - assert len([x for x in new_org_plugins if x.enabled]) == 2 # 4 Normalizers plus two boefjes enabled above + assert len([x for x in new_org_plugins if x.enabled]) == 2 # 2 Normalizers assert plugin_id not in [x.id for x in new_org_plugins if x.enabled] self.service.clone_settings_to_organisation(self.organisation, new_org_id) @@ -149,7 +147,7 @@ def test_clone_one_setting(self): new_org_plugins = self.service.get_all(new_org_id) assert len(new_org_plugins) == 5 - assert len([x for x in new_org_plugins if x.enabled]) == 2 + assert len([x for x in new_org_plugins if x.enabled]) == 3 # 2 Normalizers, 1 boefje assert plugin_id in [x.id for x in new_org_plugins if x.enabled] def test_clone_many_settings(self): diff --git a/boefjes/boefjes/katalogus/tests/test_plugins_api.py b/boefjes/tests/katalogus/test_plugins_api.py similarity index 81% rename from boefjes/boefjes/katalogus/tests/test_plugins_api.py rename to boefjes/tests/katalogus/test_plugins_api.py index 77a8a2b97e8..537e0ac81f2 100644 --- a/boefjes/boefjes/katalogus/tests/test_plugins_api.py +++ b/boefjes/tests/katalogus/test_plugins_api.py @@ -2,15 +2,26 @@ from fastapi.testclient import TestClient -from boefjes.katalogus.api.organisations import check_organisation_exists -from boefjes.katalogus.api.root import app -from boefjes.katalogus.dependencies.plugins import get_plugin_service -from boefjes.katalogus.tests.test_plugin_service import mock_plugin_service +from boefjes.dependencies.plugins import get_plugin_service +from boefjes.katalogus.organisations import check_organisation_exists +from boefjes.katalogus.root import app +from boefjes.storage.interfaces import OrganisationNotFound +from tests.katalogus.test_plugin_service import mock_plugin_service class TestPlugins(TestCase): def setUp(self) -> None: - app.dependency_overrides[get_plugin_service] = mock_plugin_service + services = { + "test-org": mock_plugin_service("test-org"), + } + + def get_service(organisation_id: str): + if organisation_id in services: + return services.get(organisation_id) + + raise OrganisationNotFound(organisation_id) + + app.dependency_overrides[get_plugin_service] = get_service app.dependency_overrides[check_organisation_exists] = lambda: None self.client = TestClient(app) @@ -104,7 +115,7 @@ def test_default_enabled_property_list(self): def test_patching_enabled_state(self): res = self.client.patch( - "/v1/organisations/test-org/plugins/test-boefje-1", + "/v1/organisations/test-org/plugins/kat_test_normalize", json={"enabled": False}, ) self.assertEqual(204, res.status_code) @@ -116,7 +127,7 @@ def test_patching_enabled_state(self): "kat_test": False, "kat_test_4": False, "kat_test_2": False, - "kat_test_normalize": True, + "kat_test_normalize": False, "kat_test_normalize_2": True, }, {plugin["id"]: plugin["enabled"] for plugin in res.json()}, @@ -124,21 +135,11 @@ def test_patching_enabled_state(self): def test_patching_enabled_state_non_existing_org(self): res = self.client.patch( - "/v1/organisations/non-existing-org/plugins/test-boefje-1", + "/v1/organisations/non-existing-org/plugins/kat_test_normalize", json={"enabled": False}, ) - self.assertEqual(204, res.status_code) + self.assertEqual(404, res.status_code) res = self.client.get("/v1/organisations/non-existing-org/plugins") - self.assertEqual(200, res.status_code) - self.assertEqual( - { - "kat_test": False, - "kat_test_2": False, - "kat_test_4": False, - "kat_test_normalize": True, - "kat_test_normalize_2": True, - }, - {plugin["id"]: plugin["enabled"] for plugin in res.json()}, - ) + self.assertEqual(404, res.status_code) diff --git a/boefjes/boefjes/katalogus/tests/test_settings.py b/boefjes/tests/katalogus/test_settings.py similarity index 90% rename from boefjes/boefjes/katalogus/tests/test_settings.py rename to boefjes/tests/katalogus/test_settings.py index 19189599b5b..603f6e88958 100644 --- a/boefjes/boefjes/katalogus/tests/test_settings.py +++ b/boefjes/tests/katalogus/test_settings.py @@ -3,7 +3,7 @@ from nacl.public import PrivateKey -from boefjes.katalogus.dependencies.encryption import NaclBoxMiddleware +from boefjes.dependencies.encryption import NaclBoxMiddleware class TestSettingsEncryption(TestCase): diff --git a/boefjes/tests/test_adr_validator.py b/boefjes/tests/test_adr_validator.py index a13d04e538c..1a60197127c 100644 --- a/boefjes/tests/test_adr_validator.py +++ b/boefjes/tests/test_adr_validator.py @@ -2,8 +2,8 @@ from unittest import TestCase from boefjes.job_models import NormalizerMeta -from boefjes.katalogus.local_repository import LocalPluginRepository from boefjes.local import LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository from tests.loading import get_dummy_data diff --git a/boefjes/tests/test_answer_parser.py b/boefjes/tests/test_answer_parser.py index 352e68d4a61..ff4114116a9 100644 --- a/boefjes/tests/test_answer_parser.py +++ b/boefjes/tests/test_answer_parser.py @@ -5,8 +5,8 @@ from pydantic import ValidationError from boefjes.job_models import NormalizerMeta -from boefjes.katalogus.local_repository import LocalPluginRepository from boefjes.local import LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository from tests.loading import get_dummy_data diff --git a/boefjes/tests/test_bodyimage.py b/boefjes/tests/test_bodyimage.py index 3750ea7a8ed..a60ddc94cee 100644 --- a/boefjes/tests/test_bodyimage.py +++ b/boefjes/tests/test_bodyimage.py @@ -6,8 +6,8 @@ from requests.models import CaseInsensitiveDict, PreparedRequest, Response from boefjes.job_models import BoefjeMeta, NormalizerMeta -from boefjes.katalogus.local_repository import LocalPluginRepository from boefjes.local import LocalBoefjeJobRunner, LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository from tests.loading import get_dummy_data diff --git a/boefjes/tests/test_calvin.py b/boefjes/tests/test_calvin.py index ad4d49a5682..d36582412cd 100644 --- a/boefjes/tests/test_calvin.py +++ b/boefjes/tests/test_calvin.py @@ -2,8 +2,8 @@ from unittest import TestCase from boefjes.job_models import NormalizerMeta -from boefjes.katalogus.local_repository import LocalPluginRepository from boefjes.local import LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository from octopoes.models.ooi.monitoring import Application from tests.loading import get_dummy_data diff --git a/boefjes/tests/test_dns.py b/boefjes/tests/test_dns.py index 555db001734..6f47e22f457 100644 --- a/boefjes/tests/test_dns.py +++ b/boefjes/tests/test_dns.py @@ -7,8 +7,8 @@ from boefjes.job_handler import serialize_ooi from boefjes.job_models import Boefje, BoefjeMeta, Normalizer, NormalizerMeta, ObservationsWithoutInputOOI, RawDataMeta -from boefjes.katalogus.local_repository import LocalPluginRepository from boefjes.local import LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository from octopoes.models import Reference from octopoes.models.ooi.dns.records import ( DNSAAAARecord, diff --git a/boefjes/tests/test_manual.py b/boefjes/tests/test_manual.py index 9dfcfd215fa..4c55ab87fa3 100644 --- a/boefjes/tests/test_manual.py +++ b/boefjes/tests/test_manual.py @@ -5,8 +5,8 @@ from pydantic_core import Url from boefjes.job_models import NormalizerMeta, NormalizerResults -from boefjes.katalogus.local_repository import LocalPluginRepository from boefjes.local import LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository from octopoes.models import Reference from tests.loading import get_dummy_data diff --git a/boefjes/tests/test_report_data.py b/boefjes/tests/test_report_data.py index ea6434c5c74..d8a8ed591ed 100644 --- a/boefjes/tests/test_report_data.py +++ b/boefjes/tests/test_report_data.py @@ -2,8 +2,8 @@ from pathlib import Path from boefjes.job_models import NormalizerDeclaration, NormalizerMeta -from boefjes.katalogus.local_repository import LocalPluginRepository from boefjes.local import LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository from tests.loading import get_dummy_data diff --git a/boefjes/tests/test_scan_profiles.py b/boefjes/tests/test_scan_profiles.py index e56da244c37..e233a278cf5 100644 --- a/boefjes/tests/test_scan_profiles.py +++ b/boefjes/tests/test_scan_profiles.py @@ -9,8 +9,8 @@ from boefjes.config import Settings from boefjes.job_handler import NormalizerHandler from boefjes.job_models import NormalizerMeta -from boefjes.katalogus.local_repository import LocalPluginRepository from boefjes.local import LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository from octopoes.models import DeclaredScanProfile from tests.loading import get_dummy_data diff --git a/boefjes/tests/test_tasks.py b/boefjes/tests/test_tasks.py index d9290187c2e..f0cbf5fac56 100644 --- a/boefjes/tests/test_tasks.py +++ b/boefjes/tests/test_tasks.py @@ -10,9 +10,9 @@ from boefjes.job_handler import BoefjeHandler from boefjes.job_models import BoefjeMeta, InvalidReturnValueNormalizer, NormalizerMeta -from boefjes.katalogus.local_repository import LocalPluginRepository -from boefjes.katalogus.models import Bit, Boefje, Normalizer, PluginType from boefjes.local import LocalBoefjeJobRunner, LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository +from boefjes.models import Bit, Boefje, Normalizer, PluginType from boefjes.runtime_interfaces import JobRuntimeError from tests.loading import get_dummy_data diff --git a/boefjes/tests/test_wappalyzer_normalizer.py b/boefjes/tests/test_wappalyzer_normalizer.py index 421616f2b7c..cf70b60bd4d 100644 --- a/boefjes/tests/test_wappalyzer_normalizer.py +++ b/boefjes/tests/test_wappalyzer_normalizer.py @@ -2,8 +2,8 @@ from unittest import TestCase from boefjes.job_models import NormalizerMeta -from boefjes.katalogus.local_repository import LocalPluginRepository from boefjes.local import LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository from tests.loading import get_dummy_data diff --git a/boefjes/tools/run_boefje.py b/boefjes/tools/run_boefje.py index 9efae30fa68..2b578143383 100755 --- a/boefjes/tools/run_boefje.py +++ b/boefjes/tools/run_boefje.py @@ -13,8 +13,8 @@ from boefjes.job_handler import BoefjeHandler, bytes_api_client from boefjes.job_models import Boefje, BoefjeMeta -from boefjes.katalogus.local_repository import get_local_repository from boefjes.local import LocalBoefjeJobRunner +from boefjes.local_repository import get_local_repository logging.basicConfig(stream=sys.stdout, level=logging.INFO, force=True) diff --git a/boefjes/tools/run_normalizer.py b/boefjes/tools/run_normalizer.py index d73221468b8..e940fa7f399 100755 --- a/boefjes/tools/run_normalizer.py +++ b/boefjes/tools/run_normalizer.py @@ -14,8 +14,8 @@ from boefjes.config import settings from boefjes.job_handler import NormalizerHandler, bytes_api_client from boefjes.job_models import Normalizer, NormalizerMeta -from boefjes.katalogus.local_repository import get_local_repository from boefjes.local import LocalNormalizerJobRunner +from boefjes.local_repository import get_local_repository logging.basicConfig(stream=sys.stdout, level=logging.INFO, force=True) diff --git a/docker-compose.yml b/docker-compose.yml index 9e730bc6691..a1b1a486639 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -183,7 +183,7 @@ services: target: dev args: ENVIRONMENT: dev - command: uvicorn boefjes.katalogus.api.root:app --host 0.0.0.0 --port 8000 --reload --reload-dir /app/boefjes/boefjes/katalogus + command: uvicorn boefjes.katalogus.root:app --host 0.0.0.0 --port 8000 --reload --reload-dir /app/boefjes/boefjes/katalogus volumes: - ./boefjes:/app/boefjes - ./octopoes/octopoes:/app/boefjes/octopoes diff --git a/mula/.ci/docker-compose.yml b/mula/.ci/docker-compose.yml index a9410d47654..6b10342ebad 100644 --- a/mula/.ci/docker-compose.yml +++ b/mula/.ci/docker-compose.yml @@ -75,7 +75,7 @@ services: target: dev args: ENVIRONMENT: dev - command: uvicorn boefjes.katalogus.api.root:app --host 0.0.0.0 + command: uvicorn boefjes.katalogus.root:app --host 0.0.0.0 ports: - "127.0.0.1:8003:8000" env_file: From d33d1c68f19885d5ab411808f2e30a485582922e Mon Sep 17 00:00:00 2001 From: ammar92 Date: Wed, 10 Jul 2024 09:13:15 +0200 Subject: [PATCH 009/112] Updated `zipp` (#3215) --- boefjes/poetry.lock | 10 +++++----- boefjes/requirements-dev.txt | 6 +++--- boefjes/requirements.txt | 6 +++--- bytes/poetry.lock | 10 +++++----- bytes/requirements-dev.txt | 6 +++--- bytes/requirements.txt | 6 +++--- keiko/poetry.lock | 10 +++++----- keiko/requirements-dev.txt | 6 +++--- keiko/requirements.txt | 6 +++--- octopoes/poetry.lock | 10 +++++----- octopoes/requirements-dev.txt | 6 +++--- octopoes/requirements.txt | 6 +++--- rocky/poetry.lock | 10 +++++----- rocky/requirements-dev.txt | 6 +++--- rocky/requirements.txt | 6 +++--- 15 files changed, 55 insertions(+), 55 deletions(-) diff --git a/boefjes/poetry.lock b/boefjes/poetry.lock index b557c4e7e4c..19282a4fbe4 100644 --- a/boefjes/poetry.lock +++ b/boefjes/poetry.lock @@ -2821,18 +2821,18 @@ multidict = ">=4.0" [[package]] name = "zipp" -version = "3.17.0" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" diff --git a/boefjes/requirements-dev.txt b/boefjes/requirements-dev.txt index fee77402b93..f04e16169ea 100644 --- a/boefjes/requirements-dev.txt +++ b/boefjes/requirements-dev.txt @@ -1426,6 +1426,6 @@ yarl==1.9.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958 \ --hash=sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749 \ --hash=sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec -zipp==3.17.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ - --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 +zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ + --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c diff --git a/boefjes/requirements.txt b/boefjes/requirements.txt index 35ae9ffbaef..b7f4f6760a0 100644 --- a/boefjes/requirements.txt +++ b/boefjes/requirements.txt @@ -1411,6 +1411,6 @@ yarl==1.9.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958 \ --hash=sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749 \ --hash=sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec -zipp==3.17.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ - --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 +zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ + --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c diff --git a/bytes/poetry.lock b/bytes/poetry.lock index 2a7a6964b8e..903b7121131 100644 --- a/bytes/poetry.lock +++ b/bytes/poetry.lock @@ -1680,18 +1680,18 @@ files = [ [[package]] name = "zipp" -version = "3.17.0" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" diff --git a/bytes/requirements-dev.txt b/bytes/requirements-dev.txt index 972f11a34e5..3da21c0a5a1 100644 --- a/bytes/requirements-dev.txt +++ b/bytes/requirements-dev.txt @@ -766,6 +766,6 @@ wrapt==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 -zipp==3.17.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ - --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 +zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ + --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c diff --git a/bytes/requirements.txt b/bytes/requirements.txt index 11e00e86269..8e53dfb22d5 100644 --- a/bytes/requirements.txt +++ b/bytes/requirements.txt @@ -748,6 +748,6 @@ wrapt==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 -zipp==3.17.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ - --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 +zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ + --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c diff --git a/keiko/poetry.lock b/keiko/poetry.lock index b09845d750b..e221e981ff0 100644 --- a/keiko/poetry.lock +++ b/keiko/poetry.lock @@ -1301,18 +1301,18 @@ files = [ [[package]] name = "zipp" -version = "3.17.0" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" diff --git a/keiko/requirements-dev.txt b/keiko/requirements-dev.txt index ff5b0dfe085..e2b6bf89e01 100644 --- a/keiko/requirements-dev.txt +++ b/keiko/requirements-dev.txt @@ -533,6 +533,6 @@ wrapt==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 -zipp==3.17.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ - --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 +zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ + --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c diff --git a/keiko/requirements.txt b/keiko/requirements.txt index 797011d05d8..9d6504633e9 100644 --- a/keiko/requirements.txt +++ b/keiko/requirements.txt @@ -373,6 +373,6 @@ wrapt==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 -zipp==3.17.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ - --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 +zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ + --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c diff --git a/octopoes/poetry.lock b/octopoes/poetry.lock index 51a229e45b3..e1bf60a9e51 100644 --- a/octopoes/poetry.lock +++ b/octopoes/poetry.lock @@ -2074,18 +2074,18 @@ files = [ [[package]] name = "zipp" -version = "3.18.1" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, - {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" diff --git a/octopoes/requirements-dev.txt b/octopoes/requirements-dev.txt index ec126a2f54c..372b6351830 100644 --- a/octopoes/requirements-dev.txt +++ b/octopoes/requirements-dev.txt @@ -855,6 +855,6 @@ wrapt==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 -zipp==3.18.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b \ - --hash=sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715 +zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ + --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c diff --git a/octopoes/requirements.txt b/octopoes/requirements.txt index 2d90b56ce3d..927526a1dc6 100644 --- a/octopoes/requirements.txt +++ b/octopoes/requirements.txt @@ -746,6 +746,6 @@ wrapt==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 -zipp==3.18.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b \ - --hash=sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715 +zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ + --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c diff --git a/rocky/poetry.lock b/rocky/poetry.lock index 54988ccf071..31b491e591f 100644 --- a/rocky/poetry.lock +++ b/rocky/poetry.lock @@ -3261,18 +3261,18 @@ files = [ [[package]] name = "zipp" -version = "3.17.0" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [[package]] name = "zopfli" diff --git a/rocky/requirements-dev.txt b/rocky/requirements-dev.txt index 974a0434412..6224f66b6dd 100644 --- a/rocky/requirements-dev.txt +++ b/rocky/requirements-dev.txt @@ -1447,9 +1447,9 @@ wrapt==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 -zipp==3.17.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ - --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 +zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ + --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c zopfli==0.2.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0574372283befa5af98fb31407e1fe6822f2f9c437ef69e7fa260e49022d8a65 \ --hash=sha256:082f030b2b7d6d4597ac517816e499c63b92130aa8f4f74a3788ebaa5770f974 \ diff --git a/rocky/requirements.txt b/rocky/requirements.txt index 4bddd1a80aa..bbd22d96eb3 100644 --- a/rocky/requirements.txt +++ b/rocky/requirements.txt @@ -959,9 +959,9 @@ wrapt==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 -zipp==3.17.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ - --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 +zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ + --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c zopfli==0.2.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0574372283befa5af98fb31407e1fe6822f2f9c437ef69e7fa260e49022d8a65 \ --hash=sha256:082f030b2b7d6d4597ac517816e499c63b92130aa8f4f74a3788ebaa5770f974 \ From 2d989a170e4f981b841294c1b792e4adeffd535a Mon Sep 17 00:00:00 2001 From: ammar92 Date: Wed, 10 Jul 2024 10:02:44 +0200 Subject: [PATCH 010/112] Updated Django (#3217) --- rocky/poetry.lock | 6 +++--- rocky/requirements-dev.txt | 6 +++--- rocky/requirements.txt | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/rocky/poetry.lock b/rocky/poetry.lock index 31b491e591f..8d1aaa3adfe 100644 --- a/rocky/poetry.lock +++ b/rocky/poetry.lock @@ -452,13 +452,13 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] name = "django" -version = "5.0.6" +version = "5.0.7" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false python-versions = ">=3.10" files = [ - {file = "Django-5.0.6-py3-none-any.whl", hash = "sha256:8363ac062bb4ef7c3f12d078f6fa5d154031d129a15170a1066412af49d30905"}, - {file = "Django-5.0.6.tar.gz", hash = "sha256:ff1b61005004e476e0aeea47c7f79b85864c70124030e95146315396f1e7951f"}, + {file = "Django-5.0.7-py3-none-any.whl", hash = "sha256:f216510ace3de5de01329463a315a629f33480e893a9024fc93d8c32c22913da"}, + {file = "Django-5.0.7.tar.gz", hash = "sha256:bd4505cae0b9bd642313e8fb71810893df5dc2ffcacaa67a33af2d5cd61888f2"}, ] [package.dependencies] diff --git a/rocky/requirements-dev.txt b/rocky/requirements-dev.txt index 6224f66b6dd..ba70602b78f 100644 --- a/rocky/requirements-dev.txt +++ b/rocky/requirements-dev.txt @@ -284,9 +284,9 @@ django-two-factor-auth==1.16.0 ; python_version >= "3.10" and python_version < " django-weasyprint==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:605eba0dd3246c0410a60fdaa581139330ad6c637fc273e1bfe90a7a09f53728 \ --hash=sha256:7f554bcc428293aeadc175ab5607b4f3bf30c0e5da3d4aa34453b3d96e0ffd3a -django==5.0.6 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8363ac062bb4ef7c3f12d078f6fa5d154031d129a15170a1066412af49d30905 \ - --hash=sha256:ff1b61005004e476e0aeea47c7f79b85864c70124030e95146315396f1e7951f +django==5.0.7 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bd4505cae0b9bd642313e8fb71810893df5dc2ffcacaa67a33af2d5cd61888f2 \ + --hash=sha256:f216510ace3de5de01329463a315a629f33480e893a9024fc93d8c32c22913da djangorestframework==3.15.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20 \ --hash=sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad diff --git a/rocky/requirements.txt b/rocky/requirements.txt index bbd22d96eb3..558cbf3e38c 100644 --- a/rocky/requirements.txt +++ b/rocky/requirements.txt @@ -225,9 +225,9 @@ django-two-factor-auth==1.16.0 ; python_version >= "3.10" and python_version < " django-weasyprint==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:605eba0dd3246c0410a60fdaa581139330ad6c637fc273e1bfe90a7a09f53728 \ --hash=sha256:7f554bcc428293aeadc175ab5607b4f3bf30c0e5da3d4aa34453b3d96e0ffd3a -django==5.0.6 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8363ac062bb4ef7c3f12d078f6fa5d154031d129a15170a1066412af49d30905 \ - --hash=sha256:ff1b61005004e476e0aeea47c7f79b85864c70124030e95146315396f1e7951f +django==5.0.7 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bd4505cae0b9bd642313e8fb71810893df5dc2ffcacaa67a33af2d5cd61888f2 \ + --hash=sha256:f216510ace3de5de01329463a315a629f33480e893a9024fc93d8c32c22913da djangorestframework==3.15.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20 \ --hash=sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad From 09b1362cee8cb71e3bad4d0d21664061149e0407 Mon Sep 17 00:00:00 2001 From: Jan Klopper Date: Wed, 10 Jul 2024 10:39:59 +0200 Subject: [PATCH 011/112] Use more concise regexes (#3181) Co-authored-by: Jeroen Dekkers Co-authored-by: ammar92 --- .../boefjes/plugins/kat_leakix/normalize.py | 8 +++---- .../bits/check_csp_header/check_csp_header.py | 4 ++-- .../spf_discovery/internetnl_spf_parser.py | 15 +++++-------- octopoes/octopoes/models/ooi/findings.py | 22 ++++++++++++++++--- 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_leakix/normalize.py b/boefjes/boefjes/plugins/kat_leakix/normalize.py index 60b68ed38ec..278e9ee8748 100644 --- a/boefjes/boefjes/plugins/kat_leakix/normalize.py +++ b/boefjes/boefjes/plugins/kat_leakix/normalize.py @@ -38,7 +38,7 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: results = json.loads(raw) - pk_ooi = Reference.from_str(input_ooi["primary_key"]) + pk_ooi_reference = Reference.from_str(input_ooi["primary_key"]) network_reference = Network(name="internet").reference for event in results: @@ -48,7 +48,7 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: # TODO: ssh, ssl # reset loop - event_ooi_reference = pk_ooi + event_ooi_reference = pk_ooi_reference # Autonomous System as_ooi = None @@ -195,9 +195,9 @@ def handle_tag(event, software_ooi_reference=None, ip_port_ooi_reference=None): # Tags (CVE's) if isinstance(event.get("tags"), Iterable): for tag in event.get("tags", {}): - if re.match("cve-[0-9]{4}-[0-9]{4,6}", tag): + if re.match(r"cve-\d{4}-\d{4,6}", tag): ft = CVEFindingType(id=tag) cve_ooi = software_ooi_reference if software_ooi_reference else ip_port_ooi_reference - f = Finding(finding_type=ft.reference, ooi=cve_ooi.reference) + f = Finding(finding_type=ft.reference, ooi=cve_ooi) yield ft yield f diff --git a/octopoes/bits/check_csp_header/check_csp_header.py b/octopoes/bits/check_csp_header/check_csp_header.py index 0348f203de2..cd975f7d677 100644 --- a/octopoes/bits/check_csp_header/check_csp_header.py +++ b/octopoes/bits/check_csp_header/check_csp_header.py @@ -52,7 +52,7 @@ def run(resource: HTTPResource, additional_oois: list[HTTPHeader], config: dict[ # 3: second-level domain # 4: end with either a space, a ';', a :port or the end of the string # {1}{ 2}{ 3 }{ 4 } - if re.search(r"\S+\*\.\S{2,3}([\s]+|$|;|:[0-9]+)", csp_header): + if re.search(r"\S+\*\.\S{2,3}([\s]+|$|;|:\d+)", csp_header): findings.append("The wildcard * for the scheme and host part of any URL should never be used in CSP settings.") if "unsafe-inline" in csp_header or "unsafe-eval" in csp_header or "unsafe-hashes" in csp_header: @@ -156,7 +156,7 @@ def _create_kat_finding(header: Reference, kat_id: str, description: str) -> Ite def _source_valid(policy: list[str]) -> bool: for value in policy: if not ( - re.search(r"\S+\.\S{2,3}([\s]+|$|;|:[0-9]+)", value) + re.search(r"\S+\.\S{2,3}([\s]+|$|;|:\d+)", value) or value in [ "'none'", diff --git a/octopoes/bits/spf_discovery/internetnl_spf_parser.py b/octopoes/bits/spf_discovery/internetnl_spf_parser.py index 711da223c63..a7b4a3708c6 100644 --- a/octopoes/bits/spf_discovery/internetnl_spf_parser.py +++ b/octopoes/bits/spf_discovery/internetnl_spf_parser.py @@ -96,12 +96,10 @@ def _check_domain_end(tokens): domain_spec = macro_string.setParseAction(_check_domain_end) -ip4_network = Regex( - r"((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])" -) +ip4_network = Regex(r"((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)") -ip6_cidr_length = CaselessLiteral("/") + Regex("(12[0-8]|1[01][0-9]|[1-9][0-9]|[0-9])") -ip4_cidr_length = CaselessLiteral("/") + Regex("(3[0-2]|[12][0-9]|[0-9])") +ip6_cidr_length = CaselessLiteral("/") + Regex(r"(12[0-8]|1[01]\d|[1-9]\d|\d)") +ip4_cidr_length = CaselessLiteral("/") + Regex(r"(3[0-2]|[12]\d|\d)") dual_cidr_length = Optional(ip4_cidr_length) + Optional(CaselessLiteral("/") + ip6_cidr_length) unknown_modifier = Combine(name + CaselessLiteral("=") + macro_string) @@ -139,9 +137,6 @@ def _check_domain_end(tokens): def parse(spf_record): try: - parsed = record.parseString(spf_record) - except ParseException: - parsed = None + return record.parseString(spf_record) except Exception: - parsed = None - return parsed + return None diff --git a/octopoes/octopoes/models/ooi/findings.py b/octopoes/octopoes/models/ooi/findings.py index a8ca1cd6456..ba3b30f4556 100644 --- a/octopoes/octopoes/models/ooi/findings.py +++ b/octopoes/octopoes/models/ooi/findings.py @@ -1,13 +1,21 @@ from enum import Enum from functools import total_ordering -from typing import Literal +from typing import Annotated, Literal -from pydantic import AnyUrl +from pydantic import AnyUrl, StringConstraints from octopoes.models import OOI, Reference from octopoes.models.persistence import ReferenceField -severity_order = ["unknown", "pending", "recommendation", "low", "medium", "high", "critical"] +severity_order = [ + "unknown", + "pending", + "recommendation", + "low", + "medium", + "high", + "critical", +] @total_ordering @@ -57,14 +65,20 @@ class ADRFindingType(FindingType): class CVEFindingType(FindingType): object_type: Literal["CVEFindingType"] = "CVEFindingType" + id: Annotated[str, StringConstraints(strip_whitespace=True, to_upper=True)] + class CWEFindingType(FindingType): object_type: Literal["CWEFindingType"] = "CWEFindingType" + id: Annotated[str, StringConstraints(strip_whitespace=True, to_upper=True)] + class CAPECFindingType(FindingType): object_type: Literal["CAPECFindingType"] = "CAPECFindingType" + id: Annotated[str, StringConstraints(strip_whitespace=True, to_upper=True)] + class RetireJSFindingType(FindingType): object_type: Literal["RetireJSFindingType"] = "RetireJSFindingType" @@ -73,6 +87,8 @@ class RetireJSFindingType(FindingType): class SnykFindingType(FindingType): object_type: Literal["SnykFindingType"] = "SnykFindingType" + id: Annotated[str, StringConstraints(strip_whitespace=True, to_upper=True)] + class KATFindingType(FindingType): object_type: Literal["KATFindingType"] = "KATFindingType" From 1b518cf4906e0aa36690c7dd55b62992780e204f Mon Sep 17 00:00:00 2001 From: originalsouth Date: Wed, 10 Jul 2024 14:43:55 +0200 Subject: [PATCH 012/112] Recalculate bit when a config object changes (#3206) Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> --- octopoes/octopoes/core/service.py | 21 ++++++++++++------- .../repositories/origin_repository.py | 7 ++++++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/octopoes/octopoes/core/service.py b/octopoes/octopoes/core/service.py index 67ea7956c97..1243ae629ae 100644 --- a/octopoes/octopoes/core/service.py +++ b/octopoes/octopoes/core/service.py @@ -28,6 +28,7 @@ ) from octopoes.models.exception import ObjectNotFoundException from octopoes.models.explanation import InheritanceSection +from octopoes.models.ooi.config import Config from octopoes.models.origin import Origin, OriginParameter, OriginType from octopoes.models.pagination import Paginated from octopoes.models.path import ( @@ -400,14 +401,20 @@ def _on_update_ooi(self, event: OOIDBEvent) -> None: if event.new_data is None: raise ValueError("Update event new_data should not be None") - inference_origins = self.origin_repository.list_origins(event.valid_time, source=event.new_data.reference) - inference_params = self.origin_parameter_repository.list_by_reference( - event.new_data.reference, valid_time=event.valid_time - ) - for inference_param in inference_params: - inference_origins.append(self.origin_repository.get(inference_param.origin_id, event.valid_time)) + if isinstance(event.new_data, Config): + relevant_bit_ids = [ + bit.id for bit in get_bit_definitions().values() if bit.config_ooi_relation_path is not None + ] + inference_origins = self.origin_repository.list_origins(event.valid_time, method=relevant_bit_ids) + else: + inference_origins = self.origin_repository.list_origins(event.valid_time, source=event.new_data.reference) + inference_params = self.origin_parameter_repository.list_by_reference( + event.new_data.reference, valid_time=event.valid_time + ) + for inference_param in inference_params: + inference_origins.append(self.origin_repository.get(inference_param.origin_id, event.valid_time)) - inference_origins = [o for o in inference_origins if o.origin_type == OriginType.INFERENCE] + inference_origins = [o for o in inference_origins if o.origin_type == OriginType.INFERENCE] for inference_origin in inference_origins: self._run_inference(inference_origin, event.valid_time) diff --git a/octopoes/octopoes/repositories/origin_repository.py b/octopoes/octopoes/repositories/origin_repository.py index c21dc4854cc..1f9ca2e9d64 100644 --- a/octopoes/octopoes/repositories/origin_repository.py +++ b/octopoes/octopoes/repositories/origin_repository.py @@ -37,6 +37,7 @@ def list_origins( task_id: UUID | None = None, source: Reference | None = None, result: Reference | None = None, + method: str | list[str] | None = None, origin_type: OriginType | None = None, ) -> list[Origin]: raise NotImplementedError @@ -73,9 +74,10 @@ def list_origins( task_id: UUID | None = None, source: Reference | None = None, result: Reference | None = None, + method: str | list[str] | None = None, origin_type: OriginType | None = None, ) -> list[Origin]: - where_parameters = {"type": Origin.__name__} + where_parameters: dict[str, str | list[str]] = {"type": Origin.__name__} if task_id: where_parameters["task_id"] = str(task_id) @@ -86,6 +88,9 @@ def list_origins( if result: where_parameters["result"] = str(result) + if method: + where_parameters["method"] = method + if origin_type: where_parameters["origin_type"] = origin_type.value From ce9abd1d6f6a0395d201a1234591928231c0cb9d Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Wed, 10 Jul 2024 20:27:20 +0200 Subject: [PATCH 013/112] cve-2024-6387 from RickGeex (#3194) Co-authored-by: Jan Klopper Co-authored-by: ammar92 Co-authored-by: Jeroen Dekkers --- .../plugins/kat_cve_2024_6387/__init__.py | 0 .../plugins/kat_cve_2024_6387/normalize.py | 68 ++++++++++++++++++ .../plugins/kat_cve_2024_6387/normalizer.json | 11 +++ .../plugins/kat_service_banner/__init__.py | 0 .../plugins/kat_service_banner/boefje.json | 9 +++ .../plugins/kat_service_banner/cover.jpg | Bin 0 -> 129936 bytes .../plugins/kat_service_banner/main.py | 41 +++++++++++ boefjes/tests/integration/test_api.py | 8 +-- boefjes/tests/test_cve-2024-6387.py | 23 ++++++ 9 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 boefjes/boefjes/plugins/kat_cve_2024_6387/__init__.py create mode 100644 boefjes/boefjes/plugins/kat_cve_2024_6387/normalize.py create mode 100644 boefjes/boefjes/plugins/kat_cve_2024_6387/normalizer.json create mode 100644 boefjes/boefjes/plugins/kat_service_banner/__init__.py create mode 100644 boefjes/boefjes/plugins/kat_service_banner/boefje.json create mode 100644 boefjes/boefjes/plugins/kat_service_banner/cover.jpg create mode 100644 boefjes/boefjes/plugins/kat_service_banner/main.py create mode 100644 boefjes/tests/test_cve-2024-6387.py diff --git a/boefjes/boefjes/plugins/kat_cve_2024_6387/__init__.py b/boefjes/boefjes/plugins/kat_cve_2024_6387/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/boefjes/boefjes/plugins/kat_cve_2024_6387/normalize.py b/boefjes/boefjes/plugins/kat_cve_2024_6387/normalize.py new file mode 100644 index 00000000000..0948823cecc --- /dev/null +++ b/boefjes/boefjes/plugins/kat_cve_2024_6387/normalize.py @@ -0,0 +1,68 @@ +""" +CVE-2024-6387 checker +Author: Mischa van Geelen <@rickgeex> + +""" + +from collections.abc import Iterable + +from boefjes.job_models import NormalizerOutput +from octopoes.models import Reference +from octopoes.models.ooi.findings import CVEFindingType, Finding +from packaging.version import Version + +VULNERABLE_VERSIONS = [ + "SSH-2.0-OpenSSH_8.5", + "SSH-2.0-OpenSSH_8.6", + "SSH-2.0-OpenSSH_8.7", + "SSH-2.0-OpenSSH_8.8", + "SSH-2.0-OpenSSH_8.9", + "SSH-2.0-OpenSSH_9.0", + "SSH-2.0-OpenSSH_9.1", + "SSH-2.0-OpenSSH_9.2", + "SSH-2.0-OpenSSH_9.3", + "SSH-2.0-OpenSSH_9.4", + "SSH-2.0-OpenSSH_9.5", + "SSH-2.0-OpenSSH_9.6", + "SSH-2.0-OpenSSH_9.7", +] + + +def is_vulnerable(banner: str) -> bool: + if not any(version in banner for version in VULNERABLE_VERSIONS): + return False + + if banner.startswith("SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u"): + _, security_update = banner.split("deb12u") + if Version(security_update) >= Version("3"): + return False + elif banner.startswith("SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu"): + _, security_update = banner.split("3ubuntu") + if Version(security_update) >= Version("13.3"): + return False + elif banner.startswith("SSH-2.0-OpenSSH_9.3p1 Ubuntu-1ubuntu"): + _, security_update = banner.split("1ubuntu") + if Version(security_update) >= Version("3.6"): + return False + elif banner.startswith("SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu"): + _, security_update = banner.split("3ubuntu") + if Version(security_update) >= Version("0.10"): + return False + + return True + + +def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: + ooi = Reference.from_str(input_ooi["primary_key"]) + + banner = raw.decode() + + if banner.startswith("SSH-2.0-OpenSSH") and is_vulnerable(banner): + finding_type = CVEFindingType(id="CVE-2024-6387") + finding = Finding( + finding_type=finding_type.reference, + ooi=ooi, + description="Service is most likely vulnerable to CVE-2024-6387", + ) + yield finding_type + yield finding diff --git a/boefjes/boefjes/plugins/kat_cve_2024_6387/normalizer.json b/boefjes/boefjes/plugins/kat_cve_2024_6387/normalizer.json new file mode 100644 index 00000000000..1cf4c49e5bf --- /dev/null +++ b/boefjes/boefjes/plugins/kat_cve_2024_6387/normalizer.json @@ -0,0 +1,11 @@ +{ + "id": "kat_cve_2024_6387_normalize", + "consumes": [ + "openkat/service-banner" + ], + "description": "Checks service banner for CVE-2024-6387, enable service banner boefje to get the service banner", + "produces": [ + "Finding", + "CVEFindingType" + ] +} diff --git a/boefjes/boefjes/plugins/kat_service_banner/__init__.py b/boefjes/boefjes/plugins/kat_service_banner/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/boefjes/boefjes/plugins/kat_service_banner/boefje.json b/boefjes/boefjes/plugins/kat_service_banner/boefje.json new file mode 100644 index 00000000000..6319afe8c94 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_service_banner/boefje.json @@ -0,0 +1,9 @@ +{ + "id": "service_banner", + "name": "Service banner download", + "description": "Downloads service banners from the target hosts", + "consumes": [ + "IPPort" + ], + "scan_level": 2 +} diff --git a/boefjes/boefjes/plugins/kat_service_banner/cover.jpg b/boefjes/boefjes/plugins/kat_service_banner/cover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..753c6d692183a96ccf16a32c0b894cb6a0fd9e2c GIT binary patch literal 129936 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

hj(n0c2yoVqR{Z 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 literal 0 HcmV?d00001 diff --git a/boefjes/boefjes/plugins/kat_service_banner/main.py b/boefjes/boefjes/plugins/kat_service_banner/main.py new file mode 100644 index 00000000000..fdc791290c6 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_service_banner/main.py @@ -0,0 +1,41 @@ +import socket + +from boefjes.job_models import BoefjeMeta + +TIMEOUT = 1.0 + + +def get_sock(ip, port, timeout): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(timeout) + try: + sock.connect((ip, port)) + return sock + except Exception: + return None + + +def get_banner(sock): + if not sock: + return [({"boefje/error"}, "Unable to connect to the service")] + try: + sock.settimeout(TIMEOUT) + banner = sock.recv(1024) + try: + banner = banner.decode().strip() + except UnicodeDecodeError: + banner = banner.decode("latin1").strip() + sock.close() + return [({"openkat/service-banner"}, banner)] + except Exception as e: + return [({"boefje/error"}, f"Unable to get banner. {str(e)}")] + + +def run(boefje_meta: BoefjeMeta) -> list[tuple[set, str | bytes]]: + input_ = boefje_meta.arguments["input"] # input is IPPort + port = input_["port"] + ip = input_["address"]["address"] + + sock = get_sock(ip, port, TIMEOUT) + + return get_banner(sock) diff --git a/boefjes/tests/integration/test_api.py b/boefjes/tests/integration/test_api.py index 40ec2b35bd0..9df55695c16 100644 --- a/boefjes/tests/integration/test_api.py +++ b/boefjes/tests/integration/test_api.py @@ -47,9 +47,9 @@ def test_get_local_plugin(self): def test_filter_plugins(self): response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/") - self.assertEqual(len(response.json()), 93) + self.assertEqual(len(response.json()), 95) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins?plugin_type=boefje") - self.assertEqual(len(response.json()), 41) + self.assertEqual(len(response.json()), 42) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins?limit=10") self.assertEqual(len(response.json()), 10) @@ -74,7 +74,7 @@ def test_add_boefje(self): self.assertEqual(response.status_code, 422) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/?plugin_type=boefje") - self.assertEqual(len(response.json()), 42) + self.assertEqual(len(response.json()), 43) boefje_dict = boefje.dict() boefje_dict["consumes"] = list(boefje_dict["consumes"]) @@ -99,7 +99,7 @@ def test_add_normalizer(self): self.assertEqual(response.status_code, 201) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/?plugin_type=normalizer") - self.assertEqual(len(response.json()), 53) + self.assertEqual(len(response.json()), 54) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/test_normalizer") self.assertEqual(response.json(), normalizer.dict()) diff --git a/boefjes/tests/test_cve-2024-6387.py b/boefjes/tests/test_cve-2024-6387.py new file mode 100644 index 00000000000..71a42490000 --- /dev/null +++ b/boefjes/tests/test_cve-2024-6387.py @@ -0,0 +1,23 @@ +from boefjes.plugins.kat_cve_2024_6387.normalize import is_vulnerable + + +def test_is_vulnerable(): + for version in [ + "SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3", + "SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u10", + "SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.3", + "SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.4", + "SSH-2.0-OpenSSH_9.3p1 Ubuntu-1ubuntu3.6", + "SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.10", + ]: + assert not is_vulnerable(version) + + for version in [ + "SSH-2.0-OpenSSH_8.9p1", + "SSH-2.0-OpenSSH_9.2p1", + "SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u2", + "SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13", + "SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.7", + "SSH-2.0-OpenSSH_8.9p1 Ubuntu-3", + ]: + assert is_vulnerable(version) From 1a75d33447116cc0cdbebf634545ad6b89c55aa0 Mon Sep 17 00:00:00 2001 From: Jan Klopper Date: Thu, 11 Jul 2024 10:36:28 +0200 Subject: [PATCH 014/112] Add observation data to observation table in OOI detail page (#3186) Co-authored-by: ammar92 --- rocky/rocky/locale/django.pot | 16 ++++++++++++++-- .../oois/ooi_detail_origins_observations.html | 10 ++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index ac2591623af..f799602fdf6 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-08 15:27+0000\n" +"POT-Creation-Date: 2024-07-09 07:22+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -5055,13 +5055,25 @@ msgid "Parameters" msgstr "" #: rocky/templates/oois/ooi_detail_origins_observations.html -msgid "Observed by" +msgid "Last observed by" msgstr "" #: rocky/templates/oois/ooi_detail_origins_observations.html msgid "Task ID" msgstr "" +#: rocky/templates/oois/ooi_detail_origins_observations.html +msgid "When" +msgstr "" + +#: rocky/templates/oois/ooi_detail_origins_observations.html +msgid "The boefje has since been deleted or disabled." +msgstr "" + +#: rocky/templates/oois/ooi_detail_origins_observations.html +msgid "No Raw file could be found, this might point to an error in OpenKAT" +msgstr "" + #: rocky/templates/oois/ooi_edit.html #, python-format msgid "Edit %(type)s: %(ooi_human_readable)s" diff --git a/rocky/rocky/templates/oois/ooi_detail_origins_observations.html b/rocky/rocky/templates/oois/ooi_detail_origins_observations.html index 86dd27991d4..32ba8628eae 100644 --- a/rocky/rocky/templates/oois/ooi_detail_origins_observations.html +++ b/rocky/rocky/templates/oois/ooi_detail_origins_observations.html @@ -4,14 +4,15 @@ {% spaceless %} {% if observations %}

-

{% translate "Observed by" %}

+

{% translate "Last observed by" %}

- + + @@ -20,6 +21,8 @@

{% translate "Observed by" %}

+ {% endfor %} From 9b388527240dd44efae7db23b6d79c219d2a39ea Mon Sep 17 00:00:00 2001 From: originalsouth Date: Thu, 11 Jul 2024 11:34:13 +0200 Subject: [PATCH 015/112] Gather BIT metrics [implementation] (#3122) Co-authored-by: Jan Klopper --- octopoes/octopoes/config/settings.py | 3 +- octopoes/octopoes/core/app.py | 11 ++- octopoes/octopoes/core/service.py | 23 +++++- octopoes/tools/analyze-bit-metric.py | 110 +++++++++++++++++++++++++++ 4 files changed, 141 insertions(+), 6 deletions(-) create mode 100755 octopoes/tools/analyze-bit-metric.py diff --git a/octopoes/octopoes/config/settings.py b/octopoes/octopoes/config/settings.py index c8cd2921ff2..a5857952eb4 100644 --- a/octopoes/octopoes/config/settings.py +++ b/octopoes/octopoes/config/settings.py @@ -88,4 +88,5 @@ def settings_customise_sources( DEFAULT_SEVERITY_FILTER = {severity for severity in RiskLevelSeverity} DEFAULT_LIMIT = 50 DEFAULT_OFFSET = 0 -QUEUE_NAME_OCTOPOES: str = "octopoes" +QUEUE_NAME_OCTOPOES = "octopoes" +GATHER_BIT_METRICS = False diff --git a/octopoes/octopoes/core/app.py b/octopoes/octopoes/core/app.py index 514742a09e9..3babe334a37 100644 --- a/octopoes/octopoes/core/app.py +++ b/octopoes/octopoes/core/app.py @@ -2,7 +2,7 @@ from amqp import AMQPError -from octopoes.config.settings import QUEUE_NAME_OCTOPOES, Settings +from octopoes.config.settings import GATHER_BIT_METRICS, QUEUE_NAME_OCTOPOES, Settings from octopoes.core.service import OctopoesService from octopoes.events.manager import EventManager, get_rabbit_channel from octopoes.repositories.ooi_repository import XTDBOOIRepository @@ -39,6 +39,9 @@ def bootstrap_octopoes(settings: Settings, client: str, xtdb_session: XTDBSessio origin_param_repository = XTDBOriginParameterRepository(event_manager, xtdb_session) scan_profile_repository = XTDBScanProfileRepository(event_manager, xtdb_session) - octopoes = OctopoesService(ooi_repository, origin_repository, origin_param_repository, scan_profile_repository) - - return octopoes + if GATHER_BIT_METRICS: + return OctopoesService( + ooi_repository, origin_repository, origin_param_repository, scan_profile_repository, xtdb_session + ) + else: + return OctopoesService(ooi_repository, origin_repository, origin_param_repository, scan_profile_repository) diff --git a/octopoes/octopoes/core/service.py b/octopoes/octopoes/core/service.py index 1243ae629ae..52fef38b695 100644 --- a/octopoes/octopoes/core/service.py +++ b/octopoes/octopoes/core/service.py @@ -3,10 +3,12 @@ from collections.abc import Callable, ValuesView from datetime import datetime, timezone from logging import getLogger +from time import perf_counter from typing import overload from bits.definitions import get_bit_definitions from bits.runner import BitRunner +from pydantic import TypeAdapter from octopoes.config.settings import ( DEFAULT_LIMIT, @@ -43,6 +45,7 @@ from octopoes.repositories.origin_parameter_repository import OriginParameterRepository from octopoes.repositories.origin_repository import OriginRepository from octopoes.repositories.scan_profile_repository import ScanProfileRepository +from octopoes.xtdb.client import Operation, OperationType, XTDBSession logger = getLogger(__name__) settings = Settings() @@ -67,11 +70,13 @@ def __init__( origin_repository: OriginRepository, origin_parameter_repository: OriginParameterRepository, scan_profile_repository: ScanProfileRepository, + session: XTDBSession | None = None, ): self.ooi_repository = ooi_repository self.origin_repository = origin_repository self.origin_parameter_repository = origin_parameter_repository self.scan_profile_repository = scan_profile_repository + self.session = session @overload def _populate_scan_profiles(self, oois: ValuesView[OOI], valid_time: datetime) -> ValuesView[OOI]: ... @@ -200,7 +205,23 @@ def _run_inference(self, origin: Origin, valid_time: datetime) -> None: config = configs[-1].config try: - resulting_oois = BitRunner(bit_definition).run(source, parameters, config=config) + if isinstance(self.session, XTDBSession): + start = perf_counter() + resulting_oois = BitRunner(bit_definition).run(source, parameters, config=config) + stop = perf_counter() + metrics: dict[str, str] = { + "bit": bit_definition.id, + "config": json.dumps(config), + "elapsed": str(stop - start), + "parameters": TypeAdapter(list[OOI]).dump_json(parameters).decode(), + "source": source.model_dump_json(), + "xt/id": "BIT_METRIC", + "yield": TypeAdapter(list[OOI]).dump_json(resulting_oois).decode(), + } + ops: list[Operation] = [(OperationType.PUT, metrics, valid_time)] + self.session.client.submit_transaction(ops) + else: + resulting_oois = BitRunner(bit_definition).run(source, parameters, config=config) self.save_origin(origin, resulting_oois, valid_time) except Exception as e: logger.exception("Error running inference", exc_info=e) diff --git a/octopoes/tools/analyze-bit-metric.py b/octopoes/tools/analyze-bit-metric.py new file mode 100755 index 00000000000..841e04fb8da --- /dev/null +++ b/octopoes/tools/analyze-bit-metric.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +import json +import logging +from datetime import datetime + +import click +from xtdb_client import XTDBClient + +logger = logging.getLogger(__name__) + + +class BitMetric: + def __init__(self, data): + date_format = "%Y-%m-%dT%H:%M:%SZ" + self.tx_time: datetime = datetime.strptime(data["txTime"], date_format) + self.tx_id: int = int(data["txId"]) + self.valid_time: datetime = datetime.strptime(data["validTime"], date_format) + self.content_hash: str = data["contentHash"] + self.yld: dict[str, str] = json.loads(data["doc"]["yield"]) + self.cfg: dict[str, str] = json.loads(data["doc"]["config"]) + self.src: dict[str, str] = json.loads(data["doc"]["source"]) + self.name: str = data["doc"]["bit"] + self.pms: list[dict[str, str]] = json.loads(data["doc"]["parameters"]) + self.elapsed: list[dict[str, str]] = json.loads(data["doc"]["elapsed"]) + + def empty(self): + return len(self.yld) == 0 + + def __eq__(self, val): + return ( + self.src == val.src + and self.cfg == val.cfg + and self.yld == val.yld + and self.name == val.name + and self.pms == val.pms + ) + + def __hash__(self): + return hash(str(hash(self.tx_time)) + self.content_hash) + + +@click.group( + context_settings={ + "help_option_names": ["-h", "--help"], + "max_content_width": 120, + "show_default": True, + } +) +@click.option("-n", "--node", default="0", help="XTDB node") +@click.option( + "-u", + "--url", + default="http://localhost:3000", + help="XTDB server base url", +) +@click.option( + "-t", + "--timeout", + type=int, + default=5000, + help="XTDB request timeout (in ms)", +) +@click.option("-v", "--verbosity", count=True, help="Increase the verbosity level") +@click.pass_context +def cli(ctx: click.Context, url: str, node: str, timeout: int, verbosity: int): + verbosities = [logging.WARN, logging.INFO, logging.DEBUG] + try: + if verbosity: + logging.basicConfig(level=verbosities[verbosity - 1]) + except IndexError: + raise click.UsageError("Invalid verbosity level (use -v, -vv, or -vvv)") + + client = XTDBClient(url, node, timeout) + logger.info("Instantiated XTDB client with endpoint %s for node %s", url, node) + + ctx.ensure_object(dict) + ctx.obj["client"] = client + ctx.obj["raw_bit_metrics"] = client.history("BIT_METRIC", False, True) + if not ctx.obj["raw_bit_metrics"]: + raise click.UsageError("No bit metrics found") + if "error" in ctx.obj["raw_bit_metrics"] and ctx.obj["raw_bit_metrics"]["error"] == "Node not found": + raise click.UsageError("Node node found") + ctx.obj["bit_metrics"] = list(map(lambda x: BitMetric(x), ctx.obj["raw_bit_metrics"])) + + +@cli.command(help="Returns the raw bit metric") +@click.pass_context +def raw(ctx: click.Context): + click.echo(json.dumps(ctx.obj["raw_bit_metrics"])) + + +@cli.command(help="Returns the parsed metric") +@click.pass_context +def parse(ctx: click.Context): + bit_metrics = ctx.obj["bit_metrics"] + metrics = { + "total": len(bit_metrics), + "total_elapsed": sum([bm.elapsed for bm in bit_metrics]), + "empty": len([bm for bm in bit_metrics if bm.empty()]), + "empty_elapsed": sum([bm.elapsed for bm in bit_metrics if bm.empty()]), + "useful": len([bm for bm in bit_metrics if not bm.empty()]), + "useful_elapsed": sum([bm.elapsed for bm in bit_metrics if not bm.empty()]), + "futile_runs": {bm.name: bit_metrics.count(bm) - 1 for bm in bit_metrics if bit_metrics.count(bm) > 1}, + } + click.echo(json.dumps(metrics)) + + +if __name__ == "__main__": + cli() From 6826ad213719c9a05e7fdb20eab658238de022da Mon Sep 17 00:00:00 2001 From: ammar92 Date: Thu, 11 Jul 2024 12:20:12 +0200 Subject: [PATCH 016/112] Implement `structlog` (#3175) Co-authored-by: Jeroen Dekkers --- boefjes/boefjes/__main__.py | 19 +++++- boefjes/boefjes/api.py | 4 +- boefjes/boefjes/app.py | 4 +- boefjes/boefjes/clients/bytes_client.py | 4 +- boefjes/boefjes/clients/scheduler_client.py | 3 - boefjes/boefjes/dependencies/plugins.py | 4 +- boefjes/boefjes/docker_boefjes_runner.py | 4 +- boefjes/boefjes/job_handler.py | 4 +- boefjes/boefjes/katalogus/root.py | 19 +++++- boefjes/boefjes/local.py | 5 +- boefjes/boefjes/local_repository.py | 9 +-- boefjes/boefjes/seed.py | 6 +- boefjes/boefjes/sql/db.py | 4 +- boefjes/boefjes/sql/organisation_storage.py | 4 +- boefjes/boefjes/sql/plugin_storage.py | 4 +- boefjes/boefjes/sql/session.py | 5 +- boefjes/poetry.lock | 19 +++++- boefjes/pyproject.toml | 1 + boefjes/requirements-dev.txt | 3 + boefjes/requirements.txt | 3 + bytes/bytes/api/__init__.py | 20 +++++- bytes/bytes/api/metrics.py | 5 +- bytes/bytes/api/root.py | 4 +- bytes/bytes/api/router.py | 4 +- bytes/bytes/auth.py | 4 +- bytes/bytes/database/db.py | 4 +- bytes/bytes/database/sql_meta_repository.py | 4 +- bytes/bytes/rabbitmq.py | 6 +- bytes/bytes/raw/file_raw_repository.py | 5 +- bytes/bytes/timestamping/hashing.py | 4 +- bytes/poetry.lock | 19 +++++- bytes/pyproject.toml | 1 + bytes/requirements-dev.txt | 3 + bytes/requirements.txt | 3 + octopoes/octopoes/api/api.py | 17 ++++- octopoes/octopoes/core/app.py | 5 +- octopoes/octopoes/events/manager.py | 4 +- .../octopoes/repositories/ooi_repository.py | 4 +- octopoes/octopoes/tasks/tasks.py | 21 +++++- octopoes/octopoes/xtdb/client.py | 4 +- octopoes/poetry.lock | 19 +++++- octopoes/pyproject.toml | 1 + octopoes/requirements-dev.txt | 3 + octopoes/requirements.txt | 3 + octopoes/tests/test_api.py | 41 +++++++---- rocky/crisis_room/views.py | 4 +- rocky/katalogus/health.py | 5 +- rocky/katalogus/views/plugin_settings_add.py | 4 -- rocky/katalogus/views/plugin_settings_list.py | 4 -- rocky/poetry.lock | 68 ++++++++++++++++++- rocky/pyproject.toml | 2 + rocky/reports/utils.py | 4 +- rocky/requirements-dev.txt | 12 ++++ rocky/requirements.txt | 12 ++++ rocky/rocky/auth/remote_user.py | 5 +- rocky/rocky/bytes_client.py | 4 +- rocky/rocky/otel.py | 5 +- rocky/rocky/settings.py | 51 ++++++++++++-- rocky/rocky/views/bytes_raw.py | 4 +- rocky/rocky/views/finding_list.py | 4 +- rocky/rocky/views/health.py | 5 +- rocky/rocky/views/mixins.py | 4 +- rocky/rocky/views/ooi_add.py | 34 +++++++--- rocky/rocky/views/organization_add.py | 5 +- rocky/rocky/views/organization_member_add.py | 4 +- rocky/tools/add_ooi_information.py | 4 +- rocky/tools/models.py | 4 +- 67 files changed, 442 insertions(+), 142 deletions(-) diff --git a/boefjes/boefjes/__main__.py b/boefjes/boefjes/__main__.py index e9621de3e0e..2f7b406f9c3 100644 --- a/boefjes/boefjes/__main__.py +++ b/boefjes/boefjes/__main__.py @@ -2,6 +2,7 @@ import logging.config import click +import structlog from boefjes.app import get_runtime_manager from boefjes.config import settings @@ -10,7 +11,23 @@ with settings.log_cfg.open() as f: logging.config.dictConfig(json.load(f)) -logger = logging.getLogger(__name__) +structlog.configure( + processors=[ + structlog.contextvars.merge_contextvars, + structlog.processors.add_log_level, + structlog.processors.StackInfoRenderer(), + structlog.dev.set_exc_info, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), + structlog.dev.ConsoleRenderer(), + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) + +logger = structlog.get_logger(__name__) @click.command() diff --git a/boefjes/boefjes/api.py b/boefjes/boefjes/api.py index c1fbce49dbe..07f768a5b24 100644 --- a/boefjes/boefjes/api.py +++ b/boefjes/boefjes/api.py @@ -1,10 +1,10 @@ import base64 -import logging import multiprocessing from datetime import datetime, timezone from enum import Enum from uuid import UUID +import structlog from fastapi import Depends, FastAPI, HTTPException, Response from httpx import HTTPError, HTTPStatusError from pydantic import BaseModel, ConfigDict, Field @@ -21,7 +21,7 @@ from octopoes.models.exception import ObjectNotFoundException app = FastAPI(title="Boefje API") -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class UvicornServer(multiprocessing.Process): diff --git a/boefjes/boefjes/app.py b/boefjes/boefjes/app.py index db725042596..16f33fa4048 100644 --- a/boefjes/boefjes/app.py +++ b/boefjes/boefjes/app.py @@ -1,4 +1,3 @@ -import logging import multiprocessing as mp import os import signal @@ -6,6 +5,7 @@ import time from queue import Queue +import structlog from httpx import HTTPError from pydantic import ValidationError @@ -21,7 +21,7 @@ from boefjes.local_repository import get_local_repository from boefjes.runtime_interfaces import Handler, WorkerManager -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class SchedulerWorkerManager(WorkerManager): diff --git a/boefjes/boefjes/clients/bytes_client.py b/boefjes/boefjes/clients/bytes_client.py index bfa91ecf9db..747a4aefcd5 100644 --- a/boefjes/boefjes/clients/bytes_client.py +++ b/boefjes/boefjes/clients/bytes_client.py @@ -1,16 +1,16 @@ -import logging import typing from collections.abc import Callable, Set from functools import wraps from typing import Any from uuid import UUID +import structlog from httpx import Client, HTTPStatusError, HTTPTransport, Response from boefjes.job_models import BoefjeMeta, NormalizerMeta, RawDataMeta BYTES_API_CLIENT_VERSION = "0.3" -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) ClientSessionMethod = Callable[..., Any] diff --git a/boefjes/boefjes/clients/scheduler_client.py b/boefjes/boefjes/clients/scheduler_client.py index be7c04f8d26..3611e687b4b 100644 --- a/boefjes/boefjes/clients/scheduler_client.py +++ b/boefjes/boefjes/clients/scheduler_client.py @@ -1,5 +1,4 @@ import datetime -import logging import uuid from enum import Enum @@ -8,8 +7,6 @@ from boefjes.job_models import BoefjeMeta, NormalizerMeta -logger = logging.getLogger(__name__) - class Queue(BaseModel): id: str diff --git a/boefjes/boefjes/dependencies/plugins.py b/boefjes/boefjes/dependencies/plugins.py index 8be80ae70db..c99896aab11 100644 --- a/boefjes/boefjes/dependencies/plugins.py +++ b/boefjes/boefjes/dependencies/plugins.py @@ -1,9 +1,9 @@ import contextlib -import logging from collections.abc import Iterator from pathlib import Path from typing import Literal +import structlog from fastapi import Query from jsonschema.exceptions import ValidationError from jsonschema.validators import validate @@ -23,7 +23,7 @@ SettingsNotConformingToSchema, ) -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class PluginService: diff --git a/boefjes/boefjes/docker_boefjes_runner.py b/boefjes/boefjes/docker_boefjes_runner.py index c52c4d2d0fd..f28c64055ae 100644 --- a/boefjes/boefjes/docker_boefjes_runner.py +++ b/boefjes/boefjes/docker_boefjes_runner.py @@ -1,7 +1,7 @@ -import logging from datetime import datetime, timezone import docker +import structlog from docker.errors import APIError, ContainerError, ImageNotFound from httpx import HTTPError @@ -11,7 +11,7 @@ from boefjes.job_models import BoefjeMeta from boefjes.models import Boefje -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class DockerBoefjesRunner: diff --git a/boefjes/boefjes/job_handler.py b/boefjes/boefjes/job_handler.py index eb3cf3715ac..95a53406cb5 100644 --- a/boefjes/boefjes/job_handler.py +++ b/boefjes/boefjes/job_handler.py @@ -1,4 +1,3 @@ -import logging import os import traceback from collections.abc import Callable @@ -7,6 +6,7 @@ from typing import Any, cast import httpx +import structlog from httpx import HTTPError from boefjes.clients.bytes_client import BytesAPIClient @@ -23,7 +23,7 @@ MIMETYPE_MIN_LENGTH = 5 # two chars before, and 2 chars after the slash ought to be reasonable -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) bytes_api_client = BytesAPIClient( str(settings.bytes_api), diff --git a/boefjes/boefjes/katalogus/root.py b/boefjes/boefjes/katalogus/root.py index 6203c850777..15b19b48401 100644 --- a/boefjes/boefjes/katalogus/root.py +++ b/boefjes/boefjes/katalogus/root.py @@ -2,6 +2,7 @@ import logging.config from typing import Any +import structlog from fastapi import APIRouter, FastAPI, Request, status from fastapi.responses import JSONResponse, RedirectResponse from opentelemetry import trace @@ -23,7 +24,23 @@ with settings.log_cfg.open() as f: logging.config.dictConfig(json.load(f)) -logger = logging.getLogger(__name__) +structlog.configure( + processors=[ + structlog.contextvars.merge_contextvars, + structlog.processors.add_log_level, + structlog.processors.StackInfoRenderer(), + structlog.dev.set_exc_info, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), + structlog.dev.ConsoleRenderer(), + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) + +logger = structlog.get_logger(__name__) app = FastAPI(title="KAT-alogus API", version=__version__) diff --git a/boefjes/boefjes/local.py b/boefjes/boefjes/local.py index adbf662dacf..e743c9b9de9 100644 --- a/boefjes/boefjes/local.py +++ b/boefjes/boefjes/local.py @@ -1,7 +1,8 @@ -import logging import os from collections.abc import Iterable +import structlog + from boefjes.job_models import ( BoefjeMeta, InvalidReturnValueNormalizer, @@ -17,7 +18,7 @@ from boefjes.runtime_interfaces import BoefjeJobRunner, JobRuntimeError, NormalizerJobRunner from octopoes.models import OOI, DeclaredScanProfile -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class TemporaryEnvironment: diff --git a/boefjes/boefjes/local_repository.py b/boefjes/boefjes/local_repository.py index ef5b17442b1..4e53054fe43 100644 --- a/boefjes/boefjes/local_repository.py +++ b/boefjes/boefjes/local_repository.py @@ -1,9 +1,10 @@ import json -import logging import pkgutil from pathlib import Path from typing import Any +import structlog + from boefjes.models import PluginType from boefjes.plugins.models import ( BOEFJE_DEFINITION_FILE, @@ -15,7 +16,7 @@ NormalizerResource, ) -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class LocalPluginRepository: @@ -133,14 +134,14 @@ def _find_packages_in_path_containing_files(self, required_files: list[str]) -> for package in pkgutil.walk_packages([str(self.path)], prefix): if not package.ispkg: - logging.debug("%s is not a package", package.name) + logger.debug("%s is not a package", package.name) continue path = self.path / package.name.replace(prefix, "").replace(".", "/") missing_files = [file for file in required_files if not (path / file).exists()] if missing_files: - logging.debug("Files %s not found for %s", missing_files, package.name) + logger.debug("Files %s not found for %s", missing_files, package.name) continue paths.append((path, package.name)) diff --git a/boefjes/boefjes/seed.py b/boefjes/boefjes/seed.py index a849fd89dc4..c28877afd18 100644 --- a/boefjes/boefjes/seed.py +++ b/boefjes/boefjes/seed.py @@ -1,5 +1,3 @@ -import logging +import structlog -logger = logging.getLogger(__name__) - -logger.warning("This module has been phased out in v1.16.0 and will be removed in v1.17.0") +structlog.get_logger(__name__).warning("This module has been phased out in v1.16.0 and will be removed in v1.17.0") diff --git a/boefjes/boefjes/sql/db.py b/boefjes/boefjes/sql/db.py index 6a1ad303574..6ff839e5d96 100644 --- a/boefjes/boefjes/sql/db.py +++ b/boefjes/boefjes/sql/db.py @@ -1,16 +1,16 @@ -import logging from collections.abc import Callable, Iterator from functools import cache from types import UnionType from typing import Any +import structlog from sqlalchemy import create_engine from sqlalchemy.engine import Engine, make_url from sqlalchemy.orm import Session, declarative_base, sessionmaker from boefjes.config import settings -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) SQL_BASE = declarative_base() diff --git a/boefjes/boefjes/sql/organisation_storage.py b/boefjes/boefjes/sql/organisation_storage.py index 012d779576f..4591ffc574f 100644 --- a/boefjes/boefjes/sql/organisation_storage.py +++ b/boefjes/boefjes/sql/organisation_storage.py @@ -1,6 +1,6 @@ -import logging from collections.abc import Iterator +import structlog from sqlalchemy.orm import Session from boefjes.config import Settings, settings @@ -10,7 +10,7 @@ from boefjes.sql.session import SessionMixin from boefjes.storage.interfaces import OrganisationNotFound, OrganisationStorage -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class SQLOrganisationStorage(SessionMixin, OrganisationStorage): diff --git a/boefjes/boefjes/sql/plugin_storage.py b/boefjes/boefjes/sql/plugin_storage.py index df368d92894..2dddd0ad822 100644 --- a/boefjes/boefjes/sql/plugin_storage.py +++ b/boefjes/boefjes/sql/plugin_storage.py @@ -1,6 +1,6 @@ -import logging from collections.abc import Iterator +import structlog from sqlalchemy.orm import Session from boefjes.config import Settings, settings @@ -10,7 +10,7 @@ from boefjes.sql.session import SessionMixin from boefjes.storage.interfaces import NotAllowed, PluginNotFound, PluginStorage -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class SQLPluginStorage(SessionMixin, PluginStorage): diff --git a/boefjes/boefjes/sql/session.py b/boefjes/boefjes/sql/session.py index 79aa1a79d0b..4a832a12bfa 100644 --- a/boefjes/boefjes/sql/session.py +++ b/boefjes/boefjes/sql/session.py @@ -1,11 +1,10 @@ -import logging - +import structlog from sqlalchemy.exc import DatabaseError from sqlalchemy.orm import Session from boefjes.storage.interfaces import StorageError -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class SessionMixin: diff --git a/boefjes/poetry.lock b/boefjes/poetry.lock index 19282a4fbe4..1d16b1e3421 100644 --- a/boefjes/poetry.lock +++ b/boefjes/poetry.lock @@ -2521,6 +2521,23 @@ anyio = ">=3.4.0,<5" [package.extras] full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] +[[package]] +name = "structlog" +version = "24.2.0" +description = "Structured Logging for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "structlog-24.2.0-py3-none-any.whl", hash = "sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a"}, + {file = "structlog-24.2.0.tar.gz", hash = "sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b"}, +] + +[package.extras] +dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] +tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] +typing = ["mypy (>=1.4)", "rich", "twisted"] + [[package]] name = "tldextract" version = "3.5.0" @@ -2837,4 +2854,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "fcf9ac947375cbf0522b47e6158313a3d1232067d799d1a57ef2a5b4052bf57f" +content-hash = "6f319dcf4745799025f981e4b04c31e8b07c57a21abfde2cb7ecc4740c19bcb3" diff --git a/boefjes/pyproject.toml b/boefjes/pyproject.toml index 0c8b9f07fed..de6becc599d 100644 --- a/boefjes/pyproject.toml +++ b/boefjes/pyproject.toml @@ -70,6 +70,7 @@ opentelemetry-proto = "^1.24.0" opentelemetry-semantic-conventions = "^0.45b0" opentelemetry-util-http = "^0.45b0" fastapi-slim = "^0.111.0" +structlog = "^24.2.0" [tool.poetry.group.dev.dependencies] pytest = "^8.2.0" diff --git a/boefjes/requirements-dev.txt b/boefjes/requirements-dev.txt index f04e16169ea..885c62a5929 100644 --- a/boefjes/requirements-dev.txt +++ b/boefjes/requirements-dev.txt @@ -1241,6 +1241,9 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 +structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ + --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a tldextract==3.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2cb271ca8d06ea1630a1361b58edad14e0cf81f34ce3c90b052854528fe2a281 \ --hash=sha256:4df1c65b95be61d59428e8611e955e54e6f1d4483d3e8d5733d3a9062155e910 diff --git a/boefjes/requirements.txt b/boefjes/requirements.txt index b7f4f6760a0..8a82a442240 100644 --- a/boefjes/requirements.txt +++ b/boefjes/requirements.txt @@ -1229,6 +1229,9 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 +structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ + --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a tldextract==3.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2cb271ca8d06ea1630a1361b58edad14e0cf81f34ce3c90b052854528fe2a281 \ --hash=sha256:4df1c65b95be61d59428e8611e955e54e6f1d4483d3e8d5733d3a9062155e910 diff --git a/bytes/bytes/api/__init__.py b/bytes/bytes/api/__init__.py index 36e1fd9064f..145af6e5986 100644 --- a/bytes/bytes/api/__init__.py +++ b/bytes/bytes/api/__init__.py @@ -1,5 +1,6 @@ import logging.config +import structlog from fastapi import FastAPI from fastapi.exceptions import RequestValidationError from opentelemetry import trace @@ -17,9 +18,24 @@ from bytes.api.router import router from bytes.config import get_settings -logger = logging.getLogger(__name__) - logging.config.fileConfig(get_settings().log_cfg, disable_existing_loggers=False) +structlog.configure( + processors=[ + structlog.contextvars.merge_contextvars, + structlog.processors.add_log_level, + structlog.processors.StackInfoRenderer(), + structlog.dev.set_exc_info, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), + structlog.dev.ConsoleRenderer(), + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) + +logger = structlog.get_logger(__name__) app = FastAPI(title="Bytes API") diff --git a/bytes/bytes/api/metrics.py b/bytes/bytes/api/metrics.py index 48f937b4719..d6a44010b4a 100644 --- a/bytes/bytes/api/metrics.py +++ b/bytes/bytes/api/metrics.py @@ -1,5 +1,4 @@ -import logging - +import structlog from cachetools import TTLCache, cached from prometheus_client import CollectorRegistry, Gauge @@ -21,7 +20,7 @@ labelnames=["organization_id"], ) -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) def ignore_arguments_key(meta_repository: MetaDataRepository): diff --git a/bytes/bytes/api/root.py b/bytes/bytes/api/root.py index d26468ee2e1..567a4bf0f03 100644 --- a/bytes/bytes/api/root.py +++ b/bytes/bytes/api/root.py @@ -1,7 +1,7 @@ -import logging from typing import Any import prometheus_client +import structlog from fastapi import APIRouter, Depends, status from fastapi.exceptions import RequestValidationError from fastapi.requests import Request @@ -16,7 +16,7 @@ from bytes.version import __version__ router = APIRouter() -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class ServiceHealth(BaseModel): diff --git a/bytes/bytes/api/router.py b/bytes/bytes/api/router.py index d6961c91dcd..c160e3db66b 100644 --- a/bytes/bytes/api/router.py +++ b/bytes/bytes/api/router.py @@ -1,6 +1,6 @@ -import logging from uuid import UUID +import structlog from cachetools import TTLCache, cached from fastapi import APIRouter, Depends, HTTPException, Query, Request from fastapi.responses import Response @@ -16,7 +16,7 @@ from bytes.rabbitmq import create_event_manager from bytes.repositories.meta_repository import BoefjeMetaFilter, MetaDataRepository, NormalizerMetaFilter, RawDataFilter -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) router = APIRouter(dependencies=[Depends(authenticate_token)]) BOEFJE_META_TAG = "BoefjeMeta" NORMALIZER_META_TAG = "NormalizerMeta" diff --git a/bytes/bytes/auth.py b/bytes/bytes/auth.py index 29e3808fe7e..65fb980f946 100644 --- a/bytes/bytes/auth.py +++ b/bytes/bytes/auth.py @@ -1,7 +1,7 @@ -import logging from datetime import datetime, timedelta, timezone import jwt +import structlog from fastapi import Depends, HTTPException from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt import InvalidTokenError @@ -11,7 +11,7 @@ from bytes.config import get_settings -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) ALGORITHM = "HS256" oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") diff --git a/bytes/bytes/database/db.py b/bytes/bytes/database/db.py index 369ff2345d6..c96790d3766 100644 --- a/bytes/bytes/database/db.py +++ b/bytes/bytes/database/db.py @@ -1,11 +1,11 @@ -import logging from functools import lru_cache +import structlog from sqlalchemy import create_engine from sqlalchemy.engine import Engine, make_url from sqlalchemy.orm import declarative_base -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) SQL_BASE = declarative_base() diff --git a/bytes/bytes/database/sql_meta_repository.py b/bytes/bytes/database/sql_meta_repository.py index 4faac6e4cab..2bdbacf2c37 100644 --- a/bytes/bytes/database/sql_meta_repository.py +++ b/bytes/bytes/database/sql_meta_repository.py @@ -1,7 +1,7 @@ -import logging import uuid from collections.abc import Iterator +import structlog from sqlalchemy import func from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import Session, sessionmaker @@ -17,7 +17,7 @@ from bytes.timestamping.hashing import hash_data from bytes.timestamping.provider import create_hash_repository -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class SQLMetaDataRepository(MetaDataRepository): diff --git a/bytes/bytes/rabbitmq.py b/bytes/bytes/rabbitmq.py index 94413d27f3b..75aebc4ab54 100644 --- a/bytes/bytes/rabbitmq.py +++ b/bytes/bytes/rabbitmq.py @@ -1,14 +1,14 @@ -import logging from functools import lru_cache import pika import pika.exceptions +import structlog from bytes.config import get_settings from bytes.events.events import Event from bytes.events.manager import EventManager -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class RabbitMQEventManager(EventManager): @@ -21,7 +21,7 @@ def __init__(self, queue_uri: str): def publish(self, event: Event) -> None: self._check_connection() - event_data = event.json() + event_data = event.model_dump_json() logger.debug("Publishing event: %s", event_data) queue_name = self._queue_name(event) diff --git a/bytes/bytes/raw/file_raw_repository.py b/bytes/bytes/raw/file_raw_repository.py index 9bdeebf5330..b8192d02988 100644 --- a/bytes/bytes/raw/file_raw_repository.py +++ b/bytes/bytes/raw/file_raw_repository.py @@ -1,13 +1,14 @@ -import logging from pathlib import Path from uuid import UUID +import structlog + from bytes.config import Settings from bytes.models import BoefjeMeta, RawData from bytes.raw.middleware import FileMiddleware, make_middleware from bytes.repositories.raw_repository import BytesFileNotFoundException, RawRepository -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) def create_raw_repository(settings: Settings) -> RawRepository: diff --git a/bytes/bytes/timestamping/hashing.py b/bytes/bytes/timestamping/hashing.py index 728b4b5917f..0c16f1cc1ef 100644 --- a/bytes/bytes/timestamping/hashing.py +++ b/bytes/bytes/timestamping/hashing.py @@ -1,12 +1,12 @@ import hashlib -import logging from typing import Any +import structlog from pydantic import AwareDatetime from bytes.models import HashingAlgorithm, RawData, SecureHash -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) def hash_data( diff --git a/bytes/poetry.lock b/bytes/poetry.lock index 903b7121131..f3cd9d0a27f 100644 --- a/bytes/poetry.lock +++ b/bytes/poetry.lock @@ -1541,6 +1541,23 @@ anyio = ">=3.4.0,<5" [package.extras] full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] +[[package]] +name = "structlog" +version = "24.2.0" +description = "Structured Logging for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "structlog-24.2.0-py3-none-any.whl", hash = "sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a"}, + {file = "structlog-24.2.0.tar.gz", hash = "sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b"}, +] + +[package.extras] +dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] +tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] +typing = ["mypy (>=1.4)", "rich", "twisted"] + [[package]] name = "tomli" version = "2.0.1" @@ -1696,4 +1713,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "2421d61418206a16e918cecd3dab98a8a62b7554a3cb0cb079336cf09d298bd5" +content-hash = "d7a3bdc28150ed7f912890a56858cd72fb43b1cba5da7d6ab7093d56e2096b6b" diff --git a/bytes/pyproject.toml b/bytes/pyproject.toml index 86ba312cb20..e1a66181544 100644 --- a/bytes/pyproject.toml +++ b/bytes/pyproject.toml @@ -38,6 +38,7 @@ opentelemetry-semantic-conventions = "^0.45b0" opentelemetry-util-http = "^0.45b0" pyjwt = "^2.8.0" fastapi-slim = "^0.111.0" +structlog = "^24.2.0" [tool.poetry.group.dev.dependencies] pytest = "^8.2.0" diff --git a/bytes/requirements-dev.txt b/bytes/requirements-dev.txt index 3da21c0a5a1..b3b2e2b51fa 100644 --- a/bytes/requirements-dev.txt +++ b/bytes/requirements-dev.txt @@ -683,6 +683,9 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 +structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ + --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a tomli==2.0.1 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f diff --git a/bytes/requirements.txt b/bytes/requirements.txt index 8e53dfb22d5..15259eca56f 100644 --- a/bytes/requirements.txt +++ b/bytes/requirements.txt @@ -668,6 +668,9 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 +structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ + --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a diff --git a/octopoes/octopoes/api/api.py b/octopoes/octopoes/api/api.py index d186b0ad995..0980dce2b3a 100644 --- a/octopoes/octopoes/api/api.py +++ b/octopoes/octopoes/api/api.py @@ -3,6 +3,7 @@ from logging import config from pathlib import Path +import structlog import yaml from fastapi import FastAPI, HTTPException, status from fastapi.exceptions import RequestValidationError @@ -38,7 +39,21 @@ except FileNotFoundError: logger.warning("No log config found at: %s", settings.log_cfg) - +structlog.configure( + processors=[ + structlog.contextvars.merge_contextvars, + structlog.processors.add_log_level, + structlog.processors.StackInfoRenderer(), + structlog.dev.set_exc_info, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), + structlog.dev.ConsoleRenderer(), + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) app = FastAPI(title="Octopoes API") # Set up OpenTelemetry instrumentation diff --git a/octopoes/octopoes/core/app.py b/octopoes/octopoes/core/app.py index 3babe334a37..9840f0beaf1 100644 --- a/octopoes/octopoes/core/app.py +++ b/octopoes/octopoes/core/app.py @@ -1,5 +1,4 @@ -import logging - +import structlog from amqp import AMQPError from octopoes.config.settings import GATHER_BIT_METRICS, QUEUE_NAME_OCTOPOES, Settings @@ -12,7 +11,7 @@ from octopoes.tasks.app import app as celery_app from octopoes.xtdb.client import XTDBHTTPClient, XTDBSession -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) def get_xtdb_client(base_uri: str, client: str) -> XTDBHTTPClient: diff --git a/octopoes/octopoes/events/manager.py b/octopoes/octopoes/events/manager.py index e6c4f16ca85..3bd3cfa9102 100644 --- a/octopoes/octopoes/events/manager.py +++ b/octopoes/octopoes/events/manager.py @@ -1,10 +1,10 @@ import json -import logging import threading import uuid from collections.abc import Callable import pika +import structlog from celery import Celery from pika.adapters.blocking_connection import BlockingChannel from pika.exceptions import StreamLostError @@ -13,7 +13,7 @@ from octopoes.events.events import DBEvent, OperationType, ScanProfileDBEvent from octopoes.models import ScanProfile, format_id_short -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class AbstractOOI(BaseModel): diff --git a/octopoes/octopoes/repositories/ooi_repository.py b/octopoes/octopoes/repositories/ooi_repository.py index 2cf056ee7dc..140148c53e9 100644 --- a/octopoes/octopoes/repositories/ooi_repository.py +++ b/octopoes/octopoes/repositories/ooi_repository.py @@ -1,11 +1,11 @@ from __future__ import annotations import json -import logging from collections import Counter from datetime import datetime from typing import Any, cast +import structlog from bits.definitions import BitDefinition from httpx import HTTPStatusError, codes from pydantic import RootModel, TypeAdapter @@ -36,7 +36,7 @@ from octopoes.xtdb.query_builder import generate_pull_query, str_val from octopoes.xtdb.related_field_generator import RelatedFieldNode -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) def merge_ooi(ooi_new: OOI, ooi_old: OOI) -> tuple[OOI, bool]: diff --git a/octopoes/octopoes/tasks/tasks.py b/octopoes/octopoes/tasks/tasks.py index 5df58487440..3144e883830 100644 --- a/octopoes/octopoes/tasks/tasks.py +++ b/octopoes/octopoes/tasks/tasks.py @@ -1,9 +1,10 @@ import timeit import uuid from datetime import datetime, timezone -from logging import config, getLogger +from logging import config from pathlib import Path +import structlog import yaml from celery.signals import worker_process_init, worker_process_shutdown from celery.utils.log import get_task_logger @@ -19,7 +20,7 @@ from octopoes.xtdb.client import XTDBSession settings = Settings() -logger = getLogger(__name__) +logger = structlog.get_logger(__name__) try: with Path(settings.log_cfg).open() as log_config: @@ -28,6 +29,22 @@ except FileNotFoundError: logger.warning("No log config found at: %s", settings.log_cfg) +structlog.configure( + processors=[ + structlog.contextvars.merge_contextvars, + structlog.processors.add_log_level, + structlog.processors.StackInfoRenderer(), + structlog.dev.set_exc_info, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.TimeStamper("iso", utc=False), + structlog.dev.ConsoleRenderer(colors=True), + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) + @worker_process_shutdown.connect def shutdown_worker(**kwargs): diff --git a/octopoes/octopoes/xtdb/client.py b/octopoes/octopoes/xtdb/client.py index 06a045ff740..4e312e81f53 100644 --- a/octopoes/octopoes/xtdb/client.py +++ b/octopoes/octopoes/xtdb/client.py @@ -1,5 +1,4 @@ import functools -import logging from collections.abc import Callable from datetime import datetime, timezone from enum import Enum @@ -7,6 +6,7 @@ from typing import Any import httpx +import structlog from httpx import HTTPError, HTTPStatusError, Response, codes from pydantic import BaseModel, ConfigDict, Field, TypeAdapter @@ -14,7 +14,7 @@ from octopoes.xtdb.exceptions import NodeNotFound, XTDBException from octopoes.xtdb.query import Query -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class OperationType(Enum): diff --git a/octopoes/poetry.lock b/octopoes/poetry.lock index e1bf60a9e51..a53f9e4f488 100644 --- a/octopoes/poetry.lock +++ b/octopoes/poetry.lock @@ -1835,6 +1835,23 @@ anyio = ">=3.4.0,<5" [package.extras] full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] +[[package]] +name = "structlog" +version = "24.2.0" +description = "Structured Logging for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "structlog-24.2.0-py3-none-any.whl", hash = "sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a"}, + {file = "structlog-24.2.0.tar.gz", hash = "sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b"}, +] + +[package.extras] +dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] +tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] +typing = ["mypy (>=1.4)", "rich", "twisted"] + [[package]] name = "tldextract" version = "3.5.0" @@ -2090,4 +2107,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "8c57cf18d907e2a0527de3ca3a88b04dca963cb20befcae344cf6069122aed72" +content-hash = "9c15b17d7b5e59678003fea67a3f095f2712d09e1a3e12358447a6335ea74836" diff --git a/octopoes/pyproject.toml b/octopoes/pyproject.toml index 6c246d4c53a..73b99e0de88 100644 --- a/octopoes/pyproject.toml +++ b/octopoes/pyproject.toml @@ -42,6 +42,7 @@ opentelemetry-semantic-conventions = "^0.45b0" opentelemetry-util-http = "^0.45b0" fastapi-slim = "^0.111.0" +structlog = "^24.2.0" [tool.poetry.group.dev.dependencies] robotframework = "^7.0" robotframework-requests = "^0.9.3" diff --git a/octopoes/requirements-dev.txt b/octopoes/requirements-dev.txt index 372b6351830..b2e7b31bdb2 100644 --- a/octopoes/requirements-dev.txt +++ b/octopoes/requirements-dev.txt @@ -751,6 +751,9 @@ sqlalchemy==1.4.48 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 +structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ + --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a tldextract==3.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2cb271ca8d06ea1630a1361b58edad14e0cf81f34ce3c90b052854528fe2a281 \ --hash=sha256:4df1c65b95be61d59428e8611e955e54e6f1d4483d3e8d5733d3a9062155e910 diff --git a/octopoes/requirements.txt b/octopoes/requirements.txt index 927526a1dc6..8a0ff99e452 100644 --- a/octopoes/requirements.txt +++ b/octopoes/requirements.txt @@ -654,6 +654,9 @@ sqlalchemy==1.4.48 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 +structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ + --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a tldextract==3.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2cb271ca8d06ea1630a1361b58edad14e0cf81f34ce3c90b052854528fe2a281 \ --hash=sha256:4df1c65b95be61d59428e8611e955e54e6f1d4483d3e8d5733d3a9062155e910 diff --git a/octopoes/tests/test_api.py b/octopoes/tests/test_api.py index 8e78b19f071..b4d8f0751fb 100644 --- a/octopoes/tests/test_api.py +++ b/octopoes/tests/test_api.py @@ -28,7 +28,10 @@ def test_health(httpx_mock, patch_pika): } httpx_mock.add_response( - method="GET", url="http://testxtdb:3000/_xtdb/_dev/status", json=xtdb_status, status_code=200 + method="GET", + url="http://testxtdb:3000/_xtdb/_dev/status", + json=xtdb_status, + status_code=200, ) response = client.get("/_dev/health") assert response.json() == { @@ -51,7 +54,9 @@ def test_health(httpx_mock, patch_pika): def test_health_no_xtdb_connection(httpx_mock, patch_pika): httpx_mock.add_exception( - httpx.ConnectTimeout("Connection timed out"), method="GET", url="http://testxtdb:3000/_xtdb/_dev/status" + httpx.ConnectTimeout("Connection timed out"), + method="GET", + url="http://testxtdb:3000/_xtdb/_dev/status", ) response = client.get("/_dev/health") assert response.json() == { @@ -94,12 +99,21 @@ def test_get_scan_profiles(httpx_mock, patch_pika, valid_time): ) response = client.get("/_dev/scan_profiles", params={"valid_time": str(valid_time)}) assert response.status_code == 200 - assert response.json() == [{"level": 0, "reference": "Hostname|internet|mispo.es", "scan_profile_type": "empty"}] + assert response.json() == [ + { + "level": 0, + "reference": "Hostname|internet|mispo.es", + "scan_profile_type": "empty", + } + ] def test_create_node(httpx_mock): httpx_mock.add_response( - method="POST", url="http://testxtdb:3000/_xtdb/create-node", json={"created": "true"}, status_code=200 + method="POST", + url="http://testxtdb:3000/_xtdb/create-node", + json={"created": "true"}, + status_code=200, ) response = client.post("/_dev/node") assert response.status_code == 200 @@ -107,7 +121,10 @@ def test_create_node(httpx_mock): def test_delete_node(httpx_mock): httpx_mock.add_response( - method="POST", url="http://testxtdb:3000/_xtdb/delete-node", json={"deleted": "true"}, status_code=200 + method="POST", + url="http://testxtdb:3000/_xtdb/delete-node", + json={"deleted": "true"}, + status_code=200, ) response = client.delete("/_dev/node") assert response.status_code == 200 @@ -157,10 +174,10 @@ def test_count_findings_by_severity(httpx_mock, patch_pika, caplog, valid_time): "unknown": 0, } - assert caplog.record_tuples == [ - ( - "octopoes.repositories.ooi_repository", - logging.WARNING, - "There are 2 KATFindingType|KAT-NO-FINDING-TYPE findings but the finding type is not in the database", - ) - ] + assert len(caplog.record_tuples) == 1 + logger, level, message = caplog.record_tuples[0] + assert logger == "octopoes.repositories.ooi_repository" + assert level == logging.WARNING + assert ( + "There are 2 KATFindingType|KAT-NO-FINDING-TYPE findings but the finding type is not in the database" in message + ) diff --git a/rocky/crisis_room/views.py b/rocky/crisis_room/views.py index 6e16e8ba0ef..0a780a0edcb 100644 --- a/rocky/crisis_room/views.py +++ b/rocky/crisis_room/views.py @@ -1,6 +1,6 @@ -import logging from dataclasses import dataclass +import structlog from account.models import KATUser from django.conf import settings from django.contrib import messages @@ -17,7 +17,7 @@ from rocky.views.mixins import ObservedAtMixin from rocky.views.ooi_view import ConnectorFormMixin -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) # dataclass to store finding type counts diff --git a/rocky/katalogus/health.py b/rocky/katalogus/health.py index 8024d6e2936..46915c54dc3 100644 --- a/rocky/katalogus/health.py +++ b/rocky/katalogus/health.py @@ -1,11 +1,10 @@ -import logging - +import structlog from httpx import HTTPError from katalogus.client import get_katalogus from rocky.health import ServiceHealth -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) def get_katalogus_health() -> ServiceHealth: diff --git a/rocky/katalogus/views/plugin_settings_add.py b/rocky/katalogus/views/plugin_settings_add.py index 5abbf5bc358..47842b284a5 100644 --- a/rocky/katalogus/views/plugin_settings_add.py +++ b/rocky/katalogus/views/plugin_settings_add.py @@ -1,5 +1,3 @@ -import logging - from account.mixins import OrganizationPermissionRequiredMixin from django.contrib import messages from django.shortcuts import redirect @@ -11,8 +9,6 @@ from katalogus.forms import PluginSchemaForm from katalogus.views.mixins import SinglePluginView -logger = logging.getLogger(__name__) - class PluginSettingsAddView(OrganizationPermissionRequiredMixin, SinglePluginView, FormView): """View to add a general setting for all plugins in KAT-alogus""" diff --git a/rocky/katalogus/views/plugin_settings_list.py b/rocky/katalogus/views/plugin_settings_list.py index 0b529429f11..0c0bb157152 100644 --- a/rocky/katalogus/views/plugin_settings_list.py +++ b/rocky/katalogus/views/plugin_settings_list.py @@ -1,5 +1,3 @@ -import logging - from django.contrib import messages from django.utils.translation import gettext_lazy as _ from django.views.generic import ListView @@ -7,8 +5,6 @@ from katalogus.views.mixins import SinglePluginView -logger = logging.getLogger(__name__) - class PluginSettingsListView(SinglePluginView, ListView): """ diff --git a/rocky/poetry.lock b/rocky/poetry.lock index 8d1aaa3adfe..54ed9666c09 100644 --- a/rocky/poetry.lock +++ b/rocky/poetry.lock @@ -567,6 +567,20 @@ files = [ [package.dependencies] Django = ">=3.2" +[[package]] +name = "django-ipware" +version = "7.0.1" +description = "A Django application to retrieve user's IP address" +optional = false +python-versions = ">=3.8" +files = [ + {file = "django-ipware-7.0.1.tar.gz", hash = "sha256:d9ec43d2bf7cdf216fed8d494a084deb5761a54860a53b2e74346a4f384cff47"}, + {file = "django_ipware-7.0.1-py2.py3-none-any.whl", hash = "sha256:db16bbee920f661ae7f678e4270460c85850f03c6761a4eaeb489bdc91f64709"}, +] + +[package.dependencies] +python-ipware = ">=2.0.3" + [[package]] name = "django-otp" version = "1.3.0" @@ -638,6 +652,27 @@ url = "https://github.com/jazzband/django-rest-knox" reference = "dd7b062147bc4b9718e22d5acd6cf1301a1036b9" resolved_reference = "dd7b062147bc4b9718e22d5acd6cf1301a1036b9" +[[package]] +name = "django-structlog" +version = "8.1.0" +description = "Structured Logging for Django" +optional = false +python-versions = ">=3.8" +files = [ + {file = "django_structlog-8.1.0-py3-none-any.whl", hash = "sha256:1072564bd6f36e8d3ba9893e7b31c1c46e94301189fedaecc0fb8a46525a3214"}, + {file = "django_structlog-8.1.0.tar.gz", hash = "sha256:0229b9a2efbd24a4e3500169788e53915c2429521e34e41dd58ccc56039bef3f"}, +] + +[package.dependencies] +asgiref = ">=3.6.0" +django = ">=4.2" +django-ipware = ">=6.0.2" +structlog = ">=21.4.0" + +[package.extras] +celery = ["celery (>=5.1)"] +commands = ["django-extensions (>=1.4.9)"] + [[package]] name = "django-tagulous" version = "1.3.3" @@ -2380,6 +2415,20 @@ files = [ [package.extras] cli = ["click (>=5.0)"] +[[package]] +name = "python-ipware" +version = "3.0.0" +description = "A Python package to retrieve user's IP address" +optional = false +python-versions = ">=3.7" +files = [ + {file = "python_ipware-3.0.0-py3-none-any.whl", hash = "sha256:fc936e6e7ec9fcc107f9315df40658f468ac72f739482a707181742882e36b60"}, + {file = "python_ipware-3.0.0.tar.gz", hash = "sha256:9117b1c4dddcb5d5ca49e6a9617de2fc66aec2ef35394563ac4eecabdf58c062"}, +] + +[package.extras] +dev = ["coverage[toml]", "coveralls (>=3.3,<4.0)", "ruff", "twine"] + [[package]] name = "pyyaml" version = "6.0.1" @@ -2996,6 +3045,23 @@ docs = ["myst-parser[linkify]", "sphinx", "sphinx-rtd-theme"] release = ["twine"] test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] +[[package]] +name = "structlog" +version = "24.2.0" +description = "Structured Logging for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "structlog-24.2.0-py3-none-any.whl", hash = "sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a"}, + {file = "structlog-24.2.0.tar.gz", hash = "sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b"}, +] + +[package.extras] +dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] +tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] +typing = ["mypy (>=1.4)", "rich", "twisted"] + [[package]] name = "tinycss2" version = "1.2.1" @@ -3350,4 +3416,4 @@ test = ["pytest"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "fd1f8a6cf8caf8216070cb5c9d8e0a2269de42f67011215e232431e262dc2153" +content-hash = "605a5548f2c3d78a4f3dcc46e5c649ffb7937763ad5f391579a33f582a49e551" diff --git a/rocky/pyproject.toml b/rocky/pyproject.toml index 22a33030ba3..6de012ec21c 100644 --- a/rocky/pyproject.toml +++ b/rocky/pyproject.toml @@ -49,6 +49,8 @@ opentelemetry-instrumentation-wsgi = "^0.45b0" opentelemetry-proto = "^1.24.0" opentelemetry-semantic-conventions = "^0.45b0" opentelemetry-util-http = "^0.45b0" +structlog = "^24.2.0" +django-structlog = "^8.1.0" [tool.poetry.group.dev.dependencies] diff --git a/rocky/reports/utils.py b/rocky/reports/utils.py index 02d672847c4..a88bed1864c 100644 --- a/rocky/reports/utils.py +++ b/rocky/reports/utils.py @@ -1,11 +1,11 @@ import dataclasses -import logging +import structlog from django.core.serializers.json import DjangoJSONEncoder from octopoes.models import OOI -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) def debug_json_keys(data: dict, path: list) -> None: diff --git a/rocky/requirements-dev.txt b/rocky/requirements-dev.txt index ba70602b78f..cdfa77ca79f 100644 --- a/rocky/requirements-dev.txt +++ b/rocky/requirements-dev.txt @@ -265,6 +265,9 @@ django-environ==0.11.2 ; python_version >= "3.10" and python_version < "4" \ django-formtools==2.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:47cb34552c6efca088863d693284d04fc36eaaf350eb21e1a1d935e0df523c93 \ --hash=sha256:bce9b64eda52cc1eef6961cc649cf75aacd1a707c2fff08d6c3efcbc8e7e761a +django-ipware==7.0.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:d9ec43d2bf7cdf216fed8d494a084deb5761a54860a53b2e74346a4f384cff47 \ + --hash=sha256:db16bbee920f661ae7f678e4270460c85850f03c6761a4eaeb489bdc91f64709 django-otp==1.3.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5277731bc05b6cdbf96aa84ac46018e30ed5fb248086053b0146f925de059060 \ --hash=sha256:8f4156a3c14ce2aaa31379385eadf388925cd50fc4b5d20a3b944f454c98ff7c @@ -275,6 +278,9 @@ django-phonenumber-field==7.3.0 ; python_version >= "3.10" and python_version < --hash=sha256:bc6eaa49d1f9d870944f5280258db511e3a1ba5e2fbbed255488dceacae45d06 \ --hash=sha256:f9cdb3de085f99c249328293a3b93d4e5fa440c0c8e3b99eb0d0f54748629797 django-rest-knox @ git+https://github.com/jazzband/django-rest-knox@dd7b062147bc4b9718e22d5acd6cf1301a1036b9 ; python_version >= "3.10" and python_version < "4.0" +django-structlog==8.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0229b9a2efbd24a4e3500169788e53915c2429521e34e41dd58ccc56039bef3f \ + --hash=sha256:1072564bd6f36e8d3ba9893e7b31c1c46e94301189fedaecc0fb8a46525a3214 django-tagulous==1.3.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ad3bb85f4cce83a47e4c0257143229cb92a294defa02fe661823b0442b35d478 \ --hash=sha256:d445590ae1b5cb9b8c5a425f97bf5f01148a33419c19edeb721ebd9fdd6792fe @@ -966,6 +972,9 @@ python-dateutil==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a +python-ipware==3.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:9117b1c4dddcb5d5ca49e6a9617de2fc66aec2ef35394563ac4eecabdf58c062 \ + --hash=sha256:fc936e6e7ec9fcc107f9315df40658f468ac72f739482a707181742882e36b60 pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \ --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ @@ -1312,6 +1321,9 @@ sqlparse==0.5.0 ; python_version >= "3.10" and python_version < "4.0" \ strenum==0.4.15 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff \ --hash=sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659 +structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ + --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a tinycss2==1.2.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 diff --git a/rocky/requirements.txt b/rocky/requirements.txt index 558cbf3e38c..8daf5ea569d 100644 --- a/rocky/requirements.txt +++ b/rocky/requirements.txt @@ -206,6 +206,9 @@ django-environ==0.11.2 ; python_version >= "3.10" and python_version < "4" \ django-formtools==2.5.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:47cb34552c6efca088863d693284d04fc36eaaf350eb21e1a1d935e0df523c93 \ --hash=sha256:bce9b64eda52cc1eef6961cc649cf75aacd1a707c2fff08d6c3efcbc8e7e761a +django-ipware==7.0.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:d9ec43d2bf7cdf216fed8d494a084deb5761a54860a53b2e74346a4f384cff47 \ + --hash=sha256:db16bbee920f661ae7f678e4270460c85850f03c6761a4eaeb489bdc91f64709 django-otp==1.3.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5277731bc05b6cdbf96aa84ac46018e30ed5fb248086053b0146f925de059060 \ --hash=sha256:8f4156a3c14ce2aaa31379385eadf388925cd50fc4b5d20a3b944f454c98ff7c @@ -216,6 +219,9 @@ django-phonenumber-field==7.3.0 ; python_version >= "3.10" and python_version < --hash=sha256:bc6eaa49d1f9d870944f5280258db511e3a1ba5e2fbbed255488dceacae45d06 \ --hash=sha256:f9cdb3de085f99c249328293a3b93d4e5fa440c0c8e3b99eb0d0f54748629797 django-rest-knox @ git+https://github.com/jazzband/django-rest-knox@dd7b062147bc4b9718e22d5acd6cf1301a1036b9 ; python_version >= "3.10" and python_version < "4.0" +django-structlog==8.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0229b9a2efbd24a4e3500169788e53915c2429521e34e41dd58ccc56039bef3f \ + --hash=sha256:1072564bd6f36e8d3ba9893e7b31c1c46e94301189fedaecc0fb8a46525a3214 django-tagulous==1.3.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ad3bb85f4cce83a47e4c0257143229cb92a294defa02fe661823b0442b35d478 \ --hash=sha256:d445590ae1b5cb9b8c5a425f97bf5f01148a33419c19edeb721ebd9fdd6792fe @@ -661,6 +667,9 @@ pypng==0.20220715.0 ; python_version >= "3.10" and python_version < "4.0" \ python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a +python-ipware==3.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:9117b1c4dddcb5d5ca49e6a9617de2fc66aec2ef35394563ac4eecabdf58c062 \ + --hash=sha256:fc936e6e7ec9fcc107f9315df40658f468ac72f739482a707181742882e36b60 qrcode==7.4.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:581dca7a029bcb2deef5d01068e39093e80ef00b4a61098a2182eac59d01643a \ --hash=sha256:9dd969454827e127dbd93696b20747239e6d540e082937c90f14ac95b30f5845 @@ -833,6 +842,9 @@ sqlparse==0.5.0 ; python_version >= "3.10" and python_version < "4.0" \ strenum==0.4.15 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff \ --hash=sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659 +structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ + --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a tinycss2==1.2.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 diff --git a/rocky/rocky/auth/remote_user.py b/rocky/rocky/auth/remote_user.py index 19176379e96..09dbe072d0a 100644 --- a/rocky/rocky/auth/remote_user.py +++ b/rocky/rocky/auth/remote_user.py @@ -1,11 +1,10 @@ -import logging - +import structlog from django.conf import settings from django.contrib.auth.backends import RemoteUserBackend as BaseRemoteUserBackend from django.contrib.auth.models import Group from tools.models import Organization, OrganizationMember -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class RemoteUserBackend(BaseRemoteUserBackend): diff --git a/rocky/rocky/bytes_client.py b/rocky/rocky/bytes_client.py index f820d54a136..4312d5eeedd 100644 --- a/rocky/rocky/bytes_client.py +++ b/rocky/rocky/bytes_client.py @@ -1,9 +1,9 @@ -import logging import uuid from collections.abc import Set from datetime import datetime, timezone import httpx +import structlog from django.conf import settings from django.http import Http404 @@ -11,7 +11,7 @@ from rocky.health import ServiceHealth from rocky.scheduler import Boefje, BoefjeMeta, Normalizer, NormalizerMeta, RawData -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class BytesClient: diff --git a/rocky/rocky/otel.py b/rocky/rocky/otel.py index 332e5beb56a..a4e5a69dfd8 100644 --- a/rocky/rocky/otel.py +++ b/rocky/rocky/otel.py @@ -1,5 +1,4 @@ -import logging - +import structlog from opentelemetry import trace from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.instrumentation.django import DjangoInstrumentor @@ -9,7 +8,7 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class OpenTelemetryHelper: diff --git a/rocky/rocky/settings.py b/rocky/rocky/settings.py index b0298bdd4fd..2ab5adfaa94 100644 --- a/rocky/rocky/settings.py +++ b/rocky/rocky/settings.py @@ -14,6 +14,7 @@ from pathlib import Path import environ +import structlog from django.conf import locale from django.core.exceptions import ImproperlyConfigured from django.utils.translation import gettext_lazy as _ @@ -55,14 +56,27 @@ LOGGING = { "version": 1, "disable_existing_loggers": False, + "formatters": { + "structlog": { + "()": structlog.stdlib.ProcessorFormatter, + "processor": structlog.processors.JSONRenderer(), + }, + }, "handlers": { "console": { + "formatter": "structlog", "class": "logging.StreamHandler", }, }, - "root": { - "handlers": ["console"], - "level": "WARNING", + "loggers": { + "root": { + "handlers": ["console"], + "level": "INFO", + }, + "django_structlog": { + "handlers": ["console"], + "level": "DEBUG", + }, }, } @@ -164,6 +178,7 @@ "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", + "django_structlog.middlewares.RequestMiddleware", ] if REMOTE_USER_HEADER: @@ -276,8 +291,18 @@ # Add custom languages not provided by Django EXTRA_LANG_INFO = { - "pap": {"bidi": False, "code": "pap", "name": "Papiamentu", "name_local": "Papiamentu"}, - "en@pirate": {"bidi": False, "code": "en@pirate", "name": "English (Pirate)", "name_local": "English (Pirate)"}, + "pap": { + "bidi": False, + "code": "pap", + "name": "Papiamentu", + "name_local": "Papiamentu", + }, + "en@pirate": { + "bidi": False, + "code": "en@pirate", + "name": "English (Pirate)", + "name_local": "English (Pirate)", + }, } LANG_INFO = locale.LANG_INFO.copy() LANG_INFO.update(EXTRA_LANG_INFO) @@ -465,3 +490,19 @@ def immutable_file_test(path, url): KNOX_TOKEN_MODEL = "account.AuthToken" FORMS_URLFIELD_ASSUME_HTTPS = True + +structlog.configure( + processors=[ + structlog.contextvars.merge_contextvars, + structlog.processors.add_log_level, + structlog.processors.StackInfoRenderer(), + structlog.dev.set_exc_info, + structlog.stdlib.PositionalArgumentsFormatter(), + structlog.processors.TimeStamper("iso"), + structlog.dev.ConsoleRenderer(colors=True), + ], + context_class=dict, + logger_factory=structlog.stdlib.LoggerFactory(), + wrapper_class=structlog.stdlib.BoundLogger, + cache_logger_on_first_use=True, +) diff --git a/rocky/rocky/views/bytes_raw.py b/rocky/rocky/views/bytes_raw.py index 3ddbadaf90b..0ccebc59495 100644 --- a/rocky/rocky/views/bytes_raw.py +++ b/rocky/rocky/views/bytes_raw.py @@ -1,8 +1,8 @@ import json -import logging import zipfile from io import BytesIO +import structlog from account.mixins import OrganizationView from django.contrib import messages from django.http import FileResponse, Http404 @@ -10,7 +10,7 @@ from django.urls import reverse from django.utils.translation import gettext_lazy as _ -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class BytesRawView(OrganizationView): diff --git a/rocky/rocky/views/finding_list.py b/rocky/rocky/views/finding_list.py index 042fd67a250..9b0430d2f7c 100644 --- a/rocky/rocky/views/finding_list.py +++ b/rocky/rocky/views/finding_list.py @@ -1,7 +1,7 @@ -import logging from collections.abc import Iterable from typing import Any +import structlog from django.urls.base import reverse_lazy from django.utils.translation import gettext_lazy as _ from django.views.generic import ListView @@ -12,7 +12,7 @@ from octopoes.models.ooi.findings import RiskLevelSeverity from rocky.views.mixins import ConnectorFormMixin, FindingList, OctopoesView, SeveritiesMixin -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) def sort_by_severity_desc(findings) -> list[dict[str, Any]]: diff --git a/rocky/rocky/views/health.py b/rocky/rocky/views/health.py index 222df344813..ea8de1c4941 100644 --- a/rocky/rocky/views/health.py +++ b/rocky/rocky/views/health.py @@ -1,5 +1,4 @@ -import logging - +import structlog from account.mixins import OrganizationView from django.http import JsonResponse from django.urls.base import reverse @@ -15,7 +14,7 @@ from rocky.scheduler import client from rocky.version import __version__ -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class Health(OrganizationView, View): diff --git a/rocky/rocky/views/mixins.py b/rocky/rocky/views/mixins.py index e0fdc786b8b..f69b93beb60 100644 --- a/rocky/rocky/views/mixins.py +++ b/rocky/rocky/views/mixins.py @@ -1,10 +1,10 @@ -import logging from collections.abc import Sequence from dataclasses import dataclass from datetime import datetime, timezone from functools import cached_property from operator import attrgetter +import structlog from account.mixins import OrganizationView from django.contrib import messages from django.http import Http404, HttpRequest @@ -30,7 +30,7 @@ from octopoes.models.types import get_relations from rocky.bytes_client import get_bytes_client -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) @dataclass diff --git a/rocky/rocky/views/ooi_add.py b/rocky/rocky/views/ooi_add.py index 73f1aa9aca8..c2a0c52ecde 100644 --- a/rocky/rocky/views/ooi_add.py +++ b/rocky/rocky/views/ooi_add.py @@ -1,5 +1,3 @@ -import logging - from account.mixins import OrganizationView from django.http import Http404 from django.shortcuts import redirect @@ -13,8 +11,6 @@ from octopoes.models.types import type_by_name from rocky.views.ooi_view import BaseOOIFormView -logger = logging.getLogger(__name__) - def ooi_type_input_choices(): ooi_types = OOI_TYPES_WITHOUT_FINDINGS @@ -30,7 +26,10 @@ def get(self, request, *args, **kwargs): return redirect( reverse( "ooi_add", - kwargs={"organization_code": self.organization.code, "ooi_type": request.GET["add_ooi_type"]}, + kwargs={ + "organization_code": self.organization.code, + "ooi_type": request.GET["add_ooi_type"], + }, ) ) @@ -41,9 +40,15 @@ def get_context_data(self, **kwargs): context["ooi_types"] = ooi_type_input_choices() context["breadcrumbs"] = [ - {"url": reverse("ooi_list", kwargs={"organization_code": self.organization.code}), "text": _("Objects")}, { - "url": reverse("ooi_add_type_select", kwargs={"organization_code": self.organization.code}), + "url": reverse("ooi_list", kwargs={"organization_code": self.organization.code}), + "text": _("Objects"), + }, + { + "url": reverse( + "ooi_add_type_select", + kwargs={"organization_code": self.organization.code}, + ), "text": _("Add object"), }, ] @@ -70,15 +75,24 @@ def get_context_data(self, **kwargs): context["type"] = self.ooi_class.get_ooi_type() context["breadcrumbs"] = [ - {"url": reverse("ooi_list", kwargs={"organization_code": self.organization.code}), "text": _("Objects")}, { - "url": reverse("ooi_add_type_select", kwargs={"organization_code": self.organization.code}), + "url": reverse("ooi_list", kwargs={"organization_code": self.organization.code}), + "text": _("Objects"), + }, + { + "url": reverse( + "ooi_add_type_select", + kwargs={"organization_code": self.organization.code}, + ), "text": _("Type select"), }, { "url": reverse( "ooi_add", - kwargs={"organization_code": self.organization.code, "ooi_type": self.ooi_class.get_ooi_type()}, + kwargs={ + "organization_code": self.organization.code, + "ooi_type": self.ooi_class.get_ooi_type(), + }, ), "text": _("Add %(ooi_type)s") % {"ooi_type": self.ooi_class.get_ooi_type()}, }, diff --git a/rocky/rocky/views/organization_add.py b/rocky/rocky/views/organization_add.py index 53e07d7c0c1..c0abad14d43 100644 --- a/rocky/rocky/views/organization_add.py +++ b/rocky/rocky/views/organization_add.py @@ -1,5 +1,4 @@ -import logging - +import structlog from account.forms import OrganizationForm from django.contrib import messages from django.contrib.auth.mixins import PermissionRequiredMixin @@ -11,7 +10,7 @@ from rocky.exceptions import ServiceException -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) class OrganizationAddView(PermissionRequiredMixin, CreateView): diff --git a/rocky/rocky/views/organization_member_add.py b/rocky/rocky/views/organization_member_add.py index f4af5b320ef..b111b217822 100644 --- a/rocky/rocky/views/organization_member_add.py +++ b/rocky/rocky/views/organization_member_add.py @@ -1,8 +1,8 @@ import csv import io -import logging from typing import Any +import structlog from account.forms import AccountTypeSelectForm, MemberRegistrationForm, PasswordResetForm from account.mixins import OrganizationPermissionRequiredMixin, OrganizationView from django.contrib import messages @@ -23,7 +23,7 @@ from rocky.messaging import clearance_level_warning_dns_report -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) User = get_user_model() diff --git a/rocky/tools/add_ooi_information.py b/rocky/tools/add_ooi_information.py index 755f4704c25..ac67027884e 100644 --- a/rocky/tools/add_ooi_information.py +++ b/rocky/tools/add_ooi_information.py @@ -1,14 +1,14 @@ import datetime -import logging from dataclasses import dataclass from itertools import product import httpx +import structlog from bs4 import BeautifulSoup SEPARATOR = "|" -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) @dataclass diff --git a/rocky/tools/models.py b/rocky/tools/models.py index 5e66ac7d340..4f78431ef56 100644 --- a/rocky/tools/models.py +++ b/rocky/tools/models.py @@ -1,10 +1,10 @@ import datetime -import logging from collections.abc import Iterable from enum import Enum from functools import cached_property from typing import cast +import structlog import tagulous.models from django.conf import settings from django.contrib.auth.models import Group, Permission @@ -30,7 +30,7 @@ GROUP_REDTEAM = "redteam" GROUP_CLIENT = "clients" -logger = logging.getLogger(__name__) +logger = structlog.get_logger(__name__) ORGANIZATION_CODE_LENGTH = 32 DENY_ORGANIZATION_CODES = [ From d77491e2f46ddc7ba1c6cd5e588a7c3a8371e472 Mon Sep 17 00:00:00 2001 From: JP Bruins Slot Date: Thu, 11 Jul 2024 13:15:55 +0200 Subject: [PATCH 017/112] Fix filtering on plugin_id for normalizers (#3226) Co-authored-by: ammar92 Co-authored-by: Rieven --- mula/scheduler/server/server.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/mula/scheduler/server/server.py b/mula/scheduler/server/server.py index 48295bd9026..9331469d218 100644 --- a/mula/scheduler/server/server.py +++ b/mula/scheduler/server/server.py @@ -306,7 +306,8 @@ def list_tasks( ) # FIXME: deprecated; backwards compatibility for rocky that uses the - # input_ooi and plugin_id parameters. + # input_ooi and plugin_id parameters. These filter options should be + # defined in the filter request payload not as query parameters. f_req = filters or storage.filters.FilterRequest(filters={}) if input_ooi is not None: if task_type == "boefje": @@ -351,6 +352,9 @@ def list_tasks( f_req.filters.update(f_ooi) # type: ignore + # FIXME: deprecated; backwards compatibility for rocky that uses the + # input_ooi and plugin_id parameters. These filter options should be + # defined in the filter request payload not as query parameters. if plugin_id is not None: if task_type == "boefje": f_plugin = { @@ -364,12 +368,16 @@ def list_tasks( ] } elif task_type == "normalizer": - f_plugin = storage.filters.Filter( - column="p_item", - field="data__normalizer__id", - operator="eq", - value=plugin_id, - ) + f_plugin = { + "and": [ + storage.filters.Filter( + column="p_item", + field="data__normalizer__id", + operator="eq", + value=plugin_id, + ) + ] + } else: f_plugin = { "or": [ From 0d6389a39bf48fe830e5999b22462552374c2d02 Mon Sep 17 00:00:00 2001 From: Rieven Date: Thu, 11 Jul 2024 16:00:49 +0200 Subject: [PATCH 018/112] Refactor Task List and filters with error handlers for Scheduler (#1957) Co-authored-by: Jan Klopper Co-authored-by: ammar92 Co-authored-by: JP Bruins Slot Co-authored-by: Jeroen Dekkers --- docs/source/developer_documentation/rocky.md | 15 +- rocky/account/mixins.py | 6 + .../css/components/table-state-icons.scss | 28 ++ rocky/katalogus/client.py | 1 + rocky/katalogus/templates/boefje_detail.html | 4 +- .../templates/normalizer_detail.html | 4 +- .../templates/partials/objects_to_scan.html | 2 +- .../templates/plugin_settings_list.html | 2 - .../katalogus/views/change_clearance_level.py | 5 +- rocky/katalogus/views/mixins.py | 54 +--- rocky/katalogus/views/plugin_detail.py | 211 ++++-------- rocky/katalogus/views/plugin_settings_list.py | 49 +-- .../aggregate_organisation_report/report.py | 7 +- rocky/reports/report_types/definitions.py | 2 +- rocky/reports/views/aggregate_report.py | 1 + rocky/rocky/locale/django.pot | 300 +++++++++--------- rocky/rocky/scheduler.py | 144 +++++---- rocky/rocky/templates/oois/ooi_detail.html | 2 +- .../templates/partials/task_history.html | 146 --------- rocky/rocky/templates/tasks/boefjes.html | 54 +++- rocky/rocky/templates/tasks/normalizers.html | 58 +++- .../templates/tasks/ooi_detail_task_list.html | 60 ++++ .../tasks/partials/boefje_task_history.html | 76 ----- .../partials/normalizer_task_history.html | 88 ----- .../rocky/templates/tasks/partials/stats.html | 2 +- .../tasks/partials/task_actions.html | 30 ++ .../templates/tasks/partials/task_filter.html | 66 +--- .../tasks/plugin_detail_task_list.html | 62 ++++ rocky/rocky/urls.py | 4 +- rocky/rocky/views/health.py | 18 +- rocky/rocky/views/ooi_detail.py | 192 ++++------- .../rocky/views/ooi_detail_related_object.py | 3 +- rocky/rocky/views/ooi_findings.py | 3 +- rocky/rocky/views/ooi_report.py | 23 +- rocky/rocky/views/ooi_tree.py | 3 +- rocky/rocky/views/ooi_view.py | 37 ++- rocky/rocky/views/page_actions.py | 32 ++ rocky/rocky/views/scan_profile.py | 6 +- rocky/rocky/views/scheduler.py | 190 +++++++++++ rocky/rocky/views/task_detail.py | 60 ++-- rocky/rocky/views/tasks.py | 119 ++----- rocky/tests/conftest.py | 112 +++++-- rocky/tests/integration/test_bench.py | 3 +- rocky/tests/integration/test_reports.py | 13 +- .../katalogus/test_katalogus_plugin_detail.py | 4 +- rocky/tests/objects/test_objects_detail.py | 73 +++-- rocky/tests/objects/test_objects_findings.py | 30 +- .../objects/test_objects_scan_profile.py | 40 ++- rocky/tests/scheduler/__init__.py | 0 .../tests/scheduler/test_scheduler_errors.py | 39 +++ rocky/tests/test_boefjes_tasks.py | 90 ++---- rocky/tests/test_groups_and_permissions.py | 8 +- rocky/tools/forms/scheduler.py | 67 ++++ rocky/tools/view_helpers.py | 55 ---- 54 files changed, 1383 insertions(+), 1320 deletions(-) delete mode 100644 rocky/rocky/templates/partials/task_history.html create mode 100644 rocky/rocky/templates/tasks/ooi_detail_task_list.html delete mode 100644 rocky/rocky/templates/tasks/partials/boefje_task_history.html delete mode 100644 rocky/rocky/templates/tasks/partials/normalizer_task_history.html create mode 100644 rocky/rocky/templates/tasks/partials/task_actions.html create mode 100644 rocky/rocky/templates/tasks/plugin_detail_task_list.html create mode 100644 rocky/rocky/views/page_actions.py create mode 100644 rocky/rocky/views/scheduler.py create mode 100644 rocky/tests/scheduler/__init__.py create mode 100644 rocky/tests/scheduler/test_scheduler_errors.py create mode 100644 rocky/tools/forms/scheduler.py diff --git a/docs/source/developer_documentation/rocky.md b/docs/source/developer_documentation/rocky.md index 0f27bd19ee3..798ccd11a93 100644 --- a/docs/source/developer_documentation/rocky.md +++ b/docs/source/developer_documentation/rocky.md @@ -220,16 +220,18 @@ classDiagram direction RL class OrganizationView class OctopoesView - class BoefjeMixin + class SchedulerView + class TaskListView OctopoesView <|-- OrganizationView - BoefjeMixin <|-- OctopoesView - BoefjeDetailView <|-- BoefjeMixin - OOIDetailView <|-- BoefjeMixin + SchedulerView <|-- OctopoesView + TaskListView <|-- SchedulerView + BoefjeDetailView <|-- TaskListView + OOIDetailView <|-- TaskListView OOIDetailView <|-- OOIRelatedObjectAddView OOIDetailView <|-- OOIFindingManager - ChangeClearanceLevel <|-- BoefjeMixin + ChangeClearanceLevel <|-- SchedulerView SingleOOIMixin <|-- OctopoesView SingleOOITreeMixin <|-- SingleOOIMixin @@ -300,13 +302,14 @@ direction RL class PluginSettingsDeleteView class BoefjeDetailView + class TaskListView KATalogusView <|-- OrganizationView KATalogusView <|-- FormView SinglePluginView <|-- OrganizationView SingleSettingView <|-- SinglePluginView BoefjeDetailView <|-- PluginSettingsListView - BoefjeDetailView <|-- BoefjeMixin + BoefjeDetailView <|-- TaskListView PluginEnableDisableView <|-- SinglePluginView PluginSettingsAddView <|-- FormView PluginSettingsAddView <|-- SinglePluginView diff --git a/rocky/account/mixins.py b/rocky/account/mixins.py index 951c6707628..3c01410ff43 100644 --- a/rocky/account/mixins.py +++ b/rocky/account/mixins.py @@ -108,6 +108,12 @@ def get_context_data(self, **kwargs): context["perms"] = OrganizationPermWrapper(self.organization_member) return context + def indemnification_error(self): + return messages.error( + self.request, + f"Indemnification not present at organization {self.organization}.", + ) + @property def may_update_clearance_level(self) -> bool: if not self.indemnification_present: diff --git a/rocky/assets/css/components/table-state-icons.scss b/rocky/assets/css/components/table-state-icons.scss index 5bf7550bd04..fbf36439a90 100644 --- a/rocky/assets/css/components/table-state-icons.scss +++ b/rocky/assets/css/components/table-state-icons.scss @@ -47,6 +47,13 @@ table td .icon { } } + &.completed { + &::before { + content: "\ea67"; // $ti-icon-circle-check + color: var(--color-alert-positive); + } + } + &.negative { &::before { content: "\ea6a"; // $ti-icon-circle-x @@ -54,6 +61,13 @@ table td .icon { } } + &.failed { + &::before { + content: "\ea6a"; // $ti-icon-circle-x + color: var(--color-alert-negative); + } + } + &.incomplete { &::before { content: "\ea6a"; // $ti-icon-circle-x @@ -68,6 +82,13 @@ table td .icon { } } + &.dispatched { + &::before { + content: "\ed27"; // $ti-icon-circle-dashed (should become ti-icon-progress, when we have it) + color: var(--color-alert-informative); + } + } + &.queued { &::before { content: "\ea70"; // $ti-icon-clock @@ -75,6 +96,13 @@ table td .icon { } } + &.pending { + &::before { + content: "\ea70"; // $ti-icon-clock + color: var(--color-alert-warning); + } + } + &.cancelled { &::before { content: "\ea05"; // $ti-icon-alert-circle diff --git a/rocky/katalogus/client.py b/rocky/katalogus/client.py index b990cd17e56..b5e06db1777 100644 --- a/rocky/katalogus/client.py +++ b/rocky/katalogus/client.py @@ -109,6 +109,7 @@ def get_plugins(self, **params): def get_plugin(self, plugin_id: str) -> Plugin: response = self.session.get(f"{self.organization_uri}/plugins/{plugin_id}") response.raise_for_status() + return parse_plugin(response.json()) def get_plugin_schema(self, plugin_id) -> dict | None: diff --git a/rocky/katalogus/templates/boefje_detail.html b/rocky/katalogus/templates/boefje_detail.html index 8b9ae11e199..a6229151d6f 100644 --- a/rocky/katalogus/templates/boefje_detail.html +++ b/rocky/katalogus/templates/boefje_detail.html @@ -37,7 +37,7 @@

{{ plugin.name }}

{% if perms.tools.can_view_katalogus_settings %} - {% include "plugin_settings_list.html" with object_list=object_list plugin=plugin %} + {% include "plugin_settings_list.html" with object_list=plugin_settings plugin=plugin %} {% endif %}
@@ -73,7 +73,7 @@

{% translate "Produces" %}

- {% include "tasks/partials/boefje_task_history.html" %} + {% include "tasks/plugin_detail_task_list.html" %}

diff --git a/rocky/katalogus/templates/normalizer_detail.html b/rocky/katalogus/templates/normalizer_detail.html index 162778077d2..dbb3d3cbc37 100644 --- a/rocky/katalogus/templates/normalizer_detail.html +++ b/rocky/katalogus/templates/normalizer_detail.html @@ -31,7 +31,7 @@

{{ plugin.name }}

{% if perms.tools.can_view_katalogus_settings %} - {% include "plugin_settings_list.html" with object_list=object_list plugin=plugin %} + {% include "plugin_settings_list.html" with object_list=plugin_settings plugin=plugin %} {% endif %}
@@ -74,7 +74,7 @@

{% translate "Produces" %}

{% endif %}

- {% include "tasks/partials/normalizer_task_history.html" %} + {% include "tasks/plugin_detail_task_list.html" %}

diff --git a/rocky/katalogus/templates/partials/objects_to_scan.html b/rocky/katalogus/templates/partials/objects_to_scan.html index 7dd98fa1662..a296673e196 100644 --- a/rocky/katalogus/templates/partials/objects_to_scan.html +++ b/rocky/katalogus/templates/partials/objects_to_scan.html @@ -36,7 +36,7 @@

{{ form_title }}

{% endif %} {% if select_oois_form.fields.ooi.choices %} - {% include "partials/form/checkbox_group_table_form.html" with checkbox_group_table_form=select_oois_form btn_text="Start scan" plugin_enabled=plugin.enabled key="boefje_id" value=plugin.id action="scan" checkbox_group_table_filter_form=select_ooi_filter_form unique_id="" %} + {% include "partials/form/checkbox_group_table_form.html" with checkbox_group_table_form=select_oois_form btn_text="Start scan" plugin_enabled=plugin.enabled key="boefje_id" value=plugin.id action="scan_oois" checkbox_group_table_filter_form=select_ooi_filter_form unique_id="" %} {% elif has_consumable_oois %} {% blocktranslate trimmed with name=plugin.name %} diff --git a/rocky/katalogus/templates/plugin_settings_list.html b/rocky/katalogus/templates/plugin_settings_list.html index 88e407208bd..3ca5ca51dfb 100644 --- a/rocky/katalogus/templates/plugin_settings_list.html +++ b/rocky/katalogus/templates/plugin_settings_list.html @@ -57,8 +57,6 @@

{{ plugin.type|title }}{% translate " Details" %}

{% csrf_token %} - {% include "partials/pagination.html" %} -
diff --git a/rocky/katalogus/views/change_clearance_level.py b/rocky/katalogus/views/change_clearance_level.py index f3dcbbf2eaa..2f1560493bc 100644 --- a/rocky/katalogus/views/change_clearance_level.py +++ b/rocky/katalogus/views/change_clearance_level.py @@ -5,10 +5,11 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic import TemplateView -from katalogus.views.mixins import BoefjeMixin, SinglePluginView +from katalogus.views.mixins import SinglePluginView +from rocky.views.scheduler import SchedulerView -class ChangeClearanceLevel(OrganizationPermissionRequiredMixin, BoefjeMixin, SinglePluginView, TemplateView): +class ChangeClearanceLevel(OrganizationPermissionRequiredMixin, SchedulerView, SinglePluginView, TemplateView): template_name = "change_clearance_level.html" permission_required = "tools.can_set_clearance_level" diff --git a/rocky/katalogus/views/mixins.py b/rocky/katalogus/views/mixins.py index fe4146bdf5f..9e770837249 100644 --- a/rocky/katalogus/views/mixins.py +++ b/rocky/katalogus/views/mixins.py @@ -8,21 +8,15 @@ from django.utils.translation import gettext_lazy as _ from httpx import HTTPError, HTTPStatusError from rest_framework.status import HTTP_404_NOT_FOUND -from tools.view_helpers import schedule_task -from katalogus.client import Boefje as KATalogusBoefje -from katalogus.client import KATalogusClientV1, get_katalogus -from katalogus.client import Normalizer as KATalogusNormalizer -from octopoes.models import OOI -from rocky.scheduler import Boefje, BoefjeTask, Normalizer, NormalizerTask, PrioritizedItem, RawData -from rocky.views.mixins import OctopoesView +from katalogus.client import KATalogusClientV1, Plugin, get_katalogus logger = getLogger(__name__) class SinglePluginView(OrganizationView): katalogus_client: KATalogusClientV1 - plugin: KATalogusBoefje | KATalogusNormalizer + plugin: Plugin def setup(self, request, *args, plugin_id: str, **kwargs): """ @@ -57,47 +51,3 @@ def is_required_field(self, field: str) -> bool: def is_secret_field(self, field: str) -> bool: """Check whether this field should be secret, defaults to False.""" return bool(self.plugin_schema and field in self.plugin_schema.get("secret", [])) - - -class NormalizerMixin(OctopoesView): - """ - When a user wants to run a normalizer on a given set of raw data, - this mixin provides the method to construct the normalizer task for that data and run it. - """ - - def run_normalizer(self, normalizer: KATalogusNormalizer, raw_data: RawData) -> None: - normalizer_task = NormalizerTask(normalizer=Normalizer(id=normalizer.id, version=None), raw_data=raw_data) - - task = PrioritizedItem(priority=1, data=normalizer_task) - - schedule_task(self.request, self.organization.code, task) - - -class BoefjeMixin(OctopoesView): - """ - When a user wants to scan one or multiple OOI's, - this mixin provides the methods to construct the boefjes for the OOI's and run them. - """ - - def run_boefje(self, katalogus_boefje: KATalogusBoefje, ooi: OOI | None) -> None: - boefje_task = BoefjeTask( - boefje=Boefje.model_validate(katalogus_boefje.model_dump()), - input_ooi=ooi.reference if ooi else None, - organization=self.organization.code, - ) - - task = PrioritizedItem(priority=1, data=boefje_task) - schedule_task(self.request, self.organization.code, task) - - def run_boefje_for_oois( - self, - boefje: KATalogusBoefje, - oois: list[OOI], - ) -> None: - if not oois and not boefje.consumes: - self.run_boefje(boefje, None) - - for ooi in oois: - if ooi.scan_profile and ooi.scan_profile.level < boefje.scan_level: - self.can_raise_clearance_level(ooi, boefje.scan_level) - self.run_boefje(boefje, ooi) diff --git a/rocky/katalogus/views/plugin_detail.py b/rocky/katalogus/views/plugin_detail.py index b1e524f2bd7..d0ecbe526b2 100644 --- a/rocky/katalogus/views/plugin_detail.py +++ b/rocky/katalogus/views/plugin_detail.py @@ -1,33 +1,22 @@ from datetime import datetime, timezone -from enum import Enum from logging import getLogger from typing import Any from account.mixins import OrganizationView from django.contrib import messages -from django.core.exceptions import BadRequest -from django.core.paginator import Page, Paginator from django.http import FileResponse from django.shortcuts import redirect from django.urls.base import reverse from django.utils.translation import gettext_lazy as _ -from django.views.generic import TemplateView from tools.forms.ooi import SelectOOIFilterForm, SelectOOIForm -from tools.view_helpers import reschedule_task -from katalogus.client import Boefje as KATalogusBoefje -from katalogus.client import get_katalogus -from katalogus.views.mixins import BoefjeMixin +from katalogus.client import Boefje, Normalizer, get_katalogus from katalogus.views.plugin_settings_list import PluginSettingsListView -from rocky import scheduler +from rocky.views.tasks import TaskListView logger = getLogger(__name__) -class PageActions(Enum): - RESCHEDULE_TASK = "reschedule_task" - - class PluginCoverImgView(OrganizationView): """Get the cover image of a plugin.""" @@ -37,72 +26,78 @@ def get(self, request, *args, **kwargs): return file -class PluginDetailView(PluginSettingsListView, TemplateView): - task_history_limit = 10 - - def get_task_history(self) -> Page: - scheduler_id = f"{self.plugin.type}-{self.organization.code}" - plugin_type = self.plugin.type - plugin_id = self.plugin.id - input_ooi = self.request.GET.get("task_history_search") - status = self.request.GET.get("task_history_status") - - if self.request.GET.get("task_history_from"): - min_created_at = datetime.strptime(self.request.GET.get("task_history_from"), "%Y-%m-%d") - else: - min_created_at = None - - if self.request.GET.get("task_history_to"): - max_created_at = datetime.strptime(self.request.GET.get("task_history_to"), "%Y-%m-%d") - else: - max_created_at = None +class PluginDetailView(TaskListView, PluginSettingsListView): + def post(self, request, *args, **kwargs): + if self.action == self.SCAN_OOIS: + selected_oois = request.POST.getlist("ooi", []) - page = int(self.request.GET.get("task_history_page", 1)) + if selected_oois and self.plugin.id: + oois = self.get_oois(selected_oois) + boefje = self.katalogus_client.get_plugin(self.plugin.id) - task_history = scheduler.client.get_lazy_task_list( - scheduler_id=scheduler_id, - task_type=plugin_type, - plugin_id=plugin_id, - input_ooi=input_ooi, - status=status, - min_created_at=min_created_at, - max_created_at=max_created_at, - ) + oois_with_clearance_level = oois["oois_with_clearance"] + oois_without_clearance_level = oois["oois_without_clearance"] - return Paginator(task_history, self.task_history_limit).page(page) + if oois_with_clearance_level: + self.run_boefje_for_oois( + boefje=boefje, + oois=oois_with_clearance_level, + ) - def post(self, request, *args, **kwargs): - action = request.POST["action"] + if oois_without_clearance_level: + if not self.organization_member.has_perm("tools.can_set_clearance_level"): + messages.error( + request, + _( + "Some selected OOIs needs an increase of clearance level to perform scans." + " You do not have the permission to change clearance level." + ), + ) + else: + request.session["selected_oois"] = oois_without_clearance_level + return redirect( + reverse( + "change_clearance_level", + kwargs={ + "plugin_type": "boefje", + "organization_code": self.organization.code, + "plugin_id": self.plugin.id, + "scan_level": self.plugin.scan_level.value, + }, + ) + ) + return super().post(request, *args, **kwargs) - if action: - self.handle_page_action(action) - return redirect(request.path) - else: - return self.get(request, *args, **kwargs) + def get_task_filters(self) -> dict[str, str | datetime | None]: + filters = super().get_task_filters() + filters["plugin_id"] = self.plugin.id # fetch only tasks for a specific plugin by id + return filters - def handle_page_action(self, action: str) -> None: - if action == PageActions.RESCHEDULE_TASK.value: - task_id = self.request.POST.get("task_id") - reschedule_task(self.request, self.organization.code, task_id) + def get_oois(self, selected_oois: list[str]) -> dict[str, Any]: + oois_with_clearance = [] + oois_without_clearance = [] + for ooi in selected_oois: + ooi_object = self.get_single_ooi(pk=ooi) + if ooi_object.scan_profile and ooi_object.scan_profile.level >= self.plugin.scan_level.value: + oois_with_clearance.append(ooi_object) + else: + oois_without_clearance.append(ooi_object.primary_key) + return { + "oois_with_clearance": oois_with_clearance, + "oois_without_clearance": oois_without_clearance, + } def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["plugin"] = self.plugin.model_dump() - context["task_history"] = self.get_task_history() - context["task_history_form_fields"] = [ - "task_history_from", - "task_history_to", - "task_history_status", - "task_history_search", - "task_history_page", - ] - + context["plugin_settings"] = self.get_plugin_settings() return context class NormalizerDetailView(PluginDetailView): template_name = "normalizer_detail.html" + plugin: Normalizer + task_type = "normalizer" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -126,12 +121,13 @@ def get_context_data(self, **kwargs): return context -class BoefjeDetailView(BoefjeMixin, PluginDetailView): +class BoefjeDetailView(PluginDetailView): """Detail view for a specific boefje. Shows boefje settings and consumable oois for scanning.""" template_name = "boefje_detail.html" limit_ooi_list = 9999 - plugin: KATalogusBoefje + plugin: Boefje + task_type = "boefje" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -139,13 +135,15 @@ def get_context_data(self, **kwargs): context["select_ooi_filter_form"] = SelectOOIFilterForm if "show_all" in self.request.GET: context["select_oois_form"] = SelectOOIForm( - oois=self.get_form_consumable_oois(), organization_code=self.organization.code + oois=self.get_form_consumable_oois(), + organization_code=self.organization.code, ) else: context["select_oois_form"] = SelectOOIForm( - oois=self.get_form_filtered_consumable_oois(), organization_code=self.organization.code + oois=self.get_form_filtered_consumable_oois(), + organization_code=self.organization.code, ) - context["plugin"] = self.plugin.model_dump() + context["breadcrumbs"] = [ { "url": reverse("katalogus", kwargs={"organization_code": self.organization.code}), @@ -165,84 +163,15 @@ def get_context_data(self, **kwargs): return context - def post(self, request, *args, **kwargs): - action = request.POST["action"] - - if action == PageActions.RESCHEDULE_TASK.value: - self.handle_page_action(action) - return redirect(request.path) - - """Start scanning oois at plugin detail page.""" - if not self.indemnification_present: - return self.get(request, *args, **kwargs) - - if "boefje_id" not in request.POST: - raise BadRequest("No boefje_id provided") - - selected_oois = request.POST.getlist("ooi") - plugin_id = request.POST["boefje_id"] - if selected_oois and plugin_id: - oois = self.get_oois(selected_oois) - boefje = self.katalogus_client.get_plugin(plugin_id) - - oois_with_clearance_level = oois["oois_with_clearance"] - oois_without_clearance_level = oois["oois_without_clearance"] - - if oois_with_clearance_level: - self.run_boefje_for_oois( - boefje=boefje, - oois=oois_with_clearance_level, - ) - - if oois_without_clearance_level: - if not self.organization_member.has_perm("tools.can_set_clearance_level"): - messages.add_message( - self.request, - messages.ERROR, - _( - "Some selected OOIs needs an increase of clearance level to perform scans." - " You do not have the permission to change clearance level." - ), - ) - else: - request.session["selected_oois"] = oois_without_clearance_level - return redirect( - reverse( - "change_clearance_level", - kwargs={ - "plugin_type": "boefje", - "organization_code": self.organization.code, - "plugin_id": plugin_id, - "scan_level": self.plugin.scan_level.value, - }, - ) - ) - return redirect(reverse("task_list", kwargs={"organization_code": self.organization.code})) - - messages.add_message(self.request, messages.ERROR, _("Please select an OOI to start scan.")) - return self.get(request, *args, **kwargs) - def get_form_consumable_oois(self): """Get all available OOIS that plugin can consume.""" return self.octopoes_api_connector.list_objects( - self.plugin.consumes, valid_time=datetime.now(timezone.utc), limit=self.limit_ooi_list + self.plugin.consumes, + valid_time=datetime.now(timezone.utc), + limit=self.limit_ooi_list, ).items def get_form_filtered_consumable_oois(self): """Return a list of oois that is filtered for oois that meets clearance level.""" oois = self.get_form_consumable_oois() return [ooi for ooi in oois if ooi.scan_profile.level >= self.plugin.scan_level.value] - - def get_oois(self, selected_oois: list[str]) -> dict[str, Any]: - oois_with_clearance = [] - oois_without_clearance = [] - for ooi in selected_oois: - ooi_object = self.get_single_ooi(pk=ooi) - if ooi_object.scan_profile and ooi_object.scan_profile.level >= self.plugin.scan_level.value: - oois_with_clearance.append(ooi_object) - else: - oois_without_clearance.append(ooi_object.primary_key) - return { - "oois_with_clearance": oois_with_clearance, - "oois_without_clearance": oois_without_clearance, - } diff --git a/rocky/katalogus/views/plugin_settings_list.py b/rocky/katalogus/views/plugin_settings_list.py index 0c0bb157152..370e93a0bfc 100644 --- a/rocky/katalogus/views/plugin_settings_list.py +++ b/rocky/katalogus/views/plugin_settings_list.py @@ -1,41 +1,42 @@ +from typing import Any + from django.contrib import messages from django.utils.translation import gettext_lazy as _ -from django.views.generic import ListView from httpx import HTTPError from katalogus.views.mixins import SinglePluginView +from rocky.paginator import RockyPaginator -class PluginSettingsListView(SinglePluginView, ListView): +class PluginSettingsListView(SinglePluginView): """ Shows all settings available for a specific plugin (plugin schema settings). """ - def get(self, request, *args, **kwargs): + paginator_class = RockyPaginator + paginate_by = 10 + context_object_name = "plugin_settings" + + def get_plugin_settings(self) -> list[dict[str, Any]]: + """Gets schema setting with additional info of the value of a setting.""" try: - self.object_list = self.get_queryset() + if self.plugin_schema is None: + return [] + + settings = self.katalogus_client.get_plugin_settings(plugin_id=self.plugin.id) + props = self.plugin_schema["properties"] + + return [ + { + "name": prop, + "value": settings.get(prop), + "required": self.is_required_field(prop), + "secret": self.is_secret_field(prop), + } + for prop in props + ] except HTTPError: messages.add_message( self.request, messages.ERROR, _("Failed getting settings for boefje {}").format(self.plugin.id) ) - self.object_list = [] - - return super().get(request, *args, **kwargs) - - def get_queryset(self): - """Gets schema setting with additional info of the value of a setting.""" - if self.plugin_schema is None: return [] - - settings = self.katalogus_client.get_plugin_settings(plugin_id=self.plugin.id) - props = self.plugin_schema["properties"] - - return [ - { - "name": prop, - "value": settings.get(prop), - "required": self.is_required_field(prop), - "secret": self.is_secret_field(prop), - } - for prop in props - ] diff --git a/rocky/reports/report_types/aggregate_organisation_report/report.py b/rocky/reports/report_types/aggregate_organisation_report/report.py index ea938ecf724..d929718491d 100644 --- a/rocky/reports/report_types/aggregate_organisation_report/report.py +++ b/rocky/reports/report_types/aggregate_organisation_report/report.py @@ -42,7 +42,7 @@ class AggregateOrganisationReport(AggregateReport): } template_path = "aggregate_organisation_report/report.html" - def post_process_data(self, data: dict[str, Any], valid_time) -> dict[str, Any]: + def post_process_data(self, data: dict[str, Any], valid_time: datetime, organization_code: str) -> dict[str, Any]: systems: dict[str, dict[str, Any]] = {"services": {}} services = {} open_ports = {} @@ -392,7 +392,7 @@ def is_mail_compliant(result): config_oois = self.octopoes_api_connector.list_objects(types={Config}, valid_time=valid_time).items - flattened_health = flatten_health(get_rocky_health(self.octopoes_api_connector)) + flattened_health = flatten_health(get_rocky_health(organization_code, self.octopoes_api_connector)) return { "systems": systems, @@ -441,6 +441,7 @@ def aggregate_reports( input_ooi_references: list[OOI], selected_report_types: list[str], valid_time: datetime, + organization_code: str, ) -> tuple[AggregateOrganisationReport, dict[str, Any], dict[str, Any], list[str]]: by_type: dict[str, list[str]] = {} @@ -475,6 +476,6 @@ def aggregate_reports( report_data[ooi_str][report_type.id] = data aggregate_report = AggregateOrganisationReport(connector) - post_processed_data = aggregate_report.post_process_data(report_data, valid_time=valid_time) + post_processed_data = aggregate_report.post_process_data(report_data, valid_time, organization_code) return aggregate_report, post_processed_data, report_data, errors diff --git a/rocky/reports/report_types/definitions.py b/rocky/reports/report_types/definitions.py index cdf44984ebe..970e6cda569 100644 --- a/rocky/reports/report_types/definitions.py +++ b/rocky/reports/report_types/definitions.py @@ -161,7 +161,7 @@ class AggregateReportSubReports(TypedDict): class AggregateReport(BaseReport): reports: AggregateReportSubReports - def post_process_data(self, data: dict[str, Any], valid_time: datetime) -> dict[str, Any]: + def post_process_data(self, data: dict[str, Any], valid_time: datetime, organization_code: str) -> dict[str, Any]: raise NotImplementedError diff --git a/rocky/reports/views/aggregate_report.py b/rocky/reports/views/aggregate_report.py index 7c9ed7530f9..11d3c0963f9 100644 --- a/rocky/reports/views/aggregate_report.py +++ b/rocky/reports/views/aggregate_report.py @@ -145,6 +145,7 @@ def save_report(self) -> ReportOOI: input_oois, self.selected_report_types, self.observed_at, + self.organization.code, ) # If OOI could not be found or the date is incorrect, it will be shown to the user as a message error diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index f799602fdf6..56326a1a539 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-09 07:22+0000\n" +"POT-Creation-Date: 2024-07-11 11:23+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -724,7 +724,6 @@ msgstr "" #: reports/templates/partials/report_ooi_list.html #: reports/templates/report_overview/report_history_table.html #: reports/templates/summary/ooi_selection.html -#: rocky/templates/partials/task_history.html msgid "Object" msgstr "" @@ -817,7 +816,7 @@ msgid "Latest plugin settings" msgstr "" #: katalogus/templates/katalogus_settings.html -#: rocky/templates/partials/task_history.html +#: rocky/templates/tasks/ooi_detail_task_list.html msgid "Plugin" msgstr "" @@ -991,6 +990,7 @@ msgid "Plugins Navigation" msgstr "" #: katalogus/templates/partials/plugins_navigation.html +#: tools/forms/scheduler.py msgid "All" msgstr "" @@ -1136,10 +1136,6 @@ msgid "" "You do not have the permission to change clearance level." msgstr "" -#: katalogus/views/plugin_detail.py -msgid "Please select an OOI to start scan." -msgstr "" - #: katalogus/views/plugin_enable_disable.py msgid "{} '{}' disabled." msgstr "" @@ -1302,7 +1298,6 @@ msgstr "" #: rocky/templates/partials/elements/ooi_detail_settings.html #: rocky/templates/partials/elements/ooi_report_settings.html #: rocky/templates/partials/form/indemnification_add_form.html -#: rocky/templates/partials/task_history.html #: rocky/templates/two_factor/_wizard_actions.html msgid "Submit" msgstr "" @@ -2683,9 +2678,9 @@ msgstr "" #: rocky/templates/findings/finding_list.html #: rocky/templates/organizations/organization_crisis_room.html #: rocky/templates/partials/ooi_report_findings_block_table.html -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/boefje_task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html +#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html +#: rocky/templates/tasks/ooi_detail_task_list.html +#: rocky/templates/tasks/plugin_detail_task_list.html msgid "Details" msgstr "" @@ -2695,9 +2690,9 @@ msgstr "" #: rocky/templates/crisis_room/crisis_room_findings_block.html #: rocky/templates/findings/finding_list.html #: rocky/templates/organizations/organization_crisis_room.html -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/boefje_task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html +#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html +#: rocky/templates/tasks/ooi_detail_task_list.html +#: rocky/templates/tasks/plugin_detail_task_list.html msgid "Close details" msgstr "" @@ -2707,9 +2702,9 @@ msgstr "" #: rocky/templates/crisis_room/crisis_room_findings_block.html #: rocky/templates/findings/finding_list.html #: rocky/templates/organizations/organization_crisis_room.html -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/boefje_task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html +#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html +#: rocky/templates/tasks/ooi_detail_task_list.html +#: rocky/templates/tasks/plugin_detail_task_list.html msgid "Open details" msgstr "" @@ -3187,10 +3182,9 @@ msgstr "" #: reports/report_types/tls_report/report.html #: reports/templates/partials/plugin_overview_table.html #: rocky/templates/organizations/organization_member_list.html -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/boefje_task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html -#: rocky/templates/tasks/partials/task_filter.html +#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html +#: rocky/templates/tasks/ooi_detail_task_list.html +#: rocky/templates/tasks/plugin_detail_task_list.html msgid "Status" msgstr "" @@ -3443,7 +3437,6 @@ msgstr "" #: reports/templates/partials/report_ooi_list.html #: rocky/templates/admin/change_list.html rocky/templates/oois/ooi_list.html -#: rocky/templates/partials/task_history.html #: rocky/templates/tasks/partials/task_filter.html msgid "Filter" msgstr "" @@ -3780,7 +3773,8 @@ msgid "Subreports:" msgstr "" #: reports/templates/report_overview/subreports_table.html -#: rocky/templates/tasks/partials/boefje_task_history.html +#: rocky/templates/tasks/boefjes.html +#: rocky/templates/tasks/plugin_detail_task_list.html msgid "Input Object" msgstr "" @@ -3891,7 +3885,7 @@ msgstr "" msgid "Date" msgstr "" -#: tools/forms/base.py +#: tools/forms/base.py tools/forms/scheduler.py msgid "The selected date is in the future. Please select a different date." msgstr "" @@ -4070,6 +4064,50 @@ msgstr "" msgid "Filter by clearance type" msgstr "" +#: tools/forms/scheduler.py +msgid "From" +msgstr "" + +#: tools/forms/scheduler.py +msgid "To" +msgstr "" + +#: tools/forms/scheduler.py rocky/templates/tasks/partials/stats.html +msgid "Cancelled" +msgstr "" + +#: tools/forms/scheduler.py rocky/templates/tasks/partials/stats.html +msgid "Completed" +msgstr "" + +#: tools/forms/scheduler.py rocky/templates/tasks/partials/stats.html +msgid "Dispatched" +msgstr "" + +#: tools/forms/scheduler.py rocky/templates/tasks/partials/stats.html +msgid "Failed" +msgstr "" + +#: tools/forms/scheduler.py rocky/templates/tasks/partials/stats.html +msgid "Pending" +msgstr "" + +#: tools/forms/scheduler.py rocky/templates/tasks/partials/stats.html +msgid "Queued" +msgstr "" + +#: tools/forms/scheduler.py rocky/templates/tasks/partials/stats.html +msgid "Running" +msgstr "" + +#: tools/forms/scheduler.py +msgid "Search" +msgstr "" + +#: tools/forms/scheduler.py +msgid "Search by object name" +msgstr "" + #: tools/forms/settings.py msgid "--- Show all ----" msgstr "" @@ -4223,17 +4261,6 @@ msgstr "" msgid "Members" msgstr "" -#: tools/view_helpers.py -msgid "" -"Your task is scheduled and will soon be started in the background. Results " -"will be added to the object list when they are in. It may take some time, a " -"refresh of the page may be needed to show the results." -msgstr "" - -#: tools/view_helpers.py rocky/scheduler.py -msgid "Task not found." -msgstr "" - #: rocky/messaging.py msgid "" "You have trusted this member with a clearance level of L{}. This member " @@ -4254,19 +4281,47 @@ msgid "That page contains no results" msgstr "" #: rocky/scheduler.py -msgid "Connectivity issues with Mula." +msgid "" +"The Scheduler has an unexpected error. Check the Scheduler logs for further " +"details." +msgstr "" + +#: rocky/scheduler.py +msgid "Could not connect to Scheduler. Service is possibly down." +msgstr "" + +#: rocky/scheduler.py +msgid "Your request could not be validated." msgstr "" #: rocky/scheduler.py -msgid "Task queue is full, please try again later." +msgid "Task could not be found." msgstr "" #: rocky/scheduler.py -msgid "Task is invalid." +msgid "" +"Scheduler is receiving too many requests. Increase SCHEDULER_PQ_MAXSIZE or " +"wait for task to finish." +msgstr "" + +#: rocky/scheduler.py +msgid "Bad request. Your request could not be interpreted by the Scheduler." msgstr "" #: rocky/scheduler.py -msgid "Task already queued." +msgid "The Scheduler has received a conflict. Your task is already in queue." +msgstr "" + +#: rocky/scheduler.py +msgid "A HTTPError occurred. See Scheduler logs for more info." +msgstr "" + +#: rocky/scheduler.py +msgid "Task list: " +msgstr "" + +#: rocky/scheduler.py +msgid "Task statistics: " msgstr "" #: rocky/settings.py @@ -4755,9 +4810,8 @@ msgstr "" msgid "Crisis room" msgstr "" -#: rocky/templates/header.html rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/boefje_task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html +#: rocky/templates/header.html rocky/templates/tasks/ooi_detail_task_list.html +#: rocky/templates/tasks/plugin_detail_task_list.html #: rocky/views/task_detail.py rocky/views/tasks.py msgid "Tasks" msgstr "" @@ -4944,9 +4998,8 @@ msgstr "" #: rocky/templates/oois/ooi_detail.html #: rocky/templates/oois/ooi_detail_origins_observations.html -#: rocky/templates/scan.html -#: rocky/templates/tasks/partials/boefje_task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html +#: rocky/templates/scan.html rocky/templates/tasks/boefjes.html +#: rocky/templates/tasks/normalizers.html msgid "Boefje" msgstr "" @@ -5798,85 +5851,6 @@ msgstr "" msgid "Go to content" msgstr "" -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "Hide filters" -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "Show filters" -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "From" -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "To" -msgstr "" - -#: rocky/templates/partials/task_history.html -msgid "Select status" -msgstr "" - -#: rocky/templates/partials/task_history.html -msgid "Success" -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/stats.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "Failed" -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "Search" -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "Search by object name" -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html -msgid "No tasks found for this object." -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/boefje_task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html -msgid "Created date" -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html -msgid "Yielded objects" -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/boefje_task_detail.html -#: rocky/templates/tasks/partials/boefje_task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html -msgid "Download meta and raw data" -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/boefje_task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html -msgid "Reschedule" -msgstr "" - -#: rocky/templates/partials/task_history.html -#: rocky/templates/tasks/partials/boefje_task_history.html -#: rocky/templates/tasks/partials/normalizer_task_history.html -msgid "Download task data" -msgstr "" - #: rocky/templates/scan_profiles/scan_profile_detail.html msgid "Current clearance level" msgstr "" @@ -5945,6 +5919,11 @@ msgid "" "An overview of the boefje task, the input OOI and the RAW data it generated." msgstr "" +#: rocky/templates/tasks/boefje_task_detail.html +#: rocky/templates/tasks/partials/task_actions.html +msgid "Download meta and raw data" +msgstr "" + #: rocky/templates/tasks/boefje_task_detail.html msgid "Download meta data" msgstr "" @@ -5961,6 +5940,12 @@ msgstr "" msgid "List of tasks for boefjes" msgstr "" +#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html +#: rocky/templates/tasks/ooi_detail_task_list.html +#: rocky/templates/tasks/plugin_detail_task_list.html +msgid "Created date" +msgstr "" + #: rocky/templates/tasks/normalizers.html msgid "There are no tasks for normalizers" msgstr "" @@ -5969,68 +5954,62 @@ msgstr "" msgid "List of tasks for normalizers" msgstr "" -#: rocky/templates/tasks/partials/boefje_task_history.html -msgid "No scans found for this object." -msgstr "" - -#: rocky/templates/tasks/partials/normalizer_task_history.html +#: rocky/templates/tasks/normalizers.html msgid "Normalizer" msgstr "" -#: rocky/templates/tasks/partials/normalizer_task_history.html +#: rocky/templates/tasks/normalizers.html msgid "Boefje input OOI" msgstr "" -#: rocky/templates/tasks/partials/stats.html -msgid "Stats - Last 24 hours" +#: rocky/templates/tasks/ooi_detail_task_list.html +#: rocky/templates/tasks/plugin_detail_task_list.html +msgid "There are no tasks for" msgstr "" -#: rocky/templates/tasks/partials/stats.html -msgid "All times in UTC, blocks of 1 hour." +#: rocky/templates/tasks/ooi_detail_task_list.html +#: rocky/templates/tasks/plugin_detail_task_list.html +msgid "List of tasks for" msgstr "" #: rocky/templates/tasks/partials/stats.html -msgid "Timeslot" +msgid "Task statistics - Last 24 hours" msgstr "" #: rocky/templates/tasks/partials/stats.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "Pending" +msgid "All times in UTC, blocks of 1 hour." msgstr "" #: rocky/templates/tasks/partials/stats.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "Queued" +msgid "Timeslot" msgstr "" #: rocky/templates/tasks/partials/stats.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "Dispatched" +msgid "Could not load stats, Scheduler error." msgstr "" -#: rocky/templates/tasks/partials/stats.html -msgid "Running" +#: rocky/templates/tasks/partials/tab_navigation.html +msgid "List of tasks" msgstr "" -#: rocky/templates/tasks/partials/stats.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "Completed" +#: rocky/templates/tasks/partials/task_actions.html +msgid "Yielded objects" msgstr "" -#: rocky/templates/tasks/partials/stats.html -msgid "Cancelled" +#: rocky/templates/tasks/partials/task_actions.html +msgid "Reschedule" msgstr "" -#: rocky/templates/tasks/partials/stats.html -msgid "Could not load stats, Scheduler error." +#: rocky/templates/tasks/partials/task_actions.html +msgid "Download task data" msgstr "" -#: rocky/templates/tasks/partials/tab_navigation.html -msgid "List of tasks" +#: rocky/templates/tasks/partials/task_filter.html +msgid "Hide filters" msgstr "" #: rocky/templates/tasks/partials/task_filter.html -msgid "all" +msgid "Show filters" msgstr "" #: rocky/templates/two_factor/_wizard_actions.html @@ -6313,6 +6292,10 @@ msgstr "" msgid "Only Question OOIs can be answered." msgstr "" +#: rocky/views/ooi_detail.py +msgid "Question has been answered." +msgstr "" + #: rocky/views/ooi_detail_related_object.py msgid " (as " msgstr "" @@ -6552,6 +6535,10 @@ msgstr "" msgid "Recalculated {number_of_bits} bits. Duration: {duration}" msgstr "" +#: rocky/views/page_actions.py +msgid "Could not process your request, action required." +msgstr "" + #: rocky/views/scan_profile.py #, python-brace-format msgid "Can not reset scan level. Scan level of {ooi_name} not declared" @@ -6561,8 +6548,11 @@ msgstr "" msgid "Reset" msgstr "" -#: rocky/views/tasks.py -msgid "Fetching tasks failed: no connection with scheduler" +#: rocky/views/scheduler.py +msgid "" +"Your task is scheduled and will soon be started in the background. Results " +"will be added to the object list when they are in. It may take some time, a " +"refresh of the page may be needed to show the results." msgstr "" #: rocky/views/upload_csv.py diff --git a/rocky/rocky/scheduler.py b/rocky/rocky/scheduler.py index f9ac40fb633..5b80b2c7c9b 100644 --- a/rocky/rocky/scheduler.py +++ b/rocky/rocky/scheduler.py @@ -4,14 +4,15 @@ import json import uuid from enum import Enum +from functools import cached_property from logging import getLogger from typing import Any import httpx from django.conf import settings from django.utils.translation import gettext_lazy as _ -from httpx import HTTPError, HTTPStatusError, RequestError, codes -from pydantic import BaseModel, ConfigDict, Field, SerializeAsAny +from httpx import ConnectError, HTTPError, HTTPStatusError, RequestError, codes +from pydantic import BaseModel, ConfigDict, Field, SerializeAsAny, ValidationError from rocky.health import ServiceHealth @@ -123,6 +124,8 @@ class PaginatedTasksResponse(BaseModel): class LazyTaskList: + HARD_LIMIT = 500 + def __init__( self, scheduler_client: SchedulerClient, @@ -132,7 +135,7 @@ def __init__( self.kwargs = kwargs self._count: int | None = None - @property + @cached_property def count(self) -> int: if self._count is None: self._count = self.scheduler_client.list_tasks( @@ -147,7 +150,8 @@ def __len__(self): def __getitem__(self, key) -> list[Task]: if isinstance(key, slice): offset = key.start or 0 - limit = key.stop - offset + limit = min(LazyTaskList.HARD_LIMIT, key.stop - offset or key.stop or LazyTaskList.HARD_LIMIT) + elif isinstance(key, int): offset = key limit = 1 @@ -161,83 +165,89 @@ def __getitem__(self, key) -> list[Task]: ) self._count = res.count + return res.results class SchedulerError(Exception): - message = _("Connectivity issues with Mula.") + message: str = _("The Scheduler has an unexpected error. Check the Scheduler logs for further details.") + + def __init__(self, *args: object, extra_message: str | None = None) -> None: + super().__init__(*args) + if extra_message is not None: + self.message = extra_message + self.message def __str__(self): return str(self.message) -class TooManyRequestsError(SchedulerError): - message = _("Task queue is full, please try again later.") +class SchedulerConnectError(SchedulerError): + message = _("Could not connect to Scheduler. Service is possibly down.") + + +class SchedulerValidationError(SchedulerError): + message = _("Your request could not be validated.") -class BadRequestError(SchedulerError): - message = _("Task is invalid.") +class SchedulerTaskNotFound(SchedulerError): + message = _("Task could not be found.") -class ConflictError(SchedulerError): - message = _("Task already queued.") +class SchedulerTooManyRequestError(SchedulerError): + message = _("Scheduler is receiving too many requests. Increase SCHEDULER_PQ_MAXSIZE or wait for task to finish.") -class TaskNotFoundError(SchedulerError): - message = _("Task not found.") +class SchedulerBadRequestError(SchedulerError): + message = _("Bad request. Your request could not be interpreted by the Scheduler.") + + +class SchedulerConflictError(SchedulerError): + message = _("The Scheduler has received a conflict. Your task is already in queue.") + + +class SchedulerHTTPError(SchedulerError): + message = _("A HTTPError occurred. See Scheduler logs for more info.") class SchedulerClient: - def __init__(self, base_uri: str): + def __init__(self, base_uri: str, organization_code: str): self._client = httpx.Client(base_url=base_uri) + self.organization_code = organization_code def list_tasks( self, **kwargs, ) -> PaginatedTasksResponse: - kwargs = {k: v for k, v in kwargs.items() if v is not None} # filter Nones from kwargs - res = self._client.get("/tasks", params=kwargs) - return PaginatedTasksResponse.model_validate_json(res.content) - - def get_lazy_task_list( - self, - scheduler_id: str, - task_type: str | None = None, - status: str | None = None, - min_created_at: datetime.datetime | None = None, - max_created_at: datetime.datetime | None = None, - input_ooi: str | None = None, - plugin_id: str | None = None, - boefje_name: str | None = None, - ) -> LazyTaskList: - return LazyTaskList( - self, - scheduler_id=scheduler_id, - type=task_type, - status=status, - min_created_at=min_created_at, - max_created_at=max_created_at, - input_ooi=input_ooi, - plugin_id=plugin_id, - boefje_name=boefje_name, - ) + try: + kwargs = {k: v for k, v in kwargs.items() if v is not None} # filter Nones from kwargs + res = self._client.get("/tasks", params=kwargs) + return PaginatedTasksResponse.model_validate_json(res.content) + except ValidationError: + raise SchedulerValidationError(extra_message=_("Task list: ")) + except ConnectError: + raise SchedulerConnectError(extra_message=_("Task list: ")) + + def get_task_details(self, task_id: str) -> Task: + try: + res = self._client.get(f"/tasks/{task_id}") + res.raise_for_status() + task_details = Task.model_validate_json(res.content) - def get_task_details(self, organization_code: str, task_id: str) -> Task: - res = self._client.get(f"/tasks/{task_id}") - res.raise_for_status() - task_details = Task.model_validate_json(res.content) + if task_details.type == "normalizer": + organization = task_details.p_item.data.raw_data.boefje_meta.organization + else: + organization = task_details.p_item.data.organization - if task_details.type == "normalizer": - organization = task_details.p_item.data.raw_data.boefje_meta.organization - else: - organization = task_details.p_item.data.organization + if organization != self.organization_code: + raise SchedulerTaskNotFound() - if organization != organization_code: - raise TaskNotFoundError() - return task_details + return task_details + except ConnectError: + raise SchedulerConnectError() - def push_task(self, queue_name: str, prioritized_item: PrioritizedItem) -> None: + def push_task(self, prioritized_item: PrioritizedItem) -> None: try: + queue_name = f"{prioritized_item.data.type}-{self.organization_code}" res = self._client.post( f"/queues/{queue_name}/push", content=prioritized_item.json(), @@ -247,29 +257,33 @@ def push_task(self, queue_name: str, prioritized_item: PrioritizedItem) -> None: except HTTPStatusError as http_error: code = http_error.response.status_code if code == codes.TOO_MANY_REQUESTS: - raise TooManyRequestsError() + raise SchedulerTooManyRequestError() elif code == codes.BAD_REQUEST: - raise BadRequestError() + raise SchedulerBadRequestError() elif code == codes.CONFLICT: - raise ConflictError() - else: - raise SchedulerError() + raise SchedulerConflictError() except RequestError: raise SchedulerError() def health(self) -> ServiceHealth: - health_endpoint = self._client.get("/health") - health_endpoint.raise_for_status() - return ServiceHealth.model_validate_json(health_endpoint.content) + try: + health_endpoint = self._client.get("/health") + health_endpoint.raise_for_status() + return ServiceHealth.model_validate_json(health_endpoint.content) + except HTTPError: + raise SchedulerHTTPError() + except ConnectError: + raise SchedulerConnectError() - def get_task_stats(self, organization_code: str, task_type: str) -> dict: + def get_task_stats(self, task_type: str) -> dict: try: - res = self._client.get(f"/tasks/stats/{task_type}-{organization_code}") + res = self._client.get(f"/tasks/stats/{task_type}-{self.organization_code}") res.raise_for_status() - except HTTPError: - raise SchedulerError() + except ConnectError: + raise SchedulerConnectError(extra_message=_("Task statistics: ")) task_stats = json.loads(res.content) return task_stats -client = SchedulerClient(settings.SCHEDULER_API) +def scheduler_client(organization_code: str) -> SchedulerClient: + return SchedulerClient(settings.SCHEDULER_API, organization_code) diff --git a/rocky/rocky/templates/oois/ooi_detail.html b/rocky/rocky/templates/oois/ooi_detail.html index a85076fcd0b..9a55c6511b2 100644 --- a/rocky/rocky/templates/oois/ooi_detail.html +++ b/rocky/rocky/templates/oois/ooi_detail.html @@ -31,7 +31,7 @@ {% include "oois/ooi_detail_origins_observations.html" %} {% include "oois/ooi_detail_origins_inference.html" %} {% include "partials/ooi_detail_related_object.html" with query=mandatory_fields ooi_past_due=ooi_past_due related=related ooi=ooi %} - {% include "partials/task_history.html" %} + {% include "tasks/ooi_detail_task_list.html" %}
diff --git a/rocky/rocky/templates/partials/task_history.html b/rocky/rocky/templates/partials/task_history.html deleted file mode 100644 index 754d8a166df..00000000000 --- a/rocky/rocky/templates/partials/task_history.html +++ /dev/null @@ -1,146 +0,0 @@ -{% load i18n %} - -
-

{% translate "Tasks" %}

-
-
-

{% translate "Filter" %}

- -
-
-
- - -
-
- - -
-
- - -
-
- - -
- {% for key, value in request.GET.items %} - {% if key not in task_history_form_fields %}{% endif %} - {% endfor %} -
- -
- -
- {% if not task_history %} - {% translate "No tasks found for this object." %} - {% else %} -
{% translate "Observed by" %}{% translate "Last observed by" %}
{% translate "Boefje" %} {% translate "Source" %} {% translate "Task ID" %}{% translate "When" %}
{% if observation.boefje.id %} {{ observation.boefje.name }} + {% else %} + {% translate "The boefje has since been deleted or disabled." %} {% endif %} @@ -28,8 +31,11 @@

{% translate "Observed by" %}

{% if observation.normalizer.raw_data.boefje_meta.id %} {{ observation.normalizer.raw_data.boefje_meta.id }} + {% else %} + {% translate "No Raw file could be found, this might point to an error in OpenKAT" %} {% endif %} {{ observation.normalizer.raw_data.boefje_meta.ended_at }}
- - - - - - - - - - - {% for task in task_history %} - - - - - - - - - - - {% endfor %} - -
{% translate "Object" %}{% translate "Plugin" %}{% translate "Status" %}{% translate "Created date" %}{% translate "Details" %}
- {% if task.type == "boefje" %} - {{ task.p_item.data.input_ooi }} - {% elif task.type == "normalizer" %} - {{ task.p_item.data.raw_data.boefje_meta.input_ooi }} - {% else %} - {{ task.id }} - {% endif %} - - {% if task.type == "boefje" %} - {{ task.p_item.data.boefje.name }} - {% elif task.type == "normalizer" %} - {{ task.p_item.data.normalizer.id }} - {% else %} - {{ task.id }} - {% endif %} - - {% if task.status.value == "pending" or task.status.value == "queued" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "running" or task.status.value == "dispatched" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "cancelled" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "failed" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "completed" %} -  {{ task.status.value|capfirst }} - {% else %} -  {{ task.status.value|capfirst }} - {% endif %} - {{ task.created_at }} - -
- {% if task.type == "normalizer" %} -
-
-

{% translate "Yielded objects" %}

-
-
-
- {% endif %} -
-
- {% if task.status.value in "completed,failed" %} - {% translate "Download meta and raw data" %} - {% include "partials/single_action_form.html" with btn_text=_("Reschedule") btn_class="ghost" btn_icon="icon ti-refresh" action="reschedule_task" key="task_id" value=task.id %} - - {% else %} - {% translate "Download task data" %} - {% endif %} -
-
-
- {% endif %} -
-{% include "partials/list_paginator.html" with page_obj=task_history page_param="task_history_page" %} diff --git a/rocky/rocky/templates/tasks/boefjes.html b/rocky/rocky/templates/tasks/boefjes.html index 60e651ecaf9..7b8ee24d0e4 100644 --- a/rocky/rocky/templates/tasks/boefjes.html +++ b/rocky/rocky/templates/tasks/boefjes.html @@ -13,18 +13,60 @@ {% include "tasks/partials/tab_navigation.html" with view="boefjes_tasks" %}

{% translate "Boefjes" %}

- {% include "tasks/partials/task_filter.html" %} - - {% if not object_list %} + {% if not task_list %}

{% translate "There are no tasks for boefjes" %}

+ {% include "tasks/partials/task_filter.html" %} + {% else %}

{% translate "List of tasks for boefjes" %}

+ {% include "tasks/partials/task_filter.html" %} +
- {% include "tasks/partials/boefje_task_history.html" with task_history=object_list %} + + + + + + + + + + + + {% for task in task_list %} + + + + + + + + + + + {% endfor %} + +
{% translate "Boefje" %}{% translate "Status" %}{% translate "Created date" %}{% translate "Input Object" %}{% translate "Details" %}
+ {{ task.p_item.data.boefje.name }} + +  {{ task.status.value|capfirst }} + {{ task.created_at }} + {{ task.p_item.data.input_ooi }} + + +
+ {% include "tasks/partials/task_actions.html" %} - - {% include "partials/list_paginator.html" %} +
+ {% include "partials/list_paginator.html" %} +
{% endif %} diff --git a/rocky/rocky/templates/tasks/normalizers.html b/rocky/rocky/templates/tasks/normalizers.html index 10ac611965c..9ead44abaf3 100644 --- a/rocky/rocky/templates/tasks/normalizers.html +++ b/rocky/rocky/templates/tasks/normalizers.html @@ -14,18 +14,64 @@ {% include "tasks/partials/tab_navigation.html" with view="normalizers_tasks" %}

{% translate "Normalizers" %}

- {% include "tasks/partials/task_filter.html" %} - - {% if not object_list %} + {% if not task_list %}

{% translate "There are no tasks for normalizers" %}

+ {% include "tasks/partials/task_filter.html" %} + {% else %}

{% translate "List of tasks for normalizers" %}

+ {% include "tasks/partials/task_filter.html" %} +
- {% include "tasks/partials/normalizer_task_history.html" with task_history=object_list %} + + + + + + + + + + + + + {% for task in task_list %} + + + + + + + + + + + + {% endfor %} + +
{% translate "Normalizer" %}{% translate "Status" %}{% translate "Created date" %}{% translate "Boefje" %}{% translate "Boefje input OOI" %}{% translate "Details" %}
+ {{ task.p_item.data.normalizer.id }} + +  {{ task.status.value|capfirst }} + {{ task.created_at }} + {{ task.p_item.data.raw_data.boefje_meta.boefje.id }} + + {{ task.p_item.data.raw_data.boefje_meta.input_ooi }} + + +
+ {% include "tasks/partials/task_actions.html" %} - - {% include "partials/list_paginator.html" %} +
+ {% include "partials/list_paginator.html" %} +
{% endif %} diff --git a/rocky/rocky/templates/tasks/ooi_detail_task_list.html b/rocky/rocky/templates/tasks/ooi_detail_task_list.html new file mode 100644 index 00000000000..bfd85589b89 --- /dev/null +++ b/rocky/rocky/templates/tasks/ooi_detail_task_list.html @@ -0,0 +1,60 @@ +{% load i18n %} + +
+

{% translate "Tasks" %}

+ {% ooi_url 'ooi_detail' ooi.primary_key organization.code query=mandatory_fields as this_url %} + {% if not task_list %} +

{% translate "There are no tasks for" %} {{ ooi }}

+ {% include "tasks/partials/task_filter.html" with clear_filter_url=this_url %} + + {% else %} +

{% translate "List of tasks for" %} {{ ooi }}

+ {% include "tasks/partials/task_filter.html" with clear_filter_url=this_url %} + + + + + + + + + + + + {% for task in task_list %} + + + + + + + + + + {% endfor %} + +
{% translate "Plugin" %}{% translate "Status" %}{% translate "Created date" %}{% translate "Details" %}
+ {% if task.type == "boefje" %} + {{ task.p_item.data.boefje.name }} + {% elif task.type == "normalizer" %} + {{ task.p_item.data.normalizer.id }} + {% else %} + {{ task.id }} + {% endif %} + +  {{ task.status.value|capfirst }} + {{ task.created_at }} + +
+ {% include "tasks/partials/task_actions.html" %} + +
+ {% endif %} +
+{% include "partials/list_paginator.html" %} diff --git a/rocky/rocky/templates/tasks/partials/boefje_task_history.html b/rocky/rocky/templates/tasks/partials/boefje_task_history.html deleted file mode 100644 index 94468bb3d42..00000000000 --- a/rocky/rocky/templates/tasks/partials/boefje_task_history.html +++ /dev/null @@ -1,76 +0,0 @@ -{% load i18n %} - -
-

{% translate "Tasks" %}

- {% if not task_history %} - {% translate "No scans found for this object." %} - {% else %} - - - - - - - - - - - - {% for task in task_history %} - - - - - - {# FIXME: implement detail page according to designs #} - - - - - - {% endfor %} - -
{% translate "Boefje" %}{% translate "Status" %}{% translate "Created date" %}{% translate "Input Object" %}{% translate "Details" %}
- {{ task.p_item.data.boefje.name }} - - {% if task.status.value == "pending" or task.status.value == "queued" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "running" or task.status.value == "dispatched" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "cancelled" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "failed" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "completed" %} -  {{ task.status.value|capfirst }} - {% else %} -  {{ task.status.value|capfirst }} - {% endif %} - {{ task.created_at }} - {{ task.p_item.data.input_ooi }} - - -
-
-
- {% if task.status.value in "completed,failed" %} - {% translate "Download meta and raw data" %} - {% include "partials/single_action_form.html" with btn_text=_("Reschedule") btn_class="ghost" btn_icon="icon ti-refresh" action="reschedule_task" key="task_id" value=task.id %} - - {% else %} - {% translate "Download task data" %} - {% endif %} -
-
-
- {% endif %} -
-{% include "partials/list_paginator.html" with page_obj=task_history page_param="task_history_page" %} diff --git a/rocky/rocky/templates/tasks/partials/normalizer_task_history.html b/rocky/rocky/templates/tasks/partials/normalizer_task_history.html deleted file mode 100644 index 77529ce57df..00000000000 --- a/rocky/rocky/templates/tasks/partials/normalizer_task_history.html +++ /dev/null @@ -1,88 +0,0 @@ -{% load i18n %} - -
-

{% translate "Tasks" %}

- {% if not task_history %} - {% translate "No tasks found for this object." %} - {% else %} - - - - - - - - - - - - - {% for task in task_history %} - - - - - - - {# FIXME: implement detail page according to designs #} - - - - - - {% endfor %} - -
{% translate "Normalizer" %}{% translate "Status" %}{% translate "Created date" %}{% translate "Boefje" %}{% translate "Boefje input OOI" %}{% translate "Details" %}
- {{ task.p_item.data.normalizer.id }} - - {% if task.status.value == "pending" or task.status.value == "queued" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "running" or task.status.value == "dispatched" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "cancelled" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "failed" %} -  {{ task.status.value|capfirst }} - {% elif task.status.value == "completed" %} -  {{ task.status.value|capfirst }} - {% else %} -  {{ task.status.value|capfirst }} - {% endif %} - {{ task.created_at }} - {{ task.p_item.data.raw_data.boefje_meta.boefje.id }} - - {{ task.p_item.data.raw_data.boefje_meta.input_ooi }} - - -
-
-
-

{% translate "Yielded objects" %}

-
-
-
-
-
-
- {% if task.status.value in "completed,failed" %} - {% translate "Download meta and raw data" %} - {% include "partials/single_action_form.html" with btn_text=_("Reschedule") btn_class="ghost" btn_icon="icon ti-refresh" action="reschedule_task" key="task_id" value=task.id %} - - {% else %} - {% translate "Download task data" %} - {% endif %} -
-
-
-
- {% endif %} -
-{% include "partials/list_paginator.html" with page_obj=task_history page_param="task_history_page" %} diff --git a/rocky/rocky/templates/tasks/partials/stats.html b/rocky/rocky/templates/tasks/partials/stats.html index 78202add532..4c06451f00b 100644 --- a/rocky/rocky/templates/tasks/partials/stats.html +++ b/rocky/rocky/templates/tasks/partials/stats.html @@ -2,7 +2,7 @@
-

{% translate "Stats - Last 24 hours" %}

+

{% translate "Task statistics - Last 24 hours" %}

{% if not stats_error %}
diff --git a/rocky/rocky/templates/tasks/partials/task_actions.html b/rocky/rocky/templates/tasks/partials/task_actions.html new file mode 100644 index 00000000000..5a21db4996b --- /dev/null +++ b/rocky/rocky/templates/tasks/partials/task_actions.html @@ -0,0 +1,30 @@ +{% load i18n %} + +{% if task.type == "normalizer" %} +
+
+

{% translate "Yielded objects" %}

+
+
+
+{% endif %} +
+
+ {% if task.status.value in "completed,failed" %} + {% if task.type == "normalizer" %} + {% translate "Download meta and raw data" %} + {% include "partials/single_action_form.html" with btn_text=_("Reschedule") btn_class="ghost" btn_icon="icon ti-refresh" action="reschedule_task" key="task_id" value=task.id %} + + {% elif task.type == "boefje" %} + {% translate "Download meta and raw data" %} + {% include "partials/single_action_form.html" with btn_text=_("Reschedule") btn_class="ghost" btn_icon="icon ti-refresh" action="reschedule_task" key="task_id" value=task.id %} + + {% endif %} + {% else %} + {% translate "Download task data" %} + {% endif %} +
+
diff --git a/rocky/rocky/templates/tasks/partials/task_filter.html b/rocky/rocky/templates/tasks/partials/task_filter.html index db748a90268..92b34d69a09 100644 --- a/rocky/rocky/templates/tasks/partials/task_filter.html +++ b/rocky/rocky/templates/tasks/partials/task_filter.html @@ -6,62 +6,14 @@ - -
- - -
-
- - -
-
- - -
-
- - - {% for key, value in request.GET.items %} - {% if key not in scan_history_form_fields %}{% endif %} - {% endfor %} -
- - {% translate "Clear filters" %} + + {% include "partials/form/fieldset.html" with fields=task_filter_form %} + + diff --git a/rocky/rocky/templates/tasks/plugin_detail_task_list.html b/rocky/rocky/templates/tasks/plugin_detail_task_list.html new file mode 100644 index 00000000000..55079e91cd2 --- /dev/null +++ b/rocky/rocky/templates/tasks/plugin_detail_task_list.html @@ -0,0 +1,62 @@ +{% load i18n %} + +
+

{% translate "Tasks" %}

+ {% if not task_list %} +

{% translate "There are no tasks for" %} {{ plugin.name }}

+ {% include "tasks/partials/task_filter.html" %} + + {% else %} +

{% translate "List of tasks for" %} {{ plugin.name }}

+ {% include "tasks/partials/task_filter.html" %} + +
+ + + + + + + + + + {% for task in task_list %} + + + + + + + + + + {% endfor %} + +
{% translate "Status" %}{% translate "Created date" %}{% translate "Input Object" %}{% translate "Details" %}
+  {{ task.status.value|capfirst }} + {{ task.created_at }} + {% if task.type == "boefje" %} + {% with ooi=task.p_item.data.input_ooi %} + {{ ooi }} + {% endwith %} + {% elif task.type == "normalizer" %} + {% with ooi=task.p_item.data.raw_data.boefje_meta.input_ooi %} + {{ ooi }} + {% endwith %} + {% endif %} + + +
+ {% include "tasks/partials/task_actions.html" %} + +
+ {% include "partials/list_paginator.html" %} + + {% endif %} +
diff --git a/rocky/rocky/urls.py b/rocky/rocky/urls.py index f5e17a8ba65..bb1157c8409 100644 --- a/rocky/rocky/urls.py +++ b/rocky/rocky/urls.py @@ -39,8 +39,8 @@ from rocky.views.privacy_statement import PrivacyStatementView from rocky.views.scan_profile import ScanProfileDetailView, ScanProfileResetView from rocky.views.scans import ScanListView -from rocky.views.task_detail import BoefjeTaskDetailView, NormalizerTaskJSONView -from rocky.views.tasks import BoefjesTaskListView, DownloadTaskDetail, NormalizersTaskListView +from rocky.views.task_detail import BoefjeTaskDetailView, DownloadTaskDetail, NormalizerTaskJSONView +from rocky.views.tasks import BoefjesTaskListView, NormalizersTaskListView from rocky.views.upload_csv import UploadCSV from rocky.views.upload_raw import UploadRaw diff --git a/rocky/rocky/views/health.py b/rocky/rocky/views/health.py index ea8de1c4941..15217211118 100644 --- a/rocky/rocky/views/health.py +++ b/rocky/rocky/views/health.py @@ -11,7 +11,7 @@ from rocky.bytes_client import get_bytes_client from rocky.health import ServiceHealth from rocky.keiko import keiko_client -from rocky.scheduler import client +from rocky.scheduler import SchedulerError, scheduler_client from rocky.version import __version__ logger = structlog.get_logger(__name__) @@ -20,7 +20,7 @@ class Health(OrganizationView, View): def get(self, request, *args, **kwargs) -> JsonResponse: octopoes_connector = self.octopoes_api_connector - rocky_health = get_rocky_health(octopoes_connector) + rocky_health = get_rocky_health(self.organization.code, octopoes_connector) return JsonResponse(rocky_health.model_dump()) @@ -51,10 +51,10 @@ def get_octopoes_health(octopoes_api_connector: OctopoesAPIConnector) -> Service return octopoes_health -def get_scheduler_health() -> ServiceHealth: +def get_scheduler_health(organization_code: str) -> ServiceHealth: try: - scheduler_health = client.health() - except HTTPError: + scheduler_health = scheduler_client(organization_code).health() + except SchedulerError: logger.exception("Error while retrieving Scheduler health state") scheduler_health = ServiceHealth( service="scheduler", @@ -76,11 +76,11 @@ def get_keiko_health() -> ServiceHealth: ) -def get_rocky_health(octopoes_api_connector: OctopoesAPIConnector) -> ServiceHealth: +def get_rocky_health(organization_code: str, octopoes_api_connector: OctopoesAPIConnector) -> ServiceHealth: services = [ get_octopoes_health(octopoes_api_connector), get_katalogus_health(), - get_scheduler_health(), + get_scheduler_health(organization_code), get_bytes_health(), get_keiko_health(), ] @@ -119,6 +119,8 @@ def get_context_data(self, **kwargs): "text": _("Beautified"), }, ] - rocky_health = get_rocky_health(self.octopoes_api_connector) + + rocky_health = get_rocky_health(self.organization.code, self.octopoes_api_connector) context["health_checks"] = flatten_health(rocky_health) + return context diff --git a/rocky/rocky/views/ooi_detail.py b/rocky/rocky/views/ooi_detail.py index 3052b3e1637..fac902817f7 100644 --- a/rocky/rocky/views/ooi_detail.py +++ b/rocky/rocky/views/ooi_detail.py @@ -1,153 +1,77 @@ import json from collections import defaultdict -from datetime import datetime, timezone -from enum import Enum +from datetime import datetime from django.contrib import messages -from django.core.paginator import Page, Paginator -from django.http import Http404 -from django.shortcuts import redirect from django.utils.translation import gettext_lazy as _ -from httpx import HTTPError from jsonschema.validators import Draft202012Validator from katalogus.client import get_katalogus from katalogus.utils import get_enabled_boefjes_for_ooi_class -from katalogus.views.mixins import BoefjeMixin -from tools.forms.base import ObservedAtForm from tools.forms.ooi import PossibleBoefjesFilterForm -from tools.models import Indemnification +from tools.forms.scheduler import OOIDetailTaskFilterForm from tools.ooi_helpers import format_display -from tools.view_helpers import reschedule_task -from octopoes.models import OOI, Reference +from octopoes.models import Reference from octopoes.models.ooi.question import Question -from rocky import scheduler from rocky.views.ooi_detail_related_object import OOIFindingManager, OOIRelatedObjectAddView from rocky.views.ooi_view import BaseOOIDetailView - - -class PageActions(Enum): - START_SCAN = "start_scan" - SUBMIT_ANSWER = "submit_answer" - RESCHEDULE_TASK = "reschedule_task" - CHANGE_CLEARANCE_LEVEL = "change_clearance_level" +from rocky.views.tasks import TaskListView class OOIDetailView( - BoefjeMixin, + BaseOOIDetailView, OOIRelatedObjectAddView, OOIFindingManager, - BaseOOIDetailView, + TaskListView, ): template_name = "oois/ooi_detail.html" - connector_form_class = ObservedAtForm - task_history_limit = 10 + task_filter_form = OOIDetailTaskFilterForm + task_type = "boefje" def post(self, request, *args, **kwargs): + if self.action == self.CHANGE_CLEARANCE_LEVEL: + self.set_clearance_level() + if self.action == self.SUBMIT_ANSWER: + self.answer_ooi_questions() + if self.action == self.START_SCAN: + self.start_boefje_scan() + return super().post(request, *args, **kwargs) + + def set_clearance_level(self) -> None: if not self.indemnification_present: - messages.add_message( - request, messages.ERROR, f"Indemnification not present at organization {self.organization}." - ) - return self.get(request, status_code=403, *args, **kwargs) - - if "action" not in self.request.POST: - return self.get(request, status_code=404, *args, **kwargs) - - self.ooi = self.get_ooi() - - action = self.request.POST.get("action") - return self.handle_page_action(action) - - def handle_page_action(self, action: str) -> bool: - try: - if action == PageActions.CHANGE_CLEARANCE_LEVEL.value: - clearance_level = int(self.request.POST.get("level")) - if not self.can_raise_clearance_level(self.ooi, clearance_level): - return redirect("account_detail", organization_code=self.organization.code) - return self.get(self.request, *self.args, **self.kwargs) - - if action == PageActions.RESCHEDULE_TASK.value: - task_id = self.request.POST.get("task_id") - reschedule_task(self.request, self.organization.code, task_id) - - if action == PageActions.START_SCAN.value: - boefje_id = self.request.POST.get("boefje_id") - ooi_id = self.request.GET.get("ooi_id") - - boefje = get_katalogus(self.organization.code).get_plugin(boefje_id) - ooi = self.get_single_ooi(pk=ooi_id) - self.run_boefje_for_oois(boefje, [ooi]) - return redirect("task_list", organization_code=self.organization.code) - - if action == PageActions.SUBMIT_ANSWER.value: - if not isinstance(self.ooi, Question): - messages.add_message(self.request, messages.ERROR, _("Only Question OOIs can be answered.")) - return self.get(self.request, status_code=500, *self.args, **self.kwargs) - - schema_answer = self.request.POST.get("schema") - parsed_schema_answer = json.loads(schema_answer) - validator = Draft202012Validator(json.loads(self.ooi.json_schema)) - - if not validator.is_valid(parsed_schema_answer): - for error in validator.iter_errors(parsed_schema_answer): - messages.add_message(self.request, messages.ERROR, error.message) - - return self.get(self.request, status_code=422, *self.args, **self.kwargs) - - raw = json.dumps({"schema": self.ooi.schema_id, "answer": parsed_schema_answer}).encode() - self.bytes_client.upload_raw(raw, {"answer"}, self.ooi.ooi) - messages.add_message(self.request, messages.SUCCESS, "Question has been answered.") - return self.get(self.request, status_code=201, *self.args, **self.kwargs) - - return self.get(self.request, status_code=404, *self.args, **self.kwargs) - except HTTPError as exception: - messages.add_message(self.request, messages.ERROR, f"{action} failed: '{exception}'") - return self.get(self.request, status_code=500, *self.args, **self.kwargs) - - def get_current_ooi(self) -> OOI | None: - # self.ooi is already the current state of the OOI - if self.observed_at.date() == datetime.utcnow().date(): - return self.ooi - try: - return self.get_ooi(pk=self.get_ooi_id(), observed_at=datetime.now(timezone.utc)) - except Http404: - return None - - def get_organization_indemnification(self): - return Indemnification.objects.filter(organization=self.organization).exists() - - def get_task_history(self) -> Page: - scheduler_id = f"boefje-{self.organization.code}" - - # FIXME: in context of ooi detail is doesn't make sense to search - # for an object name, so we search on plugin id - plugin_id = self.request.GET.get("task_history_search") or None - - page = int(self.request.GET.get("task_history_page", 1)) - - status = self.request.GET.get("task_history_status") - - if self.request.GET.get("task_history_from"): - min_created_at = datetime.strptime(self.request.GET.get("task_history_from"), "%Y-%m-%d") + return self.indemnification_error() else: - min_created_at = None - - if self.request.GET.get("task_history_to"): - max_created_at = datetime.strptime(self.request.GET.get("task_history_to"), "%Y-%m-%d") - else: - max_created_at = None - - task_history = scheduler.client.get_lazy_task_list( - scheduler_id=scheduler_id, - status=status, - min_created_at=min_created_at, - max_created_at=max_created_at, - task_type="boefje", - input_ooi=self.get_ooi_id(), - plugin_id=plugin_id, - ) - - return Paginator(task_history, self.task_history_limit).page(page) + clearance_level = int(self.request.POST.get("level")) + self.can_raise_clearance_level(self.ooi, clearance_level) # returns appropriate messages + + def answer_ooi_questions(self) -> None: + if not isinstance(self.ooi, Question): + messages.error(self.request, _("Only Question OOIs can be answered.")) + return + + schema_answer = self.request.POST.get("schema", "") + parsed_schema_answer = json.loads(schema_answer) + validator = Draft202012Validator(json.loads(self.ooi.json_schema)) + + if not validator.is_valid(parsed_schema_answer): + for error in validator.iter_errors(parsed_schema_answer): + messages.error(self.request, error.message) + return + + self.bytes_client.upload_raw(schema_answer, {"answer", f"{self.ooi.schema_id}"}, self.ooi.ooi) + messages.success(self.request, _("Question has been answered.")) + + def start_boefje_scan(self) -> None: + boefje_id = self.request.POST.get("boefje_id") + boefje = get_katalogus(self.organization.code).get_plugin(boefje_id) + ooi_id = self.request.GET.get("ooi_id") + ooi = self.get_single_ooi(pk=ooi_id) + self.run_boefje(boefje, ooi) + + def get_task_filters(self) -> dict[str, str | datetime | None]: + filters = super().get_task_filters() + filters["input_ooi"] = self.ooi.primary_key # shows only tasks for this particular ooi + return filters def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -156,7 +80,7 @@ def get_context_data(self, **kwargs): # List from katalogus boefjes = [] - if self.get_organization_indemnification(): + if self.indemnification_present: boefjes = get_enabled_boefjes_for_ooi_class(self.ooi.__class__, self.organization) if boefjes: @@ -184,6 +108,7 @@ def get_context_data(self, **kwargs): inference_origin_params.append((inference, inference_params_per_inference[inference.origin.id])) context["declarations"] = declarations + context["observations"] = observations context["inferences"] = inferences context["inference_origin_params"] = inference_origin_params @@ -192,26 +117,17 @@ def get_context_data(self, **kwargs): # TODO: generic solution to render ooi fields properly: https://github.com/minvws/nl-kat-coordination/issues/145 context["object_details"] = format_display(self.get_ooi_properties(self.ooi), ignore=["json_schema"]) context["ooi_types"] = self.get_ooi_types_input_values(self.ooi) - context["observed_at_form"] = self.get_connector_form() - context["observed_at"] = self.observed_at + context["is_question"] = isinstance(self.ooi, Question) context["ooi_past_due"] = context["observed_at"].date() < datetime.utcnow().date() context["related"] = self.get_related_objects(context["observed_at"]) - context["ooi_current"] = self.get_current_ooi() context["count_findings_per_severity"] = dict(self.count_findings_per_severity()) context["severity_summary_totals"] = sum(context["count_findings_per_severity"].values()) context["possible_boefjes_filter_form"] = filter_form - context["organization_indemnification"] = self.get_organization_indemnification() - context["task_history"] = self.get_task_history() - context["task_history_form_fields"] = [ - "task_history_from", - "task_history_to", - "task_history_status", - "task_history_search", - "task_history_page", - ] + context["organization_indemnification"] = self.indemnification_present + if self.request.GET.get("show_clearance_level_inheritance"): clearance_level_inheritance = self.get_scan_profile_inheritance(self.ooi) formatted_inheritance = [ diff --git a/rocky/rocky/views/ooi_detail_related_object.py b/rocky/rocky/views/ooi_detail_related_object.py index e34eeabc36b..356c189b9c4 100644 --- a/rocky/rocky/views/ooi_detail_related_object.py +++ b/rocky/rocky/views/ooi_detail_related_object.py @@ -3,7 +3,6 @@ from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import gettext_lazy as _ -from django.views.generic import TemplateView from tools.ooi_helpers import format_attr_name from tools.view_helpers import existing_ooi_type, get_mandatory_fields, url_with_querystring @@ -59,7 +58,7 @@ def get_finding_details(self) -> list[tuple[Finding, FindingType]]: return [(finding, self.tree.store[str(finding.finding_type)]) for finding in self.get_findings()] -class OOIRelatedObjectAddView(OOIRelatedObjectManager, TemplateView): +class OOIRelatedObjectAddView(OOIRelatedObjectManager): template_name = "oois/ooi_detail_add_related_object.html" def get(self, request, *args, **kwargs): diff --git a/rocky/rocky/views/ooi_findings.py b/rocky/rocky/views/ooi_findings.py index 8d7b73dd2e9..6b2ad33e41e 100644 --- a/rocky/rocky/views/ooi_findings.py +++ b/rocky/rocky/views/ooi_findings.py @@ -1,4 +1,5 @@ from django.utils.translation import gettext_lazy as _ +from django.views.generic import TemplateView from tools.forms.base import ObservedAtForm from tools.view_helpers import Breadcrumb, get_ooi_url @@ -6,7 +7,7 @@ from rocky.views.ooi_view import BaseOOIDetailView -class OOIFindingListView(OOIFindingManager, BaseOOIDetailView): +class OOIFindingListView(OOIFindingManager, BaseOOIDetailView, TemplateView): template_name = "oois/ooi_findings.html" connector_form_class = ObservedAtForm diff --git a/rocky/rocky/views/ooi_report.py b/rocky/rocky/views/ooi_report.py index 3b2c6e98823..23488c17314 100644 --- a/rocky/rocky/views/ooi_report.py +++ b/rocky/rocky/views/ooi_report.py @@ -7,6 +7,7 @@ from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import gettext_lazy as _ +from django.views.generic import TemplateView from katalogus.client import get_katalogus from tools.forms.ooi import OOIReportSettingsForm from tools.models import Organization @@ -36,7 +37,7 @@ from rocky.views.ooi_view import BaseOOIDetailView -class OOIReportView(BaseOOIDetailView): +class OOIReportView(BaseOOIDetailView, TemplateView): template_name = "oois/ooi_report.html" connector_form_class = OOIReportSettingsForm @@ -83,10 +84,16 @@ def get(self, request, *args, **kwargs): ), ) except GeneratingReportFailed: - messages.error(self.request, _("Generating report failed. See Keiko logs for more information.")) + messages.error( + self.request, + _("Generating report failed. See Keiko logs for more information."), + ) return redirect(get_ooi_url("ooi_report", ooi.primary_key, self.organization.code)) except ReportNotFoundException: - messages.error(self.request, _("Timeout reached generating report. See Keiko logs for more information.")) + messages.error( + self.request, + _("Timeout reached generating report. See Keiko logs for more information."), + ) return redirect(get_ooi_url("ooi_report", ooi.primary_key, self.organization.code)) return FileResponse( @@ -135,10 +142,16 @@ def get(self, request, *args, **kwargs): ), ) except GeneratingReportFailed: - messages.error(request, _("Generating report failed. See Keiko logs for more information.")) + messages.error( + request, + _("Generating report failed. See Keiko logs for more information."), + ) return redirect(reverse("finding_list", kwargs={"organization_code": self.organization.code})) except ReportNotFoundException: - messages.error(request, _("Timeout reached generating report. See Keiko logs for more information.")) + messages.error( + request, + _("Timeout reached generating report. See Keiko logs for more information."), + ) return redirect(reverse("finding_list", kwargs={"organization_code": self.organization.code})) return FileResponse( diff --git a/rocky/rocky/views/ooi_tree.py b/rocky/rocky/views/ooi_tree.py index 032abe8aa44..e943980581d 100644 --- a/rocky/rocky/views/ooi_tree.py +++ b/rocky/rocky/views/ooi_tree.py @@ -1,4 +1,5 @@ from django.utils.translation import gettext_lazy as _ +from django.views.generic import TemplateView from tools.forms.ooi import OoiTreeSettingsForm from tools.ooi_helpers import create_object_tree_item_from_ref, filter_ooi_tree, get_ooi_types_from_tree from tools.view_helpers import Breadcrumb, get_ooi_url @@ -6,7 +7,7 @@ from rocky.views.ooi_view import BaseOOIDetailView -class OOITreeView(BaseOOIDetailView): +class OOITreeView(BaseOOIDetailView, TemplateView): template_name = "oois/ooi_tree.html" connector_form_class = OoiTreeSettingsForm diff --git a/rocky/rocky/views/ooi_view.py b/rocky/rocky/views/ooi_view.py index d48205d9d91..c5e5050fb5d 100644 --- a/rocky/rocky/views/ooi_view.py +++ b/rocky/rocky/views/ooi_view.py @@ -1,12 +1,12 @@ from datetime import datetime, timezone from time import sleep -from typing import Any -from django import forms, http +from django import forms +from django.http import Http404 from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import gettext_lazy as _ -from django.views.generic import ListView, TemplateView +from django.views.generic import ListView from django.views.generic.edit import FormView from pydantic import ValidationError from tools.forms.base import BaseRockyForm, ObservedAtForm @@ -101,17 +101,33 @@ def get_context_data(self, **kwargs): return context -class BaseOOIDetailView(SingleOOITreeMixin, BreadcrumbsMixin, ConnectorFormMixin, TemplateView): - def get(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: +class BaseOOIDetailView(BreadcrumbsMixin, SingleOOITreeMixin, ConnectorFormMixin): + connector_form_class = ObservedAtForm + + def setup(self, request, *args, **kwargs): + super().setup(request, *args, **kwargs) self.ooi = self.get_ooi() - return super().get(request, *args, **kwargs) + + def get_current_ooi(self) -> OOI | None: + """ + Some OOIs have an old valid time, this will fetch the latest OOI for today. + """ + now = datetime.now(timezone.utc) + if self.observed_at.date() == now.date(): + return self.ooi + try: + return self.get_ooi(pk=self.get_ooi_id(), observed_at=now) + except Http404: + return None def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["ooi"] = self.ooi + context["ooi_current"] = self.get_current_ooi() context["mandatory_fields"] = get_mandatory_fields(self.request) context["observed_at"] = self.observed_at + context["observed_at_form"] = self.get_connector_form() return context @@ -165,8 +181,13 @@ def get_form_kwargs(self): def form_valid(self, form): # Transform into OOI try: - new_ooi = self.ooi_class.model_validate(form.cleaned_data) - create_ooi(self.octopoes_api_connector, self.bytes_client, new_ooi, datetime.now(timezone.utc)) + new_ooi = self.ooi_class.parse_obj(form.cleaned_data) + create_ooi( + self.octopoes_api_connector, + self.bytes_client, + new_ooi, + datetime.now(timezone.utc), + ) sleep(1) return redirect(self.get_ooi_success_url(new_ooi)) except ValidationError as exception: diff --git a/rocky/rocky/views/page_actions.py b/rocky/rocky/views/page_actions.py new file mode 100644 index 00000000000..2b007302aa6 --- /dev/null +++ b/rocky/rocky/views/page_actions.py @@ -0,0 +1,32 @@ +from enum import Enum +from typing import Any + +from django.contrib import messages +from django.http import HttpRequest, HttpResponse +from django.utils.translation import gettext_lazy as _ +from django.views.generic.edit import ProcessFormView + + +class PageActions(Enum): + START_SCAN = "start_scan" + SUBMIT_ANSWER = "submit_answer" + RESCHEDULE_TASK = "reschedule_task" + CHANGE_CLEARANCE_LEVEL = "change_clearance_level" + SCAN_OOIS = "scan_oois" + + +class PageActionsView(ProcessFormView): + def setup(self, request, *args, **kwargs): + super().setup(request, *args, **kwargs) + self.START_SCAN = PageActions.START_SCAN.value + self.SUBMIT_ANSWER = PageActions.SUBMIT_ANSWER.value + self.RESCHEDULE_TASK = PageActions.RESCHEDULE_TASK.value + self.CHANGE_CLEARANCE_LEVEL = PageActions.CHANGE_CLEARANCE_LEVEL.value + self.SCAN_OOIS = PageActions.SCAN_OOIS.value + self.action = request.POST.get("action") + + def post(self, request: HttpRequest, *args: str, **kwargs: Any) -> HttpResponse: + if not self.action or self.action is None: + messages.error(self.request, _("Could not process your request, action required.")) + + return self.get(request, *args, **kwargs) diff --git a/rocky/rocky/views/scan_profile.py b/rocky/rocky/views/scan_profile.py index 0df282c530b..0be16e7e67b 100644 --- a/rocky/rocky/views/scan_profile.py +++ b/rocky/rocky/views/scan_profile.py @@ -6,23 +6,19 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic import FormView from tools.forms.ooi import SetClearanceLevelForm -from tools.models import Indemnification from tools.view_helpers import Breadcrumb, get_mandatory_fields, get_ooi_url from octopoes.models import EmptyScanProfile, InheritedScanProfile from rocky.views.ooi_detail import OOIDetailView -class ScanProfileDetailView(OOIDetailView, FormView): +class ScanProfileDetailView(FormView, OOIDetailView): template_name = "scan_profiles/scan_profile_detail.html" form_class = SetClearanceLevelForm def get_context_data(self, **kwargs) -> dict[str, Any]: context = super().get_context_data(**kwargs) context["mandatory_fields"] = get_mandatory_fields(self.request) - context["organization_indemnification"] = Indemnification.objects.filter( - organization=self.organization - ).exists() return context def get_initial(self): diff --git a/rocky/rocky/views/scheduler.py b/rocky/rocky/views/scheduler.py new file mode 100644 index 00000000000..3378fc361b6 --- /dev/null +++ b/rocky/rocky/views/scheduler.py @@ -0,0 +1,190 @@ +from datetime import datetime +from typing import Any + +from django.contrib import messages +from django.http import JsonResponse +from django.utils.translation import gettext_lazy as _ +from katalogus.client import Boefje, Normalizer +from tools.forms.scheduler import TaskFilterForm + +from octopoes.models import OOI +from rocky.scheduler import Boefje as SchedulerBoefje +from rocky.scheduler import ( + BoefjeTask, + LazyTaskList, + NormalizerTask, + PrioritizedItem, + RawData, + SchedulerError, + Task, + scheduler_client, +) +from rocky.scheduler import Normalizer as SchedulerNormalizer +from rocky.views.mixins import OctopoesView + + +def get_date_time(date: str | None) -> datetime | None: + if date: + return datetime.strptime(date, "%Y-%m-%d") + return None + + +class SchedulerView(OctopoesView): + task_type: str + task_filter_form = TaskFilterForm + + def setup(self, request, *args, **kwargs): + super().setup(request, *args, **kwargs) + self.scheduler_client = scheduler_client(self.organization.code) + + def get_task_filters(self) -> dict[str, Any]: + return { + "scheduler_id": f"{self.task_type}-{self.organization.code}", + "task_type": self.task_type, + "plugin_id": None, # plugin_id present and set at plugin detail + **self.get_form_data(), + } + + def get_form_data(self) -> dict[str, Any]: + form_data = self.get_task_filter_form().data.dict() + return {k: v for k, v in form_data.items() if v} + + def get_task_filter_form(self) -> TaskFilterForm: + return self.task_filter_form(self.request.GET) + + def get_task_list(self) -> LazyTaskList | list[Any]: + try: + return LazyTaskList(self.scheduler_client, **self.get_task_filters()) + except SchedulerError as error: + messages.error(self.request, error.message) + return [] + + def get_task_details(self, task_id: str) -> Task | None: + try: + return self.scheduler_client.get_task_details(task_id) + except SchedulerError as error: + return messages.error(self.request, error.message) + + def get_task_statistics(self) -> dict[Any, Any]: + stats = {} + try: + stats = self.scheduler_client.get_task_stats(self.task_type) + except SchedulerError as error: + messages.error(self.request, error.message) + return stats + + def get_output_oois(self, task): + try: + return self.octopoes_api_connector.list_origins( + valid_time=task.p_item.data.raw_data.boefje_meta.ended_at, + task_id=task.id, + )[0].result + except IndexError: + return [] + except SchedulerError as error: + messages.error(self.request, error.message) + return [] + + def get_json_task_details(self) -> JsonResponse | None: + try: + task = self.get_task_details(self.kwargs["task_id"]) + if task: + return JsonResponse( + { + "oois": self.get_output_oois(task), + "valid_time": task.p_item.data.raw_data.boefje_meta.ended_at.strftime("%Y-%m-%dT%H:%M:%S"), + }, + safe=False, + ) + return task + except SchedulerError as error: + return messages.error(self.request, error.message) + + def schedule_task(self, p_item: PrioritizedItem) -> None: + if not self.indemnification_present: + return self.indemnification_error() + try: + # Remove id attribute of both p_item and p_item.data, since the + # scheduler will create a new task with new id's. However, pydantic + # requires an id attribute to be present in its definition and the + # default set to None when the attribute is optional, otherwise it + # will not serialize the id if it is not present in the definition. + if hasattr(p_item, "id"): + delattr(p_item, "id") + + if hasattr(p_item.data, "id"): + delattr(p_item.data, "id") + + self.scheduler_client.push_task(p_item) + + except SchedulerError as error: + messages.error(self.request, error.message) + else: + messages.success( + self.request, + _( + "Your task is scheduled and will soon be started in the background. " + "Results will be added to the object list when they are in. " + "It may take some time, a refresh of the page may be needed to show the results." + ), + ) + + # FIXME: Tasks should be (re)created with supplied data, not by fetching prior + # task info from the scheduler. Task data should be available from the context + # from which the task is created. + def reschedule_task(self, task_id: str) -> None: + try: + task = self.scheduler_client.get_task_details(task_id) + + new_p_item = PrioritizedItem( + data=task.p_item.data, + priority=1, + ) + + self.schedule_task(new_p_item) + except SchedulerError as error: + messages.error(self.request, error.message) + + def run_normalizer(self, katalogus_normalizer: Normalizer, raw_data: RawData) -> None: + try: + normalizer_task = NormalizerTask( + normalizer=SchedulerNormalizer.model_validate(katalogus_normalizer.model_dump()), + raw_data=raw_data, + ) + + p_item = PrioritizedItem(priority=1, data=normalizer_task) + + self.schedule_task(p_item) + except SchedulerError as error: + messages.error(self.request, error.message) + + def run_boefje(self, katalogus_boefje: Boefje, ooi: OOI | None) -> None: + try: + boefje_task = BoefjeTask( + boefje=SchedulerBoefje.model_validate(katalogus_boefje.model_dump()), + input_ooi=ooi.reference if ooi else None, + organization=self.organization.code, + ) + + p_item = PrioritizedItem(priority=1, data=boefje_task) + + self.schedule_task(p_item) + + except SchedulerError as error: + messages.error(self.request, error.message) + + def run_boefje_for_oois( + self, + boefje: Boefje, + oois: list[OOI], + ) -> None: + try: + if not oois and not boefje.consumes: + self.run_boefje(boefje, None) + + for ooi in oois: + if ooi.scan_profile and ooi.scan_profile.level < boefje.scan_level: + self.can_raise_clearance_level(ooi, boefje.scan_level) + self.run_boefje(boefje, ooi) + except SchedulerError as error: + messages.error(self.request, error.message) diff --git a/rocky/rocky/views/task_detail.py b/rocky/rocky/views/task_detail.py index d46de98121a..db08b03317d 100644 --- a/rocky/rocky/views/task_detail.py +++ b/rocky/rocky/views/task_detail.py @@ -1,32 +1,41 @@ from django.contrib import messages -from django.http import JsonResponse +from django.http import FileResponse, HttpResponse, JsonResponse +from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import gettext_lazy as _ from django.views.generic import TemplateView -from katalogus.views.mixins import BoefjeMixin, NormalizerMixin -from rocky.scheduler import TaskNotFoundError, client -from rocky.views.mixins import OctopoesView +from rocky.scheduler import SchedulerError +from rocky.views.tasks import SchedulerView -class TaskDetailView(OctopoesView, TemplateView): - def get_task(self, task_id): - try: - return client.get_task_details(self.organization.code, task_id) - except TaskNotFoundError as error: - messages.error(self.request, error.message) +class DownloadTaskDetail(SchedulerView): + def get(self, request, *args, **kwargs): + task_id = kwargs["task_id"] + filename = "task_" + task_id + ".json" + task_details = self.get_task_details(task_id) + if task_details is not None: + response = HttpResponse(FileResponse(task_details.json()), content_type="application/json") + response["Content-Disposition"] = "attachment; filename=" + filename + return response + return redirect(reverse("task_list", kwargs={"organization_code": self.organization.code})) + + +class TaskDetailView(SchedulerView, TemplateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["task_id"] = kwargs["task_id"] - context["task"] = self.get_task(context["task_id"]) + try: + context["task"] = self.get_task_details(context["task_id"]) + except SchedulerError as error: + messages.error(self.request, error.message) return context -class BoefjeTaskDetailView(BoefjeMixin, TaskDetailView): +class BoefjeTaskDetailView(TaskDetailView): template_name = "tasks/boefje_task_detail.html" - plugin_type = "boefje" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -48,24 +57,11 @@ def get_context_data(self, **kwargs): return context -class NormalizerTaskJSONView(NormalizerMixin, TaskDetailView): +class NormalizerTaskJSONView(TaskDetailView): plugin_type = "normalizer" - def get_output_oois(self, task): - try: - return self.octopoes_api_connector.list_origins( - valid_time=task.p_item.data.raw_data.boefje_meta.ended_at, task_id=task.id - )[0].result - except IndexError: - return [] - - def get(self, request, *args, **kwargs): - task_id = kwargs["task_id"] - task = self.get_task(task_id) - return JsonResponse( - { - "oois": self.get_output_oois(task), - "valid_time": task.p_item.data.raw_data.boefje_meta.ended_at.strftime("%Y-%m-%dT%H:%M:%S"), - }, - safe=False, - ) + def get(self, request, *args, **kwargs) -> JsonResponse | HttpResponse: + task = self.get_json_task_details() + if task is not None: + return task + return super().get(request, *args, **kwargs) diff --git a/rocky/rocky/views/tasks.py b/rocky/rocky/views/tasks.py index 897f89eec5f..8099d037496 100644 --- a/rocky/rocky/views/tasks.py +++ b/rocky/rocky/views/tasks.py @@ -1,117 +1,64 @@ -from datetime import datetime -from enum import Enum +from typing import Any -from account.mixins import OrganizationView from django.contrib import messages -from django.http import FileResponse, HttpResponse -from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import gettext_lazy as _ from django.views.generic.list import ListView from httpx import HTTPError -from katalogus.views.mixins import BoefjeMixin, NormalizerMixin -from tools.view_helpers import reschedule_task from rocky.paginator import RockyPaginator -from rocky.scheduler import SchedulerError, TaskNotFoundError, client +from rocky.scheduler import SchedulerError +from rocky.views.page_actions import PageActionsView +from rocky.views.scheduler import SchedulerView -class PageActions(Enum): - RESCHEDULE_TASK = "reschedule_task" - - -class DownloadTaskDetail(OrganizationView): - def get(self, request, *args, **kwargs): +class SchedulerListView(ListView): + def get_context_data(self, **kwargs: Any) -> dict[str, Any]: try: - task_id = kwargs["task_id"] - filename = "task_" + task_id + ".json" - task_details = client.get_task_details(self.organization.code, task_id) - response = HttpResponse(FileResponse(task_details.json()), content_type="application/json") - response["Content-Disposition"] = "attachment; filename=" + filename - return response - except TaskNotFoundError as error: + return super().get_context_data(**kwargs) + except SchedulerError as error: messages.error(self.request, error.message) - return redirect(reverse("task_list", kwargs={"organization_code": self.organization.code})) + return {} -class TaskListView(OrganizationView, ListView): - paginate_by = 20 +class TaskListView(SchedulerView, SchedulerListView, PageActionsView): paginator_class = RockyPaginator + paginate_by = 20 + context_object_name = "task_list" def get_queryset(self): - scheduler_id = self.plugin_type + "-" + self.organization.code - task_type = self.request.GET.get("type", self.plugin_type) - - status = self.request.GET.get("scan_history_status") if self.request.GET.get("scan_history_status") else None - - input_ooi = self.request.GET.get("scan_history_search") if self.request.GET.get("scan_history_search") else None - - if self.request.GET.get("scan_history_from"): - min_created_at = datetime.strptime(self.request.GET.get("scan_history_from"), "%Y-%m-%d") - else: - min_created_at = None - - if self.request.GET.get("scan_history_to"): - max_created_at = datetime.strptime(self.request.GET.get("scan_history_to"), "%Y-%m-%d") - else: - max_created_at = None - - try: - return client.get_lazy_task_list( - scheduler_id=scheduler_id, - task_type=task_type, - status=status, - min_created_at=min_created_at, - max_created_at=max_created_at, - input_ooi=input_ooi, - ) - - except HTTPError: - error_message = _("Fetching tasks failed: no connection with scheduler") - messages.add_message(self.request, messages.ERROR, error_message) - return [] + return self.get_task_list() def post(self, request, *args, **kwargs): - self.handle_page_action(request.POST["action"]) - - return redirect(request.path) - - def handle_page_action(self, action: str) -> None: - if action == PageActions.RESCHEDULE_TASK.value: - task_id = self.request.POST.get("task_id") - reschedule_task(self.request, self.organization.code, task_id) + try: + if self.action == self.RESCHEDULE_TASK: + task_id = self.request.POST.get("task_id", "") + self.reschedule_task(task_id) + except HTTPError as exc: + message = f"HTTP error for {exc.request.url} - {exc}" + messages.error(request, message) + except SchedulerError as error: + messages.error(request, error.message) + return super().post(request, *args, **kwargs) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - try: - context["stats"] = client.get_task_stats(self.organization.code, self.plugin_type) - except SchedulerError: - context["stats_error"] = True - else: - context["stats_error"] = False + context["task_filter_form"] = self.get_task_filter_form() + context["stats"] = self.get_task_statistics() context["breadcrumbs"] = [ - {"url": reverse("task_list", kwargs={"organization_code": self.organization.code}), "text": _("Tasks")}, + { + "url": reverse("task_list", kwargs={"organization_code": self.organization.code}), + "text": _("Tasks"), + }, ] return context -class BoefjesTaskListView(BoefjeMixin, TaskListView): +class BoefjesTaskListView(TaskListView): template_name = "tasks/boefjes.html" - plugin_type = "boefje" + task_type = "boefje" -class NormalizersTaskListView(NormalizerMixin, TaskListView): +class NormalizersTaskListView(TaskListView): template_name = "tasks/normalizers.html" - plugin_type = "normalizer" - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - - context["breadcrumbs"] = [ - { - "url": reverse("task_list", kwargs={"organization_code": self.organization.code}), - "text": _("Tasks"), - }, - ] - - return context + task_type = "normalizer" diff --git a/rocky/tests/conftest.py b/rocky/tests/conftest.py index bb40b78a974..14ee2f7b6de 100644 --- a/rocky/tests/conftest.py +++ b/rocky/tests/conftest.py @@ -39,7 +39,7 @@ from octopoes.models.transaction import TransactionRecord from octopoes.models.tree import ReferenceTree from octopoes.models.types import OOIType -from rocky.scheduler import Task +from rocky.scheduler import PaginatedTasksResponse, Task LANG_LIST = [code for code, _ in settings.LANGUAGES] @@ -159,14 +159,24 @@ def organization_b(): @pytest.fixture def superuser(django_user_model): return create_user( - django_user_model, "superuser@openkat.nl", "SuperSuper123!!", "Superuser name", "default", superuser=True + django_user_model, + "superuser@openkat.nl", + "SuperSuper123!!", + "Superuser name", + "default", + superuser=True, ) @pytest.fixture def superuser_b(django_user_model): return create_user( - django_user_model, "superuserB@openkat.nl", "SuperBSuperB123!!", "Superuser B name", "default_b", superuser=True + django_user_model, + "superuserB@openkat.nl", + "SuperBSuperB123!!", + "Superuser B name", + "default_b", + superuser=True, ) @@ -182,12 +192,24 @@ def superuser_member_b(superuser_b, organization_b): @pytest.fixture def adminuser(django_user_model): - return create_user(django_user_model, "admin@openkat.nl", "AdminAdmin123!!", "Admin name", "default_admin") + return create_user( + django_user_model, + "admin@openkat.nl", + "AdminAdmin123!!", + "Admin name", + "default_admin", + ) @pytest.fixture def adminuser_b(django_user_model): - return create_user(django_user_model, "adminB@openkat.nl", "AdminBAdminB123!!", "Admin B name", "default_admin_b") + return create_user( + django_user_model, + "adminB@openkat.nl", + "AdminBAdminB123!!", + "Admin B name", + "default_admin_b", + ) @pytest.fixture @@ -209,14 +231,22 @@ def admin_member_b(adminuser_b, organization_b): @pytest.fixture def redteamuser(django_user_model): return create_user( - django_user_model, "redteamer@openkat.nl", "RedteamRedteam123!!", "Redteam name", "default_redteam" + django_user_model, + "redteamer@openkat.nl", + "RedteamRedteam123!!", + "Redteam name", + "default_redteam", ) @pytest.fixture def redteamuser_b(django_user_model): return create_user( - django_user_model, "redteamerB@openkat.nl", "RedteamBRedteamB123!!", "Redteam B name", "default_redteam_b" + django_user_model, + "redteamerB@openkat.nl", + "RedteamBRedteamB123!!", + "Redteam B name", + "default_redteam_b", ) @@ -236,13 +266,23 @@ def redteam_member_b(redteamuser_b, organization_b): @pytest.fixture def clientuser(django_user_model): - return create_user(django_user_model, "client@openkat.nl", "ClientClient123!!", "Client name", "default_client") + return create_user( + django_user_model, + "client@openkat.nl", + "ClientClient123!!", + "Client name", + "default_client", + ) @pytest.fixture def clientuser_b(django_user_model): return create_user( - django_user_model, "clientB@openkat.nl", "ClientBClientB123!!", "Client B name", "default_client_b" + django_user_model, + "clientB@openkat.nl", + "ClientBClientB123!!", + "Client B name", + "default_client_b", ) @@ -271,7 +311,13 @@ def client_user_two_organizations(clientuser, organization, organization_b): @pytest.fixture def new_member(django_user_model, organization): - user = create_user(django_user_model, "cl1@openkat.nl", "TestTest123!!", "New user", "default_new_user") + user = create_user( + django_user_model, + "cl1@openkat.nl", + "TestTest123!!", + "New user", + "default_new_user", + ) member = create_member(user, organization) member.status = OrganizationMember.STATUSES.NEW member.save() @@ -280,7 +326,13 @@ def new_member(django_user_model, organization): @pytest.fixture def active_member(django_user_model, organization): - user = create_user(django_user_model, "cl2@openkat.nl", "TestTest123!!", "Active user", "default_active_user") + user = create_user( + django_user_model, + "cl2@openkat.nl", + "TestTest123!!", + "Active user", + "default_active_user", + ) member = create_member(user, organization) member.status = OrganizationMember.STATUSES.ACTIVE member.save() @@ -289,7 +341,13 @@ def active_member(django_user_model, organization): @pytest.fixture def blocked_member(django_user_model, organization): - user = create_user(django_user_model, "cl3@openkat.nl", "TestTest123!!", "Blocked user", "default_blocked_user") + user = create_user( + django_user_model, + "cl3@openkat.nl", + "TestTest123!!", + "Blocked user", + "default_blocked_user", + ) member = create_member(user, organization) member.status = OrganizationMember.STATUSES.ACTIVE member.blocked = True @@ -446,7 +504,9 @@ def network() -> Network: def url(network) -> URL: return URL( scan_profile=DeclaredScanProfile( - scan_profile_type="declared", reference=Reference("URL|testnetwork|http://example.com/"), level=ScanLevel.L1 + scan_profile_type="declared", + reference=Reference("URL|testnetwork|http://example.com/"), + level=ScanLevel.L1, ), primary_key="URL|testnetwork|http://example.com/", network=network.reference, @@ -1297,7 +1357,7 @@ def setup_request(request, user): @pytest.fixture def mock_scheduler(mocker): - return mocker.patch("rocky.views.ooi_detail.scheduler.client") + return mocker.patch("rocky.views.scheduler.scheduler_client")() def get_stub_path(file_name: str) -> Path: @@ -1322,8 +1382,8 @@ def mock_mixins_katalogus(mocker): @pytest.fixture -def mock_scheduler_client_task_list(mocker): - mock_scheduler_client_session = mocker.patch("rocky.scheduler.client._client") +def mock_scheduler_client_task_list(mock_scheduler): + mock_scheduler_session = mock_scheduler._client response = Response( 200, content=( @@ -1362,9 +1422,9 @@ def mock_scheduler_client_task_list(mocker): ), ) - mock_scheduler_client_session.get.return_value = response + mock_scheduler_session.get.return_value = response - return mock_scheduler_client_session + return mock_scheduler_session class MockOctopoesAPIConnector: @@ -1379,7 +1439,11 @@ def get(self, reference: Reference, valid_time: datetime | None = None) -> OOI: return self.oois[reference] def get_tree( - self, reference: Reference, valid_time: datetime, types: set = frozenset(), depth: int = 1 + self, + reference: Reference, + valid_time: datetime, + types: set = frozenset(), + depth: int = 1, ) -> ReferenceTree: return self.tree[reference] @@ -1457,6 +1521,16 @@ def listed_hostnames(network) -> list[Hostname]: ] +@pytest.fixture +def paginated_task_list(task): + return PaginatedTasksResponse( + count=1, + next="", + previous=None, + results=[task], + ) + + @pytest.fixture def reports_more_input_oois(): return [ diff --git a/rocky/tests/integration/test_bench.py b/rocky/tests/integration/test_bench.py index d8c722c33f5..9c55e172631 100644 --- a/rocky/tests/integration/test_bench.py +++ b/rocky/tests/integration/test_bench.py @@ -7,7 +7,7 @@ @pytest.mark.slow -def test_aggregate_report_benchmark(octopoes_api_connector, valid_time): +def test_aggregate_report_benchmark(octopoes_api_connector, valid_time, organization): hostname_range = range(0, 20) for x in hostname_range: seed_system( @@ -26,6 +26,7 @@ def test_aggregate_report_benchmark(octopoes_api_connector, valid_time): [Hostname(name=f"{x}.com", network=Network(name="test").reference) for x in hostname_range], reports, valid_time, + organization.code, ) assert data["systems"] diff --git a/rocky/tests/integration/test_reports.py b/rocky/tests/integration/test_reports.py index d18bf7acbbb..44b49a5c7a9 100644 --- a/rocky/tests/integration/test_reports.py +++ b/rocky/tests/integration/test_reports.py @@ -93,14 +93,14 @@ def test_system_report(octopoes_api_connector: OctopoesAPIConnector, valid_time) } -def test_aggregate_report(octopoes_api_connector: OctopoesAPIConnector, valid_time, hostname_oois): +def test_aggregate_report(octopoes_api_connector: OctopoesAPIConnector, valid_time, hostname_oois, organization): seed_system(octopoes_api_connector, valid_time) reports: list[type[Report] | type[MultiReport]] = ( AggregateOrganisationReport.reports["required"] + AggregateOrganisationReport.reports["optional"] ) report_ids = [report_type.id for report_type in reports] - _, data, _, _ = aggregate_reports(octopoes_api_connector, hostname_oois, report_ids, valid_time) + _, data, _, _ = aggregate_reports(octopoes_api_connector, hostname_oois, report_ids, valid_time, organization.code) v4_test_hostnames = [ "Hostname|test|a.example.com", @@ -245,14 +245,19 @@ def test_multi_report( octopoes_api_connector_2: OctopoesAPIConnector, valid_time, hostname_oois, + organization, ): seed_system(octopoes_api_connector, valid_time) seed_system(octopoes_api_connector_2, valid_time) reports = AggregateOrganisationReport.reports["required"] + AggregateOrganisationReport.reports["optional"] report_ids = [report_type.id for report_type in reports] - _, data, report_data, _ = aggregate_reports(octopoes_api_connector, hostname_oois, report_ids, valid_time) - _, data_2, report_data_2, _ = aggregate_reports(octopoes_api_connector_2, hostname_oois, report_ids, valid_time) + _, data, report_data, _ = aggregate_reports( + octopoes_api_connector, hostname_oois, report_ids, valid_time, organization.code + ) + _, data_2, report_data_2, _ = aggregate_reports( + octopoes_api_connector_2, hostname_oois, report_ids, valid_time, organization.code + ) report_data_object = ReportData( organization_code=octopoes_api_connector.client, diff --git a/rocky/tests/katalogus/test_katalogus_plugin_detail.py b/rocky/tests/katalogus/test_katalogus_plugin_detail.py index 03d717aa88f..1585f32f436 100644 --- a/rocky/tests/katalogus/test_katalogus_plugin_detail.py +++ b/rocky/tests/katalogus/test_katalogus_plugin_detail.py @@ -22,7 +22,9 @@ def test_plugin_detail_view( ) assertContains(response, "TestBoefje") - assertContains(response, "Completed") + assertContains(response, "Produces") + assertContains(response, "Tasks") + assertContains(response, "Object list") assertContains(response, "Consumes") assertContains(response, plugin_details.description) diff --git a/rocky/tests/objects/test_objects_detail.py b/rocky/tests/objects/test_objects_detail.py index 89e5509ab2f..71d5d4d63a1 100644 --- a/rocky/tests/objects/test_objects_detail.py +++ b/rocky/tests/objects/test_objects_detail.py @@ -1,7 +1,6 @@ from urllib.parse import urlencode import pytest -from django.http import HttpResponseRedirect from katalogus.client import Boefje from pytest_django.asserts import assertContains, assertNotContains from tools.enums import SCAN_LEVEL @@ -56,29 +55,31 @@ def test_ooi_detail( rf, client_member, - mock_scheduler, mock_organization_view_octopoes, - lazy_task_list_with_boefje, + mock_scheduler, + paginated_task_list, mocker, ): mocker.patch("katalogus.client.KATalogusClientV1") - request = setup_request(rf.get("ooi_detail", {"ooi_id": "Network|testnetwork"}), client_member.user) - mock_organization_view_octopoes().get_tree.return_value = ReferenceTree.model_validate(TREE_DATA) - mock_scheduler.get_lazy_task_list.return_value = lazy_task_list_with_boefje + + mock_scheduler.list_tasks.return_value = paginated_task_list + + request = setup_request(rf.get("ooi_detail", {"ooi_id": "Network|testnetwork"}), client_member.user) response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code) assert response.status_code == 200 assert mock_organization_view_octopoes().get_tree.call_count == 2 assertContains(response, "Object") - assertContains(response, "Hostname|internet|mispo.es") + assertContains(response, "Network|testnetwork") assertContains(response, "Plugin") - assertContains(response, "test-boefje") + assertContains(response, "TestBoefje") assertContains( - response, f'href="/en/{client_member.organization.code}/kat-alogus/plugins/boefje/test-boefje/">TestBoefje' + response, + f'href="/en/{client_member.organization.code}/kat-alogus/plugins/boefje/test-boefje/">TestBoefje', ) assertContains(response, "Status") assertContains(response, "Completed") @@ -91,17 +92,19 @@ def test_ooi_detail( def test_question_detail( rf, client_member, - mock_scheduler, mock_organization_view_octopoes, - lazy_task_list_with_boefje, + mock_scheduler, + paginated_task_list, mocker, ): mocker.patch("katalogus.client.KATalogusClientV1") - request = setup_request(rf.get("ooi_detail", {"ooi_id": "Question|/test|Network|testnetwork"}), client_member.user) + request = setup_request( + rf.get("ooi_detail", {"ooi_id": "Question|/test|Network|testnetwork"}), + client_member.user, + ) mock_organization_view_octopoes().get_tree.return_value = ReferenceTree.model_validate(QUESTION_DATA) - mock_scheduler.get_lazy_task_list.return_value = lazy_task_list_with_boefje response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code) @@ -124,7 +127,6 @@ def test_answer_question( ): mocker.patch("katalogus.client.KATalogusClientV1") mock_organization_view_octopoes().get_tree.return_value = ReferenceTree.model_validate(QUESTION_DATA) - mock_scheduler.get_lazy_task_list.return_value = lazy_task_list_with_boefje query_string = urlencode({"ooi_id": "Question|/test|Network|testnetwork"}, doseq=True) request = setup_request( @@ -139,8 +141,8 @@ def test_answer_question( ) response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code) - assertContains(response, "Question has been answered.", status_code=201) - assert mock_organization_view_octopoes().get_tree.call_count == 3 + assertContains(response, "Question has been answered.", status_code=200) + assert mock_organization_view_octopoes().get_tree.call_count == 2 def test_answer_question_bad_schema( @@ -154,7 +156,6 @@ def test_answer_question_bad_schema( ): mocker.patch("katalogus.client.KATalogusClientV1") mock_organization_view_octopoes().get_tree.return_value = ReferenceTree.model_validate(QUESTION_DATA) - mock_scheduler.get_lazy_task_list.return_value = lazy_task_list_with_boefje query_string = urlencode({"ooi_id": "Question|/test|Network|testnetwork"}, doseq=True) @@ -170,24 +171,26 @@ def test_answer_question_bad_schema( ) response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 422 + assert response.status_code == 200 quote_enc = "'" - assertContains(response, f"314159 is not of type {quote_enc}string{quote_enc}", status_code=422) + assertContains(response, f"314159 is not of type {quote_enc}string{quote_enc}", status_code=200) def test_ooi_detail_start_scan( rf, client_member, mock_organization_view_octopoes, + mock_scheduler, + paginated_task_list, mocker, network, ): mock_katalogus = mocker.patch("katalogus.client.KATalogusClientV1") - mocker.patch("katalogus.views.mixins.schedule_task") mock_organization_view_octopoes().get_tree.return_value = ReferenceTree.model_validate(TREE_DATA) mock_organization_view_octopoes().get.return_value = network + mock_katalogus().get_plugin.return_value = Boefje( id="nmap", name="", @@ -214,18 +217,17 @@ def test_ooi_detail_start_scan( ) response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code) - assert mock_organization_view_octopoes().get_tree.call_count == 1 - assert isinstance(response, HttpResponseRedirect) - assert response.status_code == 302 - assert response.url == f"/en/{client_member.organization.code}/tasks/" + assert mock_organization_view_octopoes().get_tree.call_count == 2 + + assert response.status_code == 200 def test_ooi_detail_start_scan_no_indemnification( rf, client_member, - mock_scheduler, mock_organization_view_octopoes, - lazy_task_list_with_boefje, + mock_scheduler, + paginated_task_list, mocker, network, ): @@ -233,6 +235,17 @@ def test_ooi_detail_start_scan_no_indemnification( mock_organization_view_octopoes().get_tree.return_value = ReferenceTree.model_validate(TREE_DATA) mock_organization_view_octopoes().get.return_value = network + mock_katalogus = mocker.patch("katalogus.client.KATalogusClientV1") + mock_katalogus().get_plugin.return_value = Boefje( + id="nmap", + name="", + description="", + enabled=True, + type="boefje", + scan_level=SCAN_LEVEL.L2, + consumes=[], + produces=[], + ) Indemnification.objects.get(user=client_member.user).delete() @@ -242,7 +255,7 @@ def test_ooi_detail_start_scan_no_indemnification( rf.post( f"/en/{client_member.organization.code}/objects/details/?{query_string}", data={ - "boefje_id": "nmap", + "boefje_id": "test-boefje", "action": "start_scan", }, ), @@ -251,8 +264,8 @@ def test_ooi_detail_start_scan_no_indemnification( response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code) assert mock_organization_view_octopoes().get_tree.call_count == 2 - assertContains(response, "Object details", status_code=403) - assertContains(response, "Indemnification not present", status_code=403) + assertContains(response, "Object details") + assertContains(response, "Indemnification not present") def test_ooi_detail_start_scan_no_action( @@ -283,7 +296,7 @@ def test_ooi_detail_start_scan_no_action( response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code) assert mock_organization_view_octopoes().get_tree.call_count == 2 - assertContains(response, "Object details", status_code=404) + assertContains(response, "Object details") @pytest.mark.parametrize("member", ["superuser_member", "admin_member", "redteam_member"]) diff --git a/rocky/tests/objects/test_objects_findings.py b/rocky/tests/objects/test_objects_findings.py index 1f60f08c5ac..c0d9dcaadcf 100644 --- a/rocky/tests/objects/test_objects_findings.py +++ b/rocky/tests/objects/test_objects_findings.py @@ -109,7 +109,10 @@ def test_mute_finding_button_is_not_visible_without_perms( def test_mute_finding_form_view(request, member, rf, mock_organization_view_octopoes): member = request.getfixturevalue(member) response = MuteFindingView.as_view()( - setup_request(rf.get("finding_mute", {"ooi_id": "Finding|Network|testnetwork|KAT-000"}), member.user), + setup_request( + rf.get("finding_mute", {"ooi_id": "Finding|Network|testnetwork|KAT-000"}), + member.user, + ), organization_code=member.organization.code, ) @@ -126,13 +129,12 @@ def test_mute_finding_form_view_no_perms(request, member, rf, mock_organization_ member = request.getfixturevalue(member) with pytest.raises(PermissionDenied): MuteFindingView.as_view()( - setup_request(rf.get("finding_mute", {"ooi_id": "Finding|Network|testnetwork|KAT-000"}), member.user), + setup_request( + rf.get("finding_mute", {"ooi_id": "Finding|Network|testnetwork|KAT-000"}), + member.user, + ), organization_code=member.organization.code, ) - with pytest.raises(PermissionDenied): - MuteFindingView.as_view()( - setup_request(rf.post("finding_mute"), member.user), organization_code=member.organization.code - ) def test_mute_finding_post( @@ -159,7 +161,9 @@ def test_mute_finding_post( ) # Uses same ooi_add post request to add a MuteFinding object response = OOIAddView.as_view()( - request, organization_code=redteam_member.organization.code, ooi_type="MutedFinding" + request, + organization_code=redteam_member.organization.code, + ooi_type="MutedFinding", ) # Redirects to ooi_detail @@ -253,8 +257,16 @@ def test_muted_finding_button_presence_more_findings_and_post( ) assert response.status_code == 200 - assertContains(response, '', html=True) - assertContains(response, '', html=True) + assertContains( + response, + '', + html=True, + ) + assertContains( + response, + '', + html=True, + ) assertContains(response, '') request = setup_request( diff --git a/rocky/tests/objects/test_objects_scan_profile.py b/rocky/tests/objects/test_objects_scan_profile.py index 2534971b477..1c2f6fa5aaa 100644 --- a/rocky/tests/objects/test_objects_scan_profile.py +++ b/rocky/tests/objects/test_objects_scan_profile.py @@ -10,7 +10,14 @@ TREE_DATA = { "root": { "reference": "Network|testnetwork", - "children": {"urls": [{"reference": "HostnameHTTPURL|https|internet|scanme.org|443|/", "children": {}}]}, + "children": { + "urls": [ + { + "reference": "HostnameHTTPURL|https|internet|scanme.org|443|/", + "children": {}, + } + ] + }, }, "store": { "Network|testnetwork": { @@ -45,7 +52,10 @@ def test_scan_profile(rf, redteam_member, mock_scheduler, mock_organization_view mocker.patch("katalogus.utils.get_katalogus") mock_organization_view_octopoes().get_tree.return_value = ReferenceTree.model_validate(TREE_DATA) - request = setup_request(rf.get("scan_profile_detail", {"ooi_id": "Network|testnetwork"}), redteam_member.user) + request = setup_request( + rf.get("scan_profile_detail", {"ooi_id": "Network|testnetwork"}), + redteam_member.user, + ) response = ScanProfileDetailView.as_view()(request, organization_code=redteam_member.organization.code) assert response.status_code == 200 @@ -84,12 +94,19 @@ def test_scan_profile_submit_no_indemnification( # Passing query params in POST requests is not well-supported for RequestFactory it seems, hence the absolute path query_string = urlencode({"ooi_id": "Network|testnetwork"}, doseq=True) request = setup_request( - rf.post(f"/en/{redteam_member.organization.code}/objects/scan-profile/?{query_string}", data={"level": "L1"}), + rf.post( + f"/en/{redteam_member.organization.code}/objects/scan-profile/?{query_string}", + data={"level": "1", "action": "change_clearance_level"}, + ), redteam_member.user, ) response = ScanProfileDetailView.as_view()(request, organization_code=redteam_member.organization.code) - assert response.status_code == 403 + assert response.status_code == 200 + assertContains( + response, + "Indemnification not present at organization " + redteam_member.organization.name, + ) def test_scan_profile_no_permissions_acknowledged( @@ -101,7 +118,10 @@ def test_scan_profile_no_permissions_acknowledged( redteam_member.acknowledged_clearance_level = -1 redteam_member.save() - request = setup_request(rf.get("scan_profile_detail", {"ooi_id": "Network|testnetwork"}), redteam_member.user) + request = setup_request( + rf.get("scan_profile_detail", {"ooi_id": "Network|testnetwork"}), + redteam_member.user, + ) response = ScanProfileDetailView.as_view()(request, organization_code=redteam_member.organization.code) assert response.status_code == 200 @@ -119,7 +139,10 @@ def test_scan_profile_no_permissions_trusted( redteam_member.trusted_clearance_level = -1 redteam_member.save() - request = setup_request(rf.get("scan_profile_detail", {"ooi_id": "Network|testnetwork"}), redteam_member.user) + request = setup_request( + rf.get("scan_profile_detail", {"ooi_id": "Network|testnetwork"}), + redteam_member.user, + ) response = ScanProfileDetailView.as_view()(request, organization_code=redteam_member.organization.code) assert response.status_code == 200 @@ -132,7 +155,10 @@ def test_scan_profile_reset_view(rf, redteam_member, mock_scheduler, mock_organi mock_organization_view_octopoes().get_tree.return_value = ReferenceTree.model_validate(TREE_DATA) mocker.patch("katalogus.utils.get_katalogus") - request = setup_request(rf.get("scan_profile_reset", {"ooi_id": "Network|testnetwork"}), redteam_member.user) + request = setup_request( + rf.get("scan_profile_reset", {"ooi_id": "Network|testnetwork"}), + redteam_member.user, + ) response = ScanProfileResetView.as_view()(request, organization_code=redteam_member.organization.code) assert response.status_code == 200 diff --git a/rocky/tests/scheduler/__init__.py b/rocky/tests/scheduler/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/rocky/tests/scheduler/test_scheduler_errors.py b/rocky/tests/scheduler/test_scheduler_errors.py new file mode 100644 index 00000000000..b9229216aab --- /dev/null +++ b/rocky/tests/scheduler/test_scheduler_errors.py @@ -0,0 +1,39 @@ +from rocky.scheduler import SchedulerConnectError, SchedulerTooManyRequestError, SchedulerValidationError +from rocky.views.tasks import BoefjesTaskListView +from tests.conftest import setup_request + + +def test_tasks_view_connect_error(rf, client_member, mock_scheduler): + mock_scheduler.list_tasks.side_effect = SchedulerConnectError + + request = setup_request(rf.get("boefjes_task_list"), client_member.user) + response = BoefjesTaskListView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 + + assert list(request._messages)[0].message == "Could not connect to Scheduler. Service is possibly down." + + +def test_tasks_view_validation_error(rf, client_member, mock_scheduler): + mock_scheduler.list_tasks.side_effect = SchedulerValidationError + + request = setup_request(rf.get("boefjes_task_list"), client_member.user) + response = BoefjesTaskListView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 + + assert list(request._messages)[0].message == "Your request could not be validated." + + +def test_tasks_view_too_many_requests_error(rf, client_member, mock_scheduler): + mock_scheduler.list_tasks.side_effect = SchedulerTooManyRequestError + + request = setup_request(rf.get("boefjes_task_list"), client_member.user) + response = BoefjesTaskListView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 + + assert ( + list(request._messages)[0].message + == "Scheduler is receiving too many requests. Increase SCHEDULER_PQ_MAXSIZE or wait for task to finish." + ) diff --git a/rocky/tests/test_boefjes_tasks.py b/rocky/tests/test_boefjes_tasks.py index 88ebe4a10f8..6d62ad57488 100644 --- a/rocky/tests/test_boefjes_tasks.py +++ b/rocky/tests/test_boefjes_tasks.py @@ -1,79 +1,38 @@ -from unittest.mock import call - import pytest from django.http import Http404 -from httpx import HTTPError from pytest_django.asserts import assertContains -from rocky.scheduler import TooManyRequestsError +from rocky.scheduler import SchedulerTooManyRequestError from rocky.views.bytes_raw import BytesRawView from rocky.views.tasks import BoefjesTaskListView from tests.conftest import setup_request -def test_boefjes_tasks(rf, client_member, mocker, lazy_task_list_empty): - mock_scheduler_client = mocker.patch("rocky.views.tasks.client") - mock_scheduler_client.get_lazy_task_list.return_value = lazy_task_list_empty - - request = setup_request(rf.get("boefjes_task_list"), client_member.user) - response = BoefjesTaskListView.as_view()(request, organization_code=client_member.organization.code) - - assert response.status_code == 200 - - mock_scheduler_client.get_lazy_task_list.assert_has_calls( - [ - call( - scheduler_id="boefje-test", - task_type="boefje", - status=None, - min_created_at=None, - max_created_at=None, - input_ooi=None, - ) - ] - ) - - -def test_tasks_view_simple(rf, client_member, mocker, lazy_task_list_with_boefje): - mock_scheduler_client = mocker.patch("rocky.views.tasks.client") - mock_scheduler_client.get_lazy_task_list.return_value = lazy_task_list_with_boefje - +def test_boefjes_tasks(rf, client_member, mock_scheduler): request = setup_request(rf.get("boefjes_task_list"), client_member.user) - response = BoefjesTaskListView.as_view()(request, organization_code=client_member.organization.code) - - assertContains(response, "1b20f85f") - assertContains(response, "Hostname|internet|mispo.es") - - mock_scheduler_client.get_lazy_task_list.assert_has_calls( - [ - call( - scheduler_id="boefje-test", - task_type="boefje", - status=None, - min_created_at=None, - max_created_at=None, - input_ooi=None, - ) - ] + response = BoefjesTaskListView.as_view()( + request, + organization_code=client_member.organization.code, + scheduler_id="boefje-test", + task_type="boefje", + status=None, + min_created_at=None, + max_created_at=None, + input_ooi=None, ) + assert response.status_code == 200 -def test_tasks_view_error(rf, client_member, mocker, lazy_task_list_with_boefje): - mock_scheduler_client = mocker.patch("rocky.views.tasks.client") - mock_scheduler_client.get_lazy_task_list.return_value = lazy_task_list_with_boefje - mock_scheduler_client.get_lazy_task_list.side_effect = HTTPError("error") +def test_tasks_view_simple(rf, client_member, mock_scheduler, mock_scheduler_client_task_list): request = setup_request(rf.get("boefjes_task_list"), client_member.user) response = BoefjesTaskListView.as_view()(request, organization_code=client_member.organization.code) - assertContains(response, "error") - assertContains(response, "Fetching tasks failed") + assertContains(response, "Completed") -def test_reschedule_task(rf, client_member, mocker, task): - mock_scheduler = mocker.patch("tools.view_helpers.client") +def test_reschedule_task(rf, client_member, mock_scheduler, task): mock_scheduler.get_task_details.return_value = task - request = setup_request( rf.post( f"/en/{client_member.organization.code}/tasks/boefjes/?task_id={task.id}", @@ -83,7 +42,7 @@ def test_reschedule_task(rf, client_member, mocker, task): ) response = BoefjesTaskListView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 302 + assert response.status_code == 200 assert list(request._messages)[0].message == ( "Your task is scheduled and will soon be started in the background. " "Results will be added to the object list when they are in. " @@ -91,10 +50,9 @@ def test_reschedule_task(rf, client_member, mocker, task): ) -def test_reschedule_task_already_queued(rf, client_member, mocker, task): - mock_scheduler = mocker.patch("tools.view_helpers.client") +def test_reschedule_task_already_queued(rf, client_member, mock_scheduler, mocker, task): mock_scheduler.get_task_details.return_value = task - mock_scheduler.push_task.side_effect = TooManyRequestsError + mock_scheduler.push_task.side_effect = SchedulerTooManyRequestError request = setup_request( rf.post( @@ -109,13 +67,15 @@ def test_reschedule_task_already_queued(rf, client_member, mocker, task): organization_code=client_member.organization.code, ) - assert response.status_code == 302 - assert list(request._messages)[0].message == "Task queue is full, please try again later." + assert response.status_code == 200 + assert ( + list(request._messages)[0].message + == "Scheduler is receiving too many requests. Increase SCHEDULER_PQ_MAXSIZE or wait for task to finish." + ) -def test_reschedule_task_from_other_org(rf, client_member, client_member_b, mocker, task): - mock_scheduler_client = mocker.patch("rocky.views.tasks.client") - mock_scheduler_client.get_task_details.return_value = task +def test_reschedule_task_from_other_org(rf, client_member, client_member_b, mock_scheduler, task): + mock_scheduler.get_task_details.return_value = task request = setup_request( rf.post( diff --git a/rocky/tests/test_groups_and_permissions.py b/rocky/tests/test_groups_and_permissions.py index f477f5a1c52..2281aaa6a1b 100644 --- a/rocky/tests/test_groups_and_permissions.py +++ b/rocky/tests/test_groups_and_permissions.py @@ -52,13 +52,13 @@ def test_plugin_settings_list_perms( mock_mixins_katalogus, plugin_details, plugin_schema, + mock_scheduler, mock_organization_view_octopoes, network, mocker, lazy_task_list_with_boefje, ): - mock_scheduler_client = mocker.patch("katalogus.views.plugin_detail.scheduler") - mock_scheduler_client.client.get_lazy_task_list.return_value = lazy_task_list_with_boefje + mock_scheduler.client.get_lazy_task_list.return_value = lazy_task_list_with_boefje mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType](count=1, items=[network]) mock_mixins_katalogus().get_plugin.return_value = plugin_details @@ -86,13 +86,13 @@ def test_plugin_settings_list_perms_2( mock_mixins_katalogus, plugin_details, plugin_schema, + mock_scheduler, mock_organization_view_octopoes, network, mocker, lazy_task_list_with_boefje, ): - mock_scheduler_client = mocker.patch("katalogus.views.plugin_detail.scheduler") - mock_scheduler_client.client.get_lazy_task_list.return_value = lazy_task_list_with_boefje + mock_scheduler.client.get_lazy_task_list.return_value = lazy_task_list_with_boefje mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType](count=1, items=[network]) mock_mixins_katalogus().get_plugin.return_value = plugin_details diff --git a/rocky/tools/forms/scheduler.py b/rocky/tools/forms/scheduler.py new file mode 100644 index 00000000000..b7682bf3ce4 --- /dev/null +++ b/rocky/tools/forms/scheduler.py @@ -0,0 +1,67 @@ +from datetime import datetime, timezone + +from django import forms +from django.utils.translation import gettext_lazy as _ + +from tools.forms.base import DateInput + + +class TaskFilterForm(forms.Form): + min_created_at = forms.DateField( + label=_("From"), + widget=DateInput(format="%Y-%m-%d"), + required=False, + ) + max_created_at = forms.DateField( + label=_("To"), + widget=DateInput(format="%Y-%m-%d"), + required=False, + ) + status = forms.ChoiceField( + choices=( + ("", _("All")), + ("cancelled", _("Cancelled")), + ("completed", _("Completed")), + ("dispatched", _("Dispatched")), + ("failed", _("Failed")), + ("pending", _("Pending")), + ("queued", _("Queued")), + ("running", _("Running")), + ), + required=False, + ) + input_ooi = forms.CharField( + label=_("Search"), + widget=forms.TextInput(attrs={"placeholder": _("Search by object name")}), + required=False, + ) + + def clean(self): + cleaned_data = super().clean() + + min_created_at = cleaned_data.get("min_created_at") + max_created_at = cleaned_data.get("max_created_at") + + date_message = _("The selected date is in the future. Please select a different date.") + + now = datetime.now(tz=timezone.utc) + + if min_created_at is not None and min_created_at > now.date(): + self.add_error("min_created_at", date_message) + + if max_created_at is not None and max_created_at > now.date(): + self.add_error("max_created_at", date_message) + + return cleaned_data + + +class OOIDetailTaskFilterForm(TaskFilterForm): + """ + Task filter at OOI detail to pass observed_at and ooi_id values. + """ + + observed_at = forms.CharField(widget=forms.HiddenInput(), required=False) + ooi_id = forms.CharField(widget=forms.HiddenInput(), required=False) + + # No need to search for OOI if you are already at the OOI detail page. + input_ooi = None diff --git a/rocky/tools/view_helpers.py b/rocky/tools/view_helpers.py index 741c59c868a..e216d944334 100644 --- a/rocky/tools/view_helpers.py +++ b/rocky/tools/view_helpers.py @@ -3,13 +3,11 @@ from typing import TypedDict from urllib.parse import urlencode, urlparse, urlunparse -from django.contrib import messages from django.http import HttpRequest from django.urls.base import reverse, reverse_lazy from django.utils.translation import gettext_lazy as _ from octopoes.models.types import OOI_TYPES -from rocky.scheduler import PrioritizedItem, SchedulerError, client from tools.models import Organization @@ -165,56 +163,3 @@ def build_breadcrumbs(self): "text": _("Objects"), } ] - - -def schedule_task(request: HttpRequest, organization_code: str, p_item: PrioritizedItem) -> None: - try: - # Remove id attribute of both p_item and p_item.data, since the - # scheduler will create a new task with new id's. However, pydantic - # requires an id attribute to be present in its definition and the - # default set to None when the attribute is optional, otherwise it - # will not serialize the id if it is not present in the definition. - if hasattr(p_item, "id"): - delattr(p_item, "id") - - if hasattr(p_item.data, "id"): - delattr(p_item.data, "id") - - client.push_task(f"{p_item.data.type}-{organization_code}", p_item) - except SchedulerError as error: - messages.error(request, error.message) - else: - messages.success( - request, - _( - "Your task is scheduled and will soon be started in the background. " - "Results will be added to the object list when they are in. " - "It may take some time, a refresh of the page may be needed to show the results." - ), - ) - - -# FIXME: Tasks should be (re)created with supplied data, not by fetching prior -# task info from the scheduler. Task data should be available from the context -# from which the task is created. -def reschedule_task(request: HttpRequest, organization_code: str, task_id: str) -> None: - try: - task = client.get_task_details(organization_code, task_id) - except SchedulerError as error: - messages.error(request, error.message) - return - - if not task: - messages.error(request, _("Task not found.")) - return - - try: - new_p_item = PrioritizedItem( - data=task.p_item.data, - priority=1, - ) - - schedule_task(request, organization_code, new_p_item) - except SchedulerError as error: - messages.error(request, error.message) - return From bd5c13ae2859e6dc00381acc07bfb038a6c0ee09 Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Wed, 17 Jul 2024 10:40:28 +0200 Subject: [PATCH 019/112] RPKI Improvements (#2759) Co-authored-by: Jan Klopper Co-authored-by: Wilco Baan Hofman Co-authored-by: Jeroen Dekkers Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> --- .../kat_finding_types.json | 6 + boefjes/boefjes/plugins/kat_rpki/main.py | 162 +++++++++++++----- boefjes/boefjes/plugins/kat_rpki/normalize.py | 25 +-- .../boefjes/plugins/kat_rpki/normalizer.json | 2 +- .../report_types/rpki_report/report.html | 2 +- .../report_types/rpki_report/report.py | 8 +- rocky/rocky/locale/django.pot | 4 +- rocky/tests/conftest.py | 4 +- rocky/tests/reports/test_rpki_report.py | 6 +- 9 files changed, 155 insertions(+), 64 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json index ffe75f9f164..31ff5bed15b 100644 --- a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json +++ b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json @@ -461,6 +461,12 @@ "impact": "Without RPKI validation, your servers might be more vulnerable to unintended or malicious routing configuration errors, potentially leading to inaccessibility of your servers or interception of internet traffic directed to them.", "recommendation": "Make sure that the Route Origin Authorizations (ROAs) that specify which Autonomous Systems (AS) are authorized to announce your IP addresses are valid and not expired." }, + "KAT-INVALID-RPKI": { + "description": "A route announcement that is matched by the published Route Policy and Authorization (RPKI) is invalid", + "risk": "medium", + "impact": "Without RPKI validation, your servers might be more vulnerable to unintended or malicious routing configuration errors, potentially leading to inaccessibility of your servers or interception of internet traffic directed to them.", + "recommendation": "Make sure that the Route Origin Authorizations (ROAs) that specify which Autonomous Systems (AS) are authorized to announce your IP addresses are valid and not expired." + }, "KAT-NO-CAA": { "description": "This zone does not carry at least one CAA record.", "source": "https://letsencrypt.org/docs/caa/", diff --git a/boefjes/boefjes/plugins/kat_rpki/main.py b/boefjes/boefjes/plugins/kat_rpki/main.py index c3257e75611..e6e4a400b26 100644 --- a/boefjes/boefjes/plugins/kat_rpki/main.py +++ b/boefjes/boefjes/plugins/kat_rpki/main.py @@ -4,7 +4,8 @@ import json import os import tempfile -from datetime import datetime +from datetime import datetime, timezone +from ipaddress import ip_address from os import getenv from pathlib import Path @@ -13,78 +14,157 @@ from boefjes.job_models import BoefjeMeta +# Paths and URLs for RPKI BASE_PATH = Path(getenv("OPENKAT_CACHE_PATH", Path(__file__).parent)) RPKI_PATH = BASE_PATH / "rpki.json" RPKI_META_PATH = BASE_PATH / "rpki-meta.json" RPKI_SOURCE_URL = "https://console.rpki-client.org/vrps.json" + +# Paths and URLs for BGP +BGP_PATH = BASE_PATH / "bgp.jsonl" +BGP_META_PATH = BASE_PATH / "bgp-meta.json" +BGP_SOURCE_URL = "https://bgp.tools/table.jsonl" + +# Cache timeout and default hash function RPKI_CACHE_TIMEOUT = 1800 # in seconds -HASHFUNC = "sha256" def run(boefje_meta: BoefjeMeta) -> list[tuple[set, bytes | str]]: input_ = boefje_meta.arguments["input"] ip = input_["address"] - now = datetime.utcnow() - hash_algorithm = getenv("HASHFUNC", HASHFUNC) + hash_algorithm = getenv("HASHFUNC", "sha256") + + # if the address is private, we do not need a ROA + if not ip_address(ip).is_global: + return [ + (set(), json.dumps("IP address is private, no need for RPKI validation")), + ] + + # RPKI cache check and refresh + if not RPKI_PATH.exists() or cache_out_of_date(RPKI_META_PATH): + rpki_json, rpki_meta = refresh_cache(RPKI_SOURCE_URL, RPKI_PATH, RPKI_META_PATH, hash_algorithm) + else: + rpki_json = load_json(RPKI_PATH) + rpki_meta = load_json(RPKI_META_PATH) - if not RPKI_PATH.exists() or cache_out_of_date(): - rpki_json, rpki_meta = refresh_rpki(hash_algorithm) + if not BGP_PATH.exists() or cache_out_of_date(BGP_META_PATH): + bgp_data, bgp_meta = refresh_cache( + BGP_SOURCE_URL, BGP_PATH, BGP_META_PATH, hash_algorithm, file_extension="jsonl" + ) else: - with RPKI_PATH.open() as json_file: - rpki_json = json.load(json_file) - with RPKI_META_PATH.open() as json_meta_file: - rpki_meta = json.load(json_meta_file) + bgp_data = load_jsonl(BGP_PATH) + bgp_meta = load_json(BGP_META_PATH) + exists = False - notexpired = False roas = [] - for roa in rpki_json["roas"]: - if IPAddress(ip) in IPNetwork(roa["prefix"]): - exists = True - expires = datetime.fromtimestamp(roa["expires"]) - roas.append({"prefix": roa["prefix"], "expires": expires.strftime("%Y-%m-%dT%H:%M"), "ta": roa["ta"]}) - if expires > now: - notexpired = True + bgp_entries = [] + invalid_bgp_entries = [] + if isinstance(rpki_json, dict) and "roas" in rpki_json: + for roa in rpki_json["roas"]: + if IPAddress(ip) in IPNetwork(roa["prefix"]): + expires = datetime.fromtimestamp(roa["expires"]) + asn = roa["asn"] + roas.append( + { + "prefix": roa["prefix"], + "expires": expires.strftime("%Y-%m-%dT%H:%M%z"), + "ta": roa["ta"], + "asn": asn, + } + ) + exists = True - results = {"vrps_records": roas, "notexpired": notexpired, "exists": exists} + # check validity through bgp json + invalid_exists = False + for entry in bgp_data: + if IPAddress(ip) in IPNetwork(entry["CIDR"]): + bgp_entries.append(entry) + if entry["ASN"] != asn: + invalid_exists = True + + if invalid_exists: + invalid_bgp_entries.append({"ip": ip, "asn": asn}) + + results = { + "vrps_records": roas, + "exists": exists, + "bgp_entries": bgp_entries, + "invalid_bgp_entries": invalid_bgp_entries, + } return [ - (set(), json.dumps(results)), + ({"rpki/results"}, json.dumps(results)), ( {"rpki/cache-meta"}, json.dumps(rpki_meta), ), + ( + {"rpki/bgp-cache-meta"}, + json.dumps(bgp_meta), + ), ] -def create_hash(data: bytes, algo: str) -> str: - hashfunc = getattr(hashlib, algo) - return hashfunc(data).hexdigest() - - -def cache_out_of_date() -> bool: - """Returns True if the file is older than the allowed cache_timout""" - now = datetime.utcnow() +def cache_out_of_date(meta_path: Path) -> bool: + """Returns True if the cache file is older than the allowed cache_timeout""" + now = datetime.now(timezone.utc) maxage = int(getenv("RPKI_CACHE_TIMEOUT", RPKI_CACHE_TIMEOUT)) - with RPKI_META_PATH.open() as meta_file: - meta = json.load(meta_file) - cached_file_timestamp = datetime.strptime(meta["timestamp"], "%Y-%m-%dT%H:%M:%SZ") + meta = load_json(meta_path) + try: + cached_file_timestamp = datetime.fromisoformat(meta["timestamp"]) + # for old meta cache files that have the old timestamp format + except ValueError: + return True return (now - cached_file_timestamp).total_seconds() > maxage -def refresh_rpki(algo: str) -> tuple[dict, dict]: - source_url = getenv("RPKI_SOURCE_URL", RPKI_SOURCE_URL) - response = requests.get(source_url, allow_redirects=True, timeout=30) +def refresh_cache( + source_url: str, data_path: Path, meta_path: Path, algo: str, file_extension: str = "json" +) -> tuple[dict | list, dict]: + """Refreshes the cache for either RPKI or BGP data. Handles both JSON and JSON Lines formats.""" + headers = {"User-Agent": getenv("USERAGENT", default="OpenKAT")} + response = requests.get(source_url, headers=headers, allow_redirects=True, timeout=30) response.raise_for_status() - with tempfile.NamedTemporaryFile(mode="wb", dir=RPKI_PATH.parent, delete=False) as temp_rpki_file: - temp_rpki_file.write(response.content) - # atomic operation - os.rename(temp_rpki_file.name, RPKI_PATH) + + with tempfile.NamedTemporaryFile(mode="wb", dir=data_path.parent, delete=False) as temp_file: + temp_file.write(response.content) + # Atomic operation to move temp file to permanent location + os.rename(temp_file.name, data_path) + + # Processing the response content based on format + if file_extension == "json": + data = json.loads(response.content) + elif file_extension == "jsonl": + # For JSON Lines, parse each line separately + data = [json.loads(line) for line in response.content.decode().splitlines()] + else: + raise ValueError(f"Unsupported format: {file_extension}") + + # Creating metadata metadata = { - "timestamp": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"), + "timestamp": datetime.now(timezone.utc).isoformat(), "source": source_url, "hash": create_hash(response.content, algo), "hash_algorithm": algo, } - with open(RPKI_META_PATH, "w") as meta_file: + with open(meta_path, "w") as meta_file: json.dump(metadata, meta_file) - return (json.loads(response.content), metadata) + + return data, metadata + + +def create_hash(data: bytes, algo: str) -> str: + hashfunc = getattr(hashlib, algo) + return hashfunc(data).hexdigest() + + +def load_json(path: Path) -> dict: + """Utility function to load a JSON file""" + with path.open() as json_file: + return json.load(json_file) + + +def load_jsonl(path: Path) -> list: + """Utility function to load a JSON Lines file""" + with path.open("r") as file: + return [json.loads(line) for line in file] diff --git a/boefjes/boefjes/plugins/kat_rpki/normalize.py b/boefjes/boefjes/plugins/kat_rpki/normalize.py index 068dfb91209..9c5b518179c 100644 --- a/boefjes/boefjes/plugins/kat_rpki/normalize.py +++ b/boefjes/boefjes/plugins/kat_rpki/normalize.py @@ -1,5 +1,6 @@ import json from collections.abc import Iterable +from ipaddress import ip_address from boefjes.job_models import NormalizerOutput from octopoes.models import Reference @@ -10,14 +11,18 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: results = json.loads(raw) ooi = Reference.from_str(input_ooi["primary_key"]) - if not results["exists"]: - ft = KATFindingType(id="KAT-NO-RPKI") - f = Finding(finding_type=ft.reference, ooi=ooi) - yield ft - yield f + address = ip_address(ooi.tokenized.address) - if not results.get("valid") and not results.get("notexpired"): - ft = KATFindingType(id="KAT-EXPIRED-RPKI") - f = Finding(finding_type=ft.reference, ooi=ooi) - yield ft - yield f + # if the address is private, we do not need a ROA + if address.is_global: + if not results["exists"]: + ft = KATFindingType(id="KAT-NO-RPKI") + f = Finding(finding_type=ft.reference, ooi=ooi) + yield ft + yield f + + if results["invalid_bgp_entries"]: + ft = KATFindingType(id="KAT-INVALID-RPKI") + f = Finding(finding_type=ft.reference, ooi=ooi) + yield ft + yield f diff --git a/boefjes/boefjes/plugins/kat_rpki/normalizer.json b/boefjes/boefjes/plugins/kat_rpki/normalizer.json index a086f2e9a99..22d2f8dc3c0 100644 --- a/boefjes/boefjes/plugins/kat_rpki/normalizer.json +++ b/boefjes/boefjes/plugins/kat_rpki/normalizer.json @@ -1,7 +1,7 @@ { "id": "kat_rpki_normalize", "consumes": [ - "boefje/rpki" + "rpki/results" ], "produces": [ "Finding", diff --git a/rocky/reports/report_types/rpki_report/report.html b/rocky/reports/report_types/rpki_report/report.html index df99dc6ce8a..55d77881f5d 100644 --- a/rocky/reports/report_types/rpki_report/report.html +++ b/rocky/reports/report_types/rpki_report/report.html @@ -52,7 +52,7 @@

{{ type }} {% translate "server" %}

- {% translate "RPKI Not expired" %} + {% translate "RPKI valid" %} {% if data.number_of_valid != data.number_of_ips %} diff --git a/rocky/reports/report_types/rpki_report/report.py b/rocky/reports/report_types/rpki_report/report.py index a4fadb72745..9c40f6a5b3a 100644 --- a/rocky/reports/report_types/rpki_report/report.py +++ b/rocky/reports/report_types/rpki_report/report.py @@ -53,11 +53,11 @@ def collect_data(self, input_oois: Iterable[str], valid_time: datetime) -> dict[ for ip in ips: finding_types = finding_types_by_source.get(ip, []) exists = not any(finding_type for finding_type in finding_types if finding_type.id in ["KAT-NO-RPKI"]) - expired = any(finding_type for finding_type in finding_types if finding_type.id in ["KAT-EXPIRED-RPKI"]) - rpki_ips[ip] = {"exists": exists, "valid": not expired} + invalid = any(finding_type for finding_type in finding_types if finding_type.id in ["KAT-INVALID-RPKI"]) + rpki_ips[ip] = {"exists": exists, "valid": not invalid} number_of_available -= 1 if not exists else 0 - number_of_valid -= 1 if expired else 0 - number_of_compliant -= 1 if not (exists and not expired) else 0 + number_of_valid -= 1 if invalid else 0 + number_of_compliant -= 1 if not (exists and not invalid) else 0 result[input_ooi] = { "input_ooi": input_ooi, diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 56326a1a539..545c935fb28 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-11 11:23+0000\n" +"POT-Creation-Date: 2024-07-16 11:52+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -3089,7 +3089,7 @@ msgid "RPKI Available" msgstr "" #: reports/report_types/rpki_report/report.html -msgid "RPKI Not expired" +msgid "RPKI valid" msgstr "" #: reports/report_types/rpki_report/report.html diff --git a/rocky/tests/conftest.py b/rocky/tests/conftest.py index 14ee2f7b6de..746114fec7e 100644 --- a/rocky/tests/conftest.py +++ b/rocky/tests/conftest.py @@ -702,8 +702,8 @@ def no_rpki_finding_type() -> KATFindingType: @pytest.fixture -def expired_rpki_finding_type() -> KATFindingType: - return KATFindingType(id="KAT-EXPIRED-RPKI") +def invalid_rpki_finding_type() -> KATFindingType: + return KATFindingType(id="KAT-INVALID-RPKI") @pytest.fixture diff --git a/rocky/tests/reports/test_rpki_report.py b/rocky/tests/reports/test_rpki_report.py index 28ca67898ea..2cf3f18a569 100644 --- a/rocky/tests/reports/test_rpki_report.py +++ b/rocky/tests/reports/test_rpki_report.py @@ -79,7 +79,7 @@ def test_rpki_hostname_with_two_ips_invalid( ipaddressv6, service, no_rpki_finding_type, - expired_rpki_finding_type, + invalid_rpki_finding_type, ): mock_octopoes_api_connector.oois = { hostname.reference: hostname, @@ -90,8 +90,8 @@ def test_rpki_hostname_with_two_ips_invalid( hostname.reference: [ipaddressv4, ipaddressv6], }, "IPAddress. Date: Wed, 17 Jul 2024 16:20:01 +0200 Subject: [PATCH 020/112] Hotfix: boefje config migration should check the SQLAlchemy session (#3227) Signed-off-by: Donny Peeters Co-authored-by: Jeroen Dekkers Co-authored-by: Jan Klopper --- ...de6eb7824b_introduce_boefjeconfig_model.py | 40 +++++++++++++++---- .../boefjes/plugins/kat_nmap_udp/boefje.json | 2 +- boefjes/boefjes/sql/config_storage.py | 3 ++ boefjes/boefjes/sql/session.py | 3 +- ...est_settings_to_boefje_config_migration.py | 20 ++++++++-- 5 files changed, 55 insertions(+), 13 deletions(-) diff --git a/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py b/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py index 265cb99c499..ffa35930368 100644 --- a/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py +++ b/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py @@ -6,12 +6,15 @@ """ +import logging + import sqlalchemy as sa from alembic import op from sqlalchemy.orm import sessionmaker from boefjes.local_repository import get_local_repository from boefjes.sql.plugin_storage import create_plugin_storage +from boefjes.storage.interfaces import PluginNotFound # revision identifiers, used by Alembic. revision = "f9de6eb7824b" @@ -20,6 +23,9 @@ depends_on = None +logger = logging.getLogger(__name__) + + def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### op.create_table( @@ -70,6 +76,12 @@ def upgrade() -> None: if local_plugins[plugin_id].type != "boefje": raise ValueError(f"Settings for normalizer or bit found: {plugin_id}. Remove these entries first.") + try: + storage.boefje_by_id(plugin_id) + continue # The Boefje already exists + except PluginNotFound: + pass # The raw query bypasses the session "cache", so this just checks for duplicates + storage.create_boefje(local_plugins[plugin_id]) # type: ignore query = """ @@ -80,7 +92,14 @@ def upgrade() -> None: for plugin_id_output in op.get_bind().execute(query).fetchall(): plugin_id = plugin_id_output[0] if plugin_id not in local_plugins: - raise ValueError(f"Invalid plugin id found: {plugin_id}") + logger.warning("Unknown plugin id found: %s. You might have to re-enable the plugin!", plugin_id) + continue + + try: + storage.boefje_by_id(plugin_id) + continue # The Boefje already exists + except PluginNotFound: + pass # The raw query bypasses the session "cache", so this just checks for duplicates if local_plugins[plugin_id].type == "boefje": storage.create_boefje(local_plugins[plugin_id]) # type: ignore @@ -93,7 +112,14 @@ def upgrade() -> None: for plugin_id_output in op.get_bind().execute(query).fetchall(): plugin_id = plugin_id_output[0] if plugin_id not in local_plugins: - raise ValueError(f"Invalid plugin id found: {plugin_id}") + logger.warning("Unknown plugin id found: %s. You might have to re-enable the plugin!", plugin_id) + continue + + try: + storage.normalizer_by_id(plugin_id) + continue # The Normalizer already exists + except PluginNotFound: + pass # The raw query bypasses the session "cache", so this just checks for duplicates if local_plugins[plugin_id].type == "normalizer": storage.create_normalizer(local_plugins[plugin_id]) # type: ignore @@ -103,25 +129,25 @@ def upgrade() -> None: INSERT INTO boefje_config (settings, boefje_id, organisation_pk) SELECT s.values, b.id, s.organisation_pk from settings s join boefje b on s.plugin_id = b.plugin_id - """) + """) # Add boefjes and set the settings for boefjes with connection.begin(): connection.execute(""" - INSERT INTO boefje_config (settings, boefje_id, organisation_pk) + INSERT INTO boefje_config (enabled, boefje_id, organisation_pk) SELECT p.enabled, b.id, p.organisation_pk FROM plugin_state p JOIN boefje b ON p.plugin_id = b.plugin_id LEFT JOIN boefje_config bc ON bc.boefje_id = b.id WHERE bc.boefje_id IS NULL - """) + """) # Add boefjes and set the enabled field for boefjes that to not exist yet connection.execute(""" UPDATE boefje_config bc SET enabled = p.enabled from plugin_state p JOIN boefje b ON p.plugin_id = b.plugin_id where b.id = bc.boefje_id and p.organisation_pk = bc.organisation_pk - """) + """) # Set the enabled field for boefjes connection.execute(""" UPDATE normalizer_config nc SET enabled = p.enabled from plugin_state p JOIN normalizer n ON p.plugin_id = n.plugin_id where n.id = nc.normalizer_id and p.organisation_pk = nc.organisation_pk - """) + """) # Set the enabled field for normalizers op.drop_table("settings") op.drop_table("plugin_state") diff --git a/boefjes/boefjes/plugins/kat_nmap_udp/boefje.json b/boefjes/boefjes/plugins/kat_nmap_udp/boefje.json index 5a67dc5f570..f9839e53e37 100644 --- a/boefjes/boefjes/plugins/kat_nmap_udp/boefje.json +++ b/boefjes/boefjes/plugins/kat_nmap_udp/boefje.json @@ -10,7 +10,7 @@ "TOP_PORTS_UDP" ], "scan_level": 2, - "oci_image": "openkat/nmap", + "oci_image": "ghcr.io/minvws/openkat/nmap:latest", "oci_arguments": [ "--open", "-T4", diff --git a/boefjes/boefjes/sql/config_storage.py b/boefjes/boefjes/sql/config_storage.py index 15afde54e6e..cd2e2b31db8 100644 --- a/boefjes/boefjes/sql/config_storage.py +++ b/boefjes/boefjes/sql/config_storage.py @@ -71,6 +71,9 @@ def get_all_settings(self, organisation_id: str, plugin_id: str) -> dict: except ConfigNotFound: return {} + if not instance.settings or instance.settings == "{}": # Handle empty settings and the server default of "{}" + return {} + return json.loads(self.encryption.decode(instance.settings)) def delete(self, organisation_id: str, plugin_id: str) -> None: diff --git a/boefjes/boefjes/sql/session.py b/boefjes/boefjes/sql/session.py index 4a832a12bfa..681a6c963ba 100644 --- a/boefjes/boefjes/sql/session.py +++ b/boefjes/boefjes/sql/session.py @@ -1,6 +1,7 @@ import structlog from sqlalchemy.exc import DatabaseError from sqlalchemy.orm import Session +from typing_extensions import Self from boefjes.storage.interfaces import StorageError @@ -23,7 +24,7 @@ class SessionMixin: def __init__(self, session: Session): self.session: Session = session - def __enter__(self) -> "SessionMixin": + def __enter__(self) -> Self: return self def __exit__(self, exc_type: type[Exception], exc_value: str, exc_traceback: str) -> None: # noqa: F841 diff --git a/boefjes/tests/integration/test_settings_to_boefje_config_migration.py b/boefjes/tests/integration/test_settings_to_boefje_config_migration.py index a646eae23dd..35e7670f614 100644 --- a/boefjes/tests/integration/test_settings_to_boefje_config_migration.py +++ b/boefjes/tests/integration/test_settings_to_boefje_config_migration.py @@ -37,6 +37,13 @@ def setUp(self) -> None: ] query = f"INSERT INTO settings (id, values, plugin_id, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 self.engine.execute(text(query)) + + entries = [(1, "dns-records", True, 1), (2, "nmap-udp", True, 1)] + query = ( + f"INSERT INTO plugin_state (id, plugin_id, enabled, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 + ) + self.engine.execute(text(query)) + session.close() def test_fail_on_wrong_plugin_ids(self): @@ -68,9 +75,13 @@ def test_fail_on_wrong_plugin_ids(self): assert SQLPluginStorage(session, settings).boefje_by_id("dns-records").id == "dns-records" - settings_storage = SQLConfigStorage(session, encrypter) - assert settings_storage.get_all_settings("dev1", "dns-records") == {"key1": "val1"} - assert settings_storage.get_all_settings("dev2", "dns-records") == {"key1": "val1", "key2": "val2"} + config_storage = SQLConfigStorage(session, encrypter) + assert config_storage.get_all_settings("dev1", "dns-records") == {"key1": "val1"} + assert config_storage.get_all_settings("dev2", "dns-records") == {"key1": "val1", "key2": "val2"} + assert config_storage.get_all_settings("dev1", "nmap-udp") == {} + + assert config_storage.is_enabled_by_id("dns-records", "dev1") + assert config_storage.is_enabled_by_id("nmap-udp", "dev1") session.close() @@ -82,11 +93,12 @@ def test_downgrade(self): encrypter = create_encrypter() all_settings = list(self.engine.execute(text("select * from settings")).fetchall()) self.assertSetEqual( - {(encrypter.decode(x[1]), x[2], x[3]) for x in all_settings}, + {(encrypter.decode(x[1]) if x[1] != "{}" else "{}", x[2], x[3]) for x in all_settings}, { ('{"key1": "val1"}', "dns-records", 1), ('{"key1": "val1", "key2": "val2"}', "dns-records", 2), ('{"key2": "val2", "key3": "val3"}', "nmap", 1), + ("{}", "nmap-udp", 1), }, ) From 3006d9a46b836bff77b84127b8696b1dbf243ee7 Mon Sep 17 00:00:00 2001 From: Rieven Date: Thu, 18 Jul 2024 12:03:15 +0200 Subject: [PATCH 021/112] Remove action buttons on example boefjes at onboarding (#3236) Co-authored-by: Jeroen Dekkers --- .../templates/step_3d_clearance_level_introduction.html | 2 +- rocky/onboarding/views.py | 4 ++-- rocky/tests/onboarding/test_onboarding_organization_steps.py | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/rocky/onboarding/templates/step_3d_clearance_level_introduction.html b/rocky/onboarding/templates/step_3d_clearance_level_introduction.html index 6be593c64f2..2a5dced79f0 100644 --- a/rocky/onboarding/templates/step_3d_clearance_level_introduction.html +++ b/rocky/onboarding/templates/step_3d_clearance_level_introduction.html @@ -33,7 +33,7 @@

{% translate "How to know required clearance level" %}

{% for boefje in boefjes %} - {% include "partials/plugin_tile.html" with plugin=boefje show_meta=False %} + {% include "partials/plugin_tile.html" with plugin=boefje remove_action_buttons=True %} {% endfor %}
diff --git a/rocky/onboarding/views.py b/rocky/onboarding/views.py index 3ef68dc3932..c5d4fee48af 100644 --- a/rocky/onboarding/views.py +++ b/rocky/onboarding/views.py @@ -183,7 +183,7 @@ def get_boefjes_tiles(self) -> list[dict[str, Any]]: { "id": "dns_zone", "type": "boefje", - "scan_level": "l1", + "scan_level": "1", "name": "DNS-Zone", "description": _("Fetch the parent DNS zone of a hostname"), "enabled": False, @@ -191,7 +191,7 @@ def get_boefjes_tiles(self) -> list[dict[str, Any]]: { "id": "fierce", "type": "boefje", - "scan_level": "l3", + "scan_level": "3", "name": "Fierce", "description": _("Finds subdomains by brute force"), "enabled": False, diff --git a/rocky/tests/onboarding/test_onboarding_organization_steps.py b/rocky/tests/onboarding/test_onboarding_organization_steps.py index ccf53aec448..72a9aae54f2 100644 --- a/rocky/tests/onboarding/test_onboarding_organization_steps.py +++ b/rocky/tests/onboarding/test_onboarding_organization_steps.py @@ -15,7 +15,7 @@ OnboardingSetupScanOOIInfoView, OnboardingSetupScanSelectPluginsView, ) -from pytest_django.asserts import assertContains +from pytest_django.asserts import assertContains, assertNotContains from tests.conftest import setup_request @@ -141,6 +141,8 @@ def test_onboarding_clearance_level_introduction(rf, redteam_member, mock_organi assertContains(response, "Skip onboarding") assertContains(response, "Continue") + assertNotContains(response, '
', html=True) + def test_onboarding_acknowledge_clearance_level(rf, redteam_member, mock_organization_view_octopoes, url): response = OnboardingAcknowledgeClearanceLevelView.as_view()( From 168eb336374ee2db5b87b39fb973c9b14a65f913 Mon Sep 17 00:00:00 2001 From: ammar92 Date: Thu, 18 Jul 2024 12:32:14 +0200 Subject: [PATCH 022/112] Implement logging format configuration (#3216) Co-authored-by: Jeroen Dekkers --- boefjes/boefjes/__main__.py | 8 +++-- boefjes/boefjes/config.py | 4 ++- boefjes/boefjes/katalogus/root.py | 8 +++-- bytes/bytes/api/__init__.py | 21 +++++++++---- bytes/bytes/config.py | 4 ++- mula/scheduler/config/settings.py | 7 ++--- mula/scheduler/context/context.py | 6 ++-- octopoes/octopoes/api/api.py | 8 +++-- octopoes/octopoes/config/settings.py | 45 ++++++++++++++++++++++------ octopoes/octopoes/tasks/tasks.py | 6 +++- rocky/rocky/settings.py | 11 +++++-- 11 files changed, 94 insertions(+), 34 deletions(-) diff --git a/boefjes/boefjes/__main__.py b/boefjes/boefjes/__main__.py index 2f7b406f9c3..a5572253d49 100644 --- a/boefjes/boefjes/__main__.py +++ b/boefjes/boefjes/__main__.py @@ -18,8 +18,12 @@ structlog.processors.StackInfoRenderer(), structlog.dev.set_exc_info, structlog.stdlib.PositionalArgumentsFormatter(), - structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), - structlog.dev.ConsoleRenderer(), + structlog.processors.TimeStamper("iso", utc=False), + ( + structlog.dev.ConsoleRenderer(colors=True, pad_level=False) + if settings.logging_format == "text" + else structlog.processors.JSONRenderer() + ), ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), diff --git a/boefjes/boefjes/config.py b/boefjes/boefjes/config.py index 72a1e02a310..79f5655e093 100644 --- a/boefjes/boefjes/config.py +++ b/boefjes/boefjes/config.py @@ -1,7 +1,7 @@ import logging import os from pathlib import Path -from typing import Any +from typing import Any, Literal from pydantic import AmqpDsn, AnyHttpUrl, Field, FilePath, IPvAnyAddress, PostgresDsn, conint from pydantic_settings import BaseSettings, PydanticBaseSettingsSource, SettingsConfigDict @@ -131,6 +131,8 @@ class Settings(BaseSettings): None, description="OpenTelemetry endpoint", validation_alias="SPAN_EXPORT_GRPC_ENDPOINT" ) + logging_format: Literal["text", "json"] = Field("text", description="Logging format") + model_config = SettingsConfigDict(env_prefix="BOEFJES_") @classmethod diff --git a/boefjes/boefjes/katalogus/root.py b/boefjes/boefjes/katalogus/root.py index 15b19b48401..5c62cea744b 100644 --- a/boefjes/boefjes/katalogus/root.py +++ b/boefjes/boefjes/katalogus/root.py @@ -31,8 +31,12 @@ structlog.processors.StackInfoRenderer(), structlog.dev.set_exc_info, structlog.stdlib.PositionalArgumentsFormatter(), - structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), - structlog.dev.ConsoleRenderer(), + structlog.processors.TimeStamper("iso", utc=False), + ( + structlog.dev.ConsoleRenderer(pad_level=False) + if settings.logging_format == "text" + else structlog.processors.JSONRenderer() + ), ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), diff --git a/bytes/bytes/api/__init__.py b/bytes/bytes/api/__init__.py index 145af6e5986..e10fa307bfa 100644 --- a/bytes/bytes/api/__init__.py +++ b/bytes/bytes/api/__init__.py @@ -18,7 +18,9 @@ from bytes.api.router import router from bytes.config import get_settings -logging.config.fileConfig(get_settings().log_cfg, disable_existing_loggers=False) +settings = get_settings() + +logging.config.fileConfig(settings.log_cfg, disable_existing_loggers=False) structlog.configure( processors=[ structlog.contextvars.merge_contextvars, @@ -26,8 +28,12 @@ structlog.processors.StackInfoRenderer(), structlog.dev.set_exc_info, structlog.stdlib.PositionalArgumentsFormatter(), - structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), - structlog.dev.ConsoleRenderer(), + structlog.processors.TimeStamper("iso", utc=False), + ( + structlog.dev.ConsoleRenderer(colors=True, pad_level=False) + if settings.logging_format == "text" + else structlog.processors.JSONRenderer() + ), ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), @@ -39,8 +45,11 @@ app = FastAPI(title="Bytes API") -if get_settings().span_export_grpc_endpoint is not None: - logger.info("Setting up instrumentation with span exporter endpoint [%s]", get_settings().span_export_grpc_endpoint) +if settings.span_export_grpc_endpoint is not None: + logger.info( + "Setting up instrumentation with span exporter endpoint [%s]", + settings.span_export_grpc_endpoint, + ) FastAPIInstrumentor.instrument_app(app) Psycopg2Instrumentor().instrument() @@ -48,7 +57,7 @@ resource = Resource(attributes={SERVICE_NAME: "bytes"}) provider = TracerProvider(resource=resource) - processor = BatchSpanProcessor(OTLPSpanExporter(endpoint=str(get_settings().span_export_grpc_endpoint))) + processor = BatchSpanProcessor(OTLPSpanExporter(endpoint=str(settings.span_export_grpc_endpoint))) provider.add_span_processor(processor) trace.set_tracer_provider(provider) diff --git a/bytes/bytes/config.py b/bytes/bytes/config.py index e206c9ec5a1..056f6fa3f39 100644 --- a/bytes/bytes/config.py +++ b/bytes/bytes/config.py @@ -2,7 +2,7 @@ import os from functools import lru_cache from pathlib import Path -from typing import Any +from typing import Any, Literal from pydantic import AmqpDsn, AnyHttpUrl, DirectoryPath, Field, FilePath, PostgresDsn from pydantic_settings import BaseSettings, EnvSettingsSource, PydanticBaseSettingsSource, SettingsConfigDict @@ -138,6 +138,8 @@ class Settings(BaseSettings): db_connection_pool_size: int = Field(16, description="Database connection pool size") + logging_format: Literal["text", "json"] = Field("text", description="Logging format") + model_config = SettingsConfigDict(env_prefix="BYTES_") @classmethod diff --git a/mula/scheduler/config/settings.py b/mula/scheduler/config/settings.py index 809f4dd00bb..9012d68bb31 100644 --- a/mula/scheduler/config/settings.py +++ b/mula/scheduler/config/settings.py @@ -1,7 +1,7 @@ import logging import os from pathlib import Path -from typing import Any +from typing import Any, Literal from pydantic import AmqpDsn, AnyHttpUrl, Field, PostgresDsn, fields from pydantic_settings import BaseSettings, PydanticBaseSettingsSource, SettingsConfigDict @@ -64,10 +64,7 @@ class Settings(BaseSettings): description="Enables/disables the collection of metrics to be used with tools like Prometheus", ) - json_logging: bool = Field( - False, - description="Enables/disables structured logging in json format", - ) + logging_format: Literal["text", "json"] = Field("text", description="Logging format") # Server settings api_host: str = Field( diff --git a/mula/scheduler/context/context.py b/mula/scheduler/context/context.py index 4369132a51a..3e5e118f70b 100644 --- a/mula/scheduler/context/context.py +++ b/mula/scheduler/context/context.py @@ -43,7 +43,7 @@ def __init__(self) -> None: logging.config.dictConfig(json.load(f)) # Check if we enabled structured logging in the configuration - if self.config.json_logging: + if self.config.logging_format == "json": structlog.configure( processors=[ # If log level is too low, abort pipeline and throw away log entry. @@ -55,7 +55,7 @@ def __init__(self) -> None: # Perform %-style formatting. structlog.stdlib.PositionalArgumentsFormatter(), # Add a timestamp in ISO 8601 format. - structlog.processors.TimeStamper(fmt="iso"), + structlog.processors.TimeStamper(fmt="iso", utc=False), # If the "stack_info" key in the event dict is true, remove it # and render the current stack trace in the "stack" key. structlog.processors.StackInfoRenderer(), @@ -98,7 +98,7 @@ def __init__(self) -> None: structlog.processors.StackInfoRenderer(), structlog.dev.set_exc_info, structlog.stdlib.PositionalArgumentsFormatter(), - structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), + structlog.processors.TimeStamper("iso", utc=False), structlog.dev.ConsoleRenderer(), ], context_class=dict, diff --git a/octopoes/octopoes/api/api.py b/octopoes/octopoes/api/api.py index 0980dce2b3a..9a537fff4af 100644 --- a/octopoes/octopoes/api/api.py +++ b/octopoes/octopoes/api/api.py @@ -46,8 +46,12 @@ structlog.processors.StackInfoRenderer(), structlog.dev.set_exc_info, structlog.stdlib.PositionalArgumentsFormatter(), - structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S", utc=False), - structlog.dev.ConsoleRenderer(), + structlog.processors.TimeStamper("iso", utc=False), + ( + structlog.dev.ConsoleRenderer(colors=True, pad_level=False) + if settings.logging_format == "text" + else structlog.processors.JSONRenderer() + ), ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), diff --git a/octopoes/octopoes/config/settings.py b/octopoes/octopoes/config/settings.py index a5857952eb4..e0bed593486 100644 --- a/octopoes/octopoes/config/settings.py +++ b/octopoes/octopoes/config/settings.py @@ -3,7 +3,7 @@ import logging import os from pathlib import Path -from typing import Any +from typing import Any, Literal from pydantic import AmqpDsn, AnyHttpUrl, Field, FilePath from pydantic_settings import BaseSettings, EnvSettingsSource, PydanticBaseSettingsSource, SettingsConfigDict @@ -34,7 +34,11 @@ def __call__(self) -> dict[str, Any]: # New variable not explicitly set through env, # ...but old variable has been explicitly set through env if new_name not in env_vars and old_name in env_vars: - logging.warning("Deprecation: %s is deprecated, use %s instead", old_name.upper(), new_name.upper()) + logging.warning( + "Deprecation: %s is deprecated, use %s instead", + old_name.upper(), + new_name.upper(), + ) d[new_name[len(env_prefix) :]] = env_vars[old_name] return d @@ -47,27 +51,45 @@ class Settings(BaseSettings): log_cfg: FilePath = Field(BASE_DIR / "logging.yml", description="Path to the logging configuration file") # External services settings - queue_uri: AmqpDsn = Field(..., examples=["amqp://"], description="KAT queue URI", validation_alias="QUEUE_URI") + queue_uri: AmqpDsn = Field( + ..., + examples=["amqp://"], + description="KAT queue URI", + validation_alias="QUEUE_URI", + ) xtdb_uri: AnyHttpUrl = Field( - ..., examples=["http://xtdb:3000"], description="XTDB API", validation_alias="XTDB_URI" + ..., + examples=["http://xtdb:3000"], + description="XTDB API", + validation_alias="XTDB_URI", ) katalogus_api: AnyHttpUrl = Field( - ..., examples=["http://localhost:8003"], description="Katalogus API URL", validation_alias="KATALOGUS_API" + ..., + examples=["http://localhost:8003"], + description="Katalogus API URL", + validation_alias="KATALOGUS_API", ) scan_level_recalculation_interval: int = Field( - 60, description="Interval in seconds of the periodic task that recalculates scan levels" + 60, + description="Interval in seconds of the periodic task that recalculates scan levels", ) bits_enabled: set[str] = Field(set(), examples=['["port-common"]'], description="Explicitly enabled bits") bits_disabled: set[str] = Field( - set(), examples=['["port-classification-ip"]'], description="Explicitly disabled bits" + set(), + examples=['["port-classification-ip"]'], + description="Explicitly disabled bits", ) span_export_grpc_endpoint: AnyHttpUrl | None = Field( - None, description="OpenTelemetry endpoint", validation_alias="SPAN_EXPORT_GRPC_ENDPOINT" + None, + description="OpenTelemetry endpoint", + validation_alias="SPAN_EXPORT_GRPC_ENDPOINT", ) + logging_format: Literal["text", "json"] = Field("text", description="Logging format") + model_config = SettingsConfigDict(env_prefix="OCTOPOES_") @classmethod @@ -80,7 +102,12 @@ def settings_customise_sources( file_secret_settings: PydanticBaseSettingsSource, ) -> tuple[PydanticBaseSettingsSource, ...]: backwards_compatible_settings = BackwardsCompatibleEnvSettings(settings_cls) - return env_settings, init_settings, file_secret_settings, backwards_compatible_settings + return ( + env_settings, + init_settings, + file_secret_settings, + backwards_compatible_settings, + ) DEFAULT_SCAN_LEVEL_FILTER = {scan_level for scan_level in ScanLevel} diff --git a/octopoes/octopoes/tasks/tasks.py b/octopoes/octopoes/tasks/tasks.py index 3144e883830..4d402e57cb7 100644 --- a/octopoes/octopoes/tasks/tasks.py +++ b/octopoes/octopoes/tasks/tasks.py @@ -37,7 +37,11 @@ structlog.dev.set_exc_info, structlog.stdlib.PositionalArgumentsFormatter(), structlog.processors.TimeStamper("iso", utc=False), - structlog.dev.ConsoleRenderer(colors=True), + ( + structlog.dev.ConsoleRenderer(colors=True, pad_level=False) + if settings.logging_format == "text" + else structlog.processors.JSONRenderer() + ), ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), diff --git a/rocky/rocky/settings.py b/rocky/rocky/settings.py index 2ab5adfaa94..b5cec6b8754 100644 --- a/rocky/rocky/settings.py +++ b/rocky/rocky/settings.py @@ -491,6 +491,9 @@ def immutable_file_test(path, url): FORMS_URLFIELD_ASSUME_HTTPS = True +# Logging format ("text" or "json") +LOGGING_FORMAT = env("LOGGING_FORMAT", default="text") + structlog.configure( processors=[ structlog.contextvars.merge_contextvars, @@ -498,8 +501,12 @@ def immutable_file_test(path, url): structlog.processors.StackInfoRenderer(), structlog.dev.set_exc_info, structlog.stdlib.PositionalArgumentsFormatter(), - structlog.processors.TimeStamper("iso"), - structlog.dev.ConsoleRenderer(colors=True), + structlog.processors.TimeStamper("iso", utc=False), + ( + structlog.processors.JSONRenderer() + if LOGGING_FORMAT == "json" + else structlog.dev.ConsoleRenderer(colors=True, pad_level=False) + ), ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), From dd8467d9c6c7d5e87365020dac23b567b20005da Mon Sep 17 00:00:00 2001 From: Roelof Korporaal Date: Thu, 18 Jul 2024 13:51:00 +0200 Subject: [PATCH 023/112] Feature/create dialog modal component (#3022) Co-authored-by: Jeroen Dekkers --- rocky/Dockerfile | 1 + rocky/assets/css/main.scss | 7 +- rocky/assets/css/manon-components.scss | 1 + .../manon/button-icon-only.scss | 11 +++ rocky/assets/js/components.js | 1 + rocky/components/main.scss | 1 + rocky/components/modal/README.md | 67 +++++++++++++++ rocky/components/modal/__init__.py | 0 rocky/components/modal/modal.py | 14 ++++ rocky/components/modal/script.js | 28 +++++++ rocky/components/modal/style.scss | 82 +++++++++++++++++++ rocky/components/modal/template.html | 33 ++++++++ rocky/poetry.lock | 16 +++- rocky/pyproject.toml | 1 + rocky/requirements-dev.txt | 3 + rocky/requirements.txt | 3 + rocky/rocky/locale/django.pot | 27 +++--- rocky/rocky/settings.py | 18 +++- 18 files changed, 295 insertions(+), 19 deletions(-) create mode 100644 rocky/assets/css/vendor_overrides/manon/button-icon-only.scss create mode 100644 rocky/assets/js/components.js create mode 100644 rocky/components/main.scss create mode 100644 rocky/components/modal/README.md create mode 100644 rocky/components/modal/__init__.py create mode 100644 rocky/components/modal/modal.py create mode 100644 rocky/components/modal/script.js create mode 100644 rocky/components/modal/style.scss create mode 100644 rocky/components/modal/template.html diff --git a/rocky/Dockerfile b/rocky/Dockerfile index 093e020652e..9b7bd80e504 100644 --- a/rocky/Dockerfile +++ b/rocky/Dockerfile @@ -6,6 +6,7 @@ WORKDIR /app COPY rocky/package.json rocky/yarn.lock . COPY rocky/assets assets +COPY rocky/components components RUN yarn --ignore-engines && yarn build diff --git a/rocky/assets/css/main.scss b/rocky/assets/css/main.scss index dd925556535..d03d64c7ccf 100644 --- a/rocky/assets/css/main.scss +++ b/rocky/assets/css/main.scss @@ -9,17 +9,18 @@ /* Vendors */ @import "manon-components"; -@import "vendor_overrides/two-factor"; @import "vendor_overrides/graph-override"; +@import "vendor_overrides/manon/button-icon-only"; @import "vendor_overrides/manon/display-toggle"; @import "vendor_overrides/manon/dl"; +@import "vendor_overrides/manon/form-fieldset-required"; +@import "vendor_overrides/manon/form-radio"; @import "vendor_overrides/manon/layout-fifty-fifty"; @import "vendor_overrides/manon/layout-form"; @import "vendor_overrides/manon/nested-section"; -@import "vendor_overrides/manon/form-radio"; -@import "vendor_overrides/manon/form-fieldset-required"; @import "vendor_overrides/manon/table"; @import "vendor_overrides/manon/tile"; +@import "vendor_overrides/two-factor"; /* Theme */ @import "themes/soft/soft"; diff --git a/rocky/assets/css/manon-components.scss b/rocky/assets/css/manon-components.scss index 8030e39a35c..37df1152b18 100644 --- a/rocky/assets/css/manon-components.scss +++ b/rocky/assets/css/manon-components.scss @@ -92,6 +92,7 @@ @use "@minvws/manon/button-destructive"; @use "@minvws/manon/button-cta"; @use "@minvws/manon/button-icon"; +@use "@minvws/manon/button-icon-only"; @use "@minvws/manon/list-base"; @use "@minvws/manon/skip-to-content"; @use "@minvws/manon/button-container"; diff --git a/rocky/assets/css/vendor_overrides/manon/button-icon-only.scss b/rocky/assets/css/vendor_overrides/manon/button-icon-only.scss new file mode 100644 index 00000000000..de146cdc734 --- /dev/null +++ b/rocky/assets/css/vendor_overrides/manon/button-icon-only.scss @@ -0,0 +1,11 @@ +button, +a.button, +input[type="button"], +input[type="submit"], +input[type="reset"] { + &.icon-only { + &::before { + color: var(--link-text-color); + } + } +} diff --git a/rocky/assets/js/components.js b/rocky/assets/js/components.js new file mode 100644 index 00000000000..aeae682952e --- /dev/null +++ b/rocky/assets/js/components.js @@ -0,0 +1 @@ +import "/components/main.scss"; diff --git a/rocky/components/main.scss b/rocky/components/main.scss new file mode 100644 index 00000000000..2c598245c5d --- /dev/null +++ b/rocky/components/main.scss @@ -0,0 +1 @@ +@import "modal/style"; diff --git a/rocky/components/modal/README.md b/rocky/components/modal/README.md new file mode 100644 index 00000000000..9dad3585dbe --- /dev/null +++ b/rocky/components/modal/README.md @@ -0,0 +1,67 @@ +# Django Modal Component + +## Goal + +The goal of this Modal Component is to have a "one stop shop" solution for a modal dialog, with the HTML structure as a template, CSS styling in SASS, JS logic for its dynamics and Django for all data related logic all bundled into one solution. Utilizing the `django-component` third-party library, it enables us to implement modals easily in Django templates, wherever they're needed. By using `slot` and `fill` we have great content flexibility, while keeping the aforementioned topics like HTML structure, CSS and JS as DRY as possible. + +## Usage + +This outlines the basic usages and provides a code block example below, of how to implement the component in a Django template. + +### Instantiate + +First you need to add `{% load component_tags %}` at the top of your template. Next you need to add the following code block at the bottom, to include the corresponding JS (if you haven't already you also need to add `{% load compress %}`). + +``` +{% block html_at_end_body %} + {% compress js %} + + {% endcompress %} +{% endblock html_at_end_body %} +``` + +After that, `{% component "modal" size="xx" %}` is enough to instantiate the dialog modal component where size should contain the appropriate class name to achieve the correct sizing. This can be either `dialog-small`, `dialog-medium` or `dialog-large`. + +### Slots and fills + +Each named `fill` corresponds with a placeholder/target `slot` in the component template. The contents between the `fill` tag will be passed to the corresponding `slot`. As shown in the below example it's possible to utilise Django template tags and `HTML` tags with these `fill` tags. This enables us to entirely build the contents of the modal in the template where we implement it. Because we can use `HTML` tags here, we can also use `forms` and leave the handling of said form up to the Django template that knows about the context and applicable data, where we implement the modal. The defaults are used when no `fill` tags are implemented for this slot at all. + +There's a total of four slots you can fill: + +1. `trigger`: call to action `button` by default, with the caption "Open modal". +2. `header`: empty by default +3. `content`: empty by default +4. `footer_buttons`: cancel `button` by default. To have _no buttons_ show at all, it's needed to implement empty `fill` tags for this `slot`. + +### The trigger element + +The trigger `slot` is a special one. This needs to contain the HTML `element` that gets assigned the click handler by JavaScript. It's essential to include the `class="modal-trigger"` attribute, because this is what we target to assign the click handler, using JS. While it might seem obvious to use a `button` as a trigger, the modal is setup in a way that allows for any HTML element to be used as a trigger. + +### CSS dependencies + +Including `{% component_css_dependencies %}` is needed to inject the reference to the correct stylesheet needed to style the component into the HTML document. Configuring the location of said stylesheet is done in the components `.py` file. + +### Example implementation + +``` +{% component "modal" size="dialog-small" %} + {% fill "trigger" %} + + {% endfill %} + {% fill "header" %} + {% translate "This is an example header." %} + {% endfill %} + {% fill "content" %} +
+ {% csrf_token %} + {% blocktranslate %} +

You can use {{ context_data_variable }} and HTML here valid_time!

+ {% endblocktranslate %} +
+ {% endfill %} + {% fill "footer_buttons" %} + + {% endfill %} +{% endcomponent %} +{% component_css_dependencies %} +``` diff --git a/rocky/components/modal/__init__.py b/rocky/components/modal/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/rocky/components/modal/modal.py b/rocky/components/modal/modal.py new file mode 100644 index 00000000000..f3ad0d6dd6d --- /dev/null +++ b/rocky/components/modal/modal.py @@ -0,0 +1,14 @@ +from django_components import component + + +@component.register("modal") +class Modal(component.Component): + template_name = "modal/template.html" + + def get_context_data(self, **kwargs): + return { + "size": kwargs["size"], + } + + class Media: + css = "dist/components.css" diff --git a/rocky/components/modal/script.js b/rocky/components/modal/script.js new file mode 100644 index 00000000000..43add51d2d0 --- /dev/null +++ b/rocky/components/modal/script.js @@ -0,0 +1,28 @@ +import { onDomReady } from "../js/imports/utils.js"; + +onDomReady(initDialogs); + +export function initDialogs(element) { + let root = element || document; + let modal_components = root.querySelectorAll(".modal-wrapper"); + + modal_components.forEach((modal) => initDialog(modal)); +} + +export function initDialog(modal) { + modal.querySelector(".modal-trigger").addEventListener("click", (event) => { + // Used ".closest" instead of ".parentNode" to make sure we stay flexible in terms of + // HTML-structure when implementing the trigger. + event.target.closest(".modal-wrapper").querySelector("dialog").showModal(); + }); + + modal.querySelector("dialog").addEventListener("click", (event) => { + // event.target.nodeName === 'DIALOG' is needed to check if the ::backdrop is clicked. + if ( + event.target.nodeName === "DIALOG" || + event.target.classList.contains("close-modal-button") + ) { + event.target.closest(".modal-wrapper").querySelector("dialog").close(); + } + }); +} diff --git a/rocky/components/modal/style.scss b/rocky/components/modal/style.scss new file mode 100644 index 00000000000..30d55050990 --- /dev/null +++ b/rocky/components/modal/style.scss @@ -0,0 +1,82 @@ +dialog { + border: 1px solid var(--colors-grey-4); + border-radius: 8px; + max-height: calc(100vh - 3rem); + padding: 0; + + &.dialog-small { + width: 27.5rem; + + .content-wrapper { + .header, + .footer { + border: 0; + } + + .content { + padding-top: 0; + padding-bottom: 0; + } + } + } + + &.dialog-medium { + width: 50rem; + } + + &.dialog-large { + width: 71.25rem; + } + + &::backdrop { + background-color: rgb(18 21 23 / 50%); + } + + .content-wrapper { + display: flex; + flex-direction: column; + max-height: inherit; + position: relative; + + .header { + padding: 1.5rem; + display: flex; + justify-content: space-between; + flex-direction: row; + border-bottom: 1px solid var(--colors-grey-4); + position: sticky; + background-color: white; + top: 0; + left: 0; + right: 0; + + button { + margin-right: -1.5rem; + } + + h2 { + font-size: 1.5rem; + } + } + + .content { + padding: 1.5rem; + flex-grow: 1; + overflow: auto; + } + + .footer { + padding: 1.5rem; + border-top: 1px solid var(--colors-grey-4); + position: sticky; + background-color: white; + bottom: 0; + left: 0; + right: 0; + + .toolbar { + justify-content: flex-start; + } + } + } +} diff --git a/rocky/components/modal/template.html b/rocky/components/modal/template.html new file mode 100644 index 00000000000..226c280a735 --- /dev/null +++ b/rocky/components/modal/template.html @@ -0,0 +1,33 @@ +{% load static %} +{% load i18n %} +{% load compress %} + + diff --git a/rocky/poetry.lock b/rocky/poetry.lock index 54ed9666c09..71e7357e144 100644 --- a/rocky/poetry.lock +++ b/rocky/poetry.lock @@ -499,6 +499,20 @@ files = [ [package.dependencies] django = "*" +[[package]] +name = "django-components" +version = "0.80" +description = "A way to create simple reusable template components in Django." +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "django_components-0.80-py3-none-any.whl", hash = "sha256:c6067f24e6428c52f33727a2bf1b51a70d61ecae7286d4ff826ce85f6745f794"}, + {file = "django_components-0.80.tar.gz", hash = "sha256:a2ca8d7f308d5b54e83122331f137e2daa397b5f2e64d212f59334ca7af65dac"}, +] + +[package.dependencies] +Django = ">=4.2" + [[package]] name = "django_compressor" version = "4.4" @@ -3416,4 +3430,4 @@ test = ["pytest"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "605a5548f2c3d78a4f3dcc46e5c649ffb7937763ad5f391579a33f582a49e551" +content-hash = "20b560adc29a6680cfee2c5b0531359495d1cd516c1a97588c231ab478b08de0" diff --git a/rocky/pyproject.toml b/rocky/pyproject.toml index 6de012ec21c..2f314f85508 100644 --- a/rocky/pyproject.toml +++ b/rocky/pyproject.toml @@ -35,6 +35,7 @@ whitenoise = { extras = ["brotli"], version = "^6.5.0" } opentelemetry-instrumentation = "^0.45b0" opentelemetry-instrumentation-fastapi = "^0.45b0" granian = "^1.3.2" +django-components = "^0.80" # These used in octopoes parts that are used by rocky pyparsing = "^3.1.1" diff --git a/rocky/requirements-dev.txt b/rocky/requirements-dev.txt index cdfa77ca79f..dd9a5744a8f 100644 --- a/rocky/requirements-dev.txt +++ b/rocky/requirements-dev.txt @@ -255,6 +255,9 @@ django-admin-auto-tests @ git+https://github.com/dekkers/django-admin-auto-tests django-appconf==1.0.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c3ae442fba1ff7ec830412c5184b17169a7a1e71cf0864a4c3f93cf4c98a1993 \ --hash=sha256:cfe87ea827c4ee04b9a70fab90b86d704cb02f2981f89da8423cb0fabf88efbf +django-components==0.80 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a2ca8d7f308d5b54e83122331f137e2daa397b5f2e64d212f59334ca7af65dac \ + --hash=sha256:c6067f24e6428c52f33727a2bf1b51a70d61ecae7286d4ff826ce85f6745f794 django-compressor @ git+https://github.com/dekkers/django-compressor@620bc0ab86590f8981dd24456a70951c9bdbf91f ; python_version >= "3.10" and python_version < "4.0" django-csp==3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:01443a07723f9a479d498bd7bb63571aaa771e690f64bde515db6cdb76e8041a \ diff --git a/rocky/requirements.txt b/rocky/requirements.txt index 8daf5ea569d..4e14a490dbd 100644 --- a/rocky/requirements.txt +++ b/rocky/requirements.txt @@ -196,6 +196,9 @@ deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \ django-appconf==1.0.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c3ae442fba1ff7ec830412c5184b17169a7a1e71cf0864a4c3f93cf4c98a1993 \ --hash=sha256:cfe87ea827c4ee04b9a70fab90b86d704cb02f2981f89da8423cb0fabf88efbf +django-components==0.80 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a2ca8d7f308d5b54e83122331f137e2daa397b5f2e64d212f59334ca7af65dac \ + --hash=sha256:c6067f24e6428c52f33727a2bf1b51a70d61ecae7286d4ff826ce85f6745f794 django-compressor @ git+https://github.com/dekkers/django-compressor@620bc0ab86590f8981dd24456a70951c9bdbf91f ; python_version >= "3.10" and python_version < "4.0" django-csp==3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:01443a07723f9a479d498bd7bb63571aaa771e690f64bde515db6cdb76e8041a \ diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 545c935fb28..6f3f1d846fc 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -564,6 +564,22 @@ msgid "" "We couldn't send a password reset link. Contact your system administrator." msgstr "" +#: components/modal/template.html +msgid "Close modal" +msgstr "" + +#: components/modal/template.html +#: katalogus/templates/change_clearance_level.html +#: katalogus/templates/confirmation_clone_settings.html +#: katalogus/templates/plugin_settings_delete.html +#: rocky/templates/oois/ooi_delete.html +#: rocky/templates/oois/ooi_mute_finding.html +#: rocky/templates/organizations/organization_edit.html +#: rocky/templates/organizations/organization_member_edit.html +#: rocky/templates/two_factor/_wizard_actions.html +msgid "Cancel" +msgstr "" + #: crisis_room/views.py msgid "" "Failed to get list of findings for organization {}, check server logs for " @@ -744,17 +760,6 @@ msgstr "" msgid "Scan" msgstr "" -#: katalogus/templates/change_clearance_level.html -#: katalogus/templates/confirmation_clone_settings.html -#: katalogus/templates/plugin_settings_delete.html -#: rocky/templates/oois/ooi_delete.html -#: rocky/templates/oois/ooi_mute_finding.html -#: rocky/templates/organizations/organization_edit.html -#: rocky/templates/organizations/organization_member_edit.html -#: rocky/templates/two_factor/_wizard_actions.html -msgid "Cancel" -msgstr "" - #: katalogus/templates/clone_settings.html #: katalogus/templates/confirmation_clone_settings.html msgid "Clone settings" diff --git a/rocky/rocky/settings.py b/rocky/rocky/settings.py index b5cec6b8754..871dad53eeb 100644 --- a/rocky/rocky/settings.py +++ b/rocky/rocky/settings.py @@ -148,8 +148,9 @@ "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", - "django.contrib.staticfiles", "django.forms", + "django_components", + "django_components.safer_staticfiles", "django_otp", "django_otp.plugins.otp_static", "django_otp.plugins.otp_totp", @@ -201,7 +202,6 @@ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [BASE_DIR / "rocky/templates", BASE_DIR / "reports/report_types"], - "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.debug", @@ -213,7 +213,17 @@ "tools.context_processors.organizations_including_blocked", "tools.context_processors.rocky_version", ], - "builtins": ["tools.templatetags.ooi_extra"], + "builtins": ["django_components.templatetags.component_tags", "tools.templatetags.ooi_extra"], + "loaders": [ + ( + "django.template.loaders.cached.Loader", + [ + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + "django_components.template_loader.Loader", + ], + ) + ], }, }, ] @@ -327,7 +337,7 @@ STATIC_URL = "/static/" STATIC_ROOT = env.path("STATIC_ROOT", BASE_DIR / "static") -STATICFILES_DIRS = (BASE_DIR / "assets",) +STATICFILES_DIRS = (BASE_DIR / "assets", BASE_DIR / "components") STATICFILES_FINDERS = [ "django.contrib.staticfiles.finders.FileSystemFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder", From 0008fb81e2c6d2b73259c2c387a90f07d6aafda0 Mon Sep 17 00:00:00 2001 From: ammar92 Date: Fri, 19 Jul 2024 11:03:45 +0200 Subject: [PATCH 024/112] Upgrade packages (#3259) --- boefjes/poetry.lock | 425 ++++++++++++++++++---------------- boefjes/pyproject.toml | 26 +-- boefjes/requirements-dev.txt | 356 ++++++++++++++-------------- boefjes/requirements.txt | 356 ++++++++++++++-------------- bytes/poetry.lock | 425 ++++++++++++++++++---------------- bytes/pyproject.toml | 26 +-- bytes/requirements-dev.txt | 356 ++++++++++++++-------------- bytes/requirements.txt | 356 ++++++++++++++-------------- keiko/poetry.lock | 354 ++++++++++++++-------------- keiko/pyproject.toml | 14 +- keiko/requirements-dev.txt | 269 ++++++++++----------- keiko/requirements.txt | 263 +++++++++++---------- mula/poetry.lock | 208 +++++++++-------- mula/requirements-dev.txt | 194 ++++++++-------- mula/requirements.txt | 194 ++++++++-------- octopoes/poetry.lock | 359 ++++++++++++++-------------- octopoes/pyproject.toml | 26 +-- octopoes/requirements-dev.txt | 290 ++++++++++++----------- octopoes/requirements.txt | 290 ++++++++++++----------- poetry.lock | 237 ++++++++++--------- requirements.txt | 206 ++++++++-------- rocky/poetry.lock | 373 +++++++++++++++-------------- rocky/pyproject.toml | 30 +-- rocky/requirements-dev.txt | 290 ++++++++++++----------- rocky/requirements.txt | 290 ++++++++++++----------- 25 files changed, 3210 insertions(+), 3003 deletions(-) diff --git a/boefjes/poetry.lock b/boefjes/poetry.lock index 1d16b1e3421..4c94dba54ea 100644 --- a/boefjes/poetry.lock +++ b/boefjes/poetry.lock @@ -512,43 +512,43 @@ testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", [[package]] name = "cryptography" -version = "42.0.5" +version = "42.0.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16"}, - {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da"}, - {file = "cryptography-42.0.5-cp37-abi3-win32.whl", hash = "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74"}, - {file = "cryptography-42.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940"}, - {file = "cryptography-42.0.5-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30"}, - {file = "cryptography-42.0.5-cp39-abi3-win32.whl", hash = "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413"}, - {file = "cryptography-42.0.5-cp39-abi3-win_amd64.whl", hash = "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd"}, - {file = "cryptography-42.0.5.tar.gz", hash = "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, + {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, + {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, + {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, + {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, + {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, + {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, ] [package.dependencies] @@ -661,13 +661,13 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi-slim" -version = "0.111.0" +version = "0.111.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi_slim-0.111.0-py3-none-any.whl", hash = "sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2"}, - {file = "fastapi_slim-0.111.0.tar.gz", hash = "sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec"}, + {file = "fastapi_slim-0.111.1-py3-none-any.whl", hash = "sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb"}, + {file = "fastapi_slim-0.111.1.tar.gz", hash = "sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d"}, ] [package.dependencies] @@ -677,7 +677,7 @@ typing-extensions = ">=4.8.0" [package.extras] all = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.7)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "filelock" @@ -1434,42 +1434,42 @@ files = [ [[package]] name = "opentelemetry-api" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.24.0-py3-none-any.whl", hash = "sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2"}, - {file = "opentelemetry_api-1.24.0.tar.gz", hash = "sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e"}, + {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, + {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.0" +importlib-metadata = ">=6.0,<=7.1" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Protobuf encoding" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0-py3-none-any.whl", hash = "sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0.tar.gz", hash = "sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, ] [package.dependencies] -opentelemetry-proto = "1.24.0" +opentelemetry-proto = "1.25.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0-py3-none-any.whl", hash = "sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0.tar.gz", hash = "sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, ] [package.dependencies] @@ -1477,22 +1477,19 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.24.0" -opentelemetry-proto = "1.24.0" -opentelemetry-sdk = ">=1.24.0,<1.25.0" - -[package.extras] -test = ["pytest-grpc"] +opentelemetry-exporter-otlp-proto-common = "1.25.0" +opentelemetry-proto = "1.25.0" +opentelemetry-sdk = ">=1.25.0,<1.26.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.45b0" +version = "0.46b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.45b0-py3-none-any.whl", hash = "sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258"}, - {file = "opentelemetry_instrumentation-0.45b0.tar.gz", hash = "sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e"}, + {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, + {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, ] [package.dependencies] @@ -1502,111 +1499,111 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.45b0" +version = "0.46b0" description = "ASGI instrumentation for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_asgi-0.45b0-py3-none-any.whl", hash = "sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b"}, - {file = "opentelemetry_instrumentation_asgi-0.45b0.tar.gz", hash = "sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6"}, + {file = "opentelemetry_instrumentation_asgi-0.46b0-py3-none-any.whl", hash = "sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759"}, + {file = "opentelemetry_instrumentation_asgi-0.46b0.tar.gz", hash = "sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a"}, ] [package.dependencies] asgiref = ">=3.0,<4.0" opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["asgiref (>=3.0,<4.0)"] [[package]] name = "opentelemetry-instrumentation-dbapi" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry Database API instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_dbapi-0.45b0-py3-none-any.whl", hash = "sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618"}, - {file = "opentelemetry_instrumentation_dbapi-0.45b0.tar.gz", hash = "sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c"}, + {file = "opentelemetry_instrumentation_dbapi-0.46b0-py3-none-any.whl", hash = "sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783"}, + {file = "opentelemetry_instrumentation_dbapi-0.46b0.tar.gz", hash = "sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry FastAPI Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_fastapi-0.45b0-py3-none-any.whl", hash = "sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314"}, - {file = "opentelemetry_instrumentation_fastapi-0.45b0.tar.gz", hash = "sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e"}, + {file = "opentelemetry_instrumentation_fastapi-0.46b0-py3-none-any.whl", hash = "sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33"}, + {file = "opentelemetry_instrumentation_fastapi-0.46b0.tar.gz", hash = "sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-instrumentation-asgi = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-instrumentation-asgi = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["fastapi (>=0.58,<1.0)"] [[package]] name = "opentelemetry-instrumentation-psycopg2" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry psycopg2 instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_psycopg2-0.45b0-py3-none-any.whl", hash = "sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7"}, - {file = "opentelemetry_instrumentation_psycopg2-0.45b0.tar.gz", hash = "sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0"}, + {file = "opentelemetry_instrumentation_psycopg2-0.46b0-py3-none-any.whl", hash = "sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899"}, + {file = "opentelemetry_instrumentation_psycopg2-0.46b0.tar.gz", hash = "sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-instrumentation-dbapi = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-instrumentation-dbapi = "0.46b0" [package.extras] instruments = ["psycopg2 (>=2.7.3.1)"] [[package]] name = "opentelemetry-instrumentation-requests" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry requests instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_requests-0.45b0-py3-none-any.whl", hash = "sha256:275851d04de518507b0411b98524602101b228b72e61f39dc627c0421ff2a81f"}, - {file = "opentelemetry_instrumentation_requests-0.45b0.tar.gz", hash = "sha256:6bf1359284105ab50fa7465ea6c60b4a62c699408cb0260af3ac8895e8a7451a"}, + {file = "opentelemetry_instrumentation_requests-0.46b0-py3-none-any.whl", hash = "sha256:a8c2472800d8686f3f286cd524b8746b386154092e85a791ba14110d1acc9b81"}, + {file = "opentelemetry_instrumentation_requests-0.46b0.tar.gz", hash = "sha256:ef0ad63bfd0d52631daaf7d687e763dbd89b465f5cb052f12a4e67e5e3d181e4"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["requests (>=2.0,<3.0)"] [[package]] name = "opentelemetry-proto" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python Proto" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.24.0-py3-none-any.whl", hash = "sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce"}, - {file = "opentelemetry_proto-1.24.0.tar.gz", hash = "sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8"}, + {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, + {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, ] [package.dependencies] @@ -1614,40 +1611,43 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.24.0-py3-none-any.whl", hash = "sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59"}, - {file = "opentelemetry_sdk-1.24.0.tar.gz", hash = "sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5"}, + {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, + {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, ] [package.dependencies] -opentelemetry-api = "1.24.0" -opentelemetry-semantic-conventions = "0.45b0" +opentelemetry-api = "1.25.0" +opentelemetry-semantic-conventions = "0.46b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.45b0-py3-none-any.whl", hash = "sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864"}, - {file = "opentelemetry_semantic_conventions-0.45b0.tar.gz", hash = "sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118"}, + {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, + {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, ] +[package.dependencies] +opentelemetry-api = "1.25.0" + [[package]] name = "opentelemetry-util-http" -version = "0.45b0" +version = "0.46b0" description = "Web util for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_util_http-0.45b0-py3-none-any.whl", hash = "sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33"}, - {file = "opentelemetry_util_http-0.45b0.tar.gz", hash = "sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd"}, + {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"}, + {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"}, ] [[package]] @@ -1856,109 +1856,122 @@ files = [ [[package]] name = "pydantic" -version = "2.7.1" +version = "2.8.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"}, - {file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"}, + {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, + {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.18.2" -typing-extensions = ">=4.6.1" +pydantic-core = "2.20.1" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] [package.extras] email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.18.2" +version = "2.20.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"}, - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"}, - {file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"}, - {file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"}, - {file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"}, - {file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"}, - {file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"}, - {file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"}, - {file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"}, - {file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"}, - {file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"}, - {file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"}, - {file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"}, - {file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"}, - {file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, + {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, + {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, + {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, + {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, + {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, + {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, + {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, + {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, + {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, + {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, + {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, + {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, + {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, ] [package.dependencies] @@ -1966,17 +1979,17 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.2.1" +version = "2.3.4" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"}, - {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"}, + {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, + {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, ] [package.dependencies] -pydantic = ">=2.3.0" +pydantic = ">=2.7.0" python-dotenv = ">=0.21.0" [package.extras] @@ -2205,13 +2218,13 @@ rpds-py = ">=0.7.0" [[package]] name = "requests" -version = "2.32.2" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, - {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -2382,19 +2395,19 @@ requests = "*" [[package]] name = "setuptools" -version = "69.1.0" +version = "71.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, - {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, + {file = "setuptools-71.0.3-py3-none-any.whl", hash = "sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207"}, + {file = "setuptools-71.0.3.tar.gz", hash = "sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (<7.4)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "shodan" @@ -2523,18 +2536,18 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "structlog" -version = "24.2.0" +version = "24.4.0" description = "Structured Logging for Python" optional = false python-versions = ">=3.8" files = [ - {file = "structlog-24.2.0-py3-none-any.whl", hash = "sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a"}, - {file = "structlog-24.2.0.tar.gz", hash = "sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b"}, + {file = "structlog-24.4.0-py3-none-any.whl", hash = "sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610"}, + {file = "structlog-24.4.0.tar.gz", hash = "sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4"}, ] [package.extras] dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] typing = ["mypy (>=1.4)", "rich", "twisted"] @@ -2568,13 +2581,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.11.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -2854,4 +2867,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "6f319dcf4745799025f981e4b04c31e8b07c57a21abfde2cb7ecc4740c19bcb3" +content-hash = "ceca67cd5b37f76d5657ab8bf5e5bb9452ff15071fa08d55a0d02a1e67acd9d3" diff --git a/boefjes/pyproject.toml b/boefjes/pyproject.toml index de6becc599d..ccd0bf7d8fa 100644 --- a/boefjes/pyproject.toml +++ b/boefjes/pyproject.toml @@ -18,12 +18,12 @@ pynacl = "^1.5.0" sqlalchemy = "^1.4.48" python-dateutil = "^2.8.2" pydantic-settings = "^2.2.1" -opentelemetry-sdk = "^1.24.0" -opentelemetry-exporter-otlp-proto-grpc = "^1.24.0" -opentelemetry-instrumentation-fastapi = "^0.45b0" -opentelemetry-instrumentation-psycopg2 = "^0.45b0" -opentelemetry-instrumentation-requests = "^0.45b0" -opentelemetry-instrumentation = "^0.45b0" +opentelemetry-sdk = "^1.25.0" +opentelemetry-exporter-otlp-proto-grpc = "^1.25.0" +opentelemetry-instrumentation-fastapi = "^0.46b0" +opentelemetry-instrumentation-psycopg2 = "^0.46b0" +opentelemetry-instrumentation-requests = "^0.46b0" +opentelemetry-instrumentation = "^0.46b0" # required by kat_snyk, kat_crt_sh, kat_crt_sh boefjes requests = "^2.32.1" # required by kat_binaryedge boefje @@ -62,13 +62,13 @@ defusedxml = "^0.7.1" # required by kat_webpage_analysis/check_images normalizer pillow = "^10.3.0" httpx = "^0.27.0" -opentelemetry-api = "^1.24.0" -opentelemetry-exporter-otlp-proto-common = "^1.24.0" -opentelemetry-instrumentation-asgi = "^0.45b0" -opentelemetry-instrumentation-dbapi = "^0.45b0" -opentelemetry-proto = "^1.24.0" -opentelemetry-semantic-conventions = "^0.45b0" -opentelemetry-util-http = "^0.45b0" +opentelemetry-api = "^1.25.0" +opentelemetry-exporter-otlp-proto-common = "^1.25.0" +opentelemetry-instrumentation-asgi = "^0.46b0" +opentelemetry-instrumentation-dbapi = "^0.46b0" +opentelemetry-proto = "^1.25.0" +opentelemetry-semantic-conventions = "^0.46b0" +opentelemetry-util-http = "^0.46b0" fastapi-slim = "^0.111.0" structlog = "^24.2.0" diff --git a/boefjes/requirements-dev.txt b/boefjes/requirements-dev.txt index 885c62a5929..e318b297e05 100644 --- a/boefjes/requirements-dev.txt +++ b/boefjes/requirements-dev.txt @@ -270,39 +270,39 @@ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" \ configparser==6.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:900ea2bb01b2540b1a644ad3d5351e9b961a4a012d4732f619375fb8f641ee19 \ --hash=sha256:ec914ab1e56c672de1f5c3483964e68f71b34e457904b7b76e06b922aec067a8 -cryptography==42.0.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee \ - --hash=sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576 \ - --hash=sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d \ - --hash=sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30 \ - --hash=sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413 \ - --hash=sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb \ - --hash=sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da \ - --hash=sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4 \ - --hash=sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd \ - --hash=sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc \ - --hash=sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8 \ - --hash=sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1 \ - --hash=sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc \ - --hash=sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e \ - --hash=sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8 \ - --hash=sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940 \ - --hash=sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400 \ - --hash=sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7 \ - --hash=sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16 \ - --hash=sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278 \ - --hash=sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74 \ - --hash=sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec \ - --hash=sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1 \ - --hash=sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2 \ - --hash=sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c \ - --hash=sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922 \ - --hash=sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a \ - --hash=sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6 \ - --hash=sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1 \ - --hash=sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e \ - --hash=sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac \ - --hash=sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7 +cryptography==42.0.8 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ + --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ + --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ + --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ + --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ + --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ + --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ + --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ + --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ + --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ + --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ + --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ + --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ + --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ + --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ + --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ + --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ + --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ + --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ + --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ + --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ + --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ + --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ + --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ + --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ + --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ + --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ + --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ + --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ + --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ + --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ + --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e decorator==5.1.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330 \ --hash=sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186 @@ -321,9 +321,9 @@ docker==7.1.0 ; python_version >= "3.10" and python_version < "4.0" \ exceptiongroup==1.2.0 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14 \ --hash=sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68 -fastapi-slim==0.111.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec \ - --hash=sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2 +fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ + --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d filelock==3.13.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e \ --hash=sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c @@ -797,45 +797,45 @@ multidict==6.0.5 ; python_version >= "3.10" and python_version < "4.0" \ netaddr==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5148b1055679d2a1ec070c521b7db82137887fabd6d7e37f5199b44f775c3bb1 \ --hash=sha256:7b46fa9b1a2d71fd5de9e4a3784ef339700a53a08c8040f08baf5f1194da0128 -opentelemetry-api==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2 \ - --hash=sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e -opentelemetry-exporter-otlp-proto-common==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461 \ - --hash=sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641 -opentelemetry-exporter-otlp-proto-grpc==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa \ - --hash=sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b -opentelemetry-instrumentation-asgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b \ - --hash=sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6 -opentelemetry-instrumentation-dbapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618 \ - --hash=sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c -opentelemetry-instrumentation-fastapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e \ - --hash=sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314 -opentelemetry-instrumentation-psycopg2==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7 \ - --hash=sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0 -opentelemetry-instrumentation-requests==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:275851d04de518507b0411b98524602101b228b72e61f39dc627c0421ff2a81f \ - --hash=sha256:6bf1359284105ab50fa7465ea6c60b4a62c699408cb0260af3ac8895e8a7451a -opentelemetry-instrumentation==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258 \ - --hash=sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e -opentelemetry-proto==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce \ - --hash=sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8 -opentelemetry-sdk==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5 \ - --hash=sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59 -opentelemetry-semantic-conventions==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118 \ - --hash=sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864 -opentelemetry-util-http==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd \ - --hash=sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33 +opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ + --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 +opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ + --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 +opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ + --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac +opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ + --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 +opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ + --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 +opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ + --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 +opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ + --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c +opentelemetry-instrumentation-requests==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a8c2472800d8686f3f286cd524b8746b386154092e85a791ba14110d1acc9b81 \ + --hash=sha256:ef0ad63bfd0d52631daaf7d687e763dbd89b465f5cb052f12a4e67e5e3d181e4 +opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ + --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda +opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ + --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f +opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ + --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 +opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ + --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa +opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ + --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 @@ -948,92 +948,102 @@ pybinaryedge==0.5 ; python_version >= "3.10" and python_version < "4.0" \ pycparser==2.21 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 -pydantic-core==2.18.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b \ - --hash=sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a \ - --hash=sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90 \ - --hash=sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d \ - --hash=sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e \ - --hash=sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d \ - --hash=sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027 \ - --hash=sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804 \ - --hash=sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347 \ - --hash=sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400 \ - --hash=sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3 \ - --hash=sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399 \ - --hash=sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349 \ - --hash=sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd \ - --hash=sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c \ - --hash=sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e \ - --hash=sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413 \ - --hash=sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3 \ - --hash=sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e \ - --hash=sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3 \ - --hash=sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91 \ - --hash=sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce \ - --hash=sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c \ - --hash=sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb \ - --hash=sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664 \ - --hash=sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6 \ - --hash=sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd \ - --hash=sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3 \ - --hash=sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af \ - --hash=sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043 \ - --hash=sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350 \ - --hash=sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7 \ - --hash=sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0 \ - --hash=sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563 \ - --hash=sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761 \ - --hash=sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72 \ - --hash=sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3 \ - --hash=sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb \ - --hash=sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788 \ - --hash=sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b \ - --hash=sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c \ - --hash=sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038 \ - --hash=sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250 \ - --hash=sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec \ - --hash=sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c \ - --hash=sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74 \ - --hash=sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81 \ - --hash=sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439 \ - --hash=sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75 \ - --hash=sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0 \ - --hash=sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8 \ - --hash=sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150 \ - --hash=sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438 \ - --hash=sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae \ - --hash=sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857 \ - --hash=sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038 \ - --hash=sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374 \ - --hash=sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f \ - --hash=sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241 \ - --hash=sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592 \ - --hash=sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4 \ - --hash=sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d \ - --hash=sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b \ - --hash=sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b \ - --hash=sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182 \ - --hash=sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e \ - --hash=sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641 \ - --hash=sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70 \ - --hash=sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9 \ - --hash=sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a \ - --hash=sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543 \ - --hash=sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b \ - --hash=sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f \ - --hash=sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38 \ - --hash=sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845 \ - --hash=sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2 \ - --hash=sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0 \ - --hash=sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4 \ - --hash=sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242 -pydantic-settings==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ - --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 -pydantic==2.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5 \ - --hash=sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pydicom==2.4.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 @@ -1089,9 +1099,9 @@ referencing==0.33.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7 requests-file==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 -requests==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ - --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c +requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 rich==13.7.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \ --hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235 @@ -1198,9 +1208,9 @@ rpds-py==0.18.0 ; python_version >= "3.10" and python_version < "4.0" \ sectxt==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c5b113cb37ec5053bf8ea335306a7c68079b53959df2324ffa9991885bec67a8 \ --hash=sha256:c81d874a55b96516d13e2b688f3150a6089e0636122237e4710717beafcb26d7 -setuptools==69.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401 \ - --hash=sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 shodan==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:7e2bddbc1b60bf620042d0010f4b762a80b43111dbea9c041d72d4325e260c23 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ @@ -1241,18 +1251,18 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 -structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ - --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a +structlog==24.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610 \ + --hash=sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4 tldextract==3.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2cb271ca8d06ea1630a1361b58edad14e0cf81f34ce3c90b052854528fe2a281 \ --hash=sha256:4df1c65b95be61d59428e8611e955e54e6f1d4483d3e8d5733d3a9062155e910 tomli==2.0.1 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f -typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ - --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a +typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 urllib3==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 diff --git a/boefjes/requirements.txt b/boefjes/requirements.txt index 8a82a442240..567e74596e3 100644 --- a/boefjes/requirements.txt +++ b/boefjes/requirements.txt @@ -270,39 +270,39 @@ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" \ configparser==6.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:900ea2bb01b2540b1a644ad3d5351e9b961a4a012d4732f619375fb8f641ee19 \ --hash=sha256:ec914ab1e56c672de1f5c3483964e68f71b34e457904b7b76e06b922aec067a8 -cryptography==42.0.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee \ - --hash=sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576 \ - --hash=sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d \ - --hash=sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30 \ - --hash=sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413 \ - --hash=sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb \ - --hash=sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da \ - --hash=sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4 \ - --hash=sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd \ - --hash=sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc \ - --hash=sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8 \ - --hash=sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1 \ - --hash=sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc \ - --hash=sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e \ - --hash=sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8 \ - --hash=sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940 \ - --hash=sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400 \ - --hash=sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7 \ - --hash=sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16 \ - --hash=sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278 \ - --hash=sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74 \ - --hash=sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec \ - --hash=sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1 \ - --hash=sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2 \ - --hash=sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c \ - --hash=sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922 \ - --hash=sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a \ - --hash=sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6 \ - --hash=sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1 \ - --hash=sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e \ - --hash=sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac \ - --hash=sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7 +cryptography==42.0.8 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ + --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ + --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ + --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ + --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ + --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ + --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ + --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ + --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ + --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ + --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ + --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ + --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ + --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ + --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ + --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ + --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ + --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ + --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ + --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ + --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ + --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ + --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ + --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ + --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ + --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ + --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ + --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ + --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ + --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ + --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ + --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e decorator==5.1.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330 \ --hash=sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186 @@ -321,9 +321,9 @@ docker==7.1.0 ; python_version >= "3.10" and python_version < "4.0" \ exceptiongroup==1.2.0 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14 \ --hash=sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68 -fastapi-slim==0.111.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec \ - --hash=sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2 +fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ + --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d filelock==3.13.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e \ --hash=sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c @@ -794,45 +794,45 @@ multidict==6.0.5 ; python_version >= "3.10" and python_version < "4.0" \ netaddr==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5148b1055679d2a1ec070c521b7db82137887fabd6d7e37f5199b44f775c3bb1 \ --hash=sha256:7b46fa9b1a2d71fd5de9e4a3784ef339700a53a08c8040f08baf5f1194da0128 -opentelemetry-api==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2 \ - --hash=sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e -opentelemetry-exporter-otlp-proto-common==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461 \ - --hash=sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641 -opentelemetry-exporter-otlp-proto-grpc==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa \ - --hash=sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b -opentelemetry-instrumentation-asgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b \ - --hash=sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6 -opentelemetry-instrumentation-dbapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618 \ - --hash=sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c -opentelemetry-instrumentation-fastapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e \ - --hash=sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314 -opentelemetry-instrumentation-psycopg2==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7 \ - --hash=sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0 -opentelemetry-instrumentation-requests==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:275851d04de518507b0411b98524602101b228b72e61f39dc627c0421ff2a81f \ - --hash=sha256:6bf1359284105ab50fa7465ea6c60b4a62c699408cb0260af3ac8895e8a7451a -opentelemetry-instrumentation==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258 \ - --hash=sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e -opentelemetry-proto==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce \ - --hash=sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8 -opentelemetry-sdk==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5 \ - --hash=sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59 -opentelemetry-semantic-conventions==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118 \ - --hash=sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864 -opentelemetry-util-http==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd \ - --hash=sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33 +opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ + --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 +opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ + --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 +opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ + --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac +opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ + --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 +opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ + --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 +opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ + --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 +opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ + --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c +opentelemetry-instrumentation-requests==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a8c2472800d8686f3f286cd524b8746b386154092e85a791ba14110d1acc9b81 \ + --hash=sha256:ef0ad63bfd0d52631daaf7d687e763dbd89b465f5cb052f12a4e67e5e3d181e4 +opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ + --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda +opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ + --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f +opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ + --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 +opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ + --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa +opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ + --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 @@ -942,92 +942,102 @@ pybinaryedge==0.5 ; python_version >= "3.10" and python_version < "4.0" \ pycparser==2.21 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 -pydantic-core==2.18.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b \ - --hash=sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a \ - --hash=sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90 \ - --hash=sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d \ - --hash=sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e \ - --hash=sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d \ - --hash=sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027 \ - --hash=sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804 \ - --hash=sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347 \ - --hash=sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400 \ - --hash=sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3 \ - --hash=sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399 \ - --hash=sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349 \ - --hash=sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd \ - --hash=sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c \ - --hash=sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e \ - --hash=sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413 \ - --hash=sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3 \ - --hash=sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e \ - --hash=sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3 \ - --hash=sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91 \ - --hash=sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce \ - --hash=sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c \ - --hash=sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb \ - --hash=sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664 \ - --hash=sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6 \ - --hash=sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd \ - --hash=sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3 \ - --hash=sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af \ - --hash=sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043 \ - --hash=sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350 \ - --hash=sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7 \ - --hash=sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0 \ - --hash=sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563 \ - --hash=sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761 \ - --hash=sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72 \ - --hash=sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3 \ - --hash=sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb \ - --hash=sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788 \ - --hash=sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b \ - --hash=sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c \ - --hash=sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038 \ - --hash=sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250 \ - --hash=sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec \ - --hash=sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c \ - --hash=sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74 \ - --hash=sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81 \ - --hash=sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439 \ - --hash=sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75 \ - --hash=sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0 \ - --hash=sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8 \ - --hash=sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150 \ - --hash=sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438 \ - --hash=sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae \ - --hash=sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857 \ - --hash=sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038 \ - --hash=sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374 \ - --hash=sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f \ - --hash=sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241 \ - --hash=sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592 \ - --hash=sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4 \ - --hash=sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d \ - --hash=sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b \ - --hash=sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b \ - --hash=sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182 \ - --hash=sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e \ - --hash=sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641 \ - --hash=sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70 \ - --hash=sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9 \ - --hash=sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a \ - --hash=sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543 \ - --hash=sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b \ - --hash=sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f \ - --hash=sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38 \ - --hash=sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845 \ - --hash=sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2 \ - --hash=sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0 \ - --hash=sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4 \ - --hash=sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242 -pydantic-settings==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ - --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 -pydantic==2.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5 \ - --hash=sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pydicom==2.4.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 @@ -1077,9 +1087,9 @@ referencing==0.33.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7 requests-file==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 -requests==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ - --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c +requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 rich==13.7.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \ --hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235 @@ -1186,9 +1196,9 @@ rpds-py==0.18.0 ; python_version >= "3.10" and python_version < "4.0" \ sectxt==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c5b113cb37ec5053bf8ea335306a7c68079b53959df2324ffa9991885bec67a8 \ --hash=sha256:c81d874a55b96516d13e2b688f3150a6089e0636122237e4710717beafcb26d7 -setuptools==69.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401 \ - --hash=sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 shodan==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:7e2bddbc1b60bf620042d0010f4b762a80b43111dbea9c041d72d4325e260c23 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ @@ -1229,15 +1239,15 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 -structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ - --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a +structlog==24.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610 \ + --hash=sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4 tldextract==3.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2cb271ca8d06ea1630a1361b58edad14e0cf81f34ce3c90b052854528fe2a281 \ --hash=sha256:4df1c65b95be61d59428e8611e955e54e6f1d4483d3e8d5733d3a9062155e910 -typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ - --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a +typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 urllib3==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 diff --git a/bytes/poetry.lock b/bytes/poetry.lock index f3cd9d0a27f..4795e6c1abc 100644 --- a/bytes/poetry.lock +++ b/bytes/poetry.lock @@ -321,43 +321,43 @@ files = [ [[package]] name = "cryptography" -version = "42.0.5" +version = "42.0.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16"}, - {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da"}, - {file = "cryptography-42.0.5-cp37-abi3-win32.whl", hash = "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74"}, - {file = "cryptography-42.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940"}, - {file = "cryptography-42.0.5-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30"}, - {file = "cryptography-42.0.5-cp39-abi3-win32.whl", hash = "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413"}, - {file = "cryptography-42.0.5-cp39-abi3-win_amd64.whl", hash = "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd"}, - {file = "cryptography-42.0.5.tar.gz", hash = "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, + {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, + {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, + {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, + {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, + {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, + {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, ] [package.dependencies] @@ -406,13 +406,13 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi-slim" -version = "0.111.0" +version = "0.111.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi_slim-0.111.0-py3-none-any.whl", hash = "sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2"}, - {file = "fastapi_slim-0.111.0.tar.gz", hash = "sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec"}, + {file = "fastapi_slim-0.111.1-py3-none-any.whl", hash = "sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb"}, + {file = "fastapi_slim-0.111.1.tar.gz", hash = "sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d"}, ] [package.dependencies] @@ -422,7 +422,7 @@ typing-extensions = ">=4.8.0" [package.extras] all = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.7)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "googleapis-common-protos" @@ -765,42 +765,42 @@ files = [ [[package]] name = "opentelemetry-api" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.24.0-py3-none-any.whl", hash = "sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2"}, - {file = "opentelemetry_api-1.24.0.tar.gz", hash = "sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e"}, + {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, + {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.0" +importlib-metadata = ">=6.0,<=7.1" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Protobuf encoding" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0-py3-none-any.whl", hash = "sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0.tar.gz", hash = "sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, ] [package.dependencies] -opentelemetry-proto = "1.24.0" +opentelemetry-proto = "1.25.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0-py3-none-any.whl", hash = "sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0.tar.gz", hash = "sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, ] [package.dependencies] @@ -808,22 +808,19 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.24.0" -opentelemetry-proto = "1.24.0" -opentelemetry-sdk = ">=1.24.0,<1.25.0" - -[package.extras] -test = ["pytest-grpc"] +opentelemetry-exporter-otlp-proto-common = "1.25.0" +opentelemetry-proto = "1.25.0" +opentelemetry-sdk = ">=1.25.0,<1.26.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.45b0" +version = "0.46b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.45b0-py3-none-any.whl", hash = "sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258"}, - {file = "opentelemetry_instrumentation-0.45b0.tar.gz", hash = "sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e"}, + {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, + {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, ] [package.dependencies] @@ -833,111 +830,111 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.45b0" +version = "0.46b0" description = "ASGI instrumentation for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_asgi-0.45b0-py3-none-any.whl", hash = "sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b"}, - {file = "opentelemetry_instrumentation_asgi-0.45b0.tar.gz", hash = "sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6"}, + {file = "opentelemetry_instrumentation_asgi-0.46b0-py3-none-any.whl", hash = "sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759"}, + {file = "opentelemetry_instrumentation_asgi-0.46b0.tar.gz", hash = "sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a"}, ] [package.dependencies] asgiref = ">=3.0,<4.0" opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["asgiref (>=3.0,<4.0)"] [[package]] name = "opentelemetry-instrumentation-dbapi" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry Database API instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_dbapi-0.45b0-py3-none-any.whl", hash = "sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618"}, - {file = "opentelemetry_instrumentation_dbapi-0.45b0.tar.gz", hash = "sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c"}, + {file = "opentelemetry_instrumentation_dbapi-0.46b0-py3-none-any.whl", hash = "sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783"}, + {file = "opentelemetry_instrumentation_dbapi-0.46b0.tar.gz", hash = "sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry FastAPI Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_fastapi-0.45b0-py3-none-any.whl", hash = "sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314"}, - {file = "opentelemetry_instrumentation_fastapi-0.45b0.tar.gz", hash = "sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e"}, + {file = "opentelemetry_instrumentation_fastapi-0.46b0-py3-none-any.whl", hash = "sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33"}, + {file = "opentelemetry_instrumentation_fastapi-0.46b0.tar.gz", hash = "sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-instrumentation-asgi = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-instrumentation-asgi = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["fastapi (>=0.58,<1.0)"] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry HTTPX Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_httpx-0.45b0-py3-none-any.whl", hash = "sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225"}, - {file = "opentelemetry_instrumentation_httpx-0.45b0.tar.gz", hash = "sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d"}, + {file = "opentelemetry_instrumentation_httpx-0.46b0-py3-none-any.whl", hash = "sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc"}, + {file = "opentelemetry_instrumentation_httpx-0.46b0.tar.gz", hash = "sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["httpx (>=0.18.0)"] [[package]] name = "opentelemetry-instrumentation-psycopg2" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry psycopg2 instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_psycopg2-0.45b0-py3-none-any.whl", hash = "sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7"}, - {file = "opentelemetry_instrumentation_psycopg2-0.45b0.tar.gz", hash = "sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0"}, + {file = "opentelemetry_instrumentation_psycopg2-0.46b0-py3-none-any.whl", hash = "sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899"}, + {file = "opentelemetry_instrumentation_psycopg2-0.46b0.tar.gz", hash = "sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-instrumentation-dbapi = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-instrumentation-dbapi = "0.46b0" [package.extras] instruments = ["psycopg2 (>=2.7.3.1)"] [[package]] name = "opentelemetry-proto" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python Proto" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.24.0-py3-none-any.whl", hash = "sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce"}, - {file = "opentelemetry_proto-1.24.0.tar.gz", hash = "sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8"}, + {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, + {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, ] [package.dependencies] @@ -945,40 +942,43 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.24.0-py3-none-any.whl", hash = "sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59"}, - {file = "opentelemetry_sdk-1.24.0.tar.gz", hash = "sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5"}, + {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, + {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, ] [package.dependencies] -opentelemetry-api = "1.24.0" -opentelemetry-semantic-conventions = "0.45b0" +opentelemetry-api = "1.25.0" +opentelemetry-semantic-conventions = "0.46b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.45b0-py3-none-any.whl", hash = "sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864"}, - {file = "opentelemetry_semantic_conventions-0.45b0.tar.gz", hash = "sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118"}, + {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, + {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, ] +[package.dependencies] +opentelemetry-api = "1.25.0" + [[package]] name = "opentelemetry-util-http" -version = "0.45b0" +version = "0.46b0" description = "Web util for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_util_http-0.45b0-py3-none-any.whl", hash = "sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33"}, - {file = "opentelemetry_util_http-0.45b0.tar.gz", hash = "sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd"}, + {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"}, + {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"}, ] [[package]] @@ -1137,109 +1137,122 @@ files = [ [[package]] name = "pydantic" -version = "2.7.1" +version = "2.8.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"}, - {file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"}, + {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, + {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.18.2" -typing-extensions = ">=4.6.1" +pydantic-core = "2.20.1" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] [package.extras] email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.18.2" +version = "2.20.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"}, - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"}, - {file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"}, - {file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"}, - {file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"}, - {file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"}, - {file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"}, - {file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"}, - {file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"}, - {file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"}, - {file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"}, - {file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"}, - {file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"}, - {file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"}, - {file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, + {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, + {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, + {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, + {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, + {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, + {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, + {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, + {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, + {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, + {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, + {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, + {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, + {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, ] [package.dependencies] @@ -1247,17 +1260,17 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.2.1" +version = "2.3.4" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"}, - {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"}, + {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, + {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, ] [package.dependencies] -pydantic = ">=2.3.0" +pydantic = ">=2.7.0" python-dotenv = ">=0.21.0" [package.extras] @@ -1391,13 +1404,13 @@ dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatc [[package]] name = "requests" -version = "2.32.2" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, - {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -1430,19 +1443,19 @@ requests = "*" [[package]] name = "setuptools" -version = "69.1.1" +version = "71.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"}, - {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"}, + {file = "setuptools-71.0.3-py3-none-any.whl", hash = "sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207"}, + {file = "setuptools-71.0.3.tar.gz", hash = "sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (<7.4)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -1543,18 +1556,18 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "structlog" -version = "24.2.0" +version = "24.4.0" description = "Structured Logging for Python" optional = false python-versions = ">=3.8" files = [ - {file = "structlog-24.2.0-py3-none-any.whl", hash = "sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a"}, - {file = "structlog-24.2.0.tar.gz", hash = "sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b"}, + {file = "structlog-24.4.0-py3-none-any.whl", hash = "sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610"}, + {file = "structlog-24.4.0.tar.gz", hash = "sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4"}, ] [package.extras] dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] typing = ["mypy (>=1.4)", "rich", "twisted"] @@ -1571,13 +1584,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.11.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -1713,4 +1726,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "d7a3bdc28150ed7f912890a56858cd72fb43b1cba5da7d6ab7093d56e2096b6b" +content-hash = "c3e05238b348fa7444098c8e005dee50e9f1d3e755d593b849d70fafcd7ccbdd" diff --git a/bytes/pyproject.toml b/bytes/pyproject.toml index e1a66181544..37b3c4fc832 100644 --- a/bytes/pyproject.toml +++ b/bytes/pyproject.toml @@ -20,22 +20,22 @@ sqlalchemy = "^1.4.48" uvicorn = "^0.29.0" # OpenTelemetry -opentelemetry-sdk = "^1.24.0" -opentelemetry-exporter-otlp-proto-grpc = "^1.24.0" -opentelemetry-instrumentation-fastapi = "^0.45b0" -opentelemetry-instrumentation-psycopg2 = "^0.45b0" -opentelemetry-instrumentation-httpx = "^0.45b0" -opentelemetry-instrumentation = "^0.45b0" -opentelemetry-instrumentation-dbapi = "^0.45b0" +opentelemetry-sdk = "^1.25.0" +opentelemetry-exporter-otlp-proto-grpc = "^1.25.0" +opentelemetry-instrumentation-fastapi = "^0.46b0" +opentelemetry-instrumentation-psycopg2 = "^0.46b0" +opentelemetry-instrumentation-httpx = "^0.46b0" +opentelemetry-instrumentation = "^0.46b0" +opentelemetry-instrumentation-dbapi = "^0.46b0" pydantic-settings = "^2.2.1" python-multipart = "^0.0.9" httpx = "^0.27.0" -opentelemetry-api = "^1.24.0" -opentelemetry-exporter-otlp-proto-common = "^1.24.0" -opentelemetry-instrumentation-asgi = "^0.45b0" -opentelemetry-proto = "^1.24.0" -opentelemetry-semantic-conventions = "^0.45b0" -opentelemetry-util-http = "^0.45b0" +opentelemetry-api = "^1.25.0" +opentelemetry-exporter-otlp-proto-common = "^1.25.0" +opentelemetry-instrumentation-asgi = "^0.46b0" +opentelemetry-proto = "^1.25.0" +opentelemetry-semantic-conventions = "^0.46b0" +opentelemetry-util-http = "^0.46b0" pyjwt = "^2.8.0" fastapi-slim = "^0.111.0" structlog = "^24.2.0" diff --git a/bytes/requirements-dev.txt b/bytes/requirements-dev.txt index b3b2e2b51fa..63e110a28f2 100644 --- a/bytes/requirements-dev.txt +++ b/bytes/requirements-dev.txt @@ -194,48 +194,48 @@ click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and (sys_platform == "win32" or platform_system == "Windows") \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 -cryptography==42.0.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee \ - --hash=sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576 \ - --hash=sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d \ - --hash=sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30 \ - --hash=sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413 \ - --hash=sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb \ - --hash=sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da \ - --hash=sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4 \ - --hash=sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd \ - --hash=sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc \ - --hash=sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8 \ - --hash=sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1 \ - --hash=sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc \ - --hash=sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e \ - --hash=sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8 \ - --hash=sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940 \ - --hash=sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400 \ - --hash=sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7 \ - --hash=sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16 \ - --hash=sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278 \ - --hash=sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74 \ - --hash=sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec \ - --hash=sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1 \ - --hash=sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2 \ - --hash=sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c \ - --hash=sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922 \ - --hash=sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a \ - --hash=sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6 \ - --hash=sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1 \ - --hash=sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e \ - --hash=sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac \ - --hash=sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7 +cryptography==42.0.8 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ + --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ + --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ + --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ + --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ + --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ + --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ + --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ + --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ + --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ + --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ + --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ + --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ + --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ + --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ + --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ + --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ + --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ + --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ + --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ + --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ + --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ + --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ + --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ + --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ + --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ + --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ + --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ + --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ + --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ + --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ + --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \ --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3 exceptiongroup==1.2.0 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14 \ --hash=sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68 -fastapi-slim==0.111.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec \ - --hash=sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2 +fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ + --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d googleapis-common-protos==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07 \ --hash=sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277 @@ -435,45 +435,45 @@ markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 -opentelemetry-api==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2 \ - --hash=sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e -opentelemetry-exporter-otlp-proto-common==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461 \ - --hash=sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641 -opentelemetry-exporter-otlp-proto-grpc==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa \ - --hash=sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b -opentelemetry-instrumentation-asgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b \ - --hash=sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6 -opentelemetry-instrumentation-dbapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618 \ - --hash=sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c -opentelemetry-instrumentation-fastapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e \ - --hash=sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314 -opentelemetry-instrumentation-httpx==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d \ - --hash=sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225 -opentelemetry-instrumentation-psycopg2==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7 \ - --hash=sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0 -opentelemetry-instrumentation==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258 \ - --hash=sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e -opentelemetry-proto==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce \ - --hash=sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8 -opentelemetry-sdk==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5 \ - --hash=sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59 -opentelemetry-semantic-conventions==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118 \ - --hash=sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864 -opentelemetry-util-http==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd \ - --hash=sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33 +opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ + --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 +opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ + --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 +opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ + --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac +opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ + --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 +opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ + --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 +opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ + --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 +opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ + --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 +opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ + --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c +opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ + --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda +opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ + --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f +opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ + --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 +opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ + --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa +opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ + --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 @@ -524,92 +524,102 @@ pyasn1==0.5.1 ; python_version >= "3.10" and python_version < "4.0" \ pycparser==2.21 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 -pydantic-core==2.18.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b \ - --hash=sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a \ - --hash=sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90 \ - --hash=sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d \ - --hash=sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e \ - --hash=sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d \ - --hash=sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027 \ - --hash=sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804 \ - --hash=sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347 \ - --hash=sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400 \ - --hash=sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3 \ - --hash=sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399 \ - --hash=sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349 \ - --hash=sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd \ - --hash=sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c \ - --hash=sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e \ - --hash=sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413 \ - --hash=sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3 \ - --hash=sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e \ - --hash=sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3 \ - --hash=sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91 \ - --hash=sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce \ - --hash=sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c \ - --hash=sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb \ - --hash=sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664 \ - --hash=sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6 \ - --hash=sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd \ - --hash=sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3 \ - --hash=sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af \ - --hash=sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043 \ - --hash=sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350 \ - --hash=sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7 \ - --hash=sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0 \ - --hash=sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563 \ - --hash=sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761 \ - --hash=sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72 \ - --hash=sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3 \ - --hash=sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb \ - --hash=sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788 \ - --hash=sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b \ - --hash=sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c \ - --hash=sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038 \ - --hash=sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250 \ - --hash=sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec \ - --hash=sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c \ - --hash=sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74 \ - --hash=sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81 \ - --hash=sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439 \ - --hash=sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75 \ - --hash=sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0 \ - --hash=sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8 \ - --hash=sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150 \ - --hash=sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438 \ - --hash=sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae \ - --hash=sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857 \ - --hash=sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038 \ - --hash=sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374 \ - --hash=sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f \ - --hash=sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241 \ - --hash=sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592 \ - --hash=sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4 \ - --hash=sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d \ - --hash=sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b \ - --hash=sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b \ - --hash=sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182 \ - --hash=sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e \ - --hash=sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641 \ - --hash=sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70 \ - --hash=sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9 \ - --hash=sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a \ - --hash=sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543 \ - --hash=sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b \ - --hash=sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f \ - --hash=sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38 \ - --hash=sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845 \ - --hash=sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2 \ - --hash=sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0 \ - --hash=sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4 \ - --hash=sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242 -pydantic-settings==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ - --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 -pydantic==2.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5 \ - --hash=sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pyjwt==2.8.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de \ --hash=sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320 @@ -639,15 +649,15 @@ python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ python-multipart==0.0.9 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026 \ --hash=sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215 -requests==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ - --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c +requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 rfc3161ng==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e88614da61b22abd591577f9dd39d3a030335f9e8a12d8bc001149c17d0a01e \ --hash=sha256:81fe7e4488f523c758b1206bf5e72ba2066b78f2812107b1b7bb16a7596e524b -setuptools==69.1.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56 \ - --hash=sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 @@ -683,15 +693,15 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 -structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ - --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a +structlog==24.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610 \ + --hash=sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4 tomli==2.0.1 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f -typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ - --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a +typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 urllib3==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 diff --git a/bytes/requirements.txt b/bytes/requirements.txt index 15259eca56f..9af7b447f78 100644 --- a/bytes/requirements.txt +++ b/bytes/requirements.txt @@ -194,48 +194,48 @@ click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows" \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 -cryptography==42.0.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee \ - --hash=sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576 \ - --hash=sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d \ - --hash=sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30 \ - --hash=sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413 \ - --hash=sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb \ - --hash=sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da \ - --hash=sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4 \ - --hash=sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd \ - --hash=sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc \ - --hash=sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8 \ - --hash=sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1 \ - --hash=sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc \ - --hash=sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e \ - --hash=sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8 \ - --hash=sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940 \ - --hash=sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400 \ - --hash=sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7 \ - --hash=sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16 \ - --hash=sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278 \ - --hash=sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74 \ - --hash=sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec \ - --hash=sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1 \ - --hash=sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2 \ - --hash=sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c \ - --hash=sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922 \ - --hash=sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a \ - --hash=sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6 \ - --hash=sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1 \ - --hash=sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e \ - --hash=sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac \ - --hash=sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7 +cryptography==42.0.8 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ + --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ + --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ + --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ + --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ + --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ + --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ + --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ + --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ + --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ + --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ + --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ + --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ + --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ + --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ + --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ + --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ + --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ + --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ + --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ + --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ + --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ + --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ + --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ + --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ + --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ + --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ + --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ + --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ + --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ + --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ + --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \ --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3 exceptiongroup==1.2.0 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14 \ --hash=sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68 -fastapi-slim==0.111.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec \ - --hash=sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2 +fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ + --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d googleapis-common-protos==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07 \ --hash=sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277 @@ -432,45 +432,45 @@ markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 -opentelemetry-api==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2 \ - --hash=sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e -opentelemetry-exporter-otlp-proto-common==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461 \ - --hash=sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641 -opentelemetry-exporter-otlp-proto-grpc==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa \ - --hash=sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b -opentelemetry-instrumentation-asgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b \ - --hash=sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6 -opentelemetry-instrumentation-dbapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618 \ - --hash=sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c -opentelemetry-instrumentation-fastapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e \ - --hash=sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314 -opentelemetry-instrumentation-httpx==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d \ - --hash=sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225 -opentelemetry-instrumentation-psycopg2==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7 \ - --hash=sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0 -opentelemetry-instrumentation==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258 \ - --hash=sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e -opentelemetry-proto==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce \ - --hash=sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8 -opentelemetry-sdk==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5 \ - --hash=sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59 -opentelemetry-semantic-conventions==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118 \ - --hash=sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864 -opentelemetry-util-http==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd \ - --hash=sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33 +opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ + --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 +opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ + --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 +opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ + --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac +opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ + --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 +opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ + --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 +opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ + --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 +opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ + --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 +opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ + --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c +opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ + --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda +opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ + --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f +opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ + --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 +opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ + --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa +opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ + --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 passlib[bcrypt]==1.7.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1 \ --hash=sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04 @@ -515,92 +515,102 @@ pyasn1==0.5.1 ; python_version >= "3.10" and python_version < "4.0" \ pycparser==2.21 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 -pydantic-core==2.18.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b \ - --hash=sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a \ - --hash=sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90 \ - --hash=sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d \ - --hash=sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e \ - --hash=sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d \ - --hash=sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027 \ - --hash=sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804 \ - --hash=sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347 \ - --hash=sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400 \ - --hash=sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3 \ - --hash=sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399 \ - --hash=sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349 \ - --hash=sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd \ - --hash=sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c \ - --hash=sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e \ - --hash=sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413 \ - --hash=sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3 \ - --hash=sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e \ - --hash=sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3 \ - --hash=sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91 \ - --hash=sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce \ - --hash=sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c \ - --hash=sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb \ - --hash=sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664 \ - --hash=sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6 \ - --hash=sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd \ - --hash=sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3 \ - --hash=sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af \ - --hash=sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043 \ - --hash=sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350 \ - --hash=sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7 \ - --hash=sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0 \ - --hash=sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563 \ - --hash=sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761 \ - --hash=sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72 \ - --hash=sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3 \ - --hash=sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb \ - --hash=sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788 \ - --hash=sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b \ - --hash=sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c \ - --hash=sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038 \ - --hash=sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250 \ - --hash=sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec \ - --hash=sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c \ - --hash=sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74 \ - --hash=sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81 \ - --hash=sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439 \ - --hash=sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75 \ - --hash=sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0 \ - --hash=sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8 \ - --hash=sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150 \ - --hash=sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438 \ - --hash=sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae \ - --hash=sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857 \ - --hash=sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038 \ - --hash=sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374 \ - --hash=sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f \ - --hash=sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241 \ - --hash=sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592 \ - --hash=sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4 \ - --hash=sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d \ - --hash=sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b \ - --hash=sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b \ - --hash=sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182 \ - --hash=sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e \ - --hash=sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641 \ - --hash=sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70 \ - --hash=sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9 \ - --hash=sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a \ - --hash=sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543 \ - --hash=sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b \ - --hash=sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f \ - --hash=sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38 \ - --hash=sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845 \ - --hash=sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2 \ - --hash=sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0 \ - --hash=sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4 \ - --hash=sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242 -pydantic-settings==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ - --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 -pydantic==2.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5 \ - --hash=sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pyjwt==2.8.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de \ --hash=sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320 @@ -624,15 +634,15 @@ python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ python-multipart==0.0.9 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026 \ --hash=sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215 -requests==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ - --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c +requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 rfc3161ng==2.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e88614da61b22abd591577f9dd39d3a030335f9e8a12d8bc001149c17d0a01e \ --hash=sha256:81fe7e4488f523c758b1206bf5e72ba2066b78f2812107b1b7bb16a7596e524b -setuptools==69.1.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56 \ - --hash=sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 @@ -668,12 +678,12 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 -structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ - --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a -typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ - --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a +structlog==24.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610 \ + --hash=sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4 +typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 urllib3==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 diff --git a/keiko/poetry.lock b/keiko/poetry.lock index e221e981ff0..22894444884 100644 --- a/keiko/poetry.lock +++ b/keiko/poetry.lock @@ -50,17 +50,6 @@ typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] -[[package]] -name = "backoff" -version = "2.2.1" -description = "Function decoration for backoff and retry" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, - {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, -] - [[package]] name = "certifi" version = "2024.7.4" @@ -229,13 +218,13 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi-slim" -version = "0.111.0" +version = "0.111.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi_slim-0.111.0-py3-none-any.whl", hash = "sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2"}, - {file = "fastapi_slim-0.111.0.tar.gz", hash = "sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec"}, + {file = "fastapi_slim-0.111.1-py3-none-any.whl", hash = "sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb"}, + {file = "fastapi_slim-0.111.1.tar.gz", hash = "sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d"}, ] [package.dependencies] @@ -245,7 +234,7 @@ typing-extensions = ">=4.8.0" [package.extras] all = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.7)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "googleapis-common-protos" @@ -550,67 +539,62 @@ files = [ [[package]] name = "opentelemetry-api" -version = "1.20.0" +version = "1.25.0" description = "OpenTelemetry Python API" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.20.0-py3-none-any.whl", hash = "sha256:982b76036fec0fdaf490ae3dfd9f28c81442a33414f737abc687a32758cdcba5"}, - {file = "opentelemetry_api-1.20.0.tar.gz", hash = "sha256:06abe351db7572f8afdd0fb889ce53f3c992dbf6f6262507b385cc1963e06983"}, + {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, + {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<7.0" +importlib-metadata = ">=6.0,<=7.1" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.20.0" +version = "1.25.0" description = "OpenTelemetry Protobuf encoding" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.20.0-py3-none-any.whl", hash = "sha256:dd63209b40702636ab6ae76a06b401b646ad7b008a906ecb41222d4af24fbdef"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.20.0.tar.gz", hash = "sha256:df60c681bd61812e50b3a39a7a1afeeb6d4066117583249fcc262269374e7a49"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, ] [package.dependencies] -backoff = {version = ">=1.10.0,<3.0.0", markers = "python_version >= \"3.7\""} -opentelemetry-proto = "1.20.0" +opentelemetry-proto = "1.25.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.20.0" +version = "1.25.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.20.0-py3-none-any.whl", hash = "sha256:7c3f066065891b56348ba2c7f9df6ec635a712841cae0a36f2f6a81642ae7dec"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.20.0.tar.gz", hash = "sha256:6c06d43c3771bda1795226e327722b4b980fa1ca1ec9e985f2ef3e29795bdd52"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, ] [package.dependencies] -backoff = {version = ">=1.10.0,<3.0.0", markers = "python_version >= \"3.7\""} deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.20.0" -opentelemetry-proto = "1.20.0" -opentelemetry-sdk = ">=1.20.0,<1.21.0" - -[package.extras] -test = ["pytest-grpc"] +opentelemetry-exporter-otlp-proto-common = "1.25.0" +opentelemetry-proto = "1.25.0" +opentelemetry-sdk = ">=1.25.0,<1.26.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.41b0" +version = "0.46b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.41b0-py3-none-any.whl", hash = "sha256:0ef9e5705ceca0205992a4a845ae4251ce6ec15a1206ca07c2b00afb0c5bd386"}, - {file = "opentelemetry_instrumentation-0.41b0.tar.gz", hash = "sha256:214382ba10dfd29d4e24898a4c7ef18b7368178a6277a1aec95cdb75cabf4612"}, + {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, + {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, ] [package.dependencies] @@ -620,57 +604,55 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.41b0" +version = "0.46b0" description = "ASGI instrumentation for OpenTelemetry" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_asgi-0.41b0-py3-none-any.whl", hash = "sha256:46084195fb9c50507abbe1dd490ae4c31c8658c5790f1ddf7af95c417dbe6422"}, - {file = "opentelemetry_instrumentation_asgi-0.41b0.tar.gz", hash = "sha256:921244138b37a9a25edf2153f1c248f16f98610ee8d840b25fd7bf6b165e4d72"}, + {file = "opentelemetry_instrumentation_asgi-0.46b0-py3-none-any.whl", hash = "sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759"}, + {file = "opentelemetry_instrumentation_asgi-0.46b0.tar.gz", hash = "sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a"}, ] [package.dependencies] asgiref = ">=3.0,<4.0" opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.41b0" -opentelemetry-semantic-conventions = "0.41b0" -opentelemetry-util-http = "0.41b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["asgiref (>=3.0,<4.0)"] -test = ["opentelemetry-instrumentation-asgi[instruments]", "opentelemetry-test-utils (==0.41b0)"] [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.41b0" +version = "0.46b0" description = "OpenTelemetry FastAPI Instrumentation" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_fastapi-0.41b0-py3-none-any.whl", hash = "sha256:5990368e99ecc989df0a248a0b9b8e85d8b3eb7c1dbf5131c36982ba7f4a43b7"}, - {file = "opentelemetry_instrumentation_fastapi-0.41b0.tar.gz", hash = "sha256:eb4ceefe8b944fc9ea5e61fa558b99afd1285431b563f3f0104ac177cde4dfe5"}, + {file = "opentelemetry_instrumentation_fastapi-0.46b0-py3-none-any.whl", hash = "sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33"}, + {file = "opentelemetry_instrumentation_fastapi-0.46b0.tar.gz", hash = "sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.41b0" -opentelemetry-instrumentation-asgi = "0.41b0" -opentelemetry-semantic-conventions = "0.41b0" -opentelemetry-util-http = "0.41b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-instrumentation-asgi = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["fastapi (>=0.58,<1.0)"] -test = ["httpx (>=0.22,<1.0)", "opentelemetry-instrumentation-fastapi[instruments]", "opentelemetry-test-utils (==0.41b0)", "requests (>=2.23,<3.0)"] [[package]] name = "opentelemetry-proto" -version = "1.20.0" +version = "1.25.0" description = "OpenTelemetry Python Proto" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.20.0-py3-none-any.whl", hash = "sha256:512c3d2c6864fb7547a69577c3907348e6c985b7a204533563cb4c4c5046203b"}, - {file = "opentelemetry_proto-1.20.0.tar.gz", hash = "sha256:cf01f49b3072ee57468bccb1a4f93bdb55411f4512d0ac3f97c5c04c0040b5a2"}, + {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, + {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, ] [package.dependencies] @@ -678,40 +660,43 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.20.0" +version = "1.25.0" description = "OpenTelemetry Python SDK" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.20.0-py3-none-any.whl", hash = "sha256:f2230c276ff4c63ea09b3cb2e2ac6b1265f90af64e8d16bbf275c81a9ce8e804"}, - {file = "opentelemetry_sdk-1.20.0.tar.gz", hash = "sha256:702e432a457fa717fd2ddfd30640180e69938f85bb7fec3e479f85f61c1843f8"}, + {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, + {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, ] [package.dependencies] -opentelemetry-api = "1.20.0" -opentelemetry-semantic-conventions = "0.41b0" +opentelemetry-api = "1.25.0" +opentelemetry-semantic-conventions = "0.46b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.41b0" +version = "0.46b0" description = "OpenTelemetry Semantic Conventions" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.41b0-py3-none-any.whl", hash = "sha256:45404391ed9e50998183a4925ad1b497c01c143f06500c3b9c3d0013492bb0f2"}, - {file = "opentelemetry_semantic_conventions-0.41b0.tar.gz", hash = "sha256:0ce5b040b8a3fc816ea5879a743b3d6fe5db61f6485e4def94c6ee4d402e1eb7"}, + {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, + {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, ] +[package.dependencies] +opentelemetry-api = "1.25.0" + [[package]] name = "opentelemetry-util-http" -version = "0.41b0" +version = "0.46b0" description = "Web util for OpenTelemetry" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "opentelemetry_util_http-0.41b0-py3-none-any.whl", hash = "sha256:6a167fd1e0e8b0f629530d971165b5d82ed0be2154b7f29498499c3a517edee5"}, - {file = "opentelemetry_util_http-0.41b0.tar.gz", hash = "sha256:16d5bd04a380dc1079e766562d1e1626cbb47720f197f67010c45f090fffdfb3"}, + {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"}, + {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"}, ] [[package]] @@ -787,109 +772,122 @@ files = [ [[package]] name = "pydantic" -version = "2.7.1" +version = "2.8.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"}, - {file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"}, + {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, + {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.18.2" -typing-extensions = ">=4.6.1" +pydantic-core = "2.20.1" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] [package.extras] email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.18.2" +version = "2.20.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"}, - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"}, - {file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"}, - {file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"}, - {file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"}, - {file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"}, - {file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"}, - {file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"}, - {file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"}, - {file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"}, - {file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"}, - {file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"}, - {file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"}, - {file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"}, - {file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, + {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, + {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, + {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, + {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, + {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, + {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, + {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, + {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, + {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, + {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, + {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, + {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, + {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, ] [package.dependencies] @@ -897,17 +895,17 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.2.1" +version = "2.3.4" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"}, - {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"}, + {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, + {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, ] [package.dependencies] -pydantic = ">=2.3.0" +pydantic = ">=2.7.0" python-dotenv = ">=0.21.0" [package.extras] @@ -982,13 +980,13 @@ cli = ["click (>=5.0)"] [[package]] name = "requests" -version = "2.32.2" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, - {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -1109,19 +1107,19 @@ generate-config = ["tomli-w (==1.0.*)"] [[package]] name = "setuptools" -version = "69.1.0" +version = "71.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, - {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, + {file = "setuptools-71.0.3-py3-none-any.whl", hash = "sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207"}, + {file = "setuptools-71.0.3.tar.gz", hash = "sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (<7.4)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "sniffio" @@ -1164,13 +1162,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.11.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -1317,4 +1315,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "73fde59efb3d19ff1fc395e560588b911962c414ac67dc7b9f9256a9b54a1df6" +content-hash = "014adceea18ed897ba06e5ce5deeb628cf57e366fc3c3ab2c58b4f9ec18012d0" diff --git a/keiko/pyproject.toml b/keiko/pyproject.toml index 03d0873546f..84abdf5f88b 100644 --- a/keiko/pyproject.toml +++ b/keiko/pyproject.toml @@ -11,12 +11,18 @@ click = "^8.1.3" pydantic = "^2.6.0" Jinja2 = "^3.1.3" uvicorn = "^0.29.0" -opentelemetry-sdk = "^1.19.0" -opentelemetry-exporter-otlp-proto-grpc = "^1.19.0" -opentelemetry-instrumentation-fastapi = "^0.41b0" -opentelemetry-instrumentation = "^0.41b0" +opentelemetry-sdk = "^1.25.0" +opentelemetry-exporter-otlp-proto-grpc = "^1.25.0" +opentelemetry-instrumentation-fastapi = "^0.46b0" +opentelemetry-instrumentation = "^0.46b0" pydantic-settings = "^2.0.3" fastapi-slim = "^0.111.0" +opentelemetry-api = "^1.25.0" +opentelemetry-exporter-otlp-proto-common = "^1.25.0" +opentelemetry-instrumentation-asgi = "^0.46b0" +opentelemetry-proto = "^1.25.0" +opentelemetry-semantic-conventions = "^0.46b0" +opentelemetry-util-http = "^0.46b0" [tool.poetry.group.dev.dependencies] pytest = "^8.0.0" diff --git a/keiko/requirements-dev.txt b/keiko/requirements-dev.txt index e2b6bf89e01..86d30ecf461 100644 --- a/keiko/requirements-dev.txt +++ b/keiko/requirements-dev.txt @@ -7,9 +7,6 @@ anyio==4.3.0 ; python_version >= "3.10" and python_version < "4.0" \ asgiref==3.7.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \ --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed -backoff==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba \ - --hash=sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8 certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 @@ -116,9 +113,9 @@ deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \ exceptiongroup==1.2.0 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14 \ --hash=sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68 -fastapi-slim==0.111.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec \ - --hash=sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2 +fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ + --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d googleapis-common-protos==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07 \ --hash=sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277 @@ -265,36 +262,36 @@ markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0" \ mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba -opentelemetry-api==1.20.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06abe351db7572f8afdd0fb889ce53f3c992dbf6f6262507b385cc1963e06983 \ - --hash=sha256:982b76036fec0fdaf490ae3dfd9f28c81442a33414f737abc687a32758cdcba5 -opentelemetry-exporter-otlp-proto-common==1.20.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:dd63209b40702636ab6ae76a06b401b646ad7b008a906ecb41222d4af24fbdef \ - --hash=sha256:df60c681bd61812e50b3a39a7a1afeeb6d4066117583249fcc262269374e7a49 -opentelemetry-exporter-otlp-proto-grpc==1.20.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6c06d43c3771bda1795226e327722b4b980fa1ca1ec9e985f2ef3e29795bdd52 \ - --hash=sha256:7c3f066065891b56348ba2c7f9df6ec635a712841cae0a36f2f6a81642ae7dec -opentelemetry-instrumentation-asgi==0.41b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:46084195fb9c50507abbe1dd490ae4c31c8658c5790f1ddf7af95c417dbe6422 \ - --hash=sha256:921244138b37a9a25edf2153f1c248f16f98610ee8d840b25fd7bf6b165e4d72 -opentelemetry-instrumentation-fastapi==0.41b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5990368e99ecc989df0a248a0b9b8e85d8b3eb7c1dbf5131c36982ba7f4a43b7 \ - --hash=sha256:eb4ceefe8b944fc9ea5e61fa558b99afd1285431b563f3f0104ac177cde4dfe5 -opentelemetry-instrumentation==0.41b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0ef9e5705ceca0205992a4a845ae4251ce6ec15a1206ca07c2b00afb0c5bd386 \ - --hash=sha256:214382ba10dfd29d4e24898a4c7ef18b7368178a6277a1aec95cdb75cabf4612 -opentelemetry-proto==1.20.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:512c3d2c6864fb7547a69577c3907348e6c985b7a204533563cb4c4c5046203b \ - --hash=sha256:cf01f49b3072ee57468bccb1a4f93bdb55411f4512d0ac3f97c5c04c0040b5a2 -opentelemetry-sdk==1.20.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:702e432a457fa717fd2ddfd30640180e69938f85bb7fec3e479f85f61c1843f8 \ - --hash=sha256:f2230c276ff4c63ea09b3cb2e2ac6b1265f90af64e8d16bbf275c81a9ce8e804 -opentelemetry-semantic-conventions==0.41b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0ce5b040b8a3fc816ea5879a743b3d6fe5db61f6485e4def94c6ee4d402e1eb7 \ - --hash=sha256:45404391ed9e50998183a4925ad1b497c01c143f06500c3b9c3d0013492bb0f2 -opentelemetry-util-http==0.41b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:16d5bd04a380dc1079e766562d1e1626cbb47720f197f67010c45f090fffdfb3 \ - --hash=sha256:6a167fd1e0e8b0f629530d971165b5d82ed0be2154b7f29498499c3a517edee5 +opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ + --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 +opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ + --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 +opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ + --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac +opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ + --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 +opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ + --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 +opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ + --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda +opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ + --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f +opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ + --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 +opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ + --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa +opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ + --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 @@ -319,92 +316,102 @@ protobuf==4.25.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \ --hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \ --hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2 -pydantic-core==2.18.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b \ - --hash=sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a \ - --hash=sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90 \ - --hash=sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d \ - --hash=sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e \ - --hash=sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d \ - --hash=sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027 \ - --hash=sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804 \ - --hash=sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347 \ - --hash=sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400 \ - --hash=sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3 \ - --hash=sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399 \ - --hash=sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349 \ - --hash=sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd \ - --hash=sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c \ - --hash=sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e \ - --hash=sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413 \ - --hash=sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3 \ - --hash=sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e \ - --hash=sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3 \ - --hash=sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91 \ - --hash=sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce \ - --hash=sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c \ - --hash=sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb \ - --hash=sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664 \ - --hash=sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6 \ - --hash=sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd \ - --hash=sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3 \ - --hash=sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af \ - --hash=sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043 \ - --hash=sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350 \ - --hash=sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7 \ - --hash=sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0 \ - --hash=sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563 \ - --hash=sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761 \ - --hash=sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72 \ - --hash=sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3 \ - --hash=sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb \ - --hash=sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788 \ - --hash=sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b \ - --hash=sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c \ - --hash=sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038 \ - --hash=sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250 \ - --hash=sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec \ - --hash=sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c \ - --hash=sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74 \ - --hash=sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81 \ - --hash=sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439 \ - --hash=sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75 \ - --hash=sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0 \ - --hash=sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8 \ - --hash=sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150 \ - --hash=sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438 \ - --hash=sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae \ - --hash=sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857 \ - --hash=sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038 \ - --hash=sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374 \ - --hash=sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f \ - --hash=sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241 \ - --hash=sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592 \ - --hash=sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4 \ - --hash=sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d \ - --hash=sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b \ - --hash=sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b \ - --hash=sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182 \ - --hash=sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e \ - --hash=sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641 \ - --hash=sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70 \ - --hash=sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9 \ - --hash=sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a \ - --hash=sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543 \ - --hash=sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b \ - --hash=sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f \ - --hash=sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38 \ - --hash=sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845 \ - --hash=sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2 \ - --hash=sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0 \ - --hash=sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4 \ - --hash=sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242 -pydantic-settings==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ - --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 -pydantic==2.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5 \ - --hash=sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pygments==2.17.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \ --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367 @@ -417,9 +424,9 @@ pytest==8.2.1 ; python_version >= "3.10" and python_version < "4.0" \ python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a -requests==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ - --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c +requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 rich-click==1.7.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:bc4163d4e2a3361e21c4d72d300eca6eb8896dfc978667923cb1d4937b8769a3 \ --hash=sha256:bced1594c497dc007ab49508ff198bb437c576d01291c13a61658999066481f4 @@ -438,9 +445,9 @@ robotframework-tidy==4.9.0 ; python_version >= "3.10" and python_version < "4.0" robotframework==7.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:04623f758346c917db182e17591ffa474090560c02ed5a64343902e72b7b4bd5 \ --hash=sha256:865f427c4e4ec8c0b71a24dedbdad6668adfecc9fce04d77d02e1b8e54b77f41 -setuptools==69.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401 \ - --hash=sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 sniffio==1.3.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \ --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384 @@ -450,9 +457,9 @@ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ tomli==2.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f -typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ - --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a +typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 urllib3==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 diff --git a/keiko/requirements.txt b/keiko/requirements.txt index 9d6504633e9..777c3e3b7fb 100644 --- a/keiko/requirements.txt +++ b/keiko/requirements.txt @@ -7,9 +7,6 @@ anyio==4.3.0 ; python_version >= "3.10" and python_version < "4.0" \ asgiref==3.7.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \ --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed -backoff==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba \ - --hash=sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8 click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de @@ -22,9 +19,9 @@ deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \ exceptiongroup==1.2.0 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14 \ --hash=sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68 -fastapi-slim==0.111.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec \ - --hash=sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2 +fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ + --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d googleapis-common-protos==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07 \ --hash=sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277 @@ -156,36 +153,36 @@ markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 -opentelemetry-api==1.20.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06abe351db7572f8afdd0fb889ce53f3c992dbf6f6262507b385cc1963e06983 \ - --hash=sha256:982b76036fec0fdaf490ae3dfd9f28c81442a33414f737abc687a32758cdcba5 -opentelemetry-exporter-otlp-proto-common==1.20.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:dd63209b40702636ab6ae76a06b401b646ad7b008a906ecb41222d4af24fbdef \ - --hash=sha256:df60c681bd61812e50b3a39a7a1afeeb6d4066117583249fcc262269374e7a49 -opentelemetry-exporter-otlp-proto-grpc==1.20.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6c06d43c3771bda1795226e327722b4b980fa1ca1ec9e985f2ef3e29795bdd52 \ - --hash=sha256:7c3f066065891b56348ba2c7f9df6ec635a712841cae0a36f2f6a81642ae7dec -opentelemetry-instrumentation-asgi==0.41b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:46084195fb9c50507abbe1dd490ae4c31c8658c5790f1ddf7af95c417dbe6422 \ - --hash=sha256:921244138b37a9a25edf2153f1c248f16f98610ee8d840b25fd7bf6b165e4d72 -opentelemetry-instrumentation-fastapi==0.41b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5990368e99ecc989df0a248a0b9b8e85d8b3eb7c1dbf5131c36982ba7f4a43b7 \ - --hash=sha256:eb4ceefe8b944fc9ea5e61fa558b99afd1285431b563f3f0104ac177cde4dfe5 -opentelemetry-instrumentation==0.41b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0ef9e5705ceca0205992a4a845ae4251ce6ec15a1206ca07c2b00afb0c5bd386 \ - --hash=sha256:214382ba10dfd29d4e24898a4c7ef18b7368178a6277a1aec95cdb75cabf4612 -opentelemetry-proto==1.20.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:512c3d2c6864fb7547a69577c3907348e6c985b7a204533563cb4c4c5046203b \ - --hash=sha256:cf01f49b3072ee57468bccb1a4f93bdb55411f4512d0ac3f97c5c04c0040b5a2 -opentelemetry-sdk==1.20.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:702e432a457fa717fd2ddfd30640180e69938f85bb7fec3e479f85f61c1843f8 \ - --hash=sha256:f2230c276ff4c63ea09b3cb2e2ac6b1265f90af64e8d16bbf275c81a9ce8e804 -opentelemetry-semantic-conventions==0.41b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0ce5b040b8a3fc816ea5879a743b3d6fe5db61f6485e4def94c6ee4d402e1eb7 \ - --hash=sha256:45404391ed9e50998183a4925ad1b497c01c143f06500c3b9c3d0013492bb0f2 -opentelemetry-util-http==0.41b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:16d5bd04a380dc1079e766562d1e1626cbb47720f197f67010c45f090fffdfb3 \ - --hash=sha256:6a167fd1e0e8b0f629530d971165b5d82ed0be2154b7f29498499c3a517edee5 +opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ + --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 +opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ + --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 +opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ + --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac +opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ + --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 +opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ + --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 +opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ + --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda +opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ + --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f +opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ + --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 +opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ + --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa +opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ + --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 protobuf==4.25.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4 \ --hash=sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8 \ @@ -198,107 +195,117 @@ protobuf==4.25.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \ --hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \ --hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2 -pydantic-core==2.18.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b \ - --hash=sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a \ - --hash=sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90 \ - --hash=sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d \ - --hash=sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e \ - --hash=sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d \ - --hash=sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027 \ - --hash=sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804 \ - --hash=sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347 \ - --hash=sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400 \ - --hash=sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3 \ - --hash=sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399 \ - --hash=sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349 \ - --hash=sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd \ - --hash=sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c \ - --hash=sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e \ - --hash=sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413 \ - --hash=sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3 \ - --hash=sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e \ - --hash=sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3 \ - --hash=sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91 \ - --hash=sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce \ - --hash=sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c \ - --hash=sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb \ - --hash=sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664 \ - --hash=sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6 \ - --hash=sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd \ - --hash=sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3 \ - --hash=sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af \ - --hash=sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043 \ - --hash=sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350 \ - --hash=sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7 \ - --hash=sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0 \ - --hash=sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563 \ - --hash=sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761 \ - --hash=sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72 \ - --hash=sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3 \ - --hash=sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb \ - --hash=sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788 \ - --hash=sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b \ - --hash=sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c \ - --hash=sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038 \ - --hash=sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250 \ - --hash=sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec \ - --hash=sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c \ - --hash=sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74 \ - --hash=sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81 \ - --hash=sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439 \ - --hash=sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75 \ - --hash=sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0 \ - --hash=sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8 \ - --hash=sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150 \ - --hash=sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438 \ - --hash=sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae \ - --hash=sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857 \ - --hash=sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038 \ - --hash=sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374 \ - --hash=sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f \ - --hash=sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241 \ - --hash=sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592 \ - --hash=sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4 \ - --hash=sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d \ - --hash=sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b \ - --hash=sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b \ - --hash=sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182 \ - --hash=sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e \ - --hash=sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641 \ - --hash=sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70 \ - --hash=sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9 \ - --hash=sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a \ - --hash=sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543 \ - --hash=sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b \ - --hash=sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f \ - --hash=sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38 \ - --hash=sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845 \ - --hash=sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2 \ - --hash=sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0 \ - --hash=sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4 \ - --hash=sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242 -pydantic-settings==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ - --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 -pydantic==2.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5 \ - --hash=sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a -setuptools==69.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401 \ - --hash=sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 sniffio==1.3.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \ --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384 starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 -typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ - --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a +typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 uvicorn==0.29.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de \ --hash=sha256:6a69214c0b6a087462412670b3ef21224fa48cae0e452b5883e8e8bdfdd11dd0 diff --git a/mula/poetry.lock b/mula/poetry.lock index 0ddbf59e57a..a200c910748 100644 --- a/mula/poetry.lock +++ b/mula/poetry.lock @@ -248,13 +248,13 @@ python-dateutil = ">=2.4" [[package]] name = "fastapi-slim" -version = "0.111.0" +version = "0.111.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi_slim-0.111.0-py3-none-any.whl", hash = "sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2"}, - {file = "fastapi_slim-0.111.0.tar.gz", hash = "sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec"}, + {file = "fastapi_slim-0.111.1-py3-none-any.whl", hash = "sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb"}, + {file = "fastapi_slim-0.111.1.tar.gz", hash = "sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d"}, ] [package.dependencies] @@ -264,7 +264,7 @@ typing-extensions = ">=4.8.0" [package.extras] all = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.7)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "googleapis-common-protos" @@ -1035,109 +1035,122 @@ files = [ [[package]] name = "pydantic" -version = "2.7.4" +version = "2.8.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.4-py3-none-any.whl", hash = "sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0"}, - {file = "pydantic-2.7.4.tar.gz", hash = "sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52"}, + {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, + {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.18.4" -typing-extensions = ">=4.6.1" +pydantic-core = "2.20.1" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] [package.extras] email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.18.4" +version = "2.20.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4"}, - {file = "pydantic_core-2.18.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb"}, - {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c"}, - {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e"}, - {file = "pydantic_core-2.18.4-cp310-none-win32.whl", hash = "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc"}, - {file = "pydantic_core-2.18.4-cp310-none-win_amd64.whl", hash = "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0"}, - {file = "pydantic_core-2.18.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d"}, - {file = "pydantic_core-2.18.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951"}, - {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2"}, - {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9"}, - {file = "pydantic_core-2.18.4-cp311-none-win32.whl", hash = "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558"}, - {file = "pydantic_core-2.18.4-cp311-none-win_amd64.whl", hash = "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b"}, - {file = "pydantic_core-2.18.4-cp311-none-win_arm64.whl", hash = "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805"}, - {file = "pydantic_core-2.18.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2"}, - {file = "pydantic_core-2.18.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9"}, - {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c"}, - {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8"}, - {file = "pydantic_core-2.18.4-cp312-none-win32.whl", hash = "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07"}, - {file = "pydantic_core-2.18.4-cp312-none-win_amd64.whl", hash = "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a"}, - {file = "pydantic_core-2.18.4-cp312-none-win_arm64.whl", hash = "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f"}, - {file = "pydantic_core-2.18.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2"}, - {file = "pydantic_core-2.18.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057"}, - {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b"}, - {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af"}, - {file = "pydantic_core-2.18.4-cp38-none-win32.whl", hash = "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2"}, - {file = "pydantic_core-2.18.4-cp38-none-win_amd64.whl", hash = "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443"}, - {file = "pydantic_core-2.18.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528"}, - {file = "pydantic_core-2.18.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23"}, - {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b"}, - {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a"}, - {file = "pydantic_core-2.18.4-cp39-none-win32.whl", hash = "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d"}, - {file = "pydantic_core-2.18.4-cp39-none-win_amd64.whl", hash = "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9"}, - {file = "pydantic_core-2.18.4.tar.gz", hash = "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, + {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, + {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, + {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, + {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, + {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, + {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, + {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, + {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, + {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, + {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, + {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, + {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, + {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, ] [package.dependencies] @@ -1145,13 +1158,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.3.3" +version = "2.3.4" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.3.3-py3-none-any.whl", hash = "sha256:e4ed62ad851670975ec11285141db888fd24947f9440bd4380d7d8788d4965de"}, - {file = "pydantic_settings-2.3.3.tar.gz", hash = "sha256:87fda838b64b5039b970cd47c3e8a1ee460ce136278ff672980af21516f6e6ce"}, + {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, + {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, ] [package.dependencies] @@ -1245,18 +1258,19 @@ decorator = ">=3.4.2" [[package]] name = "setuptools" -version = "70.0.0" +version = "71.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-70.0.0-py3-none-any.whl", hash = "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4"}, - {file = "setuptools-70.0.0.tar.gz", hash = "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0"}, + {file = "setuptools-71.0.3-py3-none-any.whl", hash = "sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207"}, + {file = "setuptools-71.0.3.tar.gz", hash = "sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (<7.4)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" diff --git a/mula/requirements-dev.txt b/mula/requirements-dev.txt index 5b102ed95d9..c5368ace86a 100644 --- a/mula/requirements-dev.txt +++ b/mula/requirements-dev.txt @@ -87,9 +87,9 @@ factory-boy==3.3.0 ; python_version >= "3.10" and python_version < "4.0" \ faker==25.8.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4c40b34a9c569018d4f9d6366d71a4da8a883d5ddf2b23197be5370f29b7e1b6 \ --hash=sha256:bdec5f2fb057d244ebef6e0ed318fea4dcbdf32c3a1a010766fc45f5d68fc68d -fastapi-slim==0.111.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec \ - --hash=sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2 +fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ + --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d googleapis-common-protos==1.63.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877 \ --hash=sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a @@ -456,92 +456,102 @@ psycopg2==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024 \ --hash=sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913 \ --hash=sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c -pydantic-core==2.18.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3 \ - --hash=sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8 \ - --hash=sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8 \ - --hash=sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30 \ - --hash=sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a \ - --hash=sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8 \ - --hash=sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d \ - --hash=sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc \ - --hash=sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2 \ - --hash=sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab \ - --hash=sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077 \ - --hash=sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e \ - --hash=sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9 \ - --hash=sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9 \ - --hash=sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef \ - --hash=sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1 \ - --hash=sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507 \ - --hash=sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528 \ - --hash=sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558 \ - --hash=sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b \ - --hash=sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154 \ - --hash=sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724 \ - --hash=sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695 \ - --hash=sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9 \ - --hash=sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851 \ - --hash=sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805 \ - --hash=sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a \ - --hash=sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5 \ - --hash=sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94 \ - --hash=sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c \ - --hash=sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d \ - --hash=sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef \ - --hash=sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26 \ - --hash=sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2 \ - --hash=sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c \ - --hash=sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0 \ - --hash=sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2 \ - --hash=sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4 \ - --hash=sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d \ - --hash=sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2 \ - --hash=sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce \ - --hash=sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34 \ - --hash=sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f \ - --hash=sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d \ - --hash=sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b \ - --hash=sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07 \ - --hash=sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312 \ - --hash=sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057 \ - --hash=sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d \ - --hash=sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af \ - --hash=sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb \ - --hash=sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd \ - --hash=sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78 \ - --hash=sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b \ - --hash=sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223 \ - --hash=sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a \ - --hash=sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4 \ - --hash=sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5 \ - --hash=sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23 \ - --hash=sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a \ - --hash=sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4 \ - --hash=sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8 \ - --hash=sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d \ - --hash=sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443 \ - --hash=sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e \ - --hash=sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f \ - --hash=sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e \ - --hash=sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d \ - --hash=sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc \ - --hash=sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443 \ - --hash=sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be \ - --hash=sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2 \ - --hash=sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee \ - --hash=sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f \ - --hash=sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae \ - --hash=sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864 \ - --hash=sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4 \ - --hash=sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951 \ - --hash=sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc -pydantic-settings==2.3.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:87fda838b64b5039b970cd47c3e8a1ee460ce136278ff672980af21516f6e6ce \ - --hash=sha256:e4ed62ad851670975ec11285141db888fd24947f9440bd4380d7d8788d4965de -pydantic==2.7.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52 \ - --hash=sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0 +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pytest-cov==5.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652 \ --hash=sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857 @@ -556,9 +566,9 @@ python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a retry2==0.9.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f7fee13b1e15d0611c462910a6aa72a8919823988dd0412152bc3719c89a4e55 -setuptools==70.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4 \ - --hash=sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 diff --git a/mula/requirements.txt b/mula/requirements.txt index e4e2af3d29b..dd7846f82af 100644 --- a/mula/requirements.txt +++ b/mula/requirements.txt @@ -28,9 +28,9 @@ deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \ exceptiongroup==1.2.1 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad \ --hash=sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16 -fastapi-slim==0.111.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec \ - --hash=sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2 +fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ + --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d googleapis-common-protos==1.63.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877 \ --hash=sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a @@ -371,100 +371,110 @@ psycopg2==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024 \ --hash=sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913 \ --hash=sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c -pydantic-core==2.18.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3 \ - --hash=sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8 \ - --hash=sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8 \ - --hash=sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30 \ - --hash=sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a \ - --hash=sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8 \ - --hash=sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d \ - --hash=sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc \ - --hash=sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2 \ - --hash=sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab \ - --hash=sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077 \ - --hash=sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e \ - --hash=sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9 \ - --hash=sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9 \ - --hash=sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef \ - --hash=sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1 \ - --hash=sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507 \ - --hash=sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528 \ - --hash=sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558 \ - --hash=sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b \ - --hash=sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154 \ - --hash=sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724 \ - --hash=sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695 \ - --hash=sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9 \ - --hash=sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851 \ - --hash=sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805 \ - --hash=sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a \ - --hash=sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5 \ - --hash=sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94 \ - --hash=sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c \ - --hash=sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d \ - --hash=sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef \ - --hash=sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26 \ - --hash=sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2 \ - --hash=sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c \ - --hash=sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0 \ - --hash=sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2 \ - --hash=sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4 \ - --hash=sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d \ - --hash=sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2 \ - --hash=sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce \ - --hash=sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34 \ - --hash=sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f \ - --hash=sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d \ - --hash=sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b \ - --hash=sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07 \ - --hash=sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312 \ - --hash=sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057 \ - --hash=sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d \ - --hash=sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af \ - --hash=sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb \ - --hash=sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd \ - --hash=sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78 \ - --hash=sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b \ - --hash=sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223 \ - --hash=sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a \ - --hash=sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4 \ - --hash=sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5 \ - --hash=sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23 \ - --hash=sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a \ - --hash=sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4 \ - --hash=sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8 \ - --hash=sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d \ - --hash=sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443 \ - --hash=sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e \ - --hash=sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f \ - --hash=sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e \ - --hash=sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d \ - --hash=sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc \ - --hash=sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443 \ - --hash=sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be \ - --hash=sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2 \ - --hash=sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee \ - --hash=sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f \ - --hash=sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae \ - --hash=sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864 \ - --hash=sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4 \ - --hash=sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951 \ - --hash=sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc -pydantic-settings==2.3.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:87fda838b64b5039b970cd47c3e8a1ee460ce136278ff672980af21516f6e6ce \ - --hash=sha256:e4ed62ad851670975ec11285141db888fd24947f9440bd4380d7d8788d4965de -pydantic==2.7.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52 \ - --hash=sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0 +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a retry2==0.9.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f7fee13b1e15d0611c462910a6aa72a8919823988dd0412152bc3719c89a4e55 -setuptools==70.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4 \ - --hash=sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc diff --git a/octopoes/poetry.lock b/octopoes/poetry.lock index a53f9e4f488..d1e929aaeeb 100644 --- a/octopoes/poetry.lock +++ b/octopoes/poetry.lock @@ -475,13 +475,13 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi-slim" -version = "0.111.0" +version = "0.111.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi_slim-0.111.0-py3-none-any.whl", hash = "sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2"}, - {file = "fastapi_slim-0.111.0.tar.gz", hash = "sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec"}, + {file = "fastapi_slim-0.111.1-py3-none-any.whl", hash = "sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb"}, + {file = "fastapi_slim-0.111.1.tar.gz", hash = "sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d"}, ] [package.dependencies] @@ -491,7 +491,7 @@ typing-extensions = ">=4.8.0" [package.extras] all = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.7)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "filelock" @@ -864,42 +864,42 @@ files = [ [[package]] name = "opentelemetry-api" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.24.0-py3-none-any.whl", hash = "sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2"}, - {file = "opentelemetry_api-1.24.0.tar.gz", hash = "sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e"}, + {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, + {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.0" +importlib-metadata = ">=6.0,<=7.1" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Protobuf encoding" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0-py3-none-any.whl", hash = "sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0.tar.gz", hash = "sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, ] [package.dependencies] -opentelemetry-proto = "1.24.0" +opentelemetry-proto = "1.25.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0-py3-none-any.whl", hash = "sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0.tar.gz", hash = "sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, ] [package.dependencies] @@ -907,22 +907,19 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.24.0" -opentelemetry-proto = "1.24.0" -opentelemetry-sdk = ">=1.24.0,<1.25.0" - -[package.extras] -test = ["pytest-grpc"] +opentelemetry-exporter-otlp-proto-common = "1.25.0" +opentelemetry-proto = "1.25.0" +opentelemetry-sdk = ">=1.25.0,<1.26.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.45b0" +version = "0.46b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.45b0-py3-none-any.whl", hash = "sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258"}, - {file = "opentelemetry_instrumentation-0.45b0.tar.gz", hash = "sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e"}, + {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, + {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, ] [package.dependencies] @@ -932,111 +929,111 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.45b0" +version = "0.46b0" description = "ASGI instrumentation for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_asgi-0.45b0-py3-none-any.whl", hash = "sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b"}, - {file = "opentelemetry_instrumentation_asgi-0.45b0.tar.gz", hash = "sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6"}, + {file = "opentelemetry_instrumentation_asgi-0.46b0-py3-none-any.whl", hash = "sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759"}, + {file = "opentelemetry_instrumentation_asgi-0.46b0.tar.gz", hash = "sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a"}, ] [package.dependencies] asgiref = ">=3.0,<4.0" opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["asgiref (>=3.0,<4.0)"] [[package]] name = "opentelemetry-instrumentation-dbapi" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry Database API instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_dbapi-0.45b0-py3-none-any.whl", hash = "sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618"}, - {file = "opentelemetry_instrumentation_dbapi-0.45b0.tar.gz", hash = "sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c"}, + {file = "opentelemetry_instrumentation_dbapi-0.46b0-py3-none-any.whl", hash = "sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783"}, + {file = "opentelemetry_instrumentation_dbapi-0.46b0.tar.gz", hash = "sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry FastAPI Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_fastapi-0.45b0-py3-none-any.whl", hash = "sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314"}, - {file = "opentelemetry_instrumentation_fastapi-0.45b0.tar.gz", hash = "sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e"}, + {file = "opentelemetry_instrumentation_fastapi-0.46b0-py3-none-any.whl", hash = "sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33"}, + {file = "opentelemetry_instrumentation_fastapi-0.46b0.tar.gz", hash = "sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-instrumentation-asgi = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-instrumentation-asgi = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["fastapi (>=0.58,<1.0)"] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry HTTPX Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_httpx-0.45b0-py3-none-any.whl", hash = "sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225"}, - {file = "opentelemetry_instrumentation_httpx-0.45b0.tar.gz", hash = "sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d"}, + {file = "opentelemetry_instrumentation_httpx-0.46b0-py3-none-any.whl", hash = "sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc"}, + {file = "opentelemetry_instrumentation_httpx-0.46b0.tar.gz", hash = "sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["httpx (>=0.18.0)"] [[package]] name = "opentelemetry-instrumentation-psycopg2" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry psycopg2 instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_psycopg2-0.45b0-py3-none-any.whl", hash = "sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7"}, - {file = "opentelemetry_instrumentation_psycopg2-0.45b0.tar.gz", hash = "sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0"}, + {file = "opentelemetry_instrumentation_psycopg2-0.46b0-py3-none-any.whl", hash = "sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899"}, + {file = "opentelemetry_instrumentation_psycopg2-0.46b0.tar.gz", hash = "sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-instrumentation-dbapi = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-instrumentation-dbapi = "0.46b0" [package.extras] instruments = ["psycopg2 (>=2.7.3.1)"] [[package]] name = "opentelemetry-proto" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python Proto" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.24.0-py3-none-any.whl", hash = "sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce"}, - {file = "opentelemetry_proto-1.24.0.tar.gz", hash = "sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8"}, + {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, + {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, ] [package.dependencies] @@ -1044,40 +1041,43 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.24.0-py3-none-any.whl", hash = "sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59"}, - {file = "opentelemetry_sdk-1.24.0.tar.gz", hash = "sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5"}, + {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, + {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, ] [package.dependencies] -opentelemetry-api = "1.24.0" -opentelemetry-semantic-conventions = "0.45b0" +opentelemetry-api = "1.25.0" +opentelemetry-semantic-conventions = "0.46b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.45b0-py3-none-any.whl", hash = "sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864"}, - {file = "opentelemetry_semantic_conventions-0.45b0.tar.gz", hash = "sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118"}, + {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, + {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, ] +[package.dependencies] +opentelemetry-api = "1.25.0" + [[package]] name = "opentelemetry-util-http" -version = "0.45b0" +version = "0.46b0" description = "Web util for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_util_http-0.45b0-py3-none-any.whl", hash = "sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33"}, - {file = "opentelemetry_util_http-0.45b0.tar.gz", hash = "sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd"}, + {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"}, + {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"}, ] [[package]] @@ -1158,109 +1158,122 @@ files = [ [[package]] name = "pydantic" -version = "2.7.1" +version = "2.8.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"}, - {file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"}, + {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, + {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.18.2" -typing-extensions = ">=4.6.1" +pydantic-core = "2.20.1" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] [package.extras] email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.18.2" +version = "2.20.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"}, - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"}, - {file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"}, - {file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"}, - {file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"}, - {file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"}, - {file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"}, - {file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"}, - {file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"}, - {file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"}, - {file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"}, - {file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"}, - {file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"}, - {file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"}, - {file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, + {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, + {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, + {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, + {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, + {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, + {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, + {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, + {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, + {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, + {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, + {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, + {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, + {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, ] [package.dependencies] @@ -1268,17 +1281,17 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.2.1" +version = "2.3.4" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"}, - {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"}, + {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, + {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, ] [package.dependencies] -pydantic = ">=2.3.0" +pydantic = ">=2.7.0" python-dotenv = ">=0.21.0" [package.extras] @@ -1510,13 +1523,13 @@ rpds-py = ">=0.7.0" [[package]] name = "requests" -version = "2.32.2" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, - {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -1697,19 +1710,19 @@ files = [ [[package]] name = "setuptools" -version = "69.5.1" +version = "71.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.5.1-py3-none-any.whl", hash = "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"}, - {file = "setuptools-69.5.1.tar.gz", hash = "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987"}, + {file = "setuptools-71.0.3-py3-none-any.whl", hash = "sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207"}, + {file = "setuptools-71.0.3.tar.gz", hash = "sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (<7.4)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -1837,18 +1850,18 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "structlog" -version = "24.2.0" +version = "24.4.0" description = "Structured Logging for Python" optional = false python-versions = ">=3.8" files = [ - {file = "structlog-24.2.0-py3-none-any.whl", hash = "sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a"}, - {file = "structlog-24.2.0.tar.gz", hash = "sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b"}, + {file = "structlog-24.4.0-py3-none-any.whl", hash = "sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610"}, + {file = "structlog-24.4.0.tar.gz", hash = "sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4"}, ] [package.extras] dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] typing = ["mypy (>=1.4)", "rich", "twisted"] @@ -1882,13 +1895,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.11.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -2107,4 +2120,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "9c15b17d7b5e59678003fea67a3f095f2712d09e1a3e12358447a6335ea74836" +content-hash = "66519283cdace78ec8340a8a02ca12f2ac5715fb1bc3e9006962f79af3ba73af" diff --git a/octopoes/pyproject.toml b/octopoes/pyproject.toml index 73b99e0de88..fa5a8e082cc 100644 --- a/octopoes/pyproject.toml +++ b/octopoes/pyproject.toml @@ -21,25 +21,25 @@ celery = "^5.2.7" pyparsing = "^3.0.9" packaging = "^23.0" tldextract = "^3.4.0" -opentelemetry-sdk = "^1.24.0" -opentelemetry-instrumentation = "^0.45b0" -opentelemetry-exporter-otlp-proto-grpc = "^1.24.0" -opentelemetry-instrumentation-fastapi = "^0.45b0" -opentelemetry-instrumentation-psycopg2 = "^0.45b0" -opentelemetry-instrumentation-httpx = "^0.45b0" +opentelemetry-sdk = "^1.25.0" +opentelemetry-instrumentation = "^0.46b0" +opentelemetry-exporter-otlp-proto-grpc = "^1.25.0" +opentelemetry-instrumentation-fastapi = "^0.46b0" +opentelemetry-instrumentation-psycopg2 = "^0.46b0" +opentelemetry-instrumentation-httpx = "^0.46b0" sqlalchemy = "1.4.48" jsonschema = "^4.18.0" pydantic-settings = "^2.2.1" httpx = "^0.27.0" # required by disallowed-csp-hostnames bit link-shorteners = "^1.11.0" -opentelemetry-api = "^1.24.0" -opentelemetry-exporter-otlp-proto-common = "^1.24.0" -opentelemetry-instrumentation-asgi = "^0.45b0" -opentelemetry-instrumentation-dbapi = "^0.45b0" -opentelemetry-proto = "^1.24.0" -opentelemetry-semantic-conventions = "^0.45b0" -opentelemetry-util-http = "^0.45b0" +opentelemetry-api = "^1.25.0" +opentelemetry-exporter-otlp-proto-common = "^1.25.0" +opentelemetry-instrumentation-asgi = "^0.46b0" +opentelemetry-instrumentation-dbapi = "^0.46b0" +opentelemetry-proto = "^1.25.0" +opentelemetry-semantic-conventions = "^0.46b0" +opentelemetry-util-http = "^0.46b0" fastapi-slim = "^0.111.0" structlog = "^24.2.0" diff --git a/octopoes/requirements-dev.txt b/octopoes/requirements-dev.txt index b2e7b31bdb2..5fcaebf417c 100644 --- a/octopoes/requirements-dev.txt +++ b/octopoes/requirements-dev.txt @@ -193,9 +193,9 @@ dnspython==2.6.1 ; python_version >= "3.10" and python_version < "4.0" \ exceptiongroup==1.2.1 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad \ --hash=sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16 -fastapi-slim==0.111.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec \ - --hash=sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2 +fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ + --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d filelock==3.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f \ --hash=sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a @@ -351,45 +351,45 @@ kombu==5.3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5634c511926309c7f9789f1433e9ed402616b56836ef9878f01bd59267b4c7a9 link-shorteners==1.11.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:57cf820ca3edc823ac19c2bbef02c1ba94f0abbebe43536f66676047f2cdd711 -opentelemetry-api==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2 \ - --hash=sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e -opentelemetry-exporter-otlp-proto-common==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461 \ - --hash=sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641 -opentelemetry-exporter-otlp-proto-grpc==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa \ - --hash=sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b -opentelemetry-instrumentation-asgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b \ - --hash=sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6 -opentelemetry-instrumentation-dbapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618 \ - --hash=sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c -opentelemetry-instrumentation-fastapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e \ - --hash=sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314 -opentelemetry-instrumentation-httpx==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d \ - --hash=sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225 -opentelemetry-instrumentation-psycopg2==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7 \ - --hash=sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0 -opentelemetry-instrumentation==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258 \ - --hash=sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e -opentelemetry-proto==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce \ - --hash=sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8 -opentelemetry-sdk==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5 \ - --hash=sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59 -opentelemetry-semantic-conventions==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118 \ - --hash=sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864 -opentelemetry-util-http==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd \ - --hash=sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33 +opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ + --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 +opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ + --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 +opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ + --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac +opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ + --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 +opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ + --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 +opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ + --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 +opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ + --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 +opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ + --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c +opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ + --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda +opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ + --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f +opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ + --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 +opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ + --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa +opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ + --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 @@ -414,92 +414,102 @@ protobuf==4.25.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \ --hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \ --hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2 -pydantic-core==2.18.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b \ - --hash=sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a \ - --hash=sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90 \ - --hash=sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d \ - --hash=sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e \ - --hash=sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d \ - --hash=sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027 \ - --hash=sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804 \ - --hash=sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347 \ - --hash=sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400 \ - --hash=sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3 \ - --hash=sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399 \ - --hash=sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349 \ - --hash=sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd \ - --hash=sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c \ - --hash=sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e \ - --hash=sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413 \ - --hash=sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3 \ - --hash=sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e \ - --hash=sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3 \ - --hash=sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91 \ - --hash=sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce \ - --hash=sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c \ - --hash=sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb \ - --hash=sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664 \ - --hash=sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6 \ - --hash=sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd \ - --hash=sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3 \ - --hash=sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af \ - --hash=sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043 \ - --hash=sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350 \ - --hash=sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7 \ - --hash=sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0 \ - --hash=sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563 \ - --hash=sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761 \ - --hash=sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72 \ - --hash=sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3 \ - --hash=sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb \ - --hash=sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788 \ - --hash=sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b \ - --hash=sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c \ - --hash=sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038 \ - --hash=sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250 \ - --hash=sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec \ - --hash=sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c \ - --hash=sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74 \ - --hash=sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81 \ - --hash=sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439 \ - --hash=sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75 \ - --hash=sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0 \ - --hash=sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8 \ - --hash=sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150 \ - --hash=sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438 \ - --hash=sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae \ - --hash=sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857 \ - --hash=sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038 \ - --hash=sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374 \ - --hash=sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f \ - --hash=sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241 \ - --hash=sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592 \ - --hash=sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4 \ - --hash=sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d \ - --hash=sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b \ - --hash=sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b \ - --hash=sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182 \ - --hash=sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e \ - --hash=sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641 \ - --hash=sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70 \ - --hash=sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9 \ - --hash=sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a \ - --hash=sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543 \ - --hash=sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b \ - --hash=sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f \ - --hash=sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38 \ - --hash=sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845 \ - --hash=sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2 \ - --hash=sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0 \ - --hash=sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4 \ - --hash=sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242 -pydantic-settings==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ - --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 -pydantic==2.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5 \ - --hash=sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pyparsing==3.1.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad \ --hash=sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742 @@ -583,9 +593,9 @@ referencing==0.35.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8080727b30e364e5783152903672df9b6b091c926a146a759080b62ca3126cd6 requests-file==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 -requests==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ - --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c +requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 robotframework-httplibrary==0.4.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f45c9ac8d5a56386a36dc354b7491ee54bf068ff525c8011cb83184c19f56aae robotframework-requests==0.9.7 ; python_version >= "3.10" and python_version < "4.0" \ @@ -694,9 +704,9 @@ rpds-py==0.18.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca \ --hash=sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58 \ --hash=sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e -setuptools==69.5.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987 \ - --hash=sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 @@ -751,18 +761,18 @@ sqlalchemy==1.4.48 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 -structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ - --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a +structlog==24.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610 \ + --hash=sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4 tldextract==3.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2cb271ca8d06ea1630a1361b58edad14e0cf81f34ce3c90b052854528fe2a281 \ --hash=sha256:4df1c65b95be61d59428e8611e955e54e6f1d4483d3e8d5733d3a9062155e910 tomli==2.0.1 ; python_version >= "3.10" and python_full_version <= "3.11.0a6" \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f -typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ - --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a +typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 tzdata==2024.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd \ --hash=sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252 diff --git a/octopoes/requirements.txt b/octopoes/requirements.txt index 8a0ff99e452..d65d563b29b 100644 --- a/octopoes/requirements.txt +++ b/octopoes/requirements.txt @@ -137,9 +137,9 @@ dnspython==2.6.1 ; python_version >= "3.10" and python_version < "4.0" \ exceptiongroup==1.2.1 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad \ --hash=sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16 -fastapi-slim==0.111.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec \ - --hash=sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2 +fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ + --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d filelock==3.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f \ --hash=sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a @@ -286,45 +286,45 @@ kombu==5.3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5634c511926309c7f9789f1433e9ed402616b56836ef9878f01bd59267b4c7a9 link-shorteners==1.11.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:57cf820ca3edc823ac19c2bbef02c1ba94f0abbebe43536f66676047f2cdd711 -opentelemetry-api==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2 \ - --hash=sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e -opentelemetry-exporter-otlp-proto-common==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461 \ - --hash=sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641 -opentelemetry-exporter-otlp-proto-grpc==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa \ - --hash=sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b -opentelemetry-instrumentation-asgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b \ - --hash=sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6 -opentelemetry-instrumentation-dbapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618 \ - --hash=sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c -opentelemetry-instrumentation-fastapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e \ - --hash=sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314 -opentelemetry-instrumentation-httpx==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d \ - --hash=sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225 -opentelemetry-instrumentation-psycopg2==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7 \ - --hash=sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0 -opentelemetry-instrumentation==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258 \ - --hash=sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e -opentelemetry-proto==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce \ - --hash=sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8 -opentelemetry-sdk==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5 \ - --hash=sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59 -opentelemetry-semantic-conventions==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118 \ - --hash=sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864 -opentelemetry-util-http==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd \ - --hash=sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33 +opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ + --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 +opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ + --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 +opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ + --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac +opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ + --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 +opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ + --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 +opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ + --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 +opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ + --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 +opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ + --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c +opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ + --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda +opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ + --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f +opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ + --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 +opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ + --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa +opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ + --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 @@ -346,92 +346,102 @@ protobuf==4.25.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \ --hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \ --hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2 -pydantic-core==2.18.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b \ - --hash=sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a \ - --hash=sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90 \ - --hash=sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d \ - --hash=sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e \ - --hash=sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d \ - --hash=sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027 \ - --hash=sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804 \ - --hash=sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347 \ - --hash=sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400 \ - --hash=sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3 \ - --hash=sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399 \ - --hash=sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349 \ - --hash=sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd \ - --hash=sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c \ - --hash=sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e \ - --hash=sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413 \ - --hash=sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3 \ - --hash=sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e \ - --hash=sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3 \ - --hash=sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91 \ - --hash=sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce \ - --hash=sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c \ - --hash=sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb \ - --hash=sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664 \ - --hash=sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6 \ - --hash=sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd \ - --hash=sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3 \ - --hash=sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af \ - --hash=sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043 \ - --hash=sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350 \ - --hash=sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7 \ - --hash=sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0 \ - --hash=sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563 \ - --hash=sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761 \ - --hash=sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72 \ - --hash=sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3 \ - --hash=sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb \ - --hash=sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788 \ - --hash=sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b \ - --hash=sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c \ - --hash=sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038 \ - --hash=sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250 \ - --hash=sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec \ - --hash=sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c \ - --hash=sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74 \ - --hash=sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81 \ - --hash=sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439 \ - --hash=sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75 \ - --hash=sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0 \ - --hash=sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8 \ - --hash=sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150 \ - --hash=sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438 \ - --hash=sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae \ - --hash=sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857 \ - --hash=sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038 \ - --hash=sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374 \ - --hash=sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f \ - --hash=sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241 \ - --hash=sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592 \ - --hash=sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4 \ - --hash=sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d \ - --hash=sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b \ - --hash=sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b \ - --hash=sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182 \ - --hash=sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e \ - --hash=sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641 \ - --hash=sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70 \ - --hash=sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9 \ - --hash=sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a \ - --hash=sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543 \ - --hash=sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b \ - --hash=sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f \ - --hash=sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38 \ - --hash=sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845 \ - --hash=sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2 \ - --hash=sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0 \ - --hash=sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4 \ - --hash=sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242 -pydantic-settings==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ - --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 -pydantic==2.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5 \ - --hash=sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pyparsing==3.1.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad \ --hash=sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742 @@ -497,9 +507,9 @@ referencing==0.35.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8080727b30e364e5783152903672df9b6b091c926a146a759080b62ca3126cd6 requests-file==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 -requests==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ - --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c +requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 rpds-py==0.18.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f \ --hash=sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c \ @@ -600,9 +610,9 @@ rpds-py==0.18.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca \ --hash=sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58 \ --hash=sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e -setuptools==69.5.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987 \ - --hash=sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 @@ -654,15 +664,15 @@ sqlalchemy==1.4.48 ; python_version >= "3.10" and python_version < "4.0" \ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 -structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ - --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a +structlog==24.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610 \ + --hash=sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4 tldextract==3.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2cb271ca8d06ea1630a1361b58edad14e0cf81f34ce3c90b052854528fe2a281 \ --hash=sha256:4df1c65b95be61d59428e8611e955e54e6f1d4483d3e8d5733d3a9062155e910 -typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ - --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a +typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 tzdata==2024.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd \ --hash=sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252 diff --git a/poetry.lock b/poetry.lock index fdc0838def6..75445e355ae 100644 --- a/poetry.lock +++ b/poetry.lock @@ -395,120 +395,133 @@ testing-docutils = ["pygments", "pytest (>=8,<9)", "pytest-param-files (>=0.6.0, [[package]] name = "packaging" -version = "24.0" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] name = "pydantic" -version = "2.7.1" +version = "2.8.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"}, - {file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"}, + {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, + {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.18.2" -typing-extensions = ">=4.6.1" +pydantic-core = "2.20.1" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] [package.extras] email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.18.2" +version = "2.20.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"}, - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"}, - {file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"}, - {file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"}, - {file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"}, - {file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"}, - {file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"}, - {file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"}, - {file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"}, - {file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"}, - {file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"}, - {file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"}, - {file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"}, - {file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"}, - {file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, + {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, + {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, + {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, + {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, + {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, + {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, + {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, + {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, + {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, + {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, + {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, + {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, + {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, ] [package.dependencies] @@ -516,17 +529,17 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.2.1" +version = "2.3.4" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"}, - {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"}, + {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, + {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, ] [package.dependencies] -pydantic = ">=2.3.0" +pydantic = ">=2.7.0" python-dotenv = ">=0.21.0" [package.extras] @@ -622,13 +635,13 @@ files = [ [[package]] name = "requests" -version = "2.32.2" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, - {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -700,26 +713,26 @@ files = [ [[package]] name = "sphinx" -version = "7.3.7" +version = "7.4.6" description = "Python documentation generator" optional = false python-versions = ">=3.9" files = [ - {file = "sphinx-7.3.7-py3-none-any.whl", hash = "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3"}, - {file = "sphinx-7.3.7.tar.gz", hash = "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc"}, + {file = "sphinx-7.4.6-py3-none-any.whl", hash = "sha256:915760d6188288a1e30c2cd0d9fa31b1b009bc6e6019cc0c32d16c77d20e86d9"}, + {file = "sphinx-7.4.6.tar.gz", hash = "sha256:116918d455c493fff3178edea12b4fe1c1e4894680fd81e7b7431ea21d47ca52"}, ] [package.dependencies] alabaster = ">=0.7.14,<0.8.0" -babel = ">=2.9" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.18.1,<0.22" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" imagesize = ">=1.3" -Jinja2 = ">=3.0" -packaging = ">=21.0" -Pygments = ">=2.14" -requests = ">=2.25.0" -snowballstemmer = ">=2.0" +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +snowballstemmer = ">=2.2" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" sphinxcontrib-htmlhelp = ">=2.0.0" @@ -730,8 +743,8 @@ tomli = {version = ">=2", markers = "python_version < \"3.11\""} [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "importlib_metadata", "mypy (==1.9.0)", "pytest (>=6.0)", "ruff (==0.3.7)", "sphinx-lint", "tomli", "types-docutils", "types-requests"] -test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=6.0)", "setuptools (>=67.0)"] +lint = ["flake8 (>=6.0)", "importlib-metadata (>=6.0)", "mypy (==1.10.1)", "pytest (>=6.0)", "ruff (==0.5.2)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-docutils (==0.21.0.20240711)", "types-requests (>=2.30.0)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] [[package]] name = "sphinx-rtd-theme" @@ -908,13 +921,13 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. [[package]] name = "typing-extensions" -version = "4.11.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] diff --git a/requirements.txt b/requirements.txt index 6810d572002..32b83b398bc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -194,95 +194,105 @@ mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" \ myst-parser==3.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1 \ --hash=sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87 -packaging==24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \ - --hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9 -pydantic-core==2.18.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b \ - --hash=sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a \ - --hash=sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90 \ - --hash=sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d \ - --hash=sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e \ - --hash=sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d \ - --hash=sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027 \ - --hash=sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804 \ - --hash=sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347 \ - --hash=sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400 \ - --hash=sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3 \ - --hash=sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399 \ - --hash=sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349 \ - --hash=sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd \ - --hash=sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c \ - --hash=sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e \ - --hash=sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413 \ - --hash=sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3 \ - --hash=sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e \ - --hash=sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3 \ - --hash=sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91 \ - --hash=sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce \ - --hash=sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c \ - --hash=sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb \ - --hash=sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664 \ - --hash=sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6 \ - --hash=sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd \ - --hash=sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3 \ - --hash=sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af \ - --hash=sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043 \ - --hash=sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350 \ - --hash=sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7 \ - --hash=sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0 \ - --hash=sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563 \ - --hash=sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761 \ - --hash=sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72 \ - --hash=sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3 \ - --hash=sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb \ - --hash=sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788 \ - --hash=sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b \ - --hash=sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c \ - --hash=sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038 \ - --hash=sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250 \ - --hash=sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec \ - --hash=sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c \ - --hash=sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74 \ - --hash=sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81 \ - --hash=sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439 \ - --hash=sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75 \ - --hash=sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0 \ - --hash=sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8 \ - --hash=sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150 \ - --hash=sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438 \ - --hash=sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae \ - --hash=sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857 \ - --hash=sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038 \ - --hash=sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374 \ - --hash=sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f \ - --hash=sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241 \ - --hash=sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592 \ - --hash=sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4 \ - --hash=sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d \ - --hash=sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b \ - --hash=sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b \ - --hash=sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182 \ - --hash=sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e \ - --hash=sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641 \ - --hash=sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70 \ - --hash=sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9 \ - --hash=sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a \ - --hash=sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543 \ - --hash=sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b \ - --hash=sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f \ - --hash=sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38 \ - --hash=sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845 \ - --hash=sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2 \ - --hash=sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0 \ - --hash=sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4 \ - --hash=sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242 -pydantic-settings==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ - --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 -pydantic==2.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5 \ - --hash=sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc +packaging==24.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ + --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pygments==2.18.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a @@ -340,9 +350,9 @@ pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \ --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \ --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f -requests==2.32.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ - --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c +requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 rich==13.7.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \ --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432 @@ -358,9 +368,9 @@ snowballstemmer==2.2.0 ; python_version >= "3.10" and python_version < "4.0" \ sphinx-rtd-theme==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b \ --hash=sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586 -sphinx==7.3.7 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3 \ - --hash=sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc +sphinx==7.4.6 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:116918d455c493fff3178edea12b4fe1c1e4894680fd81e7b7431ea21d47ca52 \ + --hash=sha256:915760d6188288a1e30c2cd0d9fa31b1b009bc6e6019cc0c32d16c77d20e86d9 sphinxcontrib-applehelp==1.0.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619 \ --hash=sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4 @@ -391,9 +401,9 @@ tomli==2.0.1 ; python_version >= "3.10" and python_version < "3.11" \ typer[all]==0.9.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:aa6c4a4e2329d868b80ecbaf16f807f2b54e192209d7ac9dd42691d63f7a54eb \ --hash=sha256:f714c2d90afae3a7929fcd72a3abb08df305e1ff61719381384211c4070af57f -typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ - --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a +typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 urllib3==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 diff --git a/rocky/poetry.lock b/rocky/poetry.lock index 71e7357e144..39d27072008 100644 --- a/rocky/poetry.lock +++ b/rocky/poetry.lock @@ -1538,42 +1538,42 @@ django = ">=1.11.0" [[package]] name = "opentelemetry-api" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.24.0-py3-none-any.whl", hash = "sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2"}, - {file = "opentelemetry_api-1.24.0.tar.gz", hash = "sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e"}, + {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, + {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.0" +importlib-metadata = ">=6.0,<=7.1" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Protobuf encoding" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0-py3-none-any.whl", hash = "sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0.tar.gz", hash = "sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, ] [package.dependencies] -opentelemetry-proto = "1.24.0" +opentelemetry-proto = "1.25.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0-py3-none-any.whl", hash = "sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0.tar.gz", hash = "sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, ] [package.dependencies] @@ -1581,22 +1581,19 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.24.0" -opentelemetry-proto = "1.24.0" -opentelemetry-sdk = ">=1.24.0,<1.25.0" - -[package.extras] -test = ["pytest-grpc"] +opentelemetry-exporter-otlp-proto-common = "1.25.0" +opentelemetry-proto = "1.25.0" +opentelemetry-sdk = ">=1.25.0,<1.26.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.45b0" +version = "0.46b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.45b0-py3-none-any.whl", hash = "sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258"}, - {file = "opentelemetry_instrumentation-0.45b0.tar.gz", hash = "sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e"}, + {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, + {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, ] [package.dependencies] @@ -1606,150 +1603,150 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.45b0" +version = "0.46b0" description = "ASGI instrumentation for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_asgi-0.45b0-py3-none-any.whl", hash = "sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b"}, - {file = "opentelemetry_instrumentation_asgi-0.45b0.tar.gz", hash = "sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6"}, + {file = "opentelemetry_instrumentation_asgi-0.46b0-py3-none-any.whl", hash = "sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759"}, + {file = "opentelemetry_instrumentation_asgi-0.46b0.tar.gz", hash = "sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a"}, ] [package.dependencies] asgiref = ">=3.0,<4.0" opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["asgiref (>=3.0,<4.0)"] [[package]] name = "opentelemetry-instrumentation-dbapi" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry Database API instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_dbapi-0.45b0-py3-none-any.whl", hash = "sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618"}, - {file = "opentelemetry_instrumentation_dbapi-0.45b0.tar.gz", hash = "sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c"}, + {file = "opentelemetry_instrumentation_dbapi-0.46b0-py3-none-any.whl", hash = "sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783"}, + {file = "opentelemetry_instrumentation_dbapi-0.46b0.tar.gz", hash = "sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-django" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry Instrumentation for Django" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_django-0.45b0-py3-none-any.whl", hash = "sha256:1e612c90eb4c69e1f0aa2e38dea89c47616596d3600392640fa7c0a201e299fa"}, - {file = "opentelemetry_instrumentation_django-0.45b0.tar.gz", hash = "sha256:d8b55747d6784167ab3a50dc128cc13b6966a2215ce55f4043392ac1c83b5bb2"}, + {file = "opentelemetry_instrumentation_django-0.46b0-py3-none-any.whl", hash = "sha256:ecc85941263122f99dbd96463a981b2d1eeea618ca287a58abe0af9fd67631ee"}, + {file = "opentelemetry_instrumentation_django-0.46b0.tar.gz", hash = "sha256:cc11b2e24f9bdd20759570390ed8619d9c5acbf788b4a5401e36e280dfc20feb"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-instrumentation-wsgi = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-instrumentation-wsgi = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] -asgi = ["opentelemetry-instrumentation-asgi (==0.45b0)"] +asgi = ["opentelemetry-instrumentation-asgi (==0.46b0)"] instruments = ["django (>=1.10)"] [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry FastAPI Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_fastapi-0.45b0-py3-none-any.whl", hash = "sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314"}, - {file = "opentelemetry_instrumentation_fastapi-0.45b0.tar.gz", hash = "sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e"}, + {file = "opentelemetry_instrumentation_fastapi-0.46b0-py3-none-any.whl", hash = "sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33"}, + {file = "opentelemetry_instrumentation_fastapi-0.46b0.tar.gz", hash = "sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-instrumentation-asgi = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-instrumentation-asgi = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["fastapi (>=0.58,<1.0)"] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry HTTPX Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_httpx-0.45b0-py3-none-any.whl", hash = "sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225"}, - {file = "opentelemetry_instrumentation_httpx-0.45b0.tar.gz", hash = "sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d"}, + {file = "opentelemetry_instrumentation_httpx-0.46b0-py3-none-any.whl", hash = "sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc"}, + {file = "opentelemetry_instrumentation_httpx-0.46b0.tar.gz", hash = "sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [package.extras] instruments = ["httpx (>=0.18.0)"] [[package]] name = "opentelemetry-instrumentation-psycopg2" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry psycopg2 instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_psycopg2-0.45b0-py3-none-any.whl", hash = "sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7"}, - {file = "opentelemetry_instrumentation_psycopg2-0.45b0.tar.gz", hash = "sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0"}, + {file = "opentelemetry_instrumentation_psycopg2-0.46b0-py3-none-any.whl", hash = "sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899"}, + {file = "opentelemetry_instrumentation_psycopg2-0.46b0.tar.gz", hash = "sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-instrumentation-dbapi = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-instrumentation-dbapi = "0.46b0" [package.extras] instruments = ["psycopg2 (>=2.7.3.1)"] [[package]] name = "opentelemetry-instrumentation-wsgi" -version = "0.45b0" +version = "0.46b0" description = "WSGI Middleware for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_wsgi-0.45b0-py3-none-any.whl", hash = "sha256:7a6f9c71b25f5c5e112827540008882f6a9088447cb65745e7f2083749516663"}, - {file = "opentelemetry_instrumentation_wsgi-0.45b0.tar.gz", hash = "sha256:f53a2a38e6582406e207d404e4c1b859b83bec11a68ad6c7366642d01c873ad0"}, + {file = "opentelemetry_instrumentation_wsgi-0.46b0-py3-none-any.whl", hash = "sha256:2386014b026f5307c802417eeab74265785ae3dd6eee8c5581a830e3b2d3435b"}, + {file = "opentelemetry_instrumentation_wsgi-0.46b0.tar.gz", hash = "sha256:f4e1001e8477eb546cac7c13cff0b0cf127812b1188a37bcaa3e43eb741451e2"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.46b0" +opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-util-http = "0.46b0" [[package]] name = "opentelemetry-proto" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python Proto" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.24.0-py3-none-any.whl", hash = "sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce"}, - {file = "opentelemetry_proto-1.24.0.tar.gz", hash = "sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8"}, + {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, + {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, ] [package.dependencies] @@ -1757,40 +1754,43 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.24.0-py3-none-any.whl", hash = "sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59"}, - {file = "opentelemetry_sdk-1.24.0.tar.gz", hash = "sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5"}, + {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, + {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, ] [package.dependencies] -opentelemetry-api = "1.24.0" -opentelemetry-semantic-conventions = "0.45b0" +opentelemetry-api = "1.25.0" +opentelemetry-semantic-conventions = "0.46b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.45b0-py3-none-any.whl", hash = "sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864"}, - {file = "opentelemetry_semantic_conventions-0.45b0.tar.gz", hash = "sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118"}, + {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, + {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, ] +[package.dependencies] +opentelemetry-api = "1.25.0" + [[package]] name = "opentelemetry-util-http" -version = "0.45b0" +version = "0.46b0" description = "Web util for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_util_http-0.45b0-py3-none-any.whl", hash = "sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33"}, - {file = "opentelemetry_util_http-0.45b0.tar.gz", hash = "sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd"}, + {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"}, + {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"}, ] [[package]] @@ -2009,109 +2009,122 @@ files = [ [[package]] name = "pydantic" -version = "2.7.1" +version = "2.8.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"}, - {file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"}, + {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, + {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.18.2" -typing-extensions = ">=4.6.1" +pydantic-core = "2.20.1" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] [package.extras] email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.18.2" +version = "2.20.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"}, - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"}, - {file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"}, - {file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"}, - {file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"}, - {file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"}, - {file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"}, - {file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"}, - {file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"}, - {file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"}, - {file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"}, - {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"}, - {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"}, - {file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"}, - {file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"}, - {file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"}, - {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"}, - {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"}, - {file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"}, - {file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"}, - {file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, + {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, + {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, + {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, + {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, + {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, + {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, + {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, + {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, + {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, + {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, + {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, + {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, + {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, ] [package.dependencies] @@ -2119,17 +2132,17 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.2.1" +version = "2.3.4" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"}, - {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"}, + {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, + {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, ] [package.dependencies] -pydantic = ">=2.3.0" +pydantic = ">=2.7.0" python-dotenv = ">=0.21.0" [package.extras] @@ -2981,19 +2994,19 @@ files = [ [[package]] name = "setuptools" -version = "69.1.0" +version = "71.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, - {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, + {file = "setuptools-71.0.3-py3-none-any.whl", hash = "sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207"}, + {file = "setuptools-71.0.3.tar.gz", hash = "sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (<7.4)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -3061,18 +3074,18 @@ test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] [[package]] name = "structlog" -version = "24.2.0" +version = "24.4.0" description = "Structured Logging for Python" optional = false python-versions = ">=3.8" files = [ - {file = "structlog-24.2.0-py3-none-any.whl", hash = "sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a"}, - {file = "structlog-24.2.0.tar.gz", hash = "sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b"}, + {file = "structlog-24.4.0-py3-none-any.whl", hash = "sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610"}, + {file = "structlog-24.4.0.tar.gz", hash = "sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4"}, ] [package.extras] dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] typing = ["mypy (>=1.4)", "rich", "twisted"] @@ -3127,13 +3140,13 @@ telegram = ["requests"] [[package]] name = "typing-extensions" -version = "4.11.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -3430,4 +3443,4 @@ test = ["pytest"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "20b560adc29a6680cfee2c5b0531359495d1cd516c1a97588c231ab478b08de0" +content-hash = "7322127db1a770df4576a537fdaf4f6a364b43d49ecf01916cbfa9c0b24cf522" diff --git a/rocky/pyproject.toml b/rocky/pyproject.toml index 2f314f85508..aad6eca0c71 100644 --- a/rocky/pyproject.toml +++ b/rocky/pyproject.toml @@ -27,29 +27,29 @@ strenum = "^0.4.15" django-rest-knox = { git = "https://github.com/jazzband/django-rest-knox", rev = "dd7b062147bc4b9718e22d5acd6cf1301a1036b9" } # OpenTelemetry -opentelemetry-sdk = "^1.24.0" -opentelemetry-exporter-otlp-proto-grpc = "^1.24.0" -opentelemetry-instrumentation-django = "^0.45b0" -opentelemetry-instrumentation-psycopg2 = "^0.45b0" +opentelemetry-sdk = "^1.25.0" +opentelemetry-exporter-otlp-proto-grpc = "^1.25.0" +opentelemetry-instrumentation-django = "^0.46b0" +opentelemetry-instrumentation-psycopg2 = "^0.46b0" whitenoise = { extras = ["brotli"], version = "^6.5.0" } -opentelemetry-instrumentation = "^0.45b0" -opentelemetry-instrumentation-fastapi = "^0.45b0" +opentelemetry-instrumentation = "^0.46b0" +opentelemetry-instrumentation-fastapi = "^0.46b0" granian = "^1.3.2" django-components = "^0.80" # These used in octopoes parts that are used by rocky pyparsing = "^3.1.1" pydantic-settings = "^2.0.3" -opentelemetry-instrumentation-httpx = "^0.45b0" +opentelemetry-instrumentation-httpx = "^0.46b0" httpx = "^0.27.0" -opentelemetry-api = "^1.24.0" -opentelemetry-exporter-otlp-proto-common = "^1.24.0" -opentelemetry-instrumentation-asgi = "^0.45b0" -opentelemetry-instrumentation-dbapi = "^0.45b0" -opentelemetry-instrumentation-wsgi = "^0.45b0" -opentelemetry-proto = "^1.24.0" -opentelemetry-semantic-conventions = "^0.45b0" -opentelemetry-util-http = "^0.45b0" +opentelemetry-api = "^1.25.0" +opentelemetry-exporter-otlp-proto-common = "^1.25.0" +opentelemetry-instrumentation-asgi = "^0.46b0" +opentelemetry-instrumentation-dbapi = "^0.46b0" +opentelemetry-instrumentation-wsgi = "^0.46b0" +opentelemetry-proto = "^1.25.0" +opentelemetry-semantic-conventions = "^0.46b0" +opentelemetry-util-http = "^0.46b0" structlog = "^24.2.0" django-structlog = "^8.1.0" diff --git a/rocky/requirements-dev.txt b/rocky/requirements-dev.txt index dd9a5744a8f..7b8f02c7719 100644 --- a/rocky/requirements-dev.txt +++ b/rocky/requirements-dev.txt @@ -663,51 +663,51 @@ mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" \ model-mommy==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:3d332afce941c57f1990f45b083ba13252ba74fcd1ae43fd047e5af7a70fb312 \ --hash=sha256:40d6e740aad7509e696a324b94cf2b0a104da93c3d4a7924cea1be3d0eb95b4f -opentelemetry-api==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2 \ - --hash=sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e -opentelemetry-exporter-otlp-proto-common==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461 \ - --hash=sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641 -opentelemetry-exporter-otlp-proto-grpc==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa \ - --hash=sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b -opentelemetry-instrumentation-asgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b \ - --hash=sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6 -opentelemetry-instrumentation-dbapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618 \ - --hash=sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c -opentelemetry-instrumentation-django==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1e612c90eb4c69e1f0aa2e38dea89c47616596d3600392640fa7c0a201e299fa \ - --hash=sha256:d8b55747d6784167ab3a50dc128cc13b6966a2215ce55f4043392ac1c83b5bb2 -opentelemetry-instrumentation-fastapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e \ - --hash=sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314 -opentelemetry-instrumentation-httpx==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d \ - --hash=sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225 -opentelemetry-instrumentation-psycopg2==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7 \ - --hash=sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0 -opentelemetry-instrumentation-wsgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7a6f9c71b25f5c5e112827540008882f6a9088447cb65745e7f2083749516663 \ - --hash=sha256:f53a2a38e6582406e207d404e4c1b859b83bec11a68ad6c7366642d01c873ad0 -opentelemetry-instrumentation==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258 \ - --hash=sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e -opentelemetry-proto==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce \ - --hash=sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8 -opentelemetry-sdk==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5 \ - --hash=sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59 -opentelemetry-semantic-conventions==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118 \ - --hash=sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864 -opentelemetry-util-http==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd \ - --hash=sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33 +opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ + --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 +opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ + --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 +opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ + --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac +opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ + --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 +opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ + --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 +opentelemetry-instrumentation-django==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:cc11b2e24f9bdd20759570390ed8619d9c5acbf788b4a5401e36e280dfc20feb \ + --hash=sha256:ecc85941263122f99dbd96463a981b2d1eeea618ca287a58abe0af9fd67631ee +opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ + --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 +opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ + --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 +opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ + --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c +opentelemetry-instrumentation-wsgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2386014b026f5307c802417eeab74265785ae3dd6eee8c5581a830e3b2d3435b \ + --hash=sha256:f4e1001e8477eb546cac7c13cff0b0cf127812b1188a37bcaa3e43eb741451e2 +opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ + --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda +opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ + --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f +opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ + --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 +opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ + --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa +opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ + --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 overrides==7.7.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a \ --hash=sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49 @@ -827,92 +827,102 @@ psycopg2==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ pycparser==2.21 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 -pydantic-core==2.18.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b \ - --hash=sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a \ - --hash=sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90 \ - --hash=sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d \ - --hash=sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e \ - --hash=sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d \ - --hash=sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027 \ - --hash=sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804 \ - --hash=sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347 \ - --hash=sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400 \ - --hash=sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3 \ - --hash=sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399 \ - --hash=sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349 \ - --hash=sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd \ - --hash=sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c \ - --hash=sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e \ - --hash=sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413 \ - --hash=sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3 \ - --hash=sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e \ - --hash=sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3 \ - --hash=sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91 \ - --hash=sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce \ - --hash=sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c \ - --hash=sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb \ - --hash=sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664 \ - --hash=sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6 \ - --hash=sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd \ - --hash=sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3 \ - --hash=sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af \ - --hash=sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043 \ - --hash=sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350 \ - --hash=sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7 \ - --hash=sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0 \ - --hash=sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563 \ - --hash=sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761 \ - --hash=sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72 \ - --hash=sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3 \ - --hash=sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb \ - --hash=sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788 \ - --hash=sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b \ - --hash=sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c \ - --hash=sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038 \ - --hash=sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250 \ - --hash=sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec \ - --hash=sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c \ - --hash=sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74 \ - --hash=sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81 \ - --hash=sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439 \ - --hash=sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75 \ - --hash=sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0 \ - --hash=sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8 \ - --hash=sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150 \ - --hash=sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438 \ - --hash=sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae \ - --hash=sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857 \ - --hash=sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038 \ - --hash=sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374 \ - --hash=sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f \ - --hash=sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241 \ - --hash=sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592 \ - --hash=sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4 \ - --hash=sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d \ - --hash=sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b \ - --hash=sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b \ - --hash=sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182 \ - --hash=sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e \ - --hash=sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641 \ - --hash=sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70 \ - --hash=sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9 \ - --hash=sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a \ - --hash=sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543 \ - --hash=sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b \ - --hash=sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f \ - --hash=sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38 \ - --hash=sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845 \ - --hash=sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2 \ - --hash=sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0 \ - --hash=sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4 \ - --hash=sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242 -pydantic-settings==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ - --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 -pydantic==2.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5 \ - --hash=sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pydyf==0.8.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:901186a2e9f897108139426a6486f5225bdcc9b70be2ec965f25111e42f8ac5d \ --hash=sha256:b22b1ef016141b54941ad66ed4e036a7bdff39c0b360993b283875c3f854dd9a @@ -1306,9 +1316,9 @@ rpds-py==0.18.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca \ --hash=sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58 \ --hash=sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e -setuptools==69.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401 \ - --hash=sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 @@ -1324,9 +1334,9 @@ sqlparse==0.5.0 ; python_version >= "3.10" and python_version < "4.0" \ strenum==0.4.15 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff \ --hash=sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659 -structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ - --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a +structlog==24.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610 \ + --hash=sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4 tinycss2==1.2.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 @@ -1336,9 +1346,9 @@ tomli==2.0.1 ; python_version >= "3.10" and python_version < "4.0" \ tqdm==4.66.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644 \ --hash=sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb -typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ - --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a +typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 tzdata==2024.1 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32" \ --hash=sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd \ --hash=sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252 diff --git a/rocky/requirements.txt b/rocky/requirements.txt index 4e14a490dbd..d919ae2078a 100644 --- a/rocky/requirements.txt +++ b/rocky/requirements.txt @@ -420,51 +420,51 @@ jsonschema-specifications==2023.12.1 ; python_version >= "3.10" and python_versi jsonschema==4.21.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f \ --hash=sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5 -opentelemetry-api==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2 \ - --hash=sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e -opentelemetry-exporter-otlp-proto-common==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461 \ - --hash=sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641 -opentelemetry-exporter-otlp-proto-grpc==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa \ - --hash=sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b -opentelemetry-instrumentation-asgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b \ - --hash=sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6 -opentelemetry-instrumentation-dbapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618 \ - --hash=sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c -opentelemetry-instrumentation-django==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1e612c90eb4c69e1f0aa2e38dea89c47616596d3600392640fa7c0a201e299fa \ - --hash=sha256:d8b55747d6784167ab3a50dc128cc13b6966a2215ce55f4043392ac1c83b5bb2 -opentelemetry-instrumentation-fastapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e \ - --hash=sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314 -opentelemetry-instrumentation-httpx==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d \ - --hash=sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225 -opentelemetry-instrumentation-psycopg2==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7 \ - --hash=sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0 -opentelemetry-instrumentation-wsgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7a6f9c71b25f5c5e112827540008882f6a9088447cb65745e7f2083749516663 \ - --hash=sha256:f53a2a38e6582406e207d404e4c1b859b83bec11a68ad6c7366642d01c873ad0 -opentelemetry-instrumentation==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258 \ - --hash=sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e -opentelemetry-proto==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce \ - --hash=sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8 -opentelemetry-sdk==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5 \ - --hash=sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59 -opentelemetry-semantic-conventions==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118 \ - --hash=sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864 -opentelemetry-util-http==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd \ - --hash=sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33 +opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ + --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 +opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ + --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 +opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ + --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac +opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ + --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 +opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ + --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 +opentelemetry-instrumentation-django==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:cc11b2e24f9bdd20759570390ed8619d9c5acbf788b4a5401e36e280dfc20feb \ + --hash=sha256:ecc85941263122f99dbd96463a981b2d1eeea618ca287a58abe0af9fd67631ee +opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ + --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 +opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ + --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 +opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ + --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c +opentelemetry-instrumentation-wsgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2386014b026f5307c802417eeab74265785ae3dd6eee8c5581a830e3b2d3435b \ + --hash=sha256:f4e1001e8477eb546cac7c13cff0b0cf127812b1188a37bcaa3e43eb741451e2 +opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ + --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda +opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ + --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f +opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ + --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 +opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ + --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa +opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ + --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 phonenumbers==8.13.33 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:991f2619f0593b36b674c345af47944ec4bae526b353cf53d707e662087be63b \ --hash=sha256:f2d653268ece55a4f3752d9cda4be6f7465f298e6d028d522aedda13cf057201 @@ -569,92 +569,102 @@ psycopg2==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ pycparser==2.21 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 -pydantic-core==2.18.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b \ - --hash=sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a \ - --hash=sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90 \ - --hash=sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d \ - --hash=sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e \ - --hash=sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d \ - --hash=sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027 \ - --hash=sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804 \ - --hash=sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347 \ - --hash=sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400 \ - --hash=sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3 \ - --hash=sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399 \ - --hash=sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349 \ - --hash=sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd \ - --hash=sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c \ - --hash=sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e \ - --hash=sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413 \ - --hash=sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3 \ - --hash=sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e \ - --hash=sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3 \ - --hash=sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91 \ - --hash=sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce \ - --hash=sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c \ - --hash=sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb \ - --hash=sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664 \ - --hash=sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6 \ - --hash=sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd \ - --hash=sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3 \ - --hash=sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af \ - --hash=sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043 \ - --hash=sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350 \ - --hash=sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7 \ - --hash=sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0 \ - --hash=sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563 \ - --hash=sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761 \ - --hash=sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72 \ - --hash=sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3 \ - --hash=sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb \ - --hash=sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788 \ - --hash=sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b \ - --hash=sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c \ - --hash=sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038 \ - --hash=sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250 \ - --hash=sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec \ - --hash=sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c \ - --hash=sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74 \ - --hash=sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81 \ - --hash=sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439 \ - --hash=sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75 \ - --hash=sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0 \ - --hash=sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8 \ - --hash=sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150 \ - --hash=sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438 \ - --hash=sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae \ - --hash=sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857 \ - --hash=sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038 \ - --hash=sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374 \ - --hash=sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f \ - --hash=sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241 \ - --hash=sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592 \ - --hash=sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4 \ - --hash=sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d \ - --hash=sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b \ - --hash=sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b \ - --hash=sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182 \ - --hash=sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e \ - --hash=sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641 \ - --hash=sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70 \ - --hash=sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9 \ - --hash=sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a \ - --hash=sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543 \ - --hash=sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b \ - --hash=sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f \ - --hash=sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38 \ - --hash=sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845 \ - --hash=sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2 \ - --hash=sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0 \ - --hash=sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4 \ - --hash=sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242 -pydantic-settings==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed \ - --hash=sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091 -pydantic==2.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5 \ - --hash=sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc +pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ + --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ + --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ + --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ + --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ + --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ + --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ + --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ + --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ + --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ + --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ + --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ + --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ + --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ + --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ + --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ + --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ + --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ + --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ + --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ + --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ + --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ + --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ + --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ + --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ + --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ + --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ + --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ + --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ + --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ + --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ + --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ + --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ + --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ + --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ + --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ + --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ + --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ + --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ + --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ + --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ + --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ + --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ + --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ + --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ + --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ + --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ + --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ + --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ + --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ + --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ + --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ + --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ + --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ + --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ + --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ + --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ + --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ + --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ + --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ + --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ + --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ + --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ + --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ + --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ + --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ + --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ + --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ + --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ + --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ + --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ + --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ + --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ + --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ + --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ + --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ + --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ + --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ + --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ + --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ + --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ + --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ + --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ + --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ + --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ + --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ + --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ + --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ + --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 +pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ + --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pydyf==0.8.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:901186a2e9f897108139426a6486f5225bdcc9b70be2ec965f25111e42f8ac5d \ --hash=sha256:b22b1ef016141b54941ad66ed4e036a7bdff39c0b360993b283875c3f854dd9a @@ -827,9 +837,9 @@ rpds-py==0.18.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca \ --hash=sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58 \ --hash=sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e -setuptools==69.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401 \ - --hash=sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6 +setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 @@ -845,15 +855,15 @@ sqlparse==0.5.0 ; python_version >= "3.10" and python_version < "4.0" \ strenum==0.4.15 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff \ --hash=sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659 -structlog==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e3fe74924a6d8857d3f612739efb94c72a7417d7c7c008d12276bca3b5bf13b \ - --hash=sha256:983bd49f70725c5e1e3867096c0c09665918936b3db27341b41d294283d7a48a +structlog==24.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610 \ + --hash=sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4 tinycss2==1.2.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 -typing-extensions==4.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ - --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a +typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 tzdata==2024.1 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32" \ --hash=sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd \ --hash=sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252 From c5541260b02de44d406428bb63b89dc425525ed5 Mon Sep 17 00:00:00 2001 From: Jan Klopper Date: Mon, 22 Jul 2024 10:26:53 +0200 Subject: [PATCH 025/112] Update mixins.py, unroll loops, dont re-init bytes/katalogus client (#3229) Co-authored-by: Ammar --- rocky/rocky/views/mixins.py | 73 ++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/rocky/rocky/views/mixins.py b/rocky/rocky/views/mixins.py index f69b93beb60..3b7871380dd 100644 --- a/rocky/rocky/views/mixins.py +++ b/rocky/rocky/views/mixins.py @@ -77,7 +77,10 @@ def observed_at(self) -> datetime: return ret except ValueError: - messages.error(self.request, _("Can not parse date, falling back to show current date.")) + messages.error( + self.request, + _("Can not parse date, falling back to show current date."), + ) return datetime.now(timezone.utc) @@ -97,33 +100,61 @@ def get_origins( reference: Reference, organization: Organization, ) -> tuple[list[OriginData], list[OriginData], list[OriginData]]: + declarations: list[OriginData] = [] + observations: list[OriginData] = [] + inferences: list[OriginData] = [] + results = declarations, observations, inferences + try: origins = self.octopoes_api_connector.list_origins(self.observed_at, result=reference) - origin_data = [OriginData(origin=origin) for origin in origins] + except Exception as e: + logger.error( + "Could not load origins for OOI: %s from octopoes, error: %s", + reference, + e, + ) + return results - for origin in origin_data: - if origin.origin.origin_type != OriginType.OBSERVATION or not origin.origin.task_id: - continue + try: + bytes_client = get_bytes_client(organization.code) + bytes_client.login() + except HTTPError as e: + logger.error(e) + return results - try: - client = get_bytes_client(organization.code) - client.login() + katalogus = get_katalogus(organization.code) - normalizer_data = client.get_normalizer_meta(origin.origin.task_id) - boefje_id = normalizer_data["raw_data"]["boefje_meta"]["boefje"]["id"] - origin.normalizer = normalizer_data - origin.boefje = get_katalogus(organization.code).get_plugin(boefje_id) + for origin in origins: + origin = OriginData(origin=origin) + if origin.origin.origin_type != OriginType.OBSERVATION or not origin.origin.task_id: + if origin.origin.origin_type == OriginType.DECLARATION: + declarations.append(origin) + elif origin.origin.origin_type == OriginType.INFERENCE: + inferences.append(origin) + continue + + try: + normalizer_data = bytes_client.get_normalizer_meta(origin.origin.task_id) + except HTTPError as e: + logger.error( + "Could not load Normalizer meta for task_id: %s, error: %s", + origin.origin.task_id, + e, + ) + else: + boefje_id = normalizer_data["raw_data"]["boefje_meta"]["boefje"]["id"] + origin.normalizer = normalizer_data + try: + origin.boefje = katalogus.get_plugin(boefje_id) except HTTPError as e: - logger.error(e) + logger.error( + "Could not load boefje: %s from katalogus, error: %s", + boefje_id, + e, + ) + observations.append(origin) - return ( - [origin for origin in origin_data if origin.origin.origin_type == OriginType.DECLARATION], - [origin for origin in origin_data if origin.origin.origin_type == OriginType.OBSERVATION], - [origin for origin in origin_data if origin.origin.origin_type == OriginType.INFERENCE], - ) - except Exception as e: - logger.error(e) - return [], [], [] + return results def handle_connector_exception(self, exception: Exception): if isinstance(exception, ObjectNotFoundException): From 2f48fbf531f8bdcf328d5ffa860b3cc5f1e42461 Mon Sep 17 00:00:00 2001 From: Rieven Date: Mon, 22 Jul 2024 16:19:06 +0200 Subject: [PATCH 026/112] Fix: add related objects crash (#3268) --- rocky/rocky/templates/partials/ooi_detail_related_object.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rocky/rocky/templates/partials/ooi_detail_related_object.html b/rocky/rocky/templates/partials/ooi_detail_related_object.html index 0fdebf2c89d..30ebfcb5467 100644 --- a/rocky/rocky/templates/partials/ooi_detail_related_object.html +++ b/rocky/rocky/templates/partials/ooi_detail_related_object.html @@ -12,8 +12,8 @@

{% translate "Related objects" %}

{% if not ooi_past_due %} {% if not ooi|is_finding and not ooi|is_finding_type %} {% endif %} {% endif %} From f3a3f92c6d9f202bea4e2e3447859484ec0a2e3c Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:22:05 +0200 Subject: [PATCH 027/112] RFC3161HashRepository accepts rfc3161_provider only as a string and Pydantic URLs are not strings anymore (#3281) --- bytes/bytes/timestamping/provider.py | 2 +- bytes/tests/conftest.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bytes/bytes/timestamping/provider.py b/bytes/bytes/timestamping/provider.py index 55af24cfa36..b9b9c6343b1 100644 --- a/bytes/bytes/timestamping/provider.py +++ b/bytes/bytes/timestamping/provider.py @@ -16,6 +16,6 @@ def create_hash_repository(settings: Settings) -> HashRepository: if settings.ext_hash_repository == HashingRepositoryReference.RFC3161: assert settings.rfc3161_cert_file and settings.rfc3161_provider, "RFC3161 service needs a url and a certificate" - return RFC3161HashRepository(settings.rfc3161_cert_file.read_bytes(), settings.rfc3161_provider) + return RFC3161HashRepository(settings.rfc3161_cert_file.read_bytes(), str(settings.rfc3161_provider)) return InMemoryHashRepository() diff --git a/bytes/tests/conftest.py b/bytes/tests/conftest.py index 69474441feb..228c7a88d98 100644 --- a/bytes/tests/conftest.py +++ b/bytes/tests/conftest.py @@ -60,7 +60,7 @@ def pastebin_hash_repository(settings: Settings) -> HashRepository: @pytest.fixture def mock_hash_repository(settings: Settings) -> HashRepository: if settings.rfc3161_cert_file and settings.rfc3161_provider: - return RFC3161HashRepository(settings.rfc3161_cert_file.read_bytes(), settings.rfc3161_provider) + return RFC3161HashRepository(settings.rfc3161_cert_file.read_bytes(), str(settings.rfc3161_provider)) return InMemoryHashRepository(signing_provider_url="https://test") From 68e5177b8694619568e93e7829da4dfab27f5af6 Mon Sep 17 00:00:00 2001 From: originalsouth Date: Tue, 23 Jul 2024 13:46:29 +0200 Subject: [PATCH 028/112] Add XTDB list and rename method in origin tool (#3234) Co-authored-by: Jeroen Dekkers Co-authored-by: ammar92 Co-authored-by: Jan Klopper --- octopoes/tools/rename-origin-method.py | 107 +++++++++++++++++++++++++ octopoes/tools/xtdb-cli.py | 2 +- octopoes/tools/xtdb_client.py | 25 +++++- 3 files changed, 131 insertions(+), 3 deletions(-) create mode 100755 octopoes/tools/rename-origin-method.py diff --git a/octopoes/tools/rename-origin-method.py b/octopoes/tools/rename-origin-method.py new file mode 100755 index 00000000000..2970b8f07c6 --- /dev/null +++ b/octopoes/tools/rename-origin-method.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +import json +import logging +from typing import Any + +import click +from xtdb_client import XTDBClient + +logger = logging.getLogger(__name__) + + +@click.group( + context_settings={ + "help_option_names": ["-h", "--help"], + "max_content_width": 120, + "show_default": True, + } +) +@click.option("-c", "--code", default="0", help="The organisation code") +@click.option( + "-u", + "--url", + default="http://localhost:3000", + envvar="XTDB_URI", + help="XTDB server base url", +) +@click.option( + "-t", + "--timeout", + type=int, + default=5000, + help="XTDB request timeout (in ms)", +) +@click.option("-v", "--verbosity", count=True, help="Increase the verbosity level") +@click.pass_context +def cli(ctx: click.Context, url: str, code: str, timeout: int, verbosity: int): + verbosities = [logging.WARN, logging.INFO, logging.DEBUG] + try: + if verbosity: + logging.basicConfig(level=verbosities[verbosity - 1]) + except IndexError: + raise click.UsageError("Invalid verbosity level (use -v, -vv, or -vvv)") + + client = XTDBClient(url, code, timeout) + logger.info("Instantiated XTDB client with endpoint %s for node %s", url, code) + + ctx.ensure_object(dict) + ctx.obj["client"] = client + + +def method_query(method: str): + method = f'"{method}"' if method else "" + return f"""{{ +:query {{ + :find [(pull ?var [*])] :where [ + [?var :type "Origin"] + [?var :origin_type "observation"] + [?var :method {method}] + ] + }} +}} +""" + + +@cli.command("list", help="List observation origins based on method") +@click.argument("method", required=False) +@click.pass_context +def list_(ctx: click.Context, method: str): + origins = ctx.obj["client"].query(method_query(method)) + if not origins: + raise click.UsageError("No targets found") + if "error" in origins: + raise click.UsageError(origins["error"]) + click.echo(json.dumps(origins)) + + +def search_replace_method(data_list: list[dict[str, Any]], search_string: str, replace_string: str) -> None: + for data_dict in data_list: + for key in ["method", "xt/id"]: + if key in data_dict and search_string in data_dict[key]: + data_dict[key] = data_dict[key].replace(search_string, replace_string) + + +@cli.command(help="Rename an observation origin method") +@click.option("--armed", is_flag=True, help="Arm the tool to overwrite the method name (confirmation)") +@click.argument("method") +@click.argument("renamed") +@click.pass_context +def rename(ctx: click.Context, armed: bool, method: str, renamed: str): + origins = ctx.obj["client"].query(method_query(method)) + if not origins: + raise click.UsageError("No targets found") + if "error" in origins: + raise click.UsageError(origins["error"]) + if armed: + delete_txs = [["delete", o[0]["xt/id"]] for o in origins] + search_replace_method([o[0] for o in origins], method, renamed) + put_txs = [["put", o[0]] for o in origins] + click.echo(json.dumps(ctx.obj["client"].submit_tx(delete_txs + put_txs))) + else: + search_replace_method([o[0] for o in origins], method, renamed) + click.echo(json.dumps(origins)) + + +if __name__ == "__main__": + cli() diff --git a/octopoes/tools/xtdb-cli.py b/octopoes/tools/xtdb-cli.py index a72940139f0..74aad128407 100755 --- a/octopoes/tools/xtdb-cli.py +++ b/octopoes/tools/xtdb-cli.py @@ -217,7 +217,7 @@ def txs(ctx: click.Context): @cli.command( - help="""Takes a vector of transactions (any combination of put, delete, match, evict and fn) + help="""Takes a space separated list of transactions (any combination of put, delete, match, evict and fn) and executes them in order. This is the only 'write' endpoint.""" ) @click.argument("txs", nargs=-1) diff --git a/octopoes/tools/xtdb_client.py b/octopoes/tools/xtdb_client.py index f353a1b76bf..70c0530912f 100644 --- a/octopoes/tools/xtdb_client.py +++ b/octopoes/tools/xtdb_client.py @@ -3,6 +3,26 @@ import httpx from pydantic import JsonValue +PutTransaction = ( + tuple[str, dict] + | tuple[str, dict, str | datetime.datetime] + | tuple[str, dict, str | datetime.datetime, str | datetime.datetime] +) + +DeleteTransaction = ( + tuple[str] | tuple[str, str | datetime.datetime] | tuple[str, str | datetime.datetime, str | datetime.datetime] +) + +EvictTransaction = DeleteTransaction + +SimpleTransactions = list[PutTransaction | DeleteTransaction | EvictTransaction] + +MatchTransaction = ( + tuple[str, str, dict, SimpleTransactions] | tuple[str, str, dict, str | datetime.datetime, SimpleTransactions] +) + +TransactionType = PutTransaction | DeleteTransaction | EvictTransaction | MatchTransaction + class XTDBClient: def __init__(self, base_url: str, node: str, timeout: int | None = None): @@ -118,8 +138,9 @@ def tx_log( return res.json() - def submit_tx(self, transactions: list[str]) -> JsonValue: - res = self._client.post("/submit-tx", json={"tx-ops": transactions}) + def submit_tx(self, transactions: list[TransactionType]) -> JsonValue: + data = {"tx-ops": transactions} + res = self._client.post("/submit-tx", json=data) return res.json() From 930ed51c2b214056724d590602ff1f8b47486f39 Mon Sep 17 00:00:00 2001 From: Jeroen Dekkers Date: Wed, 24 Jul 2024 11:04:49 +0200 Subject: [PATCH 029/112] Fix rocky logging (#3288) Co-authored-by: Ammar --- rocky/katalogus/client.py | 4 ++-- rocky/katalogus/views/mixins.py | 5 ++-- rocky/katalogus/views/plugin_detail.py | 3 --- .../katalogus/views/plugin_enable_disable.py | 4 ---- .../aggregate_organisation_report/report.py | 4 ++-- rocky/reports/report_types/definitions.py | 2 -- .../reports/report_types/dns_report/report.py | 4 ++-- .../report_types/findings_report/report.py | 3 --- .../report_types/ipv6_report/report.py | 3 --- .../report_types/mail_report/report.py | 3 --- .../multi_organization_report/report.py | 3 --- .../report_types/name_server_report/report.py | 3 --- .../report_types/open_ports_report/report.py | 3 --- .../report_types/rpki_report/report.py | 3 --- .../safe_connections_report/report.py | 3 --- .../report_types/systems_report/report.py | 3 --- .../reports/report_types/tls_report/report.py | 3 --- .../vulnerability_report/report.py | 3 --- .../report_types/web_system_report/report.py | 3 --- rocky/reports/views/base.py | 4 ++-- rocky/rocky/scheduler.py | 3 --- rocky/rocky/settings.py | 24 +++++++++++-------- rocky/rocky/views/scans.py | 4 ---- .../tools/management/commands/almost_flush.py | 5 ++-- .../management/commands/export_migrations.py | 4 ++-- .../management/commands/generate_report.py | 2 -- 26 files changed, 28 insertions(+), 80 deletions(-) diff --git a/rocky/katalogus/client.py b/rocky/katalogus/client.py index b5e06db1777..104bf2fda51 100644 --- a/rocky/katalogus/client.py +++ b/rocky/katalogus/client.py @@ -1,7 +1,7 @@ from io import BytesIO -from logging import getLogger import httpx +import structlog from django.conf import settings from django.utils.translation import gettext_lazy as _ from jsonschema.exceptions import SchemaError @@ -14,7 +14,7 @@ from octopoes.models.types import type_by_name from rocky.health import ServiceHealth -logger = getLogger(__name__) +logger = structlog.get_logger(__name__) class Plugin(BaseModel): diff --git a/rocky/katalogus/views/mixins.py b/rocky/katalogus/views/mixins.py index 9e770837249..11d935f2a24 100644 --- a/rocky/katalogus/views/mixins.py +++ b/rocky/katalogus/views/mixins.py @@ -1,5 +1,4 @@ -from logging import getLogger - +import structlog from account.mixins import OrganizationView from django.contrib import messages from django.http import Http404 @@ -11,7 +10,7 @@ from katalogus.client import KATalogusClientV1, Plugin, get_katalogus -logger = getLogger(__name__) +logger = structlog.get_logger(__name__) class SinglePluginView(OrganizationView): diff --git a/rocky/katalogus/views/plugin_detail.py b/rocky/katalogus/views/plugin_detail.py index d0ecbe526b2..119f2047d3e 100644 --- a/rocky/katalogus/views/plugin_detail.py +++ b/rocky/katalogus/views/plugin_detail.py @@ -1,5 +1,4 @@ from datetime import datetime, timezone -from logging import getLogger from typing import Any from account.mixins import OrganizationView @@ -14,8 +13,6 @@ from katalogus.views.plugin_settings_list import PluginSettingsListView from rocky.views.tasks import TaskListView -logger = getLogger(__name__) - class PluginCoverImgView(OrganizationView): """Get the cover image of a plugin.""" diff --git a/rocky/katalogus/views/plugin_enable_disable.py b/rocky/katalogus/views/plugin_enable_disable.py index 8717c6d540b..36db033e530 100644 --- a/rocky/katalogus/views/plugin_enable_disable.py +++ b/rocky/katalogus/views/plugin_enable_disable.py @@ -1,5 +1,3 @@ -from logging import getLogger - from django.contrib import messages from django.http import HttpResponseRedirect from django.shortcuts import redirect @@ -9,8 +7,6 @@ from katalogus.views.mixins import SinglePluginView -logger = getLogger(__name__) - class PluginEnableDisableView(SinglePluginView): def check_required_settings(self, settings: dict): diff --git a/rocky/reports/report_types/aggregate_organisation_report/report.py b/rocky/reports/report_types/aggregate_organisation_report/report.py index d929718491d..27a2e9d6296 100644 --- a/rocky/reports/report_types/aggregate_organisation_report/report.py +++ b/rocky/reports/report_types/aggregate_organisation_report/report.py @@ -1,7 +1,7 @@ from datetime import datetime -from logging import getLogger from typing import Any +import structlog from django.utils.translation import gettext_lazy as _ from octopoes.connector.octopoes import OctopoesAPIConnector @@ -20,7 +20,7 @@ from reports.report_types.web_system_report.report import WebSystemReport from rocky.views.health import flatten_health, get_rocky_health -logger = getLogger(__name__) +logger = structlog.get_logger(__name__) class AggregateOrganisationReport(AggregateReport): diff --git a/rocky/reports/report_types/definitions.py b/rocky/reports/report_types/definitions.py index 970e6cda569..e36661e3821 100644 --- a/rocky/reports/report_types/definitions.py +++ b/rocky/reports/report_types/definitions.py @@ -1,6 +1,5 @@ from collections.abc import Callable, Iterable from datetime import datetime -from logging import getLogger from pathlib import Path from typing import Any, TypedDict, TypeVar @@ -11,7 +10,6 @@ from octopoes.models.types import OOIType REPORTS_DIR = Path(__file__).parent -logger = getLogger(__name__) class ReportPlugins(TypedDict): diff --git a/rocky/reports/report_types/dns_report/report.py b/rocky/reports/report_types/dns_report/report.py index 0850b6756cf..2ae8f888f49 100644 --- a/rocky/reports/report_types/dns_report/report.py +++ b/rocky/reports/report_types/dns_report/report.py @@ -1,7 +1,7 @@ from datetime import datetime -from logging import getLogger from typing import Any +import structlog from django.utils.translation import gettext_lazy as _ from octopoes.models import Reference @@ -11,7 +11,7 @@ from octopoes.models.ooi.findings import Finding from reports.report_types.definitions import Report -logger = getLogger(__name__) +logger = structlog.get_logger(__name__) class DNSReport(Report): diff --git a/rocky/reports/report_types/findings_report/report.py b/rocky/reports/report_types/findings_report/report.py index 47d75a41b5f..9b05e6231b9 100644 --- a/rocky/reports/report_types/findings_report/report.py +++ b/rocky/reports/report_types/findings_report/report.py @@ -1,5 +1,4 @@ from datetime import datetime -from logging import getLogger from typing import Any from django.utils.translation import gettext_lazy as _ @@ -9,8 +8,6 @@ from octopoes.models.types import ALL_TYPES from reports.report_types.definitions import Report, ReportPlugins -logger = getLogger(__name__) - TREE_DEPTH = 9 SEVERITY_OPTIONS = [severity.value for severity in RiskLevelSeverity] diff --git a/rocky/reports/report_types/ipv6_report/report.py b/rocky/reports/report_types/ipv6_report/report.py index 24ebb465cd9..ae864dca348 100644 --- a/rocky/reports/report_types/ipv6_report/report.py +++ b/rocky/reports/report_types/ipv6_report/report.py @@ -1,7 +1,6 @@ from collections.abc import Iterable from dataclasses import dataclass from datetime import datetime -from logging import getLogger from typing import Any from django.utils.translation import gettext_lazy as _ @@ -10,8 +9,6 @@ from octopoes.models.ooi.network import IPAddressV4, IPAddressV6 from reports.report_types.definitions import Report -logger = getLogger(__name__) - @dataclass class System: diff --git a/rocky/reports/report_types/mail_report/report.py b/rocky/reports/report_types/mail_report/report.py index 9ae68a2737a..69f166a7ec9 100644 --- a/rocky/reports/report_types/mail_report/report.py +++ b/rocky/reports/report_types/mail_report/report.py @@ -1,6 +1,5 @@ from collections.abc import Iterable from datetime import datetime -from logging import getLogger from typing import Any from django.utils.translation import gettext_lazy as _ @@ -9,8 +8,6 @@ from octopoes.models.ooi.network import IPAddressV4, IPAddressV6 from reports.report_types.definitions import Report -logger = getLogger(__name__) - MAIL_FINDING_TYPES = ["KAT-NO-SPF", "KAT-NO-DMARC", "KAT-NO-DKIM"] diff --git a/rocky/reports/report_types/multi_organization_report/report.py b/rocky/reports/report_types/multi_organization_report/report.py index 3f236eba780..b32146f3f55 100644 --- a/rocky/reports/report_types/multi_organization_report/report.py +++ b/rocky/reports/report_types/multi_organization_report/report.py @@ -1,5 +1,4 @@ from datetime import datetime -from logging import getLogger from typing import Any, TypedDict from django.utils.translation import gettext_lazy as _ @@ -9,8 +8,6 @@ from octopoes.models.ooi.reports import ReportData from reports.report_types.definitions import MultiReport, ReportPlugins -logger = getLogger(__name__) - class OpenPortsDict(TypedDict): total: int diff --git a/rocky/reports/report_types/name_server_report/report.py b/rocky/reports/report_types/name_server_report/report.py index b5662c6ccbb..9398e728719 100644 --- a/rocky/reports/report_types/name_server_report/report.py +++ b/rocky/reports/report_types/name_server_report/report.py @@ -1,7 +1,6 @@ from collections.abc import Iterable from dataclasses import dataclass, field from datetime import datetime -from logging import getLogger from typing import Any, cast from django.utils.translation import gettext_lazy as _ @@ -11,8 +10,6 @@ from octopoes.models.ooi.network import IPAddressV4, IPAddressV6 from reports.report_types.definitions import Report -logger = getLogger(__name__) - @dataclass class NameServerCheck: diff --git a/rocky/reports/report_types/open_ports_report/report.py b/rocky/reports/report_types/open_ports_report/report.py index 4e82f1665ae..e868237dad5 100644 --- a/rocky/reports/report_types/open_ports_report/report.py +++ b/rocky/reports/report_types/open_ports_report/report.py @@ -1,6 +1,5 @@ from collections.abc import Iterable from datetime import datetime -from logging import getLogger from typing import Any from django.utils.translation import gettext_lazy as _ @@ -9,8 +8,6 @@ from octopoes.models.ooi.network import IPAddressV4, IPAddressV6 from reports.report_types.definitions import Report -logger = getLogger(__name__) - class OpenPortsReport(Report): id = "open-ports-report" diff --git a/rocky/reports/report_types/rpki_report/report.py b/rocky/reports/report_types/rpki_report/report.py index 9c40f6a5b3a..ed2d05576e0 100644 --- a/rocky/reports/report_types/rpki_report/report.py +++ b/rocky/reports/report_types/rpki_report/report.py @@ -1,6 +1,5 @@ from collections.abc import Iterable from datetime import datetime -from logging import getLogger from typing import Any, TypedDict from django.utils.translation import gettext_lazy as _ @@ -10,8 +9,6 @@ from octopoes.models.ooi.network import IPAddressV4, IPAddressV6 from reports.report_types.definitions import Report -logger = getLogger(__name__) - class RPKIData(TypedDict): exists: bool diff --git a/rocky/reports/report_types/safe_connections_report/report.py b/rocky/reports/report_types/safe_connections_report/report.py index 46d6f01da9b..13554d39562 100644 --- a/rocky/reports/report_types/safe_connections_report/report.py +++ b/rocky/reports/report_types/safe_connections_report/report.py @@ -1,6 +1,5 @@ from collections.abc import Iterable from datetime import datetime -from logging import getLogger from typing import Any from django.utils.translation import gettext_lazy as _ @@ -15,8 +14,6 @@ "KAT-CRITICAL-BAD-CIPHER", ] -logger = getLogger(__name__) - class SafeConnectionsReport(Report): id = "safe-connections-report" diff --git a/rocky/reports/report_types/systems_report/report.py b/rocky/reports/report_types/systems_report/report.py index 1bd0dadfb53..db71c686271 100644 --- a/rocky/reports/report_types/systems_report/report.py +++ b/rocky/reports/report_types/systems_report/report.py @@ -1,7 +1,6 @@ from collections.abc import Iterable from dataclasses import dataclass from datetime import datetime -from logging import getLogger from typing import Any from django.utils.translation import gettext_lazy as _ @@ -11,8 +10,6 @@ from octopoes.models.ooi.network import IPAddressV4, IPAddressV6 from reports.report_types.definitions import Report -logger = getLogger(__name__) - class SystemType(StrEnum): WEB = "Web" diff --git a/rocky/reports/report_types/tls_report/report.py b/rocky/reports/report_types/tls_report/report.py index 8d067cc5e71..e56cd5cf8ba 100644 --- a/rocky/reports/report_types/tls_report/report.py +++ b/rocky/reports/report_types/tls_report/report.py @@ -1,5 +1,4 @@ from datetime import datetime -from logging import getLogger from typing import Any from django.utils.translation import gettext_lazy as _ @@ -9,8 +8,6 @@ from octopoes.models.ooi.service import IPService, TLSCipher from reports.report_types.definitions import Report -logger = getLogger(__name__) - CIPHER_FINDINGS = [ "KAT-RECOMMENDATION-BAD-CIPHER", "KAT-MEDIUM-BAD-CIPHER", diff --git a/rocky/reports/report_types/vulnerability_report/report.py b/rocky/reports/report_types/vulnerability_report/report.py index 1ad08c45580..021e88978d5 100644 --- a/rocky/reports/report_types/vulnerability_report/report.py +++ b/rocky/reports/report_types/vulnerability_report/report.py @@ -1,7 +1,6 @@ from collections import Counter from collections.abc import Iterable from datetime import datetime -from logging import getLogger from typing import Any, TypedDict from django.utils.translation import gettext_lazy as _ @@ -11,8 +10,6 @@ from octopoes.models.ooi.network import IPAddressV4, IPAddressV6 from reports.report_types.definitions import Report -logger = getLogger(__name__) - class FindingsData(TypedDict): finding_types: list[FindingType] diff --git a/rocky/reports/report_types/web_system_report/report.py b/rocky/reports/report_types/web_system_report/report.py index 804a4806c6e..75aece24111 100644 --- a/rocky/reports/report_types/web_system_report/report.py +++ b/rocky/reports/report_types/web_system_report/report.py @@ -1,7 +1,6 @@ from collections.abc import Iterable from dataclasses import dataclass, field from datetime import datetime -from logging import getLogger from typing import Any, cast from django.utils.translation import gettext_lazy as _ @@ -11,8 +10,6 @@ from octopoes.models.ooi.network import IPAddressV4, IPAddressV6 from reports.report_types.definitions import Report -logger = getLogger(__name__) - @dataclass class WebCheck: diff --git a/rocky/reports/views/base.py b/rocky/reports/views/base.py index 37c5d354395..544cc1af133 100644 --- a/rocky/reports/views/base.py +++ b/rocky/reports/views/base.py @@ -2,11 +2,11 @@ from collections import defaultdict from collections.abc import Iterable, Sequence from datetime import datetime, timezone -from logging import getLogger from operator import attrgetter from typing import Any, Literal, cast from uuid import uuid4 +import structlog from account.mixins import OrganizationView from django.conf import settings from django.contrib import messages @@ -45,7 +45,7 @@ def get_selection(request: HttpRequest, pre_selection: dict[str, str | Sequence[ return "?" + urlencode(request.GET, True) -logger = getLogger(__name__) +logger = structlog.get_logger(__name__) class ReportBreadcrumbs(OrganizationView, BreadcrumbsMixin): diff --git a/rocky/rocky/scheduler.py b/rocky/rocky/scheduler.py index 5b80b2c7c9b..e4f2df0e743 100644 --- a/rocky/rocky/scheduler.py +++ b/rocky/rocky/scheduler.py @@ -5,7 +5,6 @@ import uuid from enum import Enum from functools import cached_property -from logging import getLogger from typing import Any import httpx @@ -16,8 +15,6 @@ from rocky.health import ServiceHealth -logger = getLogger(__name__) - class Boefje(BaseModel): """Boefje representation.""" diff --git a/rocky/rocky/settings.py b/rocky/rocky/settings.py index 871dad53eeb..b23194ea74e 100644 --- a/rocky/rocky/settings.py +++ b/rocky/rocky/settings.py @@ -53,19 +53,26 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = env.bool("DEBUG", False) +# Logging format ("text" or "json") +LOGGING_FORMAT = env("LOGGING_FORMAT", default="text") + LOGGING = { "version": 1, "disable_existing_loggers": False, "formatters": { - "structlog": { + "json_formatter": { "()": structlog.stdlib.ProcessorFormatter, "processor": structlog.processors.JSONRenderer(), }, + "plain_console": { + "()": structlog.stdlib.ProcessorFormatter, + "processor": structlog.dev.ConsoleRenderer(colors=True, pad_level=False), + }, }, "handlers": { "console": { - "formatter": "structlog", "class": "logging.StreamHandler", + "formatter": "json_formatter" if LOGGING_FORMAT == "json" else "plain_console", }, }, "loggers": { @@ -73,10 +80,6 @@ "handlers": ["console"], "level": "INFO", }, - "django_structlog": { - "handlers": ["console"], - "level": "DEBUG", - }, }, } @@ -158,6 +161,7 @@ "account", "tools", "fmea", + "rocky", "crisis_room", "onboarding", "katalogus", @@ -213,7 +217,10 @@ "tools.context_processors.organizations_including_blocked", "tools.context_processors.rocky_version", ], - "builtins": ["django_components.templatetags.component_tags", "tools.templatetags.ooi_extra"], + "builtins": [ + "django_components.templatetags.component_tags", + "tools.templatetags.ooi_extra", + ], "loaders": [ ( "django.template.loaders.cached.Loader", @@ -501,9 +508,6 @@ def immutable_file_test(path, url): FORMS_URLFIELD_ASSUME_HTTPS = True -# Logging format ("text" or "json") -LOGGING_FORMAT = env("LOGGING_FORMAT", default="text") - structlog.configure( processors=[ structlog.contextvars.merge_contextvars, diff --git a/rocky/rocky/views/scans.py b/rocky/rocky/views/scans.py index 103fcf360af..c6919ee4770 100644 --- a/rocky/rocky/views/scans.py +++ b/rocky/rocky/views/scans.py @@ -1,12 +1,8 @@ -from logging import getLogger - from account.mixins import OrganizationView from django.views.generic import TemplateView from katalogus.client import get_katalogus from tools.view_helpers import Breadcrumb, ObjectsBreadcrumbsMixin -logger = getLogger(__name__) - class ScanListView(ObjectsBreadcrumbsMixin, OrganizationView, TemplateView): template_name = "scan.html" diff --git a/rocky/tools/management/commands/almost_flush.py b/rocky/tools/management/commands/almost_flush.py index b99bb705090..c492c458bf8 100644 --- a/rocky/tools/management/commands/almost_flush.py +++ b/rocky/tools/management/commands/almost_flush.py @@ -1,5 +1,4 @@ -from logging import getLogger - +import structlog from django.contrib.auth import get_user_model from django.contrib.auth.models import Group from django.core.management import BaseCommand, call_command @@ -8,7 +7,7 @@ from tools.models import Indemnification, OrganizationMember User = get_user_model() -logger = getLogger(__name__) +logger = structlog.get_logger(__name__) class Command(BaseCommand): diff --git a/rocky/tools/management/commands/export_migrations.py b/rocky/tools/management/commands/export_migrations.py index 0fc4711db67..656d7344e57 100644 --- a/rocky/tools/management/commands/export_migrations.py +++ b/rocky/tools/management/commands/export_migrations.py @@ -1,12 +1,12 @@ -from logging import getLogger from pathlib import Path +import structlog from django.core.management import BaseCommand, CommandParser from django.db import DEFAULT_DB_ALIAS, connections from django.db.migrations.loader import MigrationLoader from django.db.migrations.recorder import MigrationRecorder -logger = getLogger(__name__) +logger = structlog.get_logger(__name__) class Command(BaseCommand): diff --git a/rocky/tools/management/commands/generate_report.py b/rocky/tools/management/commands/generate_report.py index 8782885979b..154d1477a3a 100644 --- a/rocky/tools/management/commands/generate_report.py +++ b/rocky/tools/management/commands/generate_report.py @@ -1,6 +1,5 @@ import sys from datetime import datetime, timezone -from logging import getLogger from pathlib import Path from typing import Any @@ -16,7 +15,6 @@ from tools.models import Organization User = get_user_model() -logger = getLogger(__name__) class Command(BaseCommand): From 5b528dce1b2fc4b81c5954f46f938c7417ca7855 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 11:10:31 +0200 Subject: [PATCH 030/112] Bump sphinx from 7.4.6 to 7.4.7 (#3265) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jan Klopper Co-authored-by: ammar92 --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- requirements.txt | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/poetry.lock b/poetry.lock index 75445e355ae..761ba6de69e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -713,13 +713,13 @@ files = [ [[package]] name = "sphinx" -version = "7.4.6" +version = "7.4.7" description = "Python documentation generator" optional = false python-versions = ">=3.9" files = [ - {file = "sphinx-7.4.6-py3-none-any.whl", hash = "sha256:915760d6188288a1e30c2cd0d9fa31b1b009bc6e6019cc0c32d16c77d20e86d9"}, - {file = "sphinx-7.4.6.tar.gz", hash = "sha256:116918d455c493fff3178edea12b4fe1c1e4894680fd81e7b7431ea21d47ca52"}, + {file = "sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239"}, + {file = "sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe"}, ] [package.dependencies] @@ -950,4 +950,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "b80a1c3975698cbaf82c4673131f1659a3b66e49a48177b7469d6e85d520ab96" +content-hash = "71b725c644473a0939fa7fe7025afa25788c8926bf028a58207622d2af7677de" diff --git a/pyproject.toml b/pyproject.toml index 8f4ab8bc977..ab4e6fd3a40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -100,7 +100,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.dependencies] python = "^3.10" -sphinx = "^7.3.7" +sphinx = "^7.4.7" sphinx_rtd_theme = "2.0.0" sphinxcontrib-mermaid = "^0.9.2" myst-parser = "^3.0.1" diff --git a/requirements.txt b/requirements.txt index 32b83b398bc..3c89cdbaeae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -368,9 +368,9 @@ snowballstemmer==2.2.0 ; python_version >= "3.10" and python_version < "4.0" \ sphinx-rtd-theme==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b \ --hash=sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586 -sphinx==7.4.6 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:116918d455c493fff3178edea12b4fe1c1e4894680fd81e7b7431ea21d47ca52 \ - --hash=sha256:915760d6188288a1e30c2cd0d9fa31b1b009bc6e6019cc0c32d16c77d20e86d9 +sphinx==7.4.7 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe \ + --hash=sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239 sphinxcontrib-applehelp==1.0.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619 \ --hash=sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4 From 633b7821d2fc4b0e01d05d4102bd95d14e398243 Mon Sep 17 00:00:00 2001 From: HeleenSG Date: Wed, 24 Jul 2024 11:16:56 +0200 Subject: [PATCH 031/112] feat: Updated color scheme (#3241) Co-authored-by: Jan Klopper --- rocky/assets/css/components/dropdown.scss | 2 +- rocky/assets/css/components/hover-block.scss | 6 +- rocky/assets/css/components/plugins.scss | 2 +- rocky/assets/css/components/qr-code.scss | 2 +- rocky/assets/css/components/report.scss | 6 +- .../css/components/risk-level-indicator.scss | 14 +- .../css/components/scan-level-indicator.scss | 8 +- rocky/assets/css/components/state-tags.scss | 33 ++--- .../css/components/stepper-variables.scss | 4 +- .../css/components/table-state-icons.scss | 2 +- rocky/assets/css/components/user-icon.scss | 4 +- rocky/assets/css/themes/soft/colors.scss | 95 -------------- .../assets/css/themes/soft/colors/colors.scss | 120 ++++++++++++++++++ .../css/themes/soft/colors/tag-colors.scss | 8 ++ .../css/themes/soft/colors/tags-6-3.scss | 27 ++++ .../css/themes/soft/manon/accordion.scss | 8 +- .../css/themes/soft/manon/body-text-set.scss | 2 +- .../css/themes/soft/manon/button-ghost.scss | 16 +-- .../assets/css/themes/soft/manon/button.scss | 12 +- .../themes/soft/manon/collapsing-element.scss | 2 +- .../css/themes/soft/manon/expando-rows.scss | 4 +- .../assets/css/themes/soft/manon/footer.scss | 4 +- rocky/assets/css/themes/soft/manon/form.scss | 6 +- .../manon/header-navigation-collapsible.scss | 4 +- .../manon/header-navigation-link-active.scss | 4 +- .../soft/manon/language-selector-list.scss | 8 +- .../css/themes/soft/manon/login-meta.scss | 4 +- rocky/assets/css/themes/soft/manon/logo.scss | 2 +- .../soft/manon/navigation-collapsible.scss | 14 +- .../css/themes/soft/manon/navigation.scss | 4 +- .../css/themes/soft/manon/nota-bene.scss | 2 +- .../soft/manon/notification-colors.scss | 16 +++ .../assets/css/themes/soft/manon/section.scss | 2 +- .../css/themes/soft/manon/sidemenu.scss | 10 +- .../css/themes/soft/manon/spot-large.scss | 4 +- rocky/assets/css/themes/soft/manon/table.scss | 14 +- rocky/assets/css/themes/soft/manon/tabs.scss | 10 +- .../css/themes/soft/manon/text-colors.scss | 4 +- rocky/assets/css/themes/soft/manon/tile.scss | 2 +- rocky/assets/css/themes/soft/report.scss | 2 +- rocky/assets/css/themes/soft/soft.scss | 4 +- 41 files changed, 284 insertions(+), 213 deletions(-) delete mode 100644 rocky/assets/css/themes/soft/colors.scss create mode 100644 rocky/assets/css/themes/soft/colors/colors.scss create mode 100644 rocky/assets/css/themes/soft/colors/tag-colors.scss create mode 100644 rocky/assets/css/themes/soft/colors/tags-6-3.scss create mode 100644 rocky/assets/css/themes/soft/manon/notification-colors.scss diff --git a/rocky/assets/css/components/dropdown.scss b/rocky/assets/css/components/dropdown.scss index 6b6934d2b42..6c93253cc43 100644 --- a/rocky/assets/css/components/dropdown.scss +++ b/rocky/assets/css/components/dropdown.scss @@ -21,7 +21,7 @@ > ul { padding: 0; display: none; - background-color: #ffffff; + background-color: var(--colors-white); list-style-type: disc; margin-block-end: 0; margin-block-start: 0; diff --git a/rocky/assets/css/components/hover-block.scss b/rocky/assets/css/components/hover-block.scss index 4d868c3da71..f55b3ad117c 100644 --- a/rocky/assets/css/components/hover-block.scss +++ b/rocky/assets/css/components/hover-block.scss @@ -22,9 +22,9 @@ tbody td.has-hover-block { } tbody td.has-hover-block .hover-block { - background: #ffffff; - border: 1px solid #cccccc; - box-shadow: 0 8px 8px rgb(10 10 10 / 10%); + background: var(--colors-white); + border: 1px solid var(--colors-grey-200); + box-shadow: 0 8px 8px var(--colors-black-10); display: none; top: calc(100% - 0.25em); left: 15%; diff --git a/rocky/assets/css/components/plugins.scss b/rocky/assets/css/components/plugins.scss index bbbed1bd514..630b2337151 100644 --- a/rocky/assets/css/components/plugins.scss +++ b/rocky/assets/css/components/plugins.scss @@ -47,7 +47,7 @@ $normalizer-bg: #e17000; .tile-label { background-color: #262431; - color: #ffffff; + color: var(--colors-white); font-size: 1.125rem; margin: 0; padding: 0.25rem 1rem; diff --git a/rocky/assets/css/components/qr-code.scss b/rocky/assets/css/components/qr-code.scss index 90cded861dc..f1742ae313b 100644 --- a/rocky/assets/css/components/qr-code.scss +++ b/rocky/assets/css/components/qr-code.scss @@ -2,6 +2,6 @@ form.horizontal-view > fieldset > div > .qr-code-image { max-width: 15rem; float: left; - background-color: #ffffff; + background-color: var(--colors-white); margin-left: var(--form-horizontal-view-gap); } diff --git a/rocky/assets/css/components/report.scss b/rocky/assets/css/components/report.scss index 8d91f5a96c3..244fc450bf9 100644 --- a/rocky/assets/css/components/report.scss +++ b/rocky/assets/css/components/report.scss @@ -100,7 +100,7 @@ span { &.label { display: inline-flex; max-width: 18.75rem; - border: 1px solid #ffffff; + border: 1px solid var(--colors-white); border-radius: var(--spacing-grid-050); padding: var(--spacing-grid-050) var(--spacing-grid-100); font-size: var(--tile-font-size); @@ -109,8 +109,8 @@ span { var(--spacing-grid-050) 0; &.tags-color-grey-2 { - color: var(--colors-grey-10); - background-color: var(--colors-grey-2); + color: var(--colors-grey-800); + background-color: var(--colors-grey-100); } } } diff --git a/rocky/assets/css/components/risk-level-indicator.scss b/rocky/assets/css/components/risk-level-indicator.scss index 64cce08ba46..58d13b9cb80 100644 --- a/rocky/assets/css/components/risk-level-indicator.scss +++ b/rocky/assets/css/components/risk-level-indicator.scss @@ -8,13 +8,13 @@ .recommendation, .pending, .unknown { - --risk-level-critical: #f84638; - --risk-level-high: #ff9a4d; - --risk-level-medium: #fbe366; - --risk-level-low: #a6e5b7; - --risk-level-informational: #c6e6fa; - --risk-level-pending: #a4a4a4; - --risk-level-unkown: #a4a4a4; + --risk-level-critical: var(--colors-red-500); + --risk-level-high: var(--colors-orange-300); + --risk-level-medium: var(--colors-ochre-150); + --risk-level-low: var(--colors-green-150); + --risk-level-informational: var(--colors-blue-150); + --risk-level-pending: var(--colors-grey-400); + --risk-level-unkown: var(--colors-grey-400); display: flex; align-items: center; diff --git a/rocky/assets/css/components/scan-level-indicator.scss b/rocky/assets/css/components/scan-level-indicator.scss index 2522407cd5d..68d83626466 100644 --- a/rocky/assets/css/components/scan-level-indicator.scss +++ b/rocky/assets/css/components/scan-level-indicator.scss @@ -35,19 +35,19 @@ Markup: } &.l1 li:first-child::before { - color: var(--colors-purrple-8); + color: var(--colors-purrple-500); } &.l2 li:nth-child(-n + 2)::before { - color: var(--colors-purrple-9); + color: var(--colors-purrple-600); } &.l3 li:nth-child(-n + 3)::before { - color: var(--colors-purrple-10); + color: var(--colors-purrple-700); } &.l4 li:nth-child(-n + 4)::before { - color: var(--colors-purrple-11); + color: var(--colors-purrple-800); } &-form { diff --git a/rocky/assets/css/components/state-tags.scss b/rocky/assets/css/components/state-tags.scss index 6955560797b..369d04b166e 100644 --- a/rocky/assets/css/components/state-tags.scss +++ b/rocky/assets/css/components/state-tags.scss @@ -3,24 +3,11 @@ .new { @extend %tag; - background-color: var(--colors-blue-1); - border: 1px solid var(--colors-blue-5); - color: var(--colors-blue-8); + background-color: var(--colors-blue-50); + border: 1px solid var(--colors-blue-300); + color: var(--colors-blue-600); } -// .tag.critical { -// @extend %tag; - -// background-color: var(--colors-red-3); -// border: 1px solid var(--risk-level-critical); -// color: var(--colors-orange-8); -// display: inline; - -// &::before { -// content: none; -// } -// } - .tag { &.critical, &.medium, @@ -35,20 +22,20 @@ } &.critical { - background-color: var(--colors-red-3); + background-color: var(--colors-red-150); border: 1px solid var(--risk-level-critical); - color: var(--colors-orange-8); + color: var(--colors-orange-700); } &.medium { - background-color: var(--colors-yellow-1); - border: 1px solid var(--colors-yellow-6); + background-color: var(--colors-yellow-50); + border: 1px solid var(--colors-yellow-300); color: var(--color-alert-warning); } &.secure { - background-color: var(--colors-green-4); - border: 1px solid var(--colors-green-7); - color: var(--colors-green-9); + background-color: var(--colors-green-200); + border: 1px solid var(--colors-green-500); + color: var(--colors-green-700); } } diff --git a/rocky/assets/css/components/stepper-variables.scss b/rocky/assets/css/components/stepper-variables.scss index 8f44ee7f75f..fd42aaed3b6 100644 --- a/rocky/assets/css/components/stepper-variables.scss +++ b/rocky/assets/css/components/stepper-variables.scss @@ -48,7 +48,7 @@ --list-item-completed-opacity ); --list-item-completed-above-breakpoint-border-top: 2px solid - var(--colors-purrple-8); + var(--colors-purrple-500); --list-item-completed-above-breakpoint-margin-top: -2px; /* Compensating for the active top border */ /* Icon between stepper items */ @@ -64,7 +64,7 @@ --stepper-item-current-icon-font-family: tabler-icons; --stepper-item-current-icon-display: block; --stepper-item-current-icon-font-weight: 400; - --stepper-item-current-icon-color: var(--colors-purrple-8); + --stepper-item-current-icon-color: var(--colors-purrple-500); --stepper-item-current-icon-position: absolute; --stepper-item-current-icon-top: -0.875rem; /* Half the size of the icon */ --stepper-item-current-icon-bottom: auto; diff --git a/rocky/assets/css/components/table-state-icons.scss b/rocky/assets/css/components/table-state-icons.scss index fbf36439a90..c5def0d7acc 100644 --- a/rocky/assets/css/components/table-state-icons.scss +++ b/rocky/assets/css/components/table-state-icons.scss @@ -71,7 +71,7 @@ table td .icon { &.incomplete { &::before { content: "\ea6a"; // $ti-icon-circle-x - color: var(--colors-grey-11); + color: var(--colors-grey-900); } } diff --git a/rocky/assets/css/components/user-icon.scss b/rocky/assets/css/components/user-icon.scss index 77d192b6d4e..2d17213526a 100644 --- a/rocky/assets/css/components/user-icon.scss +++ b/rocky/assets/css/components/user-icon.scss @@ -7,8 +7,8 @@ body > header nav ul li a.user-icon, height: 3rem; max-width: 3rem; max-height: 3rem; - background-color: var(--colors-purrple-8); - color: #ffffff; + background-color: var(--colors-purrple-500); + color: var(--colors-white); margin: auto 0; padding: 0.5rem; box-sizing: border-box; diff --git a/rocky/assets/css/themes/soft/colors.scss b/rocky/assets/css/themes/soft/colors.scss deleted file mode 100644 index b3971dcc591..00000000000 --- a/rocky/assets/css/themes/soft/colors.scss +++ /dev/null @@ -1,95 +0,0 @@ -/* Colors */ - -:root { - --colors-white: #ffffff; - - /* Grey */ - --colors-grey-1: #f6f6f6; - --colors-grey-2: #ededed; - --colors-grey-3: #efefef; - --colors-grey-4: #d4d4d4; - --colors-grey-5: #a4a4a4; - --colors-grey-6: #888888; - --colors-grey-7: #6a6a6a; - --colors-grey-8: #666666; - --colors-grey-9: #585858; - --colors-grey-10: #464646; - --colors-grey-11: #3b3b3b; - --colors-grey-12: rgb(0 0 0 / 5%); - --colors-grey-13: rgb(0 0 0 / 10%); - --colors-grey-14: rgb(0 0 0 / 15%); - --colors-grey-15: rgb(17 20 22 / 50%); - - /* Red */ - --colors-red-1: #fff4f3; - --colors-red-2: #ffe9e7; - --colors-red-3: #ffc7c3; - --colors-red-4: #ffa49d; - --colors-red-5: #ff7d73; - --colors-red-6: #f84638; - --colors-red-7: #c3372c; - --colors-red-8: #a22e25; - --colors-red-9: #6e1f19; - - /* Blue */ - --colors-blue-1: #eef8fe; - --colors-blue-2: #ddf0fc; - --colors-blue-3: #c6e6fa; - --colors-blue-4: #abdbf8; - --colors-blue-5: #78c5f4; - --colors-blue-6: #40adef; - --colors-blue-7: #008de4; - --colors-blue-8: #006fb3; - --colors-blue-9: #005c94; - --colors-blue-10: #003e64; - - /* Yellow */ - --colors-yellow-1: #fff7cf; - --colors-yellow-2: #ffef99; - --colors-yellow-3: #fbe366; - --colors-yellow-4: #fecf48; - --colors-yellow-5: #f9d100; - --colors-yellow-6: #ddb900; - --colors-yellow-7: #a08700; - --colors-yellow-8: #7d6900; - --colors-yellow-9: #685700; - --colors-yellow-10: #584a00; - - /* Green */ - --colors-green-1: #ebfaef; - --colors-green-2: #d5f5de; - --colors-green-3: #a6e5b7; - --colors-green-4: #94e6ab; - --colors-green-5: #4ad571; - --colors-green-6: #20bd4c; - --colors-green-7: #1b9d3f; - --colors-green-8: #157b31; - --colors-green-9: #116629; - --colors-green-10: #134421; - - /* Orange */ - --colors-orange-1: #fff5ed; - --colors-orange-2: #ffead9; - --colors-orange-3: #ffcaa1; - --colors-orange-4: #ffa865; - --colors-orange-5: #ff9a4d; - --colors-orange-6: #d66a17; - --colors-orange-7: #a75312; - --colors-orange-8: #8b450f; - --colors-orange-9: #5e2f0a; - - /* Purple */ - --colors-purrple-1: #f7f6fc; - --colors-purrple-2: #eeecf8; - --colors-purrple-3: #f0ebff; - --colors-purrple-4: #d6d1ef; - --colors-purrple-5: #bfb6e6; - --colors-purrple-6: #a89cdd; - --colors-purrple-7: #af9bd3; - --colors-purrple-8: #8c7cd2; - --colors-purrple-9: #6e5fae; - --colors-purrple-10: #5b4f90; - --colors-purrple-11: #4d437a; - --colors-purrple-12: #3d3560; - --colors-purrple-13: #5027bc; -} diff --git a/rocky/assets/css/themes/soft/colors/colors.scss b/rocky/assets/css/themes/soft/colors/colors.scss new file mode 100644 index 00000000000..2e9e71e6b27 --- /dev/null +++ b/rocky/assets/css/themes/soft/colors/colors.scss @@ -0,0 +1,120 @@ +/* Colors */ + +:root { + --colors-white: #ffffff; + + /* Black */ + --colors-black: #000000; + --colors-black-05: rgb(0 0 0 / 5%); + --colors-black-10: rgb(0 0 0 / 10%); + --colors-black-15: rgb(0 0 0 / 15%); + + /* Grey */ + --colors-grey-50: #f6f6f6; + --colors-grey-100: #ededed; + --colors-grey-150: #efefef; + --colors-grey-200: #d4d4d4; + --colors-grey-300: #bcbcbc; + --colors-grey-400: #a4a4a4; + --colors-grey-500: #888888; + --colors-grey-600: #6a6a6a; + --colors-grey-700: #585858; + --colors-grey-800: #4b4b4b; + --colors-grey-900: #3b3b3b; + + /* Red */ + --colors-red-50: #fff4f3; + --colors-red-100: #ffe9e7; + --colors-red-150: #ffc7c3; + --colors-red-200: #ffa49d; + --colors-red-300: #ff7d73; + --colors-red-400: #f95f53; + --colors-red-500: #f84638; + --colors-red-600: #c3372c; + --colors-red-700: #a22e25; + --colors-red-800: #8a271f; + --colors-red-900: #6e1f19; + --colors-red-1000: #531713; + + /* Blue */ + --colors-blue-50: #eef8fe; + --colors-blue-100: #ddf0fc; + --colors-blue-150: #c7e7fa; + --colors-blue-200: #abdbf8; + --colors-blue-300: #78c5f4; + --colors-blue-400: #40adef; + --colors-blue-500: #008de4; + --colors-blue-600: #006fb3; + --colors-blue-700: #005c94; + --colors-blue-800: #004e7e; + --colors-blue-900: #003e64; + --colors-blue-1000: #002033; + + /* Yellow */ + --colors-yellow-50: #fff7cf; + --colors-yellow-100: #ffef99; + --colors-yellow-150: #ffe661; + --colors-yellow-200: #f9d100; + --colors-yellow-300: #ddb900; + --colors-yellow-400: #c1a200; + --colors-yellow-500: #a08700; + --colors-yellow-600: #7d6900; + --colors-yellow-700: #685700; + --colors-yellow-800: #584a00; + --colors-yellow-900: #463b00; + + /* Green */ + --colors-green-50: #ebfaef; + --colors-green-100: #d5f5de; + --colors-green-150: #b0edc1; + --colors-green-200: #94e6ab; + --colors-green-300: #4ad571; + --colors-green-400: #20bd4c; + --colors-green-500: #1b9d3f; + --colors-green-600: #157b31; + --colors-green-700: #116629; + --colors-green-800: #0f5723; + --colors-green-900: #134421; + --colors-green-1000: #09200f; + + /* Orange */ + --colors-orange-50: #fff5ed; + --colors-orange-100: #ffead9; + --colors-orange-150: #ffdcc2; + --colors-orange-200: #ffcaa1; + --colors-orange-250: #ffb780; + --colors-orange-300: #ffa865; + --colors-orange-400: #ff8120; + --colors-orange-500: #d66a17; + --colors-orange-600: #a75312; + --colors-orange-700: #8b450f; + --colors-orange-800: #763b0d; + --colors-orange-900: #5e2f0a; + --colors-orange-1000: #2e1705; + + /* Purple */ + --colors-purrple-50: #f7f6fc; + --colors-purrple-100: #eeecf8; + --colors-purrple-200: #d6d1ef; + --colors-purrple-300: #bfb6e6; + --colors-purrple-400: #a89cdd; + --colors-purrple-500: #8c7cd2; + --colors-purrple-600: #6e5fae; + --colors-purrple-700: #5b4f90; + --colors-purrple-800: #4d437a; + --colors-purrple-900: #3d3560; + --colors-purrple-1000: #1f1b31; + + /* Ochre */ + --colors-ochre-50: #fff7e0; + --colors-ochre-100: #ffeaae; + --colors-ochre-150: #fedc7b; + --colors-ochre-200: #fecf48; + --colors-ochre-300: #ecb927; + --colors-ochre-400: #d4a00c; + --colors-ochre-500: #a87f05; + --colors-ochre-600: #916f08; + --colors-ochre-700: #614a05; + --colors-ochre-800: #584304; + --colors-ochre-900: #493803; +} diff --git a/rocky/assets/css/themes/soft/colors/tag-colors.scss b/rocky/assets/css/themes/soft/colors/tag-colors.scss new file mode 100644 index 00000000000..39e1051b158 --- /dev/null +++ b/rocky/assets/css/themes/soft/colors/tag-colors.scss @@ -0,0 +1,8 @@ +/* Tag colors */ +@import "tags-6-3"; + +:root { + --tag-color-light-grey-background-color: var(--colors-grey-100); + --tag-color-light-grey-text-color: var(--colors-grey-800); + --tag-color-light-grey-border-color: var(--colors-white); +} diff --git a/rocky/assets/css/themes/soft/colors/tags-6-3.scss b/rocky/assets/css/themes/soft/colors/tags-6-3.scss new file mode 100644 index 00000000000..5ada566dc19 --- /dev/null +++ b/rocky/assets/css/themes/soft/colors/tags-6-3.scss @@ -0,0 +1,27 @@ +/* tags-6-3 */ + +:root { + /* Blue */ + --tags-soft-blue-light-border-color: var(--colors-blue-300); + --tags-soft-blue-medium-border-color: var(--colors-blue-600); + --tags-soft-blue-dark-text-color: var(--colors-blue-700); + + /* Green */ + --tags-soft-green-light-border-color: var(--colors-green-300); + + /* Yellow */ + --tags-soft-yellow-light-background-color: var(--colors-ochre-50); + --tags-soft-yellow-light-text-color: var(--colors-ochre-500); + --tags-soft-yellow-light-border-color: var(--colors-ochre-300); + --tags-soft-yellow-medium-background-color: var(--colors-ochre-200); + --tags-soft-yellow-medium-text-color: var(--colors-ochre-600); + --tags-soft-yellow-medium-border-color: var(--colors-ochre-400); + --tags-soft-yellow-dark-background-color: var(--colors-ochre-300); + --tags-soft-yellow-dark-text-color: var(--colors-ochre-700); + --tags-soft-yellow-dark-border-color: var(--colors-ochre-600); + + /* Orange */ + --tags-soft-orange-light-text-color: var(--colors-orange-600); + --tags-soft-orange-light-border-color: var(--colors-orange-300); + --tags-soft-orange-dark-border-color: var(--colors-orange-600); +} diff --git a/rocky/assets/css/themes/soft/manon/accordion.scss b/rocky/assets/css/themes/soft/manon/accordion.scss index c8be21b7f98..f621b8da4b3 100644 --- a/rocky/assets/css/themes/soft/manon/accordion.scss +++ b/rocky/assets/css/themes/soft/manon/accordion.scss @@ -7,7 +7,7 @@ --accordion-button-padding: 0.75rem 0; --accordion-button-justify-content: flex-start; --accordion-button-background-color: transparent; - --accordion-button-text-color: #006fb3; + --accordion-button-text-color: var(--colors-blue-600); /* Button icon */ @@ -32,8 +32,8 @@ /* Content */ --accordion-content-gap: 1.5rem; --accordion-content-border-width: 0 0 1px 0; - --accordion-content-background-color: #ffffff; - --accordion-content-text-color: #000000; + --accordion-content-background-color: var(--colors-white); + --accordion-content-text-color: var(--colors-black); --accordion-content-padding: 1.5rem 2rem 2rem 2rem; } @@ -46,7 +46,7 @@ button { border-width: 0 0 1px; border-radius: 0; - border-color: #d4d4d4; + border-color: var(--colors-grey-200); max-width: 100%; word-wrap: break-word; diff --git a/rocky/assets/css/themes/soft/manon/body-text-set.scss b/rocky/assets/css/themes/soft/manon/body-text-set.scss index 103804f3693..ee0127dfb59 100644 --- a/rocky/assets/css/themes/soft/manon/body-text-set.scss +++ b/rocky/assets/css/themes/soft/manon/body-text-set.scss @@ -30,7 +30,7 @@ --body-text-small-font-size: 0.875rem; --body-text-small-font-weight: var(--text-set-font-weight); --body-text-small-line-height: var(--text-set-line-height); - --body-text-small-color: #696969; + --body-text-small-color: var(--colors-grey-700); --body-text-small-text-align: var(--text-set-text-align); /* Strong */ diff --git a/rocky/assets/css/themes/soft/manon/button-ghost.scss b/rocky/assets/css/themes/soft/manon/button-ghost.scss index 8c19c446286..f03ab8bc83b 100644 --- a/rocky/assets/css/themes/soft/manon/button-ghost.scss +++ b/rocky/assets/css/themes/soft/manon/button-ghost.scss @@ -3,8 +3,8 @@ :root { /* Button */ --button-ghost-background-color: transparent; - --button-ghost-border-color: #d4d4d4; - --button-ghost-text-color: #006fb3; + --button-ghost-border-color: var(--colors-grey-200); + --button-ghost-text-color: var(--colors-blue-600); /* Text */ --button-ghost-font-size: 1rem; @@ -15,16 +15,16 @@ /* Hover */ --button-ghost-hover-background-color: transparent; - --button-ghost-hover-border-color: #006fb3; - --button-ghost-hover-text-color: #006fb3; + --button-ghost-hover-border-color: var(--colors-blue-600); + --button-ghost-hover-text-color: var(--colors-blue-700); /* Active */ --button-ghost-active-background-color: transparent; - --button-ghost-active-border-color: var(--branding-color-1-darker); - --button-ghost-active-text-color: #006fb3; + --button-ghost-active-border-color: var(--button-ghost-hover-border-color); + --button-ghost-active-text-color: var(--button-ghost-hover-text-color); /* Focus */ --button-ghost-focus-background-color: transparent; - --button-ghost-focus-border-color: var(--branding-color-1-darker); - --button-ghost-focus-text-color: #006fb3; + --button-ghost-focus-border-color: var(--button-ghost-hover-border-color); + --button-ghost-focus-text-color: var(--button-ghost-hover-text-color); } diff --git a/rocky/assets/css/themes/soft/manon/button.scss b/rocky/assets/css/themes/soft/manon/button.scss index 63d0e59c8a3..4352c181d50 100644 --- a/rocky/assets/css/themes/soft/manon/button.scss +++ b/rocky/assets/css/themes/soft/manon/button.scss @@ -24,19 +24,19 @@ /* States */ /* Hover */ - --button-base-hover-background-color: #ddb900; - --button-base-hover-text-color: #000000; + --button-base-hover-background-color: var(--colors-yellow-300); + --button-base-hover-text-color: var(--colors-black); /* Active */ - --button-base-active-background-color: #ddb900; - --button-base-active-text-color: #000000; + --button-base-active-background-color: var(--colors-yellow-300); + --button-base-active-text-color: var(--colors-black); --button-base-active-border-style: var(--button-base-border-style); --button-base-active-border-color: var(--button-base-active-background-color); --button-base-active-border-width: var(--button-base-border-width); /* Focus */ - --button-base-focus-background-color: #ddb900; - --button-base-focus-text-color: #000000; + --button-base-focus-background-color: var(--colors-yellow-300); + --button-base-focus-text-color: var(--colors-black); --button-base-focus-border-style: var(--button-base-border-style); --button-base-focus-border-color: var(--button-base-focus-background-color); --button-base-focus-border-width: var(--button-base-border-width); diff --git a/rocky/assets/css/themes/soft/manon/collapsing-element.scss b/rocky/assets/css/themes/soft/manon/collapsing-element.scss index 5deaa1f9516..ecf2afda0d2 100644 --- a/rocky/assets/css/themes/soft/manon/collapsing-element.scss +++ b/rocky/assets/css/themes/soft/manon/collapsing-element.scss @@ -55,7 +55,7 @@ body header nav.collapsible { li:first-child { border-width: 1px 0; border-style: solid; - border-color: #d3d3d3; + border-color: var(--colors-grey-200); } } } diff --git a/rocky/assets/css/themes/soft/manon/expando-rows.scss b/rocky/assets/css/themes/soft/manon/expando-rows.scss index 72a64892c3f..50d0ebb497a 100644 --- a/rocky/assets/css/themes/soft/manon/expando-rows.scss +++ b/rocky/assets/css/themes/soft/manon/expando-rows.scss @@ -1,8 +1,8 @@ /* Expando rows - Variables */ :root { - --expando-rows-table-cell-background-color: #ffffff; - --expando-rows-row-background-color: #eeecf8; + --expando-rows-table-cell-background-color: var(--colors-white); + --expando-rows-row-background-color: var(--colors-purrple-100); --expando-rows-row-striping-background-color: var( --expando-rows-row-background-color ); diff --git a/rocky/assets/css/themes/soft/manon/footer.scss b/rocky/assets/css/themes/soft/manon/footer.scss index b5fe088c37c..4630f8e3479 100644 --- a/rocky/assets/css/themes/soft/manon/footer.scss +++ b/rocky/assets/css/themes/soft/manon/footer.scss @@ -13,8 +13,8 @@ --footer-gap: 2rem; /* Visual styling */ - --footer-background-color: #ffffff; - --footer-text-color: #6a6a6a; + --footer-background-color: var(--colors-white); + --footer-text-color: var(--colors-grey-600); /* Links */ --footer-link-text-color: var(--link-text-color); diff --git a/rocky/assets/css/themes/soft/manon/form.scss b/rocky/assets/css/themes/soft/manon/form.scss index fef76a5e614..26bbd7eb2d2 100644 --- a/rocky/assets/css/themes/soft/manon/form.scss +++ b/rocky/assets/css/themes/soft/manon/form.scss @@ -5,10 +5,10 @@ --form-accent-color-color: var(--branding-color-2); /* Input */ - --form-base-input-text-color: #000000; + --form-base-input-text-color: var(--colors-black); --form-input-border-width: 1px; --form-input-border-style: solid; - --form-input-border-color: #cccccc; + --form-input-border-color: var(--colors-grey-200); --form-inline-gap: 1rem; /* Help */ @@ -17,7 +17,7 @@ /* Textarea */ --form-textarea-text-color: var(--form-base-input-text-color); - --form-textarea-border-color: #cccccc; + --form-textarea-border-color: var(--colors-grey-200); /* Fieldset */ --form-fieldset-legend-font-weight: 600; diff --git a/rocky/assets/css/themes/soft/manon/header-navigation-collapsible.scss b/rocky/assets/css/themes/soft/manon/header-navigation-collapsible.scss index 42ed8c246f1..dfa9f5e972d 100644 --- a/rocky/assets/css/themes/soft/manon/header-navigation-collapsible.scss +++ b/rocky/assets/css/themes/soft/manon/header-navigation-collapsible.scss @@ -13,7 +13,9 @@ --header-navigation-collapsible-list-item-link-selected-icon: "\ea5e"; /* Hover */ - --header-navigation-collapsible-list-item-link-hover-background-color: #f1f1f1; + --header-navigation-collapsible-list-item-link-hover-background-color: var( + --colors-grey-50 + ); --header-navigation-collapsible-list-item-link-selected-font-weight: bold; } diff --git a/rocky/assets/css/themes/soft/manon/header-navigation-link-active.scss b/rocky/assets/css/themes/soft/manon/header-navigation-link-active.scss index 3544f44a87b..4e1f882eb8c 100644 --- a/rocky/assets/css/themes/soft/manon/header-navigation-link-active.scss +++ b/rocky/assets/css/themes/soft/manon/header-navigation-link-active.scss @@ -1,9 +1,9 @@ /* Header navigation link active - Variables */ :root { - --header-navigation-link-active-text-color: var(--colors-purrple-8); + --header-navigation-link-active-text-color: var(--colors-purrple-500); --header-navigation-link-active-border-width: 0 0 0.25rem 0; --header-navigation-link-active-border-style: solid; - --header-navigation-link-active-border-color: var(--colors-purrple-8); + --header-navigation-link-active-border-color: var(--colors-purrple-500); --header-navigation-list-align-items: stretch; } diff --git a/rocky/assets/css/themes/soft/manon/language-selector-list.scss b/rocky/assets/css/themes/soft/manon/language-selector-list.scss index 9e895209ff0..8850fc6d712 100644 --- a/rocky/assets/css/themes/soft/manon/language-selector-list.scss +++ b/rocky/assets/css/themes/soft/manon/language-selector-list.scss @@ -28,16 +28,16 @@ --language-selector-list-closed-button-icon: "\ea62"; /* List */ - --language-selector-list-border-color: #d4d4d4; + --language-selector-list-border-color: var(--colors-grey-200); --language-selector-list-border-radius: 0.25rem; --language-selector-list-margin-top: 0.25rem; - --language-selector-list-box-shadow: 0px 8px 16px 0px rgb(17 20 22 / 15%); + --language-selector-list-box-shadow: 0px 8px 16px 0px var(--colors-black-15); --language-selector-list-min-width: 8rem; /* List item */ --language-selector-list-item-background-color: transparent; --language-selector-list-item-active-background-color: transparent; - --language-selector-list-item-hover-background-color: #ededed; + --language-selector-list-item-hover-background-color: var(--colors-grey-100); /* List item link */ --language-selector-list-item-link-border-width: 0; @@ -118,7 +118,7 @@ body > header nav { button { min-width: 0; - color: #006fb3; + color: var(--colors-blue-600); text-decoration: underline; text-transform: uppercase; } diff --git a/rocky/assets/css/themes/soft/manon/login-meta.scss b/rocky/assets/css/themes/soft/manon/login-meta.scss index 67fe140e103..07fc5b6a0ed 100644 --- a/rocky/assets/css/themes/soft/manon/login-meta.scss +++ b/rocky/assets/css/themes/soft/manon/login-meta.scss @@ -1,6 +1,6 @@ /* Login meta - Variables */ :root { - --login-meta-background-color: #eaeaea; - --login-meta-color: #000000; + --login-meta-background-color: var(--colors-grey-100); + --login-meta-color: var(--colors-black); } diff --git a/rocky/assets/css/themes/soft/manon/logo.scss b/rocky/assets/css/themes/soft/manon/logo.scss index f6da24b7540..9b047f75eb3 100644 --- a/rocky/assets/css/themes/soft/manon/logo.scss +++ b/rocky/assets/css/themes/soft/manon/logo.scss @@ -1,7 +1,7 @@ /* Logo - Variables */ :root { - --logo-background-color: #111416; + --logo-background-color: var(--colors-black); --logo-border-radius: 50%; --logo-margin: 0; } diff --git a/rocky/assets/css/themes/soft/manon/navigation-collapsible.scss b/rocky/assets/css/themes/soft/manon/navigation-collapsible.scss index 084a629d329..dcca093c9f4 100644 --- a/rocky/assets/css/themes/soft/manon/navigation-collapsible.scss +++ b/rocky/assets/css/themes/soft/manon/navigation-collapsible.scss @@ -1,17 +1,19 @@ /* Navigation collapsible menu - Variables */ :root { - --navigation-collapsible-menu-collapsing-menu-list-item-link-hover-background-color: #ededed; + --navigation-collapsible-menu-collapsing-menu-list-item-link-hover-background-color: var( + --colors-grey-100 + ); } body > header nav.collapsible-menu .collapsing-menu { ul, ol { - border: 1px solid #ededed; - background-color: #ffffff; + border: 1px solid var(--colors-grey-100); + background-color: var(--colors-white); a[aria-current] { - background-color: #ffffff; + background-color: var(--colors-white); font-weight: bold; &::before { @@ -26,7 +28,7 @@ body > header nav.collapsible-menu .collapsing-menu { } > div { - background-color: #ffffff; + background-color: var(--colors-white); width: 100%; display: flex; flex-direction: column; @@ -41,7 +43,7 @@ body > header nav.collapsible-menu .collapsing-menu { justify-content: stretch; align-items: center; min-height: 3rem; - background-color: #ffffff; + background-color: var(--colors-white); width: 100%; box-sizing: border-box; order: 1; diff --git a/rocky/assets/css/themes/soft/manon/navigation.scss b/rocky/assets/css/themes/soft/manon/navigation.scss index 6b6014628c8..8ee2227eb94 100644 --- a/rocky/assets/css/themes/soft/manon/navigation.scss +++ b/rocky/assets/css/themes/soft/manon/navigation.scss @@ -14,7 +14,9 @@ /* Collapsing menu */ --navigation-collapsible-menu-collapsing-menu-width: 100%; - --navigation-collapsible-menu-list-item-collapsed-hover-background-color: #14131a; + --navigation-collapsible-menu-list-item-collapsed-hover-background-color: var( + --colors-black + ); /* Collapsing menu item */ diff --git a/rocky/assets/css/themes/soft/manon/nota-bene.scss b/rocky/assets/css/themes/soft/manon/nota-bene.scss index 7b9c0b4527f..aa5795e7fc8 100644 --- a/rocky/assets/css/themes/soft/manon/nota-bene.scss +++ b/rocky/assets/css/themes/soft/manon/nota-bene.scss @@ -1,5 +1,5 @@ /* Nota bene */ :root { - --nota-bene-text-color: #5d5d5d; + --nota-bene-text-color: var(--colors-grey-600); } diff --git a/rocky/assets/css/themes/soft/manon/notification-colors.scss b/rocky/assets/css/themes/soft/manon/notification-colors.scss new file mode 100644 index 00000000000..471b632af8d --- /dev/null +++ b/rocky/assets/css/themes/soft/manon/notification-colors.scss @@ -0,0 +1,16 @@ +/* Notification colors */ + +:root { + --error-background-color: var(--colors-red-100); + --error-text-color: var(--colors-grey-900); + --error-border-color: var(--colors-black-10); + --explanation-background-color: var(--colors-blue-100); + --explanation-text-color: var(--colors-grey-900); + --explanation-border-color: var(--colors-black-10); + --warning-background-color: var(--colors-ochre-50); + --warning-text-color: var(--colors-grey-900); + --warning-border-color: var(--colors-black-10); + --confirmation-background-color: var(--colors-green-100); + --confirmation-text-color: var(--colors-grey-900); + --confirmation-border-color: var(--colors-black-10); +} diff --git a/rocky/assets/css/themes/soft/manon/section.scss b/rocky/assets/css/themes/soft/manon/section.scss index b2e1a052d8b..1ec00f324df 100644 --- a/rocky/assets/css/themes/soft/manon/section.scss +++ b/rocky/assets/css/themes/soft/manon/section.scss @@ -27,6 +27,6 @@ body > main > section { } &.dividing-line { - border-top: 1px solid #cccccc; + border-top: 1px solid var(--colors-grey-200); } } diff --git a/rocky/assets/css/themes/soft/manon/sidemenu.scss b/rocky/assets/css/themes/soft/manon/sidemenu.scss index 563847aa860..a8a6b719872 100644 --- a/rocky/assets/css/themes/soft/manon/sidemenu.scss +++ b/rocky/assets/css/themes/soft/manon/sidemenu.scss @@ -40,7 +40,7 @@ main.sidemenu { padding-bottom: 0; padding-left: var(--sidemenu-nav-padding-left); box-sizing: border-box; - background-color: #ffffff; + background-color: var(--colors-white); border-right: 1px solid var(--sidemenu-nav-border-color); height: 100%; z-index: 1; @@ -67,7 +67,7 @@ main.sidemenu { a:visited, a:focus, a:active { - color: #000000; + color: var(--colors-black); text-decoration: none; } @@ -76,7 +76,7 @@ main.sidemenu { a:visited, a:focus, a:active { - color: #000000; + color: var(--colors-black); text-decoration: none; font-style: italic; word-break: break-all; @@ -112,7 +112,7 @@ main.sidemenu { font-size: var(--sidemenu-toggle-button-font-size); border: 0; border-radius: 0; - color: #000000; + color: var(--colors-black); /* Transition */ transition: margin-left 1s; @@ -154,7 +154,7 @@ main.sidemenu { .sticky-container > nav { position: absolute; - border-right: 1px solid #cccccc; + border-right: 1px solid var(--colors-grey-200); /* Needed to show the button */ overflow: visible; diff --git a/rocky/assets/css/themes/soft/manon/spot-large.scss b/rocky/assets/css/themes/soft/manon/spot-large.scss index 32a69b4b0fa..36beef96bb5 100644 --- a/rocky/assets/css/themes/soft/manon/spot-large.scss +++ b/rocky/assets/css/themes/soft/manon/spot-large.scss @@ -10,10 +10,10 @@ /* Main colors */ /* Lavender */ - --branding-color-1: var(--colors-purrple-2); + --branding-color-1: var(--colors-purrple-100); /* Bright yellow */ - --branding-color-2: var(--colors-yellow-4); + --branding-color-2: var(--colors-yellow-200); /* Accent colors */ diff --git a/rocky/assets/css/themes/soft/manon/table.scss b/rocky/assets/css/themes/soft/manon/table.scss index 8e1c74f4156..850fab9beaa 100644 --- a/rocky/assets/css/themes/soft/manon/table.scss +++ b/rocky/assets/css/themes/soft/manon/table.scss @@ -2,15 +2,15 @@ :root { /* Base */ - --table-background-color: #ffffff; + --table-background-color: var(--colors-white); --table-text-color: var(--application-base-text-color); --table-text-align: left; /* Table header */ - --table-head-background-color: #ffffff; + --table-head-background-color: var(--colors-white); --table-head-border-width: 0 0 2px 0; --table-head-border-style: solid; - --table-head-border-color: var(--colors-purrple-6); + --table-head-border-color: var(--colors-purrple-400); /* Table row */ --table-row-background-color-striping: transparent; @@ -25,7 +25,7 @@ /* Table cell */ --table-cell-border-width: 0 0 1px 0; --table-cell-border-style: solid; - --table-cell-border-color: #cccccc; + --table-cell-border-color: var(--colors-grey-200); --table-cell-padding: 0.5rem 1rem; --table-cells-padding: 0.25rem 1rem; @@ -35,11 +35,11 @@ --table-action-buttons-button-hover-text-color: var(--link-text-color); /* Table footer */ - --table-foot-background-color: #ffffff; + --table-foot-background-color: var(--colors-white); --table-foot-font-weight: 600; --table-foot-font-size: var(--table-font-size); --table-foot-border-width: 2px 0 0 0; - --table-foot-border-color: var(--colors-purrple-6); + --table-foot-border-color: var(--colors-purrple-400); } %tfoot-td-styling { @@ -50,7 +50,7 @@ a:visited, a:focus, a:hover { - color: #000000; + color: var(--colors-black); text-decoration: none; } } diff --git a/rocky/assets/css/themes/soft/manon/tabs.scss b/rocky/assets/css/themes/soft/manon/tabs.scss index 4220cd94a3c..d3537b92d40 100644 --- a/rocky/assets/css/themes/soft/manon/tabs.scss +++ b/rocky/assets/css/themes/soft/manon/tabs.scss @@ -4,23 +4,23 @@ --tabs-border-width: 0; /* Tab */ - --tabs-border-color: #cccccc; + --tabs-border-color: var(--colors-grey-200); --tabs-item-text-color: var(--application-base-text-color); /* Active tab */ --tabs-item-active-text-color: var(--application-base-text-color); - --tabs-item-active-border-color: var(--colors-purrple-6); - --tabs-item-active-hover-border-color: var(--colors-purrple-6); + --tabs-item-active-border-color: var(--colors-purrple-400); + --tabs-item-active-hover-border-color: var(--colors-purrple-400); --tabs-item-active-hover-text-color: var(--application-base-text-color); --tabs-item-active-border-width: 0 0 4px 0; /* Hover */ --tabs-item-hover-border-width: 0 0 4px 0; - --tabs-item-hover-border-color: #d4d4d4; + --tabs-item-hover-border-color: var(--colors-grey-200); } .tabs ul li > a:focus, ul.tabs li > a:focus { border: 0 0 4px 0; - border-color: var(--colors-purrple-6); + border-color: var(--colors-purrple-400); } diff --git a/rocky/assets/css/themes/soft/manon/text-colors.scss b/rocky/assets/css/themes/soft/manon/text-colors.scss index 0a475c5d926..34f688a1b71 100644 --- a/rocky/assets/css/themes/soft/manon/text-colors.scss +++ b/rocky/assets/css/themes/soft/manon/text-colors.scss @@ -1,6 +1,6 @@ /* Text colors */ :root { - --text-color-dark: #3b3b3b; - --text-color-light: #ffffff; + --text-color-dark: var(--colors-grey-900); + --text-color-light: var(--colors-white); } diff --git a/rocky/assets/css/themes/soft/manon/tile.scss b/rocky/assets/css/themes/soft/manon/tile.scss index 95c89bcf17f..11ac5c2ebb3 100644 --- a/rocky/assets/css/themes/soft/manon/tile.scss +++ b/rocky/assets/css/themes/soft/manon/tile.scss @@ -1,7 +1,7 @@ /* Tile - Variables */ :root { - --tile-background-color: #ffffff; + --tile-background-color: var(--colors-white); --tile-gap: var(--spacing-grid-100); --tile-font-size: var(--body-text-small-font-size); --tile-border-radius: 12px; diff --git a/rocky/assets/css/themes/soft/report.scss b/rocky/assets/css/themes/soft/report.scss index 09087584b89..54734a29af9 100644 --- a/rocky/assets/css/themes/soft/report.scss +++ b/rocky/assets/css/themes/soft/report.scss @@ -4,7 +4,7 @@ @import "fonts/fonts"; /* Styling sets. E.g color sets */ -@import "colors"; +@import "colors/colors"; @import "manon/body-text-set"; /* Branding colors */ diff --git a/rocky/assets/css/themes/soft/soft.scss b/rocky/assets/css/themes/soft/soft.scss index e92e817679d..ca54f20bc61 100644 --- a/rocky/assets/css/themes/soft/soft.scss +++ b/rocky/assets/css/themes/soft/soft.scss @@ -4,7 +4,8 @@ @import "fonts/fonts"; /* Styling sets. E.g color sets */ -@import "colors"; +@import "colors/colors"; +@import "colors/tag-colors"; @import "manon/body-text-set"; @import "manon/spot-large"; @import "manon/headings-base-set"; @@ -54,6 +55,7 @@ @import "manon/header-navigation-collapsible"; @import "manon/header-navigation-link"; @import "manon/header-navigation-link-active"; +@import "manon/notification-colors"; @import "manon/notification-block"; @import "manon/icon"; @import "manon/layout-column-4"; From 3be68aca62a99a5c66668a0128eeabb96c069bdc Mon Sep 17 00:00:00 2001 From: Jeroen Dekkers Date: Wed, 24 Jul 2024 14:09:20 +0200 Subject: [PATCH 032/112] Fix broken token auth when 2FA is enabled (#3260) Co-authored-by: ammar92 --- docs/source/manual/usermanual.rst | 4 ++-- rocky/rocky/middleware/auth_required.py | 3 ++- rocky/tests/test_api.py | 13 +++++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 rocky/tests/test_api.py diff --git a/docs/source/manual/usermanual.rst b/docs/source/manual/usermanual.rst index c3281f7d2ed..202d5b0d98e 100644 --- a/docs/source/manual/usermanual.rst +++ b/docs/source/manual/usermanual.rst @@ -246,8 +246,8 @@ After the CSV file has been uploaded the users receive a welcome email on their The OpenKAT team -Token authentication --------------------- +API token authentication +------------------------ Authentication tokens can be created in the admin interface (/admin). The token is created for an user account and will have the same permissions as the user. After creating a token it will display the newly created token once. You need to copy the token immediately, because the token are stored hashed in the database and won't be visible anymore. diff --git a/rocky/rocky/middleware/auth_required.py b/rocky/rocky/middleware/auth_required.py index 61f6c5f57ac..e0e97c32949 100644 --- a/rocky/rocky/middleware/auth_required.py +++ b/rocky/rocky/middleware/auth_required.py @@ -57,7 +57,6 @@ def middleware(request): # When 2fa is enabled, check if user is verified, otherwise redirect to 2fa setup page if ( settings.TWOFACTOR_ENABLED - and not request.user.is_verified() and not ( # check if path is not in excluded list request.path in excluded @@ -65,6 +64,8 @@ def middleware(request): # check if path starts with anything in excluded_prefix or any([request.path.startswith(prefix) for prefix in excluded_prefix]) ) + # This check should be after excluding /api because API users won't have `is_verified` + and not request.user.is_verified() ): return redirect(two_factor_setup_path) diff --git a/rocky/tests/test_api.py b/rocky/tests/test_api.py new file mode 100644 index 00000000000..5ff09ae06f0 --- /dev/null +++ b/rocky/tests/test_api.py @@ -0,0 +1,13 @@ +from account.models import AuthToken + + +# Regression test for https://github.com/minvws/nl-kat-coordination/issues/2872 +def test_api_2fa_enabled(client, settings, admin_user): + settings.TWOFACTOR_ENABLED = True + + token_object = AuthToken(name="Test", user=admin_user) + token = token_object.generate_new_token() + token_object.save() + + response = client.get("/api/v1/organization/", headers={"Authorization": f"Token {token}"}) + assert response.status_code == 200 From 7e333a3d66f064eb4a4f1d12c0945037e6e36066 Mon Sep 17 00:00:00 2001 From: Jan Klopper Date: Thu, 25 Jul 2024 10:53:01 +0200 Subject: [PATCH 033/112] Raise Timeout Exception when only timeouts from DNS server (#3264) Co-authored-by: Jeroen Dekkers --- boefjes/boefjes/plugins/kat_dns/main.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boefjes/boefjes/plugins/kat_dns/main.py b/boefjes/boefjes/plugins/kat_dns/main.py index 2db21a40685..e0b4199f1f2 100644 --- a/boefjes/boefjes/plugins/kat_dns/main.py +++ b/boefjes/boefjes/plugins/kat_dns/main.py @@ -28,6 +28,10 @@ } +class TimeoutException(Exception): + pass + + class ZoneNotFoundException(Exception): pass @@ -76,6 +80,8 @@ def run(boefje_meta: BoefjeMeta) -> list[tuple[set, bytes | str]]: "dmarc_response": get_email_security_records(resolver, hostname, "_dmarc"), "dkim_response": get_email_security_records(resolver, hostname, "_domainkey"), } + if not answers_formatted and results["dmarc_response"] == "Timeout" and results["dmarc_response"] == "Timeout": + raise TimeoutException("No answers from DNS-Server due to timeouts.") return [(set(), json.dumps(results))] From 7cb2c5e45d12b12c390afbf816410bef180a6de3 Mon Sep 17 00:00:00 2001 From: Jan Klopper Date: Mon, 29 Jul 2024 10:18:22 +0200 Subject: [PATCH 034/112] Refactor/ooi details (#3275) Co-authored-by: ammar92 --- rocky/rocky/views/mixins.py | 11 +++++++++-- rocky/rocky/views/ooi_detail.py | 10 +++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/rocky/rocky/views/mixins.py b/rocky/rocky/views/mixins.py index 3b7871380dd..2a21b60a5f2 100644 --- a/rocky/rocky/views/mixins.py +++ b/rocky/rocky/views/mixins.py @@ -3,6 +3,7 @@ from datetime import datetime, timezone from functools import cached_property from operator import attrgetter +from typing import TypedDict import structlog from account.mixins import OrganizationView @@ -47,6 +48,12 @@ class OriginData(BaseModel): params: dict[str, str] | None = None +class Origins(TypedDict): + declarations: list[OriginData] + observations: list[OriginData] + inferences: list[OriginData] + + class OOIAttributeError(AttributeError): pass @@ -99,11 +106,11 @@ def get_origins( self, reference: Reference, organization: Organization, - ) -> tuple[list[OriginData], list[OriginData], list[OriginData]]: + ) -> Origins: declarations: list[OriginData] = [] observations: list[OriginData] = [] inferences: list[OriginData] = [] - results = declarations, observations, inferences + results: Origins = {"declarations": declarations, "observations": observations, "inferences": inferences} try: origins = self.octopoes_api_connector.list_origins(self.observed_at, result=reference) diff --git a/rocky/rocky/views/ooi_detail.py b/rocky/rocky/views/ooi_detail.py index fac902817f7..fb086b97d28 100644 --- a/rocky/rocky/views/ooi_detail.py +++ b/rocky/rocky/views/ooi_detail.py @@ -93,10 +93,10 @@ def get_context_data(self, **kwargs): context["boefjes"] = [boefje for boefje in boefjes if boefje.scan_level.value <= max_level] context["ooi"] = self.ooi - declarations, observations, inferences = self.get_origins(self.ooi.reference, self.organization) + context.update(self.get_origins(self.ooi.reference, self.organization)) inference_params = self.octopoes_api_connector.list_origin_parameters( - {inference.origin.id for inference in inferences}, + {inference.origin.id for inference in context["inferences"]}, self.observed_at, ) inference_params_per_inference = defaultdict(list) @@ -104,13 +104,9 @@ def get_context_data(self, **kwargs): inference_params_per_inference[inference_param.origin_id].append(inference_param) inference_origin_params: list[tuple] = [] - for inference in inferences: + for inference in context["inferences"]: inference_origin_params.append((inference, inference_params_per_inference[inference.origin.id])) - context["declarations"] = declarations - - context["observations"] = observations - context["inferences"] = inferences context["inference_origin_params"] = inference_origin_params context["member"] = self.organization_member From 29f673af11a1636abd77d67c093d8c2cab928a49 Mon Sep 17 00:00:00 2001 From: Jeroen Dekkers Date: Mon, 29 Jul 2024 13:30:27 +0200 Subject: [PATCH 035/112] Workaround setuptools 72 removing test command (#3304) --- boefjes/Dockerfile | 4 ++-- rocky/Dockerfile | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/boefjes/Dockerfile b/boefjes/Dockerfile index 86c2df85133..b38ca57e307 100644 --- a/boefjes/Dockerfile +++ b/boefjes/Dockerfile @@ -20,10 +20,10 @@ RUN --mount=type=cache,target=/root/.cache \ pip install --upgrade pip \ && if [ "$ENVIRONMENT" = "dev" ]; \ then \ - grep -v git+https:// requirements-dev.txt | pip install -r /dev/stdin ; \ + grep -v git+https:// requirements-dev.txt | pip install -r /dev/stdin && \ grep git+https:// requirements-dev.txt | pip install -r /dev/stdin ; \ else \ - grep -v git+https:// requirements.txt | pip install -r /dev/stdin ;\ + grep -v git+https:// requirements.txt | pip install -r /dev/stdin && \ grep git+https:// requirements.txt | pip install -r /dev/stdin ; \ fi diff --git a/rocky/Dockerfile b/rocky/Dockerfile index 9b7bd80e504..2a967d4e2ed 100644 --- a/rocky/Dockerfile +++ b/rocky/Dockerfile @@ -39,15 +39,19 @@ ARG ENVIRONMENT # requirements separately COPY rocky/requirements*.txt . RUN --mount=type=cache,target=/root/.cache \ - pip install --upgrade pip \ + # Workaround for https://github.com/pypa/setuptools/issues/4519 \ + echo "setuptools<72" > /tmp/constraints.txt \ + && export PIP_CONSTRAINT=/tmp/constraints.txt \ + && pip install --upgrade pip \ && if [ "$ENVIRONMENT" = "dev" ]; \ then \ - grep -v git+https:// requirements-dev.txt | pip install -r /dev/stdin ; \ + grep -v git+https:// requirements-dev.txt | pip install -r /dev/stdin && \ grep git+https:// requirements-dev.txt | pip install -r /dev/stdin ; \ else \ - grep -v git+https:// requirements.txt | pip install -r /dev/stdin ;\ + grep -v git+https:// requirements.txt | pip install -r /dev/stdin && \ grep git+https:// requirements.txt | pip install -r /dev/stdin ; \ - fi + fi \ + && rm /tmp/constraints.txt FROM dev From 2ef5b631808d07bf75a69faec4b33483cb777fac Mon Sep 17 00:00:00 2001 From: Jan Klopper Date: Mon, 29 Jul 2024 14:03:24 +0200 Subject: [PATCH 036/112] Feat/human readable dates (#3231) Co-authored-by: Ammar Co-authored-by: Jeroen Dekkers --- rocky/rocky/locale/django.pot | 7 +++- rocky/rocky/settings.py | 1 + .../oois/ooi_detail_origins_observations.html | 13 ++++++-- rocky/rocky/views/mixins.py | 33 ++++++++++++++++--- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 6f3f1d846fc..f40ce9d289f 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-16 11:52+0000\n" +"POT-Creation-Date: 2024-07-17 11:40+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -4643,6 +4643,7 @@ msgid "warning" msgstr "" #: rocky/templates/dashboard_redteam.html +#: rocky/templates/oois/ooi_detail_origins_observations.html #: rocky/templates/partials/notifications_block.html #: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html msgid "Warning:" @@ -5132,6 +5133,10 @@ msgstr "" msgid "No Raw file could be found, this might point to an error in OpenKAT" msgstr "" +#: rocky/templates/oois/ooi_detail_origins_observations.html +msgid "Warning" +msgstr "" + #: rocky/templates/oois/ooi_edit.html #, python-format msgid "Edit %(type)s: %(ooi_human_readable)s" diff --git a/rocky/rocky/settings.py b/rocky/rocky/settings.py index b23194ea74e..fa13133df90 100644 --- a/rocky/rocky/settings.py +++ b/rocky/rocky/settings.py @@ -151,6 +151,7 @@ "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", + "django.contrib.humanize", "django.forms", "django_components", "django_components.safer_staticfiles", diff --git a/rocky/rocky/templates/oois/ooi_detail_origins_observations.html b/rocky/rocky/templates/oois/ooi_detail_origins_observations.html index 32ba8628eae..c4b4e60cc05 100644 --- a/rocky/rocky/templates/oois/ooi_detail_origins_observations.html +++ b/rocky/rocky/templates/oois/ooi_detail_origins_observations.html @@ -1,4 +1,5 @@ {% load i18n %} +{% load humanize %} {% load ooi_extra %} {% spaceless %} @@ -17,10 +18,11 @@

{% translate "Last observed by" %}

{% for observation in observations %} - + {% if observation.boefje.id %} - {{ observation.boefje.name }} + {{ observation.boefje.name }} {% else %} {% translate "The boefje has since been deleted or disabled." %} {% endif %} @@ -35,7 +37,12 @@

{% translate "Last observed by" %}

{% translate "No Raw file could be found, this might point to an error in OpenKAT" %} {% endif %} - {{ observation.normalizer.raw_data.boefje_meta.ended_at }} + + {% if observation.is_old %} + {% translate "Warning:" %} + {% endif %} + {{ observation.normalizer.raw_data.boefje_meta.ended_at|naturaltime }} + {% endfor %} diff --git a/rocky/rocky/views/mixins.py b/rocky/rocky/views/mixins.py index 2a21b60a5f2..42f97f006ce 100644 --- a/rocky/rocky/views/mixins.py +++ b/rocky/rocky/views/mixins.py @@ -1,6 +1,6 @@ from collections.abc import Sequence from dataclasses import dataclass -from datetime import datetime, timezone +from datetime import datetime, timedelta, timezone from functools import cached_property from operator import attrgetter from typing import TypedDict @@ -33,6 +33,8 @@ logger = structlog.get_logger(__name__) +ORIGIN_MAX_AGE = timedelta(days=2) + @dataclass class HydratedFinding: @@ -47,6 +49,21 @@ class OriginData(BaseModel): boefje: Boefje | None = None params: dict[str, str] | None = None + @property + def is_old(self) -> bool: + return self.is_older_than(ORIGIN_MAX_AGE) + + def is_older_than(self, time_delta: timedelta) -> bool: + if not self.normalizer: + return False + + if (observation_date := self.normalizer.get("raw_data", {}).get("boefje_meta", {}).get("ended_at")) is None: + raise ValueError("Observation date is missing in normalizer meta") + + observation_date = observation_date.replace(tzinfo=timezone.utc) + + return observation_date < datetime.now(timezone.utc) - time_delta + class Origins(TypedDict): declarations: list[OriginData] @@ -96,11 +113,12 @@ def get_single_ooi(self, pk: str) -> OOI: try: ref = Reference.from_str(pk) ooi = self.octopoes_api_connector.get(ref, valid_time=self.observed_at) + + return ooi except Exception as e: # TODO: raise the exception but let the handling be done by the method that implements "get_single_ooi" self.handle_connector_exception(e) - - return ooi + raise def get_origins( self, @@ -149,7 +167,10 @@ def get_origins( e, ) else: - boefje_id = normalizer_data["raw_data"]["boefje_meta"]["boefje"]["id"] + boefje_meta = normalizer_data["raw_data"]["boefje_meta"] + boefje_id = boefje_meta["boefje"]["id"] + if boefje_meta.get("ended_at"): + boefje_meta["ended_at"] = datetime.strptime(boefje_meta["ended_at"], "%Y-%m-%dT%H:%M:%S.%fZ") origin.normalizer = normalizer_data try: origin.boefje = katalogus.get_plugin(boefje_id) @@ -290,7 +311,9 @@ def __getitem__(self, key: int | slice) -> list[HydratedFinding]: continue hydrated_findings.append( HydratedFinding( - finding=finding, finding_type=objects[finding.finding_type], ooi=objects[finding.ooi] + finding=finding, + finding_type=objects[finding.finding_type], + ooi=objects[finding.ooi], ) ) return hydrated_findings From 324692c83e0b4801cd8e59a02d7df1ec9578378a Mon Sep 17 00:00:00 2001 From: originalsouth Date: Tue, 30 Jul 2024 22:41:54 +0200 Subject: [PATCH 037/112] Record the user who last changed the Scan Profile (#3296) Co-authored-by: Jan Klopper Co-authored-by: Jeroen Dekkers --- octopoes/octopoes/models/__init__.py | 1 + octopoes/tests/test_api.py | 1 + octopoes/tests/test_event_manager.py | 19 +++++++++++++------ rocky/account/mixins.py | 7 +++++-- rocky/rocky/locale/django.pot | 7 ++++++- .../scan_profiles/scan_profile_detail.html | 14 +++++++++++++- rocky/rocky/views/scan_profile.py | 6 ++++++ 7 files changed, 45 insertions(+), 10 deletions(-) diff --git a/octopoes/octopoes/models/__init__.py b/octopoes/octopoes/models/__init__.py index 02c970eb36e..4418150396b 100644 --- a/octopoes/octopoes/models/__init__.py +++ b/octopoes/octopoes/models/__init__.py @@ -77,6 +77,7 @@ class ScanProfileBase(BaseModel): scan_profile_type: str reference: Reference level: ScanLevel + user_id: int | None = None def __eq__(self, other): if isinstance(other, ScanProfileBase) and self.__class__ == other.__class__: diff --git a/octopoes/tests/test_api.py b/octopoes/tests/test_api.py index b4d8f0751fb..c436a5ecba4 100644 --- a/octopoes/tests/test_api.py +++ b/octopoes/tests/test_api.py @@ -104,6 +104,7 @@ def test_get_scan_profiles(httpx_mock, patch_pika, valid_time): "level": 0, "reference": "Hostname|internet|mispo.es", "scan_profile_type": "empty", + "user_id": None, } ] diff --git a/octopoes/tests/test_event_manager.py b/octopoes/tests/test_event_manager.py index 133aca06ef7..8c93b1d29e0 100644 --- a/octopoes/tests/test_event_manager.py +++ b/octopoes/tests/test_event_manager.py @@ -66,7 +66,7 @@ def test_event_manager_create_empty_scan_profile(mocker, empty_scan_profile): "valid_time": "2023-01-01T00:00:00", "client": "test", "old_data": None, - "new_data": {"scan_profile_type": "empty", "reference": "test_reference", "level": 0}, + "new_data": {"scan_profile_type": "empty", "reference": "test_reference", "level": 0, "user_id": None}, "reference": "test_reference", }, ), @@ -79,7 +79,7 @@ def test_event_manager_create_empty_scan_profile(mocker, empty_scan_profile): "test__scan_profile_mutations", b'{"operation":"create","primary_key":"test_reference","value":{"primary_key":"test_reference",' b'"object_type":"test_reference","scan_profile":{"scan_profile_type":"empty","reference":"test_reference",' - b'"level":0}}}', + b'"level":0,"user_id":null}}}', properties=pika.BasicProperties(delivery_mode=pika.DeliveryMode.Persistent), ) @@ -108,7 +108,12 @@ def test_event_manager_create_declared_scan_profile(mocker, declared_scan_profil "valid_time": "2023-01-01T00:00:00", "client": "test", "old_data": None, - "new_data": {"scan_profile_type": "declared", "reference": "test_reference", "level": 2}, + "new_data": { + "scan_profile_type": "declared", + "reference": "test_reference", + "level": 2, + "user_id": None, + }, "reference": "test_reference", }, ), @@ -122,7 +127,8 @@ def test_event_manager_create_declared_scan_profile(mocker, declared_scan_profil "", "test__scan_profile_increments", b'{"primary_key": "test_reference", "object_type": "test_reference",' - b'"scan_profile": {"scan_profile_type": "declared", "reference": "test_reference", "level": 2}}', + b'"scan_profile": {"scan_profile_type": "declared", "reference": "test_reference",\ + "level": 2, "user_id": None}}', properties=pika.BasicProperties(delivery_mode=pika.DeliveryMode.Persistent), ), mocker.call( @@ -131,7 +137,8 @@ def test_event_manager_create_declared_scan_profile(mocker, declared_scan_profil b'{"operation": "create", "primary_key": "test_reference", ' b'"value": {"primary_key": "test_reference", ' b'"object_type": "test_reference", ' - b'"scan_profile": {"scan_profile_type": "declared", "reference": "test_reference", "level": 2}}}', + b'"scan_profile": {"scan_profile_type": "declared", "reference": "test_reference",\ + "level": 2, "user_id": None}}}', properties=pika.BasicProperties(delivery_mode=pika.DeliveryMode.Persistent), ), ) @@ -160,7 +167,7 @@ def test_event_manager_delete_empty_scan_profile(mocker, empty_scan_profile): "operation_type": "delete", "valid_time": "2023-01-01T00:00:00", "client": "test", - "old_data": {"scan_profile_type": "empty", "reference": "test_reference", "level": 0}, + "old_data": {"scan_profile_type": "empty", "reference": "test_reference", "level": 0, "user_id": None}, "new_data": None, "reference": "test_reference", }, diff --git a/rocky/account/mixins.py b/rocky/account/mixins.py index 3c01410ff43..fca1182b397 100644 --- a/rocky/account/mixins.py +++ b/rocky/account/mixins.py @@ -136,7 +136,7 @@ def verify_raise_clearance_level(self, level: int) -> bool: def raise_clearance_level(self, ooi_reference: Reference, level: int) -> bool: self.verify_raise_clearance_level(level) self.octopoes_api_connector.save_scan_profile( - DeclaredScanProfile(reference=ooi_reference, level=ScanLevel(level)), + DeclaredScanProfile(reference=ooi_reference, level=ScanLevel(level), user_id=self.request.user.id), datetime.now(timezone.utc), ) @@ -145,7 +145,10 @@ def raise_clearance_level(self, ooi_reference: Reference, level: int) -> bool: def raise_clearance_levels(self, ooi_references: list[Reference], level: int) -> bool: self.verify_raise_clearance_level(level) self.octopoes_api_connector.save_many_scan_profiles( - [DeclaredScanProfile(reference=reference, level=ScanLevel(level)) for reference in ooi_references], + [ + DeclaredScanProfile(reference=reference, level=ScanLevel(level), user_id=self.request.user.id) + for reference in ooi_references + ], datetime.now(timezone.utc), ) diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index f40ce9d289f..818883a1ffe 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-17 11:40+0000\n" +"POT-Creation-Date: 2024-07-29 14:05+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -957,6 +957,7 @@ msgstr "" #: katalogus/templates/partials/plugin_settings_required.html #: katalogus/templates/plugin_settings_list.html #: rocky/templates/findings/finding_add.html +#: rocky/templates/partials/ooi_detail_related_object.html #: rocky/templates/partials/ooi_list_toolbar.html msgid "Add" msgstr "" @@ -5865,6 +5866,10 @@ msgstr "" msgid "Current clearance level" msgstr "" +#: rocky/templates/scan_profiles/scan_profile_detail.html +msgid "Inactive" +msgstr "" + #: rocky/templates/scan_profiles/scan_profile_detail.html msgid "Declared:" msgstr "" diff --git a/rocky/rocky/templates/scan_profiles/scan_profile_detail.html b/rocky/rocky/templates/scan_profiles/scan_profile_detail.html index 5c80da19e7a..e9487403bff 100644 --- a/rocky/rocky/templates/scan_profiles/scan_profile_detail.html +++ b/rocky/rocky/templates/scan_profiles/scan_profile_detail.html @@ -12,7 +12,19 @@ {% include "partials/ooi_head.html" with ooi=ooi view="scan_profile_detail" %}

{% translate "Current clearance level" %}

-

{{ ooi.scan_profile.human_readable }}, {{ ooi.scan_profile.scan_profile_type }}

+ {% if scan_profile_user %} +

+ {{ ooi.scan_profile.human_readable }}, {{ ooi.scan_profile.scan_profile_type }} (by user " + {% if not scan_profile_user.is_active %} + {{ scan_profile_user }} + {% else %} + {{ scan_profile_user }} + {% endif %} + ") +

+ {% else %} +

{{ ooi.scan_profile.human_readable }}, {{ ooi.scan_profile.scan_profile_type }}

+ {% endif %} {% if ooi.scan_profile.scan_profile_type == "declared" %}

{% translate "Declared:" %}{% blocktranslate with scan_level=ooi.scan_profile.human_readable %} diff --git a/rocky/rocky/views/scan_profile.py b/rocky/rocky/views/scan_profile.py index 0be16e7e67b..89687ed240e 100644 --- a/rocky/rocky/views/scan_profile.py +++ b/rocky/rocky/views/scan_profile.py @@ -2,6 +2,7 @@ from typing import Any from django.contrib import messages +from django.contrib.auth import get_user_model from django.shortcuts import redirect from django.utils.translation import gettext_lazy as _ from django.views.generic import FormView @@ -19,6 +20,11 @@ class ScanProfileDetailView(FormView, OOIDetailView): def get_context_data(self, **kwargs) -> dict[str, Any]: context = super().get_context_data(**kwargs) context["mandatory_fields"] = get_mandatory_fields(self.request) + if self.ooi.scan_profile and self.ooi.scan_profile.user_id: + try: + context["scan_profile_user"] = get_user_model().objects.get(id=self.ooi.scan_profile.user_id) + except get_user_model().DoesNotExist: + pass return context def get_initial(self): From 57b2bf00e78e876880b081a7622b3debc9ac38ad Mon Sep 17 00:00:00 2001 From: Jan Klopper Date: Wed, 31 Jul 2024 11:26:26 +0200 Subject: [PATCH 038/112] Catch valid DNSSEC signed SERVFAIL answers (#3271) Co-authored-by: ammar92 Co-authored-by: Jeroen Dekkers --- .pre-commit-config.yaml | 2 +- boefjes/boefjes/plugins/kat_dns/main.py | 14 ++++++++++++++ boefjes/boefjes/plugins/kat_dns/normalize.py | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 447290ba06c..0feca0fec5a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -108,7 +108,7 @@ repos: hooks: - id: codespell additional_dependencies: ["tomli"] - args: [-L, lama] + args: ["-L", "lama", "--ignore-regex", ".{1024}|.*codespell-ignore.*"] exclude: | (?x)( \.po$ | diff --git a/boefjes/boefjes/plugins/kat_dns/main.py b/boefjes/boefjes/plugins/kat_dns/main.py index e0b4199f1f2..ce01870911f 100644 --- a/boefjes/boefjes/plugins/kat_dns/main.py +++ b/boefjes/boefjes/plugins/kat_dns/main.py @@ -6,6 +6,7 @@ from os import getenv import dns.resolver +from dns.edns import EDEOption from dns.name import Name from dns.resolver import Answer @@ -52,6 +53,9 @@ def run(boefje_meta: BoefjeMeta) -> list[tuple[set, bytes | str]]: requested_dns_name = dns.name.from_text(hostname) resolver = dns.resolver.Resolver() + # https://dnspython.readthedocs.io/en/stable/_modules/dns/edns.html + # enable EDE to get the DNSSEC Bogus return values if the server supports it # codespell-ignore + resolver.use_edns(options=[EDEOption(15)]) nameserver = getenv("REMOTE_NS", "1.1.1.1") resolver.nameservers = [nameserver] @@ -102,6 +106,16 @@ def get_email_security_records(resolver: dns.resolver.Resolver, hostname: str, r try: answer = resolver.resolve(f"{record_subdomain}.{hostname}", "TXT", raise_on_no_answer=False) return answer.response.to_text() + except dns.resolver.NoNameservers as error: + # no servers responded happily, we'll check the response from the first + # https://dnspython.readthedocs.io/en/latest/_modules/dns/rcode.html + # https://www.rfc-editor.org/rfc/rfc8914#name-extended-dns-error-code-6-d + firsterror = error.kwargs["errors"][0] + if firsterror[3] == "SERVFAIL": + edeerror = int(firsterror[4].options[0].code) + if edeerror in (1, 2, 5, 6, 7, 8, 9, 10, 11, 12): # DNSSEC error codes defined in RFC 8914 + return "DNSSECFAIL" # returned when the resolver indicates a DNSSEC failure. + raise # Not dnssec related, unhandled, raise. except dns.resolver.NXDOMAIN: return "NXDOMAIN" except dns.resolver.Timeout: diff --git a/boefjes/boefjes/plugins/kat_dns/normalize.py b/boefjes/boefjes/plugins/kat_dns/normalize.py index ab8dda9a799..5dd3912b268 100644 --- a/boefjes/boefjes/plugins/kat_dns/normalize.py +++ b/boefjes/boefjes/plugins/kat_dns/normalize.py @@ -170,7 +170,7 @@ def register_record(record: DNSRecord) -> DNSRecord: # DKIM dkim_results = results["dkim_response"] - if dkim_results not in ["NXDOMAIN", "Timeout"] and dkim_results.split("\n")[2] == "rcode NOERROR": + if dkim_results not in ["NXDOMAIN", "Timeout", "DNSSECFAIL"] and dkim_results.split("\n")[2] == "rcode NOERROR": yield DKIMExists( hostname=input_hostname.reference, ) From eefc519c9b40e7b5ce826d91e24242a8c8c5e608 Mon Sep 17 00:00:00 2001 From: Madelon Dohmen <99282220+madelondohmen@users.noreply.github.com> Date: Wed, 31 Jul 2024 17:02:26 +0200 Subject: [PATCH 039/112] Give report a name (#3258) Co-authored-by: Noam Blitz Co-authored-by: Rieven Co-authored-by: Donny Peeters Co-authored-by: TwistMeister Co-authored-by: Jeroen Dekkers Co-authored-by: Heleen Co-authored-by: ammar92 Co-authored-by: Jan Klopper --- rocky/assets/js/renameReports.js | 35 +++++ rocky/components/modal/script.js | 52 ++++++- rocky/components/modal/template.html | 4 +- .../templates/partials/boefje_tile.html | 4 +- rocky/onboarding/views.py | 2 +- rocky/poetry.lock | 6 +- rocky/pyproject.toml | 2 +- .../introduction.html | 2 +- .../aggregate_report/export_setup.html | 23 +++ rocky/reports/templates/generate_report.html | 2 +- .../generate_report/export_setup.html | 23 +++ .../templates/generate_report_pdf.html | 2 +- .../partials/export_report_settings.html | 124 +++++++++++++++ .../partials/generate_report_sidemenu.html | 2 +- .../templates/partials/report_header.html | 2 +- .../templates/partials/report_setup_scan.html | 19 ++- .../report_overview/report_history_table.html | 4 +- .../report_overview/subreports_table.html | 7 +- .../summary/report_asset_overview.html | 2 +- rocky/reports/urls.py | 8 + rocky/reports/views/aggregate_report.py | 48 ++++-- rocky/reports/views/base.py | 11 +- rocky/reports/views/generate_report.py | 87 +++++++++-- rocky/reports/views/multi_report.py | 33 +++- rocky/reports/views/view_helpers.py | 19 +++ rocky/requirements-dev.txt | 6 +- rocky/requirements.txt | 6 +- rocky/rocky/locale/django.pot | 147 ++++++++++++++---- rocky/tests/conftest.py | 21 +++ rocky/tests/reports/test_history_report.py | 4 +- 30 files changed, 617 insertions(+), 90 deletions(-) create mode 100644 rocky/assets/js/renameReports.js create mode 100644 rocky/reports/templates/aggregate_report/export_setup.html create mode 100644 rocky/reports/templates/generate_report/export_setup.html create mode 100644 rocky/reports/templates/partials/export_report_settings.html diff --git a/rocky/assets/js/renameReports.js b/rocky/assets/js/renameReports.js new file mode 100644 index 00000000000..2bef5154321 --- /dev/null +++ b/rocky/assets/js/renameReports.js @@ -0,0 +1,35 @@ +import { onDomReady } from "../js/imports/utils.js"; + +onDomReady(initConfirmButtons); + +export function initConfirmButtons(element) { + let root = element || document; + let confirm_buttons = root.querySelectorAll(".confirm-button"); + + confirm_buttons.forEach((button) => initClickHandlers(button)); +} + +function initClickHandlers(button) { + button.addEventListener("click", function (event) { + const target = event.target.closest("dialog"); + + editReportName(target); + }); +} + +function editReportName(target) { + const old_name_id = target.querySelector(".old-report-name").value; + const reference_date = target.querySelector(".reference-date").value; + const update_target_input = document.getElementById(old_name_id); + const update_target_text = document.getElementById("text-" + old_name_id); + + let new_name = target.querySelector(".new-report-name").value; + + if (new_name) { + if (reference_date) { + new_name += " (" + reference_date + ")"; + } + update_target_input.setAttribute("value", new_name); + update_target_text.textContent = new_name; + } +} diff --git a/rocky/components/modal/script.js b/rocky/components/modal/script.js index 43add51d2d0..c8a8153558a 100644 --- a/rocky/components/modal/script.js +++ b/rocky/components/modal/script.js @@ -10,19 +10,67 @@ export function initDialogs(element) { } export function initDialog(modal) { + let input_elements = []; + modal.querySelector(".modal-trigger").addEventListener("click", (event) => { + // Get and clone input elements to be able to "reset" them on "cancel". + input_elements = modal.querySelectorAll("input, textarea"); + + // Clone nodeList input_elements to simple array, instead of making a pointer reference. + input_elements.forEach((element) => { + element.defaultvalue = element.value; + }); + // Used ".closest" instead of ".parentNode" to make sure we stay flexible in terms of // HTML-structure when implementing the trigger. event.target.closest(".modal-wrapper").querySelector("dialog").showModal(); }); modal.querySelector("dialog").addEventListener("click", (event) => { + // The actual handling (like posting) of the input values should be done when implementing the component. + if (event.target.classList.contains("confirm-modal-button")) { + if (input_elements) { + // Closing is only allowed when the inputs are 'valid'. + if (checkValidity(input_elements)) { + event.target + .closest(".modal-wrapper") + .querySelector("dialog") + .close(); + } + return; + } + } // event.target.nodeName === 'DIALOG' is needed to check if the ::backdrop is clicked. if ( - event.target.nodeName === "DIALOG" || - event.target.classList.contains("close-modal-button") + event.target.classList.contains("close-modal-button") || + event.target.nodeName === "DIALOG" ) { + // When canceling or closing using the 'x' remove the "error" styles. + input_elements.forEach((element) => { + element.classList.remove("error"); + }); + + // When canceling or closing the modal, the inputs get reset to their initial value. + input_elements.forEach((element) => { + element.value = element.defaultvalue; + }); + event.target.closest(".modal-wrapper").querySelector("dialog").close(); } }); } + +export function checkValidity(elements) { + let valid = true; + + elements.forEach((element) => { + if (!element.checkValidity()) { + valid = false; + element.classList.add("error"); + } else { + element.classList.remove("error"); + } + }); + + return valid; +} diff --git a/rocky/components/modal/template.html b/rocky/components/modal/template.html index 226c280a735..7e1235532f2 100644 --- a/rocky/components/modal/template.html +++ b/rocky/components/modal/template.html @@ -13,14 +13,12 @@

{% slot "header" %}{% endslot %}

-
-
{% slot "content" %}{% endslot %}
- - + {% include "forms/report_form_fields.html" with selected_oois=None %} {% if "all" not in selected_oois %}{% endif %} diff --git a/rocky/reports/templates/partials/report_setup_scan.html b/rocky/reports/templates/partials/report_setup_scan.html index de69738d1f3..fb664a92071 100644 --- a/rocky/reports/templates/partials/report_setup_scan.html +++ b/rocky/reports/templates/partials/report_setup_scan.html @@ -6,9 +6,7 @@

{% translate "Configuration" %}

{% translate "Set up the required plugins for this report." %}

{% if selected_oois and selected_report_types %} - - {% translate "Change selection" %} - + {% include "partials/return_button.html" with btn_text="Change selection" %} {% include "partials/plugin_overview_table.html" %}

{% translate "Plugins" %}

@@ -79,7 +77,7 @@

{% translate "Suggested plugins" %}

{% for optional_plugin in plugins.optional|dictsort:"enabled" %} {% if optional_plugin not in plugins.required %} - {% include "partials/plugin_tile.html" with plugin=optional_plugin form_id="generate_report" show_report_types="yes" plugin_report_types=plugin_data.plugin_report_types %} + {% include "partials/plugin_tile.html" with plugin=optional_plugin form_id="continue-to-configurationt" show_report_types="yes" plugin_report_types=plugin_data.plugin_report_types %} {% endif %} {% endfor %} @@ -94,21 +92,18 @@

{% translate "Suggested plugins" %}

{% endif %} + {% csrf_token %} {% include "forms/report_form_fields.html" %} - {% for report_type in selected_report_types %} - - {% endfor %} {% else %} - - {% translate "Go back" %} - + {% include "partials/return_button.html" with btn_text="Go back" %} + {% endif %}
diff --git a/rocky/reports/templates/partials/report_types_selection.html b/rocky/reports/templates/partials/report_types_selection.html index 74ceae9eedd..3c401605847 100644 --- a/rocky/reports/templates/partials/report_types_selection.html +++ b/rocky/reports/templates/partials/report_types_selection.html @@ -13,10 +13,9 @@

{% translate "Choose report types" %}

improvements are needed. {% endblocktranslate %}

- {% if not oois %} - - {% translate "Go back" %} - + {% if not selected_oois %} + {% include "partials/return_button.html" with btn_text="Go back" %} + {% else %}

{% blocktranslate trimmed count counter=oois|length %} @@ -25,21 +24,28 @@

Selected objects ({{ total_oois }}) {% endblocktranslate %}

- {% if 'all' in selected_oois %} -

- {% blocktranslate trimmed count counter=oois|length %} - You have selected {{ total_oois }} object in previous step. - {% plural %} - You have selected {{ total_oois }} objects in previous step. - {% endblocktranslate %} -

- {% else %} +

+ {% blocktranslate trimmed count counter=oois|length %} + You have selected {{ total_oois }} object in previous step. + {% plural %} + You have selected {{ total_oois }} objects in previous step. + {% endblocktranslate %} +

+ {% if not "all" in selected_oois %} {% include "summary/ooi_selection.html" %} {% endif %} - - {% translate "Change selection" %} - +
+ {% csrf_token %} + {% include "forms/report_form_fields.html" %} + + +
{% if available_report_types_aggregate %}

{% translate "Available report types" %} ({{ count_available_report_types_aggregate }})

{% else %} @@ -48,8 +54,9 @@

{% translate "Available report types" %} ({{ available_report_types|length }

{% translate "All report types that are available for your selection." %}

{% translate "Toggle all report types" %}
+ {% csrf_token %} {% include "forms/report_form_fields.html" %}
diff --git a/rocky/reports/templates/partials/report_types_tiles.html b/rocky/reports/templates/partials/report_types_tiles.html index c74c1566dd1..c757622d991 100644 --- a/rocky/reports/templates/partials/report_types_tiles.html +++ b/rocky/reports/templates/partials/report_types_tiles.html @@ -5,7 +5,7 @@ + {% if report_type.id in selected_report_types %}checked{% endif %} />

{{ report_type.description }}

diff --git a/rocky/reports/templates/partials/report_types_tiles_required_optional.html b/rocky/reports/templates/partials/report_types_tiles_required_optional.html index 833b8358a39..0a7581b6e3f 100644 --- a/rocky/reports/templates/partials/report_types_tiles_required_optional.html +++ b/rocky/reports/templates/partials/report_types_tiles_required_optional.html @@ -7,7 +7,7 @@ + {% if report_type.id in selected_report_types %}checked{% endif %} /> {% else %} {% endif %} diff --git a/rocky/reports/templates/partials/return_button.html b/rocky/reports/templates/partials/return_button.html new file mode 100644 index 00000000000..ed038f61bd1 --- /dev/null +++ b/rocky/reports/templates/partials/return_button.html @@ -0,0 +1,14 @@ +{% load i18n %} + + + {% csrf_token %} + {% include "forms/report_form_fields.html" %} + + +
diff --git a/rocky/reports/views/aggregate_report.py b/rocky/reports/views/aggregate_report.py index 1bdf683e2df..2b7c82a37e3 100644 --- a/rocky/reports/views/aggregate_report.py +++ b/rocky/reports/views/aggregate_report.py @@ -1,4 +1,3 @@ -from collections.abc import Sequence from datetime import datetime, timezone from typing import Any @@ -8,21 +7,19 @@ from django.urls import reverse from django.utils.http import urlencode from django.utils.translation import gettext_lazy as _ -from django.views.generic import TemplateView -from octopoes.models import ScanProfileType -from octopoes.models.ooi.reports import Report as ReportOOI -from reports.report_types.aggregate_organisation_report.report import AggregateOrganisationReport, aggregate_reports -from reports.report_types.definitions import Report +from reports.report_types.aggregate_organisation_report.report import AggregateOrganisationReport +from reports.report_types.definitions import AggregateReport, MultiReport, Report from reports.report_types.helpers import get_ooi_types_from_aggregate_report, get_report_types_from_aggregate_report from reports.views.base import ( REPORTS_PRE_SELECTION, + OOISelectionView, ReportBreadcrumbs, - ReportOOIView, ReportPluginView, - ReportTypeView, + ReportTypeSelectionView, get_selection, ) +from reports.views.mixins import SaveAggregateReportMixin from reports.views.view_helpers import AggregateReportStepsMixin from rocky.views.ooi_view import BaseOOIListView @@ -74,10 +71,7 @@ def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: class OOISelectionAggregateReportView( - AggregateReportStepsMixin, - BreadcrumbsAggregateReportView, - ReportOOIView, - BaseOOIListView, + AggregateReportStepsMixin, BreadcrumbsAggregateReportView, BaseOOIListView, OOISelectionView ): """ Select Objects for the 'Aggregate Report' flow. @@ -88,9 +82,13 @@ class OOISelectionAggregateReportView( current_step = 1 ooi_types = get_ooi_types_from_aggregate_report(AggregateOrganisationReport) + def post(self, request, *args, **kwargs): + if not self.selected_oois: + messages.error(request, self.NONE_OOI_SELECTION_MESSAGE) + return self.get(request, *args, **kwargs) + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context.update(self.get_ooi_filter_forms(self.ooi_types)) context["channel"] = "aggregate_report" return context @@ -98,9 +96,8 @@ def get_context_data(self, **kwargs): class ReportTypesSelectionAggregateReportView( AggregateReportStepsMixin, BreadcrumbsAggregateReportView, - ReportOOIView, - ReportTypeView, - TemplateView, + OOISelectionView, + ReportTypeSelectionView, ): """ Shows all possible report types from a list of Objects. @@ -118,10 +115,11 @@ def setup(self, request, *args, **kwargs): get_report_types_from_aggregate_report(AggregateOrganisationReport) ) - def get(self, request, *args, **kwargs): + def post(self, request, *args, **kwargs): if not self.selected_oois: - messages.error(self.request, _("Select at least one OOI to proceed.")) - return super().get(request, *args, **kwargs) + messages.error(request, self.NONE_OOI_SELECTION_MESSAGE) + return redirect(self.get_previous()) + return self.get(request, *args, **kwargs) def get_report_types_for_aggregate_report( self, reports_dict: dict[str, set[type[Report]]] @@ -141,74 +139,6 @@ def get_context_data(self, **kwargs): return context -class SaveAggregateReportMixin(ReportPluginView): - def save_report(self, report_names: list) -> ReportOOI: - input_oois = self.get_oois() - - aggregate_report, post_processed_data, report_data, report_errors = aggregate_reports( - self.octopoes_api_connector, - input_oois, - self.selected_report_types, - self.observed_at, - self.organization.code, - ) - - # If OOI could not be found or the date is incorrect, it will be shown to the user as a message error - if report_errors: - report_types = ", ".join(set(report_errors)) - date = self.observed_at.date() - error_message = _("No data could be found for %(report_types). Object(s) did not exist on %(date)s.") % { - "report_types": report_types, - "date": date, - } - messages.add_message(self.request, messages.ERROR, error_message) - - observed_at = self.get_observed_at() - - post_processed_data["plugins"] = self.get_plugin_data_for_saving() - post_processed_data["oois"] = [] - for input_ooi in input_oois: - post_processed_data["oois"].append( - { - "name": input_ooi.human_readable, - "type": input_ooi.object_type, - "scan_profile_level": input_ooi.scan_profile.level.value if input_ooi.scan_profile else 0, - "scan_profile_type": ( - input_ooi.scan_profile.scan_profile_type if input_ooi.scan_profile else ScanProfileType.EMPTY - ), - } - ) - - post_processed_data["report_types"] = [] - for report_type in self.report_types: - post_processed_data["report_types"].append( - { - "name": str(report_type.name), - "description": str(report_type.description), - "label_style": report_type.label_style, - } - ) - - # Create the report - report_data_raw_id = self.save_report_raw(data=post_processed_data) - report_ooi = self.save_report_ooi( - report_data_raw_id=report_data_raw_id, - report_type=type(aggregate_report), - input_oois=[ooi.primary_key for ooi in input_oois], - parent=None, - has_parent=False, - observed_at=observed_at, - name=report_names[0][1], - ) - - # Save the child reports to bytes - for ooi, types in report_data.items(): - for report_type, data in types.items(): - self.save_report_raw(data=data) - - return report_ooi - - class SetupScanAggregateReportView( SaveAggregateReportMixin, AggregateReportStepsMixin, BreadcrumbsAggregateReportView, ReportPluginView ): @@ -220,18 +150,11 @@ class SetupScanAggregateReportView( breadcrumbs_step = 5 current_step = 3 - def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: + def post(self, request, *args, **kwargs): if not self.selected_report_types: - messages.error(self.request, _("Select at least one report type to proceed.")) - return redirect( - reverse("aggregate_report_select_report_types", kwargs=self.get_kwargs()) + get_selection(self.request) - ) - if not self.report_has_required_plugins() or self.plugins_enabled(): - return redirect(self.get_next()) - if not self.plugins: + messages.error(request, self.NONE_REPORT_TYPE_SELECTION_MESSAGE) return redirect(self.get_previous()) - - return super().get(request, *args, **kwargs) + return self.get(request, *args, **kwargs) class ExportSetupAggregateReportView(AggregateReportStepsMixin, BreadcrumbsAggregateReportView, ReportPluginView): @@ -243,11 +166,7 @@ class ExportSetupAggregateReportView(AggregateReportStepsMixin, BreadcrumbsAggre breadcrumbs_step = 6 current_step = 4 - def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: - if not self.selected_report_types: - messages.error(request, _("Select at least one report type to proceed.")) - return redirect(self.get_previous()) - + def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: return super().get(request, *args, **kwargs) def get_context_data(self, **kwargs): @@ -262,9 +181,11 @@ class SaveAggregateReportView(SaveAggregateReportMixin, BreadcrumbsAggregateRepo Save the report and redirect to the saved report """ - current_step = 5 + template_name = "aggregate_report.html" + breadcrumbs_step = 6 + current_step = 6 ooi_types = get_ooi_types_from_aggregate_report(AggregateOrganisationReport) - report_types: Sequence[type[Report]] + report_types: list[type[Report] | type[MultiReport] | type[AggregateReport]] def post(self, request, *args, **kwargs): old_report_names = request.POST.getlist("old_report_name") diff --git a/rocky/reports/views/base.py b/rocky/reports/views/base.py index 890c49d8ce9..cf6e720bff6 100644 --- a/rocky/reports/views/base.py +++ b/rocky/reports/views/base.py @@ -100,40 +100,29 @@ def get_context_data(self, **kwargs): return context -class BaseSelectionView(OrganizationView): +class OOISelectionView(OOIFilterView): """ - Some views just need to check on user selection and pass selection from view to view. - The calculations for the selections are done in their own view. + Shows a list of OOIs to select from and handles OOIs selection requests. """ + NONE_OOI_SELECTION_MESSAGE = _("Select at least one OOI to proceed.") + def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - self.selected_oois = self.check_oois_selection(sorted(set(request.GET.getlist("ooi", [])))) - self.selected_report_types = request.GET.getlist("report_type", []) - - def check_oois_selection(self, selected_oois: list[str]) -> list[str]: - """all in selection overrides the rest of the selection.""" - if "all" in selected_oois and len(selected_oois) > 1: - selected_oois = ["all"] - return selected_oois - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["selected_oois"] = self.selected_oois - context["selected_report_types"] = self.selected_report_types - return context + self.selected_oois: list[str] = self.get_ooi_selection() + self.oois: list[OOI] = self.get_oois() + self.oois_pk: list[str] = self.get_oois_pk() + def get_ooi_selection(self) -> list[str]: + selected_oois = self.request.GET.getlist("ooi", []) + if "all" in selected_oois: + return selected_oois + return sorted(set(self.request.POST.getlist("ooi", []))) -class ReportOOIView(OOIFilterView, BaseSelectionView): - """ - This class will show a list of OOIs with filters and handles OOIs selections. - Needs BaseSelectionView to get selected oois. - """ - - def setup(self, request, *args, **kwargs): - super().setup(request, *args, **kwargs) - self.oois = self.get_oois() - self.oois_pk = self.get_oois_pk() + def get_total_objects(self) -> int: + if "all" in self.selected_oois: + return len(self.oois_pk) + return len(self.selected_oois) def get_oois_pk(self) -> list[str]: oois_pk = self.selected_oois @@ -141,11 +130,6 @@ def get_oois_pk(self) -> list[str]: oois_pk = [ooi.primary_key for ooi in self.oois] return oois_pk - def get_total_objects(self): - if "all" in self.selected_oois: - return len(self.oois_pk) - return len(self.selected_oois) - def get_oois(self) -> list[OOI]: if "all" in self.selected_oois: return self.octopoes_api_connector.list_objects( @@ -156,13 +140,7 @@ def get_oois(self) -> list[OOI]: scan_profile_type=self.get_ooi_profile_types(), ).items - oois = [] - for ooi_id in self.selected_oois: - try: - oois.append(self.get_single_ooi(ooi_id)) - except Exception: - logger.warning("No data could be found for '%s' ", ooi_id) - return oois + return [self.get_single_ooi(pk=ooi_pk) for ooi_pk in self.selected_oois] def get_ooi_filter_forms(self, ooi_types: Iterable[type[OOI]]) -> dict[str, Form]: return { @@ -174,23 +152,30 @@ def get_ooi_filter_forms(self, ooi_types: Iterable[type[OOI]]) -> dict[str, Form def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) + context["selected_oois"] = self.selected_oois + context["oois_pk"] = self.oois_pk context["oois"] = self.oois + context.update(self.get_ooi_filter_forms(self.ooi_types)) return context -class ReportTypeView(BaseSelectionView): +class ReportTypeSelectionView(TemplateView): """ - This view lists all report types that is being fetched from the OOIs selection. - Each report type has its own input ooi witch will be matched with the oois selection. - Needs BaseSelectionView to get and remember report type selection. + Shows report types and handles selections and requests. """ + NONE_REPORT_TYPE_SELECTION_MESSAGE = _("Select at least one report type to proceed.") + def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - self.report_types: Sequence[type[Report] | type[MultiReport] | type[AggregateReport]] = ( + self.selected_report_types = self.get_report_type_selection() + self.report_types: list[type[Report] | type[MultiReport] | type[AggregateReport]] = ( self.get_report_types_from_choice() ) - self.report_ids = [report.id for report in self.report_types] + self.report_type_ids = [report_type for report_type in self.selected_report_types] + + def get_report_type_selection(self) -> list[str]: + return sorted(set(self.request.POST.getlist("report_type", []))) def get_report_types_from_choice( self, @@ -217,8 +202,13 @@ def get_report_types(reports: set[type[BaseReportType]]) -> list[dict[str, str]] for report_type in reports ] + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["selected_report_types"] = self.selected_report_types + return context -class ReportPluginView(ReportOOIView, ReportTypeView, TemplateView): + +class ReportPluginView(OOISelectionView, ReportTypeSelectionView): """ This view shows the required and optional plugins. Needs ReportTypeView to know which report type is selected to get their plugins. @@ -266,7 +256,7 @@ def get_plugin_data_for_saving(self) -> list[dict]: return plugin_data def get_all_plugins(self) -> tuple[dict[str, list[Plugin]], dict[str, bool]]: - return self.get_required_optional_plugins(get_plugins_for_report_ids(self.report_ids)) + return self.get_required_optional_plugins(get_plugins_for_report_ids(self.report_type_ids)) def get_required_optional_plugins( self, plugin_ids_dict: dict[str, set[str]] @@ -390,12 +380,9 @@ def get_observed_at(self): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["created_at"] = datetime.now() - context["selected_oois"] = self.selected_oois - context["selected_report_types"] = self.selected_report_types context["plugins"] = self.plugins context["all_plugins_enabled"] = self.all_plugins_enabled context["plugin_data"] = self.get_plugin_data() - context["oois"] = self.get_oois() return context diff --git a/rocky/reports/views/generate_report.py b/rocky/reports/views/generate_report.py index 892b736dd54..7a6bb11d2fd 100644 --- a/rocky/reports/views/generate_report.py +++ b/rocky/reports/views/generate_report.py @@ -1,4 +1,3 @@ -from collections.abc import Sequence from datetime import datetime, timezone from typing import Any @@ -8,22 +7,18 @@ from django.urls import reverse from django.utils.http import urlencode from django.utils.translation import gettext_lazy as _ -from django.views.generic import TemplateView from octopoes.models import Reference -from octopoes.models.exception import ObjectNotFoundException, TypeNotFound -from octopoes.models.ooi.reports import Report as ReportOOI -from reports.report_types.concatenated_report.report import ConcatenatedReport -from reports.report_types.definitions import Report -from reports.report_types.helpers import REPORTS, get_ooi_types_with_report, get_report_by_id, get_report_types_for_oois +from reports.report_types.helpers import get_ooi_types_with_report, get_report_types_for_oois from reports.views.base import ( REPORTS_PRE_SELECTION, + OOISelectionView, ReportBreadcrumbs, - ReportOOIView, ReportPluginView, - ReportTypeView, + ReportTypeSelectionView, get_selection, ) +from reports.views.mixins import SaveGenerateReportMixin from reports.views.view_helpers import GenerateReportStepsMixin from rocky.views.ooi_view import BaseOOIListView @@ -75,10 +70,7 @@ def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: class OOISelectionGenerateReportView( - GenerateReportStepsMixin, - BreadcrumbsGenerateReportView, - ReportOOIView, - BaseOOIListView, + GenerateReportStepsMixin, BreadcrumbsGenerateReportView, BaseOOIListView, OOISelectionView ): """ Select objects for the 'Generate Report' flow. @@ -89,19 +81,19 @@ class OOISelectionGenerateReportView( current_step = 1 ooi_types = get_ooi_types_with_report() + def post(self, request, *args, **kwargs): + if not self.selected_oois: + messages.error(request, self.NONE_OOI_SELECTION_MESSAGE) + return self.get(request, *args, **kwargs) + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["channel"] = "generate_report" - context.update(self.get_ooi_filter_forms(self.ooi_types)) return context class ReportTypesSelectionGenerateReportView( - GenerateReportStepsMixin, - BreadcrumbsGenerateReportView, - ReportOOIView, - ReportTypeView, - TemplateView, + GenerateReportStepsMixin, BreadcrumbsGenerateReportView, OOISelectionView, ReportTypeSelectionView ): """ Shows all possible report types from a list of OOIs. @@ -111,134 +103,25 @@ class ReportTypesSelectionGenerateReportView( template_name = "generate_report/select_report_types.html" breadcrumbs_step = 4 current_step = 2 - ooi_types = get_ooi_types_with_report() - def get(self, request, *args, **kwargs): + def post(self, request, *args, **kwargs): if not self.selected_oois: - messages.error(self.request, _("Select at least one OOI to proceed.")) + messages.error(request, self.NONE_OOI_SELECTION_MESSAGE) return redirect(self.get_previous()) - return super().get(request, *args, **kwargs) + return self.get(request, *args, **kwargs) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["available_report_types"] = self.get_report_types(get_report_types_for_oois(self.oois_pk)) + context["available_report_types"] = self.get_report_types(get_report_types_for_oois(self.get_oois_pk())) context["total_oois"] = self.get_total_objects() return context -class SaveGenerateReportMixin(ReportPluginView): - def save_report(self, report_names: list) -> ReportOOI: - error_reports = [] - report_data: dict[str, dict[str, dict[str, Any]]] = {} - by_type: dict[str, list[str]] = {} - - number_of_reports = 0 - - for ooi in self.get_oois_pk(): - ooi_type = Reference.from_str(ooi).class_ - - if ooi_type not in by_type: - by_type[ooi_type] = [] - - by_type[ooi_type].append(ooi) - - sorted_report_types = list(filter(lambda x: x in self.report_types, REPORTS)) - - for report_class in sorted_report_types: - oois = { - ooi for ooi_type in report_class.input_ooi_types for ooi in by_type.get(ooi_type.get_object_type(), []) - } - - try: - results = report_class(self.octopoes_api_connector).collect_data(oois, self.observed_at) - - except ObjectNotFoundException: - error_reports.append(report_class.id) - continue - except TypeNotFound: - error_reports.append(report_class.id) - continue - - for ooi, data in results.items(): - if report_class.id not in report_data: - report_data[report_class.id] = {} - - report_data[report_class.id][ooi] = { - "data": data, - "template": report_class.template_path, - "report_name": report_class.name, - } - number_of_reports += 1 - - observed_at = self.get_observed_at() - - # if its not a single report, we need a parent - if number_of_reports > 1: - raw_id = self.save_report_raw(data={"plugins": self.get_plugin_data_for_saving()}) - report_ooi = self.save_report_ooi( - report_data_raw_id=raw_id, - report_type=ConcatenatedReport, - input_oois=[], - parent=None, - has_parent=False, - observed_at=observed_at, - name=report_names[0][1], - ) - for report_type, ooi_data in report_data.items(): - for ooi, data in ooi_data.items(): - report_type_name = str(get_report_by_id(report_type).name) - ooi_name = Reference.from_str(ooi).human_readable - for default_name, updated_name in report_names: - if ooi_name in default_name and report_type_name in default_name: - name = updated_name - break - - raw_id = self.save_report_raw(data={"report_data": data["data"]}) - self.save_report_ooi( - report_data_raw_id=raw_id, - report_type=get_report_by_id(report_type), - input_oois=[ooi], - parent=report_ooi.reference, - has_parent=True, - observed_at=observed_at, - name=name, - ) - # if its a single report we can just save it as complete - else: - report_type = next(iter(report_data)) - ooi = next(iter(report_data[report_type])) - data = report_data[report_type][ooi] - raw_id = self.save_report_raw( - data={"report_data": data["data"], "plugins": self.get_plugin_data_for_saving()} - ) - report_ooi = self.save_report_ooi( - report_data_raw_id=raw_id, - report_type=get_report_by_id(report_type), - input_oois=[ooi], - parent=None, - has_parent=False, - observed_at=observed_at, - name=report_names[0][1], - ) - # If OOI could not be found or the date is incorrect, it will be shown to the user as a message error - if error_reports: - report_types = ", ".join(set(error_reports)) - date = self.observed_at.date() - error_message = _("No data could be found for %(report_types). Object(s) did not exist on %(date)s.") % { - "report_types": report_types, - "date": date, - } - messages.error(self.request, error_message) - - return report_ooi - - class SetupScanGenerateReportView( SaveGenerateReportMixin, GenerateReportStepsMixin, BreadcrumbsGenerateReportView, ReportPluginView, - TemplateView, ): """ Show required and optional plugins to start scans to generate OOIs to include in report. @@ -248,22 +131,14 @@ class SetupScanGenerateReportView( breadcrumbs_step = 5 current_step = 3 - def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: + def post(self, request, *args, **kwargs): if not self.selected_report_types: - messages.error(self.request, _("Select at least one report type to proceed.")) - return redirect( - reverse("generate_report_select_report_types", kwargs=self.get_kwargs()) + get_selection(self.request) - ) - if not self.report_has_required_plugins() or self.plugins_enabled(): - return redirect(self.get_next()) - if not self.plugins: + messages.error(request, self.NONE_REPORT_TYPE_SELECTION_MESSAGE) return redirect(self.get_previous()) - return super().get(request, *args, **kwargs) + return self.get(request, *args, **kwargs) -class ExportSetupGenerateReportView( - GenerateReportStepsMixin, BreadcrumbsGenerateReportView, ReportPluginView, TemplateView -): +class ExportSetupGenerateReportView(GenerateReportStepsMixin, BreadcrumbsGenerateReportView, ReportPluginView): """ Shows the export setup page where users can set their export preferences. """ @@ -271,32 +146,27 @@ class ExportSetupGenerateReportView( template_name = "generate_report/export_setup.html" breadcrumbs_step = 6 current_step = 4 + reports: dict[str, str] = {} - def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: - if not self.selected_report_types: - messages.error(request, _("Select at least one report type to proceed.")) - return redirect(self.get_previous()) - + def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: + self.reports = create_report_names(self.oois_pk, self.report_types) return super().get(request, *args, **kwargs) def get_context_data(self, **kwargs): - reports = create_report_names(self.oois_pk, self.report_types) context = super().get_context_data(**kwargs) + context["reports"] = self.reports context["current_datetime"] = datetime.now(timezone.utc) - context["reports"] = reports return context -class SaveGenerateReportView(SaveGenerateReportMixin, BreadcrumbsGenerateReportView, ReportPluginView, TemplateView): +class SaveGenerateReportView(SaveGenerateReportMixin, BreadcrumbsGenerateReportView, ReportPluginView): """ Save the report generated. """ template_name = "generate_report.html" breadcrumbs_step = 6 - current_step = 6 - report_types: Sequence[type[Report]] - ooi_types = get_ooi_types_with_report() + current_step = 4 def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: old_report_names = request.POST.getlist("old_report_name") @@ -311,7 +181,7 @@ def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: ) -def create_report_names(oois_pk, report_types): +def create_report_names(oois_pk, report_types) -> dict[str, str]: reports = {} oois_count = len(oois_pk) report_types_count = len(report_types) diff --git a/rocky/reports/views/mixins.py b/rocky/reports/views/mixins.py new file mode 100644 index 00000000000..99a8e5f37bf --- /dev/null +++ b/rocky/reports/views/mixins.py @@ -0,0 +1,191 @@ +from typing import Any + +from django.contrib import messages +from django.utils.translation import gettext_lazy as _ + +from octopoes.models import Reference, ScanProfileType +from octopoes.models.exception import ObjectNotFoundException, TypeNotFound +from octopoes.models.ooi.reports import Report as ReportOOI +from reports.report_types.aggregate_organisation_report.report import aggregate_reports +from reports.report_types.concatenated_report.report import ConcatenatedReport +from reports.report_types.helpers import REPORTS, get_report_by_id +from reports.views.base import ReportPluginView + + +class SaveGenerateReportMixin(ReportPluginView): + def save_report(self, report_names: list) -> ReportOOI: + error_reports = [] + report_data: dict[str, dict[str, dict[str, Any]]] = {} + by_type: dict[str, list[str]] = {} + + number_of_reports = 0 + + for ooi in self.get_oois_pk(): + ooi_type = Reference.from_str(ooi).class_ + + if ooi_type not in by_type: + by_type[ooi_type] = [] + + by_type[ooi_type].append(ooi) + + sorted_report_types = list(filter(lambda x: x in self.report_types, REPORTS)) + + for report_class in sorted_report_types: + oois = { + ooi for ooi_type in report_class.input_ooi_types for ooi in by_type.get(ooi_type.get_object_type(), []) + } + + try: + results = report_class(self.octopoes_api_connector).collect_data(oois, self.observed_at) + + except ObjectNotFoundException: + error_reports.append(report_class.id) + continue + except TypeNotFound: + error_reports.append(report_class.id) + continue + + for ooi, data in results.items(): + if report_class.id not in report_data: + report_data[report_class.id] = {} + + report_data[report_class.id][ooi] = { + "data": data, + "template": report_class.template_path, + "report_name": report_class.name, + } + number_of_reports += 1 + + observed_at = self.get_observed_at() + + # if its not a single report, we need a parent + if number_of_reports > 1: + raw_id = self.save_report_raw(data={"plugins": self.get_plugin_data_for_saving()}) + report_ooi = self.save_report_ooi( + report_data_raw_id=raw_id, + report_type=ConcatenatedReport, + input_oois=[], + parent=None, + has_parent=False, + observed_at=observed_at, + name=report_names[0][1], + ) + for report_type, ooi_data in report_data.items(): + for ooi, data in ooi_data.items(): + report_type_name = str(get_report_by_id(report_type).name) + ooi_name = Reference.from_str(ooi).human_readable + for default_name, updated_name in report_names: + if ooi_name in default_name and report_type_name in default_name: + name = updated_name + break + else: + name = default_name + break + + raw_id = self.save_report_raw(data={"report_data": data["data"]}) + + self.save_report_ooi( + report_data_raw_id=raw_id, + report_type=get_report_by_id(report_type), + input_oois=[ooi], + parent=report_ooi.reference, + has_parent=True, + observed_at=observed_at, + name=name, + ) + # if its a single report we can just save it as complete + else: + report_type = next(iter(report_data)) + ooi = next(iter(report_data[report_type])) + data = report_data[report_type][ooi] + raw_id = self.save_report_raw( + data={"report_data": data["data"], "plugins": self.get_plugin_data_for_saving()} + ) + report_ooi = self.save_report_ooi( + report_data_raw_id=raw_id, + report_type=get_report_by_id(report_type), + input_oois=[ooi], + parent=None, + has_parent=False, + observed_at=observed_at, + name=report_names[0][1], + ) + # If OOI could not be found or the date is incorrect, it will be shown to the user as a message error + if error_reports: + report_types = ", ".join(set(error_reports)) + date = self.observed_at.date() + error_message = _("No data could be found for %(report_types). Object(s) did not exist on %(date)s.") % { + "report_types": report_types, + "date": date, + } + messages.error(self.request, error_message) + + return report_ooi + + +class SaveAggregateReportMixin(ReportPluginView): + def save_report(self, report_names: list) -> ReportOOI: + input_oois = self.get_oois() + + aggregate_report, post_processed_data, report_data, report_errors = aggregate_reports( + self.octopoes_api_connector, + input_oois, + self.selected_report_types, + self.observed_at, + self.organization.code, + ) + + # If OOI could not be found or the date is incorrect, it will be shown to the user as a message error + if report_errors: + report_types = ", ".join(set(report_errors)) + date = self.observed_at.date() + error_message = _("No data could be found for %(report_types). Object(s) did not exist on %(date)s.") % { + "report_types": report_types, + "date": date, + } + messages.add_message(self.request, messages.ERROR, error_message) + + observed_at = self.get_observed_at() + + post_processed_data["plugins"] = self.get_plugin_data_for_saving() + post_processed_data["oois"] = [] + for input_ooi in input_oois: + post_processed_data["oois"].append( + { + "name": input_ooi.human_readable, + "type": input_ooi.object_type, + "scan_profile_level": input_ooi.scan_profile.level.value if input_ooi.scan_profile else 0, + "scan_profile_type": ( + input_ooi.scan_profile.scan_profile_type if input_ooi.scan_profile else ScanProfileType.EMPTY + ), + } + ) + + post_processed_data["report_types"] = [] + for report_type in self.report_types: + post_processed_data["report_types"].append( + { + "name": str(report_type.name), + "description": str(report_type.description), + "label_style": report_type.label_style, + } + ) + + # Create the report + report_data_raw_id = self.save_report_raw(data=post_processed_data) + report_ooi = self.save_report_ooi( + report_data_raw_id=report_data_raw_id, + report_type=type(aggregate_report), + input_oois=[ooi.primary_key for ooi in input_oois], + parent=None, + has_parent=False, + observed_at=observed_at, + name=report_names[0][1], + ) + + # Save the child reports to bytes + for ooi, types in report_data.items(): + for report_type, data in types.items(): + self.save_report_raw(data=data) + + return report_ooi diff --git a/rocky/reports/views/multi_report.py b/rocky/reports/views/multi_report.py index a80bda4962f..9af648ee5b5 100644 --- a/rocky/reports/views/multi_report.py +++ b/rocky/reports/views/multi_report.py @@ -6,17 +6,16 @@ from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import gettext_lazy as _ -from django.views.generic import TemplateView from django_weasyprint import WeasyTemplateResponseMixin from tools.view_helpers import url_with_querystring from reports.report_types.multi_organization_report.report import MultiOrganizationReport, collect_report_data from reports.views.base import ( REPORTS_PRE_SELECTION, + OOISelectionView, ReportBreadcrumbs, - ReportOOIView, ReportPluginView, - ReportTypeView, + ReportTypeSelectionView, get_selection, ) from reports.views.view_helpers import MultiReportStepsMixin @@ -69,7 +68,7 @@ def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: ) -class OOISelectionMultiReportView(MultiReportStepsMixin, BreadcrumbsMultiReportView, ReportOOIView, BaseOOIListView): +class OOISelectionMultiReportView(MultiReportStepsMixin, BreadcrumbsMultiReportView, BaseOOIListView, OOISelectionView): """ Select OOIs for the 'Multi Report' flow. """ @@ -79,18 +78,17 @@ class OOISelectionMultiReportView(MultiReportStepsMixin, BreadcrumbsMultiReportV current_step = 1 ooi_types = MultiOrganizationReport.input_ooi_types - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context.update(self.get_ooi_filter_forms(self.ooi_types)) - return context + def post(self, request, *args, **kwargs): + if not self.selected_oois: + messages.error(request, self.NONE_OOI_SELECTION_MESSAGE) + return self.get(request, *args, **kwargs) class ReportTypesSelectionMultiReportView( MultiReportStepsMixin, BreadcrumbsMultiReportView, - ReportOOIView, - ReportTypeView, - TemplateView, + OOISelectionView, + ReportTypeSelectionView, ): """ Shows all possible report types from a list of OOIs. @@ -101,10 +99,11 @@ class ReportTypesSelectionMultiReportView( breadcrumbs_step = 4 current_step = 2 - def get(self, request, *args, **kwargs): + def post(self, request, *args, **kwargs): if not self.selected_oois: - messages.error(self.request, _("Select at least one OOI to proceed.")) - return super().get(request, *args, **kwargs) + messages.error(request, self.NONE_OOI_SELECTION_MESSAGE) + return redirect(self.get_previous()) + return self.get(request, *args, **kwargs) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -113,7 +112,7 @@ def get_context_data(self, **kwargs): return context -class SetupScanMultiReportView(MultiReportStepsMixin, BreadcrumbsMultiReportView, ReportPluginView, TemplateView): +class SetupScanMultiReportView(MultiReportStepsMixin, BreadcrumbsMultiReportView, ReportPluginView): """ Show required and optional plugins to start scans to multi OOIs to include in report. """ @@ -128,7 +127,7 @@ def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: return super().get(request, *args, **kwargs) -class ExportSetupMultiReportView(MultiReportStepsMixin, BreadcrumbsMultiReportView, ReportPluginView, TemplateView): +class ExportSetupMultiReportView(MultiReportStepsMixin, BreadcrumbsMultiReportView, ReportPluginView): """ Shows the export setup page where users can set their export preferences. """ @@ -151,7 +150,7 @@ def get_context_data(self, **kwargs): return context -class MultiReportView(BreadcrumbsMultiReportView, ReportPluginView, TemplateView): +class MultiReportView(BreadcrumbsMultiReportView, ReportPluginView): """ Shows the multi report from OOIS and report types. """ diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index d9087daee76..3d427696c37 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-05 06:35+0000\n" +"POT-Creation-Date: 2024-08-05 13:42+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -811,9 +811,6 @@ msgid "" msgstr "" #: katalogus/templates/katalogus_settings.html -#: reports/templates/partials/export_report_settings.html -#: reports/templates/partials/report_setup_scan.html -#: reports/templates/partials/report_types_selection.html #: rocky/templates/two_factor/core/otp_required.html msgid "Go back" msgstr "" @@ -3584,11 +3581,6 @@ msgstr "" msgid "Set up the required plugins for this report." msgstr "" -#: reports/templates/partials/report_setup_scan.html -#: reports/templates/partials/report_types_selection.html -msgid "Change selection" -msgstr "" - #: reports/templates/partials/report_setup_scan.html msgid "Plugins" msgstr "" @@ -3707,6 +3699,10 @@ msgid_plural "You have selected %(total_oois)s objects in previous step." msgstr[0] "" msgstr[1] "" +#: reports/templates/partials/report_types_selection.html +msgid "Change selection" +msgstr "" + #: reports/templates/partials/report_types_selection.html msgid "Available report types" msgstr "" @@ -3719,6 +3715,11 @@ msgstr "" msgid "Toggle all report types" msgstr "" +#: reports/templates/partials/return_button.html +#, python-format +msgid "%(btn_text)s" +msgstr "" + #: reports/templates/report_overview/report_history.html #: reports/views/report_overview.py msgid "Reports history" @@ -3913,19 +3914,11 @@ msgstr "" msgid "Save report" msgstr "" -#: reports/views/aggregate_report.py reports/views/generate_report.py -#: reports/views/multi_report.py +#: reports/views/base.py msgid "Select at least one OOI to proceed." msgstr "" -#: reports/views/aggregate_report.py reports/views/generate_report.py -msgid "" -"No data could be found for %(report_types). Object(s) did not exist on " -"%(date)s." -msgstr "" - -#: reports/views/aggregate_report.py reports/views/generate_report.py -#: reports/views/multi_report.py +#: reports/views/base.py reports/views/multi_report.py msgid "Select at least one report type to proceed." msgstr "" @@ -3954,6 +3947,12 @@ msgstr "" msgid "{report_type} for {ooi}" msgstr "" +#: reports/views/mixins.py +msgid "" +"No data could be found for %(report_types). Object(s) did not exist on " +"%(date)s." +msgstr "" + #: reports/views/multi_report.py msgid "Multi report" msgstr "" diff --git a/rocky/tests/conftest.py b/rocky/tests/conftest.py index 000a6b7fd76..ddd3574a281 100644 --- a/rocky/tests/conftest.py +++ b/rocky/tests/conftest.py @@ -18,7 +18,8 @@ from django_otp import DEVICE_ID_SESSION_KEY from django_otp.middleware import OTPMiddleware from httpx import Response -from katalogus.client import parse_plugin +from katalogus.client import Boefje, parse_plugin +from tools.enums import SCAN_LEVEL from tools.models import GROUP_ADMIN, GROUP_CLIENT, GROUP_REDTEAM, Indemnification, Organization, OrganizationMember from octopoes.config.settings import ( @@ -40,6 +41,7 @@ from octopoes.models.transaction import TransactionRecord from octopoes.models.tree import ReferenceTree from octopoes.models.types import OOIType +from rocky.health import ServiceHealth from rocky.scheduler import PaginatedTasksResponse, Task LANG_LIST = [code for code, _ in settings.LANGUAGES] @@ -1706,3 +1708,63 @@ def onboarding_collect_data(): "finding_types": [], } } + + +@pytest.fixture +def rocky_health(): + ServiceHealth( + service="rocky", + healthy=True, + version="0.0.1.dev1", + additional=None, + results=[ + ServiceHealth( + service="octopoes", + healthy=True, + version="0.0.1.dev1", + additional=None, + results=[ + ServiceHealth( + service="xtdb", + healthy=True, + version="1.24.1", + additional={ + "version": "1.24.1", + "revision": "1164f9a3c7e36edbc026867945765fd4366c1731", + "indexVersion": 22, + "consumerState": None, + "kvStore": "xtdb.rocksdb.RocksKv", + "estimateNumKeys": 24552, + "size": 24053091, + }, + results=[], + ) + ], + ), + ServiceHealth(service="katalogus", healthy=True, version="0.0.1-development", additional=None, results=[]), + ServiceHealth(service="scheduler", healthy=True, version="0.0.1.dev1", additional=None, results=[]), + ServiceHealth(service="bytes", healthy=True, version="0.0.1.dev1", additional=None, results=[]), + ServiceHealth(service="keiko", healthy=True, version="0.0.1.dev1", additional=None, results=[]), + ], + ) + + +@pytest.fixture +def boefje_dns_records(): + return Boefje( + id="dns-records", + name="DnsRecords", + version=None, + authors=None, + created=None, + description="Fetch the DNS record(s) of a hostname", + environment_keys=None, + related=[], + enabled=True, + type="boefje", + scan_level=SCAN_LEVEL.L1, + consumes={Hostname}, + options=None, + runnable_hash=None, + produces={"boefje/dns-records"}, + ) diff --git a/rocky/tests/reports/test_aggregate_report_flow.py b/rocky/tests/reports/test_aggregate_report_flow.py new file mode 100644 index 00000000000..f3c6610cbf8 --- /dev/null +++ b/rocky/tests/reports/test_aggregate_report_flow.py @@ -0,0 +1,270 @@ +from pytest_django.asserts import assertContains +from reports.views.aggregate_report import ( + OOISelectionAggregateReportView, + ReportTypesSelectionAggregateReportView, + SaveAggregateReportView, + SetupScanAggregateReportView, +) + +from octopoes.models.pagination import Paginated +from octopoes.models.types import OOIType +from tests.conftest import setup_request + + +def test_select_all_oois_post_to_select_report_types( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected oois to the report type selection page. + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "aggregate_report_select_report_types", + { + "observed_at": valid_time.strftime("%Y-%m-%d"), + "ooi": "all", + }, + ), + client_member.user, + ) + + response = ReportTypesSelectionAggregateReportView.as_view()( + request, organization_code=client_member.organization.code + ) + + assert response.status_code == 200 + total_objects = str(len(listed_hostnames)) + assertContains(response, f"You have selected {total_objects} objects in previous step.") + + +def test_select_some_oois_post_to_select_report_types( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected oois to the report type selection page. + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + ooi_pks = [hostname.primary_key for hostname in listed_hostnames] + selection = ooi_pks[0:2] + + request = setup_request( + rf.post( + "generate_report_select_report_types", + { + "observed_at": valid_time.strftime("%Y-%m-%d"), + "ooi": selection, + }, + ), + client_member.user, + ) + + response = ReportTypesSelectionAggregateReportView.as_view()( + request, organization_code=client_member.organization.code + ) + + assert response.status_code == 200 + + total_objects = str(len(selection)) + + assertContains(response, f"You have selected {total_objects} objects in previous step.") + + +def test_change_ooi_selection_for_none_selection( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected oois to the report type selection page. + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "generate_report_select_oois", + { + "observed_at": valid_time.strftime("%Y-%m-%d"), + }, + ), + client_member.user, + ) + + response = OOISelectionAggregateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 + assert response.context_data["selected_oois"] == [] + + +def test_change_ooi_selection_with_ooi_selection( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected oois to the report type selection page. + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + ooi_pks = [hostname.primary_key for hostname in listed_hostnames] + selection = ooi_pks[0:2] + + request = setup_request( + rf.post( + "generate_report_select_oois", + {"observed_at": valid_time.strftime("%Y-%m-%d"), "ooi": selection}, + ), + client_member.user, + ) + + response = OOISelectionAggregateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 + + oois_fetched_from_post = response.context_data["selected_oois"] + + assert len(oois_fetched_from_post) == 2 + + +def test_report_types_selection_nothing_selected( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected report types to the configuration page (set plugins). + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "aggregate_report_setup_scan", + {"observed_at": valid_time.strftime("%Y-%m-%d")}, + ), + client_member.user, + ) + + response = SetupScanAggregateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 302 + assert list(request._messages)[0].message == "Select at least one report type to proceed." + + +def test_report_types_selection( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, + mocker, + boefje_dns_records, + rocky_health, + mock_bytes_client, +): + """ + Will send the selected report types to the configuration page (set plugins). + """ + + katalogus_mocker = mocker.patch("reports.views.base.get_katalogus")() + katalogus_mocker.get_plugins.return_value = [boefje_dns_records] + + rocky_health_mocker = mocker.patch("reports.report_types.aggregate_organisation_report.report.get_rocky_health")() + rocky_health_mocker.return_value = rocky_health + + mock_bytes_client().upload_raw.return_value = "Report|e821aaeb-a6bd-427f-b064-e46837911a5d" + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "aggregate_report_setup_scan", + {"observed_at": valid_time.strftime("%Y-%m-%d"), "report_type": "dns-report"}, + ), + client_member.user, + ) + + response = SetupScanAggregateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 # if all plugins are enabled the view will auto redirect to generate report + + assertContains(response, '', html=True) + + +def test_save_aggregate_report_view( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, + rocky_health, + mocker, + boefje_dns_records, + mock_bytes_client, +): + """ + Will send data through post to aggregate report. + """ + + katalogus_mocker = mocker.patch("reports.views.base.get_katalogus")() + katalogus_mocker.get_plugins.return_value = [boefje_dns_records] + + rocky_health_mocker = mocker.patch("reports.report_types.aggregate_organisation_report.report.get_rocky_health")() + rocky_health_mocker.return_value = rocky_health + + mock_bytes_client().upload_raw.return_value = "Report|e821aaeb-a6bd-427f-b064-e46837911a5d" + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "aggregate_report_save", + { + "observed_at": valid_time.strftime("%Y-%m-%d"), + "ooi": "all", + "report_type": ["systems-report", "dns-report"], + "old_report_name": ["Aggregate Report"], + "report_name": ["Testing a new name for Aggregate Report"], + }, + ), + client_member.user, + ) + + response = SaveAggregateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 302 # after post follows redirect, this to first create report ID + assert "report_id=Report" in response.url diff --git a/rocky/tests/reports/test_generate_report_flow.py b/rocky/tests/reports/test_generate_report_flow.py new file mode 100644 index 00000000000..1271a69bff7 --- /dev/null +++ b/rocky/tests/reports/test_generate_report_flow.py @@ -0,0 +1,263 @@ +from pytest_django.asserts import assertContains +from reports.views.generate_report import ( + OOISelectionGenerateReportView, + ReportTypesSelectionGenerateReportView, + SaveGenerateReportView, + SetupScanGenerateReportView, +) + +from octopoes.models.pagination import Paginated +from octopoes.models.types import OOIType +from tests.conftest import setup_request + + +def test_select_all_oois_post_to_select_report_types( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected oois to the report type selection page. + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "generate_report_select_report_types", + { + "observed_at": valid_time.strftime("%Y-%m-%d"), + "ooi": "all", + }, + ), + client_member.user, + ) + + response = ReportTypesSelectionGenerateReportView.as_view()( + request, organization_code=client_member.organization.code + ) + + assert response.status_code == 200 + total_objects = str(len(listed_hostnames)) + assertContains(response, f"You have selected {total_objects} objects in previous step.") + + +def test_select_some_oois_post_to_select_report_types( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected oois to the report type selection page. + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + ooi_pks = [hostname.primary_key for hostname in listed_hostnames] + selection = ooi_pks[0:2] + + request = setup_request( + rf.post( + "generate_report_select_report_types", + { + "observed_at": valid_time.strftime("%Y-%m-%d"), + "ooi": selection, + }, + ), + client_member.user, + ) + + response = ReportTypesSelectionGenerateReportView.as_view()( + request, organization_code=client_member.organization.code + ) + + assert response.status_code == 200 + + total_objects = str(len(selection)) + + assertContains(response, f"You have selected {total_objects} objects in previous step.") + + +def test_change_ooi_selection_for_none_selection( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected oois to the report type selection page. + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "generate_report_select_oois", + { + "observed_at": valid_time.strftime("%Y-%m-%d"), + }, + ), + client_member.user, + ) + + response = OOISelectionGenerateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 + assert response.context_data["selected_oois"] == [] + + +def test_change_ooi_selection_with_ooi_selection( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected oois to the report type selection page. + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + ooi_pks = [hostname.primary_key for hostname in listed_hostnames] + selection = ooi_pks[0:2] + + request = setup_request( + rf.post( + "generate_report_select_oois", + {"observed_at": valid_time.strftime("%Y-%m-%d"), "ooi": selection}, + ), + client_member.user, + ) + + response = OOISelectionGenerateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 + + oois_fetched_from_post = response.context_data["selected_oois"] + + assert len(oois_fetched_from_post) == 2 + + +def test_report_types_selection_nothing_selected( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected report types to the configuration page (set plugins). + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "generate_report_setup_scan", + {"observed_at": valid_time.strftime("%Y-%m-%d")}, + ), + client_member.user, + ) + + response = SetupScanGenerateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 302 + assert list(request._messages)[0].message == "Select at least one report type to proceed." + + +def test_report_types_selection( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, + mocker, + boefje_dns_records, + mock_bytes_client, +): + """ + Will send the selected report types to the configuration page (set plugins). + """ + + katalogus_mocker = mocker.patch("reports.views.base.get_katalogus")() + katalogus_mocker.get_plugins.return_value = [boefje_dns_records] + + mock_bytes_client().upload_raw.return_value = "Report|e821aaeb-a6bd-427f-b064-e46837911a5d" + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "generate_report_setup_scan", + {"observed_at": valid_time.strftime("%Y-%m-%d"), "ooi": "all", "report_type": "dns-report"}, + ), + client_member.user, + ) + + response = SetupScanGenerateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 + assertContains(response, '', html=True) + + +def test_save_generate_report_view( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, + mocker, + boefje_dns_records, + mock_bytes_client, +): + """ + Will send data through post to generate report. + """ + + katalogus_mocker = mocker.patch("reports.views.base.get_katalogus")() + katalogus_mocker.get_plugins.return_value = [boefje_dns_records] + + mock_bytes_client().upload_raw.return_value = "Report|e821aaeb-a6bd-427f-b064-e46837911a5d" + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + old_report_names = [f"DNS report for {ooi.name}" for ooi in listed_hostnames] + + request = setup_request( + rf.post( + "generate_report_view", + { + "observed_at": valid_time.strftime("%Y-%m-%d"), + "ooi": "all", + "report_type": "dns-report", + "old_report_name": old_report_names, + "report_name": [f"DNS report for {len(listed_hostnames)} objects"], + }, + ), + client_member.user, + ) + + response = SaveGenerateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 302 # after post follows redirect, this to first create report ID + assert "report_id=Report" in response.url diff --git a/rocky/tests/reports/test_plugins.py b/rocky/tests/reports/test_plugins.py index 03deac4c5ee..9343f181931 100644 --- a/rocky/tests/reports/test_plugins.py +++ b/rocky/tests/reports/test_plugins.py @@ -27,7 +27,7 @@ def test_generate_report_setup_scan_wrong_plugin_id( kwargs = {"organization_code": client_member.organization.code} url = reverse("generate_report_setup_scan", kwargs=kwargs) - request = rf.get( + request = rf.post( url, { "observed_at": valid_time.strftime("%Y-%m-%d"), @@ -41,5 +41,5 @@ def test_generate_report_setup_scan_wrong_plugin_id( response = SetupScanGenerateReportView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 302 + assert response.status_code == 200 assert list(request._messages)[0].message == "A HTTP error occurred. Check logs for more info." From 0b1d0d7af847f151c8ce26c2eff299596d27c097 Mon Sep 17 00:00:00 2001 From: JP Bruins Slot Date: Tue, 6 Aug 2024 13:58:28 +0200 Subject: [PATCH 049/112] Restructure scheduler development scripts (#3293) Co-authored-by: Jeroen Dekkers --- .pre-commit-config.yaml | 1 + mula/scripts/.gitignore | 2 + mula/scripts/Dockerfile | 9 ++ mula/scripts/README.md | 31 +++++++ mula/scripts/__init__.py | 0 mula/scripts/benchmark.py | 190 ++++++++++++++++++++++++++++++++++++++ mula/scripts/load.py | 169 +++++++++++++++++++++++++++++++++ 7 files changed, 402 insertions(+) create mode 100644 mula/scripts/.gitignore create mode 100644 mula/scripts/Dockerfile create mode 100644 mula/scripts/README.md create mode 100644 mula/scripts/__init__.py create mode 100644 mula/scripts/benchmark.py create mode 100644 mula/scripts/load.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0feca0fec5a..0219f936ad8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -96,6 +96,7 @@ repos: ^boefjes/tools | ^keiko/templates | ^mula/whitelist\.py$ | + ^mula/scripts | ^octopoes/tools | ^rocky/whitelist\.py$ | /tests/ | diff --git a/mula/scripts/.gitignore b/mula/scripts/.gitignore new file mode 100644 index 00000000000..2ef021797f3 --- /dev/null +++ b/mula/scripts/.gitignore @@ -0,0 +1,2 @@ +data.csv +logs.txt diff --git a/mula/scripts/Dockerfile b/mula/scripts/Dockerfile new file mode 100644 index 00000000000..2a65ab9e3fa --- /dev/null +++ b/mula/scripts/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3.10-slim + +WORKDIR /usr/src/app + +RUN pip install --no-cache-dir httpx + +COPY . . + +ENTRYPOINT ["python"] diff --git a/mula/scripts/README.md b/mula/scripts/README.md new file mode 100644 index 00000000000..275f64bb7fb --- /dev/null +++ b/mula/scripts/README.md @@ -0,0 +1,31 @@ +# Scripts + +A collection of scripts that is used for various testing and benchmarking +purposes. + +## `load.py` + +Allows to create multiple organisations and with a supplied `data.csv` file +create objects on which a select number of boefjes will be performed upon. + +```shell +docker build -t mula_scripts . +docker run -it --rm --network=host mula_scripts load.py --orgs {number-of-orgs} +``` + +## `benchmark.py` + +Allows to benchmark the operations of the Scheduler. When running the `load.py` +the benchmark script can run along side it to measure the performance of the +Scheduler. + +It will check: + +- Errors in the logs +- Task stats (how many are queued, running, etc.) +- CPU and memory usage + +```shell +docker build -t mula_scripts . +docker run -it --rm --network=host mula_scripts benchmark.py --container {container-id-of-scheduler} +``` diff --git a/mula/scripts/__init__.py b/mula/scripts/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/mula/scripts/benchmark.py b/mula/scripts/benchmark.py new file mode 100644 index 00000000000..a70272467d8 --- /dev/null +++ b/mula/scripts/benchmark.py @@ -0,0 +1,190 @@ +import argparse +import logging +import subprocess +import threading +import time +from pathlib import Path + +import httpx + +SCHEDULER_API = "http://localhost:8004" +TIMEOUT_FOR_LOG_CAPTURE = 5 + +logger = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + +client = httpx.Client(base_url=SCHEDULER_API) + + +def are_tasks_done() -> bool: + response = client.get( + url="/tasks/stats", + timeout=30, + ) + + try: + response.raise_for_status() + except httpx.HTTPError: + logger.error("Error getting tasks") + raise + + tasks_stats = response.json() + + return all(tasks_stats[hour].get("queued") <= 0 for hour in tasks_stats) + + +def parse_stats() -> None: + resp_tasks_stats = client.get( + url="/tasks/stats", + timeout=30, + ) + + try: + resp_tasks_stats.raise_for_status() + except httpx.HTTPError: + logger.error("Error getting tasks") + raise + + tasks_stats = resp_tasks_stats.json() + for hour in tasks_stats: + queued = tasks_stats[hour].get("queued") + running = tasks_stats[hour].get("running") + failed = tasks_stats[hour].get("failed") + completed = tasks_stats[hour].get("completed") + + logger.info( + "HOUR %s, QUEUED %s, RUNNING %s, FAILED %s, COMPLETED %s", + hour, + queued, + running, + failed, + completed, + ) + + +def capture_logs(container_id: str, output_file: str) -> None: + # Capture logs + with Path.open(output_file, "w", encoding="utf-8") as file: + subprocess.run( + ["docker", "logs", container_id], + stdout=file, + stderr=file, + check=True, + ) + + +def parse_logs(path: str) -> None: + # Check if there were any errors in the logs + count = 0 + with Path.open(path, encoding="utf-8") as file: + for line in file: + if line.startswith("ERROR") or line.startswith("Traceback"): + count += 1 + logger.info(line) + + if count > 0: + logger.error("Found %d errors in the logs", count) + + +def collect_cpu(container_id: str) -> str: + return ( + subprocess.run( + [ + "docker", + "stats", + "--no-stream", + "--format", + "{{.CPUPerc}}", + container_id, + ], + capture_output=True, + check=True, + ) + .stdout.decode("utf-8") + .strip("%\n") + ) + + +def collect_memory(container_id: str) -> str: + return ( + subprocess.run( + [ + "docker", + "stats", + "--no-stream", + "--format", + "{{.MemUsage}}", + container_id, + ], + capture_output=True, + check=True, + ) + .stdout.decode("utf-8") + .split("/")[0] + .strip("MiB\n") + ) + + +def run(container_id: str) -> None: + # Start capturing logs + if container_id is not None: + thread = threading.Thread(target=capture_logs, args=(container_id, "logs.txt")) + thread.start() + + # Wait for tasks to finish + while not are_tasks_done(): + logger.debug("Tasks are not done yet") + + cpu = collect_cpu(container_id) + memory = collect_memory(container_id) + logger.info("CPU %s, MEMORY %s", cpu, memory) + + # Parse stats + parse_stats() + + time.sleep(10) + continue + + logger.debug("Tasks are done") + + # Stop capturing logs + thread.join(timeout=TIMEOUT_FOR_LOG_CAPTURE) + + # Parse stats + parse_stats() + + # Parse logs + parse_logs("logs.txt") + + +if __name__ == "__main__": + # Setup command line interface + parser = argparse.ArgumentParser(description="Benchmark the scheduler.") + + # Add arguments + parser.add_argument("--verbose", "-v", action="store_true", help="Set to enable verbose logging.") + + parser.add_argument( + "--container-id", + "-c", + type=str, + required=False, + help="The container id of the process to monitor.", + ) + + # Parse arguments + args = parser.parse_args() + + # Configure logging level, if the -v (verbose) flag was given this will + # set the log-level to DEBUG (printing all debug messages and higher), + # if -v was not given it defaults to printing level warning and higher. + level = logging.INFO + if args.verbose: + level = logging.DEBUG + + logging.basicConfig( + level=level, + format="%(asctime)s %(name)-10s %(levelname)-8s %(message)s", + ) + + run(args.container_id) diff --git a/mula/scripts/load.py b/mula/scripts/load.py new file mode 100644 index 00000000000..539de370970 --- /dev/null +++ b/mula/scripts/load.py @@ -0,0 +1,169 @@ +import argparse +import csv +import logging +import uuid +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + +import httpx + +OCTOPOES_API = "http://localhost:8001" +KATALOGUS_API = "http://localhost:8003" +SCHEDULER_API = "http://localhost:8004" + +logger = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + +octopoes_client = httpx.Client(base_url=OCTOPOES_API) +katalogus_client = httpx.Client(base_url=KATALOGUS_API) +scheduler_client = httpx.Client(base_url=SCHEDULER_API) + + +def run(org_num: int = 1): + # Create organisations + orgs: list[dict[str, Any]] = [] + for n in range(0, org_num): + org = { + "id": f"org-{n}", + "name": f"Organisation {n}", + } + orgs.append(org) + + resp_katalogus = katalogus_client.post( + url="/v1/organisations/", + json=org, + timeout=30, + ) + + try: + resp_katalogus.raise_for_status() + except httpx.HTTPStatusError: + if resp_katalogus.status_code != httpx.codes.NOT_FOUND: + logger.info("Error creating organisation in katalogus %s", org) + + if resp_katalogus.status_code == httpx.codes.NOT_FOUND: + logger.info("Organisation already exists in katalogus %s", org) + + resp_octo = octopoes_client.post( + url=f"/{org.get('id')}/node", + timeout=30, + ) + + try: + resp_octo.raise_for_status() + except httpx.HTTPStatusError: + if resp_octo.status_code != httpx.codes.NOT_FOUND: + logger.info("Error creating organisation in octopoes %s", org) + + if resp_octo.status_code == httpx.codes.NOT_FOUND: + logger.info("Organisation already exists in octopoes %s", org) + + logger.info(resp_octo.content) + + logger.info("Created organisation %s", org) + + # Enable boefjes for organisation + boefjes = ("dns-records", "dns-sec", "dns-zone") + for boefje_id in boefjes: + resp_enable_boefje = katalogus_client.patch( + url=f"/v1/organisations/{org.get('id')}/plugins/{boefje_id}", + json={"enabled": True}, + timeout=30, + ) + + try: + resp_enable_boefje.raise_for_status() + except httpx.HTTPError: + logger.info("Error enabling boefje %s", boefje_id) + raise + + logger.info("Enabled boefje %s", boefje_id) + + declarations: list[dict[str, Any]] = [] + + # Check if data file exists + if not Path("data.csv").exists(): + logger.info("data.csv file not found") + return + + with Path("data.csv").open(newline="", encoding="utf-8") as csv_file: + csv_reader = csv.DictReader(csv_file, delimiter=",", quotechar='"') + for row in csv_reader: + name = row["name"] + declaration = { + "ooi": { + "object_type": "Hostname", + "primary_key": f"Hostname|internet|{name}", + "network": "Network|internet", + "name": f"{name}", + "registered_domain": None, + "dns_zone": None, + "scan_profile": { + "scan_profile_type": "declared", + "level": 1, + "reference": f"Hostname|internet|{name}", + }, + }, + "valid_time": datetime.now(timezone.utc).isoformat(), + "method": None, + "task_id": str(uuid.uuid4()), + } + declarations.append(declaration) + + for org in orgs: + for declaration in declarations[:10]: + resp_octopoes_decl = octopoes_client.post( + f"/{org.get('id')}/declarations", + json=declaration, + timeout=30, + ) + + try: + resp_octopoes_decl.raise_for_status() + except httpx.HTTPError: + logger.info("Error creating declaration %s", declaration) + logger.info(resp_octopoes_decl.text) + raise + + logger.info("Org %s created declaration %s", org.get("id"), declaration) + + resp_octopoes_scan_profile = octopoes_client.put( + url=f"/{org.get('id')}/scan_profiles", + params={"valid_time": str(datetime.now(timezone.utc))}, + json={ + "scan_profile_type": "declared", + "reference": declaration.get("ooi").get("scan_profile").get("reference"), + "level": declaration.get("ooi").get("scan_profile").get("level"), + }, + timeout=30, + ) + + try: + resp_octopoes_scan_profile.raise_for_status() + except httpx.HTTPError: + logger.info( + "Error creating scan profile %s", + declaration.get("ooi").get("scan_profile"), + ) + logger.info(resp_octopoes_scan_profile.text) + raise + + logger.info( + "Org %s created scan profile %s", + org.get("id"), + declaration.get("ooi").get("scan_profile"), + ) + + +if __name__ == "__main__": + # Setup command line interface + parser = argparse.ArgumentParser(description="Load test the scheduler") + + # Add arguments + parser.add_argument("--orgs", type=int, default=1, help="Number of organisations to create") + + # Parse arguments + args = parser.parse_args() + + run(org_num=args.orgs) From 7b7ae2ef72660ecd4d7348ce4606ffedc16c06d9 Mon Sep 17 00:00:00 2001 From: ammar92 Date: Tue, 6 Aug 2024 18:19:46 +0200 Subject: [PATCH 050/112] Updated `Django` and `opentelemetry` packages (#3324) --- boefjes/poetry.lock | 127 +++++++++++----------- boefjes/pyproject.toml | 26 ++--- boefjes/requirements-dev.txt | 78 +++++++------- boefjes/requirements.txt | 78 +++++++------- bytes/poetry.lock | 127 +++++++++++----------- bytes/pyproject.toml | 26 ++--- bytes/requirements-dev.txt | 78 +++++++------- bytes/requirements.txt | 78 +++++++------- keiko/poetry.lock | 95 ++++++++-------- keiko/pyproject.toml | 20 ++-- keiko/requirements-dev.txt | 60 +++++------ keiko/requirements.txt | 60 +++++------ mula/poetry.lock | 131 ++++++++++++----------- mula/pyproject.toml | 26 ++--- mula/requirements-dev.txt | 78 +++++++------- mula/requirements.txt | 78 +++++++------- octopoes/poetry.lock | 127 +++++++++++----------- octopoes/pyproject.toml | 26 ++--- octopoes/requirements-dev.txt | 78 +++++++------- octopoes/requirements.txt | 78 +++++++------- rocky/poetry.lock | 196 +++++++++++++++++----------------- rocky/pyproject.toml | 32 +++--- rocky/requirements-dev.txt | 126 +++++++++++----------- rocky/requirements.txt | 126 +++++++++++----------- 24 files changed, 981 insertions(+), 974 deletions(-) diff --git a/boefjes/poetry.lock b/boefjes/poetry.lock index 4c94dba54ea..5c2f6c5c243 100644 --- a/boefjes/poetry.lock +++ b/boefjes/poetry.lock @@ -1434,42 +1434,42 @@ files = [ [[package]] name = "opentelemetry-api" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, - {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, + {file = "opentelemetry_api-1.26.0-py3-none-any.whl", hash = "sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064"}, + {file = "opentelemetry_api-1.26.0.tar.gz", hash = "sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.1" +importlib-metadata = ">=6.0,<=8.0.0" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Protobuf encoding" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0-py3-none-any.whl", hash = "sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0.tar.gz", hash = "sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92"}, ] [package.dependencies] -opentelemetry-proto = "1.25.0" +opentelemetry-proto = "1.26.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0-py3-none-any.whl", hash = "sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0.tar.gz", hash = "sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae"}, ] [package.dependencies] @@ -1477,19 +1477,19 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.25.0" -opentelemetry-proto = "1.25.0" -opentelemetry-sdk = ">=1.25.0,<1.26.0" +opentelemetry-exporter-otlp-proto-common = "1.26.0" +opentelemetry-proto = "1.26.0" +opentelemetry-sdk = ">=1.26.0,<1.27.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.46b0" +version = "0.47b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, - {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, + {file = "opentelemetry_instrumentation-0.47b0-py3-none-any.whl", hash = "sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5"}, + {file = "opentelemetry_instrumentation-0.47b0.tar.gz", hash = "sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f"}, ] [package.dependencies] @@ -1499,111 +1499,111 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.46b0" +version = "0.47b0" description = "ASGI instrumentation for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_asgi-0.46b0-py3-none-any.whl", hash = "sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759"}, - {file = "opentelemetry_instrumentation_asgi-0.46b0.tar.gz", hash = "sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0-py3-none-any.whl", hash = "sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0.tar.gz", hash = "sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a"}, ] [package.dependencies] asgiref = ">=3.0,<4.0" opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] instruments = ["asgiref (>=3.0,<4.0)"] [[package]] name = "opentelemetry-instrumentation-dbapi" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry Database API instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_dbapi-0.46b0-py3-none-any.whl", hash = "sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783"}, - {file = "opentelemetry_instrumentation_dbapi-0.46b0.tar.gz", hash = "sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92"}, + {file = "opentelemetry_instrumentation_dbapi-0.47b0-py3-none-any.whl", hash = "sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f"}, + {file = "opentelemetry_instrumentation_dbapi-0.47b0.tar.gz", hash = "sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry FastAPI Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_fastapi-0.46b0-py3-none-any.whl", hash = "sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33"}, - {file = "opentelemetry_instrumentation_fastapi-0.46b0.tar.gz", hash = "sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0-py3-none-any.whl", hash = "sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0.tar.gz", hash = "sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-instrumentation-asgi = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-asgi = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] -instruments = ["fastapi (>=0.58,<1.0)"] +instruments = ["fastapi (>=0.58,<1.0)", "fastapi-slim (>=0.111.0,<0.112.0)"] [[package]] name = "opentelemetry-instrumentation-psycopg2" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry psycopg2 instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_psycopg2-0.46b0-py3-none-any.whl", hash = "sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899"}, - {file = "opentelemetry_instrumentation_psycopg2-0.46b0.tar.gz", hash = "sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c"}, + {file = "opentelemetry_instrumentation_psycopg2-0.47b0-py3-none-any.whl", hash = "sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73"}, + {file = "opentelemetry_instrumentation_psycopg2-0.47b0.tar.gz", hash = "sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-instrumentation-dbapi = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-dbapi = "0.47b0" [package.extras] instruments = ["psycopg2 (>=2.7.3.1)"] [[package]] name = "opentelemetry-instrumentation-requests" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry requests instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_requests-0.46b0-py3-none-any.whl", hash = "sha256:a8c2472800d8686f3f286cd524b8746b386154092e85a791ba14110d1acc9b81"}, - {file = "opentelemetry_instrumentation_requests-0.46b0.tar.gz", hash = "sha256:ef0ad63bfd0d52631daaf7d687e763dbd89b465f5cb052f12a4e67e5e3d181e4"}, + {file = "opentelemetry_instrumentation_requests-0.47b0-py3-none-any.whl", hash = "sha256:77fdd13f64fef2cb44665fe6975eadb993d78f96612e55a502e79b34ef7fee47"}, + {file = "opentelemetry_instrumentation_requests-0.47b0.tar.gz", hash = "sha256:f85ed52cbca21bff226e0e7f1888e5b9bc386657ecf4b0440f328e5b3aba8436"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] instruments = ["requests (>=2.0,<3.0)"] [[package]] name = "opentelemetry-proto" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python Proto" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, - {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, + {file = "opentelemetry_proto-1.26.0-py3-none-any.whl", hash = "sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725"}, + {file = "opentelemetry_proto-1.26.0.tar.gz", hash = "sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e"}, ] [package.dependencies] @@ -1611,43 +1611,44 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, - {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, + {file = "opentelemetry_sdk-1.26.0-py3-none-any.whl", hash = "sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897"}, + {file = "opentelemetry_sdk-1.26.0.tar.gz", hash = "sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85"}, ] [package.dependencies] -opentelemetry-api = "1.25.0" -opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-api = "1.26.0" +opentelemetry-semantic-conventions = "0.47b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, - {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, + {file = "opentelemetry_semantic_conventions-0.47b0-py3-none-any.whl", hash = "sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063"}, + {file = "opentelemetry_semantic_conventions-0.47b0.tar.gz", hash = "sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e"}, ] [package.dependencies] -opentelemetry-api = "1.25.0" +deprecated = ">=1.2.6" +opentelemetry-api = "1.26.0" [[package]] name = "opentelemetry-util-http" -version = "0.46b0" +version = "0.47b0" description = "Web util for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"}, - {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"}, + {file = "opentelemetry_util_http-0.47b0-py3-none-any.whl", hash = "sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19"}, + {file = "opentelemetry_util_http-0.47b0.tar.gz", hash = "sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32"}, ] [[package]] @@ -2867,4 +2868,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "ceca67cd5b37f76d5657ab8bf5e5bb9452ff15071fa08d55a0d02a1e67acd9d3" +content-hash = "3952e6eeb2307fcd6ac25bb54625a4e5cf47ac363bfbae0a1825859072eb9c95" diff --git a/boefjes/pyproject.toml b/boefjes/pyproject.toml index ccd0bf7d8fa..bec30a07305 100644 --- a/boefjes/pyproject.toml +++ b/boefjes/pyproject.toml @@ -18,12 +18,12 @@ pynacl = "^1.5.0" sqlalchemy = "^1.4.48" python-dateutil = "^2.8.2" pydantic-settings = "^2.2.1" -opentelemetry-sdk = "^1.25.0" -opentelemetry-exporter-otlp-proto-grpc = "^1.25.0" -opentelemetry-instrumentation-fastapi = "^0.46b0" -opentelemetry-instrumentation-psycopg2 = "^0.46b0" -opentelemetry-instrumentation-requests = "^0.46b0" -opentelemetry-instrumentation = "^0.46b0" +opentelemetry-sdk = "^1.26.0" +opentelemetry-exporter-otlp-proto-grpc = "^1.26.0" +opentelemetry-instrumentation-fastapi = "^0.47b0" +opentelemetry-instrumentation-psycopg2 = "^0.47b0" +opentelemetry-instrumentation-requests = "^0.47b0" +opentelemetry-instrumentation = "^0.47b0" # required by kat_snyk, kat_crt_sh, kat_crt_sh boefjes requests = "^2.32.1" # required by kat_binaryedge boefje @@ -62,13 +62,13 @@ defusedxml = "^0.7.1" # required by kat_webpage_analysis/check_images normalizer pillow = "^10.3.0" httpx = "^0.27.0" -opentelemetry-api = "^1.25.0" -opentelemetry-exporter-otlp-proto-common = "^1.25.0" -opentelemetry-instrumentation-asgi = "^0.46b0" -opentelemetry-instrumentation-dbapi = "^0.46b0" -opentelemetry-proto = "^1.25.0" -opentelemetry-semantic-conventions = "^0.46b0" -opentelemetry-util-http = "^0.46b0" +opentelemetry-api = "^1.26.0" +opentelemetry-exporter-otlp-proto-common = "^1.26.0" +opentelemetry-instrumentation-asgi = "^0.47b0" +opentelemetry-instrumentation-dbapi = "^0.47b0" +opentelemetry-proto = "^1.26.0" +opentelemetry-semantic-conventions = "^0.47b0" +opentelemetry-util-http = "^0.47b0" fastapi-slim = "^0.111.0" structlog = "^24.2.0" diff --git a/boefjes/requirements-dev.txt b/boefjes/requirements-dev.txt index e318b297e05..2b1f8edfb5f 100644 --- a/boefjes/requirements-dev.txt +++ b/boefjes/requirements-dev.txt @@ -797,45 +797,45 @@ multidict==6.0.5 ; python_version >= "3.10" and python_version < "4.0" \ netaddr==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5148b1055679d2a1ec070c521b7db82137887fabd6d7e37f5199b44f775c3bb1 \ --hash=sha256:7b46fa9b1a2d71fd5de9e4a3784ef339700a53a08c8040f08baf5f1194da0128 -opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ - --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 -opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ - --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 -opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ - --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac -opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ - --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 -opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ - --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 -opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ - --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 -opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ - --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c -opentelemetry-instrumentation-requests==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:a8c2472800d8686f3f286cd524b8746b386154092e85a791ba14110d1acc9b81 \ - --hash=sha256:ef0ad63bfd0d52631daaf7d687e763dbd89b465f5cb052f12a4e67e5e3d181e4 -opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ - --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda -opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ - --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f -opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ - --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 -opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ - --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa -opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ - --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-dbapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f \ + --hash=sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50 +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation-psycopg2==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8 \ + --hash=sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73 +opentelemetry-instrumentation-requests==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:77fdd13f64fef2cb44665fe6975eadb993d78f96612e55a502e79b34ef7fee47 \ + --hash=sha256:f85ed52cbca21bff226e0e7f1888e5b9bc386657ecf4b0440f328e5b3aba8436 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 diff --git a/boefjes/requirements.txt b/boefjes/requirements.txt index 567e74596e3..e1cb8dbf195 100644 --- a/boefjes/requirements.txt +++ b/boefjes/requirements.txt @@ -794,45 +794,45 @@ multidict==6.0.5 ; python_version >= "3.10" and python_version < "4.0" \ netaddr==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5148b1055679d2a1ec070c521b7db82137887fabd6d7e37f5199b44f775c3bb1 \ --hash=sha256:7b46fa9b1a2d71fd5de9e4a3784ef339700a53a08c8040f08baf5f1194da0128 -opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ - --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 -opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ - --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 -opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ - --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac -opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ - --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 -opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ - --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 -opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ - --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 -opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ - --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c -opentelemetry-instrumentation-requests==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:a8c2472800d8686f3f286cd524b8746b386154092e85a791ba14110d1acc9b81 \ - --hash=sha256:ef0ad63bfd0d52631daaf7d687e763dbd89b465f5cb052f12a4e67e5e3d181e4 -opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ - --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda -opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ - --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f -opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ - --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 -opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ - --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa -opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ - --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-dbapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f \ + --hash=sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50 +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation-psycopg2==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8 \ + --hash=sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73 +opentelemetry-instrumentation-requests==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:77fdd13f64fef2cb44665fe6975eadb993d78f96612e55a502e79b34ef7fee47 \ + --hash=sha256:f85ed52cbca21bff226e0e7f1888e5b9bc386657ecf4b0440f328e5b3aba8436 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 diff --git a/bytes/poetry.lock b/bytes/poetry.lock index 4795e6c1abc..fb08d04e90f 100644 --- a/bytes/poetry.lock +++ b/bytes/poetry.lock @@ -765,42 +765,42 @@ files = [ [[package]] name = "opentelemetry-api" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, - {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, + {file = "opentelemetry_api-1.26.0-py3-none-any.whl", hash = "sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064"}, + {file = "opentelemetry_api-1.26.0.tar.gz", hash = "sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.1" +importlib-metadata = ">=6.0,<=8.0.0" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Protobuf encoding" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0-py3-none-any.whl", hash = "sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0.tar.gz", hash = "sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92"}, ] [package.dependencies] -opentelemetry-proto = "1.25.0" +opentelemetry-proto = "1.26.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0-py3-none-any.whl", hash = "sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0.tar.gz", hash = "sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae"}, ] [package.dependencies] @@ -808,19 +808,19 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.25.0" -opentelemetry-proto = "1.25.0" -opentelemetry-sdk = ">=1.25.0,<1.26.0" +opentelemetry-exporter-otlp-proto-common = "1.26.0" +opentelemetry-proto = "1.26.0" +opentelemetry-sdk = ">=1.26.0,<1.27.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.46b0" +version = "0.47b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, - {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, + {file = "opentelemetry_instrumentation-0.47b0-py3-none-any.whl", hash = "sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5"}, + {file = "opentelemetry_instrumentation-0.47b0.tar.gz", hash = "sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f"}, ] [package.dependencies] @@ -830,111 +830,111 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.46b0" +version = "0.47b0" description = "ASGI instrumentation for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_asgi-0.46b0-py3-none-any.whl", hash = "sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759"}, - {file = "opentelemetry_instrumentation_asgi-0.46b0.tar.gz", hash = "sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0-py3-none-any.whl", hash = "sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0.tar.gz", hash = "sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a"}, ] [package.dependencies] asgiref = ">=3.0,<4.0" opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] instruments = ["asgiref (>=3.0,<4.0)"] [[package]] name = "opentelemetry-instrumentation-dbapi" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry Database API instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_dbapi-0.46b0-py3-none-any.whl", hash = "sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783"}, - {file = "opentelemetry_instrumentation_dbapi-0.46b0.tar.gz", hash = "sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92"}, + {file = "opentelemetry_instrumentation_dbapi-0.47b0-py3-none-any.whl", hash = "sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f"}, + {file = "opentelemetry_instrumentation_dbapi-0.47b0.tar.gz", hash = "sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry FastAPI Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_fastapi-0.46b0-py3-none-any.whl", hash = "sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33"}, - {file = "opentelemetry_instrumentation_fastapi-0.46b0.tar.gz", hash = "sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0-py3-none-any.whl", hash = "sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0.tar.gz", hash = "sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-instrumentation-asgi = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-asgi = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] -instruments = ["fastapi (>=0.58,<1.0)"] +instruments = ["fastapi (>=0.58,<1.0)", "fastapi-slim (>=0.111.0,<0.112.0)"] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry HTTPX Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_httpx-0.46b0-py3-none-any.whl", hash = "sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc"}, - {file = "opentelemetry_instrumentation_httpx-0.46b0.tar.gz", hash = "sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109"}, + {file = "opentelemetry_instrumentation_httpx-0.47b0-py3-none-any.whl", hash = "sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a"}, + {file = "opentelemetry_instrumentation_httpx-0.47b0.tar.gz", hash = "sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] instruments = ["httpx (>=0.18.0)"] [[package]] name = "opentelemetry-instrumentation-psycopg2" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry psycopg2 instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_psycopg2-0.46b0-py3-none-any.whl", hash = "sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899"}, - {file = "opentelemetry_instrumentation_psycopg2-0.46b0.tar.gz", hash = "sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c"}, + {file = "opentelemetry_instrumentation_psycopg2-0.47b0-py3-none-any.whl", hash = "sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73"}, + {file = "opentelemetry_instrumentation_psycopg2-0.47b0.tar.gz", hash = "sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-instrumentation-dbapi = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-dbapi = "0.47b0" [package.extras] instruments = ["psycopg2 (>=2.7.3.1)"] [[package]] name = "opentelemetry-proto" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python Proto" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, - {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, + {file = "opentelemetry_proto-1.26.0-py3-none-any.whl", hash = "sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725"}, + {file = "opentelemetry_proto-1.26.0.tar.gz", hash = "sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e"}, ] [package.dependencies] @@ -942,43 +942,44 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, - {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, + {file = "opentelemetry_sdk-1.26.0-py3-none-any.whl", hash = "sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897"}, + {file = "opentelemetry_sdk-1.26.0.tar.gz", hash = "sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85"}, ] [package.dependencies] -opentelemetry-api = "1.25.0" -opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-api = "1.26.0" +opentelemetry-semantic-conventions = "0.47b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, - {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, + {file = "opentelemetry_semantic_conventions-0.47b0-py3-none-any.whl", hash = "sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063"}, + {file = "opentelemetry_semantic_conventions-0.47b0.tar.gz", hash = "sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e"}, ] [package.dependencies] -opentelemetry-api = "1.25.0" +deprecated = ">=1.2.6" +opentelemetry-api = "1.26.0" [[package]] name = "opentelemetry-util-http" -version = "0.46b0" +version = "0.47b0" description = "Web util for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"}, - {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"}, + {file = "opentelemetry_util_http-0.47b0-py3-none-any.whl", hash = "sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19"}, + {file = "opentelemetry_util_http-0.47b0.tar.gz", hash = "sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32"}, ] [[package]] @@ -1726,4 +1727,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "c3e05238b348fa7444098c8e005dee50e9f1d3e755d593b849d70fafcd7ccbdd" +content-hash = "7ef39a1dd3debd0780dd3f7395ce81de4117baabb00858acecad8e43f3c54f92" diff --git a/bytes/pyproject.toml b/bytes/pyproject.toml index 37b3c4fc832..526590bc541 100644 --- a/bytes/pyproject.toml +++ b/bytes/pyproject.toml @@ -20,22 +20,22 @@ sqlalchemy = "^1.4.48" uvicorn = "^0.29.0" # OpenTelemetry -opentelemetry-sdk = "^1.25.0" -opentelemetry-exporter-otlp-proto-grpc = "^1.25.0" -opentelemetry-instrumentation-fastapi = "^0.46b0" -opentelemetry-instrumentation-psycopg2 = "^0.46b0" -opentelemetry-instrumentation-httpx = "^0.46b0" -opentelemetry-instrumentation = "^0.46b0" -opentelemetry-instrumentation-dbapi = "^0.46b0" +opentelemetry-sdk = "^1.26.0" +opentelemetry-exporter-otlp-proto-grpc = "^1.26.0" +opentelemetry-instrumentation-fastapi = "^0.47b0" +opentelemetry-instrumentation-psycopg2 = "^0.47b0" +opentelemetry-instrumentation-httpx = "^0.47b0" +opentelemetry-instrumentation = "^0.47b0" +opentelemetry-instrumentation-dbapi = "^0.47b0" pydantic-settings = "^2.2.1" python-multipart = "^0.0.9" httpx = "^0.27.0" -opentelemetry-api = "^1.25.0" -opentelemetry-exporter-otlp-proto-common = "^1.25.0" -opentelemetry-instrumentation-asgi = "^0.46b0" -opentelemetry-proto = "^1.25.0" -opentelemetry-semantic-conventions = "^0.46b0" -opentelemetry-util-http = "^0.46b0" +opentelemetry-api = "^1.26.0" +opentelemetry-exporter-otlp-proto-common = "^1.26.0" +opentelemetry-instrumentation-asgi = "^0.47b0" +opentelemetry-proto = "^1.26.0" +opentelemetry-semantic-conventions = "^0.47b0" +opentelemetry-util-http = "^0.47b0" pyjwt = "^2.8.0" fastapi-slim = "^0.111.0" structlog = "^24.2.0" diff --git a/bytes/requirements-dev.txt b/bytes/requirements-dev.txt index 63e110a28f2..31734684fa1 100644 --- a/bytes/requirements-dev.txt +++ b/bytes/requirements-dev.txt @@ -435,45 +435,45 @@ markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 -opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ - --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 -opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ - --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 -opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ - --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac -opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ - --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 -opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ - --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 -opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ - --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 -opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ - --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 -opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ - --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c -opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ - --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda -opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ - --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f -opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ - --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 -opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ - --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa -opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ - --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-dbapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f \ + --hash=sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50 +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation-httpx==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a \ + --hash=sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d +opentelemetry-instrumentation-psycopg2==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8 \ + --hash=sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 diff --git a/bytes/requirements.txt b/bytes/requirements.txt index 9af7b447f78..081e53580f3 100644 --- a/bytes/requirements.txt +++ b/bytes/requirements.txt @@ -432,45 +432,45 @@ markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 -opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ - --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 -opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ - --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 -opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ - --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac -opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ - --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 -opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ - --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 -opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ - --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 -opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ - --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 -opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ - --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c -opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ - --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda -opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ - --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f -opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ - --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 -opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ - --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa -opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ - --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-dbapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f \ + --hash=sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50 +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation-httpx==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a \ + --hash=sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d +opentelemetry-instrumentation-psycopg2==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8 \ + --hash=sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 passlib[bcrypt]==1.7.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1 \ --hash=sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04 diff --git a/keiko/poetry.lock b/keiko/poetry.lock index 22894444884..ec7ce83a107 100644 --- a/keiko/poetry.lock +++ b/keiko/poetry.lock @@ -539,42 +539,42 @@ files = [ [[package]] name = "opentelemetry-api" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, - {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, + {file = "opentelemetry_api-1.26.0-py3-none-any.whl", hash = "sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064"}, + {file = "opentelemetry_api-1.26.0.tar.gz", hash = "sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.1" +importlib-metadata = ">=6.0,<=8.0.0" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Protobuf encoding" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0-py3-none-any.whl", hash = "sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0.tar.gz", hash = "sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92"}, ] [package.dependencies] -opentelemetry-proto = "1.25.0" +opentelemetry-proto = "1.26.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0-py3-none-any.whl", hash = "sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0.tar.gz", hash = "sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae"}, ] [package.dependencies] @@ -582,19 +582,19 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.25.0" -opentelemetry-proto = "1.25.0" -opentelemetry-sdk = ">=1.25.0,<1.26.0" +opentelemetry-exporter-otlp-proto-common = "1.26.0" +opentelemetry-proto = "1.26.0" +opentelemetry-sdk = ">=1.26.0,<1.27.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.46b0" +version = "0.47b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, - {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, + {file = "opentelemetry_instrumentation-0.47b0-py3-none-any.whl", hash = "sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5"}, + {file = "opentelemetry_instrumentation-0.47b0.tar.gz", hash = "sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f"}, ] [package.dependencies] @@ -604,55 +604,55 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.46b0" +version = "0.47b0" description = "ASGI instrumentation for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_asgi-0.46b0-py3-none-any.whl", hash = "sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759"}, - {file = "opentelemetry_instrumentation_asgi-0.46b0.tar.gz", hash = "sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0-py3-none-any.whl", hash = "sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0.tar.gz", hash = "sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a"}, ] [package.dependencies] asgiref = ">=3.0,<4.0" opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] instruments = ["asgiref (>=3.0,<4.0)"] [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry FastAPI Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_fastapi-0.46b0-py3-none-any.whl", hash = "sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33"}, - {file = "opentelemetry_instrumentation_fastapi-0.46b0.tar.gz", hash = "sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0-py3-none-any.whl", hash = "sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0.tar.gz", hash = "sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-instrumentation-asgi = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-asgi = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] -instruments = ["fastapi (>=0.58,<1.0)"] +instruments = ["fastapi (>=0.58,<1.0)", "fastapi-slim (>=0.111.0,<0.112.0)"] [[package]] name = "opentelemetry-proto" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python Proto" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, - {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, + {file = "opentelemetry_proto-1.26.0-py3-none-any.whl", hash = "sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725"}, + {file = "opentelemetry_proto-1.26.0.tar.gz", hash = "sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e"}, ] [package.dependencies] @@ -660,43 +660,44 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, - {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, + {file = "opentelemetry_sdk-1.26.0-py3-none-any.whl", hash = "sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897"}, + {file = "opentelemetry_sdk-1.26.0.tar.gz", hash = "sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85"}, ] [package.dependencies] -opentelemetry-api = "1.25.0" -opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-api = "1.26.0" +opentelemetry-semantic-conventions = "0.47b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, - {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, + {file = "opentelemetry_semantic_conventions-0.47b0-py3-none-any.whl", hash = "sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063"}, + {file = "opentelemetry_semantic_conventions-0.47b0.tar.gz", hash = "sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e"}, ] [package.dependencies] -opentelemetry-api = "1.25.0" +deprecated = ">=1.2.6" +opentelemetry-api = "1.26.0" [[package]] name = "opentelemetry-util-http" -version = "0.46b0" +version = "0.47b0" description = "Web util for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"}, - {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"}, + {file = "opentelemetry_util_http-0.47b0-py3-none-any.whl", hash = "sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19"}, + {file = "opentelemetry_util_http-0.47b0.tar.gz", hash = "sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32"}, ] [[package]] @@ -1315,4 +1316,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "014adceea18ed897ba06e5ce5deeb628cf57e366fc3c3ab2c58b4f9ec18012d0" +content-hash = "7338400214b2a3115ffcedd084b7c3c1fc5468720e4f130ffd52efa23d6128c5" diff --git a/keiko/pyproject.toml b/keiko/pyproject.toml index 84abdf5f88b..0fc91c44dec 100644 --- a/keiko/pyproject.toml +++ b/keiko/pyproject.toml @@ -11,18 +11,18 @@ click = "^8.1.3" pydantic = "^2.6.0" Jinja2 = "^3.1.3" uvicorn = "^0.29.0" -opentelemetry-sdk = "^1.25.0" -opentelemetry-exporter-otlp-proto-grpc = "^1.25.0" -opentelemetry-instrumentation-fastapi = "^0.46b0" -opentelemetry-instrumentation = "^0.46b0" +opentelemetry-sdk = "^1.26.0" +opentelemetry-exporter-otlp-proto-grpc = "^1.26.0" +opentelemetry-instrumentation-fastapi = "^0.47b0" +opentelemetry-instrumentation = "^0.47b0" pydantic-settings = "^2.0.3" fastapi-slim = "^0.111.0" -opentelemetry-api = "^1.25.0" -opentelemetry-exporter-otlp-proto-common = "^1.25.0" -opentelemetry-instrumentation-asgi = "^0.46b0" -opentelemetry-proto = "^1.25.0" -opentelemetry-semantic-conventions = "^0.46b0" -opentelemetry-util-http = "^0.46b0" +opentelemetry-api = "^1.26.0" +opentelemetry-exporter-otlp-proto-common = "^1.26.0" +opentelemetry-instrumentation-asgi = "^0.47b0" +opentelemetry-proto = "^1.26.0" +opentelemetry-semantic-conventions = "^0.47b0" +opentelemetry-util-http = "^0.47b0" [tool.poetry.group.dev.dependencies] pytest = "^8.0.0" diff --git a/keiko/requirements-dev.txt b/keiko/requirements-dev.txt index 86d30ecf461..6554f943a3a 100644 --- a/keiko/requirements-dev.txt +++ b/keiko/requirements-dev.txt @@ -262,36 +262,36 @@ markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0" \ mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba -opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ - --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 -opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ - --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 -opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ - --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac -opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ - --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 -opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ - --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 -opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ - --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda -opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ - --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f -opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ - --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 -opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ - --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa -opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ - --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 diff --git a/keiko/requirements.txt b/keiko/requirements.txt index 777c3e3b7fb..4b81b80619b 100644 --- a/keiko/requirements.txt +++ b/keiko/requirements.txt @@ -153,36 +153,36 @@ markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 -opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ - --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 -opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ - --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 -opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ - --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac -opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ - --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 -opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ - --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 -opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ - --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda -opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ - --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f -opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ - --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 -opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ - --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa -opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ - --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 protobuf==4.25.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4 \ --hash=sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8 \ diff --git a/mula/poetry.lock b/mula/poetry.lock index a200c910748..cc26d9b7fb4 100644 --- a/mula/poetry.lock +++ b/mula/poetry.lock @@ -691,42 +691,42 @@ test = ["mypy (>=1.0)", "pytest (>=7.0.0)"] [[package]] name = "opentelemetry-api" -version = "1.24.0" +version = "1.26.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.24.0-py3-none-any.whl", hash = "sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2"}, - {file = "opentelemetry_api-1.24.0.tar.gz", hash = "sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e"}, + {file = "opentelemetry_api-1.26.0-py3-none-any.whl", hash = "sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064"}, + {file = "opentelemetry_api-1.26.0.tar.gz", hash = "sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.0" +importlib-metadata = ">=6.0,<=8.0.0" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.24.0" +version = "1.26.0" description = "OpenTelemetry Protobuf encoding" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0-py3-none-any.whl", hash = "sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0.tar.gz", hash = "sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0-py3-none-any.whl", hash = "sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0.tar.gz", hash = "sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92"}, ] [package.dependencies] -opentelemetry-proto = "1.24.0" +opentelemetry-proto = "1.26.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.24.0" +version = "1.26.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0-py3-none-any.whl", hash = "sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0.tar.gz", hash = "sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0-py3-none-any.whl", hash = "sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0.tar.gz", hash = "sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae"}, ] [package.dependencies] @@ -734,22 +734,19 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.24.0" -opentelemetry-proto = "1.24.0" -opentelemetry-sdk = ">=1.24.0,<1.25.0" - -[package.extras] -test = ["pytest-grpc"] +opentelemetry-exporter-otlp-proto-common = "1.26.0" +opentelemetry-proto = "1.26.0" +opentelemetry-sdk = ">=1.26.0,<1.27.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.45b0" +version = "0.47b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.45b0-py3-none-any.whl", hash = "sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258"}, - {file = "opentelemetry_instrumentation-0.45b0.tar.gz", hash = "sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e"}, + {file = "opentelemetry_instrumentation-0.47b0-py3-none-any.whl", hash = "sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5"}, + {file = "opentelemetry_instrumentation-0.47b0.tar.gz", hash = "sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f"}, ] [package.dependencies] @@ -759,111 +756,111 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.45b0" +version = "0.47b0" description = "ASGI instrumentation for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_asgi-0.45b0-py3-none-any.whl", hash = "sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b"}, - {file = "opentelemetry_instrumentation_asgi-0.45b0.tar.gz", hash = "sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0-py3-none-any.whl", hash = "sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0.tar.gz", hash = "sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a"}, ] [package.dependencies] asgiref = ">=3.0,<4.0" opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] instruments = ["asgiref (>=3.0,<4.0)"] [[package]] name = "opentelemetry-instrumentation-dbapi" -version = "0.45b0" +version = "0.47b0" description = "OpenTelemetry Database API instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_dbapi-0.45b0-py3-none-any.whl", hash = "sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618"}, - {file = "opentelemetry_instrumentation_dbapi-0.45b0.tar.gz", hash = "sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c"}, + {file = "opentelemetry_instrumentation_dbapi-0.47b0-py3-none-any.whl", hash = "sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f"}, + {file = "opentelemetry_instrumentation_dbapi-0.47b0.tar.gz", hash = "sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.45b0" +version = "0.47b0" description = "OpenTelemetry FastAPI Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_fastapi-0.45b0-py3-none-any.whl", hash = "sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314"}, - {file = "opentelemetry_instrumentation_fastapi-0.45b0.tar.gz", hash = "sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0-py3-none-any.whl", hash = "sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0.tar.gz", hash = "sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-instrumentation-asgi = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-asgi = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] -instruments = ["fastapi (>=0.58,<1.0)"] +instruments = ["fastapi (>=0.58,<1.0)", "fastapi-slim (>=0.111.0,<0.112.0)"] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.45b0" +version = "0.47b0" description = "OpenTelemetry HTTPX Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_httpx-0.45b0-py3-none-any.whl", hash = "sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225"}, - {file = "opentelemetry_instrumentation_httpx-0.45b0.tar.gz", hash = "sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d"}, + {file = "opentelemetry_instrumentation_httpx-0.47b0-py3-none-any.whl", hash = "sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a"}, + {file = "opentelemetry_instrumentation_httpx-0.47b0.tar.gz", hash = "sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-semantic-conventions = "0.45b0" -opentelemetry-util-http = "0.45b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] instruments = ["httpx (>=0.18.0)"] [[package]] name = "opentelemetry-instrumentation-psycopg2" -version = "0.45b0" +version = "0.47b0" description = "OpenTelemetry psycopg2 instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_psycopg2-0.45b0-py3-none-any.whl", hash = "sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7"}, - {file = "opentelemetry_instrumentation_psycopg2-0.45b0.tar.gz", hash = "sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0"}, + {file = "opentelemetry_instrumentation_psycopg2-0.47b0-py3-none-any.whl", hash = "sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73"}, + {file = "opentelemetry_instrumentation_psycopg2-0.47b0.tar.gz", hash = "sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.45b0" -opentelemetry-instrumentation-dbapi = "0.45b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-dbapi = "0.47b0" [package.extras] instruments = ["psycopg2 (>=2.7.3.1)"] [[package]] name = "opentelemetry-proto" -version = "1.24.0" +version = "1.26.0" description = "OpenTelemetry Python Proto" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.24.0-py3-none-any.whl", hash = "sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce"}, - {file = "opentelemetry_proto-1.24.0.tar.gz", hash = "sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8"}, + {file = "opentelemetry_proto-1.26.0-py3-none-any.whl", hash = "sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725"}, + {file = "opentelemetry_proto-1.26.0.tar.gz", hash = "sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e"}, ] [package.dependencies] @@ -871,40 +868,44 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.24.0" +version = "1.26.0" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.24.0-py3-none-any.whl", hash = "sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59"}, - {file = "opentelemetry_sdk-1.24.0.tar.gz", hash = "sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5"}, + {file = "opentelemetry_sdk-1.26.0-py3-none-any.whl", hash = "sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897"}, + {file = "opentelemetry_sdk-1.26.0.tar.gz", hash = "sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85"}, ] [package.dependencies] -opentelemetry-api = "1.24.0" -opentelemetry-semantic-conventions = "0.45b0" +opentelemetry-api = "1.26.0" +opentelemetry-semantic-conventions = "0.47b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.45b0" +version = "0.47b0" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.45b0-py3-none-any.whl", hash = "sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864"}, - {file = "opentelemetry_semantic_conventions-0.45b0.tar.gz", hash = "sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118"}, + {file = "opentelemetry_semantic_conventions-0.47b0-py3-none-any.whl", hash = "sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063"}, + {file = "opentelemetry_semantic_conventions-0.47b0.tar.gz", hash = "sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e"}, ] +[package.dependencies] +deprecated = ">=1.2.6" +opentelemetry-api = "1.26.0" + [[package]] name = "opentelemetry-util-http" -version = "0.45b0" +version = "0.47b0" description = "Web util for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_util_http-0.45b0-py3-none-any.whl", hash = "sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33"}, - {file = "opentelemetry_util_http-0.45b0.tar.gz", hash = "sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd"}, + {file = "opentelemetry_util_http-0.47b0-py3-none-any.whl", hash = "sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19"}, + {file = "opentelemetry_util_http-0.47b0.tar.gz", hash = "sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32"}, ] [[package]] @@ -1553,4 +1554,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "4add867f92b5e2de3c528c4328696a0014bd96946d0d323473a3e1e782500c62" +content-hash = "0774b92f71998642b563e29043f09810f92a2fee9db1bcbfbaaa6f2ee59fecc5" diff --git a/mula/pyproject.toml b/mula/pyproject.toml index ed1bbb5d8b0..68e7a15a09f 100644 --- a/mula/pyproject.toml +++ b/mula/pyproject.toml @@ -22,19 +22,19 @@ uvicorn = "^0.29.0" httpx = "^0.27.0" # OpenTelemetry -opentelemetry-sdk = "^1.24.0" -opentelemetry-exporter-otlp-proto-grpc = "^1.24.0" -opentelemetry-instrumentation-fastapi = "^0.45b0" -opentelemetry-instrumentation-psycopg2 = "^0.45b0" -opentelemetry-instrumentation = "^0.45b0" -opentelemetry-instrumentation-httpx = "^0.45b0" -opentelemetry-api = "^1.24.0" -opentelemetry-exporter-otlp-proto-common = "^1.24.0" -opentelemetry-instrumentation-asgi = "^0.45b0" -opentelemetry-instrumentation-dbapi = "^0.45b0" -opentelemetry-proto = "^1.24.0" -opentelemetry-semantic-conventions = "^0.45b0" -opentelemetry-util-http = "^0.45b0" +opentelemetry-sdk = "^1.26.0" +opentelemetry-exporter-otlp-proto-grpc = "^1.26.0" +opentelemetry-instrumentation-fastapi = "^0.47b0" +opentelemetry-instrumentation-psycopg2 = "^0.47b0" +opentelemetry-instrumentation = "^0.47b0" +opentelemetry-instrumentation-httpx = "^0.47b0" +opentelemetry-api = "^1.26.0" +opentelemetry-exporter-otlp-proto-common = "^1.26.0" +opentelemetry-instrumentation-asgi = "^0.47b0" +opentelemetry-instrumentation-dbapi = "^0.47b0" +opentelemetry-proto = "^1.26.0" +opentelemetry-semantic-conventions = "^0.47b0" +opentelemetry-util-http = "^0.47b0" fastapi-slim = "^0.111.0" [tool.poetry.group.dev.dependencies] diff --git a/mula/requirements-dev.txt b/mula/requirements-dev.txt index c5368ace86a..a2516af05ad 100644 --- a/mula/requirements-dev.txt +++ b/mula/requirements-dev.txt @@ -362,45 +362,45 @@ mmh3==4.1.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f90938ff137130e47bcec8dc1f4ceb02f10178c766e2ef58a9f657ff1f62d124 \ --hash=sha256:fa7eacd2b830727ba3dd65a365bed8a5c992ecd0c8348cf39a05cc77d22f4970 \ --hash=sha256:fefef92e9c544a8dbc08f77a8d1b6d48006a750c4375bbcd5ff8199d761e263b -opentelemetry-api==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2 \ - --hash=sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e -opentelemetry-exporter-otlp-proto-common==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461 \ - --hash=sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641 -opentelemetry-exporter-otlp-proto-grpc==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa \ - --hash=sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b -opentelemetry-instrumentation-asgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b \ - --hash=sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6 -opentelemetry-instrumentation-dbapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618 \ - --hash=sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c -opentelemetry-instrumentation-fastapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e \ - --hash=sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314 -opentelemetry-instrumentation-httpx==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d \ - --hash=sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225 -opentelemetry-instrumentation-psycopg2==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7 \ - --hash=sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0 -opentelemetry-instrumentation==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258 \ - --hash=sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e -opentelemetry-proto==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce \ - --hash=sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8 -opentelemetry-sdk==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5 \ - --hash=sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59 -opentelemetry-semantic-conventions==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118 \ - --hash=sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864 -opentelemetry-util-http==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd \ - --hash=sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-dbapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f \ + --hash=sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50 +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation-httpx==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a \ + --hash=sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d +opentelemetry-instrumentation-psycopg2==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8 \ + --hash=sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 packaging==24.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 diff --git a/mula/requirements.txt b/mula/requirements.txt index dd7846f82af..4b3897ff456 100644 --- a/mula/requirements.txt +++ b/mula/requirements.txt @@ -300,45 +300,45 @@ mmh3==4.1.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f90938ff137130e47bcec8dc1f4ceb02f10178c766e2ef58a9f657ff1f62d124 \ --hash=sha256:fa7eacd2b830727ba3dd65a365bed8a5c992ecd0c8348cf39a05cc77d22f4970 \ --hash=sha256:fefef92e9c544a8dbc08f77a8d1b6d48006a750c4375bbcd5ff8199d761e263b -opentelemetry-api==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2 \ - --hash=sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e -opentelemetry-exporter-otlp-proto-common==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461 \ - --hash=sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641 -opentelemetry-exporter-otlp-proto-grpc==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa \ - --hash=sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b -opentelemetry-instrumentation-asgi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8be1157ed62f0db24e45fdf7933c530c4338bd025c5d4af7830e903c0756021b \ - --hash=sha256:97f55620f163fd3d20323e9fd8dc3aacc826c03397213ff36b877e0f4b6b08a6 -opentelemetry-instrumentation-dbapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0678578d6a98300841b8ed743724ad17a9fb3a555a7cfc0f6bb61e8441c94618 \ - --hash=sha256:f6753e13548e45a9cf86f92eaa6e9cd9a8803a56376819c7f7e6ea1aa7ff984c -opentelemetry-instrumentation-fastapi==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a6b91e1c08a01601845fcfcfdefd0a2aecdb3c356d4a436a3210cb58c21487e \ - --hash=sha256:77d9c123a363129148f5f66d44094f3d67aaaa2b201396d94782b4a7f9ce4314 -opentelemetry-instrumentation-httpx==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2e9913ca4c568767cf7bb5facab4d22e1dc65ea01ad0b6b6f77b5fcee136fb1d \ - --hash=sha256:9cfe4061cd090652d4854ba95668b7fd1c258ab8e95b2c4129df66470a68c225 -opentelemetry-instrumentation-psycopg2==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:53abba97fdf103af281e704300ba722b4ec4afb0127149967e25a1adb117d4d7 \ - --hash=sha256:60152afb9986f33ab15d49875847f845a54de06603be4c0bc24ce65413c39ca0 -opentelemetry-instrumentation==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:06c02e2c952c1b076e8eaedf1b82f715e2937ba7eeacab55913dd434fbcec258 \ - --hash=sha256:6c47120a7970bbeb458e6a73686ee9ba84b106329a79e4a4a66761f933709c7e -opentelemetry-proto==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce \ - --hash=sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8 -opentelemetry-sdk==1.24.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5 \ - --hash=sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59 -opentelemetry-semantic-conventions==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118 \ - --hash=sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864 -opentelemetry-util-http==0.45b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ce08b6a7d52dd7c96b7705b5b4f06fdb6aa3eac1233b3b0bfef8a0cab9a92cd \ - --hash=sha256:6628868b501b3004e1860f976f410eeb3d3499e009719d818000f24ce17b6e33 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-dbapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f \ + --hash=sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50 +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation-httpx==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a \ + --hash=sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d +opentelemetry-instrumentation-psycopg2==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8 \ + --hash=sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 pika==1.3.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0779a7c1fafd805672796085560d290213a465e4f6f76a6fb19e378d8041a14f \ --hash=sha256:b2a327ddddf8570b4965b3576ac77091b850262d34ce8c1d8cb4e4146aa4145f diff --git a/octopoes/poetry.lock b/octopoes/poetry.lock index d1e929aaeeb..e1803b01551 100644 --- a/octopoes/poetry.lock +++ b/octopoes/poetry.lock @@ -864,42 +864,42 @@ files = [ [[package]] name = "opentelemetry-api" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, - {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, + {file = "opentelemetry_api-1.26.0-py3-none-any.whl", hash = "sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064"}, + {file = "opentelemetry_api-1.26.0.tar.gz", hash = "sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.1" +importlib-metadata = ">=6.0,<=8.0.0" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Protobuf encoding" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0-py3-none-any.whl", hash = "sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0.tar.gz", hash = "sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92"}, ] [package.dependencies] -opentelemetry-proto = "1.25.0" +opentelemetry-proto = "1.26.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0-py3-none-any.whl", hash = "sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0.tar.gz", hash = "sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae"}, ] [package.dependencies] @@ -907,19 +907,19 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.25.0" -opentelemetry-proto = "1.25.0" -opentelemetry-sdk = ">=1.25.0,<1.26.0" +opentelemetry-exporter-otlp-proto-common = "1.26.0" +opentelemetry-proto = "1.26.0" +opentelemetry-sdk = ">=1.26.0,<1.27.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.46b0" +version = "0.47b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, - {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, + {file = "opentelemetry_instrumentation-0.47b0-py3-none-any.whl", hash = "sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5"}, + {file = "opentelemetry_instrumentation-0.47b0.tar.gz", hash = "sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f"}, ] [package.dependencies] @@ -929,111 +929,111 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.46b0" +version = "0.47b0" description = "ASGI instrumentation for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_asgi-0.46b0-py3-none-any.whl", hash = "sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759"}, - {file = "opentelemetry_instrumentation_asgi-0.46b0.tar.gz", hash = "sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0-py3-none-any.whl", hash = "sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0.tar.gz", hash = "sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a"}, ] [package.dependencies] asgiref = ">=3.0,<4.0" opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] instruments = ["asgiref (>=3.0,<4.0)"] [[package]] name = "opentelemetry-instrumentation-dbapi" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry Database API instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_dbapi-0.46b0-py3-none-any.whl", hash = "sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783"}, - {file = "opentelemetry_instrumentation_dbapi-0.46b0.tar.gz", hash = "sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92"}, + {file = "opentelemetry_instrumentation_dbapi-0.47b0-py3-none-any.whl", hash = "sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f"}, + {file = "opentelemetry_instrumentation_dbapi-0.47b0.tar.gz", hash = "sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry FastAPI Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_fastapi-0.46b0-py3-none-any.whl", hash = "sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33"}, - {file = "opentelemetry_instrumentation_fastapi-0.46b0.tar.gz", hash = "sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0-py3-none-any.whl", hash = "sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0.tar.gz", hash = "sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-instrumentation-asgi = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-asgi = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] -instruments = ["fastapi (>=0.58,<1.0)"] +instruments = ["fastapi (>=0.58,<1.0)", "fastapi-slim (>=0.111.0,<0.112.0)"] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry HTTPX Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_httpx-0.46b0-py3-none-any.whl", hash = "sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc"}, - {file = "opentelemetry_instrumentation_httpx-0.46b0.tar.gz", hash = "sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109"}, + {file = "opentelemetry_instrumentation_httpx-0.47b0-py3-none-any.whl", hash = "sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a"}, + {file = "opentelemetry_instrumentation_httpx-0.47b0.tar.gz", hash = "sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] instruments = ["httpx (>=0.18.0)"] [[package]] name = "opentelemetry-instrumentation-psycopg2" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry psycopg2 instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_psycopg2-0.46b0-py3-none-any.whl", hash = "sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899"}, - {file = "opentelemetry_instrumentation_psycopg2-0.46b0.tar.gz", hash = "sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c"}, + {file = "opentelemetry_instrumentation_psycopg2-0.47b0-py3-none-any.whl", hash = "sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73"}, + {file = "opentelemetry_instrumentation_psycopg2-0.47b0.tar.gz", hash = "sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-instrumentation-dbapi = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-dbapi = "0.47b0" [package.extras] instruments = ["psycopg2 (>=2.7.3.1)"] [[package]] name = "opentelemetry-proto" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python Proto" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, - {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, + {file = "opentelemetry_proto-1.26.0-py3-none-any.whl", hash = "sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725"}, + {file = "opentelemetry_proto-1.26.0.tar.gz", hash = "sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e"}, ] [package.dependencies] @@ -1041,43 +1041,44 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, - {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, + {file = "opentelemetry_sdk-1.26.0-py3-none-any.whl", hash = "sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897"}, + {file = "opentelemetry_sdk-1.26.0.tar.gz", hash = "sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85"}, ] [package.dependencies] -opentelemetry-api = "1.25.0" -opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-api = "1.26.0" +opentelemetry-semantic-conventions = "0.47b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, - {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, + {file = "opentelemetry_semantic_conventions-0.47b0-py3-none-any.whl", hash = "sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063"}, + {file = "opentelemetry_semantic_conventions-0.47b0.tar.gz", hash = "sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e"}, ] [package.dependencies] -opentelemetry-api = "1.25.0" +deprecated = ">=1.2.6" +opentelemetry-api = "1.26.0" [[package]] name = "opentelemetry-util-http" -version = "0.46b0" +version = "0.47b0" description = "Web util for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"}, - {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"}, + {file = "opentelemetry_util_http-0.47b0-py3-none-any.whl", hash = "sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19"}, + {file = "opentelemetry_util_http-0.47b0.tar.gz", hash = "sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32"}, ] [[package]] @@ -2120,4 +2121,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "66519283cdace78ec8340a8a02ca12f2ac5715fb1bc3e9006962f79af3ba73af" +content-hash = "a22b57bde55a27cb04df0496afa697c7a5c93a494f929a1a502fc121f092a5fe" diff --git a/octopoes/pyproject.toml b/octopoes/pyproject.toml index fa5a8e082cc..ea243023153 100644 --- a/octopoes/pyproject.toml +++ b/octopoes/pyproject.toml @@ -21,25 +21,25 @@ celery = "^5.2.7" pyparsing = "^3.0.9" packaging = "^23.0" tldextract = "^3.4.0" -opentelemetry-sdk = "^1.25.0" -opentelemetry-instrumentation = "^0.46b0" -opentelemetry-exporter-otlp-proto-grpc = "^1.25.0" -opentelemetry-instrumentation-fastapi = "^0.46b0" -opentelemetry-instrumentation-psycopg2 = "^0.46b0" -opentelemetry-instrumentation-httpx = "^0.46b0" +opentelemetry-sdk = "^1.26.0" +opentelemetry-instrumentation = "^0.47b0" +opentelemetry-exporter-otlp-proto-grpc = "^1.26.0" +opentelemetry-instrumentation-fastapi = "^0.47b0" +opentelemetry-instrumentation-psycopg2 = "^0.47b0" +opentelemetry-instrumentation-httpx = "^0.47b0" sqlalchemy = "1.4.48" jsonschema = "^4.18.0" pydantic-settings = "^2.2.1" httpx = "^0.27.0" # required by disallowed-csp-hostnames bit link-shorteners = "^1.11.0" -opentelemetry-api = "^1.25.0" -opentelemetry-exporter-otlp-proto-common = "^1.25.0" -opentelemetry-instrumentation-asgi = "^0.46b0" -opentelemetry-instrumentation-dbapi = "^0.46b0" -opentelemetry-proto = "^1.25.0" -opentelemetry-semantic-conventions = "^0.46b0" -opentelemetry-util-http = "^0.46b0" +opentelemetry-api = "^1.26.0" +opentelemetry-exporter-otlp-proto-common = "^1.26.0" +opentelemetry-instrumentation-asgi = "^0.47b0" +opentelemetry-instrumentation-dbapi = "^0.47b0" +opentelemetry-proto = "^1.26.0" +opentelemetry-semantic-conventions = "^0.47b0" +opentelemetry-util-http = "^0.47b0" fastapi-slim = "^0.111.0" structlog = "^24.2.0" diff --git a/octopoes/requirements-dev.txt b/octopoes/requirements-dev.txt index 5fcaebf417c..db8f2d996d8 100644 --- a/octopoes/requirements-dev.txt +++ b/octopoes/requirements-dev.txt @@ -351,45 +351,45 @@ kombu==5.3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5634c511926309c7f9789f1433e9ed402616b56836ef9878f01bd59267b4c7a9 link-shorteners==1.11.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:57cf820ca3edc823ac19c2bbef02c1ba94f0abbebe43536f66676047f2cdd711 -opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ - --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 -opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ - --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 -opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ - --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac -opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ - --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 -opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ - --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 -opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ - --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 -opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ - --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 -opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ - --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c -opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ - --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda -opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ - --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f -opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ - --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 -opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ - --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa -opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ - --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-dbapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f \ + --hash=sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50 +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation-httpx==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a \ + --hash=sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d +opentelemetry-instrumentation-psycopg2==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8 \ + --hash=sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 diff --git a/octopoes/requirements.txt b/octopoes/requirements.txt index d65d563b29b..96d8b51499f 100644 --- a/octopoes/requirements.txt +++ b/octopoes/requirements.txt @@ -286,45 +286,45 @@ kombu==5.3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5634c511926309c7f9789f1433e9ed402616b56836ef9878f01bd59267b4c7a9 link-shorteners==1.11.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:57cf820ca3edc823ac19c2bbef02c1ba94f0abbebe43536f66676047f2cdd711 -opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ - --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 -opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ - --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 -opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ - --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac -opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ - --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 -opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ - --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 -opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ - --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 -opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ - --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 -opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ - --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c -opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ - --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda -opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ - --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f -opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ - --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 -opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ - --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa -opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ - --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-dbapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f \ + --hash=sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50 +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation-httpx==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a \ + --hash=sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d +opentelemetry-instrumentation-psycopg2==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8 \ + --hash=sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 diff --git a/rocky/poetry.lock b/rocky/poetry.lock index 55f2b8f3ce2..5fc54c05d7b 100644 --- a/rocky/poetry.lock +++ b/rocky/poetry.lock @@ -452,13 +452,13 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] name = "django" -version = "5.0.7" +version = "5.0.8" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false python-versions = ">=3.10" files = [ - {file = "Django-5.0.7-py3-none-any.whl", hash = "sha256:f216510ace3de5de01329463a315a629f33480e893a9024fc93d8c32c22913da"}, - {file = "Django-5.0.7.tar.gz", hash = "sha256:bd4505cae0b9bd642313e8fb71810893df5dc2ffcacaa67a33af2d5cd61888f2"}, + {file = "Django-5.0.8-py3-none-any.whl", hash = "sha256:333a7988f7ca4bc14d360d3d8f6b793704517761ae3813b95432043daec22a45"}, + {file = "Django-5.0.8.tar.gz", hash = "sha256:ebe859c9da6fead9c9ee6dbfa4943b04f41342f4cea2c4d8c978ef0d10694f2b"}, ] [package.dependencies] @@ -501,13 +501,13 @@ django = "*" [[package]] name = "django-components" -version = "0.82" +version = "0.88" description = "A way to create simple reusable template components in Django." optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "django_components-0.82-py3-none-any.whl", hash = "sha256:8c84c0ae028c04675b32a2962b6f52a098871ce09b1286d66fbdc5c7038ddacc"}, - {file = "django_components-0.82.tar.gz", hash = "sha256:94e29eba63248f439291335a3093587827ebb1010e92526ede669b964884a3df"}, + {file = "django_components-0.88-py3-none-any.whl", hash = "sha256:19641759bcbdafeaf48d4363c11639201fc893946745799b12b77cd7996da8fc"}, + {file = "django_components-0.88.tar.gz", hash = "sha256:a796077706423b491234625d95bb8084761211ae022df159ead8472a1a256c7a"}, ] [package.dependencies] @@ -535,21 +535,21 @@ resolved_reference = "620bc0ab86590f8981dd24456a70951c9bdbf91f" [[package]] name = "django-csp" -version = "3.7" +version = "3.8" description = "Django Content Security Policy support." optional = false python-versions = "*" files = [ - {file = "django_csp-3.7-py2.py3-none-any.whl", hash = "sha256:01443a07723f9a479d498bd7bb63571aaa771e690f64bde515db6cdb76e8041a"}, - {file = "django_csp-3.7.tar.gz", hash = "sha256:01eda02ad3f10261c74131cdc0b5a6a62b7c7ad4fd017fbefb7a14776e0a9727"}, + {file = "django_csp-3.8-py3-none-any.whl", hash = "sha256:19b2978b03fcd73517d7d67acbc04fbbcaec0facc3e83baa502965892d1e0719"}, + {file = "django_csp-3.8.tar.gz", hash = "sha256:ef0f1a9f7d8da68ae6e169c02e9ac661c0ecf04db70e0d1d85640512a68471c0"}, ] [package.dependencies] -Django = ">=1.8" +Django = ">=3.2" [package.extras] jinja2 = ["jinja2 (>=2.9.6)"] -tests = ["jinja2 (>=2.9.6)", "mock (==1.0.1)", "pep8 (==1.4.6)", "pytest (<4.0)", "pytest-django", "pytest-flakes (==1.0.1)", "pytest-pep8 (==1.0.6)", "six (==1.12.0)"] +tests = ["jinja2 (>=2.9.6)", "pytest", "pytest-cov", "pytest-django", "pytest-ruff"] [[package]] name = "django-environ" @@ -597,13 +597,13 @@ python-ipware = ">=2.0.3" [[package]] name = "django-otp" -version = "1.3.0" +version = "1.5.1" description = "A pluggable framework for adding two-factor authentication to Django using one-time passwords." optional = false python-versions = ">=3.7" files = [ - {file = "django_otp-1.3.0-py3-none-any.whl", hash = "sha256:5277731bc05b6cdbf96aa84ac46018e30ed5fb248086053b0146f925de059060"}, - {file = "django_otp-1.3.0.tar.gz", hash = "sha256:8f4156a3c14ce2aaa31379385eadf388925cd50fc4b5d20a3b944f454c98ff7c"}, + {file = "django_otp-1.5.1-py3-none-any.whl", hash = "sha256:48d0a1943cbeb610f0bca51a0da42cc7eefcff387b101c69d3ed432cd75a0fd4"}, + {file = "django_otp-1.5.1.tar.gz", hash = "sha256:d0c60a3c20dd16e9f2c7c3d8669306c34a83c20fd021565adbf782f4ba911b13"}, ] [package.dependencies] @@ -611,6 +611,7 @@ django = ">=3.2" [package.extras] qrcode = ["qrcode"] +segno = ["segno"] [[package]] name = "django-password-validators" @@ -731,13 +732,13 @@ yubikey = ["django-otp-yubikey"] [[package]] name = "django-weasyprint" -version = "2.2.2" +version = "2.3.0" description = "Django WeasyPrint CBV" optional = false python-versions = ">=3.8" files = [ - {file = "django-weasyprint-2.2.2.tar.gz", hash = "sha256:7f554bcc428293aeadc175ab5607b4f3bf30c0e5da3d4aa34453b3d96e0ffd3a"}, - {file = "django_weasyprint-2.2.2-py3-none-any.whl", hash = "sha256:605eba0dd3246c0410a60fdaa581139330ad6c637fc273e1bfe90a7a09f53728"}, + {file = "django-weasyprint-2.3.0.tar.gz", hash = "sha256:2f849e15bfd6c1b2a58512097b9042eddf3533651d37d2e096cd6f7d8be6442b"}, + {file = "django_weasyprint-2.3.0-py3-none-any.whl", hash = "sha256:807cb3b16332123d97c8bbe2ac9c70286103fe353235351803ffd33b67284735"}, ] [package.dependencies] @@ -1538,42 +1539,42 @@ django = ">=1.11.0" [[package]] name = "opentelemetry-api" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, - {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, + {file = "opentelemetry_api-1.26.0-py3-none-any.whl", hash = "sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064"}, + {file = "opentelemetry_api-1.26.0.tar.gz", hash = "sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.1" +importlib-metadata = ">=6.0,<=8.0.0" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Protobuf encoding" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0-py3-none-any.whl", hash = "sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.26.0.tar.gz", hash = "sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92"}, ] [package.dependencies] -opentelemetry-proto = "1.25.0" +opentelemetry-proto = "1.26.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0-py3-none-any.whl", hash = "sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.26.0.tar.gz", hash = "sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae"}, ] [package.dependencies] @@ -1581,19 +1582,19 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.25.0" -opentelemetry-proto = "1.25.0" -opentelemetry-sdk = ">=1.25.0,<1.26.0" +opentelemetry-exporter-otlp-proto-common = "1.26.0" +opentelemetry-proto = "1.26.0" +opentelemetry-sdk = ">=1.26.0,<1.27.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.46b0" +version = "0.47b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, - {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, + {file = "opentelemetry_instrumentation-0.47b0-py3-none-any.whl", hash = "sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5"}, + {file = "opentelemetry_instrumentation-0.47b0.tar.gz", hash = "sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f"}, ] [package.dependencies] @@ -1603,150 +1604,150 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.46b0" +version = "0.47b0" description = "ASGI instrumentation for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_asgi-0.46b0-py3-none-any.whl", hash = "sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759"}, - {file = "opentelemetry_instrumentation_asgi-0.46b0.tar.gz", hash = "sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0-py3-none-any.whl", hash = "sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade"}, + {file = "opentelemetry_instrumentation_asgi-0.47b0.tar.gz", hash = "sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a"}, ] [package.dependencies] asgiref = ">=3.0,<4.0" opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] instruments = ["asgiref (>=3.0,<4.0)"] [[package]] name = "opentelemetry-instrumentation-dbapi" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry Database API instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_dbapi-0.46b0-py3-none-any.whl", hash = "sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783"}, - {file = "opentelemetry_instrumentation_dbapi-0.46b0.tar.gz", hash = "sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92"}, + {file = "opentelemetry_instrumentation_dbapi-0.47b0-py3-none-any.whl", hash = "sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f"}, + {file = "opentelemetry_instrumentation_dbapi-0.47b0.tar.gz", hash = "sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-instrumentation-django" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry Instrumentation for Django" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_django-0.46b0-py3-none-any.whl", hash = "sha256:ecc85941263122f99dbd96463a981b2d1eeea618ca287a58abe0af9fd67631ee"}, - {file = "opentelemetry_instrumentation_django-0.46b0.tar.gz", hash = "sha256:cc11b2e24f9bdd20759570390ed8619d9c5acbf788b4a5401e36e280dfc20feb"}, + {file = "opentelemetry_instrumentation_django-0.47b0-py3-none-any.whl", hash = "sha256:85d5d5dd4047945917b823879933a28efddcf06d5f7fabef5ac806226602b18d"}, + {file = "opentelemetry_instrumentation_django-0.47b0.tar.gz", hash = "sha256:f23c97ffa9b9b0d06a76e4a5296f189cc6e02f66c29a0ca30a97b0ea121a30b9"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-instrumentation-wsgi = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-wsgi = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] -asgi = ["opentelemetry-instrumentation-asgi (==0.46b0)"] +asgi = ["opentelemetry-instrumentation-asgi (==0.47b0)"] instruments = ["django (>=1.10)"] [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry FastAPI Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_fastapi-0.46b0-py3-none-any.whl", hash = "sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33"}, - {file = "opentelemetry_instrumentation_fastapi-0.46b0.tar.gz", hash = "sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0-py3-none-any.whl", hash = "sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21"}, + {file = "opentelemetry_instrumentation_fastapi-0.47b0.tar.gz", hash = "sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-instrumentation-asgi = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-asgi = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] -instruments = ["fastapi (>=0.58,<1.0)"] +instruments = ["fastapi (>=0.58,<1.0)", "fastapi-slim (>=0.111.0,<0.112.0)"] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry HTTPX Instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_httpx-0.46b0-py3-none-any.whl", hash = "sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc"}, - {file = "opentelemetry_instrumentation_httpx-0.46b0.tar.gz", hash = "sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109"}, + {file = "opentelemetry_instrumentation_httpx-0.47b0-py3-none-any.whl", hash = "sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a"}, + {file = "opentelemetry_instrumentation_httpx-0.47b0.tar.gz", hash = "sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [package.extras] instruments = ["httpx (>=0.18.0)"] [[package]] name = "opentelemetry-instrumentation-psycopg2" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry psycopg2 instrumentation" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_psycopg2-0.46b0-py3-none-any.whl", hash = "sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899"}, - {file = "opentelemetry_instrumentation_psycopg2-0.46b0.tar.gz", hash = "sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c"}, + {file = "opentelemetry_instrumentation_psycopg2-0.47b0-py3-none-any.whl", hash = "sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73"}, + {file = "opentelemetry_instrumentation_psycopg2-0.47b0.tar.gz", hash = "sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-instrumentation-dbapi = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-instrumentation-dbapi = "0.47b0" [package.extras] instruments = ["psycopg2 (>=2.7.3.1)"] [[package]] name = "opentelemetry-instrumentation-wsgi" -version = "0.46b0" +version = "0.47b0" description = "WSGI Middleware for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation_wsgi-0.46b0-py3-none-any.whl", hash = "sha256:2386014b026f5307c802417eeab74265785ae3dd6eee8c5581a830e3b2d3435b"}, - {file = "opentelemetry_instrumentation_wsgi-0.46b0.tar.gz", hash = "sha256:f4e1001e8477eb546cac7c13cff0b0cf127812b1188a37bcaa3e43eb741451e2"}, + {file = "opentelemetry_instrumentation_wsgi-0.47b0-py3-none-any.whl", hash = "sha256:9a1a78aa2f5682fe1073c4cc77f24ef4f083b18b66bbb674a995b0b77eef1815"}, + {file = "opentelemetry_instrumentation_wsgi-0.47b0.tar.gz", hash = "sha256:4903c3d686d53ca7ab6545bb4cc42c3de8af5b2f370996e84db2cfec688860af"}, ] [package.dependencies] opentelemetry-api = ">=1.12,<2.0" -opentelemetry-instrumentation = "0.46b0" -opentelemetry-semantic-conventions = "0.46b0" -opentelemetry-util-http = "0.46b0" +opentelemetry-instrumentation = "0.47b0" +opentelemetry-semantic-conventions = "0.47b0" +opentelemetry-util-http = "0.47b0" [[package]] name = "opentelemetry-proto" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python Proto" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, - {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, + {file = "opentelemetry_proto-1.26.0-py3-none-any.whl", hash = "sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725"}, + {file = "opentelemetry_proto-1.26.0.tar.gz", hash = "sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e"}, ] [package.dependencies] @@ -1754,43 +1755,44 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.25.0" +version = "1.26.0" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, - {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, + {file = "opentelemetry_sdk-1.26.0-py3-none-any.whl", hash = "sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897"}, + {file = "opentelemetry_sdk-1.26.0.tar.gz", hash = "sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85"}, ] [package.dependencies] -opentelemetry-api = "1.25.0" -opentelemetry-semantic-conventions = "0.46b0" +opentelemetry-api = "1.26.0" +opentelemetry-semantic-conventions = "0.47b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.46b0" +version = "0.47b0" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, - {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, + {file = "opentelemetry_semantic_conventions-0.47b0-py3-none-any.whl", hash = "sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063"}, + {file = "opentelemetry_semantic_conventions-0.47b0.tar.gz", hash = "sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e"}, ] [package.dependencies] -opentelemetry-api = "1.25.0" +deprecated = ">=1.2.6" +opentelemetry-api = "1.26.0" [[package]] name = "opentelemetry-util-http" -version = "0.46b0" +version = "0.47b0" description = "Web util for OpenTelemetry" optional = false python-versions = ">=3.8" files = [ - {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"}, - {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"}, + {file = "opentelemetry_util_http-0.47b0-py3-none-any.whl", hash = "sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19"}, + {file = "opentelemetry_util_http-0.47b0.tar.gz", hash = "sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32"}, ] [[package]] @@ -1828,13 +1830,13 @@ files = [ [[package]] name = "phonenumbers" -version = "8.13.33" +version = "8.13.42" description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers." optional = false python-versions = "*" files = [ - {file = "phonenumbers-8.13.33-py2.py3-none-any.whl", hash = "sha256:f2d653268ece55a4f3752d9cda4be6f7465f298e6d028d522aedda13cf057201"}, - {file = "phonenumbers-8.13.33.tar.gz", hash = "sha256:991f2619f0593b36b674c345af47944ec4bae526b353cf53d707e662087be63b"}, + {file = "phonenumbers-8.13.42-py2.py3-none-any.whl", hash = "sha256:18acc22ee03116d27b26e990f53806a1770a3e05f05e1620bc09ad187f889456"}, + {file = "phonenumbers-8.13.42.tar.gz", hash = "sha256:7137904f2db3b991701e853174ce8e1cb8f540b8bfdf27617540de04c0b7bed5"}, ] [[package]] @@ -3443,4 +3445,4 @@ test = ["pytest"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "7322127db1a770df4576a537fdaf4f6a364b43d49ecf01916cbfa9c0b24cf522" +content-hash = "02f0992a2c8b4010f34f92d601c5ab82862ee9d70c477eccc04eb4cb8e188b26" diff --git a/rocky/pyproject.toml b/rocky/pyproject.toml index 192fec56360..197efaeea9d 100644 --- a/rocky/pyproject.toml +++ b/rocky/pyproject.toml @@ -27,29 +27,29 @@ strenum = "^0.4.15" django-rest-knox = { git = "https://github.com/jazzband/django-rest-knox", rev = "dd7b062147bc4b9718e22d5acd6cf1301a1036b9" } # OpenTelemetry -opentelemetry-sdk = "^1.25.0" -opentelemetry-exporter-otlp-proto-grpc = "^1.25.0" -opentelemetry-instrumentation-django = "^0.46b0" -opentelemetry-instrumentation-psycopg2 = "^0.46b0" +opentelemetry-sdk = "^1.26.0" +opentelemetry-exporter-otlp-proto-grpc = "^1.26.0" +opentelemetry-instrumentation-django = "^0.47b0" +opentelemetry-instrumentation-psycopg2 = "^0.47b0" whitenoise = { extras = ["brotli"], version = "^6.5.0" } -opentelemetry-instrumentation = "^0.46b0" -opentelemetry-instrumentation-fastapi = "^0.46b0" +opentelemetry-instrumentation = "^0.47b0" +opentelemetry-instrumentation-fastapi = "^0.47b0" granian = "^1.3.2" -django-components = "^0.82" +django-components = "^0.88" # These used in octopoes parts that are used by rocky pyparsing = "^3.1.1" pydantic-settings = "^2.0.3" -opentelemetry-instrumentation-httpx = "^0.46b0" +opentelemetry-instrumentation-httpx = "^0.47b0" httpx = "^0.27.0" -opentelemetry-api = "^1.25.0" -opentelemetry-exporter-otlp-proto-common = "^1.25.0" -opentelemetry-instrumentation-asgi = "^0.46b0" -opentelemetry-instrumentation-dbapi = "^0.46b0" -opentelemetry-instrumentation-wsgi = "^0.46b0" -opentelemetry-proto = "^1.25.0" -opentelemetry-semantic-conventions = "^0.46b0" -opentelemetry-util-http = "^0.46b0" +opentelemetry-api = "^1.26.0" +opentelemetry-exporter-otlp-proto-common = "^1.26.0" +opentelemetry-instrumentation-asgi = "^0.47b0" +opentelemetry-instrumentation-dbapi = "^0.47b0" +opentelemetry-instrumentation-wsgi = "^0.47b0" +opentelemetry-proto = "^1.26.0" +opentelemetry-semantic-conventions = "^0.47b0" +opentelemetry-util-http = "^0.47b0" structlog = "^24.2.0" django-structlog = "^8.1.0" diff --git a/rocky/requirements-dev.txt b/rocky/requirements-dev.txt index 1345b091840..28a5eb002af 100644 --- a/rocky/requirements-dev.txt +++ b/rocky/requirements-dev.txt @@ -255,13 +255,13 @@ django-admin-auto-tests @ git+https://github.com/dekkers/django-admin-auto-tests django-appconf==1.0.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c3ae442fba1ff7ec830412c5184b17169a7a1e71cf0864a4c3f93cf4c98a1993 \ --hash=sha256:cfe87ea827c4ee04b9a70fab90b86d704cb02f2981f89da8423cb0fabf88efbf -django-components==0.82 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8c84c0ae028c04675b32a2962b6f52a098871ce09b1286d66fbdc5c7038ddacc \ - --hash=sha256:94e29eba63248f439291335a3093587827ebb1010e92526ede669b964884a3df +django-components==0.88 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:19641759bcbdafeaf48d4363c11639201fc893946745799b12b77cd7996da8fc \ + --hash=sha256:a796077706423b491234625d95bb8084761211ae022df159ead8472a1a256c7a django-compressor @ git+https://github.com/dekkers/django-compressor@620bc0ab86590f8981dd24456a70951c9bdbf91f ; python_version >= "3.10" and python_version < "4.0" -django-csp==3.7 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01443a07723f9a479d498bd7bb63571aaa771e690f64bde515db6cdb76e8041a \ - --hash=sha256:01eda02ad3f10261c74131cdc0b5a6a62b7c7ad4fd017fbefb7a14776e0a9727 +django-csp==3.8 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:19b2978b03fcd73517d7d67acbc04fbbcaec0facc3e83baa502965892d1e0719 \ + --hash=sha256:ef0f1a9f7d8da68ae6e169c02e9ac661c0ecf04db70e0d1d85640512a68471c0 django-environ==0.11.2 ; python_version >= "3.10" and python_version < "4" \ --hash=sha256:0ff95ab4344bfeff693836aa978e6840abef2e2f1145adff7735892711590c05 \ --hash=sha256:f32a87aa0899894c27d4e1776fa6b477e8164ed7f6b3e410a62a6d72caaf64be @@ -271,9 +271,9 @@ django-formtools==2.5.1 ; python_version >= "3.10" and python_version < "4.0" \ django-ipware==7.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d9ec43d2bf7cdf216fed8d494a084deb5761a54860a53b2e74346a4f384cff47 \ --hash=sha256:db16bbee920f661ae7f678e4270460c85850f03c6761a4eaeb489bdc91f64709 -django-otp==1.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5277731bc05b6cdbf96aa84ac46018e30ed5fb248086053b0146f925de059060 \ - --hash=sha256:8f4156a3c14ce2aaa31379385eadf388925cd50fc4b5d20a3b944f454c98ff7c +django-otp==1.5.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:48d0a1943cbeb610f0bca51a0da42cc7eefcff387b101c69d3ed432cd75a0fd4 \ + --hash=sha256:d0c60a3c20dd16e9f2c7c3d8669306c34a83c20fd021565adbf782f4ba911b13 django-password-validators==1.7.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:7175aefa6e86dc002dd3539327bf2d752097651704927dc409a669259e0d2195 \ --hash=sha256:f243a82957e9b17a0c7cf5580f9d7588471cb6530c2dce7ee4e1222dddfe5768 @@ -290,12 +290,12 @@ django-tagulous==1.3.3 ; python_version >= "3.10" and python_version < "4.0" \ django-two-factor-auth==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:662782a4ab9f59a06afe3be04540dc8dd04e63b06f52520386a546fcad8d2d41 \ --hash=sha256:bf57713232b15dc85abbed45244f372bd01de5c145159d3bee3e468af7e2b6d1 -django-weasyprint==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:605eba0dd3246c0410a60fdaa581139330ad6c637fc273e1bfe90a7a09f53728 \ - --hash=sha256:7f554bcc428293aeadc175ab5607b4f3bf30c0e5da3d4aa34453b3d96e0ffd3a -django==5.0.7 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bd4505cae0b9bd642313e8fb71810893df5dc2ffcacaa67a33af2d5cd61888f2 \ - --hash=sha256:f216510ace3de5de01329463a315a629f33480e893a9024fc93d8c32c22913da +django-weasyprint==2.3.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2f849e15bfd6c1b2a58512097b9042eddf3533651d37d2e096cd6f7d8be6442b \ + --hash=sha256:807cb3b16332123d97c8bbe2ac9c70286103fe353235351803ffd33b67284735 +django==5.0.8 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:333a7988f7ca4bc14d360d3d8f6b793704517761ae3813b95432043daec22a45 \ + --hash=sha256:ebe859c9da6fead9c9ee6dbfa4943b04f41342f4cea2c4d8c978ef0d10694f2b djangorestframework==3.15.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20 \ --hash=sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad @@ -663,51 +663,51 @@ mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" \ model-mommy==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:3d332afce941c57f1990f45b083ba13252ba74fcd1ae43fd047e5af7a70fb312 \ --hash=sha256:40d6e740aad7509e696a324b94cf2b0a104da93c3d4a7924cea1be3d0eb95b4f -opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ - --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 -opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ - --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 -opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ - --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac -opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ - --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 -opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ - --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 -opentelemetry-instrumentation-django==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:cc11b2e24f9bdd20759570390ed8619d9c5acbf788b4a5401e36e280dfc20feb \ - --hash=sha256:ecc85941263122f99dbd96463a981b2d1eeea618ca287a58abe0af9fd67631ee -opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ - --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 -opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ - --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 -opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ - --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c -opentelemetry-instrumentation-wsgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2386014b026f5307c802417eeab74265785ae3dd6eee8c5581a830e3b2d3435b \ - --hash=sha256:f4e1001e8477eb546cac7c13cff0b0cf127812b1188a37bcaa3e43eb741451e2 -opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ - --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda -opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ - --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f -opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ - --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 -opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ - --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa -opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ - --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-dbapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f \ + --hash=sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50 +opentelemetry-instrumentation-django==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:85d5d5dd4047945917b823879933a28efddcf06d5f7fabef5ac806226602b18d \ + --hash=sha256:f23c97ffa9b9b0d06a76e4a5296f189cc6e02f66c29a0ca30a97b0ea121a30b9 +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation-httpx==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a \ + --hash=sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d +opentelemetry-instrumentation-psycopg2==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8 \ + --hash=sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73 +opentelemetry-instrumentation-wsgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4903c3d686d53ca7ab6545bb4cc42c3de8af5b2f370996e84db2cfec688860af \ + --hash=sha256:9a1a78aa2f5682fe1073c4cc77f24ef4f083b18b66bbb674a995b0b77eef1815 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 overrides==7.7.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a \ --hash=sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49 @@ -717,9 +717,9 @@ packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ pathspec==0.12.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08 \ --hash=sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712 -phonenumbers==8.13.33 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:991f2619f0593b36b674c345af47944ec4bae526b353cf53d707e662087be63b \ - --hash=sha256:f2d653268ece55a4f3752d9cda4be6f7465f298e6d028d522aedda13cf057201 +phonenumbers==8.13.42 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:18acc22ee03116d27b26e990f53806a1770a3e05f05e1620bc09ad187f889456 \ + --hash=sha256:7137904f2db3b991701e853174ce8e1cb8f540b8bfdf27617540de04c0b7bed5 pillow==10.3.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c \ --hash=sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2 \ diff --git a/rocky/requirements.txt b/rocky/requirements.txt index a8568b9be79..ce160879550 100644 --- a/rocky/requirements.txt +++ b/rocky/requirements.txt @@ -196,13 +196,13 @@ deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \ django-appconf==1.0.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c3ae442fba1ff7ec830412c5184b17169a7a1e71cf0864a4c3f93cf4c98a1993 \ --hash=sha256:cfe87ea827c4ee04b9a70fab90b86d704cb02f2981f89da8423cb0fabf88efbf -django-components==0.82 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8c84c0ae028c04675b32a2962b6f52a098871ce09b1286d66fbdc5c7038ddacc \ - --hash=sha256:94e29eba63248f439291335a3093587827ebb1010e92526ede669b964884a3df +django-components==0.88 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:19641759bcbdafeaf48d4363c11639201fc893946745799b12b77cd7996da8fc \ + --hash=sha256:a796077706423b491234625d95bb8084761211ae022df159ead8472a1a256c7a django-compressor @ git+https://github.com/dekkers/django-compressor@620bc0ab86590f8981dd24456a70951c9bdbf91f ; python_version >= "3.10" and python_version < "4.0" -django-csp==3.7 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01443a07723f9a479d498bd7bb63571aaa771e690f64bde515db6cdb76e8041a \ - --hash=sha256:01eda02ad3f10261c74131cdc0b5a6a62b7c7ad4fd017fbefb7a14776e0a9727 +django-csp==3.8 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:19b2978b03fcd73517d7d67acbc04fbbcaec0facc3e83baa502965892d1e0719 \ + --hash=sha256:ef0f1a9f7d8da68ae6e169c02e9ac661c0ecf04db70e0d1d85640512a68471c0 django-environ==0.11.2 ; python_version >= "3.10" and python_version < "4" \ --hash=sha256:0ff95ab4344bfeff693836aa978e6840abef2e2f1145adff7735892711590c05 \ --hash=sha256:f32a87aa0899894c27d4e1776fa6b477e8164ed7f6b3e410a62a6d72caaf64be @@ -212,9 +212,9 @@ django-formtools==2.5.1 ; python_version >= "3.10" and python_version < "4.0" \ django-ipware==7.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d9ec43d2bf7cdf216fed8d494a084deb5761a54860a53b2e74346a4f384cff47 \ --hash=sha256:db16bbee920f661ae7f678e4270460c85850f03c6761a4eaeb489bdc91f64709 -django-otp==1.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5277731bc05b6cdbf96aa84ac46018e30ed5fb248086053b0146f925de059060 \ - --hash=sha256:8f4156a3c14ce2aaa31379385eadf388925cd50fc4b5d20a3b944f454c98ff7c +django-otp==1.5.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:48d0a1943cbeb610f0bca51a0da42cc7eefcff387b101c69d3ed432cd75a0fd4 \ + --hash=sha256:d0c60a3c20dd16e9f2c7c3d8669306c34a83c20fd021565adbf782f4ba911b13 django-password-validators==1.7.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:7175aefa6e86dc002dd3539327bf2d752097651704927dc409a669259e0d2195 \ --hash=sha256:f243a82957e9b17a0c7cf5580f9d7588471cb6530c2dce7ee4e1222dddfe5768 @@ -231,12 +231,12 @@ django-tagulous==1.3.3 ; python_version >= "3.10" and python_version < "4.0" \ django-two-factor-auth==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:662782a4ab9f59a06afe3be04540dc8dd04e63b06f52520386a546fcad8d2d41 \ --hash=sha256:bf57713232b15dc85abbed45244f372bd01de5c145159d3bee3e468af7e2b6d1 -django-weasyprint==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:605eba0dd3246c0410a60fdaa581139330ad6c637fc273e1bfe90a7a09f53728 \ - --hash=sha256:7f554bcc428293aeadc175ab5607b4f3bf30c0e5da3d4aa34453b3d96e0ffd3a -django==5.0.7 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bd4505cae0b9bd642313e8fb71810893df5dc2ffcacaa67a33af2d5cd61888f2 \ - --hash=sha256:f216510ace3de5de01329463a315a629f33480e893a9024fc93d8c32c22913da +django-weasyprint==2.3.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2f849e15bfd6c1b2a58512097b9042eddf3533651d37d2e096cd6f7d8be6442b \ + --hash=sha256:807cb3b16332123d97c8bbe2ac9c70286103fe353235351803ffd33b67284735 +django==5.0.8 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:333a7988f7ca4bc14d360d3d8f6b793704517761ae3813b95432043daec22a45 \ + --hash=sha256:ebe859c9da6fead9c9ee6dbfa4943b04f41342f4cea2c4d8c978ef0d10694f2b djangorestframework==3.15.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20 \ --hash=sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad @@ -420,54 +420,54 @@ jsonschema-specifications==2023.12.1 ; python_version >= "3.10" and python_versi jsonschema==4.21.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f \ --hash=sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5 -opentelemetry-api==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \ - --hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869 -opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \ - --hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3 -opentelemetry-exporter-otlp-proto-grpc==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4 \ - --hash=sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac -opentelemetry-instrumentation-asgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02559f30cf4b7e2a737ab17eb52aa0779bcf4cc06573064f3e2cb4dcc7d3040a \ - --hash=sha256:f13c55c852689573057837a9500aeeffc010c4ba59933c322e8f866573374759 -opentelemetry-instrumentation-dbapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01c8a3057ccb5dcdb68d730c92839d7d30e31bf60b0a4d42d37a0c01a2a37783 \ - --hash=sha256:f419cfaceaed22964622093970c70a58c1214fc2669f2b4afab76252b6834d92 -opentelemetry-instrumentation-django==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:cc11b2e24f9bdd20759570390ed8619d9c5acbf788b4a5401e36e280dfc20feb \ - --hash=sha256:ecc85941263122f99dbd96463a981b2d1eeea618ca287a58abe0af9fd67631ee -opentelemetry-instrumentation-fastapi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:928a883a36fc89f9702f15edce43d1a7104da93d740281e32d50ffd03dbb4365 \ - --hash=sha256:e0f5d150c6c36833dd011f0e6ef5ede6d7406c1aed0c7c98b2d3b38a018d1b33 -opentelemetry-instrumentation-httpx==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1d704937e46943a14c869cfad9e6cf8013c70a9cb2f5b26dffdb536f2fadc2cc \ - --hash=sha256:e08bcc9ac4086a207d216d81cf1e998253d197f3292327c8a43a5a420f98a109 -opentelemetry-instrumentation-psycopg2==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1a115ed99165c71cdb467b08e76c09fbfc3d25f8bf76863066cbecbefcb94899 \ - --hash=sha256:8eb4cd345352b6aac1304eadf98039d2c7cc4aa23e51fa288215247aa467552c -opentelemetry-instrumentation-wsgi==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2386014b026f5307c802417eeab74265785ae3dd6eee8c5581a830e3b2d3435b \ - --hash=sha256:f4e1001e8477eb546cac7c13cff0b0cf127812b1188a37bcaa3e43eb741451e2 -opentelemetry-instrumentation==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b \ - --hash=sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda -opentelemetry-proto==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3 \ - --hash=sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f -opentelemetry-sdk==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \ - --hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9 -opentelemetry-semantic-conventions==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07 \ - --hash=sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa -opentelemetry-util-http==0.46b0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6 \ - --hash=sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629 -phonenumbers==8.13.33 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:991f2619f0593b36b674c345af47944ec4bae526b353cf53d707e662087be63b \ - --hash=sha256:f2d653268ece55a4f3752d9cda4be6f7465f298e6d028d522aedda13cf057201 +opentelemetry-api==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce \ + --hash=sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064 +opentelemetry-exporter-otlp-proto-common==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bdbe50e2e22a1c71acaa0c8ba6efaadd58882e5a5978737a44a4c4b10d304c92 \ + --hash=sha256:ee4d8f8891a1b9c372abf8d109409e5b81947cf66423fd998e56880057afbc71 +opentelemetry-exporter-otlp-proto-grpc==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a65b67a9a6b06ba1ec406114568e21afe88c1cdb29c464f2507d529eb906d8ae \ + --hash=sha256:e2be5eff72ebcb010675b818e8d7c2e7d61ec451755b8de67a140bc49b9b0280 +opentelemetry-instrumentation-asgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:b798dc4957b3edc9dfecb47a4c05809036a4b762234c5071212fda39ead80ade \ + --hash=sha256:e78b7822c1bca0511e5e9610ec484b8994a81670375e570c76f06f69af7c506a +opentelemetry-instrumentation-dbapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a160029dfffdb9716ce3908f140afe7c91a4704fbe42fc623341fc5645440f \ + --hash=sha256:31fe72b7f45467592880ded77bb19aa4c04d126228684de9f0b46318325b9d50 +opentelemetry-instrumentation-django==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:85d5d5dd4047945917b823879933a28efddcf06d5f7fabef5ac806226602b18d \ + --hash=sha256:f23c97ffa9b9b0d06a76e4a5296f189cc6e02f66c29a0ca30a97b0ea121a30b9 +opentelemetry-instrumentation-fastapi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0c7c10b5d971e99a420678ffd16c5b1ea4f0db3b31b62faf305fbb03b4ebee36 \ + --hash=sha256:5ac28dd401160b02e4f544a85a9e4f61a8cbe5b077ea0379d411615376a2bd21 +opentelemetry-instrumentation-httpx==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:24a2db480919b326e50c6a5ad01bb53b717fbd4116bb4d736d104608bf34a25a \ + --hash=sha256:4a4f7ff4726445e81aaedc025ee0f9ac66c2e9074987879082edea882c4aa22d +opentelemetry-instrumentation-psycopg2==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35085c295d1ef9b299ba7fb0ed19e6ff31c2be010b3e7371df196c17a43885f8 \ + --hash=sha256:838fd49caf1b4fef0b5e436970e34eb1a9f79f76439ecf6383169053d0c72a73 +opentelemetry-instrumentation-wsgi==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4903c3d686d53ca7ab6545bb4cc42c3de8af5b2f370996e84db2cfec688860af \ + --hash=sha256:9a1a78aa2f5682fe1073c4cc77f24ef4f083b18b66bbb674a995b0b77eef1815 +opentelemetry-instrumentation==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:88974ee52b1db08fc298334b51c19d47e53099c33740e48c4f084bd1afd052d5 \ + --hash=sha256:96f9885e450c35e3f16a4f33145f2ebf620aea910c9fd74a392bbc0f807a350f +opentelemetry-proto==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:6c4d7b4d4d9c88543bcf8c28ae3f8f0448a753dc291c18c5390444c90b76a725 \ + --hash=sha256:c5c18796c0cab3751fc3b98dee53855835e90c0422924b484432ac852d93dc1e +opentelemetry-sdk==1.26.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85 \ + --hash=sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897 +opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063 \ + --hash=sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e +opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ + --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 +phonenumbers==8.13.42 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:18acc22ee03116d27b26e990f53806a1770a3e05f05e1620bc09ad187f889456 \ + --hash=sha256:7137904f2db3b991701e853174ce8e1cb8f540b8bfdf27617540de04c0b7bed5 pillow==10.3.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c \ --hash=sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2 \ From 3623dd1c8b463546eb68e679a020a059b3c8a6cc Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:31:31 +0200 Subject: [PATCH 051/112] Fix Garbage collection and disappearing ports issue (#3214) Signed-off-by: Donny Peeters Co-authored-by: Jan Klopper --- .gitignore | 1 + boefjes/.ci/.env.test | 37 +++- boefjes/.ci/docker-compose.yml | 91 +++++++++ .../.ci/wiremock/mappings/organisations.json | 15 ++ boefjes/Makefile | 6 + boefjes/boefjes/clients/bytes_client.py | 8 + boefjes/boefjes/dependencies/plugins.py | 2 +- boefjes/boefjes/job_handler.py | 3 + boefjes/pyproject.toml | 19 +- boefjes/tests/conftest.py | 117 ++++++++++- boefjes/tests/integration/test_bench.py | 113 +++++++++++ boefjes/tools/upgrade_v1_16_0.py | 187 ++++++++++++++++++ bytes/bytes/api/router.py | 4 +- docs/source/release_notes/1.13.rst | 2 +- docs/source/release_notes/1.16.rst | 19 ++ octopoes/octopoes/api/models.py | 6 + octopoes/octopoes/api/router.py | 48 ++++- octopoes/octopoes/connector/octopoes.py | 24 ++- octopoes/octopoes/models/origin.py | 7 + .../repositories/origin_repository.py | 6 + octopoes/tests/conftest.py | 4 +- .../tests/integration/test_api_connector.py | 101 +++++++++- octopoes/tests/integration/test_unicode.py | 2 + rocky/tests/integration/conftest.py | 9 +- 24 files changed, 810 insertions(+), 21 deletions(-) create mode 100644 boefjes/.ci/wiremock/mappings/organisations.json create mode 100644 boefjes/tests/integration/test_bench.py create mode 100755 boefjes/tools/upgrade_v1_16_0.py diff --git a/.gitignore b/.gitignore index cbf5265286c..bce85366c2c 100644 --- a/.gitignore +++ b/.gitignore @@ -444,3 +444,4 @@ nl-kat-* /boefjes/boefjes/plugins/kat_rpki/rpki-meta.json *.pstat +**/.cache* diff --git a/boefjes/.ci/.env.test b/boefjes/.ci/.env.test index 88a4030008b..896206d75ad 100644 --- a/boefjes/.ci/.env.test +++ b/boefjes/.ci/.env.test @@ -1,11 +1,42 @@ POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres -POSTGRES_DB=ci_katalogus +POSTGRES_DB=test -KATALOGUS_DB_URI=postgresql://postgres:postgres@ci_katalogus-db:5432/ci_katalogus +KATALOGUS_DB_URI=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@ci_katalogus-db:5432/${POSTGRES_DB} CI=1 -ENCRYPTION_MIDDLEWARE=NACL_SEALBOX +BOEFJES_ENCRYPTION_MIDDLEWARE=NACL_SEALBOX KATALOGUS_PRIVATE_KEY_B64=Vpb0g34rGFbnoUuiSjkFr8TKh278AViSJEdjII5DvQY= KATALOGUS_PUBLIC_KEY_B64=iR/vPrBVrx0LXOiwK6DMB3QCggjzQXDtj/hyVK7mpy8= +BOEFJES_API=http://placeholder:1234 + + +# Benchmark setup +RABBITMQ_DEFAULT_VHOST=kat +RABBITMQ_DEFAULT_USER=ci_user +RABBITMQ_DEFAULT_PASS=ci_pass + +QUEUE_URI=amqp://${RABBITMQ_DEFAULT_USER}:${RABBITMQ_DEFAULT_PASS}@ci_rabbitmq:5672/${RABBITMQ_DEFAULT_VHOST} + +KATALOGUS_API=http://ci_katalogus:8080 +OCTOPOES_API=http://ci_octopoes:80 +XTDB_URI=http://ci_xtdb:3000 +BYTES_API=http://ci_bytes:8000 +SCHEDULER_API=http://placeholder:8000 + +CI=1 + +# CI Bytes configuration + +BYTES_SECRET=3d54f6e4e65723aa678d17d8fd22aba5234136d3e44e5a77305dedaa8ce13f45 +BYTES_ACCESS_TOKEN_EXPIRE_MINUTES=1000 +BYTES_USERNAME=test +BYTES_PASSWORD=secret +BYTES_ENCRYPTION_MIDDLEWARE=IDENTITY + +BYTES_DB_URI=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@ci_bytes-db:5432/${POSTGRES_DB} +BYTES_LOG_FILE=/var/log/bytes-test.log +BYTES_FILE_PERMISSION=555 + +BYTES_METRICS_TTL_SECONDS=0 diff --git a/boefjes/.ci/docker-compose.yml b/boefjes/.ci/docker-compose.yml index 16d8686e789..407d1678336 100644 --- a/boefjes/.ci/docker-compose.yml +++ b/boefjes/.ci/docker-compose.yml @@ -17,3 +17,94 @@ services: image: docker.io/library/postgres:15 env_file: - .ci/.env.test + + migration_bench: + build: + context: .. + dockerfile: boefjes/Dockerfile + args: + - ENVIRONMENT=dev + command: bash -c "python -m cProfile -o .ci/bench_$(date +%Y_%m_%d-%H:%M:%S).pstat -m pytest -v -m slow tests/integration" + depends_on: + - ci_bytes + - ci_octopoes + - ci_katalogus-db + env_file: + - .ci/.env.test + volumes: + - .:/app/boefjes + environment: + - DATABASE_MIGRATION=1 + + ci_bytes: + build: + context: ../bytes + args: + ENVIRONMENT: dev + command: uvicorn bytes.api:app --host 0.0.0.0 + depends_on: + ci_rabbitmq: + condition: service_healthy + ci_bytes-db: + condition: service_started + env_file: + - .ci/.env.test + environment: + - DATABASE_MIGRATION=1 + + ci_bytes-db: + image: docker.io/library/postgres:15 + env_file: + - .ci/.env.test + + ci_octopoes: + build: + context: ../octopoes + command: uvicorn octopoes.api.api:app --host 0.0.0.0 --port 80 + depends_on: + ci_rabbitmq: + condition: service_healthy + ci_xtdb: + condition: service_started + ci_katalogus: + condition: service_started + ci_octopoes_api_worker: + condition: service_started + env_file: + - .ci/.env.test + + ci_rabbitmq: + restart: on-failure + image: "docker.io/library/rabbitmq:3.12-management" + healthcheck: + test: ["CMD", "rabbitmqctl", "status"] + interval: 5s + retries: 4 + env_file: + - .ci/.env.test + + ci_xtdb: + image: "ghcr.io/dekkers/xtdb-http-multinode:v1.0.8" + + ci_octopoes_api_worker: + build: + context: ../octopoes + command: celery -A octopoes.tasks.tasks worker -E --loglevel=INFO + depends_on: + ci_rabbitmq: + condition: service_healthy + ci_xtdb: + condition: service_started + env_file: + - .ci/.env.test + ulimits: + nofile: + soft: 262144 + hard: 262144 + + ci_katalogus: + image: "docker.io/wiremock/wiremock:2.34.0" + volumes: + - .ci/wiremock:/home/wiremock + env_file: + - .ci/.env.test diff --git a/boefjes/.ci/wiremock/mappings/organisations.json b/boefjes/.ci/wiremock/mappings/organisations.json new file mode 100644 index 00000000000..13124e6222f --- /dev/null +++ b/boefjes/.ci/wiremock/mappings/organisations.json @@ -0,0 +1,15 @@ +{ + "request": { + "method": "GET", + "url": "/v1/organisations" + }, + "response": { + "status": 200, + "jsonBody": { + "_dev": { + "id": "_dev", + "name": "Development Organisation" + } + } + } +} diff --git a/boefjes/Makefile b/boefjes/Makefile index 579543e3926..09e5fc21b47 100644 --- a/boefjes/Makefile +++ b/boefjes/Makefile @@ -77,6 +77,12 @@ itest: ## Run the integration tests. $(ci-docker-compose) run --rm katalogus_integration $(ci-docker-compose) down +bench: ## Run the report benchmark. + $(ci-docker-compose) build + $(ci-docker-compose) down --remove-orphans + $(ci-docker-compose) run --rm migration_bench + $(ci-docker-compose) stop + debian12: docker run --rm \ --env PKG_NAME=kat-boefjes \ diff --git a/boefjes/boefjes/clients/bytes_client.py b/boefjes/boefjes/clients/bytes_client.py index 747a4aefcd5..c2698523183 100644 --- a/boefjes/boefjes/clients/bytes_client.py +++ b/boefjes/boefjes/clients/bytes_client.py @@ -1,4 +1,5 @@ import typing +import uuid from collections.abc import Callable, Set from functools import wraps from typing import Any @@ -89,6 +90,13 @@ def save_normalizer_meta(self, normalizer_meta: NormalizerMeta) -> None: self._verify_response(response) + @retry_with_login + def get_normalizer_meta(self, normalizer_meta_id: uuid.UUID) -> NormalizerMeta: + response = self._session.get(f"/bytes/normalizer_meta/{normalizer_meta_id}", headers=self.headers) + self._verify_response(response) + + return NormalizerMeta.model_validate_json(response.content) + @retry_with_login def save_raw(self, boefje_meta_id: str, raw: str | bytes, mime_types: Set[str] = frozenset()) -> UUID: headers = {"content-type": "application/octet-stream"} diff --git a/boefjes/boefjes/dependencies/plugins.py b/boefjes/boefjes/dependencies/plugins.py index c99896aab11..c6f922ce9d4 100644 --- a/boefjes/boefjes/dependencies/plugins.py +++ b/boefjes/boefjes/dependencies/plugins.py @@ -52,7 +52,7 @@ def get_all(self, organisation_id: str) -> list[PluginType]: return [self._set_plugin_enabled(plugin, organisation_id) for plugin in all_plugins.values()] - def _get_all_without_enabled(self): + def _get_all_without_enabled(self) -> dict[str, PluginType]: all_plugins = {plugin.id: plugin for plugin in self.local_repo.get_all()} for plugin in self.plugin_storage.get_all(): diff --git a/boefjes/boefjes/job_handler.py b/boefjes/boefjes/job_handler.py index 95a53406cb5..5b165ecc260 100644 --- a/boefjes/boefjes/job_handler.py +++ b/boefjes/boefjes/job_handler.py @@ -209,6 +209,7 @@ def handle(self, normalizer_meta: NormalizerMeta) -> None: Observation( method=normalizer_meta.normalizer.id, source=reference, + source_method=normalizer_meta.raw_data.boefje_meta.boefje.id, task_id=normalizer_meta.id, valid_time=normalizer_meta.raw_data.boefje_meta.ended_at, result=[ooi for ooi in observation.results if ooi.primary_key != observation.input_ooi], @@ -219,6 +220,7 @@ def handle(self, normalizer_meta: NormalizerMeta) -> None: connector.save_declaration( Declaration( method=normalizer_meta.normalizer.id, + source_method=normalizer_meta.raw_data.boefje_meta.boefje.id, ooi=declaration.ooi, task_id=normalizer_meta.id, valid_time=normalizer_meta.raw_data.boefje_meta.ended_at, @@ -229,6 +231,7 @@ def handle(self, normalizer_meta: NormalizerMeta) -> None: connector.save_affirmation( Affirmation( method=normalizer_meta.normalizer.id, + source_method=normalizer_meta.raw_data.boefje_meta.boefje.id, ooi=affirmation.ooi, task_id=normalizer_meta.id, valid_time=normalizer_meta.raw_data.boefje_meta.ended_at, diff --git a/boefjes/pyproject.toml b/boefjes/pyproject.toml index bec30a07305..0b21d41aa68 100644 --- a/boefjes/pyproject.toml +++ b/boefjes/pyproject.toml @@ -85,14 +85,15 @@ line-length = 120 transform-concats = true [tool.pytest.ini_options] +addopts = "-m 'not slow'" env = [ - "KATALOGUS_DB_URI=postgresql://postgres:postgres@ci_katalogus-db:5432/ci_katalogus", - "QUEUE_URI=amqp://placeholder", - "BOEFJE_API=http://placeholder:8006", - "KATALOGUS_API=http://placeholder:8000", - "OCTOPOES_API=http://placeholder:8001", - "SCHEDULER_API=http://placeholder:8002", - "BYTES_API=http://placeholder:8003", - "BYTES_USERNAME=placeholder", - "BYTES_PASSWORD=placeholder", + "D:KATALOGUS_DB_URI=postgresql://postgres:postgres@ci_katalogus-db:5432/ci_katalogus", + "D:QUEUE_URI=amqp://placeholder", + "D:BOEFJE_API=http://placeholder:8006", + "D:KATALOGUS_API=http://placeholder:8000", + "D:OCTOPOES_API=http://placeholder:8001", + "D:SCHEDULER_API=http://placeholder:8002", + "D:BYTES_API=http://placeholder:8003", + "D:BYTES_USERNAME=placeholder", + "D:BYTES_PASSWORD=placeholder", ] diff --git a/boefjes/tests/conftest.py b/boefjes/tests/conftest.py index e65a1b0e754..fe1a5d6b789 100644 --- a/boefjes/tests/conftest.py +++ b/boefjes/tests/conftest.py @@ -1,6 +1,8 @@ import multiprocessing import time +import uuid from datetime import datetime, timezone +from ipaddress import ip_address from multiprocessing import Manager from pathlib import Path from uuid import UUID @@ -8,12 +10,24 @@ import pytest from fastapi.testclient import TestClient from pydantic import TypeAdapter +from sqlalchemy.orm import sessionmaker from boefjes.app import SchedulerWorkerManager +from boefjes.clients.bytes_client import BytesAPIClient from boefjes.clients.scheduler_client import Queue, QueuePrioritizedItem, SchedulerClientInterface, Task, TaskStatus -from boefjes.config import Settings +from boefjes.config import Settings, settings +from boefjes.job_handler import bytes_api_client from boefjes.job_models import BoefjeMeta, NormalizerMeta +from boefjes.models import Organisation from boefjes.runtime_interfaces import Handler, WorkerManager +from boefjes.sql.db import SQL_BASE, get_engine +from boefjes.sql.organisation_storage import SQLOrganisationStorage +from octopoes.api.models import Declaration, Observation +from octopoes.connector.octopoes import OctopoesAPIConnector +from octopoes.models import OOI +from octopoes.models.ooi.dns.zone import Hostname +from octopoes.models.ooi.network import IPAddressV4, IPAddressV6, IPPort, Network +from octopoes.models.ooi.service import IPService, Service from tests.loading import get_dummy_data @@ -131,3 +145,104 @@ def api(tmp_path): from boefjes.api import app return TestClient(app) + + +@pytest.fixture +def organisation_repository(): + engine = get_engine() + session = sessionmaker(bind=engine)() + + yield SQLOrganisationStorage(session, settings) + + session.execute(";".join([f"TRUNCATE TABLE {t} CASCADE" for t in SQL_BASE.metadata.tables])) + session.close() + + +@pytest.fixture +def organisation(organisation_repository) -> Organisation: + organisation = Organisation(id="test", name="Test org") + + with organisation_repository as repo: + repo.create(organisation) + + return organisation + + +@pytest.fixture +def octopoes_api_connector(organisation) -> OctopoesAPIConnector: + connector = OctopoesAPIConnector(str(settings.octopoes_api), organisation.id) + connector.create_node() + yield connector + connector.delete_node() + + +@pytest.fixture +def bytes_client(request) -> BytesAPIClient: + return bytes_api_client + + +@pytest.fixture +def valid_time(): + return datetime.now(timezone.utc) + + +def seed_system( + octopoes_api_connector: OctopoesAPIConnector, + valid_time: datetime, + test_hostname: str = "example.com", + test_ip: str = "192.0.2.3", + test_ipv6: str = "3e4d:64a2:cb49:bd48:a1ba:def3:d15d:9230", + method: str = "kat_nmap_normalize", +) -> dict[str, list[OOI]]: + network = Network(name="test") + octopoes_api_connector.save_declaration(Declaration(ooi=network, valid_time=valid_time)) + + hostnames = [ + Hostname(network=network.reference, name=test_hostname), + Hostname(network=network.reference, name=f"a.{test_hostname}"), + Hostname(network=network.reference, name=f"b.{test_hostname}"), + Hostname(network=network.reference, name=f"c.{test_hostname}"), + Hostname(network=network.reference, name=f"d.{test_hostname}"), + Hostname(network=network.reference, name=f"e.{test_hostname}"), + Hostname(network=network.reference, name=f"f.{test_hostname}"), + ] + + addresses = [ + IPAddressV4(network=network.reference, address=ip_address(test_ip)), + IPAddressV6(network=network.reference, address=ip_address(test_ipv6)), + ] + ports = [ + IPPort(address=addresses[0].reference, protocol="tcp", port=25), + IPPort(address=addresses[0].reference, protocol="tcp", port=443), + IPPort(address=addresses[0].reference, protocol="tcp", port=22), + IPPort(address=addresses[1].reference, protocol="tcp", port=80), + ] + services = [Service(name="smtp"), Service(name="https"), Service(name="http"), Service(name="ssh")] + ip_services = [ + IPService(ip_port=ports[0].reference, service=services[0].reference), + IPService(ip_port=ports[1].reference, service=services[1].reference), + IPService(ip_port=ports[2].reference, service=services[3].reference), + IPService(ip_port=ports[3].reference, service=services[2].reference), + ] + + oois = hostnames + addresses + ports + services + ip_services + + octopoes_api_connector.save_observation( + Observation( + method=method, + source_method=None, + source=hostnames[0].reference, + task_id=uuid.uuid4(), + valid_time=valid_time, + result=oois, + ) + ) + octopoes_api_connector.recalculate_bits() + + return { + "hostnames": hostnames, + "addresses": addresses, + "ports": ports, + "services": services, + "ip_services": ip_services, + } diff --git a/boefjes/tests/integration/test_bench.py b/boefjes/tests/integration/test_bench.py new file mode 100644 index 00000000000..a77d5732092 --- /dev/null +++ b/boefjes/tests/integration/test_bench.py @@ -0,0 +1,113 @@ +import json +import uuid +from pathlib import Path + +import pytest +from tools.upgrade_v1_16_0 import upgrade + +from boefjes.clients.bytes_client import BytesAPIClient +from boefjes.config import BASE_DIR +from boefjes.sql.organisation_storage import SQLOrganisationStorage +from octopoes.connector.octopoes import OctopoesAPIConnector +from octopoes.models import Reference +from octopoes.models.origin import OriginType +from tests.conftest import seed_system +from tests.loading import get_boefje_meta, get_normalizer_meta + + +@pytest.mark.slow +def test_migration( + octopoes_api_connector: OctopoesAPIConnector, + bytes_client: BytesAPIClient, + organisation_repository: SQLOrganisationStorage, + valid_time, +): + octopoes_api_connector.session._timeout.connect = 60 + octopoes_api_connector.session._timeout.read = 60 + + iterations = 30 + cache_path = Path(BASE_DIR.parent / ".ci" / f".cache_{iterations}.json") + hostname_range = range(0, iterations) + + if cache_path.exists(): + export = json.load(cache_path.open()) + exported = json.dumps(export) + else: + for x in hostname_range: + seed_system( + octopoes_api_connector, + valid_time, + test_hostname=f"{x}.com", + test_ip=f"192.0.{x % 7}.{x % 13}", + test_ipv6=f"{x % 7}e4d:64a2:cb49:bd48:a1ba:def3:d15d:{x % 5}230", + method="kat_nmap_normalize" if x % 3 == 0 else "kat_dns_normalize", # 30% of the origins need Bytes + ) + + export = [] + + # Drop the source method field to test the migration + for tx in octopoes_api_connector.export_all(): + if "txOps" in tx: + ops = [] + for tx_op in tx["txOps"]: + if "source_method" in tx_op[1]: + del tx_op[1]["source_method"] + + ops.append(tx_op) + + tx["txOps"] = ops + + export.append(tx) + + exported = json.dumps(export) + cache_path.write_text(exported) + + octopoes_api_connector.import_new(exported) + + raw = b"1234567890" + bytes_client.login() + + for method in ["kat_nmap_normalize", "kat_dns_normalize"]: + for origin in octopoes_api_connector.list_origins( + valid_time, method=method, origin_type=OriginType.OBSERVATION + ): + boefje_id = "boefje_" + method + + if "3.com" in origin.source: # create one udp scan + boefje_id = "boefje_udp" + + boefje_meta = get_boefje_meta(uuid.uuid4(), boefje_id=boefje_id) + bytes_client.save_boefje_meta(boefje_meta) + raw_data_id = bytes_client.save_raw(boefje_meta.id, raw) + + normalizer_meta = get_normalizer_meta(boefje_meta, raw_data_id) + normalizer_meta.id = origin.task_id + normalizer_meta.normalizer.id = method + + bytes_client.save_normalizer_meta(normalizer_meta) + + total_oois = octopoes_api_connector.list_objects(set(), valid_time).count + total_processed, total_failed = upgrade(organisation_repository, valid_time) + + assert total_processed == len(hostname_range) + assert total_failed == 0 + + observation = octopoes_api_connector.list_origins( + valid_time, source=Reference.from_str("Hostname|test|0.com"), origin_type=OriginType.OBSERVATION + )[0] + assert observation.method == "kat_nmap_normalize" + assert observation.source_method == "boefje_kat_nmap_normalize" + + observation = octopoes_api_connector.list_origins( + valid_time, source=Reference.from_str("Hostname|test|1.com"), origin_type=OriginType.OBSERVATION + )[0] + assert observation.method == "kat_dns_normalize" + assert observation.source_method == "dns-records" # the logic has found the right boefje id + + observation = octopoes_api_connector.list_origins( + valid_time, source=Reference.from_str("Hostname|test|3.com"), origin_type=OriginType.OBSERVATION + )[0] + assert observation.method == "kat_nmap_normalize" + assert observation.source_method == "boefje_udp" + + assert octopoes_api_connector.list_objects(set(), valid_time).count == total_oois diff --git a/boefjes/tools/upgrade_v1_16_0.py b/boefjes/tools/upgrade_v1_16_0.py new file mode 100755 index 00000000000..b60977c1e08 --- /dev/null +++ b/boefjes/tools/upgrade_v1_16_0.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python3 + +"""Migration script for v1.16.0 due to a bug in the garbage collection. To be removed in later versions. +https://github.com/minvws/nl-kat-coordination/issues/2875""" + +import json +import logging.config +import sys +from datetime import datetime, timezone +from pathlib import Path + +import click +from httpx import HTTPStatusError +from sqlalchemy.orm import sessionmaker + +from boefjes.api import get_bytes_client +from boefjes.config import settings +from boefjes.dependencies.plugins import PluginService +from boefjes.job_handler import get_octopoes_api_connector +from boefjes.local_repository import get_local_repository +from boefjes.models import Boefje +from boefjes.sql.config_storage import create_config_storage +from boefjes.sql.db import get_engine +from boefjes.sql.organisation_storage import create_organisation_storage +from boefjes.sql.plugin_storage import create_plugin_storage +from boefjes.storage.interfaces import OrganisationStorage +from octopoes.models.origin import OriginType + +sys.path.append(str(Path(__file__).resolve().parent.parent)) + + +with settings.log_cfg.open() as f: + logging.config.dictConfig(json.load(f)) + +logger = logging.getLogger(__name__) + + +def upgrade(organisation_repository: OrganisationStorage, valid_time: datetime | None = None) -> tuple[int, int]: + """ + Perform the migration for all organisations in the database. The happy flow in this script is idempotent, + meaning that it can be rerun until there are no, or only expected, exceptions. + """ + if valid_time is None: + valid_time = datetime.now(timezone.utc) + + bytes_client = get_bytes_client() + bytes_client.login() + + total_failed = 0 + total_processed = 0 + + organisations = organisation_repository.get_all() + logger.info("Processing %s organisations in total", len(organisations)) + + boefjes_per_normalizer = collect_boefjes_per_normalizer() + logger.info("Found %s normalizers", len(boefjes_per_normalizer)) + + for organisation_id in organisations: + connector = get_octopoes_api_connector(organisation_id) + logger.info("Processing organisation [organization_id=%s]", organisation_id) + + failed, processed = migrate_organisation( + bytes_client, connector, organisation_id, boefjes_per_normalizer, valid_time + ) + total_failed += failed + total_processed += processed + + logger.info("Processed organisation [total_processed=%s, total_failed=%s]", processed, failed) + + logger.info("Finished migration [total_processed=%s, total_failed=%s]", total_processed, total_failed) + + return total_processed, total_failed + + +def migrate_organisation( + bytes_client, connector, organisation_id, boefjes_per_normalizer, valid_time +) -> tuple[int, int]: + """ + For each organisation, we paginate through the origin API, find the matching normalizer meta in Bytes, + and set the source_method to the boefje id. Then update the origin, i.e. save it and delete the old one. + """ + + failed = 0 + processed = 0 + + offset = 0 + page_size = 200 + + bulk_updated_origins = [] + + while True: + # We loop through the paginated API until we reach the end + + origins = connector.list_origins( + valid_time, method=[x for x in boefjes_per_normalizer], offset=offset, limit=page_size + ) + logger.info("Processing %s origins", len(origins)) + + for origin in origins: + if origin.source_method is not None or origin.origin_type == OriginType.INFERENCE: + continue + + if origin.method in boefjes_per_normalizer and len(boefjes_per_normalizer[origin.method]) == 1: + origin.source_method = boefjes_per_normalizer[origin.method][0].id + bulk_updated_origins.append(origin) + continue + + try: + normalizer_meta = bytes_client.get_normalizer_meta(origin.task_id) + origin.source_method = normalizer_meta.raw_data.boefje_meta.boefje.id + bulk_updated_origins.append(origin) + except HTTPStatusError as error: + # We expect to find Declaration/Affirmations without a normalizer meta + if error.response.status_code == 404 and origin.method != "manual": + logger.warning( + "Could not find normalizer_meta [task_id=%s, method=%s, origin_type=%s]", + origin.task_id, + origin.method, + origin.origin_type, + ) + elif error.response.status_code == 404: + logger.info( + "Could not find normalizer_meta [task_id=%s, method=%s, origin_type=%s]", + origin.task_id, + origin.method, + origin.origin_type, + ) + else: + logger.exception( + "Could not find normalizer_meta [task_id=%s, method=%s, origin_type=%s]", + origin.task_id, + origin.method, + origin.origin_type, + ) + failed += 1 + + continue + + if len(origins) < 200: + logger.info("Processed all origins [organization_id=%s]", organisation_id) + break + + offset += page_size + + connector._bulk_migrate_origins(bulk_updated_origins, valid_time) + processed += len(bulk_updated_origins) + + return failed, processed + + +def collect_boefjes_per_normalizer() -> dict[str, list[Boefje]]: + session = sessionmaker(bind=get_engine())() + + all_plugins = PluginService( + create_plugin_storage(session), + create_config_storage(session), + get_local_repository(), + )._get_all_without_enabled() + + normalizers = {} + + for normalizer in [x for x in all_plugins.values() if x.type == "normalizer"]: + boefjes = [] + + for plugin in all_plugins.values(): + if plugin.type == "boefje" and f"boefje/{plugin.id}" in normalizer.consumes: + boefjes.append(plugin) + + normalizers[normalizer.id] = boefjes + + session.close() + + return normalizers + + +@click.command() +def main(): + session = sessionmaker(bind=get_engine())() + organisations = create_organisation_storage(session) + + upgrade(organisations) + + session.close() + + +if __name__ == "__main__": + main() diff --git a/bytes/bytes/api/router.py b/bytes/bytes/api/router.py index c160e3db66b..de424b5a3be 100644 --- a/bytes/bytes/api/router.py +++ b/bytes/bytes/api/router.py @@ -105,8 +105,10 @@ def get_normalizer_meta_by_id( normalizer_meta_id: UUID, meta_repository: MetaDataRepository = Depends(create_meta_data_repository), ) -> NormalizerMeta: - with meta_repository: + try: return meta_repository.get_normalizer_meta_by_id(normalizer_meta_id) + except ObjectNotFoundException as error: + raise HTTPException(status_code=404, detail="Normalizer meta not found") from error @router.get("/normalizer_meta", response_model=list[NormalizerMeta], tags=[NORMALIZER_META_TAG]) diff --git a/docs/source/release_notes/1.13.rst b/docs/source/release_notes/1.13.rst index 5451ce6366e..d66c3b895e1 100644 --- a/docs/source/release_notes/1.13.rst +++ b/docs/source/release_notes/1.13.rst @@ -88,7 +88,7 @@ If you want to switch to Granian you can create the directory ExecStart=/opt/venvs/kat-rocky/bin/granian --interface wsgi rocky.wsgi:application Type=simple -This file is also used by the packagings scripts in new installations to have +This file is also used by the packaging scripts in new installations to have those installations use Granian by default. Do not put any other configuration in this file because it will be automatically removed when upgrading to 1.14. diff --git a/docs/source/release_notes/1.16.rst b/docs/source/release_notes/1.16.rst index 8cd8c69d472..18a2d1bc704 100644 --- a/docs/source/release_notes/1.16.rst +++ b/docs/source/release_notes/1.16.rst @@ -91,6 +91,25 @@ Then follow the steps above using the HTTP endpoints to delete the other entries After these steps, again the normal instructions for upgrading :ref:`Debian packages` or upgrading :ref:`containers ` should be followed. +Running the Origin Migration +================================ +Upon upgrading, one migration needs to be triggered manually. +This is the `boefjes/tools/upgrade_v1_16_0.py` script, which you can run in your ``boefje`` environment using: + +.. code-block:: sh + + python -m tools.upgrade_v1_16_0 + +Or, using Docker: + +.. code-block:: sh + + docker compose exec boefje python -m tools.upgrade_v1_16_0 + +Please check the logs for any errors in the migration. +The script can be run multiple times in case unexpected errors appear, although some warnings are to be expected. +After running the script (ideally once), the next run should log that `total_processed=0` and `total_failed=0`. + Full Changelog ============== diff --git a/octopoes/octopoes/api/models.py b/octopoes/octopoes/api/models.py index 81cbd842b12..e2d2aabd962 100644 --- a/octopoes/octopoes/api/models.py +++ b/octopoes/octopoes/api/models.py @@ -22,6 +22,7 @@ class ServiceHealth(BaseModel): class _BaseObservation(BaseModel): method: str source: Reference + source_method: str | None result: list[OOIType] valid_time: AwareDatetime task_id: uuid.UUID @@ -41,6 +42,7 @@ class Declaration(BaseModel): ooi: OOIType valid_time: datetime method: str | None = None + source_method: str | None = None task_id: uuid.UUID | None = None @@ -50,6 +52,7 @@ class Affirmation(BaseModel): ooi: OOIType valid_time: datetime method: str | None = None + source_method: str | None = None task_id: uuid.UUID | None = None @@ -68,6 +71,7 @@ class ValidatedObservation(_BaseObservation): result: list[ValidatedOOIType] valid_time: AwareDatetime + source_method: str | None = None class ValidatedDeclaration(BaseModel): @@ -76,6 +80,7 @@ class ValidatedDeclaration(BaseModel): ooi: ValidatedOOIType valid_time: AwareDatetime method: str | None = "manual" + source_method: str | None = None task_id: uuid.UUID | None = Field(default_factory=uuid.uuid4) @@ -85,4 +90,5 @@ class ValidatedAffirmation(BaseModel): ooi: ValidatedOOIType valid_time: AwareDatetime method: str | None = "hydration" + source_method: str | None = None task_id: uuid.UUID | None = Field(default_factory=uuid.uuid4) diff --git a/octopoes/octopoes/api/router.py b/octopoes/octopoes/api/router.py index 4c60dadeafa..4e6e0eae6a2 100644 --- a/octopoes/octopoes/api/router.py +++ b/octopoes/octopoes/api/router.py @@ -33,6 +33,7 @@ from octopoes.models.transaction import TransactionRecord from octopoes.models.tree import ReferenceTree from octopoes.models.types import type_by_name +from octopoes.repositories.origin_repository import XTDBOriginRepository from octopoes.version import __version__ from octopoes.xtdb.client import Operation, OperationType, XTDBSession from octopoes.xtdb.exceptions import XTDBException @@ -251,6 +252,17 @@ def delete_object( octopoes.commit() +@router.delete("/origins", tags=["Origins"]) +def delete_origin( + origin_id: str, + octopoes: OctopoesService = Depends(octopoes_service), + valid_time: datetime = Depends(extract_valid_time), +) -> None: + origin = octopoes.origin_repository.get(origin_id, valid_time) + octopoes.origin_repository.delete(origin, valid_time) + octopoes.commit() + + @router.post("/objects/delete_many", tags=["Objects"]) def delete_many( octopoes: OctopoesService = Depends(octopoes_service), @@ -283,16 +295,22 @@ def get_tree( def list_origins( octopoes: OctopoesService = Depends(octopoes_service), valid_time: datetime = Depends(extract_valid_time), + offset: int = 0, + limit: int | None = None, source: Reference | None = Query(None), result: Reference | None = Query(None), + method: str | list[str] | None = Query(None), task_id: uuid.UUID | None = Query(None), origin_type: OriginType | None = Query(None), ) -> list[Origin]: return octopoes.origin_repository.list_origins( valid_time, task_id=task_id, + offset=offset, + limit=limit, source=source, result=result, + method=method, origin_type=origin_type, ) @@ -315,6 +333,7 @@ def save_observation( origin_type=OriginType.OBSERVATION, method=observation.method, source=observation.source, + source_method=observation.source_method, result=[ooi.reference for ooi in observation.result], task_id=observation.task_id, ) @@ -331,6 +350,7 @@ def save_declaration( origin_type=OriginType.DECLARATION, method=declaration.method if declaration.method else "manual", source=declaration.ooi.reference, + source_method=declaration.source_method, result=[declaration.ooi.reference], task_id=declaration.task_id if declaration.task_id else uuid.uuid4(), ) @@ -347,6 +367,7 @@ def save_affirmation( origin_type=OriginType.AFFIRMATION, method=affirmation.method if affirmation.method else "hydration", source=affirmation.ooi.reference, + source_method=affirmation.source_method, result=[affirmation.ooi.reference], task_id=affirmation.task_id if affirmation.task_id else uuid.uuid4(), ) @@ -494,7 +515,12 @@ def delete_node(xtdb_session_: XTDBSession = Depends(xtdb_session)) -> None: @router.post("/bits/recalculate", tags=["Bits"]) def recalculate_bits(octopoes: OctopoesService = Depends(octopoes_service)) -> int: - inference_count = octopoes.recalculate_bits() + try: + inference_count = octopoes.recalculate_bits() + except ObjectNotFoundException: + logger.exception("Failed to recalculate bits") + raise + octopoes.commit() return inference_count @@ -557,3 +583,23 @@ async def importer_new(request: Request, xtdb_session_: XTDBSession = Depends(xt except Exception as e: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Error receiving objects") from e return importer(data, xtdb_session_, True) + + +@router.post("/origins/migrate", tags=["Origins"]) +def migrate_origins( + origins: list[Origin], + session: XTDBSession = Depends(xtdb_session), + valid_time: datetime = Depends(extract_valid_time), +) -> None: + for origin in origins: + if origin.source_method is None: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, detail="Only origins with a new source method can be migrated" + ) + + session.add((OperationType.PUT, XTDBOriginRepository.serialize(origin), valid_time)) + + origin.source_method = None # To ensure the id property has the original pk value that we want to delete + session.add((OperationType.DELETE, origin.id, valid_time)) + + session.commit() # The save-delete order is important to avoid garbage collection of the results diff --git a/octopoes/octopoes/connector/octopoes.py b/octopoes/octopoes/connector/octopoes.py index daca6c5472d..3cb5a26d898 100644 --- a/octopoes/octopoes/connector/octopoes.py +++ b/octopoes/octopoes/connector/octopoes.py @@ -133,8 +133,11 @@ def get_tree( def list_origins( self, valid_time: datetime, + offset: int = DEFAULT_OFFSET, + limit: int = DEFAULT_LIMIT, source: Reference | None = None, result: Reference | None = None, + method: str | list[str] | None = None, task_id: UUID | None = None, origin_type: OriginType | None = None, ) -> list[Origin]: @@ -142,8 +145,11 @@ def list_origins( "valid_time": str(valid_time), "source": source, "result": result, + "offset": offset, + "limit": limit, + "method": method, "task_id": str(task_id) if task_id else None, - "origin_type": str(origin_type) if origin_type else None, + "origin_type": str(origin_type.value) if origin_type else None, } params = {k: v for k, v in params.items() if v is not None} # filter out None values res = self.session.get( @@ -153,6 +159,14 @@ def list_origins( return TypeAdapter(list[Origin]).validate_json(res.content) + def delete_origin(self, origin_id: str, valid_time: datetime) -> None: + params = { + "valid_time": str(valid_time), + "origin_id": origin_id, + } + + self.session.delete(f"/{self.client}/origins", params=params) + def save_observation(self, observation: Observation) -> None: self.session.post( f"/{self.client}/observations", @@ -324,3 +338,11 @@ def import_add(self, content): def import_new(self, content): return self.session.post(f"/{self.client}/io/import/new", content=content).json() + + def _bulk_migrate_origins(self, origins: list[Origin], valid_time: datetime) -> None: + """Single-purpose method that should not be used outside the migration, hence private""" + + params = {"valid_time": str(valid_time)} + self.session.post( + f"/{self.client}/origins/migrate", params=params, json=[json.loads(x.model_dump_json()) for x in origins] + ) diff --git a/octopoes/octopoes/models/origin.py b/octopoes/octopoes/models/origin.py index 8b87d332810..b39ec31e7a2 100644 --- a/octopoes/octopoes/models/origin.py +++ b/octopoes/octopoes/models/origin.py @@ -17,6 +17,7 @@ class Origin(BaseModel): origin_type: OriginType method: str source: Reference + source_method: str | None = None # None for bits and normalizers result: list[Reference] = Field(default_factory=list) task_id: UUID | None = None @@ -28,6 +29,11 @@ def __sub__(self, other) -> set[Reference]: @property def id(self) -> str: + if self.source_method is not None: + return ( + f"{self.__class__.__name__}|{self.origin_type.value}|{self.method}|{self.source_method}|{self.source}" + ) + return f"{self.__class__.__name__}|{self.origin_type.value}|{self.method}|{self.source}" def __eq__(self, other): @@ -35,6 +41,7 @@ def __eq__(self, other): return ( self.origin_type == other.origin_type and self.method == other.method + and self.source_method == other.source_method and self.source == other.source and set(self.result) == set(other.result) ) diff --git a/octopoes/octopoes/repositories/origin_repository.py b/octopoes/octopoes/repositories/origin_repository.py index 1f9ca2e9d64..252f166b1cd 100644 --- a/octopoes/octopoes/repositories/origin_repository.py +++ b/octopoes/octopoes/repositories/origin_repository.py @@ -35,6 +35,8 @@ def list_origins( valid_time: datetime, *, task_id: UUID | None = None, + offset: int = 0, + limit: int | None = None, source: Reference | None = None, result: Reference | None = None, method: str | list[str] | None = None, @@ -72,6 +74,8 @@ def list_origins( valid_time: datetime, *, task_id: UUID | None = None, + offset: int = 0, + limit: int | None = None, source: Reference | None = None, result: Reference | None = None, method: str | list[str] | None = None, @@ -97,6 +101,8 @@ def list_origins( query = generate_pull_query( FieldSet.ALL_FIELDS, where_parameters, + offset=offset, + limit=limit, ) results = self.session.client.query(query, valid_time=valid_time) diff --git a/octopoes/tests/conftest.py b/octopoes/tests/conftest.py index da309daa0d2..3fdd1f0f385 100644 --- a/octopoes/tests/conftest.py +++ b/octopoes/tests/conftest.py @@ -422,8 +422,9 @@ def seed_system(xtdb_ooi_repository: XTDBOOIRepository, xtdb_origin_repository: network_origin = Origin( origin_type=OriginType.DECLARATION, - method="manual", + method="kat_manual_csv", source=network.reference, + source_method="manual", result=[network.reference], task_id=uuid.uuid4(), ) @@ -434,6 +435,7 @@ def seed_system(xtdb_ooi_repository: XTDBOOIRepository, xtdb_origin_repository: origin_type=OriginType.OBSERVATION, method="", source=network.reference, + source_method="manual", result=[ooi.reference for ooi in oois], task_id=uuid.uuid4(), ) diff --git a/octopoes/tests/integration/test_api_connector.py b/octopoes/tests/integration/test_api_connector.py index e73eef80880..b57693e5fd5 100644 --- a/octopoes/tests/integration/test_api_connector.py +++ b/octopoes/tests/integration/test_api_connector.py @@ -10,7 +10,8 @@ from octopoes.models import OOI, DeclaredScanProfile, Reference, ScanLevel from octopoes.models.ooi.dns.records import DNSAAAARecord, DNSARecord, DNSMXRecord, DNSNSRecord from octopoes.models.ooi.dns.zone import Hostname -from octopoes.models.ooi.network import IPAddressV4, IPAddressV6, IPPort, Network +from octopoes.models.ooi.findings import Finding, KATFindingType, RiskLevelSeverity +from octopoes.models.ooi.network import IPAddressV4, IPAddressV6, IPPort, Network, PortState, Protocol from octopoes.models.ooi.service import IPService, Service from octopoes.models.ooi.web import Website from octopoes.models.origin import OriginType @@ -34,6 +35,7 @@ def test_bulk_operations(octopoes_api_connector: OctopoesAPIConnector, valid_tim Observation( method="normalizer_id", source=network.reference, + source_method="manual", task_id=task_id, valid_time=valid_time, result=hostnames, @@ -55,6 +57,7 @@ def test_bulk_operations(octopoes_api_connector: OctopoesAPIConnector, valid_tim "method": "normalizer_id", "origin_type": OriginType.OBSERVATION, "source": network.reference, + "source_method": "manual", "result": [hostname.reference for hostname in hostnames], "task_id": task_id, } @@ -153,6 +156,7 @@ def test_query(octopoes_api_connector: OctopoesAPIConnector, valid_time: datetim Observation( method="normalizer_id", source=network.reference, + source_method="manual", task_id=uuid.uuid4(), valid_time=valid_time, result=all_new_oois, @@ -221,3 +225,98 @@ def test_query(octopoes_api_connector: OctopoesAPIConnector, valid_time: datetim assert len(result) == 3 assert result[0][0] == hostnames[0].reference assert result[0][1] == dns_ns_records[0] + + +def test_no_disappearing_ports(octopoes_api_connector: OctopoesAPIConnector): + first_valid_time = datetime.now(timezone.utc) + import time + + network = Network(name="test") + octopoes_api_connector.save_declaration( + Declaration( + ooi=network, + valid_time=first_valid_time, + ) + ) + + ip = IPAddressV4(network=network.reference, address="10.10.10.10") + tcp_port = IPPort( + address=ip.reference, + protocol=Protocol.TCP, + port=3306, + state=PortState.OPEN, + ) + + octopoes_api_connector.save_observation( + Observation( + method="kat_nmap_normalize", + source=ip.reference, + source_method="nmap", + task_id=uuid.uuid4(), + valid_time=first_valid_time, + result=[ip, tcp_port], + ) + ) + + octopoes_api_connector.save_many_scan_profiles( + [DeclaredScanProfile(reference=ooi.reference, level=ScanLevel.L2) for ooi in [ip, tcp_port, network]], + first_valid_time, + ) + second_valid_time = datetime.now(timezone.utc) + + time.sleep(2) + octopoes_api_connector.recalculate_bits() + time.sleep(2) + + findings = octopoes_api_connector.list_findings({severity for severity in RiskLevelSeverity}, second_valid_time) + + assert findings.items == [ + Finding( + finding_type=KATFindingType(id="KAT-OPEN-DATABASE-PORT").reference, + description="Port 3306/tcp is a database port and should not be open.", + ooi=tcp_port.reference, + ) + ] + + udp_port = IPPort( + address=ip.reference, + protocol=Protocol.UDP, + port=53, + state=PortState.OPEN, + ) + + octopoes_api_connector.save_observation( + Observation( + method="kat_nmap_normalize", + source=ip.reference, + source_method="nmap-udp", + task_id=uuid.uuid4(), + valid_time=second_valid_time, + result=[ip, udp_port], + ) + ) + + octopoes_api_connector.save_scan_profile( + DeclaredScanProfile(reference=udp_port.reference, level=ScanLevel.L2), + second_valid_time, + ) + + assert octopoes_api_connector.get(udp_port.reference, second_valid_time) + + octopoes_api_connector.recalculate_bits() + time.sleep(2) + + third_valid_time = datetime.now(timezone.utc) + + assert octopoes_api_connector.get(udp_port.reference, third_valid_time) + + findings = octopoes_api_connector.list_findings({severity for severity in RiskLevelSeverity}, third_valid_time) + assert octopoes_api_connector.get(tcp_port.reference, third_valid_time) + + assert findings.items == [ + Finding( + finding_type=KATFindingType(id="KAT-OPEN-DATABASE-PORT").reference, + description="Port 3306/tcp is a database port and should not be open.", + ooi=tcp_port.reference, + ) + ] diff --git a/octopoes/tests/integration/test_unicode.py b/octopoes/tests/integration/test_unicode.py index b57bbc83895..dbdc14019d9 100644 --- a/octopoes/tests/integration/test_unicode.py +++ b/octopoes/tests/integration/test_unicode.py @@ -54,6 +54,7 @@ def test_unicode_hostname(octopoes_api_connector: OctopoesAPIConnector, valid_ti Observation( method=NAMES[2], source=network.reference, + source_method="test", task_id=task_id, valid_time=valid_time, result=[hostname], @@ -80,6 +81,7 @@ def test_unicode_hostname(octopoes_api_connector: OctopoesAPIConnector, valid_ti "method": NAMES[2], "origin_type": OriginType.OBSERVATION, "source": network.reference, + "source_method": "test", "result": [hostname.reference], "task_id": task_id, } diff --git a/rocky/tests/integration/conftest.py b/rocky/tests/integration/conftest.py index 73ae76443cc..fb80952ba6e 100644 --- a/rocky/tests/integration/conftest.py +++ b/rocky/tests/integration/conftest.py @@ -170,7 +170,14 @@ def seed_system( ) octopoes_api_connector.save_observation( - Observation(method="", source=network.reference, task_id=uuid.uuid4(), valid_time=valid_time, result=oois) + Observation( + method="", + source_method="test", + source=network.reference, + task_id=uuid.uuid4(), + valid_time=valid_time, + result=oois, + ) ) octopoes_api_connector.recalculate_bits() From a8feebe38cce657c62aaa474c29c30a40ed914ab Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:01:22 +0200 Subject: [PATCH 052/112] Raw upload with Scan OOIS (#3169) Co-authored-by: ammar92 Co-authored-by: Jan Klopper Co-authored-by: Donny Peeters <46660228+Donnype@users.noreply.github.com> Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> --- boefjes/boefjes/api.py | 4 +- boefjes/boefjes/job_handler.py | 37 ++-------------- boefjes/boefjes/job_models.py | 4 +- boefjes/tests/test_dns.py | 15 +++---- boefjes/tests/test_dnssec.py | 7 ++- boefjes/tests/test_leakix.py | 3 +- boefjes/tests/test_nmap.py | 3 +- octopoes/octopoes/models/__init__.py | 32 +++++++++++++- octopoes/octopoes/models/ooi/scans.py | 17 ++++++++ octopoes/octopoes/models/types.py | 3 ++ rocky/rocky/bytes_client.py | 15 +++++-- rocky/rocky/locale/django.pot | 25 ++++++++++- rocky/rocky/templates/upload_raw.html | 3 ++ rocky/rocky/views/upload_raw.py | 37 +++++++++++++++- rocky/tests/test_upload_raw.py | 43 +++++++++++++----- rocky/tools/forms/settings.py | 2 + rocky/tools/forms/upload_raw.py | 63 ++++++++++++++++++++++++++- 17 files changed, 239 insertions(+), 74 deletions(-) create mode 100644 octopoes/octopoes/models/ooi/scans.py diff --git a/boefjes/boefjes/api.py b/boefjes/boefjes/api.py index 07f768a5b24..155d609c973 100644 --- a/boefjes/boefjes/api.py +++ b/boefjes/boefjes/api.py @@ -13,7 +13,7 @@ from boefjes.clients.bytes_client import BytesAPIClient from boefjes.clients.scheduler_client import SchedulerAPIClient, TaskStatus from boefjes.config import settings -from boefjes.job_handler import get_environment_settings, get_octopoes_api_connector, serialize_ooi +from boefjes.job_handler import get_environment_settings, get_octopoes_api_connector from boefjes.job_models import BoefjeMeta from boefjes.local_repository import LocalPluginRepository, get_local_repository from boefjes.plugins.models import _default_mime_types @@ -165,7 +165,7 @@ def create_boefje_meta(task, local_repository): except ObjectNotFoundException as e: raise ObjectNotFoundException(f"Object {reference} not found in Octopoes") from e - arguments["input"] = serialize_ooi(ooi) + arguments["input"] = ooi.serialize() boefje_meta = BoefjeMeta( id=task.id, diff --git a/boefjes/boefjes/job_handler.py b/boefjes/boefjes/job_handler.py index 5b165ecc260..a7e0d4feca1 100644 --- a/boefjes/boefjes/job_handler.py +++ b/boefjes/boefjes/job_handler.py @@ -2,8 +2,7 @@ import traceback from collections.abc import Callable from datetime import datetime, timezone -from enum import Enum -from typing import Any, cast +from typing import cast import httpx import structlog @@ -12,13 +11,13 @@ from boefjes.clients.bytes_client import BytesAPIClient from boefjes.config import settings from boefjes.docker_boefjes_runner import DockerBoefjesRunner -from boefjes.job_models import BoefjeMeta, NormalizerMeta, SerializedOOI, SerializedOOIValue +from boefjes.job_models import BoefjeMeta, NormalizerMeta from boefjes.local_repository import LocalPluginRepository from boefjes.plugins.models import _default_mime_types from boefjes.runtime_interfaces import BoefjeJobRunner, Handler, NormalizerJobRunner from octopoes.api.models import Affirmation, Declaration, Observation from octopoes.connector.octopoes import OctopoesAPIConnector -from octopoes.models import OOI, Reference, ScanLevel +from octopoes.models import Reference, ScanLevel from octopoes.models.exception import ObjectNotFoundException MIMETYPE_MIN_LENGTH = 5 # two chars before, and 2 chars after the slash ought to be reasonable @@ -32,34 +31,6 @@ ) -def _serialize_value(value: Any, required: bool) -> SerializedOOIValue: - if isinstance(value, list): - return [_serialize_value(item, required) for item in value] - if isinstance(value, Reference): - try: - return value.tokenized.root - except AttributeError: - if required: - raise - - return None - if isinstance(value, Enum): - return value.value - if isinstance(value, int | float): - return value - else: - return str(value) - - -def serialize_ooi(ooi: OOI) -> SerializedOOI: - serialized_oois = {} - for key, value in ooi: - if key not in ooi.model_fields: - continue - serialized_oois[key] = _serialize_value(value, ooi.model_fields[key].is_required()) - return serialized_oois - - def get_octopoes_api_connector(org_code: str) -> OctopoesAPIConnector: return OctopoesAPIConnector(str(settings.octopoes_api), org_code) @@ -124,7 +95,7 @@ def handle(self, boefje_meta: BoefjeMeta) -> None: except ObjectNotFoundException as e: raise ObjectNotFoundException(f"Object {reference} not found in Octopoes") from e - boefje_meta.arguments["input"] = serialize_ooi(ooi) + boefje_meta.arguments["input"] = ooi.serialize() env_keys = boefje_resource.environment_keys diff --git a/boefjes/boefjes/job_models.py b/boefjes/boefjes/job_models.py index 9d1a0e49aca..0d40cb497c3 100644 --- a/boefjes/boefjes/job_models.py +++ b/boefjes/boefjes/job_models.py @@ -4,7 +4,7 @@ from pydantic import AwareDatetime, BaseModel, Field, StringConstraints -from octopoes.models import DeclaredScanProfile, PrimaryKeyToken +from octopoes.models import DeclaredScanProfile from octopoes.models.types import OOIType @@ -100,5 +100,3 @@ class NormalizerResults(BaseModel): NormalizerOutput: TypeAlias = OOIType | NormalizerDeclaration | NormalizerAffirmation | DeclaredScanProfile -SerializedOOIValue: TypeAlias = None | str | int | float | dict[str, str | PrimaryKeyToken] | list["SerializedOOIValue"] -SerializedOOI: TypeAlias = dict[str, SerializedOOIValue] diff --git a/boefjes/tests/test_dns.py b/boefjes/tests/test_dns.py index 6f47e22f457..0ae1124b0f8 100644 --- a/boefjes/tests/test_dns.py +++ b/boefjes/tests/test_dns.py @@ -5,7 +5,6 @@ from pydantic import BaseModel -from boefjes.job_handler import serialize_ooi from boefjes.job_models import Boefje, BoefjeMeta, Normalizer, NormalizerMeta, ObservationsWithoutInputOOI, RawDataMeta from boefjes.local import LocalNormalizerJobRunner from boefjes.local_repository import LocalPluginRepository @@ -447,14 +446,12 @@ def test_find_parent_dns_zone(self): minimum=86400, ) - input_ = serialize_ooi( - DNSZone( - hostname=Hostname( - network=Reference.from_str("Network|internet"), - name="sub.example.nl", - ).reference - ) - ) + input_ = DNSZone( + hostname=Hostname( + network=Reference.from_str("Network|internet"), + name="sub.example.nl", + ).reference + ).serialize() meta = NormalizerMeta( id=uuid.UUID("ee8374bb-e79f-4083-9ce9-add4f96006f2"), diff --git a/boefjes/tests/test_dnssec.py b/boefjes/tests/test_dnssec.py index ffdb5171005..b5b36c2e3c1 100644 --- a/boefjes/tests/test_dnssec.py +++ b/boefjes/tests/test_dnssec.py @@ -1,4 +1,3 @@ -from boefjes.job_handler import serialize_ooi from boefjes.plugins.kat_dnssec.normalize import run from octopoes.models.ooi.dns.zone import Hostname from octopoes.models.ooi.network import Network @@ -7,20 +6,20 @@ def test_dnssec_unsigned(): input_ooi = Hostname(network=Network(name="internet").reference, name="example.org") - output = list(run(serialize_ooi(input_ooi), get_dummy_data("inputs/dnssec-unsigned.txt"))) + output = list(run(input_ooi.serialize(), get_dummy_data("inputs/dnssec-unsigned.txt"))) assert output[1].primary_key == "Finding|Hostname|internet|example.org|KAT-NO-DNSSEC" def test_dnssec_invalid(): input_ooi = Hostname(network=Network(name="internet").reference, name="example.org") - output = list(run(serialize_ooi(input_ooi), get_dummy_data("inputs/dnssec-self-signed.txt"))) + output = list(run(input_ooi.serialize(), get_dummy_data("inputs/dnssec-self-signed.txt"))) assert output[1].primary_key == "Finding|Hostname|internet|example.org|KAT-INVALID-DNSSEC" def test_dnssec_valid(): input_ooi = Hostname(network=Network(name="internet").reference, name="example.org") - output = list(run(serialize_ooi(input_ooi), get_dummy_data("inputs/dnssec-valid.txt"))) + output = list(run(input_ooi.serialize(), get_dummy_data("inputs/dnssec-valid.txt"))) assert len(output) == 0 diff --git a/boefjes/tests/test_leakix.py b/boefjes/tests/test_leakix.py index f807243e60a..5f3658aa550 100644 --- a/boefjes/tests/test_leakix.py +++ b/boefjes/tests/test_leakix.py @@ -2,7 +2,6 @@ from pydantic import parse_obj_as -from boefjes.job_handler import serialize_ooi from boefjes.plugins.kat_leakix.normalize import run from octopoes.models.types import OOIType from tests.loading import get_dummy_data @@ -22,7 +21,7 @@ def test_output(self): }, ) - output = [x for x in run(serialize_ooi(input_ooi), get_dummy_data("raw/leakix-example.com.json"))] + output = [x for x in run(input_ooi.serialize(), get_dummy_data("raw/leakix-example.com.json"))] self.assertEqual(170, len(output)) self.assertEqual(get_dummy_data("raw/leakix-example.com-output.txt").decode().strip(), str(output)) diff --git a/boefjes/tests/test_nmap.py b/boefjes/tests/test_nmap.py index c2232dbee2f..8a5b9e29b9e 100644 --- a/boefjes/tests/test_nmap.py +++ b/boefjes/tests/test_nmap.py @@ -1,6 +1,5 @@ from unittest import TestCase -from boefjes.job_handler import serialize_ooi from boefjes.plugins.kat_nmap_tcp.normalize import run from octopoes.models.ooi.network import IPAddressV4, Network from tests.loading import get_dummy_data @@ -9,7 +8,7 @@ class NmapTest(TestCase): def test_normalizer(self): input_ooi = IPAddressV4(network=Network(name="internet").reference, address="134.209.85.72") - output = list(run(serialize_ooi(input_ooi), get_dummy_data("raw/nmap_mispoes.xml"))) + output = list(run(input_ooi.serialize(), get_dummy_data("raw/nmap_mispoes.xml"))) self.assertEqual(16, len(output)) for i, out in enumerate(output[:-1]): if out.object_type == "IPPort" and output[i + 1].object_type == "Service": diff --git a/octopoes/octopoes/models/__init__.py b/octopoes/octopoes/models/__init__.py index ea6907f28ee..bb126e24f66 100644 --- a/octopoes/octopoes/models/__init__.py +++ b/octopoes/octopoes/models/__init__.py @@ -1,7 +1,7 @@ from __future__ import annotations from enum import Enum, IntEnum -from typing import Any, ClassVar, Literal, TypeVar +from typing import Any, ClassVar, Literal, TypeAlias, TypeVar from pydantic import BaseModel, GetCoreSchemaHandler, RootModel from pydantic_core import CoreSchema, core_schema @@ -213,6 +213,32 @@ def format_reference_human_readable(cls, reference: Reference) -> str: def traversable(cls) -> bool: return cls._traversable + def serialize(self) -> SerializedOOI: + serialized_oois = {} + for key, value in self: + if key not in self.model_fields: + continue + serialized_oois[key] = self._serialize_value(value, self.model_fields[key].is_required()) + return serialized_oois + + def _serialize_value(self, value: Any, required: bool) -> SerializedOOIValue: + if isinstance(value, list): + return [self._serialize_value(item, required) for item in value] + if isinstance(value, Reference): + try: + return value.tokenized.root + except AttributeError: + if required: + raise + + return None + if isinstance(value, Enum): + return value.value + if isinstance(value, int | float): + return value + else: + return str(value) + def __hash__(self): return hash(self.primary_key) @@ -264,3 +290,7 @@ def build_token_tree(ooi_class: type[OOI]) -> dict[str, dict | str]: else: tokens[attribute] = "" return tokens + + +SerializedOOIValue: TypeAlias = None | str | int | float | dict[str, str | PrimaryKeyToken] | list["SerializedOOIValue"] +SerializedOOI: TypeAlias = dict[str, SerializedOOIValue] diff --git a/octopoes/octopoes/models/ooi/scans.py b/octopoes/octopoes/models/ooi/scans.py new file mode 100644 index 00000000000..73b156b8b20 --- /dev/null +++ b/octopoes/octopoes/models/ooi/scans.py @@ -0,0 +1,17 @@ +from typing import Literal + +from octopoes.models import OOI, Reference + + +class ExternalScan(OOI): + object_type: Literal["ExternalScan"] = "ExternalScan" + + name: str + + _natural_key_attrs = ["name"] + _information_value = ["name"] + _traversable = False + + @classmethod + def format_reference_human_readable(cls, reference: Reference) -> str: + return reference.tokenized.name diff --git a/octopoes/octopoes/models/types.py b/octopoes/octopoes/models/types.py index aa99b0f1399..b0fd6067b29 100644 --- a/octopoes/octopoes/models/types.py +++ b/octopoes/octopoes/models/types.py @@ -59,6 +59,7 @@ ) from octopoes.models.ooi.question import Question from octopoes.models.ooi.reports import Report, ReportData +from octopoes.models.ooi.scans import ExternalScan from octopoes.models.ooi.service import IPService, Service, TLSCipher from octopoes.models.ooi.software import Software, SoftwareInstance from octopoes.models.ooi.web import ( @@ -136,6 +137,7 @@ MonitoringType = Application | Incident ConfigType = Config ReportsType = ReportData +ScanType = ExternalScan ConcreteOOIType = ( CertificateType @@ -157,6 +159,7 @@ | ConfigType | Question | ReportsType + | ScanType | Report ) diff --git a/rocky/rocky/bytes_client.py b/rocky/rocky/bytes_client.py index 4312d5eeedd..89c051bc89e 100644 --- a/rocky/rocky/bytes_client.py +++ b/rocky/rocky/bytes_client.py @@ -70,17 +70,24 @@ def add_manual_proof( ), ) - def upload_raw(self, raw: bytes, manual_mime_types: set[str], input_ooi: str | None = None) -> str: + def upload_raw( + self, + raw: bytes, + manual_mime_types: set[str], + input_ooi: str | None = None, + input_dict: dict | None = None, + valid_time: datetime | None = None, + ) -> str: self.login() boefje_meta = BoefjeMeta( id=uuid.uuid4(), boefje=Boefje(id="manual"), input_ooi=input_ooi, - arguments={}, + arguments={"input": input_dict} if input_dict else {}, organization=self.organization, - started_at=datetime.now(timezone.utc), - ended_at=datetime.now(timezone.utc), + started_at=valid_time or datetime.now(timezone.utc), + ended_at=valid_time or datetime.now(timezone.utc), ) self._save_boefje_meta(boefje_meta) diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 3d427696c37..573ef91b9de 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -4094,11 +4094,11 @@ msgstr "" msgid "Please explain how to reproduce your finding" msgstr "" -#: tools/forms/finding_type.py +#: tools/forms/finding_type.py tools/forms/upload_raw.py msgid "Date/Time (UTC)" msgstr "" -#: tools/forms/finding_type.py +#: tools/forms/finding_type.py tools/forms/upload_raw.py msgid "Doc! I'm from the future, I'm here to take you back!" msgstr "" @@ -4260,6 +4260,10 @@ msgstr "" msgid "Add the date and time of your finding (UTC)" msgstr "" +#: tools/forms/settings.py +msgid "Add the date and time of when the raw file was generated (UTC)" +msgstr "" + #: tools/forms/settings.py msgid "" "OpenKAT stores a time indication with every observation, so it is possible " @@ -4333,6 +4337,14 @@ msgstr "" msgid "Upload raw file" msgstr "" +#: tools/forms/upload_raw.py +msgid "Click to select one of the available options, or type one yourself" +msgstr "" + +#: tools/forms/upload_raw.py +msgid "OOI doesn't exist, try another valid time" +msgstr "" + #: tools/models.py msgid "The name of the organisation" msgstr "" @@ -6361,6 +6373,15 @@ msgstr "" msgid "Automate the creation of multiple objects by uploading a raw file." msgstr "" +#: rocky/templates/upload_raw.html +msgid "" +"An input OOI can be selected for the normalizer to attach newly yielded OOIs " +"to. If no input OOI was used for the raw file, a placeholder ExternalScan " +"OOI can be used. ExternalScan OOIs can be created from the objects page. " +"When a new version of the raw file is generated, the same ExternalScan OOI " +"should be chosen to ensure that old results are overwritten." +msgstr "" + #: rocky/templates/upload_raw.html rocky/views/upload_raw.py msgid "Upload raw" msgstr "" diff --git a/rocky/rocky/templates/upload_raw.html b/rocky/rocky/templates/upload_raw.html index 07d5e110312..f74ccbab117 100644 --- a/rocky/rocky/templates/upload_raw.html +++ b/rocky/rocky/templates/upload_raw.html @@ -11,6 +11,9 @@

{% translate "Upload raw file" %}

{% translate "Automate the creation of multiple objects by uploading a raw file." %}

+

+ {% translate "An input OOI can be selected for the normalizer to attach newly yielded OOIs to. If no input OOI was used for the raw file, a placeholder ExternalScan OOI can be used. ExternalScan OOIs can be created from the objects page. When a new version of the raw file is generated, the same ExternalScan OOI should be chosen to ensure that old results are overwritten." %} +

    {% for criterion in criteria %}
  • {{ criterion }}
  • {% endfor %}
diff --git a/rocky/rocky/views/upload_raw.py b/rocky/rocky/views/upload_raw.py index 082c19e09a4..5159b2ad9bc 100644 --- a/rocky/rocky/views/upload_raw.py +++ b/rocky/rocky/views/upload_raw.py @@ -1,3 +1,4 @@ +from datetime import datetime, timezone from urllib.parse import unquote from account.mixins import OrganizationPermissionRequiredMixin, OrganizationView @@ -10,6 +11,7 @@ from httpx import HTTPError, HTTPStatusError from tools.forms.upload_raw import UploadRawForm +from octopoes.models.types import OOI_TYPES from rocky.bytes_client import get_bytes_client @@ -59,9 +61,17 @@ def add_success_notification(self, success_message): def process_raw(self, form): raw_file = form.cleaned_data["raw_file"] mime_types = form.cleaned_data["mime_types"] + input_ooi = form.cleaned_data["ooi"] + valid_time = form.cleaned_data["date"] try: - get_bytes_client(self.organization.code).upload_raw(raw_file.read(), mime_types) + get_bytes_client(self.organization.code).upload_raw( + raw_file.read(), + mime_types, + input_ooi=input_ooi.primary_key, + input_dict=input_ooi.serialize(), + valid_time=valid_time, + ) except HTTPStatusError as exc: return self.add_error_notification( _("Raw file could not be uploaded to Bytes: status code %d") % exc.response.status_code @@ -70,3 +80,28 @@ def process_raw(self, form): return self.add_error_notification(_("Raw file could not be uploaded to Bytes: %s") % str(exc)) else: self.add_success_notification(_("Raw file successfully added.")) + + def get_form_kwargs(self): + kwargs = { + "connector": self.octopoes_api_connector, + "ooi_list": self.get_ooi_options(), + } + kwargs.update(super().get_form_kwargs()) + + if "ooi_class" in kwargs: + del kwargs["ooi_class"] + + observed_at = self.request.GET.get("observed_at") + if observed_at: + kwargs["observed_at"] = observed_at + + return kwargs + + def get_ooi_options(self) -> list[tuple[str, str]]: + objects = self.octopoes_api_connector.list_objects( + set(OOI_TYPES.values()), valid_time=datetime.now(timezone.utc) + ).items + + options = [(o.primary_key, o.get_ooi_type()) for o in objects] + + return options diff --git a/rocky/tests/test_upload_raw.py b/rocky/tests/test_upload_raw.py index a41dba4b81e..1d29f2c9421 100644 --- a/rocky/tests/test_upload_raw.py +++ b/rocky/tests/test_upload_raw.py @@ -1,3 +1,4 @@ +from datetime import datetime, timezone from io import BytesIO from pytest_django.asserts import assertContains @@ -6,7 +7,7 @@ from tests.conftest import setup_request -def test_upload_raw_page(rf, redteam_member): +def test_upload_raw_page(rf, redteam_member, mock_organization_view_octopoes): request = setup_request(rf.get("upload_raw"), redteam_member.user) response = UploadRaw.as_view()(request, organization_code=redteam_member.organization.code) @@ -14,18 +15,22 @@ def test_upload_raw_page(rf, redteam_member): assertContains(response, "Upload raw") -def test_upload_raw_simple(rf, redteam_member): +def test_upload_raw_simple(rf, redteam_member, mock_organization_view_octopoes): request = setup_request(rf.get("upload_raw"), redteam_member.user) response = UploadRaw.as_view()(request, organization_code=redteam_member.organization.code) assert response.status_code == 200 -def test_upload_empty(rf, redteam_member, mock_organization_view_octopoes, mock_bytes_client): +def test_upload_empty(rf, redteam_member, mock_organization_view_octopoes, mock_bytes_client, network): example_file = BytesIO(b"") request = setup_request( - rf.post("upload_raw", {"mime_types": "Hostname", "raw_file": example_file}), redteam_member.user + rf.post( + "upload_raw", + {"mime_types": "Hostname", "raw_file": example_file, "ooi_id": network, "date": datetime.now(timezone.utc)}, + ), + redteam_member.user, ) response = UploadRaw.as_view()(request, organization_code=redteam_member.organization.code) @@ -34,34 +39,52 @@ def test_upload_empty(rf, redteam_member, mock_organization_view_octopoes, mock_ assertContains(response, "This field is required") -def test_upload_raw(rf, redteam_member, mock_organization_view_octopoes, mock_bytes_client): +def test_upload_raw(rf, redteam_member, mock_organization_view_octopoes, mock_bytes_client, network): example_file = BytesIO(b"abc") example_file.name = "test" + date = datetime.now(timezone.utc) + request = setup_request( - rf.post("upload_raw", {"mime_types": "abc/def,ghi", "raw_file": example_file}), redteam_member.user + rf.post("upload_raw", {"mime_types": "abc/def,ghi", "raw_file": example_file, "ooi_id": network, "date": date}), + redteam_member.user, ) response = UploadRaw.as_view()(request, organization_code=redteam_member.organization.code) assert response.status_code == 302 - mock_bytes_client().upload_raw.assert_called_once_with(b"abc", {"abc/def", "ghi"}) + mock_bytes_client().upload_raw.assert_called_once_with( + b"abc", + {"abc/def", "ghi"}, + input_ooi=mock_organization_view_octopoes().get().primary_key, + input_dict=mock_organization_view_octopoes().get().serialize(), + valid_time=date, + ) messages = list(request._messages) assert "successfully added" in messages[0].message -def test_upload_raw_empty_mime_types(rf, redteam_member, mock_bytes_client): +def test_upload_raw_empty_mime_types(rf, redteam_member, mock_bytes_client, mock_organization_view_octopoes, network): example_file = BytesIO(b"abc") example_file.name = "test" + date = datetime.now(timezone.utc) + request = setup_request( - rf.post("upload_raw", {"mime_types": "abc,,,,", "raw_file": example_file}), redteam_member.user + rf.post("upload_raw", {"mime_types": "abc,,,,", "raw_file": example_file, "ooi_id": network, "date": date}), + redteam_member.user, ) response = UploadRaw.as_view()(request, organization_code=redteam_member.organization.code) assert response.status_code == 302 - mock_bytes_client().upload_raw.assert_called_once_with(b"abc", {"abc"}) + mock_bytes_client().upload_raw.assert_called_once_with( + b"abc", + {"abc"}, + input_ooi=mock_organization_view_octopoes().get().primary_key, + input_dict=mock_organization_view_octopoes().get().serialize(), + valid_time=date, + ) messages = list(request._messages) assert "successfully added" in messages[0].message diff --git a/rocky/tools/forms/settings.py b/rocky/tools/forms/settings.py index 4774f022942..3e107731ff7 100644 --- a/rocky/tools/forms/settings.py +++ b/rocky/tools/forms/settings.py @@ -50,6 +50,8 @@ FINDING_DATETIME_HELP_TEXT = _("Add the date and time of your finding (UTC)") +RAW_FILE_DATETIME_HELP_TEXT = _("Add the date and time of when the raw file was generated (UTC)") + OBSERVED_AT_HELP_TEXT = _( "OpenKAT stores a time indication with every observation, " "so it is possible to see the status of your network through time. " diff --git a/rocky/tools/forms/upload_raw.py b/rocky/tools/forms/upload_raw.py index f84802157ab..6691689b708 100644 --- a/rocky/tools/forms/upload_raw.py +++ b/rocky/tools/forms/upload_raw.py @@ -1,9 +1,17 @@ +from datetime import datetime, timezone + from django import forms from django.utils.safestring import mark_safe from django.utils.translation import gettext as _ +from octopoes.connector.octopoes import OctopoesAPIConnector +from octopoes.models import Reference +from octopoes.models.exception import ObjectNotFoundException +from tools.forms.base import BaseRockyForm, DataListInput, DateTimeInput +from tools.forms.settings import RAW_FILE_DATETIME_HELP_TEXT + -class UploadRawForm(forms.Form): +class UploadRawForm(BaseRockyForm): mime_types = forms.CharField( label=_("Mime types"), help_text=mark_safe( @@ -22,7 +30,60 @@ class UploadRawForm(forms.Form): allow_empty_file=False, ) + ooi_id = forms.CharField( + label="Input or Scan OOI", + widget=DataListInput( + attrs={"placeholder": _("Click to select one of the available options, or type one yourself")} + ), + ) + + date = forms.DateTimeField( + label=_("Date/Time (UTC)"), + widget=DateTimeInput(format="%Y-%m-%dT%H:%M"), + help_text=RAW_FILE_DATETIME_HELP_TEXT, + ) + + def __init__( + self, + connector: OctopoesAPIConnector, + ooi_list: list[tuple[str, str]], + *args, + **kwargs, + ): + observed_at = kwargs.pop("observed_at", None) + super().__init__(*args, **kwargs) + self.octopoes_connector = connector + self.set_choices_for_widget("ooi_id", ooi_list) + + if observed_at: + try: + parsed_date = ( + datetime.strptime(observed_at, "%Y-%m-%d").replace(tzinfo=timezone.utc).replace(hour=23, minute=59) + ) + self.fields["date"].initial = parsed_date + except ValueError: + self.fields["date"].initial = datetime.now(tz=timezone.utc) + else: + self.fields["date"].initial = datetime.now(tz=timezone.utc) + def clean_mime_types(self) -> set[str]: mime_types = self.cleaned_data["mime_types"] return {mime_type.strip() for mime_type in mime_types.split(",") if mime_type.strip()} + + def clean(self): + cleaned_data = super().clean() + + date = self.cleaned_data["date"] + ooi_id = self.cleaned_data["ooi_id"] + + # date should not be in the future + if date > datetime.now(tz=timezone.utc): + self.add_error("date", _("Doc! I'm from the future, I'm here to take you back!")) + + try: + cleaned_data["ooi"] = self.octopoes_connector.get(Reference.from_str(ooi_id), date) + except ObjectNotFoundException: + self.add_error("ooi_id", _("OOI doesn't exist, try another valid time")) + + return cleaned_data From 72457ccd84eb98b510cfd4fb7226eb47f393f99f Mon Sep 17 00:00:00 2001 From: ammar92 Date: Thu, 8 Aug 2024 11:33:11 +0200 Subject: [PATCH 053/112] Basic audit trails via logging (#3317) Co-authored-by: Jeroen Dekkers Co-authored-by: Donny Peeters <46660228+Donnype@users.noreply.github.com> Co-authored-by: Jan Klopper --- octopoes/octopoes/connector/octopoes.py | 17 +++++++++- rocky/account/mixins.py | 4 +++ rocky/account/models.py | 4 +++ rocky/katalogus/client.py | 13 +++++++- rocky/rocky/apps.py | 12 +++---- rocky/rocky/bytes_client.py | 5 ++- rocky/rocky/signals.py | 43 +++++++++++++++++++++++-- rocky/tools/models.py | 8 +++++ 8 files changed, 93 insertions(+), 13 deletions(-) diff --git a/octopoes/octopoes/connector/octopoes.py b/octopoes/octopoes/connector/octopoes.py index 3cb5a26d898..ba319df63b3 100644 --- a/octopoes/octopoes/connector/octopoes.py +++ b/octopoes/octopoes/connector/octopoes.py @@ -4,6 +4,7 @@ from uuid import UUID import httpx +import structlog from httpx import HTTPError, Response from pydantic import TypeAdapter @@ -38,8 +39,8 @@ class OctopoesAPIConnector: def __init__(self, base_uri: str, client: str): self.base_uri = base_uri self.client = client - self.session = httpx.Client(base_url=base_uri, timeout=30, event_hooks={"response": [self._verify_response]}) + self.logger = structlog.get_logger("octopoes-connector", organisation_code=client) @staticmethod def _verify_response(response: Response) -> None: @@ -174,6 +175,8 @@ def save_observation(self, observation: Observation) -> None: content=observation.model_dump_json(), ) + self.logger.info("Saved observation", observation=observation) + def save_declaration(self, declaration: Declaration) -> None: self.session.post( f"/{self.client}/declarations", @@ -181,6 +184,8 @@ def save_declaration(self, declaration: Declaration) -> None: content=declaration.model_dump_json(), ) + self.logger.info("Saved declaration", declaration=declaration) + def save_affirmation(self, affirmation: Affirmation) -> None: self.session.post( f"/{self.client}/affirmations", @@ -188,6 +193,8 @@ def save_affirmation(self, affirmation: Affirmation) -> None: content=affirmation.model_dump_json(), ) + self.logger.info("Saved affirmation", affirmation=affirmation) + def save_scan_profile(self, scan_profile: ScanProfile, valid_time: datetime): params = {"valid_time": str(valid_time)} self.session.put( @@ -209,10 +216,14 @@ def delete(self, reference: Reference, valid_time: datetime) -> None: params = {"reference": str(reference), "valid_time": str(valid_time)} self.session.delete(f"/{self.client}/", params=params) + self.logger.info("Deleted object", reference=reference, valid_time=valid_time) + def delete_many(self, references: list[Reference], valid_time: datetime) -> None: params = {"valid_time": str(valid_time)} self.session.post(f"/{self.client}/objects/delete_many", params=params, json=[str(ref) for ref in references]) + self.logger.info("Deleted objects", references=references, valid_time=valid_time) + def list_origin_parameters(self, origin_id: set[str], valid_time: datetime) -> list[OriginParameter]: params = {"origin_id": list(origin_id), "valid_time": str(valid_time)} res = self.session.get(f"/{self.client}/origin_parameters", params=params) @@ -221,9 +232,13 @@ def list_origin_parameters(self, origin_id: set[str], valid_time: datetime) -> l def create_node(self): self.session.post(f"/{self.client}/node") + self.logger.info("Created node") + def delete_node(self): self.session.delete(f"/{self.client}/node") + self.logger.info("Deleted node") + def get_scan_profile_inheritance(self, reference: Reference, valid_time: datetime) -> list[InheritanceSection]: params = {"reference": str(reference), "valid_time": str(valid_time)} res = self.session.get(f"/{self.client}/scan_profiles/inheritance", params=params) diff --git a/rocky/account/mixins.py b/rocky/account/mixins.py index fca1182b397..549b9599b53 100644 --- a/rocky/account/mixins.py +++ b/rocky/account/mixins.py @@ -1,5 +1,6 @@ from datetime import datetime, timezone +import structlog.contextvars from django.conf import settings from django.contrib import messages from django.contrib.auth.mixins import PermissionRequiredMixin @@ -70,6 +71,9 @@ def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) organization_code = kwargs["organization_code"] + # bind organization_code to log context + structlog.contextvars.bind_contextvars(organization_code=organization_code) + try: self.organization = Organization.objects.get(code=organization_code) except Organization.DoesNotExist: diff --git a/rocky/account/models.py b/rocky/account/models.py index 7d082739f7d..38511691d03 100644 --- a/rocky/account/models.py +++ b/rocky/account/models.py @@ -84,6 +84,8 @@ class KATUser(AbstractBaseUser, PermissionsMixin): objects = KATUserManager() + EVENT_CODES = {"created": 900101, "updated": 900102, "deleted": 900103} + def get_full_name(self): return self.full_name @@ -129,6 +131,8 @@ class Meta: models.UniqueConstraint("user", Lower("name"), name="unique name"), ] + EVENT_CODES = {"created": 900111, "updated": 900122, "deleted": 900123} + def __str__(self): return f"{self.name} ({self.user})" diff --git a/rocky/katalogus/client.py b/rocky/katalogus/client.py index 104bf2fda51..9c293a670ba 100644 --- a/rocky/katalogus/client.py +++ b/rocky/katalogus/client.py @@ -14,7 +14,7 @@ from octopoes.models.types import type_by_name from rocky.health import ServiceHealth -logger = structlog.get_logger(__name__) +logger = structlog.get_logger("katalogus_client") class Plugin(BaseModel): @@ -94,10 +94,14 @@ def create_organization(self, name: str): response = self.session.post("/v1/organisations/", json={"id": self.organization, "name": name}) response.raise_for_status() + logger.info("Created organization", name=name) + def delete_organization(self): response = self.session.delete(self.organization_uri) response.raise_for_status() + logger.info("Deleted organization", organization_code=self.organization) + def get_plugins(self, **params): try: response = self.session.get(f"{self.organization_uri}/plugins", params=params) @@ -138,9 +142,14 @@ def upsert_plugin_settings(self, plugin_id: str, values: dict) -> None: response = self.session.put(f"{self.organization_uri}/{plugin_id}/settings", json=values) response.raise_for_status() + logger.info("Upsert plugin settings", plugin_id=plugin_id) + def delete_plugin_settings(self, plugin_id: str): response = self.session.delete(f"{self.organization_uri}/{plugin_id}/settings") response.raise_for_status() + + logger.info("Delete plugin settings", plugin_id=plugin_id) + return response def clone_all_configuration_to_organization(self, to_organization: str): @@ -177,6 +186,8 @@ def get_enabled_normalizers(self) -> list[Plugin]: return [plugin for plugin in self.get_normalizers() if plugin.enabled] def _patch_boefje_state(self, boefje_id: str, enabled: bool) -> None: + logger.info("Toggle plugin state", plugin_id=boefje_id, enabled=enabled) + response = self.session.patch( f"{self.organization_uri}/plugins/{boefje_id}", json={"enabled": enabled}, diff --git a/rocky/rocky/apps.py b/rocky/rocky/apps.py index b9d6ec8e89a..42e0cc1fe2b 100644 --- a/rocky/rocky/apps.py +++ b/rocky/rocky/apps.py @@ -1,14 +1,10 @@ from django.apps import AppConfig -from django.db.models.signals import post_delete, post_save class RockyConfig(AppConfig): name = "rocky" - def ready(self) -> None: - # We need to do the import here because else we will get an "apps aren't - # loaded yet" error from Django. - from rocky.signals import log_delete, log_save - - post_save.connect(log_save, dispatch_uid="log_save") - post_delete.connect(log_delete, dispatch_uid="log_delete") + def ready(self): + # import the signals module to ensure that the signal handlers are connected + # and to avoid "apps aren't loaded yet" error from Django + from . import signals # noqa: F401 diff --git a/rocky/rocky/bytes_client.py b/rocky/rocky/bytes_client.py index 89c051bc89e..837d586ebc9 100644 --- a/rocky/rocky/bytes_client.py +++ b/rocky/rocky/bytes_client.py @@ -11,7 +11,7 @@ from rocky.health import ServiceHealth from rocky.scheduler import Boefje, BoefjeMeta, Normalizer, NormalizerMeta, RawData -logger = structlog.get_logger(__name__) +logger = structlog.get_logger("bytes_client") class BytesClient: @@ -92,6 +92,9 @@ def upload_raw( self._save_boefje_meta(boefje_meta) raw_id = self._save_raw(boefje_meta.id, raw, {"boefje/manual"}.union(manual_mime_types)) + + logger.info("Uploaded raw data", raw_id=raw_id, organization=self.organization) + return raw_id def _save_boefje_meta(self, boefje_meta: BoefjeMeta) -> None: diff --git a/rocky/rocky/signals.py b/rocky/rocky/signals.py index f4a646783e4..59c8bebd9a3 100644 --- a/rocky/rocky/signals.py +++ b/rocky/rocky/signals.py @@ -1,38 +1,77 @@ -import structlog from django.contrib.admin.models import LogEntry +from django.contrib.auth.signals import user_logged_in, user_logged_out, user_login_failed +from django.db.models.signals import post_delete, post_save +from django.dispatch import receiver +from structlog import get_logger -logger = structlog.get_logger(__name__) +logger = get_logger(__name__) +# Signal sent when a user logs in +@receiver(user_logged_in) +def user_logged_in_callback(sender, request, user, **kwargs): + logger.info("User logged in", username=user.get_username()) + + +# Signal sent when a user logs out +@receiver(user_logged_out) +def user_logged_out_callback(sender, request, user, **kwargs): + logger.info("User logged out", userername=user.get_username()) + + +# Signal sent when a user login attempt fails +@receiver(user_login_failed) +def user_login_failed_callback(sender, credentials, request, **kwargs): + logger.info("User login failed", credentials=credentials) + + +# Signal sent when a model is saved +@receiver(post_save, dispatch_uid="log_save") def log_save(sender, instance, created, **kwargs) -> None: if isinstance(instance, LogEntry): # Django admin will automatically create a LogEntry for each admin # action, but we shouldn't send log messages about these. return + context = {} + event_codes = getattr(instance, "EVENT_CODES", None) + if created: + if event_codes and "created" in event_codes: + context["event_code"] = event_codes["created"] logger.info( "%s %s created", instance._meta.object_name, instance, object_type=instance._meta.object_name, object=str(instance), + **context, ) else: + if event_codes and "updated" in event_codes: + context["event_code"] = event_codes["updated"] logger.info( "%s %s updated", instance._meta.object_name, instance, object_type=instance._meta.object_name, object=str(instance), + **context, ) +# Signal sent when a model is deleted +@receiver(post_delete, dispatch_uid="log_delete") def log_delete(sender, instance, **kwargs) -> None: + context = {} + event_codes = getattr(instance, "EVENT_CODES", None) + if event_codes and "deleted" in event_codes: + context["event_code"] = event_codes["deleted"] logger.info( "%s %s deleted", instance._meta.object_name, instance, object_type=instance._meta.object_name, object=str(instance), + **context, ) diff --git a/rocky/tools/models.py b/rocky/tools/models.py index 4f78431ef56..5e8cf119958 100644 --- a/rocky/tools/models.py +++ b/rocky/tools/models.py @@ -91,6 +91,8 @@ class Organization(models.Model): ) tags = tagulous.models.TagField(to=OrganizationTag, blank=True) + EVENT_CODES = {"created": 900201, "updated": 900202, "deleted": 900203} + def __str__(self): return str(self.name) @@ -229,6 +231,8 @@ class STATUSES(models.TextChoices): default=-1, validators=[MinValueValidator(-1), MaxValueValidator(max(scan_levels))] ) + EVENT_CODES = {"created": 900211, "updated": 900212, "deleted": 900213} + @cached_property def all_permissions(self) -> set[str]: if self.user.is_active and self.user.is_superuser: @@ -266,6 +270,8 @@ class Indemnification(models.Model): user = models.ForeignKey("account.KATUser", on_delete=models.SET_NULL, null=True) organization = models.ForeignKey(Organization, on_delete=models.SET_NULL, null=True) + EVENT_CODES = {"created": 900221, "updated": 900222, "deleted": 900223} + class OOIInformation(models.Model): id = models.CharField(max_length=256, primary_key=True) @@ -273,6 +279,8 @@ class OOIInformation(models.Model): data = models.JSONField(null=True) consult_api = models.BooleanField(default=False) + EVENT_CODES = {"created": 900231, "updated": 900232, "deleted": 900233} + def save(self, *args, **kwargs): if self.data is None: self.data = {"description": ""} From 71e74e2b3ff7f0e38a17aa4c23df462d5f8f457d Mon Sep 17 00:00:00 2001 From: ammar92 Date: Mon, 12 Aug 2024 09:28:19 +0200 Subject: [PATCH 054/112] Limit the number of Celery workers that Octopoes can start #3232 (#3337) --- .env-dist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.env-dist b/.env-dist index 5e441c4ed95..daca58ec3ff 100644 --- a/.env-dist +++ b/.env-dist @@ -65,6 +65,8 @@ BYTES_DB_URI=postgresql://${BYTES_DB_USER}:${BYTES_DB_PASSWORD}@postgres:5432/${ # --- Octopoes --- # # See `octopoes/octopoes/config/settings.py` +# Number of Celery workers (for the Octopoes API worker) that need to be started +CELERY_WORKER_CONCURRENCY=${CELERY_WORKER_CONCURRENCY:-4} # --- Mula --- # # See `mula/scheduler/config/settings.py` From 0cf9a5a55d99b12372a1aff5245f7c52d14f7422 Mon Sep 17 00:00:00 2001 From: originalsouth Date: Mon, 12 Aug 2024 12:03:46 +0200 Subject: [PATCH 055/112] Allow MuteFindings to expire by a user specified datetime (#3343) Co-authored-by: Jan Klopper Co-authored-by: Jeroen Dekkers Co-authored-by: ammar92 --- boefjes/boefjes/job_models.py | 3 ++- .../plugins/kat_manual/single_ooi/normalize.py | 3 ++- octopoes/octopoes/api/models.py | 2 ++ octopoes/octopoes/api/router.py | 2 +- octopoes/octopoes/core/service.py | 6 ++++-- .../octopoes/repositories/origin_repository.py | 4 ++-- octopoes/octopoes/xtdb/client.py | 2 +- .../tests/integration/test_api_connector.py | 2 +- octopoes/tests/test_octopoes_service.py | 4 ++-- rocky/rocky/locale/django.pot | 6 +++++- .../rocky/templates/findings/finding_list.html | 4 ++++ rocky/rocky/views/ooi_mute.py | 11 +++++++++-- rocky/rocky/views/ooi_view.py | 4 ++++ rocky/tests/objects/test_objects_add.py | 3 ++- rocky/tools/forms/ooi.py | 5 +++++ rocky/tools/forms/ooi_form.py | 12 ++++++++++++ rocky/tools/ooi_helpers.py | 18 ++++++++++++++---- 17 files changed, 72 insertions(+), 19 deletions(-) diff --git a/boefjes/boefjes/job_models.py b/boefjes/boefjes/job_models.py index 0d40cb497c3..8e419b79541 100644 --- a/boefjes/boefjes/job_models.py +++ b/boefjes/boefjes/job_models.py @@ -1,4 +1,4 @@ -from datetime import timedelta +from datetime import datetime, timedelta from typing import Annotated, Literal, TypeAlias from uuid import UUID @@ -85,6 +85,7 @@ class NormalizerObservation(BaseModel): class NormalizerDeclaration(BaseModel): type: Literal["declaration"] = "declaration" ooi: OOIType + end_valid_time: datetime | None = None class NormalizerAffirmation(BaseModel): diff --git a/boefjes/boefjes/plugins/kat_manual/single_ooi/normalize.py b/boefjes/boefjes/plugins/kat_manual/single_ooi/normalize.py index 84ada07af3b..093ace2e3a1 100644 --- a/boefjes/boefjes/plugins/kat_manual/single_ooi/normalize.py +++ b/boefjes/boefjes/plugins/kat_manual/single_ooi/normalize.py @@ -6,4 +6,5 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: for declaration in json.loads(raw.decode()): - yield NormalizerDeclaration(ooi=declaration["ooi"]) + end_valid_time = declaration.pop("end_valid_time", None) + yield NormalizerDeclaration(ooi=declaration["ooi"], end_valid_time=end_valid_time) diff --git a/octopoes/octopoes/api/models.py b/octopoes/octopoes/api/models.py index e2d2aabd962..7156231c6c9 100644 --- a/octopoes/octopoes/api/models.py +++ b/octopoes/octopoes/api/models.py @@ -41,6 +41,7 @@ class Declaration(BaseModel): ooi: OOIType valid_time: datetime + end_valid_time: datetime | None = None method: str | None = None source_method: str | None = None task_id: uuid.UUID | None = None @@ -79,6 +80,7 @@ class ValidatedDeclaration(BaseModel): ooi: ValidatedOOIType valid_time: AwareDatetime + end_valid_time: AwareDatetime | None = None method: str | None = "manual" source_method: str | None = None task_id: uuid.UUID | None = Field(default_factory=uuid.uuid4) diff --git a/octopoes/octopoes/api/router.py b/octopoes/octopoes/api/router.py index 4e6e0eae6a2..21a17cdeefa 100644 --- a/octopoes/octopoes/api/router.py +++ b/octopoes/octopoes/api/router.py @@ -354,7 +354,7 @@ def save_declaration( result=[declaration.ooi.reference], task_id=declaration.task_id if declaration.task_id else uuid.uuid4(), ) - octopoes.save_origin(origin, [declaration.ooi], declaration.valid_time) + octopoes.save_origin(origin, [declaration.ooi], declaration.valid_time, declaration.end_valid_time) octopoes.commit() diff --git a/octopoes/octopoes/core/service.py b/octopoes/octopoes/core/service.py index 52fef38b695..81f8ee9355f 100644 --- a/octopoes/octopoes/core/service.py +++ b/octopoes/octopoes/core/service.py @@ -152,7 +152,9 @@ def _delete_ooi(self, reference: Reference, valid_time: datetime) -> None: if not referencing_origins: self.ooi_repository.delete(reference, valid_time) - def save_origin(self, origin: Origin, oois: list[OOI], valid_time: datetime) -> None: + def save_origin( + self, origin: Origin, oois: list[OOI], valid_time: datetime, end_valid_time: datetime | None = None + ) -> None: origin.result = [ooi.reference for ooi in oois] # When an Origin is saved while the source OOI does not exist, reject saving the results @@ -166,7 +168,7 @@ def save_origin(self, origin: Origin, oois: list[OOI], valid_time: datetime) -> raise ValueError("Origin source of observation does not exist") for ooi in oois: - self.ooi_repository.save(ooi, valid_time=valid_time) + self.ooi_repository.save(ooi, valid_time=valid_time, end_valid_time=end_valid_time) self.origin_repository.save(origin, valid_time=valid_time) def _run_inference(self, origin: Origin, valid_time: datetime) -> None: diff --git a/octopoes/octopoes/repositories/origin_repository.py b/octopoes/octopoes/repositories/origin_repository.py index 252f166b1cd..0706e27ff4b 100644 --- a/octopoes/octopoes/repositories/origin_repository.py +++ b/octopoes/octopoes/repositories/origin_repository.py @@ -60,14 +60,14 @@ def commit(self): @classmethod def serialize(cls, origin: Origin) -> dict[str, Any]: - data = origin.dict() + data = origin.model_dump() data[cls.pk_prefix] = origin.id data["type"] = origin.__class__.__name__ return data @classmethod def deserialize(cls, data: dict[str, Any]) -> Origin: - return Origin.parse_obj(data) + return Origin.model_validate(data) def list_origins( self, diff --git a/octopoes/octopoes/xtdb/client.py b/octopoes/octopoes/xtdb/client.py index 4e312e81f53..f78ef380b8b 100644 --- a/octopoes/octopoes/xtdb/client.py +++ b/octopoes/octopoes/xtdb/client.py @@ -136,7 +136,7 @@ def await_transaction(self, transaction_id: int) -> None: def submit_transaction(self, operations: list[Operation]) -> None: res = self._session.post( f"{self.client_url()}/submit-tx", - content=Transaction(operations=operations).json(by_alias=True), + content=Transaction(operations=operations).model_dump_json(by_alias=True), headers={"Content-Type": "application/json"}, ) diff --git a/octopoes/tests/integration/test_api_connector.py b/octopoes/tests/integration/test_api_connector.py index b57693e5fd5..34c28224f77 100644 --- a/octopoes/tests/integration/test_api_connector.py +++ b/octopoes/tests/integration/test_api_connector.py @@ -53,7 +53,7 @@ def test_bulk_operations(octopoes_api_connector: OctopoesAPIConnector, valid_tim assert len(octopoes_api_connector.list_origins(task_id=uuid.uuid4(), valid_time=valid_time)) == 0 origins = octopoes_api_connector.list_origins(task_id=task_id, valid_time=valid_time) assert len(origins) == 1 - assert origins[0].dict() == { + assert origins[0].model_dump() == { "method": "normalizer_id", "origin_type": OriginType.OBSERVATION, "source": network.reference, diff --git a/octopoes/tests/test_octopoes_service.py b/octopoes/tests/test_octopoes_service.py index 5eac373b197..dc7626c3b2b 100644 --- a/octopoes/tests/test_octopoes_service.py +++ b/octopoes/tests/test_octopoes_service.py @@ -133,5 +133,5 @@ def test_on_create_scan_profile(octopoes_service, new_data, old_data, bit_runner octopoes_service.process_event(event) assert octopoes_service.ooi_repository.save.call_count == 2 - octopoes_service.ooi_repository.save.assert_any_call(mock_oois[0], valid_time=valid_time) - octopoes_service.ooi_repository.save.assert_any_call(mock_oois[1], valid_time=valid_time) + octopoes_service.ooi_repository.save.assert_any_call(mock_oois[0], valid_time=valid_time, end_valid_time=None) + octopoes_service.ooi_repository.save.assert_any_call(mock_oois[1], valid_time=valid_time, end_valid_time=None) diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 573ef91b9de..1faac03bc93 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-05 13:42+0000\n" +"POT-Creation-Date: 2024-08-07 13:24+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -4873,6 +4873,10 @@ msgstr "" msgid "Reason:" msgstr "" +#: rocky/templates/findings/finding_list.html +msgid "Expires by (UTC):" +msgstr "" + #: rocky/templates/findings/finding_list.html msgid "Unmute Findings" msgstr "" diff --git a/rocky/rocky/templates/findings/finding_list.html b/rocky/rocky/templates/findings/finding_list.html index 6e34a5e7167..d9c5c47e65d 100644 --- a/rocky/rocky/templates/findings/finding_list.html +++ b/rocky/rocky/templates/findings/finding_list.html @@ -113,6 +113,10 @@

{% translate "Risk score" %}

+
+ + +
{% endif %} diff --git a/rocky/rocky/views/ooi_mute.py b/rocky/rocky/views/ooi_mute.py index a95759ffe71..89c8cef6106 100644 --- a/rocky/rocky/views/ooi_mute.py +++ b/rocky/rocky/views/ooi_mute.py @@ -42,6 +42,11 @@ def post(self, request, *args, **kwargs): unmute = request.POST.get("unmute", None) selected_findings = request.POST.getlist("finding", None) reason = request.POST.get("reason", None) + end_valid_time = request.POST.get("end_valid_time", None) + if end_valid_time: + end_valid_time = datetime.strptime(end_valid_time, "%Y-%m-%dT%H:%M").replace(tzinfo=timezone.utc) + else: + end_valid_time = None if not selected_findings: messages.add_message(self.request, messages.WARNING, _("Please select at least one finding.")) @@ -54,8 +59,10 @@ def post(self, request, *args, **kwargs): return redirect(reverse("finding_list", kwargs={"organization_code": self.organization.code})) else: for finding in selected_findings: - ooi = self.ooi_class.parse_obj({"finding": finding, "reason": reason}) - create_ooi(self.octopoes_api_connector, self.bytes_client, ooi, datetime.now(timezone.utc)) + ooi = self.ooi_class.model_validate({"finding": finding, "reason": reason}) + create_ooi( + self.octopoes_api_connector, self.bytes_client, ooi, datetime.now(timezone.utc), end_valid_time + ) messages.add_message(self.request, messages.SUCCESS, _("Finding(s) successfully muted.")) return redirect(reverse("finding_list", kwargs={"organization_code": self.organization.code})) diff --git a/rocky/rocky/views/ooi_view.py b/rocky/rocky/views/ooi_view.py index 983fdd709b6..5722858273a 100644 --- a/rocky/rocky/views/ooi_view.py +++ b/rocky/rocky/views/ooi_view.py @@ -181,12 +181,16 @@ def get_form_kwargs(self): def form_valid(self, form): # Transform into OOI try: + end_valid_time = form.cleaned_data.pop("end_valid_time", None) + if end_valid_time is not None: + end_valid_time = end_valid_time.replace(tzinfo=timezone.utc) new_ooi = self.ooi_class.model_validate(form.cleaned_data) create_ooi( self.octopoes_api_connector, self.bytes_client, new_ooi, datetime.now(timezone.utc), + end_valid_time, ) sleep(1) return redirect(self.get_ooi_success_url(new_ooi)) diff --git a/rocky/tests/objects/test_objects_add.py b/rocky/tests/objects/test_objects_add.py index 8b69f6cdaf0..5c3a4accc81 100644 --- a/rocky/tests/objects/test_objects_add.py +++ b/rocky/tests/objects/test_objects_add.py @@ -31,7 +31,8 @@ def test_add_ooi(rf, client_member, mock_organization_view_octopoes, mock_bytes_ def test_add_bad_schema(rf, client_member): request = setup_request( - rf.post("ooi_add", {"ooi_type": "Network", "testnamewrong": "testnetwork"}), client_member.user + rf.post("ooi_add", {"ooi_type": "Network", "testnamewrong": "testnetwork"}), + client_member.user, ) response = OOIAddView.as_view()(request, organization_code=client_member.organization.code, ooi_type="Network") diff --git a/rocky/tools/forms/ooi.py b/rocky/tools/forms/ooi.py index 849862f46af..6e910beda53 100644 --- a/rocky/tools/forms/ooi.py +++ b/rocky/tools/forms/ooi.py @@ -117,3 +117,8 @@ class MuteFindingForm(forms.Form): finding = forms.CharField(widget=forms.HiddenInput(), required=False) ooi_type = forms.CharField(widget=forms.HiddenInput(), required=False) reason = forms.CharField(widget=forms.Textarea(attrs={"name": "reason", "rows": "3", "cols": "5"}), required=False) + end_valid_time = forms.DateTimeField( + label="Expires by (UTC)", + widget=forms.DateTimeInput(attrs={"name": "end_valid_time", "type": "datetime-local"}), + required=False, + ) diff --git a/rocky/tools/forms/ooi_form.py b/rocky/tools/forms/ooi_form.py index ec7e3c19f0b..992edc08e96 100644 --- a/rocky/tools/forms/ooi_form.py +++ b/rocky/tools/forms/ooi_form.py @@ -100,6 +100,18 @@ def generate_form_fields( else: fields[name] = forms.CharField(max_length=256, **default_attrs) + # ruff: noqa: ERA001 + # Currently we are not ready to use the following line as the + # event manager is not aware of the deletion of a generic OOI + # it does work for 'end-point'-OOIs like MutedFinding and the + # field is hidden for now + # fields["end_valid_time"] = forms.DateTimeField( + # label="Expires by", + # widget=forms.DateTimeInput(attrs={"type": "datetime-local"}), + # required=False, + # ) + fields["end_valid_time"] = forms.DateTimeField(widget=forms.HiddenInput(), required=False) + return fields diff --git a/rocky/tools/ooi_helpers.py b/rocky/tools/ooi_helpers.py index 7d2c6238254..ddf6e8d1b85 100644 --- a/rocky/tools/ooi_helpers.py +++ b/rocky/tools/ooi_helpers.py @@ -237,18 +237,28 @@ def get_finding_type_from_finding(finding: Finding) -> FindingType: def get_or_create_ooi( - api_connector: OctopoesAPIConnector, bytes_client: BytesClient, ooi: OOI, observed_at: datetime + api_connector: OctopoesAPIConnector, + bytes_client: BytesClient, + ooi: OOI, + observed_at: datetime, + end_valid_time: datetime | None = None, ) -> tuple[OOI, bool]: try: return api_connector.get(ooi.reference, observed_at), False except ObjectNotFoundException: - create_ooi(api_connector, bytes_client, ooi, observed_at) + create_ooi(api_connector, bytes_client, ooi, observed_at, end_valid_time) return ooi, True -def create_ooi(api_connector: OctopoesAPIConnector, bytes_client: BytesClient, ooi: OOI, observed_at: datetime) -> None: +def create_ooi( + api_connector: OctopoesAPIConnector, + bytes_client: BytesClient, + ooi: OOI, + observed_at: datetime, + end_valid_time: datetime | None = None, +) -> None: task_id = uuid4() - declaration = Declaration(ooi=ooi, valid_time=observed_at, task_id=str(task_id)) + declaration = Declaration(ooi=ooi, valid_time=observed_at, task_id=task_id, end_valid_time=end_valid_time) bytes_client.add_manual_proof(task_id, BytesClient.raw_from_declarations([declaration])) api_connector.save_declaration(declaration) From 1e6dab2718e289434058a41099a9e72bd407a019 Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:25:02 +0200 Subject: [PATCH 056/112] Add geo OOI type and Maxmind geoip boefje (#3238) Co-authored-by: Jeroen Dekkers Co-authored-by: ammar92 Co-authored-by: Jan Klopper Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> --- .../plugins/kat_maxmind_geoip/__init__.py | 0 .../plugins/kat_maxmind_geoip/boefje.json | 14 + .../plugins/kat_maxmind_geoip/cover.jpg | Bin 0 -> 56688 bytes .../boefjes/plugins/kat_maxmind_geoip/main.py | 122 ++ .../plugins/kat_maxmind_geoip/normalize.py | 19 + .../plugins/kat_maxmind_geoip/normalizer.json | 9 + .../plugins/kat_maxmind_geoip/schema.json | 40 + boefjes/poetry.lock | 1480 ++++++++++------- boefjes/pyproject.toml | 2 + boefjes/requirements-dev.txt | 1357 +++++++++------ boefjes/requirements.txt | 1351 +++++++++------ boefjes/tests/integration/test_api.py | 8 +- octopoes/octopoes/models/ooi/geography.py | 19 + octopoes/octopoes/models/types.py | 2 + 14 files changed, 2757 insertions(+), 1666 deletions(-) create mode 100644 boefjes/boefjes/plugins/kat_maxmind_geoip/__init__.py create mode 100644 boefjes/boefjes/plugins/kat_maxmind_geoip/boefje.json create mode 100644 boefjes/boefjes/plugins/kat_maxmind_geoip/cover.jpg create mode 100644 boefjes/boefjes/plugins/kat_maxmind_geoip/main.py create mode 100644 boefjes/boefjes/plugins/kat_maxmind_geoip/normalize.py create mode 100644 boefjes/boefjes/plugins/kat_maxmind_geoip/normalizer.json create mode 100644 boefjes/boefjes/plugins/kat_maxmind_geoip/schema.json create mode 100644 octopoes/octopoes/models/ooi/geography.py diff --git a/boefjes/boefjes/plugins/kat_maxmind_geoip/__init__.py b/boefjes/boefjes/plugins/kat_maxmind_geoip/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/boefjes/boefjes/plugins/kat_maxmind_geoip/boefje.json b/boefjes/boefjes/plugins/kat_maxmind_geoip/boefje.json new file mode 100644 index 00000000000..ba6e2e43c02 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_maxmind_geoip/boefje.json @@ -0,0 +1,14 @@ +{ + "id": "maxmind", + "name": "Maxmind", + "description": "Fetch geolocation information for an IP address from Maxmind", + "consumes": [ + "IPAddressV4", + "IPAddressV6" + ], + "scan_level": 1, + "environment_keys": [ + "MAXMIND_USER_ID", + "MAXMIND_LICENCE_KEY" + ] +} diff --git a/boefjes/boefjes/plugins/kat_maxmind_geoip/cover.jpg b/boefjes/boefjes/plugins/kat_maxmind_geoip/cover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..69ab294fe3b94dcebd9fd5bcce9cdc3135ce2ec7 GIT binary patch literal 56688 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¬_)I>uq+HDC#s3O0x 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 Izvr9(*^W3NrvLx| literal 0 HcmV?d00001 diff --git a/boefjes/boefjes/plugins/kat_maxmind_geoip/main.py b/boefjes/boefjes/plugins/kat_maxmind_geoip/main.py new file mode 100644 index 00000000000..bc2245c935b --- /dev/null +++ b/boefjes/boefjes/plugins/kat_maxmind_geoip/main.py @@ -0,0 +1,122 @@ +import hashlib +import io +import json +import os +import re +import shutil +import tarfile +from datetime import datetime, timezone +from os import getenv +from pathlib import Path + +import maxminddb +import requests + +from boefjes.job_models import BoefjeMeta + +BASE_PATH = Path(getenv("OPENKAT_CACHE_PATH", Path(__file__).parent)) +GEOIP_PATH_PATTERN = r"GeoLite2-City_\d+/GeoLite2-City.mmdb" +GEOIP_META_PATH = BASE_PATH / "geoip-meta.json" +GEOIP_SOURCE_URL = "https://download.maxmind.com/geoip/databases/GeoLite2-City/download?suffix=tar.gz" +GEOIP_CACHE_TIMEOUT = 86400 # in seconds +HASHFUNC = "sha256" +REQUEST_TIMEOUT = 30 + + +def run(boefje_meta: BoefjeMeta) -> list[tuple[set, bytes | str]]: + input_ = boefje_meta.arguments["input"] + hash_algorithm = getenv("HASHFUNC", HASHFUNC) + + if not geoip_file_exists() or cache_out_of_date(): + geoip_meta = refresh_geoip(hash_algorithm) + else: + with GEOIP_META_PATH.open() as json_meta_file: + geoip_meta = json.load(json_meta_file) + + geoip_path = find_geoip_path() + + with maxminddb.open_database(geoip_path) as reader: + results = reader.get(input_["address"]) + + return [ + ({"maxmind-geoip/geo_data"}, json.dumps(results)), + ( + {"maxmind-geoip/cache-meta"}, + json.dumps(geoip_meta), + ), + ] + + +def create_hash(data: bytes, algo: str) -> str: + hashfunc = getattr(hashlib, algo) + return hashfunc(data).hexdigest() + + +def cache_out_of_date() -> bool: + """Returns True if the file is older than the allowed cache_timout""" + now = datetime.now(timezone.utc) + max_age = int(getenv("GEOIP_CACHE_TIMEOUT", GEOIP_CACHE_TIMEOUT)) + with GEOIP_META_PATH.open() as meta_file: + meta = json.load(meta_file) + cached_file_timestamp = datetime.fromisoformat(meta["timestamp"]) + return (now - cached_file_timestamp).total_seconds() > max_age + + +def refresh_geoip(algo: str) -> dict: + maxmind_user_id = str(getenv("MAXMIND_USER_ID", "")) + maxmind_licence_key = getenv("MAXMIND_LICENCE_KEY", "") + source_url = getenv("GEOIP_SOURCE_URL", GEOIP_SOURCE_URL) + request_timeout = getenv("REQUEST_TIMEOUT", REQUEST_TIMEOUT) + response = requests.get( + source_url, allow_redirects=True, timeout=float(request_timeout), auth=(maxmind_user_id, maxmind_licence_key) + ) + response.raise_for_status() + + remove_old_geolite_data() + + file_like_object = io.BytesIO(response.content) + + with tarfile.open("r:gz", fileobj=file_like_object) as tf: + geoip_file = None + for member in tf.getmembers(): + if re.match(GEOIP_PATH_PATTERN, member.name): + geoip_file = member + break + if geoip_file: + tf.extract(geoip_file, BASE_PATH) + else: + raise FileNotFoundError("GeoLite2-City.mmdb not found in the tar archive") + + metadata = { + "timestamp": datetime.now(timezone.utc).isoformat(), + "source": source_url, + "hash": create_hash(response.content, algo), + "hash_algorithm": algo, + } + with open(GEOIP_META_PATH, "w") as meta_file: + json.dump(metadata, meta_file) + return metadata + + +def find_geoip_path() -> str: + """Find the GeoLite2-City.mmdb file in the BASE_PATH""" + for path in BASE_PATH.glob("GeoLite2-City_*/GeoLite2-City.mmdb"): + return str(path) + raise FileNotFoundError("GeoLite2-City.mmdb file not found in BASE_PATH") + + +def geoip_file_exists() -> bool: + """Check if the GeoLite2-City.mmdb file exists in the BASE_PATH""" + try: + find_geoip_path() + return True + except FileNotFoundError: + return False + + +def remove_old_geolite_data(): + """Removes old GeoLite2 directory""" + for root, dirs, files in os.walk(BASE_PATH, topdown=False): + for directory in dirs: + dir_path = os.path.join(root, directory) + shutil.rmtree(dir_path) diff --git a/boefjes/boefjes/plugins/kat_maxmind_geoip/normalize.py b/boefjes/boefjes/plugins/kat_maxmind_geoip/normalize.py new file mode 100644 index 00000000000..654086f3f90 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_maxmind_geoip/normalize.py @@ -0,0 +1,19 @@ +import json +from collections.abc import Iterable + +from boefjes.job_models import NormalizerOutput +from octopoes.models import Reference +from octopoes.models.ooi.geography import GeographicPoint + + +def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: + """Yields GeographicPoints.""" + results = json.loads(raw) + if not results: + return + + yield GeographicPoint( + ooi=Reference.from_str(input_ooi["primary_key"]), + longitude=results.get("location", {}).get("longitude"), + latitude=results.get("location", {}).get("latitude"), + ) diff --git a/boefjes/boefjes/plugins/kat_maxmind_geoip/normalizer.json b/boefjes/boefjes/plugins/kat_maxmind_geoip/normalizer.json new file mode 100644 index 00000000000..6a2c4c8012d --- /dev/null +++ b/boefjes/boefjes/plugins/kat_maxmind_geoip/normalizer.json @@ -0,0 +1,9 @@ +{ + "id": "kat_maxmind_geoip_normalize", + "consumes": [ + "maxmind-geoip/geo_data" + ], + "produces": [ + "GeographicPoint" + ] +} diff --git a/boefjes/boefjes/plugins/kat_maxmind_geoip/schema.json b/boefjes/boefjes/plugins/kat_maxmind_geoip/schema.json new file mode 100644 index 00000000000..0bee31c6b8d --- /dev/null +++ b/boefjes/boefjes/plugins/kat_maxmind_geoip/schema.json @@ -0,0 +1,40 @@ +{ + "title": "Arguments", + "type": "object", + "properties": { + "MAXMIND_USER_ID": { + "title": "User ID", + "type": "integer", + "maxLength": 48, + "description": "Numeric user id for MaxMind" + }, + "MAXMIND_LICENCE_KEY": { + "title": "Licence Key", + "maxLength": 48, + "type": "string", + "description": "Licence key for MaxMind" + }, + "GEOIP_CACHE_TIMEOUT": { + "title": "Cache Timeout", + "type": "integer", + "description": "Cache timeout in seconds" + }, + "GEOIP_SOURCE_URL": { + "title": "Source URL", + "type": "string", + "description": "URL to download the GeoIP database from" + }, + "REQUEST_TIMEOUT": { + "title": "Request Timeout", + "type": "integer", + "description": "Request timeout in seconds" + } + }, + "required": [ + "MAXMIND_USER_ID", + "MAXMIND_LICENCE_KEY" + ], + "secret": [ + "MAXMIND_LICENCE_KEY" + ] +} diff --git a/boefjes/poetry.lock b/boefjes/poetry.lock index 5c2f6c5c243..bc80d4d6270 100644 --- a/boefjes/poetry.lock +++ b/boefjes/poetry.lock @@ -1,91 +1,103 @@ # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +[[package]] +name = "aiohappyeyeballs" +version = "2.3.5" +description = "Happy Eyeballs for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohappyeyeballs-2.3.5-py3-none-any.whl", hash = "sha256:4d6dea59215537dbc746e93e779caea8178c866856a721c9c660d7a5a7b8be03"}, + {file = "aiohappyeyeballs-2.3.5.tar.gz", hash = "sha256:6fa48b9f1317254f122a07a131a86b71ca6946ca989ce6326fff54a99a920105"}, +] + [[package]] name = "aiohttp" -version = "3.9.5" +version = "3.10.1" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"}, - {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"}, - {file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"}, - {file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"}, - {file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"}, - {file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"}, - {file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"}, - {file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"}, - {file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe"}, - {file = "aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da"}, - {file = "aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2"}, - {file = "aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09"}, - {file = "aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1"}, - {file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"}, + {file = "aiohttp-3.10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:47b4c2412960e64d97258f40616efddaebcb34ff664c8a972119ed38fac2a62c"}, + {file = "aiohttp-3.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7dbf637f87dd315fa1f36aaed8afa929ee2c607454fb7791e74c88a0d94da59"}, + {file = "aiohttp-3.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c8fb76214b5b739ce59e2236a6489d9dc3483649cfd6f563dbf5d8e40dbdd57d"}, + {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c577cdcf8f92862363b3d598d971c6a84ed8f0bf824d4cc1ce70c2fb02acb4a"}, + {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:777e23609899cb230ad2642b4bdf1008890f84968be78de29099a8a86f10b261"}, + {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b07286a1090483799599a2f72f76ac396993da31f6e08efedb59f40876c144fa"}, + {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9db600a86414a9a653e3c1c7f6a2f6a1894ab8f83d11505247bd1b90ad57157"}, + {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c3f1eb280008e51965a8d160a108c333136f4a39d46f516c64d2aa2e6a53f2"}, + {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f5dd109a925fee4c9ac3f6a094900461a2712df41745f5d04782ebcbe6479ccb"}, + {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8c81ff4afffef9b1186639506d70ea90888218f5ddfff03870e74ec80bb59970"}, + {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2a384dfbe8bfebd203b778a30a712886d147c61943675f4719b56725a8bbe803"}, + {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:b9fb6508893dc31cfcbb8191ef35abd79751db1d6871b3e2caee83959b4d91eb"}, + {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:88596384c3bec644a96ae46287bb646d6a23fa6014afe3799156aef42669c6bd"}, + {file = "aiohttp-3.10.1-cp310-cp310-win32.whl", hash = "sha256:68164d43c580c2e8bf8e0eb4960142919d304052ccab92be10250a3a33b53268"}, + {file = "aiohttp-3.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d6bbe2c90c10382ca96df33b56e2060404a4f0f88673e1e84b44c8952517e5f3"}, + {file = "aiohttp-3.10.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f6979b4f20d3e557a867da9d9227de4c156fcdcb348a5848e3e6190fd7feb972"}, + {file = "aiohttp-3.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03c0c380c83f8a8d4416224aafb88d378376d6f4cadebb56b060688251055cd4"}, + {file = "aiohttp-3.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c2b104e81b3c3deba7e6f5bc1a9a0e9161c380530479970766a6655b8b77c7c"}, + {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b023b68c61ab0cd48bd38416b421464a62c381e32b9dc7b4bdfa2905807452a4"}, + {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a07c76a82390506ca0eabf57c0540cf5a60c993c442928fe4928472c4c6e5e6"}, + {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:41d8dab8c64ded1edf117d2a64f353efa096c52b853ef461aebd49abae979f16"}, + {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:615348fab1a9ef7d0960a905e83ad39051ae9cb0d2837da739b5d3a7671e497a"}, + {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:256ee6044214ee9d66d531bb374f065ee94e60667d6bbeaa25ca111fc3997158"}, + {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7d5bb926805022508b7ddeaad957f1fce7a8d77532068d7bdb431056dc630cd"}, + {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:028faf71b338f069077af6315ad54281612705d68889f5d914318cbc2aab0d50"}, + {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:5c12310d153b27aa630750be44e79313acc4e864c421eb7d2bc6fa3429c41bf8"}, + {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:de1a91d5faded9054957ed0a9e01b9d632109341942fc123947ced358c5d9009"}, + {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9c186b270979fb1dee3ababe2d12fb243ed7da08b30abc83ebac3a928a4ddb15"}, + {file = "aiohttp-3.10.1-cp311-cp311-win32.whl", hash = "sha256:4a9ce70f5e00380377aac0e568abd075266ff992be2e271765f7b35d228a990c"}, + {file = "aiohttp-3.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:a77c79bac8d908d839d32c212aef2354d2246eb9deb3e2cb01ffa83fb7a6ea5d"}, + {file = "aiohttp-3.10.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2212296cdb63b092e295c3e4b4b442e7b7eb41e8a30d0f53c16d5962efed395d"}, + {file = "aiohttp-3.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4dcb127ca3eb0a61205818a606393cbb60d93b7afb9accd2fd1e9081cc533144"}, + {file = "aiohttp-3.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb8b79a65332e1a426ccb6290ce0409e1dc16b4daac1cc5761e059127fa3d134"}, + {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68cc24f707ed9cb961f6ee04020ca01de2c89b2811f3cf3361dc7c96a14bfbcc"}, + {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cb54f5725b4b37af12edf6c9e834df59258c82c15a244daa521a065fbb11717"}, + {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:51d03e948e53b3639ce4d438f3d1d8202898ec6655cadcc09ec99229d4adc2a9"}, + {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:786299d719eb5d868f161aeec56d589396b053925b7e0ce36e983d30d0a3e55c"}, + {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abda4009a30d51d3f06f36bc7411a62b3e647fa6cc935ef667e3e3d3a7dd09b1"}, + {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:67f7639424c313125213954e93a6229d3a1d386855d70c292a12628f600c7150"}, + {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8e5a26d7aac4c0d8414a347da162696eea0629fdce939ada6aedf951abb1d745"}, + {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:120548d89f14b76a041088b582454d89389370632ee12bf39d919cc5c561d1ca"}, + {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f5293726943bdcea24715b121d8c4ae12581441d22623b0e6ab12d07ce85f9c4"}, + {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1f8605e573ed6c44ec689d94544b2c4bb1390aaa723a8b5a2cc0a5a485987a68"}, + {file = "aiohttp-3.10.1-cp312-cp312-win32.whl", hash = "sha256:e7168782621be4448d90169a60c8b37e9b0926b3b79b6097bc180c0a8a119e73"}, + {file = "aiohttp-3.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fbf8c0ded367c5c8eaf585f85ca8dd85ff4d5b73fb8fe1e6ac9e1b5e62e11f7"}, + {file = "aiohttp-3.10.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:54b7f4a20d7cc6bfa4438abbde069d417bb7a119f870975f78a2b99890226d55"}, + {file = "aiohttp-3.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2fa643ca990323db68911b92f3f7a0ca9ae300ae340d0235de87c523601e58d9"}, + {file = "aiohttp-3.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d8311d0d690487359fe2247ec5d2cac9946e70d50dced8c01ce9e72341c21151"}, + {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222821c60b8f6a64c5908cb43d69c0ee978a1188f6a8433d4757d39231b42cdb"}, + {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7b55d9ede66af7feb6de87ff277e0ccf6d51c7db74cc39337fe3a0e31b5872d"}, + {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a95151a5567b3b00368e99e9c5334a919514f60888a6b6d2054fea5e66e527e"}, + {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e9e9171d2fe6bfd9d3838a6fe63b1e91b55e0bf726c16edf265536e4eafed19"}, + {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a57e73f9523e980f6101dc9a83adcd7ac0006ea8bf7937ca3870391c7bb4f8ff"}, + {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0df51a3d70a2bfbb9c921619f68d6d02591f24f10e9c76de6f3388c89ed01de6"}, + {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:b0de63ff0307eac3961b4af74382d30220d4813f36b7aaaf57f063a1243b4214"}, + {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:8db9b749f589b5af8e4993623dbda6716b2b7a5fcb0fa2277bf3ce4b278c7059"}, + {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6b14c19172eb53b63931d3e62a9749d6519f7c121149493e6eefca055fcdb352"}, + {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5cd57ad998e3038aa87c38fe85c99ed728001bf5dde8eca121cadee06ee3f637"}, + {file = "aiohttp-3.10.1-cp38-cp38-win32.whl", hash = "sha256:df31641e3f02b77eb3c5fb63c0508bee0fc067cf153da0e002ebbb0db0b6d91a"}, + {file = "aiohttp-3.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:93094eba50bc2ad4c40ff4997ead1fdcd41536116f2e7d6cfec9596a8ecb3615"}, + {file = "aiohttp-3.10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:440954ddc6b77257e67170d57b1026aa9545275c33312357472504eef7b4cc0b"}, + {file = "aiohttp-3.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f9f8beed277488a52ee2b459b23c4135e54d6a819eaba2e120e57311015b58e9"}, + {file = "aiohttp-3.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d8a8221a63602008550022aa3a4152ca357e1dde7ab3dd1da7e1925050b56863"}, + {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a702bd3663b5cbf3916e84bf332400d24cdb18399f0877ca6b313ce6c08bfb43"}, + {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1988b370536eb14f0ce7f3a4a5b422ab64c4e255b3f5d7752c5f583dc8c967fc"}, + {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ccf1f0a304352c891d124ac1a9dea59b14b2abed1704aaa7689fc90ef9c5be1"}, + {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc3ea6ef2a83edad84bbdb5d96e22f587b67c68922cd7b6f9d8f24865e655bcf"}, + {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89b47c125ab07f0831803b88aeb12b04c564d5f07a1c1a225d4eb4d2f26e8b5e"}, + {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:21778552ef3d44aac3278cc6f6d13a6423504fa5f09f2df34bfe489ed9ded7f5"}, + {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bde0693073fd5e542e46ea100aa6c1a5d36282dbdbad85b1c3365d5421490a92"}, + {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:bf66149bb348d8e713f3a8e0b4f5b952094c2948c408e1cfef03b49e86745d60"}, + {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:587237571a85716d6f71f60d103416c9df7d5acb55d96d3d3ced65f39bff9c0c"}, + {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bfe33cba6e127d0b5b417623c9aa621f0a69f304742acdca929a9fdab4593693"}, + {file = "aiohttp-3.10.1-cp39-cp39-win32.whl", hash = "sha256:9fbff00646cf8211b330690eb2fd64b23e1ce5b63a342436c1d1d6951d53d8dd"}, + {file = "aiohttp-3.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:5951c328f9ac42d7bce7a6ded535879bc9ae13032818d036749631fa27777905"}, + {file = "aiohttp-3.10.1.tar.gz", hash = "sha256:8b0d058e4e425d3b45e8ec70d49b402f4d6b21041e674798b1f91ba027c73f28"}, ] [package.dependencies] +aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" @@ -94,7 +106,7 @@ multidict = ">=4.5,<7.0" yarl = ">=1.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns", "brotlicffi"] +speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] [[package]] name = "aioresponses" @@ -126,13 +138,13 @@ frozenlist = ">=1.1.0" [[package]] name = "alembic" -version = "1.13.1" +version = "1.13.2" description = "A database migration tool for SQLAlchemy." optional = false python-versions = ">=3.8" files = [ - {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, - {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, + {file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"}, + {file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"}, ] [package.dependencies] @@ -167,13 +179,13 @@ files = [ [[package]] name = "anyio" -version = "4.3.0" +version = "4.4.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, - {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, + {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, + {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, ] [package.dependencies] @@ -189,13 +201,13 @@ trio = ["trio (>=0.23)"] [[package]] name = "asgiref" -version = "3.7.2" +version = "3.8.1" description = "ASGI specs, helper code, and adapters" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, - {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, + {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, + {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, ] [package.dependencies] @@ -217,22 +229,22 @@ files = [ [[package]] name = "attrs" -version = "23.2.0" +version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "backoff" @@ -292,63 +304,78 @@ files = [ [[package]] name = "cffi" -version = "1.16.0" +version = "1.17.0" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, + {file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"}, + {file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b"}, + {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206"}, + {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa"}, + {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f"}, + {file = "cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc"}, + {file = "cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2"}, + {file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"}, + {file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"}, + {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"}, + {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"}, + {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"}, + {file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"}, + {file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"}, + {file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"}, + {file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"}, + {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"}, + {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"}, + {file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"}, + {file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"}, + {file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"}, + {file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"}, + {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"}, + {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"}, + {file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"}, + {file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"}, + {file = "cffi-1.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c"}, + {file = "cffi-1.17.0-cp38-cp38-win32.whl", hash = "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499"}, + {file = "cffi-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c"}, + {file = "cffi-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2"}, + {file = "cffi-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932"}, + {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693"}, + {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3"}, + {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4"}, + {file = "cffi-1.17.0-cp39-cp39-win32.whl", hash = "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb"}, + {file = "cffi-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29"}, + {file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"}, ] [package.dependencies] @@ -497,18 +524,18 @@ files = [ [[package]] name = "configparser" -version = "6.0.0" +version = "7.0.0" description = "Updated configparser from stdlib for earlier Pythons." optional = false python-versions = ">=3.8" files = [ - {file = "configparser-6.0.0-py3-none-any.whl", hash = "sha256:900ea2bb01b2540b1a644ad3d5351e9b961a4a012d4732f619375fb8f641ee19"}, - {file = "configparser-6.0.0.tar.gz", hash = "sha256:ec914ab1e56c672de1f5c3483964e68f71b34e457904b7b76e06b922aec067a8"}, + {file = "configparser-7.0.0-py3-none-any.whl", hash = "sha256:f46d52a12811c637104c6bb8eb33693be0038ab6bf01d69aae009c39ec8c2017"}, + {file = "configparser-7.0.0.tar.gz", hash = "sha256:af3c618a67aaaedc4d689fd7317d238f566b9aa03cae50102e92d7f0dfe78ba0"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "types-backports"] +testing = ["pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "types-backports"] [[package]] name = "cryptography" @@ -647,13 +674,13 @@ websockets = ["websocket-client (>=1.3.0)"] [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -681,18 +708,18 @@ standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23 [[package]] name = "filelock" -version = "3.13.1" +version = "3.15.4" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, - {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, + {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, + {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] typing = ["typing-extensions (>=4.8)"] [[package]] @@ -798,17 +825,17 @@ files = [ [[package]] name = "googleapis-common-protos" -version = "1.62.0" +version = "1.63.2" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, - {file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"}, + {file = "googleapis-common-protos-1.63.2.tar.gz", hash = "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87"}, + {file = "googleapis_common_protos-1.63.2-py2.py3-none-any.whl", hash = "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945"}, ] [package.dependencies] -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] @@ -886,69 +913,61 @@ test = ["objgraph", "psutil"] [[package]] name = "grpcio" -version = "1.62.0" +version = "1.65.4" description = "HTTP/2-based RPC framework" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "grpcio-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271"}, - {file = "grpcio-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6"}, - {file = "grpcio-1.62.0-cp310-cp310-win32.whl", hash = "sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc"}, - {file = "grpcio-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa"}, - {file = "grpcio-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f"}, - {file = "grpcio-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e"}, - {file = "grpcio-1.62.0-cp311-cp311-win32.whl", hash = "sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd"}, - {file = "grpcio-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334"}, - {file = "grpcio-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8"}, - {file = "grpcio-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388"}, - {file = "grpcio-1.62.0-cp312-cp312-win32.whl", hash = "sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701"}, - {file = "grpcio-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842"}, - {file = "grpcio-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9"}, - {file = "grpcio-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b"}, - {file = "grpcio-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b"}, - {file = "grpcio-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35"}, - {file = "grpcio-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38"}, - {file = "grpcio-1.62.0-cp38-cp38-win32.whl", hash = "sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe"}, - {file = "grpcio-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270"}, - {file = "grpcio-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170"}, - {file = "grpcio-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a"}, - {file = "grpcio-1.62.0-cp39-cp39-win32.whl", hash = "sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93"}, - {file = "grpcio-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5"}, - {file = "grpcio-1.62.0.tar.gz", hash = "sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7"}, + {file = "grpcio-1.65.4-cp310-cp310-linux_armv7l.whl", hash = "sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c"}, + {file = "grpcio-1.65.4-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e"}, + {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de"}, + {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d"}, + {file = "grpcio-1.65.4-cp310-cp310-win32.whl", hash = "sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1"}, + {file = "grpcio-1.65.4-cp310-cp310-win_amd64.whl", hash = "sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec"}, + {file = "grpcio-1.65.4-cp311-cp311-linux_armv7l.whl", hash = "sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef"}, + {file = "grpcio-1.65.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4"}, + {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e"}, + {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5"}, + {file = "grpcio-1.65.4-cp311-cp311-win32.whl", hash = "sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b"}, + {file = "grpcio-1.65.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558"}, + {file = "grpcio-1.65.4-cp312-cp312-linux_armv7l.whl", hash = "sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56"}, + {file = "grpcio-1.65.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63"}, + {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a"}, + {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28"}, + {file = "grpcio-1.65.4-cp312-cp312-win32.whl", hash = "sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0"}, + {file = "grpcio-1.65.4-cp312-cp312-win_amd64.whl", hash = "sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416"}, + {file = "grpcio-1.65.4-cp38-cp38-linux_armv7l.whl", hash = "sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021"}, + {file = "grpcio-1.65.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816"}, + {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524"}, + {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7"}, + {file = "grpcio-1.65.4-cp38-cp38-win32.whl", hash = "sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a"}, + {file = "grpcio-1.65.4-cp38-cp38-win_amd64.whl", hash = "sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f"}, + {file = "grpcio-1.65.4-cp39-cp39-linux_armv7l.whl", hash = "sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733"}, + {file = "grpcio-1.65.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b"}, + {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2"}, + {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257"}, + {file = "grpcio-1.65.4-cp39-cp39-win32.whl", hash = "sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d"}, + {file = "grpcio-1.65.4-cp39-cp39-win_amd64.whl", hash = "sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9"}, + {file = "grpcio-1.65.4.tar.gz", hash = "sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.62.0)"] +protobuf = ["grpcio-tools (>=1.65.4)"] [[package]] name = "h11" @@ -1029,22 +1048,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.11.0" +version = "8.0.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.11.0-py3-none-any.whl", hash = "sha256:f0afba6205ad8f8947c7d338b5342d5db2afbfd82f9cbef7879a9539cc12eb9b"}, - {file = "importlib_metadata-6.11.0.tar.gz", hash = "sha256:1231cf92d825c9e03cfc4da076a16de6422c863558229ea0b22b675657463443"}, + {file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"}, + {file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "iniconfig" @@ -1059,13 +1078,13 @@ files = [ [[package]] name = "jsonschema" -version = "4.21.1" +version = "4.23.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema-4.21.1-py3-none-any.whl", hash = "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f"}, - {file = "jsonschema-4.21.1.tar.gz", hash = "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5"}, + {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, + {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, ] [package.dependencies] @@ -1076,7 +1095,7 @@ rpds-py = ">=0.7.1" [package.extras] format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] [[package]] name = "jsonschema-specifications" @@ -1094,120 +1113,207 @@ referencing = ">=0.31.0" [[package]] name = "langcodes" -version = "3.3.0" +version = "3.4.0" description = "Tools for labeling human languages with IETF language tags" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "langcodes-3.3.0-py3-none-any.whl", hash = "sha256:4d89fc9acb6e9c8fdef70bcdf376113a3db09b67285d9e1d534de6d8818e7e69"}, - {file = "langcodes-3.3.0.tar.gz", hash = "sha256:794d07d5a28781231ac335a1561b8442f8648ca07cd518310aeb45d6f0807ef6"}, + {file = "langcodes-3.4.0-py3-none-any.whl", hash = "sha256:10a4cc078b8e8937d8485d3352312a0a89a3125190db9f2bb2074250eef654e9"}, + {file = "langcodes-3.4.0.tar.gz", hash = "sha256:ae5a77d1a01d0d1e91854a671890892b7ce9abb601ab7327fc5c874f899e1979"}, ] +[package.dependencies] +language-data = ">=1.2" + +[package.extras] +build = ["build", "twine"] +test = ["pytest", "pytest-cov"] + +[[package]] +name = "language-data" +version = "1.2.0" +description = "Supplementary data about languages used by the langcodes module" +optional = false +python-versions = "*" +files = [ + {file = "language_data-1.2.0-py3-none-any.whl", hash = "sha256:77d5cab917f91ee0b2f1aa7018443e911cf8985ef734ca2ba3940770f6a3816b"}, + {file = "language_data-1.2.0.tar.gz", hash = "sha256:82a86050bbd677bfde87d97885b17566cfe75dad3ac4f5ce44b52c28f752e773"}, +] + +[package.dependencies] +marisa-trie = ">=0.7.7" + [package.extras] -data = ["language-data (>=1.1,<2.0)"] +build = ["build", "twine"] +test = ["pytest", "pytest-cov"] [[package]] name = "lxml" -version = "5.1.0" +version = "5.2.2" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" files = [ - {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e"}, - {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da"}, - {file = "lxml-5.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2befa20a13f1a75c751f47e00929fb3433d67eb9923c2c0b364de449121f447c"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22b7ee4c35f374e2c20337a95502057964d7e35b996b1c667b5c65c567d2252a"}, - {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bf8443781533b8d37b295016a4b53c1494fa9a03573c09ca5104550c138d5c05"}, - {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147"}, - {file = "lxml-5.1.0-cp310-cp310-win32.whl", hash = "sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93"}, - {file = "lxml-5.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af8920ce4a55ff41167ddbc20077f5698c2e710ad3353d32a07d3264f3a2021e"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cfced4a069003d8913408e10ca8ed092c49a7f6cefee9bb74b6b3e860683b45"}, - {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9e5ac3437746189a9b4121db2a7b86056ac8786b12e88838696899328fc44bb2"}, - {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204"}, - {file = "lxml-5.1.0-cp311-cp311-win32.whl", hash = "sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b"}, - {file = "lxml-5.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16dd953fb719f0ffc5bc067428fc9e88f599e15723a85618c45847c96f11f431"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16018f7099245157564d7148165132c70adb272fb5a17c048ba70d9cc542a1a1"}, - {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:82cd34f1081ae4ea2ede3d52f71b7be313756e99b4b5f829f89b12da552d3aa3"}, - {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:19a1bc898ae9f06bccb7c3e1dfd73897ecbbd2c96afe9095a6026016e5ca97b8"}, - {file = "lxml-5.1.0-cp312-cp312-win32.whl", hash = "sha256:13521a321a25c641b9ea127ef478b580b5ec82aa2e9fc076c86169d161798b01"}, - {file = "lxml-5.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:1ad17c20e3666c035db502c78b86e58ff6b5991906e55bdbef94977700c72623"}, - {file = "lxml-5.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:24ef5a4631c0b6cceaf2dbca21687e29725b7c4e171f33a8f8ce23c12558ded1"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d2900b7f5318bc7ad8631d3d40190b95ef2aa8cc59473b73b294e4a55e9f30f"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:601f4a75797d7a770daed8b42b97cd1bb1ba18bd51a9382077a6a247a12aa38d"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4b68c961b5cc402cbd99cca5eb2547e46ce77260eb705f4d117fd9c3f932b95"}, - {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:afd825e30f8d1f521713a5669b63657bcfe5980a916c95855060048b88e1adb7"}, - {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:262bc5f512a66b527d026518507e78c2f9c2bd9eb5c8aeeb9f0eb43fcb69dc67"}, - {file = "lxml-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:e856c1c7255c739434489ec9c8aa9cdf5179785d10ff20add308b5d673bed5cd"}, - {file = "lxml-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c7257171bb8d4432fe9d6fdde4d55fdbe663a63636a17f7f9aaba9bcb3153ad7"}, - {file = "lxml-5.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b9e240ae0ba96477682aa87899d94ddec1cc7926f9df29b1dd57b39e797d5ab5"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a96f02ba1bcd330807fc060ed91d1f7a20853da6dd449e5da4b09bfcc08fdcf5"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3898ae2b58eeafedfe99e542a17859017d72d7f6a63de0f04f99c2cb125936"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61c5a7edbd7c695e54fca029ceb351fc45cd8860119a0f83e48be44e1c464862"}, - {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3aeca824b38ca78d9ee2ab82bd9883083d0492d9d17df065ba3b94e88e4d7ee6"}, - {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764"}, - {file = "lxml-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8"}, - {file = "lxml-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b"}, - {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1"}, - {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45"}, - {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:98f3f020a2b736566c707c8e034945c02aa94e124c24f77ca097c446f81b01f1"}, - {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e"}, - {file = "lxml-5.1.0-cp38-cp38-win32.whl", hash = "sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a"}, - {file = "lxml-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f8b0c78e7aac24979ef09b7f50da871c2de2def043d468c4b41f512d831e912"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bcf86dfc8ff3e992fed847c077bd875d9e0ba2fa25d859c3a0f0f76f07f0c8d"}, - {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:49a9b4af45e8b925e1cd6f3b15bbba2c81e7dba6dce170c677c9cda547411e14"}, - {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:280f3edf15c2a967d923bcfb1f8f15337ad36f93525828b40a0f9d6c2ad24890"}, - {file = "lxml-5.1.0-cp39-cp39-win32.whl", hash = "sha256:ed7326563024b6e91fef6b6c7a1a2ff0a71b97793ac33dbbcf38f6005e51ff6e"}, - {file = "lxml-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:8d7b4beebb178e9183138f552238f7e6613162a42164233e2bda00cb3afac58f"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9bd0ae7cc2b85320abd5e0abad5ccee5564ed5f0cc90245d2f9a8ef330a8deae"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8c1d679df4361408b628f42b26a5d62bd3e9ba7f0c0e7969f925021554755aa"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2ad3a8ce9e8a767131061a22cd28fdffa3cd2dc193f399ff7b81777f3520e372"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:304128394c9c22b6569eba2a6d98392b56fbdfbad58f83ea702530be80d0f9df"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d74fcaf87132ffc0447b3c685a9f862ffb5b43e70ea6beec2fb8057d5d2a1fea"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8cf5877f7ed384dabfdcc37922c3191bf27e55b498fecece9fd5c2c7aaa34c33"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:877efb968c3d7eb2dad540b6cabf2f1d3c0fbf4b2d309a3c141f79c7e0061324"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f14a4fb1c1c402a22e6a341a24c1341b4a3def81b41cd354386dcb795f83897"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:25663d6e99659544ee8fe1b89b1a8c0aaa5e34b103fab124b17fa958c4a324a6"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8b9f19df998761babaa7f09e6bc169294eefafd6149aaa272081cbddc7ba4ca3"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e53d7e6a98b64fe54775d23a7c669763451340c3d44ad5e3a3b48a1efbdc96f"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c3cd1fc1dc7c376c54440aeaaa0dcc803d2126732ff5c6b68ccd619f2e64be4f"}, - {file = "lxml-5.1.0.tar.gz", hash = "sha256:3eea6ed6e6c918e468e693c41ef07f3c3acc310b70ddd9cc72d9ef84bc9564ca"}, + {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632"}, + {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74e4f025ef3db1c6da4460dd27c118d8cd136d0391da4e387a15e48e5c975147"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981a06a3076997adf7c743dcd0d7a0415582661e2517c7d961493572e909aa1d"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aef5474d913d3b05e613906ba4090433c515e13ea49c837aca18bde190853dff"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e275ea572389e41e8b039ac076a46cb87ee6b8542df3fff26f5baab43713bca"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5b65529bb2f21ac7861a0e94fdbf5dc0daab41497d18223b46ee8515e5ad297"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bcc98f911f10278d1daf14b87d65325851a1d29153caaf146877ec37031d5f36"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:b47633251727c8fe279f34025844b3b3a3e40cd1b198356d003aa146258d13a2"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:fbc9d316552f9ef7bba39f4edfad4a734d3d6f93341232a9dddadec4f15d425f"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:13e69be35391ce72712184f69000cda04fc89689429179bc4c0ae5f0b7a8c21b"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3b6a30a9ab040b3f545b697cb3adbf3696c05a3a68aad172e3fd7ca73ab3c835"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a233bb68625a85126ac9f1fc66d24337d6e8a0f9207b688eec2e7c880f012ec0"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:dfa7c241073d8f2b8e8dbc7803c434f57dbb83ae2a3d7892dd068d99e96efe2c"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a7aca7964ac4bb07680d5c9d63b9d7028cace3e2d43175cb50bba8c5ad33316"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ae4073a60ab98529ab8a72ebf429f2a8cc612619a8c04e08bed27450d52103c0"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ffb2be176fed4457e445fe540617f0252a72a8bc56208fd65a690fdb1f57660b"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e290d79a4107d7d794634ce3e985b9ae4f920380a813717adf61804904dc4393"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:96e85aa09274955bb6bd483eaf5b12abadade01010478154b0ec70284c1b1526"}, + {file = "lxml-5.2.2-cp310-cp310-win32.whl", hash = "sha256:f956196ef61369f1685d14dad80611488d8dc1ef00be57c0c5a03064005b0f30"}, + {file = "lxml-5.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:875a3f90d7eb5c5d77e529080d95140eacb3c6d13ad5b616ee8095447b1d22e7"}, + {file = "lxml-5.2.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:45f9494613160d0405682f9eee781c7e6d1bf45f819654eb249f8f46a2c22545"}, + {file = "lxml-5.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b0b3f2df149efb242cee2ffdeb6674b7f30d23c9a7af26595099afaf46ef4e88"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d28cb356f119a437cc58a13f8135ab8a4c8ece18159eb9194b0d269ec4e28083"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:657a972f46bbefdbba2d4f14413c0d079f9ae243bd68193cb5061b9732fa54c1"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b9ea10063efb77a965a8d5f4182806fbf59ed068b3c3fd6f30d2ac7bee734"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07542787f86112d46d07d4f3c4e7c760282011b354d012dc4141cc12a68cef5f"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:303f540ad2dddd35b92415b74b900c749ec2010e703ab3bfd6660979d01fd4ed"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2eb2227ce1ff998faf0cd7fe85bbf086aa41dfc5af3b1d80867ecfe75fb68df3"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:1d8a701774dfc42a2f0b8ccdfe7dbc140500d1049e0632a611985d943fcf12df"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:56793b7a1a091a7c286b5f4aa1fe4ae5d1446fe742d00cdf2ffb1077865db10d"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eb00b549b13bd6d884c863554566095bf6fa9c3cecb2e7b399c4bc7904cb33b5"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a2569a1f15ae6c8c64108a2cd2b4a858fc1e13d25846be0666fc144715e32ab"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:8cf85a6e40ff1f37fe0f25719aadf443686b1ac7652593dc53c7ef9b8492b115"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:d237ba6664b8e60fd90b8549a149a74fcc675272e0e95539a00522e4ca688b04"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0b3f5016e00ae7630a4b83d0868fca1e3d494c78a75b1c7252606a3a1c5fc2ad"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23441e2b5339bc54dc949e9e675fa35efe858108404ef9aa92f0456929ef6fe8"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2fb0ba3e8566548d6c8e7dd82a8229ff47bd8fb8c2da237607ac8e5a1b8312e5"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:79d1fb9252e7e2cfe4de6e9a6610c7cbb99b9708e2c3e29057f487de5a9eaefa"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6dcc3d17eac1df7859ae01202e9bb11ffa8c98949dcbeb1069c8b9a75917e01b"}, + {file = "lxml-5.2.2-cp311-cp311-win32.whl", hash = "sha256:4c30a2f83677876465f44c018830f608fa3c6a8a466eb223535035fbc16f3438"}, + {file = "lxml-5.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:49095a38eb333aaf44c06052fd2ec3b8f23e19747ca7ec6f6c954ffea6dbf7be"}, + {file = "lxml-5.2.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7429e7faa1a60cad26ae4227f4dd0459efde239e494c7312624ce228e04f6391"}, + {file = "lxml-5.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:50ccb5d355961c0f12f6cf24b7187dbabd5433f29e15147a67995474f27d1776"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc911208b18842a3a57266d8e51fc3cfaccee90a5351b92079beed912a7914c2"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33ce9e786753743159799fdf8e92a5da351158c4bfb6f2db0bf31e7892a1feb5"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec87c44f619380878bd49ca109669c9f221d9ae6883a5bcb3616785fa8f94c97"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08ea0f606808354eb8f2dfaac095963cb25d9d28e27edcc375d7b30ab01abbf6"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75a9632f1d4f698b2e6e2e1ada40e71f369b15d69baddb8968dcc8e683839b18"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74da9f97daec6928567b48c90ea2c82a106b2d500f397eeb8941e47d30b1ca85"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:0969e92af09c5687d769731e3f39ed62427cc72176cebb54b7a9d52cc4fa3b73"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:9164361769b6ca7769079f4d426a41df6164879f7f3568be9086e15baca61466"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d26a618ae1766279f2660aca0081b2220aca6bd1aa06b2cf73f07383faf48927"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab67ed772c584b7ef2379797bf14b82df9aa5f7438c5b9a09624dd834c1c1aaf"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:3d1e35572a56941b32c239774d7e9ad724074d37f90c7a7d499ab98761bd80cf"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:8268cbcd48c5375f46e000adb1390572c98879eb4f77910c6053d25cc3ac2c67"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e282aedd63c639c07c3857097fc0e236f984ceb4089a8b284da1c526491e3f3d"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfdc2bfe69e9adf0df4915949c22a25b39d175d599bf98e7ddf620a13678585"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4aefd911793b5d2d7a921233a54c90329bf3d4a6817dc465f12ffdfe4fc7b8fe"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8b8df03a9e995b6211dafa63b32f9d405881518ff1ddd775db4e7b98fb545e1c"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f11ae142f3a322d44513de1018b50f474f8f736bc3cd91d969f464b5bfef8836"}, + {file = "lxml-5.2.2-cp312-cp312-win32.whl", hash = "sha256:16a8326e51fcdffc886294c1e70b11ddccec836516a343f9ed0f82aac043c24a"}, + {file = "lxml-5.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:bbc4b80af581e18568ff07f6395c02114d05f4865c2812a1f02f2eaecf0bfd48"}, + {file = "lxml-5.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e3d9d13603410b72787579769469af730c38f2f25505573a5888a94b62b920f8"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38b67afb0a06b8575948641c1d6d68e41b83a3abeae2ca9eed2ac59892b36706"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c689d0d5381f56de7bd6966a4541bff6e08bf8d3871bbd89a0c6ab18aa699573"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:cf2a978c795b54c539f47964ec05e35c05bd045db5ca1e8366988c7f2fe6b3ce"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:739e36ef7412b2bd940f75b278749106e6d025e40027c0b94a17ef7968d55d56"}, + {file = "lxml-5.2.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d8bbcd21769594dbba9c37d3c819e2d5847656ca99c747ddb31ac1701d0c0ed9"}, + {file = "lxml-5.2.2-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:2304d3c93f2258ccf2cf7a6ba8c761d76ef84948d87bf9664e14d203da2cd264"}, + {file = "lxml-5.2.2-cp36-cp36m-win32.whl", hash = "sha256:02437fb7308386867c8b7b0e5bc4cd4b04548b1c5d089ffb8e7b31009b961dc3"}, + {file = "lxml-5.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196"}, + {file = "lxml-5.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61"}, + {file = "lxml-5.2.2-cp37-cp37m-win32.whl", hash = "sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f"}, + {file = "lxml-5.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40"}, + {file = "lxml-5.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7ed07b3062b055d7a7f9d6557a251cc655eed0b3152b76de619516621c56f5d3"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f60fdd125d85bf9c279ffb8e94c78c51b3b6a37711464e1f5f31078b45002421"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a7e24cb69ee5f32e003f50e016d5fde438010c1022c96738b04fc2423e61706"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23cfafd56887eaed93d07bc4547abd5e09d837a002b791e9767765492a75883f"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19b4e485cd07b7d83e3fe3b72132e7df70bfac22b14fe4bf7a23822c3a35bff5"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7ce7ad8abebe737ad6143d9d3bf94b88b93365ea30a5b81f6877ec9c0dee0a48"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e49b052b768bb74f58c7dda4e0bdf7b79d43a9204ca584ffe1fb48a6f3c84c66"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d14a0d029a4e176795cef99c056d58067c06195e0c7e2dbb293bf95c08f772a3"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:be49ad33819d7dcc28a309b86d4ed98e1a65f3075c6acd3cd4fe32103235222b"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a6d17e0370d2516d5bb9062c7b4cb731cff921fc875644c3d751ad857ba9c5b1"}, + {file = "lxml-5.2.2-cp38-cp38-win32.whl", hash = "sha256:5b8c041b6265e08eac8a724b74b655404070b636a8dd6d7a13c3adc07882ef30"}, + {file = "lxml-5.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:f61efaf4bed1cc0860e567d2ecb2363974d414f7f1f124b1df368bbf183453a6"}, + {file = "lxml-5.2.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fb91819461b1b56d06fa4bcf86617fac795f6a99d12239fb0c68dbeba41a0a30"}, + {file = "lxml-5.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d4ed0c7cbecde7194cd3228c044e86bf73e30a23505af852857c09c24e77ec5d"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54401c77a63cc7d6dc4b4e173bb484f28a5607f3df71484709fe037c92d4f0ed"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:625e3ef310e7fa3a761d48ca7ea1f9d8718a32b1542e727d584d82f4453d5eeb"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:519895c99c815a1a24a926d5b60627ce5ea48e9f639a5cd328bda0515ea0f10c"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c7079d5eb1c1315a858bbf180000757db8ad904a89476653232db835c3114001"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:343ab62e9ca78094f2306aefed67dcfad61c4683f87eee48ff2fd74902447726"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:cd9e78285da6c9ba2d5c769628f43ef66d96ac3085e59b10ad4f3707980710d3"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:546cf886f6242dff9ec206331209db9c8e1643ae642dea5fdbecae2453cb50fd"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:02f6a8eb6512fdc2fd4ca10a49c341c4e109aa6e9448cc4859af5b949622715a"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:339ee4a4704bc724757cd5dd9dc8cf4d00980f5d3e6e06d5847c1b594ace68ab"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0a028b61a2e357ace98b1615fc03f76eb517cc028993964fe08ad514b1e8892d"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f90e552ecbad426eab352e7b2933091f2be77115bb16f09f78404861c8322981"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d83e2d94b69bf31ead2fa45f0acdef0757fa0458a129734f59f67f3d2eb7ef32"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a02d3c48f9bb1e10c7788d92c0c7db6f2002d024ab6e74d6f45ae33e3d0288a3"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6d68ce8e7b2075390e8ac1e1d3a99e8b6372c694bbe612632606d1d546794207"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:453d037e09a5176d92ec0fd282e934ed26d806331a8b70ab431a81e2fbabf56d"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:3b019d4ee84b683342af793b56bb35034bd749e4cbdd3d33f7d1107790f8c472"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb3942960f0beb9f46e2a71a3aca220d1ca32feb5a398656be934320804c0df9"}, + {file = "lxml-5.2.2-cp39-cp39-win32.whl", hash = "sha256:ac6540c9fff6e3813d29d0403ee7a81897f1d8ecc09a8ff84d2eea70ede1cdbf"}, + {file = "lxml-5.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:610b5c77428a50269f38a534057444c249976433f40f53e3b47e68349cca1425"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b537bd04d7ccd7c6350cdaaaad911f6312cbd61e6e6045542f781c7f8b2e99d2"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4820c02195d6dfb7b8508ff276752f6b2ff8b64ae5d13ebe02e7667e035000b9"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a09f6184f17a80897172863a655467da2b11151ec98ba8d7af89f17bf63dae"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:76acba4c66c47d27c8365e7c10b3d8016a7da83d3191d053a58382311a8bf4e1"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b128092c927eaf485928cec0c28f6b8bead277e28acf56800e972aa2c2abd7a2"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ae791f6bd43305aade8c0e22f816b34f3b72b6c820477aab4d18473a37e8090b"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a2f6a1bc2460e643785a2cde17293bd7a8f990884b822f7bca47bee0a82fc66b"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e8d351ff44c1638cb6e980623d517abd9f580d2e53bfcd18d8941c052a5a009"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bec4bd9133420c5c52d562469c754f27c5c9e36ee06abc169612c959bd7dbb07"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:55ce6b6d803890bd3cc89975fca9de1dff39729b43b73cb15ddd933b8bc20484"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ab6a358d1286498d80fe67bd3d69fcbc7d1359b45b41e74c4a26964ca99c3f8"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:06668e39e1f3c065349c51ac27ae430719d7806c026fec462e5693b08b95696b"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9cd5323344d8ebb9fb5e96da5de5ad4ebab993bbf51674259dbe9d7a18049525"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89feb82ca055af0fe797a2323ec9043b26bc371365847dbe83c7fd2e2f181c34"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e481bba1e11ba585fb06db666bfc23dbe181dbafc7b25776156120bf12e0d5a6"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d6c6ea6a11ca0ff9cd0390b885984ed31157c168565702959c25e2191674a14"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3d98de734abee23e61f6b8c2e08a88453ada7d6486dc7cdc82922a03968928db"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:69ab77a1373f1e7563e0fb5a29a8440367dec051da6c7405333699d07444f511"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:34e17913c431f5ae01d8658dbf792fdc457073dcdfbb31dc0cc6ab256e664a8d"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f8757b03208c3f50097761be2dea0aba02e94f0dc7023ed73a7bb14ff11eb0"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a520b4f9974b0a0a6ed73c2154de57cdfd0c8800f4f15ab2b73238ffed0b36e"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5e097646944b66207023bc3c634827de858aebc226d5d4d6d16f0b77566ea182"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b5e4ef22ff25bfd4ede5f8fb30f7b24446345f3e79d9b7455aef2836437bc38a"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324"}, + {file = "lxml-5.2.2.tar.gz", hash = "sha256:bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] +html-clean = ["lxml-html-clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.7)"] +source = ["Cython (>=3.0.10)"] [[package]] name = "mako" -version = "1.3.2" +version = "1.3.5" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false python-versions = ">=3.8" files = [ - {file = "Mako-1.3.2-py3-none-any.whl", hash = "sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c"}, - {file = "Mako-1.3.2.tar.gz", hash = "sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e"}, + {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"}, + {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"}, ] [package.dependencies] @@ -1218,6 +1324,109 @@ babel = ["Babel"] lingua = ["lingua"] testing = ["pytest"] +[[package]] +name = "marisa-trie" +version = "1.2.0" +description = "Static memory-efficient and fast Trie-like structures for Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "marisa_trie-1.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:61fab91fef677f0af0e818e61595f2334f7e0b3e122b24ec65889aae69ba468d"}, + {file = "marisa_trie-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f5b3080316de735bd2b07265de5eea3ae176fa2fc60f9871aeaa9cdcddfc8f7"}, + {file = "marisa_trie-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:77bfde3287314e91e28d3a882c7b87519ef0ee104c921df72c7819987d5e4863"}, + {file = "marisa_trie-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4fbb1ec1d9e891060a0aee9f9c243acec63de1e197097a14850ba38ec8a4013"}, + {file = "marisa_trie-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e04e9c86fe8908b61c2aebb8444217cacaed15b93d2dccaac3849e36a6dc660"}, + {file = "marisa_trie-1.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a7c75a508f44e40f7af8448d466045a97534adcbb026e63989407cefb9ebfa6"}, + {file = "marisa_trie-1.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5321211647609869907e81b0230ad2dfdfa7e19fe1ee469b46304a622391e6a1"}, + {file = "marisa_trie-1.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:88660e6ee0f821872aaf63ba4b9a7513428b9cab20c69cc013c368bd72c3a4fe"}, + {file = "marisa_trie-1.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4e4535fc5458de2b59789e574cdd55923d63de5612dc159d33941af79cd62786"}, + {file = "marisa_trie-1.2.0-cp310-cp310-win32.whl", hash = "sha256:bdd1d4d430e33abbe558971d1bd57da2d44ca129fa8a86924c51437dba5cb345"}, + {file = "marisa_trie-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:c729e2b8f9699874b1372b5a01515b340eda1292f5e08a3fe4633b745f80ad7a"}, + {file = "marisa_trie-1.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d62985a0e6f2cfeb36cd6afa0460063bbe83ef4bfd9afe189a99103487547210"}, + {file = "marisa_trie-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1890cc993149db4aa8242973526589e8133c3f92949b0ac74c2c9a6596707ae3"}, + {file = "marisa_trie-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26177cd0dadb7b44f47c17c40e16ac157c4d22ac7ed83b5a47f44713239e10d1"}, + {file = "marisa_trie-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3425dc81d49a374be49e3a063cb6ccdf57973201b0a30127082acea50562a85e"}, + {file = "marisa_trie-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:525b8df41a1a7337ed7f982eb63b704d7d75f047e30970fcfbe9cf6fc22c5991"}, + {file = "marisa_trie-1.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c643c66bbde6a115e4ec8713c087a9fe9cb7b7c684e6af4cf448c120fa427ea4"}, + {file = "marisa_trie-1.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5a83fe83e0eab9154a2dc7c556898c86584b7779ddf4214c606fce4ceff07c13"}, + {file = "marisa_trie-1.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:49701db6bb8f1ec0133abd95f0a4891cfd6f84f3bd019e343037e31a5a5b0210"}, + {file = "marisa_trie-1.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a3f0562863deaad58c5dc3a51f706da92582bc9084189148a45f7a12fe261a51"}, + {file = "marisa_trie-1.2.0-cp311-cp311-win32.whl", hash = "sha256:b08968ccad00f54f31e38516e4452fae59dd15a3fcee56aea3101ba2304680b3"}, + {file = "marisa_trie-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3ef375491e7dd71a0a7e7bf288c88750942bd1ee0c379dcd6ad43e31af67d00"}, + {file = "marisa_trie-1.2.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:39b88f126988ea83e8458259297d2b2f9391bfba8f4dc5d7a246813aae1c1def"}, + {file = "marisa_trie-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ec167b006884a90d130ee30518a9aa44cb40211f702bf07031b2d7d4d1db569b"}, + {file = "marisa_trie-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1b855e6286faef5411386bf9d676dfb545c09f7d109f197f347c9366aeb12f07"}, + {file = "marisa_trie-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cd287ff323224d87c2b739cba39614aac3737c95a254e0ff70e77d9b8df226d"}, + {file = "marisa_trie-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d8a1c0361165231f4fb915237470afc8cc4803c535f535f4fc42ca72855b124"}, + {file = "marisa_trie-1.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3267f438d258d7d85ee3dde363c4f96c3196ca9cd9e63fe429a59543cc544b15"}, + {file = "marisa_trie-1.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c87a0c2cccce12b07bfcb70708637c0816970282d966a1531ecda1a24bd1cc8"}, + {file = "marisa_trie-1.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d3c0e38f0501951e2322f7274a39b8e2344bbd91ceaa9da439f46022570ddc9d"}, + {file = "marisa_trie-1.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cd88a338c87e6dc130b6cea7b697580c21f0c83a8a8b46671cfecbb713d3fe24"}, + {file = "marisa_trie-1.2.0-cp312-cp312-win32.whl", hash = "sha256:5cea60975184f03fbcff51339df0eb44d2abe106a1693983cc64415eb87b897b"}, + {file = "marisa_trie-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:b04a07b99b62b9bdf3eaf1d44571a3293ce249ce8971944e780c9c709593462f"}, + {file = "marisa_trie-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c11af35d9304de420b359741e12b885d04f11403697efcbbe8cb50f834261ebc"}, + {file = "marisa_trie-1.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2db8e74493c3bffb480c54afaa88890a39bf90063ff5b322acf64bf076e4b36e"}, + {file = "marisa_trie-1.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bcc6613bc873136dc62609b66aaa27363e2bd46c03fdab62d638f7cf69d5f82"}, + {file = "marisa_trie-1.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5cb731581effb3e05258f3ddc2a155475de74bb00f61eb280f991e13b48f783"}, + {file = "marisa_trie-1.2.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:eba1061bbeaeec4149282beab2ae163631606f119f549a10246b014e13f9047b"}, + {file = "marisa_trie-1.2.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:015594427360c6ad0fa94d51ee3d50fb83b0f7278996497fd2d69f877c3de9bd"}, + {file = "marisa_trie-1.2.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:36d65bcbf22a70cdd0202bd8608c2feecc58bdb9e5dd9a2f5a723b651fcab287"}, + {file = "marisa_trie-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:bc138625b383998f5cd0cbf6cd38d66d414f3786ae6d7b4e4a6fc970140ef4e9"}, + {file = "marisa_trie-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:27d270a64eb655754dfb4e352c60a084b16ab999b3a97a0cdc7dbecbca3c0e35"}, + {file = "marisa_trie-1.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fa1fa7f67d317a921315a65e266b9e156ce5a956076ec2b6dbf72d67c7df8216"}, + {file = "marisa_trie-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9dccef41d4af11a03558c1d101de58bd723b3039a5bc4e064250008c118037ec"}, + {file = "marisa_trie-1.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:873efd212dfef2b736ff2ff43e10b348c428d5dbac7b8cb8aa777004bc8c7b0e"}, + {file = "marisa_trie-1.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8af7a21ac2ba6dc23e4257fc3a40b3070e776275d3d0b5b2ef44473ad92caf3a"}, + {file = "marisa_trie-1.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7202ba0ca1db5245feaebbeb3d0c776b2da1fffb0abc3500dd505f679686aa1"}, + {file = "marisa_trie-1.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83d90be28c083323909d23ff8e9b4a2764b9e75520d1bae1a277e9fa7ca20d15"}, + {file = "marisa_trie-1.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:40e2a374026492ac84232897f1f1d8f92a4a1f8bcf3f0ded1f2b8b708d1acfff"}, + {file = "marisa_trie-1.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:7c6e6506bd24a5799b9b4b9cf1e8d6fa281f136396ba018a95d95d4d74715227"}, + {file = "marisa_trie-1.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:437bf6c0d7ba4cf17656a0e3bdd0b3c2c92c01fedfa670904177eef3116a4f45"}, + {file = "marisa_trie-1.2.0-cp38-cp38-win32.whl", hash = "sha256:6aeef7b364fb3b34dbba1cc57b79f1668fad0c3f039738d65a5b0d5ddce15f47"}, + {file = "marisa_trie-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:02f773e85cc566a24c0e0e28c744052db7691c4f13d02e4257bc657a49b9ab14"}, + {file = "marisa_trie-1.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ff705cb3b907bdeacb8c4b3bf0541691f52b101014d189a707ca41ebfacad59"}, + {file = "marisa_trie-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:006419c59866979188906babc42ae0918081c18cabc2bdabca027f68c081c127"}, + {file = "marisa_trie-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7196691681ecb8a12629fb6277c33bafdb27cf2b6c18c28bc48fa42a15eab8f"}, + {file = "marisa_trie-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eaf052c0a1f4531ee12fd4c637212e77ad2af8c3b38a0d3096622abd01a22212"}, + {file = "marisa_trie-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fb95f3ab95ba933f6a2fa2629185e9deb9da45ff2aa4ba8cc8f722528c038ef"}, + {file = "marisa_trie-1.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7459b1e1937e33daed65a6d55f8b95f9a8601f4f8749d01641cf548ecac03840"}, + {file = "marisa_trie-1.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:902ea948677421093651ca98df62d255383f865f7c353f956ef666e92500e79f"}, + {file = "marisa_trie-1.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fdf7a2d066907816726f3bf241b8cb05b698d6ffaa3c5ea2658d4ba69e87ec57"}, + {file = "marisa_trie-1.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3540bb85b38dfc17060263e061c95a0a435681b04543d1ae7e8d7441a9790593"}, + {file = "marisa_trie-1.2.0-cp39-cp39-win32.whl", hash = "sha256:fe1394e1f262e5b45d22d30bd1ef75174d1f2772e86716b5f93f9c29dfc1a779"}, + {file = "marisa_trie-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:84c44cb13803723f0f76aa2ba1a657f762a0bb9d8a9b80dfff249bb1c3218dd6"}, + {file = "marisa_trie-1.2.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:035c4c8f3b313b4d7b7451ddd539da811a11077a9e359c6a0345f816b1bdccb3"}, + {file = "marisa_trie-1.2.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d4f05c2ee218a5ab09d269b640d06f9708b0cf37c842344cbdffb0661c74c472"}, + {file = "marisa_trie-1.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92ac63e1519598de946c7d9346df3bb52ed96968eb3021b4e89b51d79bc72a86"}, + {file = "marisa_trie-1.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:045f32eaeb5dcdb5beadb571ba616d7a34141764b616eebb4decce71b366f5fa"}, + {file = "marisa_trie-1.2.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb60c2f9897ce2bfc31a69ac25a040de4f8643ab2a339bb0ff1185e1a9dedaf8"}, + {file = "marisa_trie-1.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f19c5fcf23c02f1303deb69c67603ee37ed8f01de2d8b19f1716a6cf5afd5455"}, + {file = "marisa_trie-1.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a06a77075240eb83a47b780902322e66c968a06a2b6318cab06757c65ea64190"}, + {file = "marisa_trie-1.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:125016400449e46ec0e5fabd14c8314959c4dfa02ffc2861195c99efa2b5b011"}, + {file = "marisa_trie-1.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c57647dd9f9ba16fc5bb4679c915d7d48d5c0b25134fb10f095ccd839686a027"}, + {file = "marisa_trie-1.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6601e74338fb31e1b20674257706150113463182a01d3a1310df6b8840720b17"}, + {file = "marisa_trie-1.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ce2f68e1000c4c72820c5b2c9d037f326fcf75f036453a5e629f225f99b92cfc"}, + {file = "marisa_trie-1.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:069ac10a133d96b3f3ed1cc071b973a3f28490345e7941c778a1d81cf176f04a"}, + {file = "marisa_trie-1.2.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:de9911480ce2a0513582cb84ee4484e5ee8791e692276c7f5cd7378e114d1988"}, + {file = "marisa_trie-1.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cfec001cf233e8853a29e1c2bb74031c217aa61e7bd19389007e04861855731"}, + {file = "marisa_trie-1.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd1f3ef8de89684fbdd6aaead09d53b82e718bad4375d2beb938cbd24b48c51a"}, + {file = "marisa_trie-1.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65f5d8c1ecc85283b5b03a1475a5da723b94b3beda752c895b2f748477d8f1b1"}, + {file = "marisa_trie-1.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2e7540f844c1de493a90ad7d0f5bffc6a2cba19fe312d6db7b97aceff11d97f8"}, + {file = "marisa_trie-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2fb9243f66563285677079c9dccc697d35985287bacb36c8e685305687b0e025"}, + {file = "marisa_trie-1.2.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:58e2b84cbb6394f9c567f1f4351fc2995a094e1b684da9b577d4139b145401d6"}, + {file = "marisa_trie-1.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b4a8d3ed1f1b8f551b52e11a1265eaf0718f06bb206654b2c529cecda0913dd"}, + {file = "marisa_trie-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97652c5fbc92f52100afe1c4583625015611000fa81606ad17f1b3bbb9f3bfa"}, + {file = "marisa_trie-1.2.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7183d84da20c89b2a366bf581f0d79d1e248909678f164e8536f291120432e8"}, + {file = "marisa_trie-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c7f4df4163202b0aa5dad3eeddf088ecb61e9101986c8b31f1e052ebd6df9292"}, + {file = "marisa_trie-1.2.0.tar.gz", hash = "sha256:fedfc67497f8aa2757756b5cf493759f245d321fb78914ce125b6d75daa89b5f"}, +] + +[package.dependencies] +setuptools = "*" + +[package.extras] +test = ["hypothesis", "pytest", "readme-renderer"] + [[package]] name = "markdown-it-py" version = "3.0.0" @@ -1311,6 +1520,84 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] +[[package]] +name = "maxminddb" +version = "2.6.2" +description = "Reader for the MaxMind DB format" +optional = false +python-versions = ">=3.8" +files = [ + {file = "maxminddb-2.6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cfdf5c29a2739610700b9fea7f8d68ce81dcf30bb8016f1a1853ef889a2624b"}, + {file = "maxminddb-2.6.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:05e873eb82281cef6e787bd40bd1d58b2e496a21b3689346f0d0420988b3cbb1"}, + {file = "maxminddb-2.6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2b85ffc9fb2e192321c2f0b34d0b291b8e82de6e51a6ec7534645663678e835"}, + {file = "maxminddb-2.6.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28a2eaf9769262c05c486e777016771f3367c843b053c43cd5fde1108755753d"}, + {file = "maxminddb-2.6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96a1fa38322bce1d587bb6ce39a0e6ca4c1b824f48fbc5739a5ec507f63aa889"}, + {file = "maxminddb-2.6.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:eb534333f5fd7180e35c0207b3d95d621e4b9be3b8c1709995d0feb6c752b6f4"}, + {file = "maxminddb-2.6.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b281c0eec3601dde1f169a1c04e2615751c66368141aded9f03131fe635450b"}, + {file = "maxminddb-2.6.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a771df92e599ad867c16ae4acb08cc3763c9d1028f4ca772c0571da97f7f86d2"}, + {file = "maxminddb-2.6.2-cp310-cp310-win32.whl", hash = "sha256:f412a54f87ef9083911c334267188d3d1b14f2591eac94b94ca32528f21d5f25"}, + {file = "maxminddb-2.6.2-cp310-cp310-win_amd64.whl", hash = "sha256:7e5a90a1cb0c7fd6226aa44e18a87b26fa85b6eebae36d529d7582f93e8dfbd1"}, + {file = "maxminddb-2.6.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:38941a38278491bf95e5ca544969782c7ab33326802f6a93816867289c3f6401"}, + {file = "maxminddb-2.6.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eef1c26210155c7b94c4ca28fef65eb44a5ca1584427b1fbdeec1cd3c81e25c5"}, + {file = "maxminddb-2.6.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4d9cd7ddd02ee123a44d0d7821166d31540ea85352deb06b29d55e802f32781"}, + {file = "maxminddb-2.6.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8101291e5b92bd272a050c25822a5e30860d453dde16b4fffed9d751f0483a82"}, + {file = "maxminddb-2.6.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5c7c520d06d335b288d06a00b786cea9b7e023bd588efb1a6ef485e94ccc7244"}, + {file = "maxminddb-2.6.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:58bfd2c55c96aaaa7c4996c704edabfb1bd369dfc1592cedf8957a24062178b1"}, + {file = "maxminddb-2.6.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:886af3ba4aa26214ff39214565f53152b62a5abdb6ef9e00c76c194dbfd79231"}, + {file = "maxminddb-2.6.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:93691c8b4b4c448babb37bedc6f3d51523a3f06ab11bdd171da7ffc4005a7897"}, + {file = "maxminddb-2.6.2-cp311-cp311-win32.whl", hash = "sha256:e9013076deca5d136c260510cd05e82ec2b4ddb9476d63e2180a13ddfd305c3e"}, + {file = "maxminddb-2.6.2-cp311-cp311-win_amd64.whl", hash = "sha256:47170ec0e1e76787cc5882301c487f495d67f3146318f2f4e2adc281951a96ef"}, + {file = "maxminddb-2.6.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:eacd65e38bdf4efdf42bbc15cfa734b09eb818ecfef76b7b36e64be382be4c83"}, + {file = "maxminddb-2.6.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:20662878bc9514e90b0b4c4eb1a76622ecc7504d012e76bad9cdb7372fc0ef96"}, + {file = "maxminddb-2.6.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7607e45f7eca991fa34d57c03a791a1dfbe774ddd9250d0f35cdcc6f17142a15"}, + {file = "maxminddb-2.6.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0970b661c4fac6624b9128057ed5fe35a2d95aa60359272289cd4c7207c9a6d"}, + {file = "maxminddb-2.6.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12207f0becf3f2bf14e7a4bf86efcaa6e90d665a918915ae228c4e77792d7151"}, + {file = "maxminddb-2.6.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:826a1858b93b193df7fa71e3caca65c3051db20545df0020444f55c02e8ed2c3"}, + {file = "maxminddb-2.6.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e63649a82926f1d93acdd3df5f7be66dc9473653350afe73f365bb25e5b34368"}, + {file = "maxminddb-2.6.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ebf9fdf8a8e55862aabb8b2c34a4af31a8a5b686007288eeb561fa20ef348378"}, + {file = "maxminddb-2.6.2-cp312-cp312-win32.whl", hash = "sha256:2aaefb62f881151960bb67e5aeb302c159a32bd2d623cf72dad688bda1020869"}, + {file = "maxminddb-2.6.2-cp312-cp312-win_amd64.whl", hash = "sha256:78c3aa70c62be68ace23f819e7f23258545f2bfbd92cd6c33ee398cd261f6b84"}, + {file = "maxminddb-2.6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e1e40449bd278fdca1f351df442f391e72fd3d98b054ccac1672f27d70210642"}, + {file = "maxminddb-2.6.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:80d7f943f6b8bc437eaae5da778a83d8f38e4b7463756fdee04833e1be0bdea2"}, + {file = "maxminddb-2.6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:058ca89789bc1770fe58d02a88272ca91dabeef9f3fe0011fe506484355f1804"}, + {file = "maxminddb-2.6.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80d20683afe01b4d41bad1c1829f87ab12f3d19c68ec230f83318a2fd13871a7"}, + {file = "maxminddb-2.6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd90c3798e6c347d48d5d9a9c95dc678b52a5a965f1fb72152067fdf52b994da"}, + {file = "maxminddb-2.6.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:add1e55620033516c5f0734b1d9d03848859192d9f3825aabe720dfa8a783958"}, + {file = "maxminddb-2.6.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:8cb992da535264177b380e7b81943c884d57dcbfad6b3335d7f633967144746e"}, + {file = "maxminddb-2.6.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:86048ff328793599e584bcc2fc8278c2b7c5d3a4005c70403613449ec93817ef"}, + {file = "maxminddb-2.6.2-cp38-cp38-win32.whl", hash = "sha256:f2e326a99eaa924ff2fb09d6e44127983a43016228e7780888f15e9ba171d7b3"}, + {file = "maxminddb-2.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a2671e8f4161130803cf226cd9cb8b93ec5c4b2493f83a902986177052d95d3"}, + {file = "maxminddb-2.6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6a50bc348c699d8f6a5f0aa35e5096515d642ca2f38b944bd71c3dedda3d3588"}, + {file = "maxminddb-2.6.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc9f1203eb2b139252aa08965960fe13c36cc8b80b536490b94b05c31aa1fca9"}, + {file = "maxminddb-2.6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ccca5327cb4e706f669456ec6d556badfa92c0fdacd57a15076f3cdc061560"}, + {file = "maxminddb-2.6.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3987e103396e925edebbef4877e94515822f63b3b436027a0b164b500622fccd"}, + {file = "maxminddb-2.6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b31ecf3083b78c77624783bfdf6177e6ac73ae14684ef182855eb5569bc78e7c"}, + {file = "maxminddb-2.6.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:cd4530b9604d66cfa5e37eb94c671e54feff87769f8ba7fa997cce959e0cb241"}, + {file = "maxminddb-2.6.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ecce0b2d125691e2311f94dbd564c2d61c36c5033d082919431a21e6c694fa3f"}, + {file = "maxminddb-2.6.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:34b6e8d667d724f60d52635f3d959f793ab4e5d57d78b27fe66f02752d8c6b08"}, + {file = "maxminddb-2.6.2-cp39-cp39-win32.whl", hash = "sha256:d15414d251513748cb646d284a2829a5f4c69d8c90963a6e6da53a1a6d0accf7"}, + {file = "maxminddb-2.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c1220838ba9b0bcdaa0c5846f9da70a2304df2ac255fe518370f8faf8c18316"}, + {file = "maxminddb-2.6.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:39eab93ddd75fd02f8d5ad6b1bd3f8d894828d91d6f6c1a96bb9e87c34e94aaa"}, + {file = "maxminddb-2.6.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa8cb54b01a29a23a0ea6659fbb38deec6f35453588c5decdbf8669feb53b624"}, + {file = "maxminddb-2.6.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c096dfd20926c4de7d7fd5b5e75c756eddd4bdac5ab7aafd4bb67d000b13743"}, + {file = "maxminddb-2.6.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dc2b511c7255f7cbbb01e8ba01ba82e62e9c1213e382d36f9d9b0ee45c2f6b2"}, + {file = "maxminddb-2.6.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80d7495565d30260c630afbe74d61522b13dd31ed05b8916003ec5b127109a12"}, + {file = "maxminddb-2.6.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9dccd7a438f81e3df84dfc31a75af4c8d29adefb6082329385bfde604c9ea01b"}, + {file = "maxminddb-2.6.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b0a3b9cab1a94cc633df3da85c6567f0188f10165e3338ec9a6c421de9fe53b9"}, + {file = "maxminddb-2.6.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fb38aa94e76a87785b654c035f9f3ee39b74a98e9beea9a10b1aa62abdcc4cbd"}, + {file = "maxminddb-2.6.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9e9e893f7c0fa44cfdd5ab819a07d93f63ee398c28b792cedd50b94dcfea7c0"}, + {file = "maxminddb-2.6.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28af9470f28fce2ccb945478235f53fb52d98a505653b1bf4028e34df6149a06"}, + {file = "maxminddb-2.6.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a74b60cdc61a69b967ec44201c6259fbc48ef2eab2e885fbdc50ec1accaad545"}, + {file = "maxminddb-2.6.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:485c0778f6801e1437c2efd6e3b964a7ae71c8819f063e0b5460c3267d977040"}, + {file = "maxminddb-2.6.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0b480a31589750da4e36d1ba04b77ee3ac3853ac7b94d63f337b9d4d0403043f"}, + {file = "maxminddb-2.6.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:85fc9406f42c1311ce8ea9f2c820db5d7ac687a39ab5d932708dc783607378ef"}, + {file = "maxminddb-2.6.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fd1a612110ff182a559d8010e7615e5d05ef9d2c234b5f7de124ee8fdf1ecb9"}, + {file = "maxminddb-2.6.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cd7f525eb2331cf05181c5ba562cc3edec3de4b41dbb18a5fee9ad24884b499"}, + {file = "maxminddb-2.6.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d32266792b349f5507b0369d3277d45318fcd346a16dcc98b484aadc208e4d74"}, + {file = "maxminddb-2.6.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5662386db91872d5505fde9e7bb0b9530b6aab7a6f3ece7df59a2b43a7b45d17"}, + {file = "maxminddb-2.6.2.tar.gz", hash = "sha256:7d842d32e2620abc894b7d79a5a1007a69df2c6cf279a06b94c9c3913f66f264"}, +] + [[package]] name = "mdurl" version = "0.1.2" @@ -1653,13 +1940,13 @@ files = [ [[package]] name = "packaging" -version = "23.2" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -1678,84 +1965,95 @@ pyasn1 = "*" [[package]] name = "pillow" -version = "10.3.0" +version = "10.4.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, - {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, - {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, - {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, - {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, - {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, - {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, - {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, - {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, - {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, - {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, - {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, - {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, - {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, - {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, - {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, - {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, + {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, + {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, + {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, + {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, + {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, + {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, + {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, + {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, + {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, + {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, + {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, + {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, + {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, + {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"}, + {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"}, + {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"}, + {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"}, + {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"}, + {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"}, + {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] @@ -1779,22 +2077,22 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "protobuf" -version = "4.25.3" +version = "4.25.4" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, - {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, - {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, - {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, - {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, - {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, - {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, - {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, - {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, - {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, - {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, + {file = "protobuf-4.25.4-cp310-abi3-win32.whl", hash = "sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4"}, + {file = "protobuf-4.25.4-cp310-abi3-win_amd64.whl", hash = "sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d"}, + {file = "protobuf-4.25.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b"}, + {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835"}, + {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040"}, + {file = "protobuf-4.25.4-cp38-cp38-win32.whl", hash = "sha256:7e372cbbda66a63ebca18f8ffaa6948455dfecc4e9c1029312f6c2edcd86c4e1"}, + {file = "protobuf-4.25.4-cp38-cp38-win_amd64.whl", hash = "sha256:051e97ce9fa6067a4546e75cb14f90cf0232dcb3e3d508c448b8d0e4265b61c1"}, + {file = "protobuf-4.25.4-cp39-cp39-win32.whl", hash = "sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca"}, + {file = "protobuf-4.25.4-cp39-cp39-win_amd64.whl", hash = "sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f"}, + {file = "protobuf-4.25.4-py3-none-any.whl", hash = "sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978"}, + {file = "protobuf-4.25.4.tar.gz", hash = "sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d"}, ] [[package]] @@ -1821,13 +2119,13 @@ files = [ [[package]] name = "pyasn1" -version = "0.5.1" +version = "0.6.0" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, - {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, + {file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"}, + {file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"}, ] [[package]] @@ -1846,13 +2144,13 @@ requests = "*" [[package]] name = "pycparser" -version = "2.21" +version = "2.22" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] [[package]] @@ -1980,13 +2278,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.3.4" +version = "2.4.0" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, - {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, + {file = "pydantic_settings-2.4.0-py3-none-any.whl", hash = "sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315"}, + {file = "pydantic_settings-2.4.0.tar.gz", hash = "sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88"}, ] [package.dependencies] @@ -1994,6 +2292,7 @@ pydantic = ">=2.7.0" python-dotenv = ">=0.21.0" [package.extras] +azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] toml = ["tomli (>=2.0.1)"] yaml = ["pyyaml (>=6.0.1)"] @@ -2013,17 +2312,16 @@ docs = ["matplotlib", "numpy", "numpydoc", "pillow", "sphinx", "sphinx-copybutto [[package]] name = "pygments" -version = "2.17.2" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] [[package]] @@ -2073,13 +2371,13 @@ tests = ["pyfakefs", "pytest", "sqlalchemy"] [[package]] name = "pytest" -version = "8.2.1" +version = "8.3.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, - {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, + {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, + {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, ] [package.dependencies] @@ -2087,7 +2385,7 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=1.5,<2.0" +pluggy = ">=1.5,<2" tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] @@ -2113,13 +2411,13 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "pytest-mock (>=3.12)"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -2204,13 +2502,13 @@ files = [ [[package]] name = "referencing" -version = "0.33.0" +version = "0.35.1" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" files = [ - {file = "referencing-0.33.0-py3-none-any.whl", hash = "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5"}, - {file = "referencing-0.33.0.tar.gz", hash = "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7"}, + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, ] [package.dependencies] @@ -2240,12 +2538,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-file" -version = "2.0.0" +version = "2.1.0" description = "File transport adapter for Requests" optional = false python-versions = "*" files = [ - {file = "requests-file-2.0.0.tar.gz", hash = "sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972"}, + {file = "requests_file-2.1.0-py2.py3-none-any.whl", hash = "sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c"}, + {file = "requests_file-2.1.0.tar.gz", hash = "sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658"}, ] [package.dependencies] @@ -2253,13 +2552,13 @@ requests = ">=1.0.0" [[package]] name = "rich" -version = "13.7.0" +version = "13.7.1" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, - {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, ] [package.dependencies] @@ -2271,110 +2570,114 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "rpds-py" -version = "0.18.0" +version = "0.20.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.18.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e"}, - {file = "rpds_py-0.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434"}, - {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3"}, - {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e"}, - {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88"}, - {file = "rpds_py-0.18.0-cp310-none-win32.whl", hash = "sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337"}, - {file = "rpds_py-0.18.0-cp310-none-win_amd64.whl", hash = "sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66"}, - {file = "rpds_py-0.18.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4"}, - {file = "rpds_py-0.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6"}, - {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688"}, - {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b"}, - {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836"}, - {file = "rpds_py-0.18.0-cp311-none-win32.whl", hash = "sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1"}, - {file = "rpds_py-0.18.0-cp311-none-win_amd64.whl", hash = "sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa"}, - {file = "rpds_py-0.18.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0"}, - {file = "rpds_py-0.18.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157"}, - {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496"}, - {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f"}, - {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7"}, - {file = "rpds_py-0.18.0-cp312-none-win32.whl", hash = "sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98"}, - {file = "rpds_py-0.18.0-cp312-none-win_amd64.whl", hash = "sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec"}, - {file = "rpds_py-0.18.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e"}, - {file = "rpds_py-0.18.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c"}, - {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f"}, - {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c"}, - {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594"}, - {file = "rpds_py-0.18.0-cp38-none-win32.whl", hash = "sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e"}, - {file = "rpds_py-0.18.0-cp38-none-win_amd64.whl", hash = "sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1"}, - {file = "rpds_py-0.18.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33"}, - {file = "rpds_py-0.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f"}, - {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e"}, - {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024"}, - {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20"}, - {file = "rpds_py-0.18.0-cp39-none-win32.whl", hash = "sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7"}, - {file = "rpds_py-0.18.0-cp39-none-win_amd64.whl", hash = "sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f"}, - {file = "rpds_py-0.18.0.tar.gz", hash = "sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d"}, + {file = "rpds_py-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2"}, + {file = "rpds_py-0.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf"}, + {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140"}, + {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f"}, + {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce"}, + {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94"}, + {file = "rpds_py-0.20.0-cp310-none-win32.whl", hash = "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee"}, + {file = "rpds_py-0.20.0-cp310-none-win_amd64.whl", hash = "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399"}, + {file = "rpds_py-0.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489"}, + {file = "rpds_py-0.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209"}, + {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3"}, + {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272"}, + {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad"}, + {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58"}, + {file = "rpds_py-0.20.0-cp311-none-win32.whl", hash = "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0"}, + {file = "rpds_py-0.20.0-cp311-none-win_amd64.whl", hash = "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c"}, + {file = "rpds_py-0.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6"}, + {file = "rpds_py-0.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4"}, + {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef"}, + {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821"}, + {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940"}, + {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174"}, + {file = "rpds_py-0.20.0-cp312-none-win32.whl", hash = "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139"}, + {file = "rpds_py-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585"}, + {file = "rpds_py-0.20.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29"}, + {file = "rpds_py-0.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879"}, + {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f"}, + {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c"}, + {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2"}, + {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57"}, + {file = "rpds_py-0.20.0-cp313-none-win32.whl", hash = "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a"}, + {file = "rpds_py-0.20.0-cp313-none-win_amd64.whl", hash = "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2"}, + {file = "rpds_py-0.20.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24"}, + {file = "rpds_py-0.20.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751"}, + {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8"}, + {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e"}, + {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253"}, + {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a"}, + {file = "rpds_py-0.20.0-cp38-none-win32.whl", hash = "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5"}, + {file = "rpds_py-0.20.0-cp38-none-win_amd64.whl", hash = "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232"}, + {file = "rpds_py-0.20.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22"}, + {file = "rpds_py-0.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda"}, + {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580"}, + {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b"}, + {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420"}, + {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b"}, + {file = "rpds_py-0.20.0-cp39-none-win32.whl", hash = "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7"}, + {file = "rpds_py-0.20.0-cp39-none-win_amd64.whl", hash = "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344"}, + {file = "rpds_py-0.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec"}, + {file = "rpds_py-0.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8"}, + {file = "rpds_py-0.20.0.tar.gz", hash = "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121"}, ] [[package]] @@ -2396,19 +2699,19 @@ requests = "*" [[package]] name = "setuptools" -version = "71.0.3" +version = "72.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-71.0.3-py3-none-any.whl", hash = "sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207"}, - {file = "setuptools-71.0.3.tar.gz", hash = "sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d"}, + {file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"}, + {file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"}, ] [package.extras] core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (<7.4)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "shodan" @@ -2440,13 +2743,13 @@ files = [ [[package]] name = "sniffio" -version = "1.3.0" +version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] [[package]] @@ -2462,36 +2765,55 @@ files = [ [[package]] name = "sqlalchemy" -version = "1.4.51" +version = "1.4.53" description = "Database Abstraction Library" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2be4e6294c53f2ec8ea36486b56390e3bcaa052bf3a9a47005687ccf376745d1"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca484ca11c65e05639ffe80f20d45e6be81fbec7683d6c9a15cd421e6e8b340"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0535d5b57d014d06ceeaeffd816bb3a6e2dddeb670222570b8c4953e2d2ea678"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af55cc207865d641a57f7044e98b08b09220da3d1b13a46f26487cc2f898a072"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7deeae5071930abb3669b5185abb6c33ddfd2398f87660fafdb9e6a5fb0f3f2f"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0892e7ac8bc76da499ad3ee8de8da4d7905a3110b952e2a35a940dab1ffa550e"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cacc0b2dd7d22a918a9642fc89840a5d3cee18a0e1fe41080b1141b23b10916"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:245c67c88e63f1523e9216cad6ba3107dea2d3ee19adc359597a628afcabfbcb"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ec7a0ed9b32afdf337172678a4a0e6419775ba4e649b66f49415615fa47efbd"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352df882088a55293f621328ec33b6ffca936ad7f23013b22520542e1ab6ad1b"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:86a22143a4001f53bf58027b044da1fb10d67b62a785fc1390b5c7f089d9838c"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c37bc677690fd33932182b85d37433845de612962ed080c3e4d92f758d1bd894"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c55040d8ea65414de7c47f1a23823cd9f3fad0dc93e6b6b728fee81230f817b"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ef80328e3fee2be0a1abe3fe9445d3a2e52a1282ba342d0dab6edf1fef4707"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f8cafa6f885a0ff5e39efa9325195217bb47d5929ab0051636610d24aef45ade"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8f2df79a46e130235bc5e1bbef4de0583fb19d481eaa0bffa76e8347ea45ec6"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb18549b770351b54e1ab5da37d22bc530b8bfe2ee31e22b9ebe650640d2ef12"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55e699466106d09f028ab78d3c2e1f621b5ef2c8694598242259e4515715da7c"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2ad16880ccd971ac8e570550fbdef1385e094b022d6fc85ef3ce7df400dddad3"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b97fd5bb6b7c1a64b7ac0632f7ce389b8ab362e7bd5f60654c2a418496be5d7f"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e646b19f47d655261b22df9976e572f588185279970efba3d45c377127d35349"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3cf56cc36d42908495760b223ca9c2c0f9f0002b4eddc994b24db5fcb86a9e4"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0d661cff58c91726c601cc0ee626bf167b20cc4d7941c93c5f3ac28dc34ddbea"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3823dda635988e6744d4417e13f2e2b5fe76c4bf29dd67e95f98717e1b094cad"}, - {file = "SQLAlchemy-1.4.51.tar.gz", hash = "sha256:e7908c2025eb18394e32d65dd02d2e37e17d733cdbe7d78231c2b6d7eb20cdb9"}, + {file = "SQLAlchemy-1.4.53-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:b61ac5457d91b5629a3dea2b258deb4cdd35ac8f6fa2031d2b9b2fff5b3396da"}, + {file = "SQLAlchemy-1.4.53-cp310-cp310-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a96aa8d425047551676b0e178ddb0683421e78eda879ab55775128b2e612cae"}, + {file = "SQLAlchemy-1.4.53-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e10ac36f0b994235c13388b39598bf27219ec8bdea5be99bdac612b01cbe525"}, + {file = "SQLAlchemy-1.4.53-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:437592b341a3229dd0443c9c803b0bf0a466f8f539014fef6cdb9c06b7edb7f9"}, + {file = "SQLAlchemy-1.4.53-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:784272ceb5eb71421fea9568749bcbe8bd019261a0e2e710a7efa76057af2499"}, + {file = "SQLAlchemy-1.4.53-cp310-cp310-win32.whl", hash = "sha256:122d7b5722df1a24402c6748bbb04687ef981493bb559d0cc0beffe722e0e6ed"}, + {file = "SQLAlchemy-1.4.53-cp310-cp310-win_amd64.whl", hash = "sha256:4604d42b2abccba266d3f5bbe883684b5df93e74054024c70d3fbb5eea45e530"}, + {file = "SQLAlchemy-1.4.53-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fb8e15dfa47f5de11ab073e12aadd6b502cfb7ac4bafd18bd18cfd1c7d13dbbc"}, + {file = "SQLAlchemy-1.4.53-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8be4df55e8fde3006d9cb1f6b3df2ba26db613855dc4df2c0fcd5ec15cb3b7"}, + {file = "SQLAlchemy-1.4.53-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b11640251f9a9789fd96cd6e5d176b1c230230c70ad40299bcbcc568451b4c"}, + {file = "SQLAlchemy-1.4.53-cp311-cp311-win32.whl", hash = "sha256:cd534c716f86bdf95b7b984a34ee278c91d1b1d7d183e7e5ff878600b1696046"}, + {file = "SQLAlchemy-1.4.53-cp311-cp311-win_amd64.whl", hash = "sha256:6dd06572872ca13ef5a90306a3e5af787498ddaa17fb00109b1243642646cd69"}, + {file = "SQLAlchemy-1.4.53-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2774c24c405136c3ef472e2352bdca7330659d481fbf2283f996c0ef9eb90f22"}, + {file = "SQLAlchemy-1.4.53-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68a614765197b3d13a730d631a78c3bb9b3b72ba58ed7ab295d58d517464e315"}, + {file = "SQLAlchemy-1.4.53-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d13d4dfbc6e52363886b47cf02cf68c5d2a37c468626694dc210d7e97d4ad330"}, + {file = "SQLAlchemy-1.4.53-cp312-cp312-win32.whl", hash = "sha256:197065b91456574d70b6459bfa62bc0b52a4960a29ef923c375ec427274a3e05"}, + {file = "SQLAlchemy-1.4.53-cp312-cp312-win_amd64.whl", hash = "sha256:421306c4b936b0271a3ce2dc074928d5ece4a36f9c482daa5770f44ecfc3a883"}, + {file = "SQLAlchemy-1.4.53-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:13fc34b35d8ddb3fbe3f8fcfdf6c2546e676187f0fb20f5774da362ddaf8fa2d"}, + {file = "SQLAlchemy-1.4.53-cp36-cp36m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626be971ff89541cfd3e70b54be00b57a7f8557204decb6223ce0428fec058f3"}, + {file = "SQLAlchemy-1.4.53-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:991e42fdfec561ebc6a4fae7161a86d129d6069fa14210b96b8dd752afa7059c"}, + {file = "SQLAlchemy-1.4.53-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:95123f3a1e0e8020848fd32ba751db889a01a44e4e4fef7e58c87ddd0b2fca59"}, + {file = "SQLAlchemy-1.4.53-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c58e011e9e6373b3a091d83f20601fb335a3b4bace80bfcb914ac168aad3b70d"}, + {file = "SQLAlchemy-1.4.53-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:670c7769bf5dcae9aff331247b5d82fe635c63731088a46ce68ba2ba519ef36e"}, + {file = "SQLAlchemy-1.4.53-cp37-cp37m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07ba54f09033d387ae9df8d62cbe211ed7304e0bfbece1f8c55e21db9fae5c11"}, + {file = "SQLAlchemy-1.4.53-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a38834b4c183c33daf58544281395aad2e985f0b47cca1e88ea5ada88344e63"}, + {file = "SQLAlchemy-1.4.53-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:616492f5315128a847f293a7c552f3561ac7e996d2aa5dc46bef4fb0d3781f1d"}, + {file = "SQLAlchemy-1.4.53-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0cf8c0af9563892c6632f7343bc393dfce6eeef8e4d10c5fadba9c0390520bd"}, + {file = "SQLAlchemy-1.4.53-cp37-cp37m-win32.whl", hash = "sha256:c05fe05941424c2f3747a8952381b7725e24cba2ca00141380e54789d5b616b6"}, + {file = "SQLAlchemy-1.4.53-cp37-cp37m-win_amd64.whl", hash = "sha256:93e90aa3e3b2f8e8cbae4d5509f8e0cf82972378d323c740a8df1c1e9f484172"}, + {file = "SQLAlchemy-1.4.53-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:9d7368df54d3ed45a18955f6cec38ebe075290594ac0d5c87a8ddaff7e10de27"}, + {file = "SQLAlchemy-1.4.53-cp38-cp38-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89d8ac4158ef68eea8bb0f6dd0583127d9aa8720606964ba8eee20b254f9c83a"}, + {file = "SQLAlchemy-1.4.53-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16bb9fa4d00b4581b14d9f0e2224dc7745b854aa4687738279af0f48f7056c98"}, + {file = "SQLAlchemy-1.4.53-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4fe5168d0249c23f537950b6d75935ff2709365a113e29938a979aec36668ecf"}, + {file = "SQLAlchemy-1.4.53-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b8608d162d3bd29d807aab32c3fb6e2f8e225a43d1c54c917fed38513785380"}, + {file = "SQLAlchemy-1.4.53-cp38-cp38-win32.whl", hash = "sha256:a9d4d132198844bd6828047135ce7b887687c92925049a2468a605fc775c7a1a"}, + {file = "SQLAlchemy-1.4.53-cp38-cp38-win_amd64.whl", hash = "sha256:c15d1f1fcf1f9bec0499ae1d9132b950fcc7730f2d26d10484c8808b4e077816"}, + {file = "SQLAlchemy-1.4.53-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:edf094a20a386ff2ec73de65ef18014b250259cb860edc61741e240ca22d6981"}, + {file = "SQLAlchemy-1.4.53-cp39-cp39-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83a9c3514ff19d9d30d8a8d378b24cd1dfa5528d20891481cb5f196117db6a48"}, + {file = "SQLAlchemy-1.4.53-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eaaeedbceb4dfd688fff2faf25a9a87a391f548811494f7bff7fa701b639abc3"}, + {file = "SQLAlchemy-1.4.53-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d021699b9007deb7aa715629078830c99a5fec2753d9bdd5ff33290d363ef755"}, + {file = "SQLAlchemy-1.4.53-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0465b8a68f8f4de754c1966c45b187ac784ad97bc9747736f913130f0e1adea0"}, + {file = "SQLAlchemy-1.4.53-cp39-cp39-win32.whl", hash = "sha256:5f67b9e9dcac3241781e96575468d55a42332157dee04bdbf781df573dff5f85"}, + {file = "SQLAlchemy-1.4.53-cp39-cp39-win_amd64.whl", hash = "sha256:a8c2f2a0b2c4e3b86eb58c9b6bb98548205eea2fba9dae4edfd29dc6aebbe95a"}, + {file = "SQLAlchemy-1.4.53.tar.gz", hash = "sha256:5e6ab710c4c064755fd92d1a417bef360228a19bdf0eee32b03aa0f5f8e9fe0d"}, ] [package.dependencies] @@ -2502,17 +2824,17 @@ aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)", "mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] -mssql-pymssql = ["pymssql"] -mssql-pyodbc = ["pyodbc"] +mssql-pymssql = ["pymssql", "pymssql"] +mssql-pyodbc = ["pyodbc", "pyodbc"] mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] -mysql-connector = ["mysql-connector-python"] +mysql-connector = ["mysql-connector-python", "mysql-connector-python"] oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] +postgresql-asyncpg = ["asyncpg", "asyncpg", "greenlet (!=0.4.17)", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)", "pg8000 (>=1.16.6,!=1.29.0)"] postgresql-psycopg2binary = ["psycopg2-binary"] postgresql-psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql", "pymysql (<1)"] @@ -2868,4 +3190,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "3952e6eeb2307fcd6ac25bb54625a4e5cf47ac363bfbae0a1825859072eb9c95" +content-hash = "5065bdc0a65dda4d1d607f6f6fa30f8f3a0bfd6ce11afdc410f044c10d7720e3" diff --git a/boefjes/pyproject.toml b/boefjes/pyproject.toml index 0b21d41aa68..31c11e2cf98 100644 --- a/boefjes/pyproject.toml +++ b/boefjes/pyproject.toml @@ -71,6 +71,8 @@ opentelemetry-semantic-conventions = "^0.47b0" opentelemetry-util-http = "^0.47b0" fastapi-slim = "^0.111.0" structlog = "^24.2.0" +# required by kat_maxmind_geoip +maxminddb = "^2.6.2" [tool.poetry.group.dev.dependencies] pytest = "^8.2.0" diff --git a/boefjes/requirements-dev.txt b/boefjes/requirements-dev.txt index 2b1f8edfb5f..bdaacd0c071 100644 --- a/boefjes/requirements-dev.txt +++ b/boefjes/requirements-dev.txt @@ -1,107 +1,110 @@ -aiohttp==3.9.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8 \ - --hash=sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c \ - --hash=sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475 \ - --hash=sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed \ - --hash=sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf \ - --hash=sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372 \ - --hash=sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81 \ - --hash=sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f \ - --hash=sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1 \ - --hash=sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd \ - --hash=sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a \ - --hash=sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb \ - --hash=sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46 \ - --hash=sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de \ - --hash=sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78 \ - --hash=sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c \ - --hash=sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771 \ - --hash=sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb \ - --hash=sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430 \ - --hash=sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233 \ - --hash=sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156 \ - --hash=sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9 \ - --hash=sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59 \ - --hash=sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888 \ - --hash=sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c \ - --hash=sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c \ - --hash=sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da \ - --hash=sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424 \ - --hash=sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2 \ - --hash=sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb \ - --hash=sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8 \ - --hash=sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a \ - --hash=sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10 \ - --hash=sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0 \ - --hash=sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09 \ - --hash=sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031 \ - --hash=sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4 \ - --hash=sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3 \ - --hash=sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa \ - --hash=sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a \ - --hash=sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe \ - --hash=sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a \ - --hash=sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2 \ - --hash=sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1 \ - --hash=sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323 \ - --hash=sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b \ - --hash=sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b \ - --hash=sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106 \ - --hash=sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac \ - --hash=sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6 \ - --hash=sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832 \ - --hash=sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75 \ - --hash=sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6 \ - --hash=sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d \ - --hash=sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72 \ - --hash=sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db \ - --hash=sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a \ - --hash=sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da \ - --hash=sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678 \ - --hash=sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b \ - --hash=sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24 \ - --hash=sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed \ - --hash=sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f \ - --hash=sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e \ - --hash=sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58 \ - --hash=sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a \ - --hash=sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342 \ - --hash=sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558 \ - --hash=sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2 \ - --hash=sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551 \ - --hash=sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595 \ - --hash=sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee \ - --hash=sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11 \ - --hash=sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d \ - --hash=sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7 \ - --hash=sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f +aiohappyeyeballs==2.3.5 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4d6dea59215537dbc746e93e779caea8178c866856a721c9c660d7a5a7b8be03 \ + --hash=sha256:6fa48b9f1317254f122a07a131a86b71ca6946ca989ce6326fff54a99a920105 +aiohttp==3.10.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01c3f1eb280008e51965a8d160a108c333136f4a39d46f516c64d2aa2e6a53f2 \ + --hash=sha256:028faf71b338f069077af6315ad54281612705d68889f5d914318cbc2aab0d50 \ + --hash=sha256:03c0c380c83f8a8d4416224aafb88d378376d6f4cadebb56b060688251055cd4 \ + --hash=sha256:0df51a3d70a2bfbb9c921619f68d6d02591f24f10e9c76de6f3388c89ed01de6 \ + --hash=sha256:120548d89f14b76a041088b582454d89389370632ee12bf39d919cc5c561d1ca \ + --hash=sha256:1988b370536eb14f0ce7f3a4a5b422ab64c4e255b3f5d7752c5f583dc8c967fc \ + --hash=sha256:1a07c76a82390506ca0eabf57c0540cf5a60c993c442928fe4928472c4c6e5e6 \ + --hash=sha256:1c2b104e81b3c3deba7e6f5bc1a9a0e9161c380530479970766a6655b8b77c7c \ + --hash=sha256:1c577cdcf8f92862363b3d598d971c6a84ed8f0bf824d4cc1ce70c2fb02acb4a \ + --hash=sha256:1f8605e573ed6c44ec689d94544b2c4bb1390aaa723a8b5a2cc0a5a485987a68 \ + --hash=sha256:21778552ef3d44aac3278cc6f6d13a6423504fa5f09f2df34bfe489ed9ded7f5 \ + --hash=sha256:2212296cdb63b092e295c3e4b4b442e7b7eb41e8a30d0f53c16d5962efed395d \ + --hash=sha256:222821c60b8f6a64c5908cb43d69c0ee978a1188f6a8433d4757d39231b42cdb \ + --hash=sha256:256ee6044214ee9d66d531bb374f065ee94e60667d6bbeaa25ca111fc3997158 \ + --hash=sha256:2a384dfbe8bfebd203b778a30a712886d147c61943675f4719b56725a8bbe803 \ + --hash=sha256:2fa643ca990323db68911b92f3f7a0ca9ae300ae340d0235de87c523601e58d9 \ + --hash=sha256:41d8dab8c64ded1edf117d2a64f353efa096c52b853ef461aebd49abae979f16 \ + --hash=sha256:440954ddc6b77257e67170d57b1026aa9545275c33312357472504eef7b4cc0b \ + --hash=sha256:47b4c2412960e64d97258f40616efddaebcb34ff664c8a972119ed38fac2a62c \ + --hash=sha256:4a9ce70f5e00380377aac0e568abd075266ff992be2e271765f7b35d228a990c \ + --hash=sha256:4dcb127ca3eb0a61205818a606393cbb60d93b7afb9accd2fd1e9081cc533144 \ + --hash=sha256:4e9e9171d2fe6bfd9d3838a6fe63b1e91b55e0bf726c16edf265536e4eafed19 \ + --hash=sha256:51d03e948e53b3639ce4d438f3d1d8202898ec6655cadcc09ec99229d4adc2a9 \ + --hash=sha256:54b7f4a20d7cc6bfa4438abbde069d417bb7a119f870975f78a2b99890226d55 \ + --hash=sha256:587237571a85716d6f71f60d103416c9df7d5acb55d96d3d3ced65f39bff9c0c \ + --hash=sha256:5951c328f9ac42d7bce7a6ded535879bc9ae13032818d036749631fa27777905 \ + --hash=sha256:5a95151a5567b3b00368e99e9c5334a919514f60888a6b6d2054fea5e66e527e \ + --hash=sha256:5c12310d153b27aa630750be44e79313acc4e864c421eb7d2bc6fa3429c41bf8 \ + --hash=sha256:5cd57ad998e3038aa87c38fe85c99ed728001bf5dde8eca121cadee06ee3f637 \ + --hash=sha256:615348fab1a9ef7d0960a905e83ad39051ae9cb0d2837da739b5d3a7671e497a \ + --hash=sha256:67f7639424c313125213954e93a6229d3a1d386855d70c292a12628f600c7150 \ + --hash=sha256:68164d43c580c2e8bf8e0eb4960142919d304052ccab92be10250a3a33b53268 \ + --hash=sha256:68cc24f707ed9cb961f6ee04020ca01de2c89b2811f3cf3361dc7c96a14bfbcc \ + --hash=sha256:6b14c19172eb53b63931d3e62a9749d6519f7c121149493e6eefca055fcdb352 \ + --hash=sha256:777e23609899cb230ad2642b4bdf1008890f84968be78de29099a8a86f10b261 \ + --hash=sha256:786299d719eb5d868f161aeec56d589396b053925b7e0ce36e983d30d0a3e55c \ + --hash=sha256:7ccf1f0a304352c891d124ac1a9dea59b14b2abed1704aaa7689fc90ef9c5be1 \ + --hash=sha256:88596384c3bec644a96ae46287bb646d6a23fa6014afe3799156aef42669c6bd \ + --hash=sha256:89b47c125ab07f0831803b88aeb12b04c564d5f07a1c1a225d4eb4d2f26e8b5e \ + --hash=sha256:8b0d058e4e425d3b45e8ec70d49b402f4d6b21041e674798b1f91ba027c73f28 \ + --hash=sha256:8c81ff4afffef9b1186639506d70ea90888218f5ddfff03870e74ec80bb59970 \ + --hash=sha256:8db9b749f589b5af8e4993623dbda6716b2b7a5fcb0fa2277bf3ce4b278c7059 \ + --hash=sha256:8e5a26d7aac4c0d8414a347da162696eea0629fdce939ada6aedf951abb1d745 \ + --hash=sha256:8fbf8c0ded367c5c8eaf585f85ca8dd85ff4d5b73fb8fe1e6ac9e1b5e62e11f7 \ + --hash=sha256:93094eba50bc2ad4c40ff4997ead1fdcd41536116f2e7d6cfec9596a8ecb3615 \ + --hash=sha256:9c186b270979fb1dee3ababe2d12fb243ed7da08b30abc83ebac3a928a4ddb15 \ + --hash=sha256:9cb54f5725b4b37af12edf6c9e834df59258c82c15a244daa521a065fbb11717 \ + --hash=sha256:9fbff00646cf8211b330690eb2fd64b23e1ce5b63a342436c1d1d6951d53d8dd \ + --hash=sha256:a57e73f9523e980f6101dc9a83adcd7ac0006ea8bf7937ca3870391c7bb4f8ff \ + --hash=sha256:a702bd3663b5cbf3916e84bf332400d24cdb18399f0877ca6b313ce6c08bfb43 \ + --hash=sha256:a77c79bac8d908d839d32c212aef2354d2246eb9deb3e2cb01ffa83fb7a6ea5d \ + --hash=sha256:abda4009a30d51d3f06f36bc7411a62b3e647fa6cc935ef667e3e3d3a7dd09b1 \ + --hash=sha256:b023b68c61ab0cd48bd38416b421464a62c381e32b9dc7b4bdfa2905807452a4 \ + --hash=sha256:b07286a1090483799599a2f72f76ac396993da31f6e08efedb59f40876c144fa \ + --hash=sha256:b0de63ff0307eac3961b4af74382d30220d4813f36b7aaaf57f063a1243b4214 \ + --hash=sha256:b7d5bb926805022508b7ddeaad957f1fce7a8d77532068d7bdb431056dc630cd \ + --hash=sha256:b9db600a86414a9a653e3c1c7f6a2f6a1894ab8f83d11505247bd1b90ad57157 \ + --hash=sha256:b9fb6508893dc31cfcbb8191ef35abd79751db1d6871b3e2caee83959b4d91eb \ + --hash=sha256:bc3ea6ef2a83edad84bbdb5d96e22f587b67c68922cd7b6f9d8f24865e655bcf \ + --hash=sha256:bde0693073fd5e542e46ea100aa6c1a5d36282dbdbad85b1c3365d5421490a92 \ + --hash=sha256:bf66149bb348d8e713f3a8e0b4f5b952094c2948c408e1cfef03b49e86745d60 \ + --hash=sha256:bfe33cba6e127d0b5b417623c9aa621f0a69f304742acdca929a9fdab4593693 \ + --hash=sha256:c8fb76214b5b739ce59e2236a6489d9dc3483649cfd6f563dbf5d8e40dbdd57d \ + --hash=sha256:cb8b79a65332e1a426ccb6290ce0409e1dc16b4daac1cc5761e059127fa3d134 \ + --hash=sha256:d6bbe2c90c10382ca96df33b56e2060404a4f0f88673e1e84b44c8952517e5f3 \ + --hash=sha256:d8311d0d690487359fe2247ec5d2cac9946e70d50dced8c01ce9e72341c21151 \ + --hash=sha256:d8a8221a63602008550022aa3a4152ca357e1dde7ab3dd1da7e1925050b56863 \ + --hash=sha256:de1a91d5faded9054957ed0a9e01b9d632109341942fc123947ced358c5d9009 \ + --hash=sha256:df31641e3f02b77eb3c5fb63c0508bee0fc067cf153da0e002ebbb0db0b6d91a \ + --hash=sha256:e7168782621be4448d90169a60c8b37e9b0926b3b79b6097bc180c0a8a119e73 \ + --hash=sha256:e7b55d9ede66af7feb6de87ff277e0ccf6d51c7db74cc39337fe3a0e31b5872d \ + --hash=sha256:e7dbf637f87dd315fa1f36aaed8afa929ee2c607454fb7791e74c88a0d94da59 \ + --hash=sha256:f5293726943bdcea24715b121d8c4ae12581441d22623b0e6ab12d07ce85f9c4 \ + --hash=sha256:f5dd109a925fee4c9ac3f6a094900461a2712df41745f5d04782ebcbe6479ccb \ + --hash=sha256:f6979b4f20d3e557a867da9d9227de4c156fcdcb348a5848e3e6190fd7feb972 \ + --hash=sha256:f9f8beed277488a52ee2b459b23c4135e54d6a819eaba2e120e57311015b58e9 aioresponses==0.7.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d2c26defbb9b440ea2685ec132e90700907fd10bcca3e85ec2f157219f0d26f7 \ --hash=sha256:f795d9dbda2d61774840e7e32f5366f45752d1adc1b74c9362afd017296c7ee1 aiosignal==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc \ --hash=sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17 -alembic==1.13.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43 \ - --hash=sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595 +alembic==1.13.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef \ + --hash=sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953 annotated-types==0.7.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \ --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89 ansicolors==1.1.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:00d2dde5a675579325902536738dd27e4fac1fd68f773fe36c21044eb559e187 \ --hash=sha256:99f94f5e3348a0bcd43c82e5fc4414013ccc19d70bd939ad71e0133ce9c372e0 -anyio==4.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8 \ - --hash=sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6 -asgiref==3.7.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \ - --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed +anyio==4.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94 \ + --hash=sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7 +asgiref==3.8.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \ + --hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590 async-timeout==4.0.3 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \ --hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028 -attrs==23.2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \ - --hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1 +attrs==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ + --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2 backoff==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba \ --hash=sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8 @@ -114,59 +117,74 @@ censys==2.1.8 ; python_version >= "3.10" and python_version < "4.0" \ certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 -cffi==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ - --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ - --hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \ - --hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \ - --hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \ - --hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \ - --hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \ - --hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \ - --hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \ - --hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \ - --hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \ - --hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \ - --hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \ - --hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \ - --hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \ - --hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \ - --hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \ - --hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \ - --hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \ - --hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \ - --hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \ - --hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \ - --hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \ - --hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \ - --hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \ - --hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \ - --hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \ - --hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \ - --hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \ - --hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \ - --hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \ - --hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \ - --hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \ - --hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \ - --hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \ - --hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \ - --hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \ - --hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \ - --hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \ - --hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \ - --hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \ - --hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \ - --hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \ - --hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \ - --hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \ - --hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \ - --hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \ - --hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \ - --hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \ - --hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \ - --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \ - --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357 +cffi==1.17.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f \ + --hash=sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab \ + --hash=sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499 \ + --hash=sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058 \ + --hash=sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693 \ + --hash=sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb \ + --hash=sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377 \ + --hash=sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885 \ + --hash=sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2 \ + --hash=sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401 \ + --hash=sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4 \ + --hash=sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b \ + --hash=sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59 \ + --hash=sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f \ + --hash=sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c \ + --hash=sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555 \ + --hash=sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa \ + --hash=sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424 \ + --hash=sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb \ + --hash=sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2 \ + --hash=sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8 \ + --hash=sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e \ + --hash=sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9 \ + --hash=sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82 \ + --hash=sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828 \ + --hash=sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759 \ + --hash=sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc \ + --hash=sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118 \ + --hash=sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf \ + --hash=sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932 \ + --hash=sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a \ + --hash=sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29 \ + --hash=sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206 \ + --hash=sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2 \ + --hash=sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c \ + --hash=sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c \ + --hash=sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0 \ + --hash=sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a \ + --hash=sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195 \ + --hash=sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6 \ + --hash=sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9 \ + --hash=sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc \ + --hash=sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb \ + --hash=sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0 \ + --hash=sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7 \ + --hash=sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb \ + --hash=sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a \ + --hash=sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492 \ + --hash=sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720 \ + --hash=sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42 \ + --hash=sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7 \ + --hash=sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d \ + --hash=sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d \ + --hash=sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb \ + --hash=sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4 \ + --hash=sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2 \ + --hash=sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b \ + --hash=sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8 \ + --hash=sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e \ + --hash=sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204 \ + --hash=sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3 \ + --hash=sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150 \ + --hash=sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4 \ + --hash=sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76 \ + --hash=sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e \ + --hash=sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb \ + --hash=sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91 charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ @@ -267,9 +285,9 @@ click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 -configparser==6.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:900ea2bb01b2540b1a644ad3d5351e9b961a4a012d4732f619375fb8f641ee19 \ - --hash=sha256:ec914ab1e56c672de1f5c3483964e68f71b34e457904b7b76e06b922aec067a8 +configparser==7.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:af3c618a67aaaedc4d689fd7317d238f566b9aa03cae50102e92d7f0dfe78ba0 \ + --hash=sha256:f46d52a12811c637104c6bb8eb33693be0038ab6bf01d69aae009c39ec8c2017 cryptography==42.0.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ @@ -318,15 +336,15 @@ dnspython==2.6.1 ; python_version >= "3.10" and python_version < "4.0" \ docker==7.1.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c \ --hash=sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0 -exceptiongroup==1.2.0 ; python_version >= "3.10" and python_version < "3.11" \ - --hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14 \ - --hash=sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68 +exceptiongroup==1.2.2 ; python_version >= "3.10" and python_version < "3.11" \ + --hash=sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b \ + --hash=sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d -filelock==3.13.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e \ - --hash=sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c +filelock==3.15.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb \ + --hash=sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7 forcediphttpsadapter==1.1.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0d224cf6e8e50eb788c9f5994a7afa6d389bac6dbe540b7dfd77a32590ad0153 \ --hash=sha256:5e7662ece61735585332d09b87d94fffe4752469d5c0d3feff48746e5d70744b @@ -408,9 +426,9 @@ frozenlist==1.4.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887 \ --hash=sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced \ --hash=sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74 -googleapis-common-protos==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07 \ - --hash=sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277 +googleapis-common-protos==1.63.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945 \ + --hash=sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87 greenlet==3.0.3 ; python_version >= "3.10" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "4.0" \ --hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \ --hash=sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6 \ @@ -470,61 +488,53 @@ greenlet==3.0.3 ; python_version >= "3.10" and (platform_machine == "aarch64" or --hash=sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf \ --hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \ --hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33 -grpcio==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701 \ - --hash=sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e \ - --hash=sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532 \ - --hash=sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a \ - --hash=sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271 \ - --hash=sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f \ - --hash=sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7 \ - --hash=sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b \ - --hash=sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4 \ - --hash=sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839 \ - --hash=sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6 \ - --hash=sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb \ - --hash=sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e \ - --hash=sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93 \ - --hash=sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f \ - --hash=sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6 \ - --hash=sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1 \ - --hash=sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35 \ - --hash=sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842 \ - --hash=sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6 \ - --hash=sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c \ - --hash=sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873 \ - --hash=sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7 \ - --hash=sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c \ - --hash=sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928 \ - --hash=sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9 \ - --hash=sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c \ - --hash=sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021 \ - --hash=sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa \ - --hash=sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38 \ - --hash=sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc \ - --hash=sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe \ - --hash=sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8 \ - --hash=sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402 \ - --hash=sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388 \ - --hash=sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0 \ - --hash=sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b \ - --hash=sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b \ - --hash=sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2 \ - --hash=sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b \ - --hash=sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5 \ - --hash=sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829 \ - --hash=sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2 \ - --hash=sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6 \ - --hash=sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd \ - --hash=sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0 \ - --hash=sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8 \ - --hash=sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334 \ - --hash=sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee \ - --hash=sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c \ - --hash=sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72 \ - --hash=sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4 \ - --hash=sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270 \ - --hash=sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170 +grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ + --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ + --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ + --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ + --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ + --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ + --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ + --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ + --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ + --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ + --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ + --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ + --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ + --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ + --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ + --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ + --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ + --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ + --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ + --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ + --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ + --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ + --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ + --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ + --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ + --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ + --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ + --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ + --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ + --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ + --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ + --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ + --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ + --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ + --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ + --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ + --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ + --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ + --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ + --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ + --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ + --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ + --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ + --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ + --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ + --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -539,103 +549,259 @@ httpx==0.27.0 ; python_version >= "3.10" and python_version < "4.0" \ idna==3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 -importlib-metadata==6.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1231cf92d825c9e03cfc4da076a16de6422c863558229ea0b22b675657463443 \ - --hash=sha256:f0afba6205ad8f8947c7d338b5342d5db2afbfd82f9cbef7879a9539cc12eb9b +importlib-metadata==8.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f \ + --hash=sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812 iniconfig==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \ --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 jsonschema-specifications==2023.12.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc \ --hash=sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c -jsonschema==4.21.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f \ - --hash=sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5 -langcodes==3.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4d89fc9acb6e9c8fdef70bcdf376113a3db09b67285d9e1d534de6d8818e7e69 \ - --hash=sha256:794d07d5a28781231ac335a1561b8442f8648ca07cd518310aeb45d6f0807ef6 -lxml==5.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:13521a321a25c641b9ea127ef478b580b5ec82aa2e9fc076c86169d161798b01 \ - --hash=sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f \ - --hash=sha256:16018f7099245157564d7148165132c70adb272fb5a17c048ba70d9cc542a1a1 \ - --hash=sha256:16dd953fb719f0ffc5bc067428fc9e88f599e15723a85618c45847c96f11f431 \ - --hash=sha256:19a1bc898ae9f06bccb7c3e1dfd73897ecbbd2c96afe9095a6026016e5ca97b8 \ - --hash=sha256:1ad17c20e3666c035db502c78b86e58ff6b5991906e55bdbef94977700c72623 \ - --hash=sha256:22b7ee4c35f374e2c20337a95502057964d7e35b996b1c667b5c65c567d2252a \ - --hash=sha256:24ef5a4631c0b6cceaf2dbca21687e29725b7c4e171f33a8f8ce23c12558ded1 \ - --hash=sha256:25663d6e99659544ee8fe1b89b1a8c0aaa5e34b103fab124b17fa958c4a324a6 \ - --hash=sha256:262bc5f512a66b527d026518507e78c2f9c2bd9eb5c8aeeb9f0eb43fcb69dc67 \ - --hash=sha256:280f3edf15c2a967d923bcfb1f8f15337ad36f93525828b40a0f9d6c2ad24890 \ - --hash=sha256:2ad3a8ce9e8a767131061a22cd28fdffa3cd2dc193f399ff7b81777f3520e372 \ - --hash=sha256:2befa20a13f1a75c751f47e00929fb3433d67eb9923c2c0b364de449121f447c \ - --hash=sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb \ - --hash=sha256:304128394c9c22b6569eba2a6d98392b56fbdfbad58f83ea702530be80d0f9df \ - --hash=sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84 \ - --hash=sha256:3aeca824b38ca78d9ee2ab82bd9883083d0492d9d17df065ba3b94e88e4d7ee6 \ - --hash=sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45 \ - --hash=sha256:3e3898ae2b58eeafedfe99e542a17859017d72d7f6a63de0f04f99c2cb125936 \ - --hash=sha256:3eea6ed6e6c918e468e693c41ef07f3c3acc310b70ddd9cc72d9ef84bc9564ca \ - --hash=sha256:3f14a4fb1c1c402a22e6a341a24c1341b4a3def81b41cd354386dcb795f83897 \ - --hash=sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a \ - --hash=sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d \ - --hash=sha256:49a9b4af45e8b925e1cd6f3b15bbba2c81e7dba6dce170c677c9cda547411e14 \ - --hash=sha256:4f8b0c78e7aac24979ef09b7f50da871c2de2def043d468c4b41f512d831e912 \ - --hash=sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354 \ - --hash=sha256:5e53d7e6a98b64fe54775d23a7c669763451340c3d44ad5e3a3b48a1efbdc96f \ - --hash=sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c \ - --hash=sha256:601f4a75797d7a770daed8b42b97cd1bb1ba18bd51a9382077a6a247a12aa38d \ - --hash=sha256:61c5a7edbd7c695e54fca029ceb351fc45cd8860119a0f83e48be44e1c464862 \ - --hash=sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969 \ - --hash=sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e \ - --hash=sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8 \ - --hash=sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e \ - --hash=sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa \ - --hash=sha256:7cfced4a069003d8913408e10ca8ed092c49a7f6cefee9bb74b6b3e860683b45 \ - --hash=sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a \ - --hash=sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147 \ - --hash=sha256:82cd34f1081ae4ea2ede3d52f71b7be313756e99b4b5f829f89b12da552d3aa3 \ - --hash=sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3 \ - --hash=sha256:877efb968c3d7eb2dad540b6cabf2f1d3c0fbf4b2d309a3c141f79c7e0061324 \ - --hash=sha256:8b9f19df998761babaa7f09e6bc169294eefafd6149aaa272081cbddc7ba4ca3 \ - --hash=sha256:8cf5877f7ed384dabfdcc37922c3191bf27e55b498fecece9fd5c2c7aaa34c33 \ - --hash=sha256:8d2900b7f5318bc7ad8631d3d40190b95ef2aa8cc59473b73b294e4a55e9f30f \ - --hash=sha256:8d7b4beebb178e9183138f552238f7e6613162a42164233e2bda00cb3afac58f \ - --hash=sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764 \ - --hash=sha256:98f3f020a2b736566c707c8e034945c02aa94e124c24f77ca097c446f81b01f1 \ - --hash=sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114 \ - --hash=sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581 \ - --hash=sha256:9bcf86dfc8ff3e992fed847c077bd875d9e0ba2fa25d859c3a0f0f76f07f0c8d \ - --hash=sha256:9bd0ae7cc2b85320abd5e0abad5ccee5564ed5f0cc90245d2f9a8ef330a8deae \ - --hash=sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da \ - --hash=sha256:9e5ac3437746189a9b4121db2a7b86056ac8786b12e88838696899328fc44bb2 \ - --hash=sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e \ - --hash=sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda \ - --hash=sha256:a96f02ba1bcd330807fc060ed91d1f7a20853da6dd449e5da4b09bfcc08fdcf5 \ - --hash=sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa \ - --hash=sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1 \ - --hash=sha256:af8920ce4a55ff41167ddbc20077f5698c2e710ad3353d32a07d3264f3a2021e \ - --hash=sha256:afd825e30f8d1f521713a5669b63657bcfe5980a916c95855060048b88e1adb7 \ - --hash=sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1 \ - --hash=sha256:b4b68c961b5cc402cbd99cca5eb2547e46ce77260eb705f4d117fd9c3f932b95 \ - --hash=sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93 \ - --hash=sha256:b9e240ae0ba96477682aa87899d94ddec1cc7926f9df29b1dd57b39e797d5ab5 \ - --hash=sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b \ - --hash=sha256:bf8443781533b8d37b295016a4b53c1494fa9a03573c09ca5104550c138d5c05 \ - --hash=sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5 \ - --hash=sha256:c3cd1fc1dc7c376c54440aeaaa0dcc803d2126732ff5c6b68ccd619f2e64be4f \ - --hash=sha256:c7257171bb8d4432fe9d6fdde4d55fdbe663a63636a17f7f9aaba9bcb3153ad7 \ - --hash=sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8 \ - --hash=sha256:d74fcaf87132ffc0447b3c685a9f862ffb5b43e70ea6beec2fb8057d5d2a1fea \ - --hash=sha256:d8c1d679df4361408b628f42b26a5d62bd3e9ba7f0c0e7969f925021554755aa \ - --hash=sha256:e856c1c7255c739434489ec9c8aa9cdf5179785d10ff20add308b5d673bed5cd \ - --hash=sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b \ - --hash=sha256:ed7326563024b6e91fef6b6c7a1a2ff0a71b97793ac33dbbcf38f6005e51ff6e \ - --hash=sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4 \ - --hash=sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204 \ - --hash=sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a -mako==1.3.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e \ - --hash=sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c +jsonschema==4.23.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4 \ + --hash=sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566 +langcodes==3.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:10a4cc078b8e8937d8485d3352312a0a89a3125190db9f2bb2074250eef654e9 \ + --hash=sha256:ae5a77d1a01d0d1e91854a671890892b7ce9abb601ab7327fc5c874f899e1979 +language-data==1.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:77d5cab917f91ee0b2f1aa7018443e911cf8985ef734ca2ba3940770f6a3816b \ + --hash=sha256:82a86050bbd677bfde87d97885b17566cfe75dad3ac4f5ce44b52c28f752e773 +lxml==5.2.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02437fb7308386867c8b7b0e5bc4cd4b04548b1c5d089ffb8e7b31009b961dc3 \ + --hash=sha256:02f6a8eb6512fdc2fd4ca10a49c341c4e109aa6e9448cc4859af5b949622715a \ + --hash=sha256:05f8757b03208c3f50097761be2dea0aba02e94f0dc7023ed73a7bb14ff11eb0 \ + --hash=sha256:06668e39e1f3c065349c51ac27ae430719d7806c026fec462e5693b08b95696b \ + --hash=sha256:07542787f86112d46d07d4f3c4e7c760282011b354d012dc4141cc12a68cef5f \ + --hash=sha256:08ea0f606808354eb8f2dfaac095963cb25d9d28e27edcc375d7b30ab01abbf6 \ + --hash=sha256:0969e92af09c5687d769731e3f39ed62427cc72176cebb54b7a9d52cc4fa3b73 \ + --hash=sha256:0a028b61a2e357ace98b1615fc03f76eb517cc028993964fe08ad514b1e8892d \ + --hash=sha256:0b3f5016e00ae7630a4b83d0868fca1e3d494c78a75b1c7252606a3a1c5fc2ad \ + --hash=sha256:13e69be35391ce72712184f69000cda04fc89689429179bc4c0ae5f0b7a8c21b \ + --hash=sha256:16a8326e51fcdffc886294c1e70b11ddccec836516a343f9ed0f82aac043c24a \ + --hash=sha256:19b4e485cd07b7d83e3fe3b72132e7df70bfac22b14fe4bf7a23822c3a35bff5 \ + --hash=sha256:1a2569a1f15ae6c8c64108a2cd2b4a858fc1e13d25846be0666fc144715e32ab \ + --hash=sha256:1a7aca7964ac4bb07680d5c9d63b9d7028cace3e2d43175cb50bba8c5ad33316 \ + --hash=sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6 \ + --hash=sha256:1d8a701774dfc42a2f0b8ccdfe7dbc140500d1049e0632a611985d943fcf12df \ + --hash=sha256:1e275ea572389e41e8b039ac076a46cb87ee6b8542df3fff26f5baab43713bca \ + --hash=sha256:2304d3c93f2258ccf2cf7a6ba8c761d76ef84948d87bf9664e14d203da2cd264 \ + --hash=sha256:23441e2b5339bc54dc949e9e675fa35efe858108404ef9aa92f0456929ef6fe8 \ + --hash=sha256:23cfafd56887eaed93d07bc4547abd5e09d837a002b791e9767765492a75883f \ + --hash=sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b \ + --hash=sha256:2eb2227ce1ff998faf0cd7fe85bbf086aa41dfc5af3b1d80867ecfe75fb68df3 \ + --hash=sha256:2fb0ba3e8566548d6c8e7dd82a8229ff47bd8fb8c2da237607ac8e5a1b8312e5 \ + --hash=sha256:303f540ad2dddd35b92415b74b900c749ec2010e703ab3bfd6660979d01fd4ed \ + --hash=sha256:339ee4a4704bc724757cd5dd9dc8cf4d00980f5d3e6e06d5847c1b594ace68ab \ + --hash=sha256:33ce9e786753743159799fdf8e92a5da351158c4bfb6f2db0bf31e7892a1feb5 \ + --hash=sha256:343ab62e9ca78094f2306aefed67dcfad61c4683f87eee48ff2fd74902447726 \ + --hash=sha256:34e17913c431f5ae01d8658dbf792fdc457073dcdfbb31dc0cc6ab256e664a8d \ + --hash=sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632 \ + --hash=sha256:38b67afb0a06b8575948641c1d6d68e41b83a3abeae2ca9eed2ac59892b36706 \ + --hash=sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8 \ + --hash=sha256:3b019d4ee84b683342af793b56bb35034bd749e4cbdd3d33f7d1107790f8c472 \ + --hash=sha256:3b6a30a9ab040b3f545b697cb3adbf3696c05a3a68aad172e3fd7ca73ab3c835 \ + --hash=sha256:3d1e35572a56941b32c239774d7e9ad724074d37f90c7a7d499ab98761bd80cf \ + --hash=sha256:3d98de734abee23e61f6b8c2e08a88453ada7d6486dc7cdc82922a03968928db \ + --hash=sha256:453d037e09a5176d92ec0fd282e934ed26d806331a8b70ab431a81e2fbabf56d \ + --hash=sha256:45f9494613160d0405682f9eee781c7e6d1bf45f819654eb249f8f46a2c22545 \ + --hash=sha256:4820c02195d6dfb7b8508ff276752f6b2ff8b64ae5d13ebe02e7667e035000b9 \ + --hash=sha256:49095a38eb333aaf44c06052fd2ec3b8f23e19747ca7ec6f6c954ffea6dbf7be \ + --hash=sha256:4aefd911793b5d2d7a921233a54c90329bf3d4a6817dc465f12ffdfe4fc7b8fe \ + --hash=sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905 \ + --hash=sha256:4c30a2f83677876465f44c018830f608fa3c6a8a466eb223535035fbc16f3438 \ + --hash=sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db \ + --hash=sha256:50ccb5d355961c0f12f6cf24b7187dbabd5433f29e15147a67995474f27d1776 \ + --hash=sha256:519895c99c815a1a24a926d5b60627ce5ea48e9f639a5cd328bda0515ea0f10c \ + --hash=sha256:54401c77a63cc7d6dc4b4e173bb484f28a5607f3df71484709fe037c92d4f0ed \ + --hash=sha256:546cf886f6242dff9ec206331209db9c8e1643ae642dea5fdbecae2453cb50fd \ + --hash=sha256:55ce6b6d803890bd3cc89975fca9de1dff39729b43b73cb15ddd933b8bc20484 \ + --hash=sha256:56793b7a1a091a7c286b5f4aa1fe4ae5d1446fe742d00cdf2ffb1077865db10d \ + --hash=sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6 \ + --hash=sha256:5b8c041b6265e08eac8a724b74b655404070b636a8dd6d7a13c3adc07882ef30 \ + --hash=sha256:5e097646944b66207023bc3c634827de858aebc226d5d4d6d16f0b77566ea182 \ + --hash=sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61 \ + --hash=sha256:610b5c77428a50269f38a534057444c249976433f40f53e3b47e68349cca1425 \ + --hash=sha256:625e3ef310e7fa3a761d48ca7ea1f9d8718a32b1542e727d584d82f4453d5eeb \ + --hash=sha256:657a972f46bbefdbba2d4f14413c0d079f9ae243bd68193cb5061b9732fa54c1 \ + --hash=sha256:69ab77a1373f1e7563e0fb5a29a8440367dec051da6c7405333699d07444f511 \ + --hash=sha256:6a520b4f9974b0a0a6ed73c2154de57cdfd0c8800f4f15ab2b73238ffed0b36e \ + --hash=sha256:6d68ce8e7b2075390e8ac1e1d3a99e8b6372c694bbe612632606d1d546794207 \ + --hash=sha256:6dcc3d17eac1df7859ae01202e9bb11ffa8c98949dcbeb1069c8b9a75917e01b \ + --hash=sha256:6dfdc2bfe69e9adf0df4915949c22a25b39d175d599bf98e7ddf620a13678585 \ + --hash=sha256:739e36ef7412b2bd940f75b278749106e6d025e40027c0b94a17ef7968d55d56 \ + --hash=sha256:7429e7faa1a60cad26ae4227f4dd0459efde239e494c7312624ce228e04f6391 \ + --hash=sha256:74da9f97daec6928567b48c90ea2c82a106b2d500f397eeb8941e47d30b1ca85 \ + --hash=sha256:74e4f025ef3db1c6da4460dd27c118d8cd136d0391da4e387a15e48e5c975147 \ + --hash=sha256:75a9632f1d4f698b2e6e2e1ada40e71f369b15d69baddb8968dcc8e683839b18 \ + --hash=sha256:76acba4c66c47d27c8365e7c10b3d8016a7da83d3191d053a58382311a8bf4e1 \ + --hash=sha256:79d1fb9252e7e2cfe4de6e9a6610c7cbb99b9708e2c3e29057f487de5a9eaefa \ + --hash=sha256:7ce7ad8abebe737ad6143d9d3bf94b88b93365ea30a5b81f6877ec9c0dee0a48 \ + --hash=sha256:7ed07b3062b055d7a7f9d6557a251cc655eed0b3152b76de619516621c56f5d3 \ + --hash=sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184 \ + --hash=sha256:8268cbcd48c5375f46e000adb1390572c98879eb4f77910c6053d25cc3ac2c67 \ + --hash=sha256:875a3f90d7eb5c5d77e529080d95140eacb3c6d13ad5b616ee8095447b1d22e7 \ + --hash=sha256:89feb82ca055af0fe797a2323ec9043b26bc371365847dbe83c7fd2e2f181c34 \ + --hash=sha256:8a7e24cb69ee5f32e003f50e016d5fde438010c1022c96738b04fc2423e61706 \ + --hash=sha256:8ab6a358d1286498d80fe67bd3d69fcbc7d1359b45b41e74c4a26964ca99c3f8 \ + --hash=sha256:8b8df03a9e995b6211dafa63b32f9d405881518ff1ddd775db4e7b98fb545e1c \ + --hash=sha256:8cf85a6e40ff1f37fe0f25719aadf443686b1ac7652593dc53c7ef9b8492b115 \ + --hash=sha256:8e8d351ff44c1638cb6e980623d517abd9f580d2e53bfcd18d8941c052a5a009 \ + --hash=sha256:9164361769b6ca7769079f4d426a41df6164879f7f3568be9086e15baca61466 \ + --hash=sha256:96e85aa09274955bb6bd483eaf5b12abadade01010478154b0ec70284c1b1526 \ + --hash=sha256:981a06a3076997adf7c743dcd0d7a0415582661e2517c7d961493572e909aa1d \ + --hash=sha256:9cd5323344d8ebb9fb5e96da5de5ad4ebab993bbf51674259dbe9d7a18049525 \ + --hash=sha256:9d6c6ea6a11ca0ff9cd0390b885984ed31157c168565702959c25e2191674a14 \ + --hash=sha256:a02d3c48f9bb1e10c7788d92c0c7db6f2002d024ab6e74d6f45ae33e3d0288a3 \ + --hash=sha256:a233bb68625a85126ac9f1fc66d24337d6e8a0f9207b688eec2e7c880f012ec0 \ + --hash=sha256:a2f6a1bc2460e643785a2cde17293bd7a8f990884b822f7bca47bee0a82fc66b \ + --hash=sha256:a6d17e0370d2516d5bb9062c7b4cb731cff921fc875644c3d751ad857ba9c5b1 \ + --hash=sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f \ + --hash=sha256:ab67ed772c584b7ef2379797bf14b82df9aa5f7438c5b9a09624dd834c1c1aaf \ + --hash=sha256:ac6540c9fff6e3813d29d0403ee7a81897f1d8ecc09a8ff84d2eea70ede1cdbf \ + --hash=sha256:ae4073a60ab98529ab8a72ebf429f2a8cc612619a8c04e08bed27450d52103c0 \ + --hash=sha256:ae791f6bd43305aade8c0e22f816b34f3b72b6c820477aab4d18473a37e8090b \ + --hash=sha256:aef5474d913d3b05e613906ba4090433c515e13ea49c837aca18bde190853dff \ + --hash=sha256:b0b3f2df149efb242cee2ffdeb6674b7f30d23c9a7af26595099afaf46ef4e88 \ + --hash=sha256:b128092c927eaf485928cec0c28f6b8bead277e28acf56800e972aa2c2abd7a2 \ + --hash=sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40 \ + --hash=sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716 \ + --hash=sha256:b47633251727c8fe279f34025844b3b3a3e40cd1b198356d003aa146258d13a2 \ + --hash=sha256:b537bd04d7ccd7c6350cdaaaad911f6312cbd61e6e6045542f781c7f8b2e99d2 \ + --hash=sha256:b5e4ef22ff25bfd4ede5f8fb30f7b24446345f3e79d9b7455aef2836437bc38a \ + --hash=sha256:b74b9ea10063efb77a965a8d5f4182806fbf59ed068b3c3fd6f30d2ac7bee734 \ + --hash=sha256:bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87 \ + --hash=sha256:bbc4b80af581e18568ff07f6395c02114d05f4865c2812a1f02f2eaecf0bfd48 \ + --hash=sha256:bcc98f911f10278d1daf14b87d65325851a1d29153caaf146877ec37031d5f36 \ + --hash=sha256:be49ad33819d7dcc28a309b86d4ed98e1a65f3075c6acd3cd4fe32103235222b \ + --hash=sha256:bec4bd9133420c5c52d562469c754f27c5c9e36ee06abc169612c959bd7dbb07 \ + --hash=sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c \ + --hash=sha256:c689d0d5381f56de7bd6966a4541bff6e08bf8d3871bbd89a0c6ab18aa699573 \ + --hash=sha256:c7079d5eb1c1315a858bbf180000757db8ad904a89476653232db835c3114001 \ + --hash=sha256:cb3942960f0beb9f46e2a71a3aca220d1ca32feb5a398656be934320804c0df9 \ + --hash=sha256:cd9e78285da6c9ba2d5c769628f43ef66d96ac3085e59b10ad4f3707980710d3 \ + --hash=sha256:cf2a978c795b54c539f47964ec05e35c05bd045db5ca1e8366988c7f2fe6b3ce \ + --hash=sha256:d14a0d029a4e176795cef99c056d58067c06195e0c7e2dbb293bf95c08f772a3 \ + --hash=sha256:d237ba6664b8e60fd90b8549a149a74fcc675272e0e95539a00522e4ca688b04 \ + --hash=sha256:d26a618ae1766279f2660aca0081b2220aca6bd1aa06b2cf73f07383faf48927 \ + --hash=sha256:d28cb356f119a437cc58a13f8135ab8a4c8ece18159eb9194b0d269ec4e28083 \ + --hash=sha256:d4ed0c7cbecde7194cd3228c044e86bf73e30a23505af852857c09c24e77ec5d \ + --hash=sha256:d83e2d94b69bf31ead2fa45f0acdef0757fa0458a129734f59f67f3d2eb7ef32 \ + --hash=sha256:d8bbcd21769594dbba9c37d3c819e2d5847656ca99c747ddb31ac1701d0c0ed9 \ + --hash=sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f \ + --hash=sha256:dc911208b18842a3a57266d8e51fc3cfaccee90a5351b92079beed912a7914c2 \ + --hash=sha256:dfa7c241073d8f2b8e8dbc7803c434f57dbb83ae2a3d7892dd068d99e96efe2c \ + --hash=sha256:e282aedd63c639c07c3857097fc0e236f984ceb4089a8b284da1c526491e3f3d \ + --hash=sha256:e290d79a4107d7d794634ce3e985b9ae4f920380a813717adf61804904dc4393 \ + --hash=sha256:e3d9d13603410b72787579769469af730c38f2f25505573a5888a94b62b920f8 \ + --hash=sha256:e481bba1e11ba585fb06db666bfc23dbe181dbafc7b25776156120bf12e0d5a6 \ + --hash=sha256:e49b052b768bb74f58c7dda4e0bdf7b79d43a9204ca584ffe1fb48a6f3c84c66 \ + --hash=sha256:eb00b549b13bd6d884c863554566095bf6fa9c3cecb2e7b399c4bc7904cb33b5 \ + --hash=sha256:ec87c44f619380878bd49ca109669c9f221d9ae6883a5bcb3616785fa8f94c97 \ + --hash=sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196 \ + --hash=sha256:f11ae142f3a322d44513de1018b50f474f8f736bc3cd91d969f464b5bfef8836 \ + --hash=sha256:f2a09f6184f17a80897172863a655467da2b11151ec98ba8d7af89f17bf63dae \ + --hash=sha256:f5b65529bb2f21ac7861a0e94fdbf5dc0daab41497d18223b46ee8515e5ad297 \ + --hash=sha256:f60fdd125d85bf9c279ffb8e94c78c51b3b6a37711464e1f5f31078b45002421 \ + --hash=sha256:f61efaf4bed1cc0860e567d2ecb2363974d414f7f1f124b1df368bbf183453a6 \ + --hash=sha256:f90e552ecbad426eab352e7b2933091f2be77115bb16f09f78404861c8322981 \ + --hash=sha256:f956196ef61369f1685d14dad80611488d8dc1ef00be57c0c5a03064005b0f30 \ + --hash=sha256:fb91819461b1b56d06fa4bcf86617fac795f6a99d12239fb0c68dbeba41a0a30 \ + --hash=sha256:fbc9d316552f9ef7bba39f4edfad4a734d3d6f93341232a9dddadec4f15d425f \ + --hash=sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324 \ + --hash=sha256:ffb2be176fed4457e445fe540617f0252a72a8bc56208fd65a690fdb1f57660b +mako==1.3.5 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a \ + --hash=sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc +marisa-trie==1.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:006419c59866979188906babc42ae0918081c18cabc2bdabca027f68c081c127 \ + --hash=sha256:015594427360c6ad0fa94d51ee3d50fb83b0f7278996497fd2d69f877c3de9bd \ + --hash=sha256:02f773e85cc566a24c0e0e28c744052db7691c4f13d02e4257bc657a49b9ab14 \ + --hash=sha256:035c4c8f3b313b4d7b7451ddd539da811a11077a9e359c6a0345f816b1bdccb3 \ + --hash=sha256:045f32eaeb5dcdb5beadb571ba616d7a34141764b616eebb4decce71b366f5fa \ + --hash=sha256:069ac10a133d96b3f3ed1cc071b973a3f28490345e7941c778a1d81cf176f04a \ + --hash=sha256:125016400449e46ec0e5fabd14c8314959c4dfa02ffc2861195c99efa2b5b011 \ + --hash=sha256:1890cc993149db4aa8242973526589e8133c3f92949b0ac74c2c9a6596707ae3 \ + --hash=sha256:1b855e6286faef5411386bf9d676dfb545c09f7d109f197f347c9366aeb12f07 \ + --hash=sha256:26177cd0dadb7b44f47c17c40e16ac157c4d22ac7ed83b5a47f44713239e10d1 \ + --hash=sha256:27d270a64eb655754dfb4e352c60a084b16ab999b3a97a0cdc7dbecbca3c0e35 \ + --hash=sha256:2db8e74493c3bffb480c54afaa88890a39bf90063ff5b322acf64bf076e4b36e \ + --hash=sha256:2e7540f844c1de493a90ad7d0f5bffc6a2cba19fe312d6db7b97aceff11d97f8 \ + --hash=sha256:2fb9243f66563285677079c9dccc697d35985287bacb36c8e685305687b0e025 \ + --hash=sha256:3267f438d258d7d85ee3dde363c4f96c3196ca9cd9e63fe429a59543cc544b15 \ + --hash=sha256:3425dc81d49a374be49e3a063cb6ccdf57973201b0a30127082acea50562a85e \ + --hash=sha256:3540bb85b38dfc17060263e061c95a0a435681b04543d1ae7e8d7441a9790593 \ + --hash=sha256:36d65bcbf22a70cdd0202bd8608c2feecc58bdb9e5dd9a2f5a723b651fcab287 \ + --hash=sha256:39b88f126988ea83e8458259297d2b2f9391bfba8f4dc5d7a246813aae1c1def \ + --hash=sha256:40e2a374026492ac84232897f1f1d8f92a4a1f8bcf3f0ded1f2b8b708d1acfff \ + --hash=sha256:437bf6c0d7ba4cf17656a0e3bdd0b3c2c92c01fedfa670904177eef3116a4f45 \ + --hash=sha256:49701db6bb8f1ec0133abd95f0a4891cfd6f84f3bd019e343037e31a5a5b0210 \ + --hash=sha256:4cfec001cf233e8853a29e1c2bb74031c217aa61e7bd19389007e04861855731 \ + --hash=sha256:4e4535fc5458de2b59789e574cdd55923d63de5612dc159d33941af79cd62786 \ + --hash=sha256:525b8df41a1a7337ed7f982eb63b704d7d75f047e30970fcfbe9cf6fc22c5991 \ + --hash=sha256:5321211647609869907e81b0230ad2dfdfa7e19fe1ee469b46304a622391e6a1 \ + --hash=sha256:58e2b84cbb6394f9c567f1f4351fc2995a094e1b684da9b577d4139b145401d6 \ + --hash=sha256:5a7c75a508f44e40f7af8448d466045a97534adcbb026e63989407cefb9ebfa6 \ + --hash=sha256:5a83fe83e0eab9154a2dc7c556898c86584b7779ddf4214c606fce4ceff07c13 \ + --hash=sha256:5b4a8d3ed1f1b8f551b52e11a1265eaf0718f06bb206654b2c529cecda0913dd \ + --hash=sha256:5cea60975184f03fbcff51339df0eb44d2abe106a1693983cc64415eb87b897b \ + --hash=sha256:5d8a1c0361165231f4fb915237470afc8cc4803c535f535f4fc42ca72855b124 \ + --hash=sha256:5e04e9c86fe8908b61c2aebb8444217cacaed15b93d2dccaac3849e36a6dc660 \ + --hash=sha256:5f5b3080316de735bd2b07265de5eea3ae176fa2fc60f9871aeaa9cdcddfc8f7 \ + --hash=sha256:61fab91fef677f0af0e818e61595f2334f7e0b3e122b24ec65889aae69ba468d \ + --hash=sha256:65f5d8c1ecc85283b5b03a1475a5da723b94b3beda752c895b2f748477d8f1b1 \ + --hash=sha256:6601e74338fb31e1b20674257706150113463182a01d3a1310df6b8840720b17 \ + --hash=sha256:6aeef7b364fb3b34dbba1cc57b79f1668fad0c3f039738d65a5b0d5ddce15f47 \ + --hash=sha256:6ff705cb3b907bdeacb8c4b3bf0541691f52b101014d189a707ca41ebfacad59 \ + --hash=sha256:7459b1e1937e33daed65a6d55f8b95f9a8601f4f8749d01641cf548ecac03840 \ + --hash=sha256:77bfde3287314e91e28d3a882c7b87519ef0ee104c921df72c7819987d5e4863 \ + --hash=sha256:7c6e6506bd24a5799b9b4b9cf1e8d6fa281f136396ba018a95d95d4d74715227 \ + --hash=sha256:7c87a0c2cccce12b07bfcb70708637c0816970282d966a1531ecda1a24bd1cc8 \ + --hash=sha256:83d90be28c083323909d23ff8e9b4a2764b9e75520d1bae1a277e9fa7ca20d15 \ + --hash=sha256:84c44cb13803723f0f76aa2ba1a657f762a0bb9d8a9b80dfff249bb1c3218dd6 \ + --hash=sha256:873efd212dfef2b736ff2ff43e10b348c428d5dbac7b8cb8aa777004bc8c7b0e \ + --hash=sha256:88660e6ee0f821872aaf63ba4b9a7513428b9cab20c69cc013c368bd72c3a4fe \ + --hash=sha256:8af7a21ac2ba6dc23e4257fc3a40b3070e776275d3d0b5b2ef44473ad92caf3a \ + --hash=sha256:8cd287ff323224d87c2b739cba39614aac3737c95a254e0ff70e77d9b8df226d \ + --hash=sha256:902ea948677421093651ca98df62d255383f865f7c353f956ef666e92500e79f \ + --hash=sha256:92ac63e1519598de946c7d9346df3bb52ed96968eb3021b4e89b51d79bc72a86 \ + --hash=sha256:9bcc6613bc873136dc62609b66aaa27363e2bd46c03fdab62d638f7cf69d5f82 \ + --hash=sha256:9dccef41d4af11a03558c1d101de58bd723b3039a5bc4e064250008c118037ec \ + --hash=sha256:9fb95f3ab95ba933f6a2fa2629185e9deb9da45ff2aa4ba8cc8f722528c038ef \ + --hash=sha256:a06a77075240eb83a47b780902322e66c968a06a2b6318cab06757c65ea64190 \ + --hash=sha256:a3f0562863deaad58c5dc3a51f706da92582bc9084189148a45f7a12fe261a51 \ + --hash=sha256:a7183d84da20c89b2a366bf581f0d79d1e248909678f164e8536f291120432e8 \ + --hash=sha256:a7196691681ecb8a12629fb6277c33bafdb27cf2b6c18c28bc48fa42a15eab8f \ + --hash=sha256:a97652c5fbc92f52100afe1c4583625015611000fa81606ad17f1b3bbb9f3bfa \ + --hash=sha256:b04a07b99b62b9bdf3eaf1d44571a3293ce249ce8971944e780c9c709593462f \ + --hash=sha256:b08968ccad00f54f31e38516e4452fae59dd15a3fcee56aea3101ba2304680b3 \ + --hash=sha256:bc138625b383998f5cd0cbf6cd38d66d414f3786ae6d7b4e4a6fc970140ef4e9 \ + --hash=sha256:bd1f3ef8de89684fbdd6aaead09d53b82e718bad4375d2beb938cbd24b48c51a \ + --hash=sha256:bdd1d4d430e33abbe558971d1bd57da2d44ca129fa8a86924c51437dba5cb345 \ + --hash=sha256:c11af35d9304de420b359741e12b885d04f11403697efcbbe8cb50f834261ebc \ + --hash=sha256:c4fbb1ec1d9e891060a0aee9f9c243acec63de1e197097a14850ba38ec8a4013 \ + --hash=sha256:c57647dd9f9ba16fc5bb4679c915d7d48d5c0b25134fb10f095ccd839686a027 \ + --hash=sha256:c643c66bbde6a115e4ec8713c087a9fe9cb7b7c684e6af4cf448c120fa427ea4 \ + --hash=sha256:c729e2b8f9699874b1372b5a01515b340eda1292f5e08a3fe4633b745f80ad7a \ + --hash=sha256:c7f4df4163202b0aa5dad3eeddf088ecb61e9101986c8b31f1e052ebd6df9292 \ + --hash=sha256:cb60c2f9897ce2bfc31a69ac25a040de4f8643ab2a339bb0ff1185e1a9dedaf8 \ + --hash=sha256:cd88a338c87e6dc130b6cea7b697580c21f0c83a8a8b46671cfecbb713d3fe24 \ + --hash=sha256:ce2f68e1000c4c72820c5b2c9d037f326fcf75f036453a5e629f225f99b92cfc \ + --hash=sha256:d3c0e38f0501951e2322f7274a39b8e2344bbd91ceaa9da439f46022570ddc9d \ + --hash=sha256:d3ef375491e7dd71a0a7e7bf288c88750942bd1ee0c379dcd6ad43e31af67d00 \ + --hash=sha256:d4f05c2ee218a5ab09d269b640d06f9708b0cf37c842344cbdffb0661c74c472 \ + --hash=sha256:d62985a0e6f2cfeb36cd6afa0460063bbe83ef4bfd9afe189a99103487547210 \ + --hash=sha256:de9911480ce2a0513582cb84ee4484e5ee8791e692276c7f5cd7378e114d1988 \ + --hash=sha256:e7202ba0ca1db5245feaebbeb3d0c776b2da1fffb0abc3500dd505f679686aa1 \ + --hash=sha256:eaf052c0a1f4531ee12fd4c637212e77ad2af8c3b38a0d3096622abd01a22212 \ + --hash=sha256:eba1061bbeaeec4149282beab2ae163631606f119f549a10246b014e13f9047b \ + --hash=sha256:ec167b006884a90d130ee30518a9aa44cb40211f702bf07031b2d7d4d1db569b \ + --hash=sha256:f19c5fcf23c02f1303deb69c67603ee37ed8f01de2d8b19f1716a6cf5afd5455 \ + --hash=sha256:f5cb731581effb3e05258f3ddc2a155475de74bb00f61eb280f991e13b48f783 \ + --hash=sha256:fa1fa7f67d317a921315a65e266b9e156ce5a956076ec2b6dbf72d67c7df8216 \ + --hash=sha256:fdf7a2d066907816726f3bf241b8cb05b698d6ffaa3c5ea2658d4ba69e87ec57 \ + --hash=sha256:fe1394e1f262e5b45d22d30bd1ef75174d1f2772e86716b5f93f9c29dfc1a779 \ + --hash=sha256:fedfc67497f8aa2757756b5cf493759f245d321fb78914ce125b6d75daa89b5f markdown-it-py==3.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb @@ -700,6 +866,76 @@ markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 +maxminddb==2.6.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:058ca89789bc1770fe58d02a88272ca91dabeef9f3fe0011fe506484355f1804 \ + --hash=sha256:05e873eb82281cef6e787bd40bd1d58b2e496a21b3689346f0d0420988b3cbb1 \ + --hash=sha256:0b281c0eec3601dde1f169a1c04e2615751c66368141aded9f03131fe635450b \ + --hash=sha256:0b480a31589750da4e36d1ba04b77ee3ac3853ac7b94d63f337b9d4d0403043f \ + --hash=sha256:12207f0becf3f2bf14e7a4bf86efcaa6e90d665a918915ae228c4e77792d7151 \ + --hash=sha256:1c096dfd20926c4de7d7fd5b5e75c756eddd4bdac5ab7aafd4bb67d000b13743 \ + --hash=sha256:1dc2b511c7255f7cbbb01e8ba01ba82e62e9c1213e382d36f9d9b0ee45c2f6b2 \ + --hash=sha256:20662878bc9514e90b0b4c4eb1a76622ecc7504d012e76bad9cdb7372fc0ef96 \ + --hash=sha256:28a2eaf9769262c05c486e777016771f3367c843b053c43cd5fde1108755753d \ + --hash=sha256:28af9470f28fce2ccb945478235f53fb52d98a505653b1bf4028e34df6149a06 \ + --hash=sha256:2aaefb62f881151960bb67e5aeb302c159a32bd2d623cf72dad688bda1020869 \ + --hash=sha256:34b6e8d667d724f60d52635f3d959f793ab4e5d57d78b27fe66f02752d8c6b08 \ + --hash=sha256:38941a38278491bf95e5ca544969782c7ab33326802f6a93816867289c3f6401 \ + --hash=sha256:3987e103396e925edebbef4877e94515822f63b3b436027a0b164b500622fccd \ + --hash=sha256:39eab93ddd75fd02f8d5ad6b1bd3f8d894828d91d6f6c1a96bb9e87c34e94aaa \ + --hash=sha256:47170ec0e1e76787cc5882301c487f495d67f3146318f2f4e2adc281951a96ef \ + --hash=sha256:485c0778f6801e1437c2efd6e3b964a7ae71c8819f063e0b5460c3267d977040 \ + --hash=sha256:5662386db91872d5505fde9e7bb0b9530b6aab7a6f3ece7df59a2b43a7b45d17 \ + --hash=sha256:58bfd2c55c96aaaa7c4996c704edabfb1bd369dfc1592cedf8957a24062178b1 \ + --hash=sha256:5c7c520d06d335b288d06a00b786cea9b7e023bd588efb1a6ef485e94ccc7244 \ + --hash=sha256:6a50bc348c699d8f6a5f0aa35e5096515d642ca2f38b944bd71c3dedda3d3588 \ + --hash=sha256:6fd1a612110ff182a559d8010e7615e5d05ef9d2c234b5f7de124ee8fdf1ecb9 \ + --hash=sha256:7607e45f7eca991fa34d57c03a791a1dfbe774ddd9250d0f35cdcc6f17142a15 \ + --hash=sha256:78c3aa70c62be68ace23f819e7f23258545f2bfbd92cd6c33ee398cd261f6b84 \ + --hash=sha256:7c1220838ba9b0bcdaa0c5846f9da70a2304df2ac255fe518370f8faf8c18316 \ + --hash=sha256:7cd7f525eb2331cf05181c5ba562cc3edec3de4b41dbb18a5fee9ad24884b499 \ + --hash=sha256:7cfdf5c29a2739610700b9fea7f8d68ce81dcf30bb8016f1a1853ef889a2624b \ + --hash=sha256:7d842d32e2620abc894b7d79a5a1007a69df2c6cf279a06b94c9c3913f66f264 \ + --hash=sha256:7e5a90a1cb0c7fd6226aa44e18a87b26fa85b6eebae36d529d7582f93e8dfbd1 \ + --hash=sha256:80d20683afe01b4d41bad1c1829f87ab12f3d19c68ec230f83318a2fd13871a7 \ + --hash=sha256:80d7495565d30260c630afbe74d61522b13dd31ed05b8916003ec5b127109a12 \ + --hash=sha256:80d7f943f6b8bc437eaae5da778a83d8f38e4b7463756fdee04833e1be0bdea2 \ + --hash=sha256:8101291e5b92bd272a050c25822a5e30860d453dde16b4fffed9d751f0483a82 \ + --hash=sha256:826a1858b93b193df7fa71e3caca65c3051db20545df0020444f55c02e8ed2c3 \ + --hash=sha256:85fc9406f42c1311ce8ea9f2c820db5d7ac687a39ab5d932708dc783607378ef \ + --hash=sha256:86048ff328793599e584bcc2fc8278c2b7c5d3a4005c70403613449ec93817ef \ + --hash=sha256:886af3ba4aa26214ff39214565f53152b62a5abdb6ef9e00c76c194dbfd79231 \ + --hash=sha256:8cb992da535264177b380e7b81943c884d57dcbfad6b3335d7f633967144746e \ + --hash=sha256:93691c8b4b4c448babb37bedc6f3d51523a3f06ab11bdd171da7ffc4005a7897 \ + --hash=sha256:96a1fa38322bce1d587bb6ce39a0e6ca4c1b824f48fbc5739a5ec507f63aa889 \ + --hash=sha256:9a2671e8f4161130803cf226cd9cb8b93ec5c4b2493f83a902986177052d95d3 \ + --hash=sha256:9dccd7a438f81e3df84dfc31a75af4c8d29adefb6082329385bfde604c9ea01b \ + --hash=sha256:a74b60cdc61a69b967ec44201c6259fbc48ef2eab2e885fbdc50ec1accaad545 \ + --hash=sha256:a771df92e599ad867c16ae4acb08cc3763c9d1028f4ca772c0571da97f7f86d2 \ + --hash=sha256:aa8cb54b01a29a23a0ea6659fbb38deec6f35453588c5decdbf8669feb53b624 \ + --hash=sha256:add1e55620033516c5f0734b1d9d03848859192d9f3825aabe720dfa8a783958 \ + --hash=sha256:b0a3b9cab1a94cc633df3da85c6567f0188f10165e3338ec9a6c421de9fe53b9 \ + --hash=sha256:b31ecf3083b78c77624783bfdf6177e6ac73ae14684ef182855eb5569bc78e7c \ + --hash=sha256:b4d9cd7ddd02ee123a44d0d7821166d31540ea85352deb06b29d55e802f32781 \ + --hash=sha256:c9e9e893f7c0fa44cfdd5ab819a07d93f63ee398c28b792cedd50b94dcfea7c0 \ + --hash=sha256:cd4530b9604d66cfa5e37eb94c671e54feff87769f8ba7fa997cce959e0cb241 \ + --hash=sha256:d0970b661c4fac6624b9128057ed5fe35a2d95aa60359272289cd4c7207c9a6d \ + --hash=sha256:d15414d251513748cb646d284a2829a5f4c69d8c90963a6e6da53a1a6d0accf7 \ + --hash=sha256:d32266792b349f5507b0369d3277d45318fcd346a16dcc98b484aadc208e4d74 \ + --hash=sha256:d8ccca5327cb4e706f669456ec6d556badfa92c0fdacd57a15076f3cdc061560 \ + --hash=sha256:dc9f1203eb2b139252aa08965960fe13c36cc8b80b536490b94b05c31aa1fca9 \ + --hash=sha256:dd90c3798e6c347d48d5d9a9c95dc678b52a5a965f1fb72152067fdf52b994da \ + --hash=sha256:e1e40449bd278fdca1f351df442f391e72fd3d98b054ccac1672f27d70210642 \ + --hash=sha256:e2b85ffc9fb2e192321c2f0b34d0b291b8e82de6e51a6ec7534645663678e835 \ + --hash=sha256:e63649a82926f1d93acdd3df5f7be66dc9473653350afe73f365bb25e5b34368 \ + --hash=sha256:e9013076deca5d136c260510cd05e82ec2b4ddb9476d63e2180a13ddfd305c3e \ + --hash=sha256:eacd65e38bdf4efdf42bbc15cfa734b09eb818ecfef76b7b36e64be382be4c83 \ + --hash=sha256:eb534333f5fd7180e35c0207b3d95d621e4b9be3b8c1709995d0feb6c752b6f4 \ + --hash=sha256:ebf9fdf8a8e55862aabb8b2c34a4af31a8a5b686007288eeb561fa20ef348378 \ + --hash=sha256:ecce0b2d125691e2311f94dbd564c2d61c36c5033d082919431a21e6c694fa3f \ + --hash=sha256:eef1c26210155c7b94c4ca28fef65eb44a5ca1584427b1fbdeec1cd3c81e25c5 \ + --hash=sha256:f2e326a99eaa924ff2fb09d6e44127983a43016228e7780888f15e9ba171d7b3 \ + --hash=sha256:f412a54f87ef9083911c334267188d3d1b14f2591eac94b94ca32528f21d5f25 \ + --hash=sha256:fb38aa94e76a87785b654c035f9f3ee39b74a98e9beea9a10b1aa62abdcc4cbd mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba @@ -836,96 +1072,107 @@ opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 -packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ - --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 +packaging==24.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ + --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 pgpy==0.6.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:279c2e353f4c3a319f00bd9bd582456e420f8a3ac6de2b4e9731444746828383 -pillow==10.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c \ - --hash=sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2 \ - --hash=sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb \ - --hash=sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d \ - --hash=sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa \ - --hash=sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3 \ - --hash=sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1 \ - --hash=sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a \ - --hash=sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd \ - --hash=sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8 \ - --hash=sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999 \ - --hash=sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599 \ - --hash=sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936 \ - --hash=sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375 \ - --hash=sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d \ - --hash=sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b \ - --hash=sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60 \ - --hash=sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572 \ - --hash=sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3 \ - --hash=sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced \ - --hash=sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f \ - --hash=sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b \ - --hash=sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19 \ - --hash=sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f \ - --hash=sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d \ - --hash=sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383 \ - --hash=sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795 \ - --hash=sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355 \ - --hash=sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57 \ - --hash=sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09 \ - --hash=sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b \ - --hash=sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462 \ - --hash=sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf \ - --hash=sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f \ - --hash=sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a \ - --hash=sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad \ - --hash=sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9 \ - --hash=sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d \ - --hash=sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45 \ - --hash=sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994 \ - --hash=sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d \ - --hash=sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338 \ - --hash=sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463 \ - --hash=sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451 \ - --hash=sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591 \ - --hash=sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c \ - --hash=sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd \ - --hash=sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32 \ - --hash=sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9 \ - --hash=sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf \ - --hash=sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5 \ - --hash=sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828 \ - --hash=sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3 \ - --hash=sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5 \ - --hash=sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2 \ - --hash=sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b \ - --hash=sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2 \ - --hash=sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475 \ - --hash=sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3 \ - --hash=sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb \ - --hash=sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef \ - --hash=sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015 \ - --hash=sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002 \ - --hash=sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170 \ - --hash=sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84 \ - --hash=sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57 \ - --hash=sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f \ - --hash=sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27 \ - --hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a +pillow==10.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885 \ + --hash=sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea \ + --hash=sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df \ + --hash=sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5 \ + --hash=sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c \ + --hash=sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d \ + --hash=sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd \ + --hash=sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06 \ + --hash=sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908 \ + --hash=sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a \ + --hash=sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be \ + --hash=sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0 \ + --hash=sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b \ + --hash=sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80 \ + --hash=sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a \ + --hash=sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e \ + --hash=sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9 \ + --hash=sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696 \ + --hash=sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b \ + --hash=sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309 \ + --hash=sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e \ + --hash=sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab \ + --hash=sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d \ + --hash=sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060 \ + --hash=sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d \ + --hash=sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d \ + --hash=sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4 \ + --hash=sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3 \ + --hash=sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6 \ + --hash=sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb \ + --hash=sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94 \ + --hash=sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b \ + --hash=sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496 \ + --hash=sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0 \ + --hash=sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319 \ + --hash=sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b \ + --hash=sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856 \ + --hash=sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef \ + --hash=sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680 \ + --hash=sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b \ + --hash=sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42 \ + --hash=sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e \ + --hash=sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597 \ + --hash=sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a \ + --hash=sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8 \ + --hash=sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3 \ + --hash=sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736 \ + --hash=sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da \ + --hash=sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126 \ + --hash=sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd \ + --hash=sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5 \ + --hash=sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b \ + --hash=sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026 \ + --hash=sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b \ + --hash=sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc \ + --hash=sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46 \ + --hash=sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2 \ + --hash=sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c \ + --hash=sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe \ + --hash=sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984 \ + --hash=sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a \ + --hash=sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70 \ + --hash=sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca \ + --hash=sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b \ + --hash=sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91 \ + --hash=sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3 \ + --hash=sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84 \ + --hash=sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1 \ + --hash=sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5 \ + --hash=sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be \ + --hash=sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f \ + --hash=sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc \ + --hash=sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9 \ + --hash=sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e \ + --hash=sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141 \ + --hash=sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef \ + --hash=sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22 \ + --hash=sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27 \ + --hash=sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e \ + --hash=sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1 pluggy==1.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1 \ --hash=sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669 -protobuf==4.25.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4 \ - --hash=sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8 \ - --hash=sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c \ - --hash=sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d \ - --hash=sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4 \ - --hash=sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa \ - --hash=sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c \ - --hash=sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019 \ - --hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \ - --hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \ - --hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2 +protobuf==4.25.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:051e97ce9fa6067a4546e75cb14f90cf0232dcb3e3d508c448b8d0e4265b61c1 \ + --hash=sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d \ + --hash=sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040 \ + --hash=sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835 \ + --hash=sha256:7e372cbbda66a63ebca18f8ffaa6948455dfecc4e9c1029312f6c2edcd86c4e1 \ + --hash=sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca \ + --hash=sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f \ + --hash=sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d \ + --hash=sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978 \ + --hash=sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4 \ + --hash=sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b psycopg2==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981 \ --hash=sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516 \ @@ -940,14 +1187,14 @@ psycopg2==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024 \ --hash=sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913 \ --hash=sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c -pyasn1==0.5.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58 \ - --hash=sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c +pyasn1==0.6.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c \ + --hash=sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473 pybinaryedge==0.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:00cf2f253aa44c7d6589a56d70c5b820a5060c3a0a2aee018f0b4ed732fe7632 -pycparser==2.21 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ - --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 +pycparser==2.22 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ + --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ @@ -1038,18 +1285,18 @@ pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 -pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ - --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic-settings==2.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315 \ + --hash=sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88 pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pydicom==2.4.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 -pygments==2.17.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \ - --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367 +pygments==2.18.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ + --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a pynacl==1.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858 \ --hash=sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d \ @@ -1067,12 +1314,12 @@ pynetdicom==2.0.2 ; python_version >= "3.10" and python_version < "4.0" \ pytest-env==1.1.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:aada77e6d09fcfb04540a6e462c58533c37df35fa853da78707b17ec04d17dfc \ --hash=sha256:fcd7dc23bb71efd3d35632bde1bbe5ee8c8dc4489d6617fb010674880d96216b -pytest==8.2.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd \ - --hash=sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1 -python-dateutil==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ - --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 +pytest==8.3.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5 \ + --hash=sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce +python-dateutil==2.9.0.post0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ + --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a @@ -1094,160 +1341,184 @@ pywin32==306 ; python_version >= "3.10" and python_version < "4.0" and sys_platf --hash=sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a \ --hash=sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407 \ --hash=sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0 -referencing==0.33.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5 \ - --hash=sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7 -requests-file==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 +referencing==0.35.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \ + --hash=sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de +requests-file==2.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658 \ + --hash=sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 -rich==13.7.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \ - --hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235 -rpds-py==0.18.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f \ - --hash=sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c \ - --hash=sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76 \ - --hash=sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e \ - --hash=sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157 \ - --hash=sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f \ - --hash=sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5 \ - --hash=sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05 \ - --hash=sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24 \ - --hash=sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1 \ - --hash=sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8 \ - --hash=sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b \ - --hash=sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb \ - --hash=sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07 \ - --hash=sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1 \ - --hash=sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6 \ - --hash=sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e \ - --hash=sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e \ - --hash=sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1 \ - --hash=sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab \ - --hash=sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4 \ - --hash=sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17 \ - --hash=sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594 \ - --hash=sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d \ - --hash=sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d \ - --hash=sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3 \ - --hash=sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c \ - --hash=sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66 \ - --hash=sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f \ - --hash=sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80 \ - --hash=sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33 \ - --hash=sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f \ - --hash=sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c \ - --hash=sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022 \ - --hash=sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e \ - --hash=sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f \ - --hash=sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da \ - --hash=sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1 \ - --hash=sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688 \ - --hash=sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795 \ - --hash=sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c \ - --hash=sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98 \ - --hash=sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1 \ - --hash=sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20 \ - --hash=sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307 \ - --hash=sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4 \ - --hash=sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18 \ - --hash=sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294 \ - --hash=sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66 \ - --hash=sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467 \ - --hash=sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948 \ - --hash=sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e \ - --hash=sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1 \ - --hash=sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0 \ - --hash=sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7 \ - --hash=sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd \ - --hash=sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641 \ - --hash=sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d \ - --hash=sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9 \ - --hash=sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1 \ - --hash=sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da \ - --hash=sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3 \ - --hash=sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa \ - --hash=sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7 \ - --hash=sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40 \ - --hash=sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496 \ - --hash=sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124 \ - --hash=sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836 \ - --hash=sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434 \ - --hash=sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984 \ - --hash=sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f \ - --hash=sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6 \ - --hash=sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e \ - --hash=sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461 \ - --hash=sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c \ - --hash=sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432 \ - --hash=sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73 \ - --hash=sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58 \ - --hash=sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88 \ - --hash=sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337 \ - --hash=sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7 \ - --hash=sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863 \ - --hash=sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475 \ - --hash=sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3 \ - --hash=sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51 \ - --hash=sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf \ - --hash=sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024 \ - --hash=sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40 \ - --hash=sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9 \ - --hash=sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec \ - --hash=sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb \ - --hash=sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7 \ - --hash=sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861 \ - --hash=sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880 \ - --hash=sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f \ - --hash=sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd \ - --hash=sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca \ - --hash=sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58 \ - --hash=sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e +rich==13.7.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \ + --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432 +rpds-py==0.20.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c \ + --hash=sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585 \ + --hash=sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5 \ + --hash=sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6 \ + --hash=sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef \ + --hash=sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2 \ + --hash=sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29 \ + --hash=sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318 \ + --hash=sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b \ + --hash=sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399 \ + --hash=sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739 \ + --hash=sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee \ + --hash=sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174 \ + --hash=sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a \ + --hash=sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344 \ + --hash=sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2 \ + --hash=sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03 \ + --hash=sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5 \ + --hash=sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22 \ + --hash=sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e \ + --hash=sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96 \ + --hash=sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91 \ + --hash=sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752 \ + --hash=sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075 \ + --hash=sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253 \ + --hash=sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee \ + --hash=sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad \ + --hash=sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5 \ + --hash=sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce \ + --hash=sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7 \ + --hash=sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b \ + --hash=sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8 \ + --hash=sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57 \ + --hash=sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3 \ + --hash=sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec \ + --hash=sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209 \ + --hash=sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921 \ + --hash=sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045 \ + --hash=sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074 \ + --hash=sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580 \ + --hash=sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7 \ + --hash=sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5 \ + --hash=sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3 \ + --hash=sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0 \ + --hash=sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24 \ + --hash=sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139 \ + --hash=sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db \ + --hash=sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc \ + --hash=sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789 \ + --hash=sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f \ + --hash=sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2 \ + --hash=sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c \ + --hash=sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232 \ + --hash=sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6 \ + --hash=sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c \ + --hash=sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29 \ + --hash=sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489 \ + --hash=sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94 \ + --hash=sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751 \ + --hash=sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2 \ + --hash=sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda \ + --hash=sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9 \ + --hash=sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51 \ + --hash=sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c \ + --hash=sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8 \ + --hash=sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989 \ + --hash=sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511 \ + --hash=sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1 \ + --hash=sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2 \ + --hash=sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150 \ + --hash=sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c \ + --hash=sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965 \ + --hash=sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f \ + --hash=sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58 \ + --hash=sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b \ + --hash=sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f \ + --hash=sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d \ + --hash=sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821 \ + --hash=sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de \ + --hash=sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121 \ + --hash=sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855 \ + --hash=sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272 \ + --hash=sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60 \ + --hash=sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02 \ + --hash=sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1 \ + --hash=sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140 \ + --hash=sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879 \ + --hash=sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940 \ + --hash=sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364 \ + --hash=sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4 \ + --hash=sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e \ + --hash=sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420 \ + --hash=sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5 \ + --hash=sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24 \ + --hash=sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c \ + --hash=sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf \ + --hash=sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f \ + --hash=sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e \ + --hash=sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab \ + --hash=sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08 \ + --hash=sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92 \ + --hash=sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a \ + --hash=sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8 sectxt==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c5b113cb37ec5053bf8ea335306a7c68079b53959df2324ffa9991885bec67a8 \ --hash=sha256:c81d874a55b96516d13e2b688f3150a6089e0636122237e4710717beafcb26d7 -setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ - --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 +setuptools==72.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1 \ + --hash=sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec shodan==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:7e2bddbc1b60bf620042d0010f4b762a80b43111dbea9c041d72d4325e260c23 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 -sniffio==1.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \ - --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384 +sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ + --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc soupsieve==2.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690 \ --hash=sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7 -sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0535d5b57d014d06ceeaeffd816bb3a6e2dddeb670222570b8c4953e2d2ea678 \ - --hash=sha256:0892e7ac8bc76da499ad3ee8de8da4d7905a3110b952e2a35a940dab1ffa550e \ - --hash=sha256:0d661cff58c91726c601cc0ee626bf167b20cc4d7941c93c5f3ac28dc34ddbea \ - --hash=sha256:245c67c88e63f1523e9216cad6ba3107dea2d3ee19adc359597a628afcabfbcb \ - --hash=sha256:2ad16880ccd971ac8e570550fbdef1385e094b022d6fc85ef3ce7df400dddad3 \ - --hash=sha256:2be4e6294c53f2ec8ea36486b56390e3bcaa052bf3a9a47005687ccf376745d1 \ - --hash=sha256:2c55040d8ea65414de7c47f1a23823cd9f3fad0dc93e6b6b728fee81230f817b \ - --hash=sha256:352df882088a55293f621328ec33b6ffca936ad7f23013b22520542e1ab6ad1b \ - --hash=sha256:3823dda635988e6744d4417e13f2e2b5fe76c4bf29dd67e95f98717e1b094cad \ - --hash=sha256:38ef80328e3fee2be0a1abe3fe9445d3a2e52a1282ba342d0dab6edf1fef4707 \ - --hash=sha256:3ec7a0ed9b32afdf337172678a4a0e6419775ba4e649b66f49415615fa47efbd \ - --hash=sha256:55e699466106d09f028ab78d3c2e1f621b5ef2c8694598242259e4515715da7c \ - --hash=sha256:6cacc0b2dd7d22a918a9642fc89840a5d3cee18a0e1fe41080b1141b23b10916 \ - --hash=sha256:7deeae5071930abb3669b5185abb6c33ddfd2398f87660fafdb9e6a5fb0f3f2f \ - --hash=sha256:86a22143a4001f53bf58027b044da1fb10d67b62a785fc1390b5c7f089d9838c \ - --hash=sha256:8ca484ca11c65e05639ffe80f20d45e6be81fbec7683d6c9a15cd421e6e8b340 \ - --hash=sha256:af55cc207865d641a57f7044e98b08b09220da3d1b13a46f26487cc2f898a072 \ - --hash=sha256:b97fd5bb6b7c1a64b7ac0632f7ce389b8ab362e7bd5f60654c2a418496be5d7f \ - --hash=sha256:c37bc677690fd33932182b85d37433845de612962ed080c3e4d92f758d1bd894 \ - --hash=sha256:d3cf56cc36d42908495760b223ca9c2c0f9f0002b4eddc994b24db5fcb86a9e4 \ - --hash=sha256:e646b19f47d655261b22df9976e572f588185279970efba3d45c377127d35349 \ - --hash=sha256:e7908c2025eb18394e32d65dd02d2e37e17d733cdbe7d78231c2b6d7eb20cdb9 \ - --hash=sha256:e8f2df79a46e130235bc5e1bbef4de0583fb19d481eaa0bffa76e8347ea45ec6 \ - --hash=sha256:eb18549b770351b54e1ab5da37d22bc530b8bfe2ee31e22b9ebe650640d2ef12 \ - --hash=sha256:f8cafa6f885a0ff5e39efa9325195217bb47d5929ab0051636610d24aef45ade +sqlalchemy==1.4.53 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0465b8a68f8f4de754c1966c45b187ac784ad97bc9747736f913130f0e1adea0 \ + --hash=sha256:07ba54f09033d387ae9df8d62cbe211ed7304e0bfbece1f8c55e21db9fae5c11 \ + --hash=sha256:122d7b5722df1a24402c6748bbb04687ef981493bb559d0cc0beffe722e0e6ed \ + --hash=sha256:13fc34b35d8ddb3fbe3f8fcfdf6c2546e676187f0fb20f5774da362ddaf8fa2d \ + --hash=sha256:16bb9fa4d00b4581b14d9f0e2224dc7745b854aa4687738279af0f48f7056c98 \ + --hash=sha256:197065b91456574d70b6459bfa62bc0b52a4960a29ef923c375ec427274a3e05 \ + --hash=sha256:1a38834b4c183c33daf58544281395aad2e985f0b47cca1e88ea5ada88344e63 \ + --hash=sha256:1a96aa8d425047551676b0e178ddb0683421e78eda879ab55775128b2e612cae \ + --hash=sha256:2774c24c405136c3ef472e2352bdca7330659d481fbf2283f996c0ef9eb90f22 \ + --hash=sha256:421306c4b936b0271a3ce2dc074928d5ece4a36f9c482daa5770f44ecfc3a883 \ + --hash=sha256:437592b341a3229dd0443c9c803b0bf0a466f8f539014fef6cdb9c06b7edb7f9 \ + --hash=sha256:4604d42b2abccba266d3f5bbe883684b5df93e74054024c70d3fbb5eea45e530 \ + --hash=sha256:4e10ac36f0b994235c13388b39598bf27219ec8bdea5be99bdac612b01cbe525 \ + --hash=sha256:4fe5168d0249c23f537950b6d75935ff2709365a113e29938a979aec36668ecf \ + --hash=sha256:5e6ab710c4c064755fd92d1a417bef360228a19bdf0eee32b03aa0f5f8e9fe0d \ + --hash=sha256:5f67b9e9dcac3241781e96575468d55a42332157dee04bdbf781df573dff5f85 \ + --hash=sha256:616492f5315128a847f293a7c552f3561ac7e996d2aa5dc46bef4fb0d3781f1d \ + --hash=sha256:626be971ff89541cfd3e70b54be00b57a7f8557204decb6223ce0428fec058f3 \ + --hash=sha256:670c7769bf5dcae9aff331247b5d82fe635c63731088a46ce68ba2ba519ef36e \ + --hash=sha256:68a614765197b3d13a730d631a78c3bb9b3b72ba58ed7ab295d58d517464e315 \ + --hash=sha256:6dd06572872ca13ef5a90306a3e5af787498ddaa17fb00109b1243642646cd69 \ + --hash=sha256:784272ceb5eb71421fea9568749bcbe8bd019261a0e2e710a7efa76057af2499 \ + --hash=sha256:83a9c3514ff19d9d30d8a8d378b24cd1dfa5528d20891481cb5f196117db6a48 \ + --hash=sha256:86b11640251f9a9789fd96cd6e5d176b1c230230c70ad40299bcbcc568451b4c \ + --hash=sha256:89d8ac4158ef68eea8bb0f6dd0583127d9aa8720606964ba8eee20b254f9c83a \ + --hash=sha256:8b8608d162d3bd29d807aab32c3fb6e2f8e225a43d1c54c917fed38513785380 \ + --hash=sha256:93e90aa3e3b2f8e8cbae4d5509f8e0cf82972378d323c740a8df1c1e9f484172 \ + --hash=sha256:95123f3a1e0e8020848fd32ba751db889a01a44e4e4fef7e58c87ddd0b2fca59 \ + --hash=sha256:991e42fdfec561ebc6a4fae7161a86d129d6069fa14210b96b8dd752afa7059c \ + --hash=sha256:9d7368df54d3ed45a18955f6cec38ebe075290594ac0d5c87a8ddaff7e10de27 \ + --hash=sha256:a8c2f2a0b2c4e3b86eb58c9b6bb98548205eea2fba9dae4edfd29dc6aebbe95a \ + --hash=sha256:a9d4d132198844bd6828047135ce7b887687c92925049a2468a605fc775c7a1a \ + --hash=sha256:b61ac5457d91b5629a3dea2b258deb4cdd35ac8f6fa2031d2b9b2fff5b3396da \ + --hash=sha256:bc8be4df55e8fde3006d9cb1f6b3df2ba26db613855dc4df2c0fcd5ec15cb3b7 \ + --hash=sha256:c05fe05941424c2f3747a8952381b7725e24cba2ca00141380e54789d5b616b6 \ + --hash=sha256:c0cf8c0af9563892c6632f7343bc393dfce6eeef8e4d10c5fadba9c0390520bd \ + --hash=sha256:c15d1f1fcf1f9bec0499ae1d9132b950fcc7730f2d26d10484c8808b4e077816 \ + --hash=sha256:c58e011e9e6373b3a091d83f20601fb335a3b4bace80bfcb914ac168aad3b70d \ + --hash=sha256:cd534c716f86bdf95b7b984a34ee278c91d1b1d7d183e7e5ff878600b1696046 \ + --hash=sha256:d021699b9007deb7aa715629078830c99a5fec2753d9bdd5ff33290d363ef755 \ + --hash=sha256:d13d4dfbc6e52363886b47cf02cf68c5d2a37c468626694dc210d7e97d4ad330 \ + --hash=sha256:eaaeedbceb4dfd688fff2faf25a9a87a391f548811494f7bff7fa701b639abc3 \ + --hash=sha256:edf094a20a386ff2ec73de65ef18014b250259cb860edc61741e240ca22d6981 \ + --hash=sha256:fb8e15dfa47f5de11ab073e12aadd6b502cfb7ac4bafd18bd18cfd1c7d13dbbc starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 diff --git a/boefjes/requirements.txt b/boefjes/requirements.txt index e1cb8dbf195..095b0a7ca16 100644 --- a/boefjes/requirements.txt +++ b/boefjes/requirements.txt @@ -1,107 +1,110 @@ -aiohttp==3.9.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8 \ - --hash=sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c \ - --hash=sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475 \ - --hash=sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed \ - --hash=sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf \ - --hash=sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372 \ - --hash=sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81 \ - --hash=sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f \ - --hash=sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1 \ - --hash=sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd \ - --hash=sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a \ - --hash=sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb \ - --hash=sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46 \ - --hash=sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de \ - --hash=sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78 \ - --hash=sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c \ - --hash=sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771 \ - --hash=sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb \ - --hash=sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430 \ - --hash=sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233 \ - --hash=sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156 \ - --hash=sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9 \ - --hash=sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59 \ - --hash=sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888 \ - --hash=sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c \ - --hash=sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c \ - --hash=sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da \ - --hash=sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424 \ - --hash=sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2 \ - --hash=sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb \ - --hash=sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8 \ - --hash=sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a \ - --hash=sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10 \ - --hash=sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0 \ - --hash=sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09 \ - --hash=sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031 \ - --hash=sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4 \ - --hash=sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3 \ - --hash=sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa \ - --hash=sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a \ - --hash=sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe \ - --hash=sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a \ - --hash=sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2 \ - --hash=sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1 \ - --hash=sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323 \ - --hash=sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b \ - --hash=sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b \ - --hash=sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106 \ - --hash=sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac \ - --hash=sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6 \ - --hash=sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832 \ - --hash=sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75 \ - --hash=sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6 \ - --hash=sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d \ - --hash=sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72 \ - --hash=sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db \ - --hash=sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a \ - --hash=sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da \ - --hash=sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678 \ - --hash=sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b \ - --hash=sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24 \ - --hash=sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed \ - --hash=sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f \ - --hash=sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e \ - --hash=sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58 \ - --hash=sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a \ - --hash=sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342 \ - --hash=sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558 \ - --hash=sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2 \ - --hash=sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551 \ - --hash=sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595 \ - --hash=sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee \ - --hash=sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11 \ - --hash=sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d \ - --hash=sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7 \ - --hash=sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f +aiohappyeyeballs==2.3.5 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4d6dea59215537dbc746e93e779caea8178c866856a721c9c660d7a5a7b8be03 \ + --hash=sha256:6fa48b9f1317254f122a07a131a86b71ca6946ca989ce6326fff54a99a920105 +aiohttp==3.10.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01c3f1eb280008e51965a8d160a108c333136f4a39d46f516c64d2aa2e6a53f2 \ + --hash=sha256:028faf71b338f069077af6315ad54281612705d68889f5d914318cbc2aab0d50 \ + --hash=sha256:03c0c380c83f8a8d4416224aafb88d378376d6f4cadebb56b060688251055cd4 \ + --hash=sha256:0df51a3d70a2bfbb9c921619f68d6d02591f24f10e9c76de6f3388c89ed01de6 \ + --hash=sha256:120548d89f14b76a041088b582454d89389370632ee12bf39d919cc5c561d1ca \ + --hash=sha256:1988b370536eb14f0ce7f3a4a5b422ab64c4e255b3f5d7752c5f583dc8c967fc \ + --hash=sha256:1a07c76a82390506ca0eabf57c0540cf5a60c993c442928fe4928472c4c6e5e6 \ + --hash=sha256:1c2b104e81b3c3deba7e6f5bc1a9a0e9161c380530479970766a6655b8b77c7c \ + --hash=sha256:1c577cdcf8f92862363b3d598d971c6a84ed8f0bf824d4cc1ce70c2fb02acb4a \ + --hash=sha256:1f8605e573ed6c44ec689d94544b2c4bb1390aaa723a8b5a2cc0a5a485987a68 \ + --hash=sha256:21778552ef3d44aac3278cc6f6d13a6423504fa5f09f2df34bfe489ed9ded7f5 \ + --hash=sha256:2212296cdb63b092e295c3e4b4b442e7b7eb41e8a30d0f53c16d5962efed395d \ + --hash=sha256:222821c60b8f6a64c5908cb43d69c0ee978a1188f6a8433d4757d39231b42cdb \ + --hash=sha256:256ee6044214ee9d66d531bb374f065ee94e60667d6bbeaa25ca111fc3997158 \ + --hash=sha256:2a384dfbe8bfebd203b778a30a712886d147c61943675f4719b56725a8bbe803 \ + --hash=sha256:2fa643ca990323db68911b92f3f7a0ca9ae300ae340d0235de87c523601e58d9 \ + --hash=sha256:41d8dab8c64ded1edf117d2a64f353efa096c52b853ef461aebd49abae979f16 \ + --hash=sha256:440954ddc6b77257e67170d57b1026aa9545275c33312357472504eef7b4cc0b \ + --hash=sha256:47b4c2412960e64d97258f40616efddaebcb34ff664c8a972119ed38fac2a62c \ + --hash=sha256:4a9ce70f5e00380377aac0e568abd075266ff992be2e271765f7b35d228a990c \ + --hash=sha256:4dcb127ca3eb0a61205818a606393cbb60d93b7afb9accd2fd1e9081cc533144 \ + --hash=sha256:4e9e9171d2fe6bfd9d3838a6fe63b1e91b55e0bf726c16edf265536e4eafed19 \ + --hash=sha256:51d03e948e53b3639ce4d438f3d1d8202898ec6655cadcc09ec99229d4adc2a9 \ + --hash=sha256:54b7f4a20d7cc6bfa4438abbde069d417bb7a119f870975f78a2b99890226d55 \ + --hash=sha256:587237571a85716d6f71f60d103416c9df7d5acb55d96d3d3ced65f39bff9c0c \ + --hash=sha256:5951c328f9ac42d7bce7a6ded535879bc9ae13032818d036749631fa27777905 \ + --hash=sha256:5a95151a5567b3b00368e99e9c5334a919514f60888a6b6d2054fea5e66e527e \ + --hash=sha256:5c12310d153b27aa630750be44e79313acc4e864c421eb7d2bc6fa3429c41bf8 \ + --hash=sha256:5cd57ad998e3038aa87c38fe85c99ed728001bf5dde8eca121cadee06ee3f637 \ + --hash=sha256:615348fab1a9ef7d0960a905e83ad39051ae9cb0d2837da739b5d3a7671e497a \ + --hash=sha256:67f7639424c313125213954e93a6229d3a1d386855d70c292a12628f600c7150 \ + --hash=sha256:68164d43c580c2e8bf8e0eb4960142919d304052ccab92be10250a3a33b53268 \ + --hash=sha256:68cc24f707ed9cb961f6ee04020ca01de2c89b2811f3cf3361dc7c96a14bfbcc \ + --hash=sha256:6b14c19172eb53b63931d3e62a9749d6519f7c121149493e6eefca055fcdb352 \ + --hash=sha256:777e23609899cb230ad2642b4bdf1008890f84968be78de29099a8a86f10b261 \ + --hash=sha256:786299d719eb5d868f161aeec56d589396b053925b7e0ce36e983d30d0a3e55c \ + --hash=sha256:7ccf1f0a304352c891d124ac1a9dea59b14b2abed1704aaa7689fc90ef9c5be1 \ + --hash=sha256:88596384c3bec644a96ae46287bb646d6a23fa6014afe3799156aef42669c6bd \ + --hash=sha256:89b47c125ab07f0831803b88aeb12b04c564d5f07a1c1a225d4eb4d2f26e8b5e \ + --hash=sha256:8b0d058e4e425d3b45e8ec70d49b402f4d6b21041e674798b1f91ba027c73f28 \ + --hash=sha256:8c81ff4afffef9b1186639506d70ea90888218f5ddfff03870e74ec80bb59970 \ + --hash=sha256:8db9b749f589b5af8e4993623dbda6716b2b7a5fcb0fa2277bf3ce4b278c7059 \ + --hash=sha256:8e5a26d7aac4c0d8414a347da162696eea0629fdce939ada6aedf951abb1d745 \ + --hash=sha256:8fbf8c0ded367c5c8eaf585f85ca8dd85ff4d5b73fb8fe1e6ac9e1b5e62e11f7 \ + --hash=sha256:93094eba50bc2ad4c40ff4997ead1fdcd41536116f2e7d6cfec9596a8ecb3615 \ + --hash=sha256:9c186b270979fb1dee3ababe2d12fb243ed7da08b30abc83ebac3a928a4ddb15 \ + --hash=sha256:9cb54f5725b4b37af12edf6c9e834df59258c82c15a244daa521a065fbb11717 \ + --hash=sha256:9fbff00646cf8211b330690eb2fd64b23e1ce5b63a342436c1d1d6951d53d8dd \ + --hash=sha256:a57e73f9523e980f6101dc9a83adcd7ac0006ea8bf7937ca3870391c7bb4f8ff \ + --hash=sha256:a702bd3663b5cbf3916e84bf332400d24cdb18399f0877ca6b313ce6c08bfb43 \ + --hash=sha256:a77c79bac8d908d839d32c212aef2354d2246eb9deb3e2cb01ffa83fb7a6ea5d \ + --hash=sha256:abda4009a30d51d3f06f36bc7411a62b3e647fa6cc935ef667e3e3d3a7dd09b1 \ + --hash=sha256:b023b68c61ab0cd48bd38416b421464a62c381e32b9dc7b4bdfa2905807452a4 \ + --hash=sha256:b07286a1090483799599a2f72f76ac396993da31f6e08efedb59f40876c144fa \ + --hash=sha256:b0de63ff0307eac3961b4af74382d30220d4813f36b7aaaf57f063a1243b4214 \ + --hash=sha256:b7d5bb926805022508b7ddeaad957f1fce7a8d77532068d7bdb431056dc630cd \ + --hash=sha256:b9db600a86414a9a653e3c1c7f6a2f6a1894ab8f83d11505247bd1b90ad57157 \ + --hash=sha256:b9fb6508893dc31cfcbb8191ef35abd79751db1d6871b3e2caee83959b4d91eb \ + --hash=sha256:bc3ea6ef2a83edad84bbdb5d96e22f587b67c68922cd7b6f9d8f24865e655bcf \ + --hash=sha256:bde0693073fd5e542e46ea100aa6c1a5d36282dbdbad85b1c3365d5421490a92 \ + --hash=sha256:bf66149bb348d8e713f3a8e0b4f5b952094c2948c408e1cfef03b49e86745d60 \ + --hash=sha256:bfe33cba6e127d0b5b417623c9aa621f0a69f304742acdca929a9fdab4593693 \ + --hash=sha256:c8fb76214b5b739ce59e2236a6489d9dc3483649cfd6f563dbf5d8e40dbdd57d \ + --hash=sha256:cb8b79a65332e1a426ccb6290ce0409e1dc16b4daac1cc5761e059127fa3d134 \ + --hash=sha256:d6bbe2c90c10382ca96df33b56e2060404a4f0f88673e1e84b44c8952517e5f3 \ + --hash=sha256:d8311d0d690487359fe2247ec5d2cac9946e70d50dced8c01ce9e72341c21151 \ + --hash=sha256:d8a8221a63602008550022aa3a4152ca357e1dde7ab3dd1da7e1925050b56863 \ + --hash=sha256:de1a91d5faded9054957ed0a9e01b9d632109341942fc123947ced358c5d9009 \ + --hash=sha256:df31641e3f02b77eb3c5fb63c0508bee0fc067cf153da0e002ebbb0db0b6d91a \ + --hash=sha256:e7168782621be4448d90169a60c8b37e9b0926b3b79b6097bc180c0a8a119e73 \ + --hash=sha256:e7b55d9ede66af7feb6de87ff277e0ccf6d51c7db74cc39337fe3a0e31b5872d \ + --hash=sha256:e7dbf637f87dd315fa1f36aaed8afa929ee2c607454fb7791e74c88a0d94da59 \ + --hash=sha256:f5293726943bdcea24715b121d8c4ae12581441d22623b0e6ab12d07ce85f9c4 \ + --hash=sha256:f5dd109a925fee4c9ac3f6a094900461a2712df41745f5d04782ebcbe6479ccb \ + --hash=sha256:f6979b4f20d3e557a867da9d9227de4c156fcdcb348a5848e3e6190fd7feb972 \ + --hash=sha256:f9f8beed277488a52ee2b459b23c4135e54d6a819eaba2e120e57311015b58e9 aioresponses==0.7.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d2c26defbb9b440ea2685ec132e90700907fd10bcca3e85ec2f157219f0d26f7 \ --hash=sha256:f795d9dbda2d61774840e7e32f5366f45752d1adc1b74c9362afd017296c7ee1 aiosignal==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc \ --hash=sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17 -alembic==1.13.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43 \ - --hash=sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595 +alembic==1.13.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef \ + --hash=sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953 annotated-types==0.7.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \ --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89 ansicolors==1.1.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:00d2dde5a675579325902536738dd27e4fac1fd68f773fe36c21044eb559e187 \ --hash=sha256:99f94f5e3348a0bcd43c82e5fc4414013ccc19d70bd939ad71e0133ce9c372e0 -anyio==4.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8 \ - --hash=sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6 -asgiref==3.7.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \ - --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed +anyio==4.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94 \ + --hash=sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7 +asgiref==3.8.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \ + --hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590 async-timeout==4.0.3 ; python_version >= "3.10" and python_version < "3.11" \ --hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \ --hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028 -attrs==23.2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \ - --hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1 +attrs==24.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ + --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2 backoff==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba \ --hash=sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8 @@ -114,59 +117,74 @@ censys==2.1.8 ; python_version >= "3.10" and python_version < "4.0" \ certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 -cffi==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ - --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ - --hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \ - --hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \ - --hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \ - --hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \ - --hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \ - --hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \ - --hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \ - --hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \ - --hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \ - --hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \ - --hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \ - --hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \ - --hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \ - --hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \ - --hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \ - --hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \ - --hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \ - --hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \ - --hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \ - --hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \ - --hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \ - --hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \ - --hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \ - --hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \ - --hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \ - --hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \ - --hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \ - --hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \ - --hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \ - --hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \ - --hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \ - --hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \ - --hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \ - --hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \ - --hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \ - --hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \ - --hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \ - --hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \ - --hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \ - --hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \ - --hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \ - --hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \ - --hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \ - --hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \ - --hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \ - --hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \ - --hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \ - --hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \ - --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \ - --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357 +cffi==1.17.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f \ + --hash=sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab \ + --hash=sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499 \ + --hash=sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058 \ + --hash=sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693 \ + --hash=sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb \ + --hash=sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377 \ + --hash=sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885 \ + --hash=sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2 \ + --hash=sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401 \ + --hash=sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4 \ + --hash=sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b \ + --hash=sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59 \ + --hash=sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f \ + --hash=sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c \ + --hash=sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555 \ + --hash=sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa \ + --hash=sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424 \ + --hash=sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb \ + --hash=sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2 \ + --hash=sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8 \ + --hash=sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e \ + --hash=sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9 \ + --hash=sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82 \ + --hash=sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828 \ + --hash=sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759 \ + --hash=sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc \ + --hash=sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118 \ + --hash=sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf \ + --hash=sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932 \ + --hash=sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a \ + --hash=sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29 \ + --hash=sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206 \ + --hash=sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2 \ + --hash=sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c \ + --hash=sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c \ + --hash=sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0 \ + --hash=sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a \ + --hash=sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195 \ + --hash=sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6 \ + --hash=sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9 \ + --hash=sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc \ + --hash=sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb \ + --hash=sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0 \ + --hash=sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7 \ + --hash=sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb \ + --hash=sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a \ + --hash=sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492 \ + --hash=sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720 \ + --hash=sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42 \ + --hash=sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7 \ + --hash=sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d \ + --hash=sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d \ + --hash=sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb \ + --hash=sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4 \ + --hash=sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2 \ + --hash=sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b \ + --hash=sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8 \ + --hash=sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e \ + --hash=sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204 \ + --hash=sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3 \ + --hash=sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150 \ + --hash=sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4 \ + --hash=sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76 \ + --hash=sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e \ + --hash=sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb \ + --hash=sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91 charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ @@ -267,9 +285,9 @@ click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 -configparser==6.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:900ea2bb01b2540b1a644ad3d5351e9b961a4a012d4732f619375fb8f641ee19 \ - --hash=sha256:ec914ab1e56c672de1f5c3483964e68f71b34e457904b7b76e06b922aec067a8 +configparser==7.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:af3c618a67aaaedc4d689fd7317d238f566b9aa03cae50102e92d7f0dfe78ba0 \ + --hash=sha256:f46d52a12811c637104c6bb8eb33693be0038ab6bf01d69aae009c39ec8c2017 cryptography==42.0.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ @@ -318,15 +336,15 @@ dnspython==2.6.1 ; python_version >= "3.10" and python_version < "4.0" \ docker==7.1.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c \ --hash=sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0 -exceptiongroup==1.2.0 ; python_version >= "3.10" and python_version < "3.11" \ - --hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14 \ - --hash=sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68 +exceptiongroup==1.2.2 ; python_version >= "3.10" and python_version < "3.11" \ + --hash=sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b \ + --hash=sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d -filelock==3.13.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e \ - --hash=sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c +filelock==3.15.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb \ + --hash=sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7 forcediphttpsadapter==1.1.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0d224cf6e8e50eb788c9f5994a7afa6d389bac6dbe540b7dfd77a32590ad0153 \ --hash=sha256:5e7662ece61735585332d09b87d94fffe4752469d5c0d3feff48746e5d70744b @@ -408,9 +426,9 @@ frozenlist==1.4.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887 \ --hash=sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced \ --hash=sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74 -googleapis-common-protos==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07 \ - --hash=sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277 +googleapis-common-protos==1.63.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945 \ + --hash=sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87 greenlet==3.0.3 ; python_version >= "3.10" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "4.0" \ --hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \ --hash=sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6 \ @@ -470,61 +488,53 @@ greenlet==3.0.3 ; python_version >= "3.10" and (platform_machine == "aarch64" or --hash=sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf \ --hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \ --hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33 -grpcio==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701 \ - --hash=sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e \ - --hash=sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532 \ - --hash=sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a \ - --hash=sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271 \ - --hash=sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f \ - --hash=sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7 \ - --hash=sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b \ - --hash=sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4 \ - --hash=sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839 \ - --hash=sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6 \ - --hash=sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb \ - --hash=sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e \ - --hash=sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93 \ - --hash=sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f \ - --hash=sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6 \ - --hash=sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1 \ - --hash=sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35 \ - --hash=sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842 \ - --hash=sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6 \ - --hash=sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c \ - --hash=sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873 \ - --hash=sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7 \ - --hash=sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c \ - --hash=sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928 \ - --hash=sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9 \ - --hash=sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c \ - --hash=sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021 \ - --hash=sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa \ - --hash=sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38 \ - --hash=sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc \ - --hash=sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe \ - --hash=sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8 \ - --hash=sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402 \ - --hash=sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388 \ - --hash=sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0 \ - --hash=sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b \ - --hash=sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b \ - --hash=sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2 \ - --hash=sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b \ - --hash=sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5 \ - --hash=sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829 \ - --hash=sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2 \ - --hash=sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6 \ - --hash=sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd \ - --hash=sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0 \ - --hash=sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8 \ - --hash=sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334 \ - --hash=sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee \ - --hash=sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c \ - --hash=sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72 \ - --hash=sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4 \ - --hash=sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270 \ - --hash=sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170 +grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ + --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ + --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ + --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ + --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ + --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ + --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ + --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ + --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ + --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ + --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ + --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ + --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ + --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ + --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ + --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ + --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ + --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ + --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ + --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ + --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ + --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ + --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ + --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ + --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ + --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ + --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ + --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ + --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ + --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ + --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ + --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ + --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ + --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ + --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ + --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ + --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ + --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ + --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ + --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ + --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ + --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ + --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ + --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ + --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ + --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -539,100 +549,256 @@ httpx==0.27.0 ; python_version >= "3.10" and python_version < "4.0" \ idna==3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 -importlib-metadata==6.11.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:1231cf92d825c9e03cfc4da076a16de6422c863558229ea0b22b675657463443 \ - --hash=sha256:f0afba6205ad8f8947c7d338b5342d5db2afbfd82f9cbef7879a9539cc12eb9b +importlib-metadata==8.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f \ + --hash=sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812 jsonschema-specifications==2023.12.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc \ --hash=sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c -jsonschema==4.21.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f \ - --hash=sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5 -langcodes==3.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4d89fc9acb6e9c8fdef70bcdf376113a3db09b67285d9e1d534de6d8818e7e69 \ - --hash=sha256:794d07d5a28781231ac335a1561b8442f8648ca07cd518310aeb45d6f0807ef6 -lxml==5.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:13521a321a25c641b9ea127ef478b580b5ec82aa2e9fc076c86169d161798b01 \ - --hash=sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f \ - --hash=sha256:16018f7099245157564d7148165132c70adb272fb5a17c048ba70d9cc542a1a1 \ - --hash=sha256:16dd953fb719f0ffc5bc067428fc9e88f599e15723a85618c45847c96f11f431 \ - --hash=sha256:19a1bc898ae9f06bccb7c3e1dfd73897ecbbd2c96afe9095a6026016e5ca97b8 \ - --hash=sha256:1ad17c20e3666c035db502c78b86e58ff6b5991906e55bdbef94977700c72623 \ - --hash=sha256:22b7ee4c35f374e2c20337a95502057964d7e35b996b1c667b5c65c567d2252a \ - --hash=sha256:24ef5a4631c0b6cceaf2dbca21687e29725b7c4e171f33a8f8ce23c12558ded1 \ - --hash=sha256:25663d6e99659544ee8fe1b89b1a8c0aaa5e34b103fab124b17fa958c4a324a6 \ - --hash=sha256:262bc5f512a66b527d026518507e78c2f9c2bd9eb5c8aeeb9f0eb43fcb69dc67 \ - --hash=sha256:280f3edf15c2a967d923bcfb1f8f15337ad36f93525828b40a0f9d6c2ad24890 \ - --hash=sha256:2ad3a8ce9e8a767131061a22cd28fdffa3cd2dc193f399ff7b81777f3520e372 \ - --hash=sha256:2befa20a13f1a75c751f47e00929fb3433d67eb9923c2c0b364de449121f447c \ - --hash=sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb \ - --hash=sha256:304128394c9c22b6569eba2a6d98392b56fbdfbad58f83ea702530be80d0f9df \ - --hash=sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84 \ - --hash=sha256:3aeca824b38ca78d9ee2ab82bd9883083d0492d9d17df065ba3b94e88e4d7ee6 \ - --hash=sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45 \ - --hash=sha256:3e3898ae2b58eeafedfe99e542a17859017d72d7f6a63de0f04f99c2cb125936 \ - --hash=sha256:3eea6ed6e6c918e468e693c41ef07f3c3acc310b70ddd9cc72d9ef84bc9564ca \ - --hash=sha256:3f14a4fb1c1c402a22e6a341a24c1341b4a3def81b41cd354386dcb795f83897 \ - --hash=sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a \ - --hash=sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d \ - --hash=sha256:49a9b4af45e8b925e1cd6f3b15bbba2c81e7dba6dce170c677c9cda547411e14 \ - --hash=sha256:4f8b0c78e7aac24979ef09b7f50da871c2de2def043d468c4b41f512d831e912 \ - --hash=sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354 \ - --hash=sha256:5e53d7e6a98b64fe54775d23a7c669763451340c3d44ad5e3a3b48a1efbdc96f \ - --hash=sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c \ - --hash=sha256:601f4a75797d7a770daed8b42b97cd1bb1ba18bd51a9382077a6a247a12aa38d \ - --hash=sha256:61c5a7edbd7c695e54fca029ceb351fc45cd8860119a0f83e48be44e1c464862 \ - --hash=sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969 \ - --hash=sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e \ - --hash=sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8 \ - --hash=sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e \ - --hash=sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa \ - --hash=sha256:7cfced4a069003d8913408e10ca8ed092c49a7f6cefee9bb74b6b3e860683b45 \ - --hash=sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a \ - --hash=sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147 \ - --hash=sha256:82cd34f1081ae4ea2ede3d52f71b7be313756e99b4b5f829f89b12da552d3aa3 \ - --hash=sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3 \ - --hash=sha256:877efb968c3d7eb2dad540b6cabf2f1d3c0fbf4b2d309a3c141f79c7e0061324 \ - --hash=sha256:8b9f19df998761babaa7f09e6bc169294eefafd6149aaa272081cbddc7ba4ca3 \ - --hash=sha256:8cf5877f7ed384dabfdcc37922c3191bf27e55b498fecece9fd5c2c7aaa34c33 \ - --hash=sha256:8d2900b7f5318bc7ad8631d3d40190b95ef2aa8cc59473b73b294e4a55e9f30f \ - --hash=sha256:8d7b4beebb178e9183138f552238f7e6613162a42164233e2bda00cb3afac58f \ - --hash=sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764 \ - --hash=sha256:98f3f020a2b736566c707c8e034945c02aa94e124c24f77ca097c446f81b01f1 \ - --hash=sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114 \ - --hash=sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581 \ - --hash=sha256:9bcf86dfc8ff3e992fed847c077bd875d9e0ba2fa25d859c3a0f0f76f07f0c8d \ - --hash=sha256:9bd0ae7cc2b85320abd5e0abad5ccee5564ed5f0cc90245d2f9a8ef330a8deae \ - --hash=sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da \ - --hash=sha256:9e5ac3437746189a9b4121db2a7b86056ac8786b12e88838696899328fc44bb2 \ - --hash=sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e \ - --hash=sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda \ - --hash=sha256:a96f02ba1bcd330807fc060ed91d1f7a20853da6dd449e5da4b09bfcc08fdcf5 \ - --hash=sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa \ - --hash=sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1 \ - --hash=sha256:af8920ce4a55ff41167ddbc20077f5698c2e710ad3353d32a07d3264f3a2021e \ - --hash=sha256:afd825e30f8d1f521713a5669b63657bcfe5980a916c95855060048b88e1adb7 \ - --hash=sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1 \ - --hash=sha256:b4b68c961b5cc402cbd99cca5eb2547e46ce77260eb705f4d117fd9c3f932b95 \ - --hash=sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93 \ - --hash=sha256:b9e240ae0ba96477682aa87899d94ddec1cc7926f9df29b1dd57b39e797d5ab5 \ - --hash=sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b \ - --hash=sha256:bf8443781533b8d37b295016a4b53c1494fa9a03573c09ca5104550c138d5c05 \ - --hash=sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5 \ - --hash=sha256:c3cd1fc1dc7c376c54440aeaaa0dcc803d2126732ff5c6b68ccd619f2e64be4f \ - --hash=sha256:c7257171bb8d4432fe9d6fdde4d55fdbe663a63636a17f7f9aaba9bcb3153ad7 \ - --hash=sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8 \ - --hash=sha256:d74fcaf87132ffc0447b3c685a9f862ffb5b43e70ea6beec2fb8057d5d2a1fea \ - --hash=sha256:d8c1d679df4361408b628f42b26a5d62bd3e9ba7f0c0e7969f925021554755aa \ - --hash=sha256:e856c1c7255c739434489ec9c8aa9cdf5179785d10ff20add308b5d673bed5cd \ - --hash=sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b \ - --hash=sha256:ed7326563024b6e91fef6b6c7a1a2ff0a71b97793ac33dbbcf38f6005e51ff6e \ - --hash=sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4 \ - --hash=sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204 \ - --hash=sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a -mako==1.3.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e \ - --hash=sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c +jsonschema==4.23.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4 \ + --hash=sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566 +langcodes==3.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:10a4cc078b8e8937d8485d3352312a0a89a3125190db9f2bb2074250eef654e9 \ + --hash=sha256:ae5a77d1a01d0d1e91854a671890892b7ce9abb601ab7327fc5c874f899e1979 +language-data==1.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:77d5cab917f91ee0b2f1aa7018443e911cf8985ef734ca2ba3940770f6a3816b \ + --hash=sha256:82a86050bbd677bfde87d97885b17566cfe75dad3ac4f5ce44b52c28f752e773 +lxml==5.2.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02437fb7308386867c8b7b0e5bc4cd4b04548b1c5d089ffb8e7b31009b961dc3 \ + --hash=sha256:02f6a8eb6512fdc2fd4ca10a49c341c4e109aa6e9448cc4859af5b949622715a \ + --hash=sha256:05f8757b03208c3f50097761be2dea0aba02e94f0dc7023ed73a7bb14ff11eb0 \ + --hash=sha256:06668e39e1f3c065349c51ac27ae430719d7806c026fec462e5693b08b95696b \ + --hash=sha256:07542787f86112d46d07d4f3c4e7c760282011b354d012dc4141cc12a68cef5f \ + --hash=sha256:08ea0f606808354eb8f2dfaac095963cb25d9d28e27edcc375d7b30ab01abbf6 \ + --hash=sha256:0969e92af09c5687d769731e3f39ed62427cc72176cebb54b7a9d52cc4fa3b73 \ + --hash=sha256:0a028b61a2e357ace98b1615fc03f76eb517cc028993964fe08ad514b1e8892d \ + --hash=sha256:0b3f5016e00ae7630a4b83d0868fca1e3d494c78a75b1c7252606a3a1c5fc2ad \ + --hash=sha256:13e69be35391ce72712184f69000cda04fc89689429179bc4c0ae5f0b7a8c21b \ + --hash=sha256:16a8326e51fcdffc886294c1e70b11ddccec836516a343f9ed0f82aac043c24a \ + --hash=sha256:19b4e485cd07b7d83e3fe3b72132e7df70bfac22b14fe4bf7a23822c3a35bff5 \ + --hash=sha256:1a2569a1f15ae6c8c64108a2cd2b4a858fc1e13d25846be0666fc144715e32ab \ + --hash=sha256:1a7aca7964ac4bb07680d5c9d63b9d7028cace3e2d43175cb50bba8c5ad33316 \ + --hash=sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6 \ + --hash=sha256:1d8a701774dfc42a2f0b8ccdfe7dbc140500d1049e0632a611985d943fcf12df \ + --hash=sha256:1e275ea572389e41e8b039ac076a46cb87ee6b8542df3fff26f5baab43713bca \ + --hash=sha256:2304d3c93f2258ccf2cf7a6ba8c761d76ef84948d87bf9664e14d203da2cd264 \ + --hash=sha256:23441e2b5339bc54dc949e9e675fa35efe858108404ef9aa92f0456929ef6fe8 \ + --hash=sha256:23cfafd56887eaed93d07bc4547abd5e09d837a002b791e9767765492a75883f \ + --hash=sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b \ + --hash=sha256:2eb2227ce1ff998faf0cd7fe85bbf086aa41dfc5af3b1d80867ecfe75fb68df3 \ + --hash=sha256:2fb0ba3e8566548d6c8e7dd82a8229ff47bd8fb8c2da237607ac8e5a1b8312e5 \ + --hash=sha256:303f540ad2dddd35b92415b74b900c749ec2010e703ab3bfd6660979d01fd4ed \ + --hash=sha256:339ee4a4704bc724757cd5dd9dc8cf4d00980f5d3e6e06d5847c1b594ace68ab \ + --hash=sha256:33ce9e786753743159799fdf8e92a5da351158c4bfb6f2db0bf31e7892a1feb5 \ + --hash=sha256:343ab62e9ca78094f2306aefed67dcfad61c4683f87eee48ff2fd74902447726 \ + --hash=sha256:34e17913c431f5ae01d8658dbf792fdc457073dcdfbb31dc0cc6ab256e664a8d \ + --hash=sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632 \ + --hash=sha256:38b67afb0a06b8575948641c1d6d68e41b83a3abeae2ca9eed2ac59892b36706 \ + --hash=sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8 \ + --hash=sha256:3b019d4ee84b683342af793b56bb35034bd749e4cbdd3d33f7d1107790f8c472 \ + --hash=sha256:3b6a30a9ab040b3f545b697cb3adbf3696c05a3a68aad172e3fd7ca73ab3c835 \ + --hash=sha256:3d1e35572a56941b32c239774d7e9ad724074d37f90c7a7d499ab98761bd80cf \ + --hash=sha256:3d98de734abee23e61f6b8c2e08a88453ada7d6486dc7cdc82922a03968928db \ + --hash=sha256:453d037e09a5176d92ec0fd282e934ed26d806331a8b70ab431a81e2fbabf56d \ + --hash=sha256:45f9494613160d0405682f9eee781c7e6d1bf45f819654eb249f8f46a2c22545 \ + --hash=sha256:4820c02195d6dfb7b8508ff276752f6b2ff8b64ae5d13ebe02e7667e035000b9 \ + --hash=sha256:49095a38eb333aaf44c06052fd2ec3b8f23e19747ca7ec6f6c954ffea6dbf7be \ + --hash=sha256:4aefd911793b5d2d7a921233a54c90329bf3d4a6817dc465f12ffdfe4fc7b8fe \ + --hash=sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905 \ + --hash=sha256:4c30a2f83677876465f44c018830f608fa3c6a8a466eb223535035fbc16f3438 \ + --hash=sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db \ + --hash=sha256:50ccb5d355961c0f12f6cf24b7187dbabd5433f29e15147a67995474f27d1776 \ + --hash=sha256:519895c99c815a1a24a926d5b60627ce5ea48e9f639a5cd328bda0515ea0f10c \ + --hash=sha256:54401c77a63cc7d6dc4b4e173bb484f28a5607f3df71484709fe037c92d4f0ed \ + --hash=sha256:546cf886f6242dff9ec206331209db9c8e1643ae642dea5fdbecae2453cb50fd \ + --hash=sha256:55ce6b6d803890bd3cc89975fca9de1dff39729b43b73cb15ddd933b8bc20484 \ + --hash=sha256:56793b7a1a091a7c286b5f4aa1fe4ae5d1446fe742d00cdf2ffb1077865db10d \ + --hash=sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6 \ + --hash=sha256:5b8c041b6265e08eac8a724b74b655404070b636a8dd6d7a13c3adc07882ef30 \ + --hash=sha256:5e097646944b66207023bc3c634827de858aebc226d5d4d6d16f0b77566ea182 \ + --hash=sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61 \ + --hash=sha256:610b5c77428a50269f38a534057444c249976433f40f53e3b47e68349cca1425 \ + --hash=sha256:625e3ef310e7fa3a761d48ca7ea1f9d8718a32b1542e727d584d82f4453d5eeb \ + --hash=sha256:657a972f46bbefdbba2d4f14413c0d079f9ae243bd68193cb5061b9732fa54c1 \ + --hash=sha256:69ab77a1373f1e7563e0fb5a29a8440367dec051da6c7405333699d07444f511 \ + --hash=sha256:6a520b4f9974b0a0a6ed73c2154de57cdfd0c8800f4f15ab2b73238ffed0b36e \ + --hash=sha256:6d68ce8e7b2075390e8ac1e1d3a99e8b6372c694bbe612632606d1d546794207 \ + --hash=sha256:6dcc3d17eac1df7859ae01202e9bb11ffa8c98949dcbeb1069c8b9a75917e01b \ + --hash=sha256:6dfdc2bfe69e9adf0df4915949c22a25b39d175d599bf98e7ddf620a13678585 \ + --hash=sha256:739e36ef7412b2bd940f75b278749106e6d025e40027c0b94a17ef7968d55d56 \ + --hash=sha256:7429e7faa1a60cad26ae4227f4dd0459efde239e494c7312624ce228e04f6391 \ + --hash=sha256:74da9f97daec6928567b48c90ea2c82a106b2d500f397eeb8941e47d30b1ca85 \ + --hash=sha256:74e4f025ef3db1c6da4460dd27c118d8cd136d0391da4e387a15e48e5c975147 \ + --hash=sha256:75a9632f1d4f698b2e6e2e1ada40e71f369b15d69baddb8968dcc8e683839b18 \ + --hash=sha256:76acba4c66c47d27c8365e7c10b3d8016a7da83d3191d053a58382311a8bf4e1 \ + --hash=sha256:79d1fb9252e7e2cfe4de6e9a6610c7cbb99b9708e2c3e29057f487de5a9eaefa \ + --hash=sha256:7ce7ad8abebe737ad6143d9d3bf94b88b93365ea30a5b81f6877ec9c0dee0a48 \ + --hash=sha256:7ed07b3062b055d7a7f9d6557a251cc655eed0b3152b76de619516621c56f5d3 \ + --hash=sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184 \ + --hash=sha256:8268cbcd48c5375f46e000adb1390572c98879eb4f77910c6053d25cc3ac2c67 \ + --hash=sha256:875a3f90d7eb5c5d77e529080d95140eacb3c6d13ad5b616ee8095447b1d22e7 \ + --hash=sha256:89feb82ca055af0fe797a2323ec9043b26bc371365847dbe83c7fd2e2f181c34 \ + --hash=sha256:8a7e24cb69ee5f32e003f50e016d5fde438010c1022c96738b04fc2423e61706 \ + --hash=sha256:8ab6a358d1286498d80fe67bd3d69fcbc7d1359b45b41e74c4a26964ca99c3f8 \ + --hash=sha256:8b8df03a9e995b6211dafa63b32f9d405881518ff1ddd775db4e7b98fb545e1c \ + --hash=sha256:8cf85a6e40ff1f37fe0f25719aadf443686b1ac7652593dc53c7ef9b8492b115 \ + --hash=sha256:8e8d351ff44c1638cb6e980623d517abd9f580d2e53bfcd18d8941c052a5a009 \ + --hash=sha256:9164361769b6ca7769079f4d426a41df6164879f7f3568be9086e15baca61466 \ + --hash=sha256:96e85aa09274955bb6bd483eaf5b12abadade01010478154b0ec70284c1b1526 \ + --hash=sha256:981a06a3076997adf7c743dcd0d7a0415582661e2517c7d961493572e909aa1d \ + --hash=sha256:9cd5323344d8ebb9fb5e96da5de5ad4ebab993bbf51674259dbe9d7a18049525 \ + --hash=sha256:9d6c6ea6a11ca0ff9cd0390b885984ed31157c168565702959c25e2191674a14 \ + --hash=sha256:a02d3c48f9bb1e10c7788d92c0c7db6f2002d024ab6e74d6f45ae33e3d0288a3 \ + --hash=sha256:a233bb68625a85126ac9f1fc66d24337d6e8a0f9207b688eec2e7c880f012ec0 \ + --hash=sha256:a2f6a1bc2460e643785a2cde17293bd7a8f990884b822f7bca47bee0a82fc66b \ + --hash=sha256:a6d17e0370d2516d5bb9062c7b4cb731cff921fc875644c3d751ad857ba9c5b1 \ + --hash=sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f \ + --hash=sha256:ab67ed772c584b7ef2379797bf14b82df9aa5f7438c5b9a09624dd834c1c1aaf \ + --hash=sha256:ac6540c9fff6e3813d29d0403ee7a81897f1d8ecc09a8ff84d2eea70ede1cdbf \ + --hash=sha256:ae4073a60ab98529ab8a72ebf429f2a8cc612619a8c04e08bed27450d52103c0 \ + --hash=sha256:ae791f6bd43305aade8c0e22f816b34f3b72b6c820477aab4d18473a37e8090b \ + --hash=sha256:aef5474d913d3b05e613906ba4090433c515e13ea49c837aca18bde190853dff \ + --hash=sha256:b0b3f2df149efb242cee2ffdeb6674b7f30d23c9a7af26595099afaf46ef4e88 \ + --hash=sha256:b128092c927eaf485928cec0c28f6b8bead277e28acf56800e972aa2c2abd7a2 \ + --hash=sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40 \ + --hash=sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716 \ + --hash=sha256:b47633251727c8fe279f34025844b3b3a3e40cd1b198356d003aa146258d13a2 \ + --hash=sha256:b537bd04d7ccd7c6350cdaaaad911f6312cbd61e6e6045542f781c7f8b2e99d2 \ + --hash=sha256:b5e4ef22ff25bfd4ede5f8fb30f7b24446345f3e79d9b7455aef2836437bc38a \ + --hash=sha256:b74b9ea10063efb77a965a8d5f4182806fbf59ed068b3c3fd6f30d2ac7bee734 \ + --hash=sha256:bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87 \ + --hash=sha256:bbc4b80af581e18568ff07f6395c02114d05f4865c2812a1f02f2eaecf0bfd48 \ + --hash=sha256:bcc98f911f10278d1daf14b87d65325851a1d29153caaf146877ec37031d5f36 \ + --hash=sha256:be49ad33819d7dcc28a309b86d4ed98e1a65f3075c6acd3cd4fe32103235222b \ + --hash=sha256:bec4bd9133420c5c52d562469c754f27c5c9e36ee06abc169612c959bd7dbb07 \ + --hash=sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c \ + --hash=sha256:c689d0d5381f56de7bd6966a4541bff6e08bf8d3871bbd89a0c6ab18aa699573 \ + --hash=sha256:c7079d5eb1c1315a858bbf180000757db8ad904a89476653232db835c3114001 \ + --hash=sha256:cb3942960f0beb9f46e2a71a3aca220d1ca32feb5a398656be934320804c0df9 \ + --hash=sha256:cd9e78285da6c9ba2d5c769628f43ef66d96ac3085e59b10ad4f3707980710d3 \ + --hash=sha256:cf2a978c795b54c539f47964ec05e35c05bd045db5ca1e8366988c7f2fe6b3ce \ + --hash=sha256:d14a0d029a4e176795cef99c056d58067c06195e0c7e2dbb293bf95c08f772a3 \ + --hash=sha256:d237ba6664b8e60fd90b8549a149a74fcc675272e0e95539a00522e4ca688b04 \ + --hash=sha256:d26a618ae1766279f2660aca0081b2220aca6bd1aa06b2cf73f07383faf48927 \ + --hash=sha256:d28cb356f119a437cc58a13f8135ab8a4c8ece18159eb9194b0d269ec4e28083 \ + --hash=sha256:d4ed0c7cbecde7194cd3228c044e86bf73e30a23505af852857c09c24e77ec5d \ + --hash=sha256:d83e2d94b69bf31ead2fa45f0acdef0757fa0458a129734f59f67f3d2eb7ef32 \ + --hash=sha256:d8bbcd21769594dbba9c37d3c819e2d5847656ca99c747ddb31ac1701d0c0ed9 \ + --hash=sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f \ + --hash=sha256:dc911208b18842a3a57266d8e51fc3cfaccee90a5351b92079beed912a7914c2 \ + --hash=sha256:dfa7c241073d8f2b8e8dbc7803c434f57dbb83ae2a3d7892dd068d99e96efe2c \ + --hash=sha256:e282aedd63c639c07c3857097fc0e236f984ceb4089a8b284da1c526491e3f3d \ + --hash=sha256:e290d79a4107d7d794634ce3e985b9ae4f920380a813717adf61804904dc4393 \ + --hash=sha256:e3d9d13603410b72787579769469af730c38f2f25505573a5888a94b62b920f8 \ + --hash=sha256:e481bba1e11ba585fb06db666bfc23dbe181dbafc7b25776156120bf12e0d5a6 \ + --hash=sha256:e49b052b768bb74f58c7dda4e0bdf7b79d43a9204ca584ffe1fb48a6f3c84c66 \ + --hash=sha256:eb00b549b13bd6d884c863554566095bf6fa9c3cecb2e7b399c4bc7904cb33b5 \ + --hash=sha256:ec87c44f619380878bd49ca109669c9f221d9ae6883a5bcb3616785fa8f94c97 \ + --hash=sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196 \ + --hash=sha256:f11ae142f3a322d44513de1018b50f474f8f736bc3cd91d969f464b5bfef8836 \ + --hash=sha256:f2a09f6184f17a80897172863a655467da2b11151ec98ba8d7af89f17bf63dae \ + --hash=sha256:f5b65529bb2f21ac7861a0e94fdbf5dc0daab41497d18223b46ee8515e5ad297 \ + --hash=sha256:f60fdd125d85bf9c279ffb8e94c78c51b3b6a37711464e1f5f31078b45002421 \ + --hash=sha256:f61efaf4bed1cc0860e567d2ecb2363974d414f7f1f124b1df368bbf183453a6 \ + --hash=sha256:f90e552ecbad426eab352e7b2933091f2be77115bb16f09f78404861c8322981 \ + --hash=sha256:f956196ef61369f1685d14dad80611488d8dc1ef00be57c0c5a03064005b0f30 \ + --hash=sha256:fb91819461b1b56d06fa4bcf86617fac795f6a99d12239fb0c68dbeba41a0a30 \ + --hash=sha256:fbc9d316552f9ef7bba39f4edfad4a734d3d6f93341232a9dddadec4f15d425f \ + --hash=sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324 \ + --hash=sha256:ffb2be176fed4457e445fe540617f0252a72a8bc56208fd65a690fdb1f57660b +mako==1.3.5 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a \ + --hash=sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc +marisa-trie==1.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:006419c59866979188906babc42ae0918081c18cabc2bdabca027f68c081c127 \ + --hash=sha256:015594427360c6ad0fa94d51ee3d50fb83b0f7278996497fd2d69f877c3de9bd \ + --hash=sha256:02f773e85cc566a24c0e0e28c744052db7691c4f13d02e4257bc657a49b9ab14 \ + --hash=sha256:035c4c8f3b313b4d7b7451ddd539da811a11077a9e359c6a0345f816b1bdccb3 \ + --hash=sha256:045f32eaeb5dcdb5beadb571ba616d7a34141764b616eebb4decce71b366f5fa \ + --hash=sha256:069ac10a133d96b3f3ed1cc071b973a3f28490345e7941c778a1d81cf176f04a \ + --hash=sha256:125016400449e46ec0e5fabd14c8314959c4dfa02ffc2861195c99efa2b5b011 \ + --hash=sha256:1890cc993149db4aa8242973526589e8133c3f92949b0ac74c2c9a6596707ae3 \ + --hash=sha256:1b855e6286faef5411386bf9d676dfb545c09f7d109f197f347c9366aeb12f07 \ + --hash=sha256:26177cd0dadb7b44f47c17c40e16ac157c4d22ac7ed83b5a47f44713239e10d1 \ + --hash=sha256:27d270a64eb655754dfb4e352c60a084b16ab999b3a97a0cdc7dbecbca3c0e35 \ + --hash=sha256:2db8e74493c3bffb480c54afaa88890a39bf90063ff5b322acf64bf076e4b36e \ + --hash=sha256:2e7540f844c1de493a90ad7d0f5bffc6a2cba19fe312d6db7b97aceff11d97f8 \ + --hash=sha256:2fb9243f66563285677079c9dccc697d35985287bacb36c8e685305687b0e025 \ + --hash=sha256:3267f438d258d7d85ee3dde363c4f96c3196ca9cd9e63fe429a59543cc544b15 \ + --hash=sha256:3425dc81d49a374be49e3a063cb6ccdf57973201b0a30127082acea50562a85e \ + --hash=sha256:3540bb85b38dfc17060263e061c95a0a435681b04543d1ae7e8d7441a9790593 \ + --hash=sha256:36d65bcbf22a70cdd0202bd8608c2feecc58bdb9e5dd9a2f5a723b651fcab287 \ + --hash=sha256:39b88f126988ea83e8458259297d2b2f9391bfba8f4dc5d7a246813aae1c1def \ + --hash=sha256:40e2a374026492ac84232897f1f1d8f92a4a1f8bcf3f0ded1f2b8b708d1acfff \ + --hash=sha256:437bf6c0d7ba4cf17656a0e3bdd0b3c2c92c01fedfa670904177eef3116a4f45 \ + --hash=sha256:49701db6bb8f1ec0133abd95f0a4891cfd6f84f3bd019e343037e31a5a5b0210 \ + --hash=sha256:4cfec001cf233e8853a29e1c2bb74031c217aa61e7bd19389007e04861855731 \ + --hash=sha256:4e4535fc5458de2b59789e574cdd55923d63de5612dc159d33941af79cd62786 \ + --hash=sha256:525b8df41a1a7337ed7f982eb63b704d7d75f047e30970fcfbe9cf6fc22c5991 \ + --hash=sha256:5321211647609869907e81b0230ad2dfdfa7e19fe1ee469b46304a622391e6a1 \ + --hash=sha256:58e2b84cbb6394f9c567f1f4351fc2995a094e1b684da9b577d4139b145401d6 \ + --hash=sha256:5a7c75a508f44e40f7af8448d466045a97534adcbb026e63989407cefb9ebfa6 \ + --hash=sha256:5a83fe83e0eab9154a2dc7c556898c86584b7779ddf4214c606fce4ceff07c13 \ + --hash=sha256:5b4a8d3ed1f1b8f551b52e11a1265eaf0718f06bb206654b2c529cecda0913dd \ + --hash=sha256:5cea60975184f03fbcff51339df0eb44d2abe106a1693983cc64415eb87b897b \ + --hash=sha256:5d8a1c0361165231f4fb915237470afc8cc4803c535f535f4fc42ca72855b124 \ + --hash=sha256:5e04e9c86fe8908b61c2aebb8444217cacaed15b93d2dccaac3849e36a6dc660 \ + --hash=sha256:5f5b3080316de735bd2b07265de5eea3ae176fa2fc60f9871aeaa9cdcddfc8f7 \ + --hash=sha256:61fab91fef677f0af0e818e61595f2334f7e0b3e122b24ec65889aae69ba468d \ + --hash=sha256:65f5d8c1ecc85283b5b03a1475a5da723b94b3beda752c895b2f748477d8f1b1 \ + --hash=sha256:6601e74338fb31e1b20674257706150113463182a01d3a1310df6b8840720b17 \ + --hash=sha256:6aeef7b364fb3b34dbba1cc57b79f1668fad0c3f039738d65a5b0d5ddce15f47 \ + --hash=sha256:6ff705cb3b907bdeacb8c4b3bf0541691f52b101014d189a707ca41ebfacad59 \ + --hash=sha256:7459b1e1937e33daed65a6d55f8b95f9a8601f4f8749d01641cf548ecac03840 \ + --hash=sha256:77bfde3287314e91e28d3a882c7b87519ef0ee104c921df72c7819987d5e4863 \ + --hash=sha256:7c6e6506bd24a5799b9b4b9cf1e8d6fa281f136396ba018a95d95d4d74715227 \ + --hash=sha256:7c87a0c2cccce12b07bfcb70708637c0816970282d966a1531ecda1a24bd1cc8 \ + --hash=sha256:83d90be28c083323909d23ff8e9b4a2764b9e75520d1bae1a277e9fa7ca20d15 \ + --hash=sha256:84c44cb13803723f0f76aa2ba1a657f762a0bb9d8a9b80dfff249bb1c3218dd6 \ + --hash=sha256:873efd212dfef2b736ff2ff43e10b348c428d5dbac7b8cb8aa777004bc8c7b0e \ + --hash=sha256:88660e6ee0f821872aaf63ba4b9a7513428b9cab20c69cc013c368bd72c3a4fe \ + --hash=sha256:8af7a21ac2ba6dc23e4257fc3a40b3070e776275d3d0b5b2ef44473ad92caf3a \ + --hash=sha256:8cd287ff323224d87c2b739cba39614aac3737c95a254e0ff70e77d9b8df226d \ + --hash=sha256:902ea948677421093651ca98df62d255383f865f7c353f956ef666e92500e79f \ + --hash=sha256:92ac63e1519598de946c7d9346df3bb52ed96968eb3021b4e89b51d79bc72a86 \ + --hash=sha256:9bcc6613bc873136dc62609b66aaa27363e2bd46c03fdab62d638f7cf69d5f82 \ + --hash=sha256:9dccef41d4af11a03558c1d101de58bd723b3039a5bc4e064250008c118037ec \ + --hash=sha256:9fb95f3ab95ba933f6a2fa2629185e9deb9da45ff2aa4ba8cc8f722528c038ef \ + --hash=sha256:a06a77075240eb83a47b780902322e66c968a06a2b6318cab06757c65ea64190 \ + --hash=sha256:a3f0562863deaad58c5dc3a51f706da92582bc9084189148a45f7a12fe261a51 \ + --hash=sha256:a7183d84da20c89b2a366bf581f0d79d1e248909678f164e8536f291120432e8 \ + --hash=sha256:a7196691681ecb8a12629fb6277c33bafdb27cf2b6c18c28bc48fa42a15eab8f \ + --hash=sha256:a97652c5fbc92f52100afe1c4583625015611000fa81606ad17f1b3bbb9f3bfa \ + --hash=sha256:b04a07b99b62b9bdf3eaf1d44571a3293ce249ce8971944e780c9c709593462f \ + --hash=sha256:b08968ccad00f54f31e38516e4452fae59dd15a3fcee56aea3101ba2304680b3 \ + --hash=sha256:bc138625b383998f5cd0cbf6cd38d66d414f3786ae6d7b4e4a6fc970140ef4e9 \ + --hash=sha256:bd1f3ef8de89684fbdd6aaead09d53b82e718bad4375d2beb938cbd24b48c51a \ + --hash=sha256:bdd1d4d430e33abbe558971d1bd57da2d44ca129fa8a86924c51437dba5cb345 \ + --hash=sha256:c11af35d9304de420b359741e12b885d04f11403697efcbbe8cb50f834261ebc \ + --hash=sha256:c4fbb1ec1d9e891060a0aee9f9c243acec63de1e197097a14850ba38ec8a4013 \ + --hash=sha256:c57647dd9f9ba16fc5bb4679c915d7d48d5c0b25134fb10f095ccd839686a027 \ + --hash=sha256:c643c66bbde6a115e4ec8713c087a9fe9cb7b7c684e6af4cf448c120fa427ea4 \ + --hash=sha256:c729e2b8f9699874b1372b5a01515b340eda1292f5e08a3fe4633b745f80ad7a \ + --hash=sha256:c7f4df4163202b0aa5dad3eeddf088ecb61e9101986c8b31f1e052ebd6df9292 \ + --hash=sha256:cb60c2f9897ce2bfc31a69ac25a040de4f8643ab2a339bb0ff1185e1a9dedaf8 \ + --hash=sha256:cd88a338c87e6dc130b6cea7b697580c21f0c83a8a8b46671cfecbb713d3fe24 \ + --hash=sha256:ce2f68e1000c4c72820c5b2c9d037f326fcf75f036453a5e629f225f99b92cfc \ + --hash=sha256:d3c0e38f0501951e2322f7274a39b8e2344bbd91ceaa9da439f46022570ddc9d \ + --hash=sha256:d3ef375491e7dd71a0a7e7bf288c88750942bd1ee0c379dcd6ad43e31af67d00 \ + --hash=sha256:d4f05c2ee218a5ab09d269b640d06f9708b0cf37c842344cbdffb0661c74c472 \ + --hash=sha256:d62985a0e6f2cfeb36cd6afa0460063bbe83ef4bfd9afe189a99103487547210 \ + --hash=sha256:de9911480ce2a0513582cb84ee4484e5ee8791e692276c7f5cd7378e114d1988 \ + --hash=sha256:e7202ba0ca1db5245feaebbeb3d0c776b2da1fffb0abc3500dd505f679686aa1 \ + --hash=sha256:eaf052c0a1f4531ee12fd4c637212e77ad2af8c3b38a0d3096622abd01a22212 \ + --hash=sha256:eba1061bbeaeec4149282beab2ae163631606f119f549a10246b014e13f9047b \ + --hash=sha256:ec167b006884a90d130ee30518a9aa44cb40211f702bf07031b2d7d4d1db569b \ + --hash=sha256:f19c5fcf23c02f1303deb69c67603ee37ed8f01de2d8b19f1716a6cf5afd5455 \ + --hash=sha256:f5cb731581effb3e05258f3ddc2a155475de74bb00f61eb280f991e13b48f783 \ + --hash=sha256:fa1fa7f67d317a921315a65e266b9e156ce5a956076ec2b6dbf72d67c7df8216 \ + --hash=sha256:fdf7a2d066907816726f3bf241b8cb05b698d6ffaa3c5ea2658d4ba69e87ec57 \ + --hash=sha256:fe1394e1f262e5b45d22d30bd1ef75174d1f2772e86716b5f93f9c29dfc1a779 \ + --hash=sha256:fedfc67497f8aa2757756b5cf493759f245d321fb78914ce125b6d75daa89b5f markdown-it-py==3.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb @@ -697,6 +863,76 @@ markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 +maxminddb==2.6.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:058ca89789bc1770fe58d02a88272ca91dabeef9f3fe0011fe506484355f1804 \ + --hash=sha256:05e873eb82281cef6e787bd40bd1d58b2e496a21b3689346f0d0420988b3cbb1 \ + --hash=sha256:0b281c0eec3601dde1f169a1c04e2615751c66368141aded9f03131fe635450b \ + --hash=sha256:0b480a31589750da4e36d1ba04b77ee3ac3853ac7b94d63f337b9d4d0403043f \ + --hash=sha256:12207f0becf3f2bf14e7a4bf86efcaa6e90d665a918915ae228c4e77792d7151 \ + --hash=sha256:1c096dfd20926c4de7d7fd5b5e75c756eddd4bdac5ab7aafd4bb67d000b13743 \ + --hash=sha256:1dc2b511c7255f7cbbb01e8ba01ba82e62e9c1213e382d36f9d9b0ee45c2f6b2 \ + --hash=sha256:20662878bc9514e90b0b4c4eb1a76622ecc7504d012e76bad9cdb7372fc0ef96 \ + --hash=sha256:28a2eaf9769262c05c486e777016771f3367c843b053c43cd5fde1108755753d \ + --hash=sha256:28af9470f28fce2ccb945478235f53fb52d98a505653b1bf4028e34df6149a06 \ + --hash=sha256:2aaefb62f881151960bb67e5aeb302c159a32bd2d623cf72dad688bda1020869 \ + --hash=sha256:34b6e8d667d724f60d52635f3d959f793ab4e5d57d78b27fe66f02752d8c6b08 \ + --hash=sha256:38941a38278491bf95e5ca544969782c7ab33326802f6a93816867289c3f6401 \ + --hash=sha256:3987e103396e925edebbef4877e94515822f63b3b436027a0b164b500622fccd \ + --hash=sha256:39eab93ddd75fd02f8d5ad6b1bd3f8d894828d91d6f6c1a96bb9e87c34e94aaa \ + --hash=sha256:47170ec0e1e76787cc5882301c487f495d67f3146318f2f4e2adc281951a96ef \ + --hash=sha256:485c0778f6801e1437c2efd6e3b964a7ae71c8819f063e0b5460c3267d977040 \ + --hash=sha256:5662386db91872d5505fde9e7bb0b9530b6aab7a6f3ece7df59a2b43a7b45d17 \ + --hash=sha256:58bfd2c55c96aaaa7c4996c704edabfb1bd369dfc1592cedf8957a24062178b1 \ + --hash=sha256:5c7c520d06d335b288d06a00b786cea9b7e023bd588efb1a6ef485e94ccc7244 \ + --hash=sha256:6a50bc348c699d8f6a5f0aa35e5096515d642ca2f38b944bd71c3dedda3d3588 \ + --hash=sha256:6fd1a612110ff182a559d8010e7615e5d05ef9d2c234b5f7de124ee8fdf1ecb9 \ + --hash=sha256:7607e45f7eca991fa34d57c03a791a1dfbe774ddd9250d0f35cdcc6f17142a15 \ + --hash=sha256:78c3aa70c62be68ace23f819e7f23258545f2bfbd92cd6c33ee398cd261f6b84 \ + --hash=sha256:7c1220838ba9b0bcdaa0c5846f9da70a2304df2ac255fe518370f8faf8c18316 \ + --hash=sha256:7cd7f525eb2331cf05181c5ba562cc3edec3de4b41dbb18a5fee9ad24884b499 \ + --hash=sha256:7cfdf5c29a2739610700b9fea7f8d68ce81dcf30bb8016f1a1853ef889a2624b \ + --hash=sha256:7d842d32e2620abc894b7d79a5a1007a69df2c6cf279a06b94c9c3913f66f264 \ + --hash=sha256:7e5a90a1cb0c7fd6226aa44e18a87b26fa85b6eebae36d529d7582f93e8dfbd1 \ + --hash=sha256:80d20683afe01b4d41bad1c1829f87ab12f3d19c68ec230f83318a2fd13871a7 \ + --hash=sha256:80d7495565d30260c630afbe74d61522b13dd31ed05b8916003ec5b127109a12 \ + --hash=sha256:80d7f943f6b8bc437eaae5da778a83d8f38e4b7463756fdee04833e1be0bdea2 \ + --hash=sha256:8101291e5b92bd272a050c25822a5e30860d453dde16b4fffed9d751f0483a82 \ + --hash=sha256:826a1858b93b193df7fa71e3caca65c3051db20545df0020444f55c02e8ed2c3 \ + --hash=sha256:85fc9406f42c1311ce8ea9f2c820db5d7ac687a39ab5d932708dc783607378ef \ + --hash=sha256:86048ff328793599e584bcc2fc8278c2b7c5d3a4005c70403613449ec93817ef \ + --hash=sha256:886af3ba4aa26214ff39214565f53152b62a5abdb6ef9e00c76c194dbfd79231 \ + --hash=sha256:8cb992da535264177b380e7b81943c884d57dcbfad6b3335d7f633967144746e \ + --hash=sha256:93691c8b4b4c448babb37bedc6f3d51523a3f06ab11bdd171da7ffc4005a7897 \ + --hash=sha256:96a1fa38322bce1d587bb6ce39a0e6ca4c1b824f48fbc5739a5ec507f63aa889 \ + --hash=sha256:9a2671e8f4161130803cf226cd9cb8b93ec5c4b2493f83a902986177052d95d3 \ + --hash=sha256:9dccd7a438f81e3df84dfc31a75af4c8d29adefb6082329385bfde604c9ea01b \ + --hash=sha256:a74b60cdc61a69b967ec44201c6259fbc48ef2eab2e885fbdc50ec1accaad545 \ + --hash=sha256:a771df92e599ad867c16ae4acb08cc3763c9d1028f4ca772c0571da97f7f86d2 \ + --hash=sha256:aa8cb54b01a29a23a0ea6659fbb38deec6f35453588c5decdbf8669feb53b624 \ + --hash=sha256:add1e55620033516c5f0734b1d9d03848859192d9f3825aabe720dfa8a783958 \ + --hash=sha256:b0a3b9cab1a94cc633df3da85c6567f0188f10165e3338ec9a6c421de9fe53b9 \ + --hash=sha256:b31ecf3083b78c77624783bfdf6177e6ac73ae14684ef182855eb5569bc78e7c \ + --hash=sha256:b4d9cd7ddd02ee123a44d0d7821166d31540ea85352deb06b29d55e802f32781 \ + --hash=sha256:c9e9e893f7c0fa44cfdd5ab819a07d93f63ee398c28b792cedd50b94dcfea7c0 \ + --hash=sha256:cd4530b9604d66cfa5e37eb94c671e54feff87769f8ba7fa997cce959e0cb241 \ + --hash=sha256:d0970b661c4fac6624b9128057ed5fe35a2d95aa60359272289cd4c7207c9a6d \ + --hash=sha256:d15414d251513748cb646d284a2829a5f4c69d8c90963a6e6da53a1a6d0accf7 \ + --hash=sha256:d32266792b349f5507b0369d3277d45318fcd346a16dcc98b484aadc208e4d74 \ + --hash=sha256:d8ccca5327cb4e706f669456ec6d556badfa92c0fdacd57a15076f3cdc061560 \ + --hash=sha256:dc9f1203eb2b139252aa08965960fe13c36cc8b80b536490b94b05c31aa1fca9 \ + --hash=sha256:dd90c3798e6c347d48d5d9a9c95dc678b52a5a965f1fb72152067fdf52b994da \ + --hash=sha256:e1e40449bd278fdca1f351df442f391e72fd3d98b054ccac1672f27d70210642 \ + --hash=sha256:e2b85ffc9fb2e192321c2f0b34d0b291b8e82de6e51a6ec7534645663678e835 \ + --hash=sha256:e63649a82926f1d93acdd3df5f7be66dc9473653350afe73f365bb25e5b34368 \ + --hash=sha256:e9013076deca5d136c260510cd05e82ec2b4ddb9476d63e2180a13ddfd305c3e \ + --hash=sha256:eacd65e38bdf4efdf42bbc15cfa734b09eb818ecfef76b7b36e64be382be4c83 \ + --hash=sha256:eb534333f5fd7180e35c0207b3d95d621e4b9be3b8c1709995d0feb6c752b6f4 \ + --hash=sha256:ebf9fdf8a8e55862aabb8b2c34a4af31a8a5b686007288eeb561fa20ef348378 \ + --hash=sha256:ecce0b2d125691e2311f94dbd564c2d61c36c5033d082919431a21e6c694fa3f \ + --hash=sha256:eef1c26210155c7b94c4ca28fef65eb44a5ca1584427b1fbdeec1cd3c81e25c5 \ + --hash=sha256:f2e326a99eaa924ff2fb09d6e44127983a43016228e7780888f15e9ba171d7b3 \ + --hash=sha256:f412a54f87ef9083911c334267188d3d1b14f2591eac94b94ca32528f21d5f25 \ + --hash=sha256:fb38aa94e76a87785b654c035f9f3ee39b74a98e9beea9a10b1aa62abdcc4cbd mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba @@ -833,93 +1069,104 @@ opentelemetry-semantic-conventions==0.47b0 ; python_version >= "3.10" and python opentelemetry-util-http==0.47b0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:352a07664c18eef827eb8ddcbd64c64a7284a39dd1655e2f16f577eb046ccb32 \ --hash=sha256:3d3215e09c4a723b12da6d0233a31395aeb2bb33a64d7b15a1500690ba250f19 -packaging==23.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ - --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 +packaging==24.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ + --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 pgpy==0.6.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:279c2e353f4c3a319f00bd9bd582456e420f8a3ac6de2b4e9731444746828383 -pillow==10.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c \ - --hash=sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2 \ - --hash=sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb \ - --hash=sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d \ - --hash=sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa \ - --hash=sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3 \ - --hash=sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1 \ - --hash=sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a \ - --hash=sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd \ - --hash=sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8 \ - --hash=sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999 \ - --hash=sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599 \ - --hash=sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936 \ - --hash=sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375 \ - --hash=sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d \ - --hash=sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b \ - --hash=sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60 \ - --hash=sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572 \ - --hash=sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3 \ - --hash=sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced \ - --hash=sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f \ - --hash=sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b \ - --hash=sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19 \ - --hash=sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f \ - --hash=sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d \ - --hash=sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383 \ - --hash=sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795 \ - --hash=sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355 \ - --hash=sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57 \ - --hash=sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09 \ - --hash=sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b \ - --hash=sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462 \ - --hash=sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf \ - --hash=sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f \ - --hash=sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a \ - --hash=sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad \ - --hash=sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9 \ - --hash=sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d \ - --hash=sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45 \ - --hash=sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994 \ - --hash=sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d \ - --hash=sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338 \ - --hash=sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463 \ - --hash=sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451 \ - --hash=sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591 \ - --hash=sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c \ - --hash=sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd \ - --hash=sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32 \ - --hash=sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9 \ - --hash=sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf \ - --hash=sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5 \ - --hash=sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828 \ - --hash=sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3 \ - --hash=sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5 \ - --hash=sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2 \ - --hash=sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b \ - --hash=sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2 \ - --hash=sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475 \ - --hash=sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3 \ - --hash=sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb \ - --hash=sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef \ - --hash=sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015 \ - --hash=sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002 \ - --hash=sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170 \ - --hash=sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84 \ - --hash=sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57 \ - --hash=sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f \ - --hash=sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27 \ - --hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a -protobuf==4.25.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4 \ - --hash=sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8 \ - --hash=sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c \ - --hash=sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d \ - --hash=sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4 \ - --hash=sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa \ - --hash=sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c \ - --hash=sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019 \ - --hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \ - --hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \ - --hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2 +pillow==10.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885 \ + --hash=sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea \ + --hash=sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df \ + --hash=sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5 \ + --hash=sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c \ + --hash=sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d \ + --hash=sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd \ + --hash=sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06 \ + --hash=sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908 \ + --hash=sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a \ + --hash=sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be \ + --hash=sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0 \ + --hash=sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b \ + --hash=sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80 \ + --hash=sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a \ + --hash=sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e \ + --hash=sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9 \ + --hash=sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696 \ + --hash=sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b \ + --hash=sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309 \ + --hash=sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e \ + --hash=sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab \ + --hash=sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d \ + --hash=sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060 \ + --hash=sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d \ + --hash=sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d \ + --hash=sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4 \ + --hash=sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3 \ + --hash=sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6 \ + --hash=sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb \ + --hash=sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94 \ + --hash=sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b \ + --hash=sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496 \ + --hash=sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0 \ + --hash=sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319 \ + --hash=sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b \ + --hash=sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856 \ + --hash=sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef \ + --hash=sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680 \ + --hash=sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b \ + --hash=sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42 \ + --hash=sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e \ + --hash=sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597 \ + --hash=sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a \ + --hash=sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8 \ + --hash=sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3 \ + --hash=sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736 \ + --hash=sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da \ + --hash=sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126 \ + --hash=sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd \ + --hash=sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5 \ + --hash=sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b \ + --hash=sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026 \ + --hash=sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b \ + --hash=sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc \ + --hash=sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46 \ + --hash=sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2 \ + --hash=sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c \ + --hash=sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe \ + --hash=sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984 \ + --hash=sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a \ + --hash=sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70 \ + --hash=sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca \ + --hash=sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b \ + --hash=sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91 \ + --hash=sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3 \ + --hash=sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84 \ + --hash=sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1 \ + --hash=sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5 \ + --hash=sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be \ + --hash=sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f \ + --hash=sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc \ + --hash=sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9 \ + --hash=sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e \ + --hash=sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141 \ + --hash=sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef \ + --hash=sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22 \ + --hash=sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27 \ + --hash=sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e \ + --hash=sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1 +protobuf==4.25.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:051e97ce9fa6067a4546e75cb14f90cf0232dcb3e3d508c448b8d0e4265b61c1 \ + --hash=sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d \ + --hash=sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040 \ + --hash=sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835 \ + --hash=sha256:7e372cbbda66a63ebca18f8ffaa6948455dfecc4e9c1029312f6c2edcd86c4e1 \ + --hash=sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca \ + --hash=sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f \ + --hash=sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d \ + --hash=sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978 \ + --hash=sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4 \ + --hash=sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b psycopg2==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981 \ --hash=sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516 \ @@ -934,14 +1181,14 @@ psycopg2==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024 \ --hash=sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913 \ --hash=sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c -pyasn1==0.5.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58 \ - --hash=sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c +pyasn1==0.6.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c \ + --hash=sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473 pybinaryedge==0.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:00cf2f253aa44c7d6589a56d70c5b820a5060c3a0a2aee018f0b4ed732fe7632 -pycparser==2.21 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ - --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 +pycparser==2.22 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ + --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ @@ -1032,18 +1279,18 @@ pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 -pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ - --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic-settings==2.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315 \ + --hash=sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88 pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pydicom==2.4.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 -pygments==2.17.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \ - --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367 +pygments==2.18.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ + --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a pynacl==1.5.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858 \ --hash=sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d \ @@ -1058,9 +1305,9 @@ pynacl==1.5.0 ; python_version >= "3.10" and python_version < "4.0" \ pynetdicom==2.0.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:231212e9b9c5e0debf2af4f17d8afa14ecd1b262a11cdb891b2b2b15f7ab5939 \ --hash=sha256:6726173d25a51f66f2a4557d816c0f93b3b2a8435ce3d319e6cdd8e48bf657d5 -python-dateutil==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ - --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 +python-dateutil==2.9.0.post0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ + --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a @@ -1082,160 +1329,184 @@ pywin32==306 ; python_version >= "3.10" and python_version < "4.0" and sys_platf --hash=sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a \ --hash=sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407 \ --hash=sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0 -referencing==0.33.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5 \ - --hash=sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7 -requests-file==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 +referencing==0.35.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \ + --hash=sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de +requests-file==2.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658 \ + --hash=sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 -rich==13.7.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \ - --hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235 -rpds-py==0.18.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f \ - --hash=sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c \ - --hash=sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76 \ - --hash=sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e \ - --hash=sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157 \ - --hash=sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f \ - --hash=sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5 \ - --hash=sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05 \ - --hash=sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24 \ - --hash=sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1 \ - --hash=sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8 \ - --hash=sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b \ - --hash=sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb \ - --hash=sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07 \ - --hash=sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1 \ - --hash=sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6 \ - --hash=sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e \ - --hash=sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e \ - --hash=sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1 \ - --hash=sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab \ - --hash=sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4 \ - --hash=sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17 \ - --hash=sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594 \ - --hash=sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d \ - --hash=sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d \ - --hash=sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3 \ - --hash=sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c \ - --hash=sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66 \ - --hash=sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f \ - --hash=sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80 \ - --hash=sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33 \ - --hash=sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f \ - --hash=sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c \ - --hash=sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022 \ - --hash=sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e \ - --hash=sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f \ - --hash=sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da \ - --hash=sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1 \ - --hash=sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688 \ - --hash=sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795 \ - --hash=sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c \ - --hash=sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98 \ - --hash=sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1 \ - --hash=sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20 \ - --hash=sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307 \ - --hash=sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4 \ - --hash=sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18 \ - --hash=sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294 \ - --hash=sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66 \ - --hash=sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467 \ - --hash=sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948 \ - --hash=sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e \ - --hash=sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1 \ - --hash=sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0 \ - --hash=sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7 \ - --hash=sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd \ - --hash=sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641 \ - --hash=sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d \ - --hash=sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9 \ - --hash=sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1 \ - --hash=sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da \ - --hash=sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3 \ - --hash=sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa \ - --hash=sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7 \ - --hash=sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40 \ - --hash=sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496 \ - --hash=sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124 \ - --hash=sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836 \ - --hash=sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434 \ - --hash=sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984 \ - --hash=sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f \ - --hash=sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6 \ - --hash=sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e \ - --hash=sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461 \ - --hash=sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c \ - --hash=sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432 \ - --hash=sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73 \ - --hash=sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58 \ - --hash=sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88 \ - --hash=sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337 \ - --hash=sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7 \ - --hash=sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863 \ - --hash=sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475 \ - --hash=sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3 \ - --hash=sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51 \ - --hash=sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf \ - --hash=sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024 \ - --hash=sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40 \ - --hash=sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9 \ - --hash=sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec \ - --hash=sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb \ - --hash=sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7 \ - --hash=sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861 \ - --hash=sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880 \ - --hash=sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f \ - --hash=sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd \ - --hash=sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca \ - --hash=sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58 \ - --hash=sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e +rich==13.7.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \ + --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432 +rpds-py==0.20.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c \ + --hash=sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585 \ + --hash=sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5 \ + --hash=sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6 \ + --hash=sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef \ + --hash=sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2 \ + --hash=sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29 \ + --hash=sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318 \ + --hash=sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b \ + --hash=sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399 \ + --hash=sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739 \ + --hash=sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee \ + --hash=sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174 \ + --hash=sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a \ + --hash=sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344 \ + --hash=sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2 \ + --hash=sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03 \ + --hash=sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5 \ + --hash=sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22 \ + --hash=sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e \ + --hash=sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96 \ + --hash=sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91 \ + --hash=sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752 \ + --hash=sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075 \ + --hash=sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253 \ + --hash=sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee \ + --hash=sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad \ + --hash=sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5 \ + --hash=sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce \ + --hash=sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7 \ + --hash=sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b \ + --hash=sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8 \ + --hash=sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57 \ + --hash=sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3 \ + --hash=sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec \ + --hash=sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209 \ + --hash=sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921 \ + --hash=sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045 \ + --hash=sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074 \ + --hash=sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580 \ + --hash=sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7 \ + --hash=sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5 \ + --hash=sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3 \ + --hash=sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0 \ + --hash=sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24 \ + --hash=sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139 \ + --hash=sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db \ + --hash=sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc \ + --hash=sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789 \ + --hash=sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f \ + --hash=sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2 \ + --hash=sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c \ + --hash=sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232 \ + --hash=sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6 \ + --hash=sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c \ + --hash=sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29 \ + --hash=sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489 \ + --hash=sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94 \ + --hash=sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751 \ + --hash=sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2 \ + --hash=sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda \ + --hash=sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9 \ + --hash=sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51 \ + --hash=sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c \ + --hash=sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8 \ + --hash=sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989 \ + --hash=sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511 \ + --hash=sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1 \ + --hash=sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2 \ + --hash=sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150 \ + --hash=sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c \ + --hash=sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965 \ + --hash=sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f \ + --hash=sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58 \ + --hash=sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b \ + --hash=sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f \ + --hash=sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d \ + --hash=sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821 \ + --hash=sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de \ + --hash=sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121 \ + --hash=sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855 \ + --hash=sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272 \ + --hash=sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60 \ + --hash=sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02 \ + --hash=sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1 \ + --hash=sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140 \ + --hash=sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879 \ + --hash=sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940 \ + --hash=sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364 \ + --hash=sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4 \ + --hash=sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e \ + --hash=sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420 \ + --hash=sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5 \ + --hash=sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24 \ + --hash=sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c \ + --hash=sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf \ + --hash=sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f \ + --hash=sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e \ + --hash=sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab \ + --hash=sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08 \ + --hash=sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92 \ + --hash=sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a \ + --hash=sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8 sectxt==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c5b113cb37ec5053bf8ea335306a7c68079b53959df2324ffa9991885bec67a8 \ --hash=sha256:c81d874a55b96516d13e2b688f3150a6089e0636122237e4710717beafcb26d7 -setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ - --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 +setuptools==72.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1 \ + --hash=sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec shodan==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:7e2bddbc1b60bf620042d0010f4b762a80b43111dbea9c041d72d4325e260c23 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 -sniffio==1.3.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \ - --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384 +sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ + --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc soupsieve==2.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690 \ --hash=sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7 -sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0535d5b57d014d06ceeaeffd816bb3a6e2dddeb670222570b8c4953e2d2ea678 \ - --hash=sha256:0892e7ac8bc76da499ad3ee8de8da4d7905a3110b952e2a35a940dab1ffa550e \ - --hash=sha256:0d661cff58c91726c601cc0ee626bf167b20cc4d7941c93c5f3ac28dc34ddbea \ - --hash=sha256:245c67c88e63f1523e9216cad6ba3107dea2d3ee19adc359597a628afcabfbcb \ - --hash=sha256:2ad16880ccd971ac8e570550fbdef1385e094b022d6fc85ef3ce7df400dddad3 \ - --hash=sha256:2be4e6294c53f2ec8ea36486b56390e3bcaa052bf3a9a47005687ccf376745d1 \ - --hash=sha256:2c55040d8ea65414de7c47f1a23823cd9f3fad0dc93e6b6b728fee81230f817b \ - --hash=sha256:352df882088a55293f621328ec33b6ffca936ad7f23013b22520542e1ab6ad1b \ - --hash=sha256:3823dda635988e6744d4417e13f2e2b5fe76c4bf29dd67e95f98717e1b094cad \ - --hash=sha256:38ef80328e3fee2be0a1abe3fe9445d3a2e52a1282ba342d0dab6edf1fef4707 \ - --hash=sha256:3ec7a0ed9b32afdf337172678a4a0e6419775ba4e649b66f49415615fa47efbd \ - --hash=sha256:55e699466106d09f028ab78d3c2e1f621b5ef2c8694598242259e4515715da7c \ - --hash=sha256:6cacc0b2dd7d22a918a9642fc89840a5d3cee18a0e1fe41080b1141b23b10916 \ - --hash=sha256:7deeae5071930abb3669b5185abb6c33ddfd2398f87660fafdb9e6a5fb0f3f2f \ - --hash=sha256:86a22143a4001f53bf58027b044da1fb10d67b62a785fc1390b5c7f089d9838c \ - --hash=sha256:8ca484ca11c65e05639ffe80f20d45e6be81fbec7683d6c9a15cd421e6e8b340 \ - --hash=sha256:af55cc207865d641a57f7044e98b08b09220da3d1b13a46f26487cc2f898a072 \ - --hash=sha256:b97fd5bb6b7c1a64b7ac0632f7ce389b8ab362e7bd5f60654c2a418496be5d7f \ - --hash=sha256:c37bc677690fd33932182b85d37433845de612962ed080c3e4d92f758d1bd894 \ - --hash=sha256:d3cf56cc36d42908495760b223ca9c2c0f9f0002b4eddc994b24db5fcb86a9e4 \ - --hash=sha256:e646b19f47d655261b22df9976e572f588185279970efba3d45c377127d35349 \ - --hash=sha256:e7908c2025eb18394e32d65dd02d2e37e17d733cdbe7d78231c2b6d7eb20cdb9 \ - --hash=sha256:e8f2df79a46e130235bc5e1bbef4de0583fb19d481eaa0bffa76e8347ea45ec6 \ - --hash=sha256:eb18549b770351b54e1ab5da37d22bc530b8bfe2ee31e22b9ebe650640d2ef12 \ - --hash=sha256:f8cafa6f885a0ff5e39efa9325195217bb47d5929ab0051636610d24aef45ade +sqlalchemy==1.4.53 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0465b8a68f8f4de754c1966c45b187ac784ad97bc9747736f913130f0e1adea0 \ + --hash=sha256:07ba54f09033d387ae9df8d62cbe211ed7304e0bfbece1f8c55e21db9fae5c11 \ + --hash=sha256:122d7b5722df1a24402c6748bbb04687ef981493bb559d0cc0beffe722e0e6ed \ + --hash=sha256:13fc34b35d8ddb3fbe3f8fcfdf6c2546e676187f0fb20f5774da362ddaf8fa2d \ + --hash=sha256:16bb9fa4d00b4581b14d9f0e2224dc7745b854aa4687738279af0f48f7056c98 \ + --hash=sha256:197065b91456574d70b6459bfa62bc0b52a4960a29ef923c375ec427274a3e05 \ + --hash=sha256:1a38834b4c183c33daf58544281395aad2e985f0b47cca1e88ea5ada88344e63 \ + --hash=sha256:1a96aa8d425047551676b0e178ddb0683421e78eda879ab55775128b2e612cae \ + --hash=sha256:2774c24c405136c3ef472e2352bdca7330659d481fbf2283f996c0ef9eb90f22 \ + --hash=sha256:421306c4b936b0271a3ce2dc074928d5ece4a36f9c482daa5770f44ecfc3a883 \ + --hash=sha256:437592b341a3229dd0443c9c803b0bf0a466f8f539014fef6cdb9c06b7edb7f9 \ + --hash=sha256:4604d42b2abccba266d3f5bbe883684b5df93e74054024c70d3fbb5eea45e530 \ + --hash=sha256:4e10ac36f0b994235c13388b39598bf27219ec8bdea5be99bdac612b01cbe525 \ + --hash=sha256:4fe5168d0249c23f537950b6d75935ff2709365a113e29938a979aec36668ecf \ + --hash=sha256:5e6ab710c4c064755fd92d1a417bef360228a19bdf0eee32b03aa0f5f8e9fe0d \ + --hash=sha256:5f67b9e9dcac3241781e96575468d55a42332157dee04bdbf781df573dff5f85 \ + --hash=sha256:616492f5315128a847f293a7c552f3561ac7e996d2aa5dc46bef4fb0d3781f1d \ + --hash=sha256:626be971ff89541cfd3e70b54be00b57a7f8557204decb6223ce0428fec058f3 \ + --hash=sha256:670c7769bf5dcae9aff331247b5d82fe635c63731088a46ce68ba2ba519ef36e \ + --hash=sha256:68a614765197b3d13a730d631a78c3bb9b3b72ba58ed7ab295d58d517464e315 \ + --hash=sha256:6dd06572872ca13ef5a90306a3e5af787498ddaa17fb00109b1243642646cd69 \ + --hash=sha256:784272ceb5eb71421fea9568749bcbe8bd019261a0e2e710a7efa76057af2499 \ + --hash=sha256:83a9c3514ff19d9d30d8a8d378b24cd1dfa5528d20891481cb5f196117db6a48 \ + --hash=sha256:86b11640251f9a9789fd96cd6e5d176b1c230230c70ad40299bcbcc568451b4c \ + --hash=sha256:89d8ac4158ef68eea8bb0f6dd0583127d9aa8720606964ba8eee20b254f9c83a \ + --hash=sha256:8b8608d162d3bd29d807aab32c3fb6e2f8e225a43d1c54c917fed38513785380 \ + --hash=sha256:93e90aa3e3b2f8e8cbae4d5509f8e0cf82972378d323c740a8df1c1e9f484172 \ + --hash=sha256:95123f3a1e0e8020848fd32ba751db889a01a44e4e4fef7e58c87ddd0b2fca59 \ + --hash=sha256:991e42fdfec561ebc6a4fae7161a86d129d6069fa14210b96b8dd752afa7059c \ + --hash=sha256:9d7368df54d3ed45a18955f6cec38ebe075290594ac0d5c87a8ddaff7e10de27 \ + --hash=sha256:a8c2f2a0b2c4e3b86eb58c9b6bb98548205eea2fba9dae4edfd29dc6aebbe95a \ + --hash=sha256:a9d4d132198844bd6828047135ce7b887687c92925049a2468a605fc775c7a1a \ + --hash=sha256:b61ac5457d91b5629a3dea2b258deb4cdd35ac8f6fa2031d2b9b2fff5b3396da \ + --hash=sha256:bc8be4df55e8fde3006d9cb1f6b3df2ba26db613855dc4df2c0fcd5ec15cb3b7 \ + --hash=sha256:c05fe05941424c2f3747a8952381b7725e24cba2ca00141380e54789d5b616b6 \ + --hash=sha256:c0cf8c0af9563892c6632f7343bc393dfce6eeef8e4d10c5fadba9c0390520bd \ + --hash=sha256:c15d1f1fcf1f9bec0499ae1d9132b950fcc7730f2d26d10484c8808b4e077816 \ + --hash=sha256:c58e011e9e6373b3a091d83f20601fb335a3b4bace80bfcb914ac168aad3b70d \ + --hash=sha256:cd534c716f86bdf95b7b984a34ee278c91d1b1d7d183e7e5ff878600b1696046 \ + --hash=sha256:d021699b9007deb7aa715629078830c99a5fec2753d9bdd5ff33290d363ef755 \ + --hash=sha256:d13d4dfbc6e52363886b47cf02cf68c5d2a37c468626694dc210d7e97d4ad330 \ + --hash=sha256:eaaeedbceb4dfd688fff2faf25a9a87a391f548811494f7bff7fa701b639abc3 \ + --hash=sha256:edf094a20a386ff2ec73de65ef18014b250259cb860edc61741e240ca22d6981 \ + --hash=sha256:fb8e15dfa47f5de11ab073e12aadd6b502cfb7ac4bafd18bd18cfd1c7d13dbbc starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 diff --git a/boefjes/tests/integration/test_api.py b/boefjes/tests/integration/test_api.py index 9df55695c16..b29060cf316 100644 --- a/boefjes/tests/integration/test_api.py +++ b/boefjes/tests/integration/test_api.py @@ -47,9 +47,9 @@ def test_get_local_plugin(self): def test_filter_plugins(self): response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/") - self.assertEqual(len(response.json()), 95) + self.assertEqual(len(response.json()), 97) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins?plugin_type=boefje") - self.assertEqual(len(response.json()), 42) + self.assertEqual(len(response.json()), 43) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins?limit=10") self.assertEqual(len(response.json()), 10) @@ -74,7 +74,7 @@ def test_add_boefje(self): self.assertEqual(response.status_code, 422) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/?plugin_type=boefje") - self.assertEqual(len(response.json()), 43) + self.assertEqual(len(response.json()), 44) boefje_dict = boefje.dict() boefje_dict["consumes"] = list(boefje_dict["consumes"]) @@ -99,7 +99,7 @@ def test_add_normalizer(self): self.assertEqual(response.status_code, 201) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/?plugin_type=normalizer") - self.assertEqual(len(response.json()), 54) + self.assertEqual(len(response.json()), 55) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/test_normalizer") self.assertEqual(response.json(), normalizer.dict()) diff --git a/octopoes/octopoes/models/ooi/geography.py b/octopoes/octopoes/models/ooi/geography.py new file mode 100644 index 00000000000..f9762520567 --- /dev/null +++ b/octopoes/octopoes/models/ooi/geography.py @@ -0,0 +1,19 @@ +from typing import Annotated, Literal + +from pydantic import Field + +from octopoes.models import OOI, Reference +from octopoes.models.persistence import ReferenceField + + +class GeographicPoint(OOI): + object_type: Literal["GeographicPoint"] = "GeographicPoint" + + ooi: Reference = ReferenceField(OOI) + + longitude: Annotated[float, Field(strict=True, ge=-180.0, le=180.0)] + latitude: Annotated[float, Field(strict=True, ge=-180.0, le=180.0)] + + @property + def natural_key(self) -> str: + return f"{str(self.ooi)}|{self.longitude}|{self.latitude}" diff --git a/octopoes/octopoes/models/types.py b/octopoes/octopoes/models/types.py index b0fd6067b29..2bc1acc9af9 100644 --- a/octopoes/octopoes/models/types.py +++ b/octopoes/octopoes/models/types.py @@ -46,6 +46,7 @@ RetireJSFindingType, SnykFindingType, ) +from octopoes.models.ooi.geography import GeographicPoint from octopoes.models.ooi.monitoring import Application, Incident from octopoes.models.ooi.network import ( AutonomousSystem, @@ -161,6 +162,7 @@ | ReportsType | ScanType | Report + | GeographicPoint ) OOIType = ConcreteOOIType | NetworkType | FindingTypeType From df6f526ba50351ec2824648dd2d6fcac1afec3ac Mon Sep 17 00:00:00 2001 From: JP Bruins Slot Date: Tue, 13 Aug 2024 10:14:19 +0200 Subject: [PATCH 057/112] Flexible scheduling (#2786) Co-authored-by: Jan Klopper Co-authored-by: ammar92 --- boefjes/boefjes/api.py | 10 +- boefjes/boefjes/app.py | 9 +- boefjes/boefjes/clients/scheduler_client.py | 30 +- boefjes/tests/conftest.py | 34 +- .../scheduler/pop_response_boefje.json | 8 +- .../scheduler/pop_response_boefje_no_ooi.json | 8 +- .../scheduler/pop_response_normalizer.json | 7 +- .../examples/scheduler/should_crash.json | 7 +- boefjes/tests/test_api.py | 8 +- mula/.ci/docker-compose.yml | 4 +- mula/docs/openapi.json | 1215 +++++++++++------ mula/logging.json | 7 + mula/poetry.lock | 448 +++--- mula/pyproject.toml | 3 + mula/requirements-dev.txt | 403 +++--- mula/requirements.txt | 271 ++-- .../versions/0008_add_task_schedule.py | 182 +++ .../scheduler/connectors/services/octopoes.py | 2 +- mula/scheduler/context/context.py | 6 +- mula/scheduler/models/__init__.py | 6 +- mula/scheduler/models/errors.py | 2 + mula/scheduler/models/queue.py | 65 +- mula/scheduler/models/raw_data.py | 4 +- mula/scheduler/models/request.py | 8 - mula/scheduler/models/schedule.py | 84 ++ mula/scheduler/models/{tasks.py => task.py} | 49 +- mula/scheduler/queues/__init__.py | 4 +- mula/scheduler/queues/boefje.py | 24 - mula/scheduler/queues/errors.py | 4 +- mula/scheduler/queues/normalizer.py | 35 - mula/scheduler/queues/pq.py | 87 +- mula/scheduler/schedulers/boefje.py | 653 +++++---- mula/scheduler/schedulers/normalizer.py | 233 ++-- mula/scheduler/schedulers/scheduler.py | 542 +++++--- mula/scheduler/server/handlers/__init__.py | 1 + mula/scheduler/server/handlers/queues.py | 37 +- mula/scheduler/server/handlers/schedules.py | 184 +++ mula/scheduler/server/handlers/tasks.py | 36 +- mula/scheduler/server/pagination.py | 34 - mula/scheduler/server/serializers/__init__.py | 2 +- mula/scheduler/server/serializers/p_item.py | 8 - mula/scheduler/server/serializers/schedule.py | 18 + mula/scheduler/server/serializers/task.py | 18 +- mula/scheduler/server/server.py | 1 + mula/scheduler/storage/__init__.py | 1 + mula/scheduler/storage/filters/comparison.py | 17 +- mula/scheduler/storage/filters/filters.py | 16 +- mula/scheduler/storage/pq_store.py | 111 +- mula/scheduler/storage/schedule_store.py | 120 ++ mula/scheduler/storage/task_store.py | 4 +- mula/scheduler/utils/cron.py | 11 + mula/tests/integration/test_api.py | 319 ++++- .../integration/test_boefje_scheduler.py | 945 +++++++------ .../integration/test_normalizer_scheduler.py | 135 +- mula/tests/integration/test_pq_store.py | 84 ++ mula/tests/integration/test_schedule_store.py | 258 ++++ mula/tests/integration/test_scheduler.py | 323 ++++- mula/tests/integration/test_task_store.py | 973 ++----------- mula/tests/mocks/item.py | 23 + mula/tests/mocks/queue.py | 2 +- mula/tests/mocks/scheduler.py | 5 + mula/tests/scripts/.gitignore | 2 - mula/tests/scripts/__init__.py | 0 mula/tests/scripts/benchmark.py | 173 --- mula/tests/scripts/load.py | 145 -- mula/tests/simulation/test_simulation.py | 8 +- mula/tests/unit/test_queue.py | 135 +- mula/tests/utils/__init__.py | 1 + mula/tests/utils/functions.py | 70 +- mula/tests/utils/json.py | 9 + rocky/rocky/scheduler.py | 61 +- .../templates/tasks/boefje_task_detail.html | 4 +- rocky/rocky/templates/tasks/boefjes.html | 4 +- rocky/rocky/templates/tasks/normalizers.html | 6 +- .../templates/tasks/ooi_detail_task_list.html | 4 +- .../tasks/partials/task_actions.html | 2 +- .../tasks/plugin_detail_task_list.html | 4 +- rocky/rocky/views/scheduler.py | 59 +- rocky/rocky/views/task_detail.py | 7 +- rocky/tests/conftest.py | 117 +- 80 files changed, 5063 insertions(+), 3896 deletions(-) create mode 100644 mula/scheduler/alembic/versions/0008_add_task_schedule.py create mode 100644 mula/scheduler/models/errors.py delete mode 100644 mula/scheduler/models/request.py create mode 100644 mula/scheduler/models/schedule.py rename mula/scheduler/models/{tasks.py => task.py} (79%) delete mode 100644 mula/scheduler/queues/boefje.py delete mode 100644 mula/scheduler/queues/normalizer.py create mode 100644 mula/scheduler/server/handlers/schedules.py delete mode 100644 mula/scheduler/server/pagination.py delete mode 100644 mula/scheduler/server/serializers/p_item.py create mode 100644 mula/scheduler/server/serializers/schedule.py create mode 100644 mula/scheduler/storage/schedule_store.py create mode 100644 mula/scheduler/utils/cron.py create mode 100644 mula/tests/integration/test_pq_store.py create mode 100644 mula/tests/integration/test_schedule_store.py create mode 100644 mula/tests/mocks/item.py delete mode 100644 mula/tests/scripts/.gitignore delete mode 100644 mula/tests/scripts/__init__.py delete mode 100644 mula/tests/scripts/benchmark.py delete mode 100644 mula/tests/scripts/load.py create mode 100644 mula/tests/utils/json.py diff --git a/boefjes/boefjes/api.py b/boefjes/boefjes/api.py index 155d609c973..78eaaf3ca33 100644 --- a/boefjes/boefjes/api.py +++ b/boefjes/boefjes/api.py @@ -122,7 +122,7 @@ async def boefje_output( bytes_client.save_boefje_meta(boefje_meta) if boefje_output.files: - mime_types = _default_mime_types(task.p_item.data.boefje) + mime_types = _default_mime_types(task.data.boefje) for file in boefje_output.files: raw = base64.b64decode(file.content) # when supported, also save file.name to Bytes @@ -149,13 +149,13 @@ def get_task(task_id, scheduler_client): def create_boefje_meta(task, local_repository): - boefje = task.p_item.data.boefje + boefje = task.data.boefje boefje_resource = local_repository.by_id(boefje.id) env_keys = boefje_resource.environment_keys - environment = get_environment_settings(task.p_item.data, env_keys) if env_keys else {} + environment = get_environment_settings(task.data, env_keys) if env_keys else {} - organization = task.p_item.data.organization - input_ooi = task.p_item.data.input_ooi + organization = task.data.organization + input_ooi = task.data.input_ooi arguments = {"oci_arguments": boefje_resource.oci_arguments} if input_ooi: diff --git a/boefjes/boefjes/app.py b/boefjes/boefjes/app.py index 16f33fa4048..731cbd7e19c 100644 --- a/boefjes/boefjes/app.py +++ b/boefjes/boefjes/app.py @@ -9,12 +9,7 @@ from httpx import HTTPError from pydantic import ValidationError -from boefjes.clients.scheduler_client import ( - QueuePrioritizedItem, - SchedulerAPIClient, - SchedulerClientInterface, - TaskStatus, -) +from boefjes.clients.scheduler_client import SchedulerAPIClient, SchedulerClientInterface, Task, TaskStatus from boefjes.config import Settings from boefjes.job_handler import BoefjeHandler, NormalizerHandler, bytes_api_client from boefjes.local import LocalBoefjeJobRunner, LocalNormalizerJobRunner @@ -192,7 +187,7 @@ def exit(self, queue_type: WorkerManager.Queue, signum: int | None = None): logger.info("Received %s, exiting", signal.Signals(signum).name) if not self.task_queue.empty(): - items: list[QueuePrioritizedItem] = [self.task_queue.get() for _ in range(self.task_queue.qsize())] + items: list[Task] = [self.task_queue.get() for _ in range(self.task_queue.qsize())] for p_item in items: try: diff --git a/boefjes/boefjes/clients/scheduler_client.py b/boefjes/boefjes/clients/scheduler_client.py index 3611e687b4b..5e07d83d0be 100644 --- a/boefjes/boefjes/clients/scheduler_client.py +++ b/boefjes/boefjes/clients/scheduler_client.py @@ -13,18 +13,6 @@ class Queue(BaseModel): size: int -class QueuePrioritizedItem(BaseModel): - """Representation of a queue.PrioritizedItem on the priority queue. Used - for unmarshalling of priority queue prioritized items to a JSON - representation. - """ - - id: uuid.UUID - priority: int - hash: str | None = None - data: BoefjeMeta | NormalizerMeta - - class TaskStatus(Enum): """Status of a task.""" @@ -34,14 +22,18 @@ class TaskStatus(Enum): RUNNING = "running" COMPLETED = "completed" FAILED = "failed" + CANCELLED = "cancelled" class Task(BaseModel): id: uuid.UUID scheduler_id: str - type: str - p_item: QueuePrioritizedItem + schedule_id: str | None + priority: int status: TaskStatus + type: str + hash: str | None = None + data: BoefjeMeta | NormalizerMeta created_at: datetime.datetime modified_at: datetime.datetime @@ -50,7 +42,7 @@ class SchedulerClientInterface: def get_queues(self) -> list[Queue]: raise NotImplementedError() - def pop_item(self, queue: str) -> QueuePrioritizedItem | None: + def pop_item(self, queue: str) -> Task | None: raise NotImplementedError() def patch_task(self, task_id: uuid.UUID, status: TaskStatus) -> None: @@ -59,7 +51,7 @@ def patch_task(self, task_id: uuid.UUID, status: TaskStatus) -> None: def get_task(self, task_id: uuid.UUID) -> Task: raise NotImplementedError() - def push_item(self, queue_id: str, p_item: QueuePrioritizedItem) -> None: + def push_item(self, queue_id: str, p_item: Task) -> None: raise NotImplementedError() @@ -77,13 +69,13 @@ def get_queues(self) -> list[Queue]: return TypeAdapter(list[Queue]).validate_json(response.content) - def pop_item(self, queue: str) -> QueuePrioritizedItem | None: + def pop_item(self, queue: str) -> Task | None: response = self._session.post(f"/queues/{queue}/pop") self._verify_response(response) - return TypeAdapter(QueuePrioritizedItem | None).validate_json(response.content) + return TypeAdapter(Task | None).validate_json(response.content) - def push_item(self, queue_id: str, p_item: QueuePrioritizedItem) -> None: + def push_item(self, queue_id: str, p_item: Task) -> None: response = self._session.post(f"/queues/{queue_id}/push", content=p_item.json()) self._verify_response(response) diff --git a/boefjes/tests/conftest.py b/boefjes/tests/conftest.py index fe1a5d6b789..d94dc074344 100644 --- a/boefjes/tests/conftest.py +++ b/boefjes/tests/conftest.py @@ -14,7 +14,7 @@ from boefjes.app import SchedulerWorkerManager from boefjes.clients.bytes_client import BytesAPIClient -from boefjes.clients.scheduler_client import Queue, QueuePrioritizedItem, SchedulerClientInterface, Task, TaskStatus +from boefjes.clients.scheduler_client import Queue, SchedulerClientInterface, Task, TaskStatus from boefjes.config import Settings, settings from boefjes.job_handler import bytes_api_client from boefjes.job_models import BoefjeMeta, NormalizerMeta @@ -52,25 +52,25 @@ def __init__( self._iterations = 0 self._tasks: dict[str, Task] = multiprocessing.Manager().dict() - self._popped_items: dict[str, QueuePrioritizedItem] = multiprocessing.Manager().dict() - self._pushed_items: dict[str, tuple[str, QueuePrioritizedItem]] = multiprocessing.Manager().dict() + self._popped_items: dict[str, Task] = multiprocessing.Manager().dict() + self._pushed_items: dict[str, tuple[str, Task]] = multiprocessing.Manager().dict() def get_queues(self) -> list[Queue]: time.sleep(self.sleep_time) return TypeAdapter(list[Queue]).validate_json(self.queue_response) - def pop_item(self, queue: str) -> QueuePrioritizedItem | None: + def pop_item(self, queue: str) -> Task | None: time.sleep(self.sleep_time) try: if WorkerManager.Queue.BOEFJES.value in queue: - p_item = TypeAdapter(QueuePrioritizedItem).validate_json(self.boefje_responses.pop(0)) + p_item = TypeAdapter(Task).validate_json(self.boefje_responses.pop(0)) self._popped_items[str(p_item.id)] = p_item self._tasks[str(p_item.id)] = self._task_from_id(p_item.id) return p_item if WorkerManager.Queue.NORMALIZERS.value in queue: - p_item = TypeAdapter(QueuePrioritizedItem).validate_json(self.normalizer_responses.pop(0)) + p_item = TypeAdapter(Task).validate_json(self.normalizer_responses.pop(0)) self._popped_items[str(p_item.id)] = p_item return p_item except IndexError: @@ -92,17 +92,9 @@ def get_task(self, task_id: UUID) -> Task: return self._task_from_id(task_id) if str(task_id) not in self._tasks else self._tasks[str(task_id)] def _task_from_id(self, task_id: UUID): - return Task( - id=task_id, - scheduler_id="test", - type="test", - p_item=self._popped_items[str(task_id)], - status=TaskStatus.DISPATCHED, - created_at=datetime.now(timezone.utc), - modified_at=datetime.now(timezone.utc), - ) + return self._popped_items[str(task_id)] - def push_item(self, queue_id: str, p_item: QueuePrioritizedItem) -> None: + def push_item(self, queue_id: str, p_item: Task) -> None: self._pushed_items[str(p_item.id)] = (queue_id, p_item) @@ -131,10 +123,12 @@ def item_handler(tmp_path: Path): @pytest.fixture def manager(item_handler: MockHandler, tmp_path: Path) -> SchedulerWorkerManager: scheduler_client = MockSchedulerClient( - get_dummy_data("scheduler/queues_response.json"), - 2 * [get_dummy_data("scheduler/pop_response_boefje.json")] + [get_dummy_data("scheduler/should_crash.json")], - [get_dummy_data("scheduler/pop_response_normalizer.json")], - tmp_path / "patch_task_log", + queue_response=get_dummy_data("scheduler/queues_response.json"), + boefje_responses=( + 2 * [get_dummy_data("scheduler/pop_response_boefje.json")] + [get_dummy_data("scheduler/should_crash.json")] + ), + normalizer_responses=[get_dummy_data("scheduler/pop_response_normalizer.json")], + log_path=tmp_path / "patch_task_log", ) return SchedulerWorkerManager(item_handler, scheduler_client, Settings(pool_size=1, poll_interval=0.01), "DEBUG") diff --git a/boefjes/tests/examples/scheduler/pop_response_boefje.json b/boefjes/tests/examples/scheduler/pop_response_boefje.json index 638ef115b8e..29e7d5dfb72 100644 --- a/boefjes/tests/examples/scheduler/pop_response_boefje.json +++ b/boefjes/tests/examples/scheduler/pop_response_boefje.json @@ -1,6 +1,10 @@ { "id": "70da7d4f-f41f-4940-901b-d98a92e9014b", "priority": 1, + "scheduler_id": "boefje-_dev", + "schedule_id": null, + "status": "dispatched", + "type": "boefje", "hash": "70da7d4f-f41f-4940-901b-d98a92e9014b", "data": { "id": "70da7d4f-f41f-4940-901b-d98a92e9014b", @@ -15,5 +19,7 @@ "runnable_hash": null, "environment": null, "ended_at": null - } + }, + "created_at": "2021-06-29T14:00:00", + "modified_at": "2021-06-29T14:00:00" } diff --git a/boefjes/tests/examples/scheduler/pop_response_boefje_no_ooi.json b/boefjes/tests/examples/scheduler/pop_response_boefje_no_ooi.json index 10ba87f09b0..5ce2ad45c9e 100644 --- a/boefjes/tests/examples/scheduler/pop_response_boefje_no_ooi.json +++ b/boefjes/tests/examples/scheduler/pop_response_boefje_no_ooi.json @@ -1,6 +1,10 @@ { "id": "70da7d4f-f41f-4940-901b-d98a92e9014b", "priority": 1, + "scheduler_id": "boefje-_dev", + "schedule_id": null, + "status": "dispatched", + "type": "boefje", "hash": "70da7d4f-f41f-4940-901b-d98a92e9014b", "data": { "id": "70da7d4f-f41f-4940-901b-d98a92e9014b", @@ -15,5 +19,7 @@ "runnable_hash": null, "environment": null, "ended_at": null - } + }, + "created_at": "2021-06-29T14:00:00", + "modified_at": "2021-06-29T14:00:00" } diff --git a/boefjes/tests/examples/scheduler/pop_response_normalizer.json b/boefjes/tests/examples/scheduler/pop_response_normalizer.json index 3e04ff3b720..274a9798c28 100644 --- a/boefjes/tests/examples/scheduler/pop_response_normalizer.json +++ b/boefjes/tests/examples/scheduler/pop_response_normalizer.json @@ -2,6 +2,9 @@ "id": "60da7d4ff41f4940901bd98a92e9014b", "priority": 1, "scheduler_id": "normalizer-_dev", + "schedule_id": null, + "status": "dispatched", + "type": "normalizer", "hash": "7e698c377cfd85015c0d7086b76b76b4", "data": { "id": "60da7d4ff41f4940901bd98a92e9014b", @@ -48,5 +51,7 @@ "normalizer": { "id": "kat_dns_normalize" } - } + }, + "created_at": "2021-06-29T14:00:00", + "modified_at": "2021-06-29T14:00:00" } diff --git a/boefjes/tests/examples/scheduler/should_crash.json b/boefjes/tests/examples/scheduler/should_crash.json index 6eb1e8023f2..f267bf5fc57 100644 --- a/boefjes/tests/examples/scheduler/should_crash.json +++ b/boefjes/tests/examples/scheduler/should_crash.json @@ -2,6 +2,9 @@ "id": "9071c9fd-2b9f-440f-a524-ef1ca4824fd4", "priority": 1, "scheduler_id": "boefje-_dev", + "schedule_id": null, + "status": "dispatched", + "type": "boefje", "hash": "7e698c377cfd85015c0d7086b76b76b4", "data": { "id": "9071c9fd-2b9f-440f-a524-ef1ca4824fd4", @@ -34,5 +37,7 @@ "input_ooi": "Hostname|internet|test.test", "organization": "_dev", "dispatches": [] - } + }, + "created_at": "2021-06-29T14:00:00", + "modified_at": "2021-06-29T14:00:00" } diff --git a/boefjes/tests/test_api.py b/boefjes/tests/test_api.py index d9b4483eda9..e1e95b7b50e 100644 --- a/boefjes/tests/test_api.py +++ b/boefjes/tests/test_api.py @@ -8,10 +8,10 @@ def _mocked_scheduler_client(tmp_path: Path): return MockSchedulerClient( - get_dummy_data("scheduler/queues_response.json"), - [get_dummy_data("scheduler/pop_response_boefje_no_ooi.json")], - [], - tmp_path / "patch_task_log", + queue_response=get_dummy_data("scheduler/queues_response.json"), + boefje_responses=[get_dummy_data("scheduler/pop_response_boefje_no_ooi.json")], + normalizer_responses=[], + log_path=tmp_path / "patch_task_log", ) diff --git a/mula/.ci/docker-compose.yml b/mula/.ci/docker-compose.yml index 6b10342ebad..162f07c27e4 100644 --- a/mula/.ci/docker-compose.yml +++ b/mula/.ci/docker-compose.yml @@ -28,7 +28,9 @@ services: - ci_rabbitmq ci_postgres: - image: docker.io/library/postgres:15 + image: postgres:15 + command: + ["postgres", "-c", "log_statement=all", "-c", "log_destination=stderr"] healthcheck: test: ["CMD", "gosu", "postgres", "pg_isready"] interval: 3s diff --git a/mula/docs/openapi.json b/mula/docs/openapi.json index c292ae9b88b..94069a59f99 100644 --- a/mula/docs/openapi.json +++ b/mula/docs/openapi.json @@ -1,22 +1,27 @@ { "openapi": "3.1.0", "info": { - "title": "FastAPI", + "title": "Scheduler", + "description": "Scheduler API", "version": "0.1.0" }, "paths": { - "/": { + "/schedulers": { "get": { - "summary": "Root", - "description": "Root endpoint", - "operationId": "root__get", + "summary": "List", + "description": "List all schedulers", + "operationId": "list_schedulers_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { - "title": "Response Root Get" + "items": { + "$ref": "#/components/schemas/Scheduler" + }, + "type": "array", + "title": "Response List Schedulers Get" } } } @@ -24,37 +29,87 @@ } } }, - "/health": { + "/schedulers/{scheduler_id}": { "get": { - "summary": "Health", - "description": "Health check endpoint", - "operationId": "health_health_get", + "summary": "Get", + "description": "Get a scheduler", + "operationId": "get_schedulers__scheduler_id__get", + "parameters": [ + { + "name": "scheduler_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Scheduler Id" + } + } + ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ServiceHealth" + "$ref": "#/components/schemas/Scheduler" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" } } } } } - } - }, - "/metrics": { - "get": { - "summary": "Metrics", - "description": "OpenMetrics compliant metrics endpoint", - "operationId": "metrics_metrics_get", + }, + "patch": { + "summary": "Patch", + "description": "Update a scheduler", + "operationId": "patch_schedulers__scheduler_id__patch", + "parameters": [ + { + "name": "scheduler_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Scheduler Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Scheduler" + } + } + } + }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { - "title": "Response Metrics Metrics Get" + "$ref": "#/components/schemas/Scheduler" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" } } } @@ -62,11 +117,11 @@ } } }, - "/schedulers": { + "/queues": { "get": { - "summary": "Get Schedulers", - "description": "List all schedulers", - "operationId": "get_schedulers_schedulers_get", + "summary": "List", + "description": "List all queues", + "operationId": "list_queues_get", "responses": { "200": { "description": "Successful Response", @@ -74,10 +129,10 @@ "application/json": { "schema": { "items": { - "$ref": "#/components/schemas/Scheduler-Output" + "$ref": "#/components/schemas/Queue" }, "type": "array", - "title": "Response Get Schedulers Schedulers Get" + "title": "Response List Queues Get" } } } @@ -85,19 +140,19 @@ } } }, - "/schedulers/{scheduler_id}": { + "/queues/{queue_id}": { "get": { - "summary": "Get Scheduler", - "description": "Get a scheduler", - "operationId": "get_scheduler_schedulers__scheduler_id__get", + "summary": "Get", + "description": "Get a queue", + "operationId": "get_queues__queue_id__get", "parameters": [ { - "name": "scheduler_id", + "name": "queue_id", "in": "path", "required": true, "schema": { "type": "string", - "title": "Scheduler Id" + "title": "Queue Id" } } ], @@ -107,7 +162,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Scheduler-Output" + "$ref": "#/components/schemas/Queue" } } } @@ -123,28 +178,37 @@ } } } - }, - "patch": { - "summary": "Patch Scheduler", - "description": "Update a scheduler", - "operationId": "patch_scheduler_schedulers__scheduler_id__patch", + } + }, + "/queues/{queue_id}/pop": { + "post": { + "summary": "Pop", + "description": "Pop an item from a queue", + "operationId": "pop_queues__queue_id__pop_post", "parameters": [ { - "name": "scheduler_id", + "name": "queue_id", "in": "path", "required": true, "schema": { "type": "string", - "title": "Scheduler Id" + "title": "Queue Id" } } ], "requestBody": { - "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Scheduler-Input" + "anyOf": [ + { + "$ref": "#/components/schemas/FilterRequest" + }, + { + "type": "null" + } + ], + "title": "Filters" } } } @@ -155,7 +219,15 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Scheduler-Output" + "anyOf": [ + { + "$ref": "#/components/schemas/Task-Output" + }, + { + "type": "null" + } + ], + "title": "Response Pop Queues Queue Id Pop Post" } } } @@ -173,30 +245,72 @@ } } }, - "/schedulers/{scheduler_id}/tasks": { - "get": { - "summary": "List Tasks", - "description": "List all tasks for a scheduler", - "operationId": "list_tasks_schedulers__scheduler_id__tasks_get", + "/queues/{queue_id}/push": { + "post": { + "summary": "Push", + "description": "Push an item to a queue", + "operationId": "push_queues__queue_id__push_post", "parameters": [ { - "name": "scheduler_id", + "name": "queue_id", "in": "path", "required": true, "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" + "type": "string", + "title": "Queue Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Task-Input" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/Task-Output" + }, + { + "type": "null" + } + ], + "title": "Response Push Queues Queue Id Push Post" } - ], - "title": "Scheduler Id" + } } }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/schedules": { + "get": { + "summary": "List", + "description": "List all schedules", + "operationId": "list_schedules_post", + "parameters": [ { - "name": "task_type", + "name": "schedule_hash", "in": "query", "required": false, "schema": { @@ -208,23 +322,24 @@ "type": "null" } ], - "title": "Task Type" + "title": "Schedule Hash" } }, { - "name": "status", + "name": "enabled", "in": "query", "required": false, "schema": { "anyOf": [ { - "type": "string" + "type": "boolean" }, { "type": "null" } ], - "title": "Status" + "default": true, + "title": "Enabled" } }, { @@ -248,7 +363,7 @@ } }, { - "name": "min_created_at", + "name": "min_deadline_at", "in": "query", "required": false, "schema": { @@ -261,11 +376,11 @@ "type": "null" } ], - "title": "Min Created At" + "title": "Min Deadline At" } }, { - "name": "max_created_at", + "name": "max_deadline_at", "in": "query", "required": false, "schema": { @@ -278,59 +393,44 @@ "type": "null" } ], - "title": "Max Created At" + "title": "Max Deadline At" } }, { - "name": "input_ooi", + "name": "min_created_at", "in": "query", "required": false, "schema": { "anyOf": [ { - "type": "string" + "type": "string", + "format": "date-time" }, { "type": "null" } ], - "title": "Input Ooi" + "title": "Min Created At" } }, { - "name": "plugin_id", + "name": "max_created_at", "in": "query", "required": false, "schema": { "anyOf": [ { - "type": "string" + "type": "string", + "format": "date-time" }, { "type": "null" } ], - "title": "Plugin Id" + "title": "Max Created At" } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/FilterRequest" - }, - { - "type": "null" - } - ], - "title": "Filters" - } - } - } - }, "responses": { "200": { "description": "Successful Response", @@ -353,32 +453,14 @@ } } } - } - }, - "/tasks": { + }, "post": { - "summary": "List Tasks", - "description": "List all tasks", - "operationId": "list_tasks_tasks_post", + "summary": "List", + "description": "List all schedules", + "operationId": "list_schedules_post", "parameters": [ { - "name": "scheduler_id", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Scheduler Id" - } - }, - { - "name": "task_type", + "name": "schedule_hash", "in": "query", "required": false, "schema": { @@ -390,23 +472,24 @@ "type": "null" } ], - "title": "Task Type" + "title": "Schedule Hash" } }, { - "name": "status", + "name": "enabled", "in": "query", "required": false, "schema": { "anyOf": [ { - "type": "string" + "type": "boolean" }, { "type": "null" } ], - "title": "Status" + "default": true, + "title": "Enabled" } }, { @@ -430,7 +513,7 @@ } }, { - "name": "min_created_at", + "name": "min_deadline_at", "in": "query", "required": false, "schema": { @@ -443,11 +526,11 @@ "type": "null" } ], - "title": "Min Created At" + "title": "Min Deadline At" } }, { - "name": "max_created_at", + "name": "max_deadline_at", "in": "query", "required": false, "schema": { @@ -460,17 +543,274 @@ "type": "null" } ], - "title": "Max Created At" + "title": "Max Deadline At" } }, { - "name": "input_ooi", + "name": "min_created_at", "in": "query", "required": false, "schema": { "anyOf": [ { - "type": "string" + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Min Created At" + } + }, + { + "name": "max_created_at", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Max Created At" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/schedules/{schedule_id}": { + "get": { + "summary": "Get", + "description": "Get a schedule", + "operationId": "get_schedules__schedule_id__get", + "parameters": [ + { + "name": "schedule_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Schedule Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Schedule-Output" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "patch": { + "summary": "Patch", + "description": "Update a schedule", + "operationId": "patch_schedules__schedule_id__patch", + "parameters": [ + { + "name": "schedule_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Schedule Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Schedule-Input" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Schedule-Output" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/tasks": { + "post": { + "summary": "List", + "description": "List all tasks", + "operationId": "list_tasks_post", + "parameters": [ + { + "name": "scheduler_id", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Scheduler Id" + } + }, + { + "name": "task_type", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Task Type" + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Status" + } + }, + { + "name": "offset", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 0, + "title": "Offset" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 10, + "title": "Limit" + } + }, + { + "name": "min_created_at", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Min Created At" + } + }, + { + "name": "max_created_at", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Max Created At" + } + }, + { + "name": "input_ooi", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" }, { "type": "null" @@ -537,9 +877,9 @@ } }, "get": { - "summary": "List Tasks", + "summary": "List", "description": "List all tasks", - "operationId": "list_tasks_tasks_post", + "operationId": "list_tasks_post", "parameters": [ { "name": "scheduler_id", @@ -719,9 +1059,9 @@ }, "/tasks/stats": { "get": { - "summary": "Get Task Stats", + "summary": "Stats", "description": "Get task status counts for all schedulers in last 24 hours", - "operationId": "get_task_stats_tasks_stats_get", + "operationId": "stats_tasks_stats_get", "parameters": [ { "name": "scheduler_id", @@ -760,7 +1100,7 @@ "type": "null" } ], - "title": "Response Get Task Stats Tasks Stats Get" + "title": "Response Stats Tasks Stats Get" } } } @@ -780,9 +1120,9 @@ }, "/tasks/stats/{scheduler_id}": { "get": { - "summary": "Get Task Stats", + "summary": "Stats", "description": "Get task status counts for a scheduler in last 24 hours", - "operationId": "get_task_stats_tasks_stats__scheduler_id__get", + "operationId": "stats_tasks_stats__scheduler_id__get", "parameters": [ { "name": "scheduler_id", @@ -821,7 +1161,7 @@ "type": "null" } ], - "title": "Response Get Task Stats Tasks Stats Scheduler Id Get" + "title": "Response Stats Tasks Stats Scheduler Id Get" } } } @@ -841,9 +1181,9 @@ }, "/tasks/{task_id}": { "get": { - "summary": "Get Task", + "summary": "Get", "description": "Get a task", - "operationId": "get_task_tasks__task_id__get", + "operationId": "get_tasks__task_id__get", "parameters": [ { "name": "task_id", @@ -851,6 +1191,7 @@ "required": true, "schema": { "type": "string", + "format": "uuid", "title": "Task Id" } } @@ -861,7 +1202,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Task" + "$ref": "#/components/schemas/Task-Output" } } } @@ -879,9 +1220,9 @@ } }, "patch": { - "summary": "Patch Task", + "summary": "Patch", "description": "Update a task", - "operationId": "patch_task_tasks__task_id__patch", + "operationId": "patch_tasks__task_id__patch", "parameters": [ { "name": "task_id", @@ -889,6 +1230,7 @@ "required": true, "schema": { "type": "string", + "format": "uuid", "title": "Task Id" } } @@ -898,8 +1240,7 @@ "content": { "application/json": { "schema": { - "type": "object", - "title": "Item" + "$ref": "#/components/schemas/Task-Input" } } } @@ -910,7 +1251,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Task" + "$ref": "#/components/schemas/Task-Output" } } } @@ -928,22 +1269,18 @@ } } }, - "/queues": { + "/metrics": { "get": { - "summary": "Get Queues", - "description": "List all queues", - "operationId": "get_queues_queues_get", + "summary": "Metrics", + "description": "OpenMetrics compliant metrics endpoint", + "operationId": "metrics_metrics_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { - "items": { - "$ref": "#/components/schemas/Queue" - }, - "type": "array", - "title": "Response Get Queues Queues Get" + "title": "Response Metrics Metrics Get" } } } @@ -951,19 +1288,20 @@ } } }, - "/queues/{queue_id}": { + "/health": { "get": { - "summary": "Get Queue", - "description": "Get a queue", - "operationId": "get_queue_queues__queue_id__get", + "summary": "Health", + "description": "Health check endpoint", + "operationId": "health_health_get", "parameters": [ { - "name": "queue_id", - "in": "path", - "required": true, + "name": "externals", + "in": "query", + "required": false, "schema": { - "type": "string", - "title": "Queue Id" + "type": "boolean", + "default": false, + "title": "Externals" } } ], @@ -973,7 +1311,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Queue" + "$ref": "#/components/schemas/ServiceHealth" } } } @@ -991,114 +1329,18 @@ } } }, - "/queues/{queue_id}/pop": { - "post": { - "summary": "Pop Queue", - "description": "Pop an item from a queue", - "operationId": "pop_queue_queues__queue_id__pop_post", - "parameters": [ - { - "name": "queue_id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Queue Id" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/FilterRequest" - }, - { - "type": "null" - } - ], - "title": "Filters" - } - } - } - }, + "/": { + "get": { + "summary": "Root", + "description": "Root endpoint", + "operationId": "root__get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/PrioritizedItem-Output" - }, - { - "type": "null" - } - ], - "title": "Response Pop Queue Queues Queue Id Pop Post" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/queues/{queue_id}/push": { - "post": { - "summary": "Push Queue", - "description": "Push an item to a queue", - "operationId": "push_queue_queues__queue_id__push_post", - "parameters": [ - { - "name": "queue_id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Queue Id" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PrioritizedItem-Input" - } - } - } - }, - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Push Queue Queues Queue Id Push Post" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" + "title": "Response Root Get" } } } @@ -1176,6 +1418,10 @@ { "type": "boolean" }, + { + "type": "string", + "format": "date-time" + }, { "items": { "type": "string" @@ -1308,24 +1554,65 @@ ], "title": "PaginatedResponse" }, - "PrioritizedItem-Input": { + "Queue": { "properties": { "id": { "type": "string", - "format": "uuid", "title": "Id" }, - "scheduler_id": { + "size": { + "type": "integer", + "title": "Size" + }, + "maxsize": { + "type": "integer", + "title": "Maxsize" + }, + "item_type": { + "type": "string", + "title": "Item Type" + }, + "allow_replace": { + "type": "boolean", + "title": "Allow Replace" + }, + "allow_updates": { + "type": "boolean", + "title": "Allow Updates" + }, + "allow_priority_updates": { + "type": "boolean", + "title": "Allow Priority Updates" + }, + "pq": { "anyOf": [ { - "type": "string" + "items": { + "$ref": "#/components/schemas/Task-Output" + }, + "type": "array" }, { "type": "null" } ], - "title": "Scheduler Id" - }, + "title": "Pq" + } + }, + "type": "object", + "required": [ + "id", + "size", + "maxsize", + "item_type", + "allow_replace", + "allow_updates", + "allow_priority_updates" + ], + "title": "Queue" + }, + "Schedule-Input": { + "properties": { "hash": { "anyOf": [ { @@ -1338,208 +1625,146 @@ ], "title": "Hash" }, - "priority": { + "data": { "anyOf": [ { - "type": "integer" + "type": "object" }, { "type": "null" } ], - "title": "Priority" - }, - "data": { - "type": "object", - "title": "Data" - }, - "created_at": { - "type": "string", - "format": "date-time", - "title": "Created At" - }, - "modified_at": { - "type": "string", - "format": "date-time", - "title": "Modified At" - } - }, - "type": "object", - "required": [ - "priority", - "data" - ], - "title": "PrioritizedItem", - "description": "Representation of an queue.PrioritizedItem on the priority queue. Used\nfor unmarshalling of priority queue prioritized items to a JSON\nrepresentation." - }, - "PrioritizedItem-Output": { - "properties": { - "id": { - "type": "string", - "format": "uuid", - "title": "Id" + "title": "Data", + "default": {} }, - "scheduler_id": { + "enabled": { "anyOf": [ { - "type": "string" + "type": "boolean" }, { "type": "null" } ], - "title": "Scheduler Id" + "title": "Enabled", + "default": true }, - "hash": { + "schedule": { "anyOf": [ { - "type": "string", - "maxLength": 32 + "type": "string" }, { "type": "null" } ], - "title": "Hash" + "title": "Schedule" }, - "priority": { + "deadline_at": { "anyOf": [ { - "type": "integer" + "type": "string", + "format": "date-time" }, { "type": "null" } ], - "title": "Priority" - }, - "data": { - "type": "object", - "title": "Data" - }, - "created_at": { - "type": "string", - "format": "date-time", - "title": "Created At" - }, - "modified_at": { - "type": "string", - "format": "date-time", - "title": "Modified At" + "title": "Deadline At" } }, "type": "object", - "required": [ - "id", - "scheduler_id", - "hash", - "priority", - "data", - "created_at", - "modified_at" - ], - "title": "PrioritizedItem", - "description": "Representation of an queue.PrioritizedItem on the priority queue. Used\nfor unmarshalling of priority queue prioritized items to a JSON\nrepresentation." + "title": "Schedule" }, - "Queue": { + "Schedule-Output": { "properties": { "id": { "type": "string", + "format": "uuid", "title": "Id" }, - "size": { - "type": "integer", - "title": "Size" - }, - "maxsize": { - "type": "integer", - "title": "Maxsize" - }, - "item_type": { + "scheduler_id": { "type": "string", - "title": "Item Type" - }, - "allow_replace": { - "type": "boolean", - "title": "Allow Replace" - }, - "allow_updates": { - "type": "boolean", - "title": "Allow Updates" - }, - "allow_priority_updates": { - "type": "boolean", - "title": "Allow Priority Updates" + "title": "Scheduler Id" }, - "pq": { + "hash": { "anyOf": [ { - "items": { - "$ref": "#/components/schemas/PrioritizedItem-Output" - }, - "type": "array" + "type": "string", + "maxLength": 32 }, { "type": "null" } ], - "title": "Pq" - } - }, - "type": "object", - "required": [ - "id", - "size", - "maxsize", - "item_type", - "allow_replace", - "allow_updates", - "allow_priority_updates", - "pq" - ], - "title": "Queue" - }, - "Scheduler-Input": { - "properties": { - "id": { + "title": "Hash" + }, + "data": { "anyOf": [ { - "type": "string" + "type": "object" }, { "type": "null" } ], - "title": "Id" + "title": "Data", + "default": {} }, "enabled": { + "type": "boolean", + "title": "Enabled", + "default": true + }, + "schedule": { "anyOf": [ { - "type": "boolean" + "type": "string" }, { "type": "null" } ], - "title": "Enabled" + "title": "Schedule" }, - "priority_queue": { + "tasks": { + "items": { + "$ref": "#/components/schemas/Task-Output" + }, + "type": "array", + "title": "Tasks", + "default": [] + }, + "deadline_at": { "anyOf": [ { - "type": "object" + "type": "string", + "format": "date-time" }, { "type": "null" } ], - "title": "Priority Queue" + "title": "Deadline At" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At" + }, + "modified_at": { + "type": "string", + "format": "date-time", + "title": "Modified At" } }, "type": "object", - "title": "Scheduler", - "description": "Representation of a schedulers.Scheduler instance. Used for\nunmarshalling of schedulers to a JSON representation." + "required": [ + "scheduler_id" + ], + "title": "Schedule" }, - "Scheduler-Output": { + "Scheduler": { "properties": { "id": { "anyOf": [ @@ -1573,14 +1798,21 @@ } ], "title": "Priority Queue" + }, + "last_activity": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Last Activity" } }, "type": "object", - "required": [ - "id", - "enabled", - "priority_queue" - ], "title": "Scheduler", "description": "Representation of a schedulers.Scheduler instance. Used for\nunmarshalling of schedulers to a JSON representation." }, @@ -1614,8 +1846,7 @@ "$ref": "#/components/schemas/ServiceHealth" }, "type": "array", - "title": "Results", - "default": [] + "title": "Results" }, "externals": { "additionalProperties": { @@ -1628,17 +1859,119 @@ }, "type": "object", "required": [ - "service", - "healthy", - "version", - "additional", - "results", - "externals" + "service" ], "title": "ServiceHealth", "description": "ServiceHealth is used as response model for health check in the\nserver.Server for the health endpoint." }, - "Task": { + "Task-Input": { + "properties": { + "id": { + "anyOf": [ + { + "type": "string", + "format": "uuid" + }, + { + "type": "null" + } + ], + "title": "Id" + }, + "scheduler_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Scheduler Id" + }, + "schedule_id": { + "anyOf": [ + { + "type": "string", + "format": "uuid" + }, + { + "type": "null" + } + ], + "title": "Schedule Id" + }, + "priority": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Priority", + "default": 0 + }, + "status": { + "allOf": [ + { + "$ref": "#/components/schemas/TaskStatus" + } + ], + "default": "pending" + }, + "hash": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Hash" + }, + "data": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Data" + }, + "created_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "modified_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Modified At" + } + }, + "type": "object", + "title": "Task" + }, + "Task-Output": { "properties": { "id": { "type": "string", @@ -1646,18 +1979,71 @@ "title": "Id" }, "scheduler_id": { - "type": "string", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], "title": "Scheduler Id" }, - "type": { - "type": "string", - "title": "Type" + "schedule_id": { + "anyOf": [ + { + "type": "string", + "format": "uuid" + }, + { + "type": "null" + } + ], + "title": "Schedule Id" }, - "p_item": { - "$ref": "#/components/schemas/PrioritizedItem-Output" + "priority": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Priority", + "default": 0 }, "status": { - "$ref": "#/components/schemas/TaskStatus" + "allOf": [ + { + "$ref": "#/components/schemas/TaskStatus" + } + ], + "default": "pending" + }, + "hash": { + "anyOf": [ + { + "type": "string", + "maxLength": 32 + }, + { + "type": "null" + } + ], + "title": "Hash" + }, + "data": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Data", + "default": {} }, "created_at": { "type": "string", @@ -1671,15 +2057,6 @@ } }, "type": "object", - "required": [ - "id", - "scheduler_id", - "type", - "p_item", - "status", - "created_at", - "modified_at" - ], "title": "Task" }, "TaskStatus": { diff --git a/mula/logging.json b/mula/logging.json index 607cf1b2c22..2d7a02642d9 100644 --- a/mula/logging.json +++ b/mula/logging.json @@ -69,6 +69,13 @@ "console" ], "propagate": 0 + }, + "httpcore": { + "level": "CRITICAL", + "handlers": [ + "console" + ], + "propagate": 0 } } } diff --git a/mula/poetry.lock b/mula/poetry.lock index cc26d9b7fb4..f6c64ee22f8 100644 --- a/mula/poetry.lock +++ b/mula/poetry.lock @@ -2,13 +2,13 @@ [[package]] name = "alembic" -version = "1.13.1" +version = "1.13.2" description = "A database migration tool for SQLAlchemy." optional = false python-versions = ">=3.8" files = [ - {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, - {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, + {file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"}, + {file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"}, ] [package.dependencies] @@ -107,63 +107,83 @@ files = [ [[package]] name = "coverage" -version = "7.5.3" +version = "7.6.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, - {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, - {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, - {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, - {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, - {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, - {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, - {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, - {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, - {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, - {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, - {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, - {file = "coverage-7.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb"}, - {file = "coverage-7.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0"}, - {file = "coverage-7.5.3-cp38-cp38-win32.whl", hash = "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485"}, - {file = "coverage-7.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56"}, - {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"}, - {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"}, - {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"}, - {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"}, - {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, - {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, + {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, + {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, + {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, + {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, ] [package.dependencies] @@ -172,6 +192,21 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] +[[package]] +name = "croniter" +version = "3.0.3" +description = "croniter provides iteration for datetime object with cron like format" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.6" +files = [ + {file = "croniter-3.0.3-py2.py3-none-any.whl", hash = "sha256:b3bd11f270dc54ccd1f2397b813436015a86d30ffc5a7a9438eec1ed916f2101"}, + {file = "croniter-3.0.3.tar.gz", hash = "sha256:34117ec1741f10a7bd0ec3ad7d8f0eb8fa457a2feb9be32e6a2250e158957668"}, +] + +[package.dependencies] +python-dateutil = "*" +pytz = ">2021.1" + [[package]] name = "decorator" version = "5.1.1" @@ -202,13 +237,13 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] name = "exceptiongroup" -version = "1.2.1" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -234,13 +269,13 @@ doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"] [[package]] name = "faker" -version = "25.8.0" +version = "26.2.0" description = "Faker is a Python package that generates fake data for you." optional = false python-versions = ">=3.8" files = [ - {file = "Faker-25.8.0-py3-none-any.whl", hash = "sha256:4c40b34a9c569018d4f9d6366d71a4da8a883d5ddf2b23197be5370f29b7e1b6"}, - {file = "Faker-25.8.0.tar.gz", hash = "sha256:bdec5f2fb057d244ebef6e0ed318fea4dcbdf32c3a1a010766fc45f5d68fc68d"}, + {file = "Faker-26.2.0-py3-none-any.whl", hash = "sha256:7b123090774deff5f2cd3eb92a84dcbbf1e163f30a6d07321b7852c11bfe6a75"}, + {file = "Faker-26.2.0.tar.gz", hash = "sha256:81768de19012147521140f0d8bf5353e501ac42c1065d25e0cac455d3615c0a7"}, ] [package.dependencies] @@ -268,17 +303,17 @@ standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23 [[package]] name = "googleapis-common-protos" -version = "1.63.1" +version = "1.63.2" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.63.1.tar.gz", hash = "sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a"}, - {file = "googleapis_common_protos-1.63.1-py2.py3-none-any.whl", hash = "sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877"}, + {file = "googleapis-common-protos-1.63.2.tar.gz", hash = "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87"}, + {file = "googleapis_common_protos-1.63.2-py2.py3-none-any.whl", hash = "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945"}, ] [package.dependencies] -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] @@ -356,61 +391,61 @@ test = ["objgraph", "psutil"] [[package]] name = "grpcio" -version = "1.64.1" +version = "1.65.4" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" files = [ - {file = "grpcio-1.64.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:55697ecec192bc3f2f3cc13a295ab670f51de29884ca9ae6cd6247df55df2502"}, - {file = "grpcio-1.64.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3b64ae304c175671efdaa7ec9ae2cc36996b681eb63ca39c464958396697daff"}, - {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:bac71b4b28bc9af61efcdc7630b166440bbfbaa80940c9a697271b5e1dabbc61"}, - {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c024ffc22d6dc59000faf8ad781696d81e8e38f4078cb0f2630b4a3cf231a90"}, - {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7cd5c1325f6808b8ae31657d281aadb2a51ac11ab081ae335f4f7fc44c1721d"}, - {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0a2813093ddb27418a4c99f9b1c223fab0b053157176a64cc9db0f4557b69bd9"}, - {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2981c7365a9353f9b5c864595c510c983251b1ab403e05b1ccc70a3d9541a73b"}, - {file = "grpcio-1.64.1-cp310-cp310-win32.whl", hash = "sha256:1262402af5a511c245c3ae918167eca57342c72320dffae5d9b51840c4b2f86d"}, - {file = "grpcio-1.64.1-cp310-cp310-win_amd64.whl", hash = "sha256:19264fc964576ddb065368cae953f8d0514ecc6cb3da8903766d9fb9d4554c33"}, - {file = "grpcio-1.64.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:58b1041e7c870bb30ee41d3090cbd6f0851f30ae4eb68228955d973d3efa2e61"}, - {file = "grpcio-1.64.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bbc5b1d78a7822b0a84c6f8917faa986c1a744e65d762ef6d8be9d75677af2ca"}, - {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:5841dd1f284bd1b3d8a6eca3a7f062b06f1eec09b184397e1d1d43447e89a7ae"}, - {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8caee47e970b92b3dd948371230fcceb80d3f2277b3bf7fbd7c0564e7d39068e"}, - {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73819689c169417a4f978e562d24f2def2be75739c4bed1992435d007819da1b"}, - {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6503b64c8b2dfad299749cad1b595c650c91e5b2c8a1b775380fcf8d2cbba1e9"}, - {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1de403fc1305fd96cfa75e83be3dee8538f2413a6b1685b8452301c7ba33c294"}, - {file = "grpcio-1.64.1-cp311-cp311-win32.whl", hash = "sha256:d4d29cc612e1332237877dfa7fe687157973aab1d63bd0f84cf06692f04c0367"}, - {file = "grpcio-1.64.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e56462b05a6f860b72f0fa50dca06d5b26543a4e88d0396259a07dc30f4e5aa"}, - {file = "grpcio-1.64.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:4657d24c8063e6095f850b68f2d1ba3b39f2b287a38242dcabc166453e950c59"}, - {file = "grpcio-1.64.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:62b4e6eb7bf901719fce0ca83e3ed474ae5022bb3827b0a501e056458c51c0a1"}, - {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:ee73a2f5ca4ba44fa33b4d7d2c71e2c8a9e9f78d53f6507ad68e7d2ad5f64a22"}, - {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:198908f9b22e2672a998870355e226a725aeab327ac4e6ff3a1399792ece4762"}, - {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b9d0acaa8d835a6566c640f48b50054f422d03e77e49716d4c4e8e279665a1"}, - {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5e42634a989c3aa6049f132266faf6b949ec2a6f7d302dbb5c15395b77d757eb"}, - {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b1a82e0b9b3022799c336e1fc0f6210adc019ae84efb7321d668129d28ee1efb"}, - {file = "grpcio-1.64.1-cp312-cp312-win32.whl", hash = "sha256:55260032b95c49bee69a423c2f5365baa9369d2f7d233e933564d8a47b893027"}, - {file = "grpcio-1.64.1-cp312-cp312-win_amd64.whl", hash = "sha256:c1a786ac592b47573a5bb7e35665c08064a5d77ab88a076eec11f8ae86b3e3f6"}, - {file = "grpcio-1.64.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:a011ac6c03cfe162ff2b727bcb530567826cec85eb8d4ad2bfb4bd023287a52d"}, - {file = "grpcio-1.64.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4d6dab6124225496010bd22690f2d9bd35c7cbb267b3f14e7a3eb05c911325d4"}, - {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a5e771d0252e871ce194d0fdcafd13971f1aae0ddacc5f25615030d5df55c3a2"}, - {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3c1b90ab93fed424e454e93c0ed0b9d552bdf1b0929712b094f5ecfe7a23ad"}, - {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20405cb8b13fd779135df23fabadc53b86522d0f1cba8cca0e87968587f50650"}, - {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0cc79c982ccb2feec8aad0e8fb0d168bcbca85bc77b080d0d3c5f2f15c24ea8f"}, - {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a3a035c37ce7565b8f4f35ff683a4db34d24e53dc487e47438e434eb3f701b2a"}, - {file = "grpcio-1.64.1-cp38-cp38-win32.whl", hash = "sha256:1257b76748612aca0f89beec7fa0615727fd6f2a1ad580a9638816a4b2eb18fd"}, - {file = "grpcio-1.64.1-cp38-cp38-win_amd64.whl", hash = "sha256:0a12ddb1678ebc6a84ec6b0487feac020ee2b1659cbe69b80f06dbffdb249122"}, - {file = "grpcio-1.64.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:75dbbf415026d2862192fe1b28d71f209e2fd87079d98470db90bebe57b33179"}, - {file = "grpcio-1.64.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e3d9f8d1221baa0ced7ec7322a981e28deb23749c76eeeb3d33e18b72935ab62"}, - {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5f8b75f64d5d324c565b263c67dbe4f0af595635bbdd93bb1a88189fc62ed2e5"}, - {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c84ad903d0d94311a2b7eea608da163dace97c5fe9412ea311e72c3684925602"}, - {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:940e3ec884520155f68a3b712d045e077d61c520a195d1a5932c531f11883489"}, - {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f10193c69fc9d3d726e83bbf0f3d316f1847c3071c8c93d8090cf5f326b14309"}, - {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac15b6c2c80a4d1338b04d42a02d376a53395ddf0ec9ab157cbaf44191f3ffdd"}, - {file = "grpcio-1.64.1-cp39-cp39-win32.whl", hash = "sha256:03b43d0ccf99c557ec671c7dede64f023c7da9bb632ac65dbc57f166e4970040"}, - {file = "grpcio-1.64.1-cp39-cp39-win_amd64.whl", hash = "sha256:ed6091fa0adcc7e4ff944090cf203a52da35c37a130efa564ded02b7aff63bcd"}, - {file = "grpcio-1.64.1.tar.gz", hash = "sha256:8d51dd1c59d5fa0f34266b80a3805ec29a1f26425c2a54736133f6d87fc4968a"}, + {file = "grpcio-1.65.4-cp310-cp310-linux_armv7l.whl", hash = "sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c"}, + {file = "grpcio-1.65.4-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e"}, + {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de"}, + {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d"}, + {file = "grpcio-1.65.4-cp310-cp310-win32.whl", hash = "sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1"}, + {file = "grpcio-1.65.4-cp310-cp310-win_amd64.whl", hash = "sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec"}, + {file = "grpcio-1.65.4-cp311-cp311-linux_armv7l.whl", hash = "sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef"}, + {file = "grpcio-1.65.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4"}, + {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e"}, + {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5"}, + {file = "grpcio-1.65.4-cp311-cp311-win32.whl", hash = "sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b"}, + {file = "grpcio-1.65.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558"}, + {file = "grpcio-1.65.4-cp312-cp312-linux_armv7l.whl", hash = "sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56"}, + {file = "grpcio-1.65.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63"}, + {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a"}, + {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28"}, + {file = "grpcio-1.65.4-cp312-cp312-win32.whl", hash = "sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0"}, + {file = "grpcio-1.65.4-cp312-cp312-win_amd64.whl", hash = "sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416"}, + {file = "grpcio-1.65.4-cp38-cp38-linux_armv7l.whl", hash = "sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021"}, + {file = "grpcio-1.65.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816"}, + {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524"}, + {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7"}, + {file = "grpcio-1.65.4-cp38-cp38-win32.whl", hash = "sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a"}, + {file = "grpcio-1.65.4-cp38-cp38-win_amd64.whl", hash = "sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f"}, + {file = "grpcio-1.65.4-cp39-cp39-linux_armv7l.whl", hash = "sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733"}, + {file = "grpcio-1.65.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b"}, + {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2"}, + {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257"}, + {file = "grpcio-1.65.4-cp39-cp39-win32.whl", hash = "sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d"}, + {file = "grpcio-1.65.4-cp39-cp39-win_amd64.whl", hash = "sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9"}, + {file = "grpcio-1.65.4.tar.gz", hash = "sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.64.1)"] +protobuf = ["grpcio-tools (>=1.65.4)"] [[package]] name = "h11" @@ -481,22 +516,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.0" +version = "8.0.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.0-py3-none-any.whl", hash = "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67"}, - {file = "importlib_metadata-7.0.0.tar.gz", hash = "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7"}, + {file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"}, + {file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "iniconfig" @@ -966,22 +1001,22 @@ twisted = ["twisted"] [[package]] name = "protobuf" -version = "4.25.3" +version = "4.25.4" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, - {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, - {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, - {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, - {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, - {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, - {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, - {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, - {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, - {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, - {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, + {file = "protobuf-4.25.4-cp310-abi3-win32.whl", hash = "sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4"}, + {file = "protobuf-4.25.4-cp310-abi3-win_amd64.whl", hash = "sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d"}, + {file = "protobuf-4.25.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b"}, + {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835"}, + {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040"}, + {file = "protobuf-4.25.4-cp38-cp38-win32.whl", hash = "sha256:7e372cbbda66a63ebca18f8ffaa6948455dfecc4e9c1029312f6c2edcd86c4e1"}, + {file = "protobuf-4.25.4-cp38-cp38-win_amd64.whl", hash = "sha256:051e97ce9fa6067a4546e75cb14f90cf0232dcb3e3d508c448b8d0e4265b61c1"}, + {file = "protobuf-4.25.4-cp39-cp39-win32.whl", hash = "sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca"}, + {file = "protobuf-4.25.4-cp39-cp39-win_amd64.whl", hash = "sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f"}, + {file = "protobuf-4.25.4-py3-none-any.whl", hash = "sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978"}, + {file = "protobuf-4.25.4.tar.gz", hash = "sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d"}, ] [[package]] @@ -1159,13 +1194,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.3.4" +version = "2.4.0" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, - {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, + {file = "pydantic_settings-2.4.0-py3-none-any.whl", hash = "sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315"}, + {file = "pydantic_settings-2.4.0.tar.gz", hash = "sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88"}, ] [package.dependencies] @@ -1173,18 +1208,19 @@ pydantic = ">=2.7.0" python-dotenv = ">=0.21.0" [package.extras] +azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] toml = ["tomli (>=2.0.1)"] yaml = ["pyyaml (>=6.0.1)"] [[package]] name = "pytest" -version = "8.2.2" +version = "8.3.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"}, - {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"}, + {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, + {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, ] [package.dependencies] @@ -1192,7 +1228,7 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=1.5,<2.0" +pluggy = ">=1.5,<2" tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] @@ -1244,6 +1280,17 @@ files = [ [package.extras] cli = ["click (>=5.0)"] +[[package]] +name = "pytz" +version = "2024.1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + [[package]] name = "retry2" version = "0.9.5" @@ -1259,19 +1306,19 @@ decorator = ">=3.4.2" [[package]] name = "setuptools" -version = "71.0.3" +version = "72.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-71.0.3-py3-none-any.whl", hash = "sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207"}, - {file = "setuptools-71.0.3.tar.gz", hash = "sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d"}, + {file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"}, + {file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"}, ] [package.extras] core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (<7.4)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -1297,64 +1344,64 @@ files = [ [[package]] name = "sqlalchemy" -version = "2.0.30" +version = "2.0.32" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.30-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b48154678e76445c7ded1896715ce05319f74b1e73cf82d4f8b59b46e9c0ddc"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2753743c2afd061bb95a61a51bbb6a1a11ac1c44292fad898f10c9839a7f75b2"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7bfc726d167f425d4c16269a9a10fe8630ff6d14b683d588044dcef2d0f6be7"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4f61ada6979223013d9ab83a3ed003ded6959eae37d0d685db2c147e9143797"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a365eda439b7a00732638f11072907c1bc8e351c7665e7e5da91b169af794af"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bba002a9447b291548e8d66fd8c96a6a7ed4f2def0bb155f4f0a1309fd2735d5"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-win32.whl", hash = "sha256:0138c5c16be3600923fa2169532205d18891b28afa817cb49b50e08f62198bb8"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-win_amd64.whl", hash = "sha256:99650e9f4cf3ad0d409fed3eec4f071fadd032e9a5edc7270cd646a26446feeb"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:955991a09f0992c68a499791a753523f50f71a6885531568404fa0f231832aa0"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f69e4c756ee2686767eb80f94c0125c8b0a0b87ede03eacc5c8ae3b54b99dc46"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69c9db1ce00e59e8dd09d7bae852a9add716efdc070a3e2068377e6ff0d6fdaa"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1429a4b0f709f19ff3b0cf13675b2b9bfa8a7e79990003207a011c0db880a13"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:efedba7e13aa9a6c8407c48facfdfa108a5a4128e35f4c68f20c3407e4376aa9"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:16863e2b132b761891d6c49f0a0f70030e0bcac4fd208117f6b7e053e68668d0"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-win32.whl", hash = "sha256:2ecabd9ccaa6e914e3dbb2aa46b76dede7eadc8cbf1b8083c94d936bcd5ffb49"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-win_amd64.whl", hash = "sha256:0b3f4c438e37d22b83e640f825ef0f37b95db9aa2d68203f2c9549375d0b2260"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5a79d65395ac5e6b0c2890935bad892eabb911c4aa8e8015067ddb37eea3d56c"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9a5baf9267b752390252889f0c802ea13b52dfee5e369527da229189b8bd592e"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cb5a646930c5123f8461f6468901573f334c2c63c795b9af350063a736d0134"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:296230899df0b77dec4eb799bcea6fbe39a43707ce7bb166519c97b583cfcab3"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c62d401223f468eb4da32627bffc0c78ed516b03bb8a34a58be54d618b74d472"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3b69e934f0f2b677ec111b4d83f92dc1a3210a779f69bf905273192cf4ed433e"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-win32.whl", hash = "sha256:77d2edb1f54aff37e3318f611637171e8ec71472f1fdc7348b41dcb226f93d90"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-win_amd64.whl", hash = "sha256:b6c7ec2b1f4969fc19b65b7059ed00497e25f54069407a8701091beb69e591a5"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5a8e3b0a7e09e94be7510d1661339d6b52daf202ed2f5b1f9f48ea34ee6f2d57"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b60203c63e8f984df92035610c5fb76d941254cf5d19751faab7d33b21e5ddc0"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1dc3eabd8c0232ee8387fbe03e0a62220a6f089e278b1f0aaf5e2d6210741ad"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:40ad017c672c00b9b663fcfcd5f0864a0a97828e2ee7ab0c140dc84058d194cf"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e42203d8d20dc704604862977b1470a122e4892791fe3ed165f041e4bf447a1b"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-win32.whl", hash = "sha256:2a4f4da89c74435f2bc61878cd08f3646b699e7d2eba97144030d1be44e27584"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-win_amd64.whl", hash = "sha256:b6bf767d14b77f6a18b6982cbbf29d71bede087edae495d11ab358280f304d8e"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc0c53579650a891f9b83fa3cecd4e00218e071d0ba00c4890f5be0c34887ed3"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:311710f9a2ee235f1403537b10c7687214bb1f2b9ebb52702c5aa4a77f0b3af7"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:408f8b0e2c04677e9c93f40eef3ab22f550fecb3011b187f66a096395ff3d9fd"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37a4b4fb0dd4d2669070fb05b8b8824afd0af57587393015baee1cf9890242d9"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a943d297126c9230719c27fcbbeab57ecd5d15b0bd6bfd26e91bfcfe64220621"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0a089e218654e740a41388893e090d2e2c22c29028c9d1353feb38638820bbeb"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-win32.whl", hash = "sha256:fa561138a64f949f3e889eb9ab8c58e1504ab351d6cf55259dc4c248eaa19da6"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-win_amd64.whl", hash = "sha256:7d74336c65705b986d12a7e337ba27ab2b9d819993851b140efdf029248e818e"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae8c62fe2480dd61c532ccafdbce9b29dacc126fe8be0d9a927ca3e699b9491a"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2383146973a15435e4717f94c7509982770e3e54974c71f76500a0136f22810b"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8409de825f2c3b62ab15788635ccaec0c881c3f12a8af2b12ae4910a0a9aeef6"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0094c5dc698a5f78d3d1539853e8ecec02516b62b8223c970c86d44e7a80f6c7"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:edc16a50f5e1b7a06a2dcc1f2205b0b961074c123ed17ebda726f376a5ab0953"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f7703c2010355dd28f53deb644a05fc30f796bd8598b43f0ba678878780b6e4c"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-win32.whl", hash = "sha256:1f9a727312ff6ad5248a4367358e2cf7e625e98b1028b1d7ab7b806b7d757513"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-win_amd64.whl", hash = "sha256:a0ef36b28534f2a5771191be6edb44cc2673c7b2edf6deac6562400288664221"}, - {file = "SQLAlchemy-2.0.30-py3-none-any.whl", hash = "sha256:7108d569d3990c71e26a42f60474b4c02c8586c4681af5fd67e51a044fdea86a"}, - {file = "SQLAlchemy-2.0.30.tar.gz", hash = "sha256:2b1708916730f4830bc69d6f49d37f7698b5bd7530aca7f04f785f8849e95255"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0c9045ecc2e4db59bfc97b20516dfdf8e41d910ac6fb667ebd3a79ea54084619"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1467940318e4a860afd546ef61fefb98a14d935cd6817ed07a228c7f7c62f389"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5954463675cb15db8d4b521f3566a017c8789222b8316b1e6934c811018ee08b"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:167e7497035c303ae50651b351c28dc22a40bb98fbdb8468cdc971821b1ae533"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b27dfb676ac02529fb6e343b3a482303f16e6bc3a4d868b73935b8792edb52d0"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bf2360a5e0f7bd75fa80431bf8ebcfb920c9f885e7956c7efde89031695cafb8"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-win32.whl", hash = "sha256:306fe44e754a91cd9d600a6b070c1f2fadbb4a1a257b8781ccf33c7067fd3e4d"}, + {file = "SQLAlchemy-2.0.32-cp310-cp310-win_amd64.whl", hash = "sha256:99db65e6f3ab42e06c318f15c98f59a436f1c78179e6a6f40f529c8cc7100b22"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:21b053be28a8a414f2ddd401f1be8361e41032d2ef5884b2f31d31cb723e559f"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b178e875a7a25b5938b53b006598ee7645172fccafe1c291a706e93f48499ff5"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723a40ee2cc7ea653645bd4cf024326dea2076673fc9d3d33f20f6c81db83e1d"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:295ff8689544f7ee7e819529633d058bd458c1fd7f7e3eebd0f9268ebc56c2a0"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:49496b68cd190a147118af585173ee624114dfb2e0297558c460ad7495f9dfe2"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:acd9b73c5c15f0ec5ce18128b1fe9157ddd0044abc373e6ecd5ba376a7e5d961"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-win32.whl", hash = "sha256:9365a3da32dabd3e69e06b972b1ffb0c89668994c7e8e75ce21d3e5e69ddef28"}, + {file = "SQLAlchemy-2.0.32-cp311-cp311-win_amd64.whl", hash = "sha256:8bd63d051f4f313b102a2af1cbc8b80f061bf78f3d5bd0843ff70b5859e27924"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6bab3db192a0c35e3c9d1560eb8332463e29e5507dbd822e29a0a3c48c0a8d92"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:19d98f4f58b13900d8dec4ed09dd09ef292208ee44cc9c2fe01c1f0a2fe440e9"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd33c61513cb1b7371fd40cf221256456d26a56284e7d19d1f0b9f1eb7dd7e8"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d6ba0497c1d066dd004e0f02a92426ca2df20fac08728d03f67f6960271feec"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2b6be53e4fde0065524f1a0a7929b10e9280987b320716c1509478b712a7688c"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:916a798f62f410c0b80b63683c8061f5ebe237b0f4ad778739304253353bc1cb"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-win32.whl", hash = "sha256:31983018b74908ebc6c996a16ad3690301a23befb643093fcfe85efd292e384d"}, + {file = "SQLAlchemy-2.0.32-cp312-cp312-win_amd64.whl", hash = "sha256:4363ed245a6231f2e2957cccdda3c776265a75851f4753c60f3004b90e69bfeb"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b8afd5b26570bf41c35c0121801479958b4446751a3971fb9a480c1afd85558e"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c750987fc876813f27b60d619b987b057eb4896b81117f73bb8d9918c14f1cad"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ada0102afff4890f651ed91120c1120065663506b760da4e7823913ebd3258be"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:78c03d0f8a5ab4f3034c0e8482cfcc415a3ec6193491cfa1c643ed707d476f16"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:3bd1cae7519283ff525e64645ebd7a3e0283f3c038f461ecc1c7b040a0c932a1"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-win32.whl", hash = "sha256:01438ebcdc566d58c93af0171c74ec28efe6a29184b773e378a385e6215389da"}, + {file = "SQLAlchemy-2.0.32-cp37-cp37m-win_amd64.whl", hash = "sha256:4979dc80fbbc9d2ef569e71e0896990bc94df2b9fdbd878290bd129b65ab579c"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c742be912f57586ac43af38b3848f7688863a403dfb220193a882ea60e1ec3a"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:62e23d0ac103bcf1c5555b6c88c114089587bc64d048fef5bbdb58dfd26f96da"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:251f0d1108aab8ea7b9aadbd07fb47fb8e3a5838dde34aa95a3349876b5a1f1d"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef18a84e5116340e38eca3e7f9eeaaef62738891422e7c2a0b80feab165905f"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3eb6a97a1d39976f360b10ff208c73afb6a4de86dd2a6212ddf65c4a6a2347d5"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0c1c9b673d21477cec17ab10bc4decb1322843ba35b481585facd88203754fc5"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-win32.whl", hash = "sha256:c41a2b9ca80ee555decc605bd3c4520cc6fef9abde8fd66b1cf65126a6922d65"}, + {file = "SQLAlchemy-2.0.32-cp38-cp38-win_amd64.whl", hash = "sha256:8a37e4d265033c897892279e8adf505c8b6b4075f2b40d77afb31f7185cd6ecd"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:52fec964fba2ef46476312a03ec8c425956b05c20220a1a03703537824b5e8e1"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:328429aecaba2aee3d71e11f2477c14eec5990fb6d0e884107935f7fb6001632"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85a01b5599e790e76ac3fe3aa2f26e1feba56270023d6afd5550ed63c68552b3"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaf04784797dcdf4c0aa952c8d234fa01974c4729db55c45732520ce12dd95b4"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4488120becf9b71b3ac718f4138269a6be99a42fe023ec457896ba4f80749525"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:14e09e083a5796d513918a66f3d6aedbc131e39e80875afe81d98a03312889e6"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-win32.whl", hash = "sha256:0d322cc9c9b2154ba7e82f7bf25ecc7c36fbe2d82e2933b3642fc095a52cfc78"}, + {file = "SQLAlchemy-2.0.32-cp39-cp39-win_amd64.whl", hash = "sha256:7dd8583df2f98dea28b5cd53a1beac963f4f9d087888d75f22fcc93a07cf8d84"}, + {file = "SQLAlchemy-2.0.32-py3-none-any.whl", hash = "sha256:e567a8793a692451f706b363ccf3c45e056b67d90ead58c3bc9471af5d212202"}, + {file = "SQLAlchemy-2.0.32.tar.gz", hash = "sha256:c1b88cc8b02b6a5f0efb0345a03672d4c897dc7d92585176f88c67346f565ea8"}, ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} +greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} typing-extensions = ">=4.6.0" [package.extras] @@ -1427,6 +1474,17 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "types-croniter" +version = "3.0.3.20240731" +description = "Typing stubs for croniter" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-croniter-3.0.3.20240731.tar.gz", hash = "sha256:7a170660642da662c704a463b011e31c049f5a218d27d30199a80ac5e8d15002"}, + {file = "types_croniter-3.0.3.20240731-py3-none-any.whl", hash = "sha256:da039d543e07b1db4ad93680cb837afd0f5c64974970287da8c6432d19441b71"}, +] + [[package]] name = "typing-extensions" version = "4.12.2" @@ -1554,4 +1612,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "0774b92f71998642b563e29043f09810f92a2fee9db1bcbfbaaa6f2ee59fecc5" +content-hash = "044202695a2ec6a10e479b05d6a2ba72b3ea78231fc2496b0e27918cfb253926" diff --git a/mula/pyproject.toml b/mula/pyproject.toml index 68e7a15a09f..12258110ad2 100644 --- a/mula/pyproject.toml +++ b/mula/pyproject.toml @@ -8,6 +8,7 @@ license = "EUPL" [tool.poetry.dependencies] python = "^3.10" alembic = "^1.12.1" +croniter = "^3.0.3" mmh3 = "^4.0.1" pika = "^1.3.2" prometheus-client = "^0.19.0" @@ -18,6 +19,8 @@ python-dotenv = "^1.0.0" retry2 = "^0.9.5" sqlalchemy = "^2.0.23" structlog = "^23.2.0" +types-croniter = "^3.0.3.20240731" +typing-extensions = "^4.8.0" uvicorn = "^0.29.0" httpx = "^0.27.0" diff --git a/mula/requirements-dev.txt b/mula/requirements-dev.txt index a2516af05ad..a8404516c76 100644 --- a/mula/requirements-dev.txt +++ b/mula/requirements-dev.txt @@ -1,6 +1,6 @@ -alembic==1.13.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43 \ - --hash=sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595 +alembic==1.13.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef \ + --hash=sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953 annotated-types==0.7.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \ --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89 @@ -19,81 +19,104 @@ click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and (platform_system == "Windows" or sys_platform == "win32") \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 -coverage[toml]==7.5.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523 \ - --hash=sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f \ - --hash=sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d \ - --hash=sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb \ - --hash=sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0 \ - --hash=sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c \ - --hash=sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98 \ - --hash=sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83 \ - --hash=sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8 \ - --hash=sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7 \ - --hash=sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac \ - --hash=sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84 \ - --hash=sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb \ - --hash=sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3 \ - --hash=sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884 \ - --hash=sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614 \ - --hash=sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd \ - --hash=sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807 \ - --hash=sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd \ - --hash=sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8 \ - --hash=sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc \ - --hash=sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db \ - --hash=sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0 \ - --hash=sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08 \ - --hash=sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232 \ - --hash=sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d \ - --hash=sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a \ - --hash=sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1 \ - --hash=sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286 \ - --hash=sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303 \ - --hash=sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341 \ - --hash=sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84 \ - --hash=sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45 \ - --hash=sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc \ - --hash=sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec \ - --hash=sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd \ - --hash=sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155 \ - --hash=sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52 \ - --hash=sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d \ - --hash=sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485 \ - --hash=sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31 \ - --hash=sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d \ - --hash=sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d \ - --hash=sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d \ - --hash=sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85 \ - --hash=sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce \ - --hash=sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb \ - --hash=sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974 \ - --hash=sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24 \ - --hash=sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56 \ - --hash=sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9 \ - --hash=sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35 +coverage[toml]==7.6.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca \ + --hash=sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d \ + --hash=sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6 \ + --hash=sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989 \ + --hash=sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c \ + --hash=sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b \ + --hash=sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223 \ + --hash=sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f \ + --hash=sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56 \ + --hash=sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3 \ + --hash=sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8 \ + --hash=sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb \ + --hash=sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388 \ + --hash=sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0 \ + --hash=sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a \ + --hash=sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8 \ + --hash=sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f \ + --hash=sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a \ + --hash=sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962 \ + --hash=sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8 \ + --hash=sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391 \ + --hash=sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc \ + --hash=sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2 \ + --hash=sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155 \ + --hash=sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb \ + --hash=sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0 \ + --hash=sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c \ + --hash=sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a \ + --hash=sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004 \ + --hash=sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060 \ + --hash=sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232 \ + --hash=sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93 \ + --hash=sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129 \ + --hash=sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163 \ + --hash=sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de \ + --hash=sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6 \ + --hash=sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23 \ + --hash=sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569 \ + --hash=sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d \ + --hash=sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778 \ + --hash=sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d \ + --hash=sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36 \ + --hash=sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a \ + --hash=sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6 \ + --hash=sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34 \ + --hash=sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704 \ + --hash=sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106 \ + --hash=sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9 \ + --hash=sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862 \ + --hash=sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b \ + --hash=sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255 \ + --hash=sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16 \ + --hash=sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3 \ + --hash=sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133 \ + --hash=sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb \ + --hash=sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657 \ + --hash=sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d \ + --hash=sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca \ + --hash=sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36 \ + --hash=sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c \ + --hash=sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e \ + --hash=sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff \ + --hash=sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7 \ + --hash=sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5 \ + --hash=sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02 \ + --hash=sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c \ + --hash=sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df \ + --hash=sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3 \ + --hash=sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a \ + --hash=sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959 \ + --hash=sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234 \ + --hash=sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc +croniter==3.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:34117ec1741f10a7bd0ec3ad7d8f0eb8fa457a2feb9be32e6a2250e158957668 \ + --hash=sha256:b3bd11f270dc54ccd1f2397b813436015a86d30ffc5a7a9438eec1ed916f2101 decorator==5.1.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330 \ --hash=sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186 deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \ --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3 -exceptiongroup==1.2.1 ; python_version >= "3.10" and python_version < "3.11" \ - --hash=sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad \ - --hash=sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16 +exceptiongroup==1.2.2 ; python_version >= "3.10" and python_version < "3.11" \ + --hash=sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b \ + --hash=sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc factory-boy==3.3.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:a2cdbdb63228177aa4f1c52f4b6d83fab2b8623bf602c7dedd7eb83c0f69c04c \ --hash=sha256:bc76d97d1a65bbd9842a6d722882098eb549ec8ee1081f9fb2e8ff29f0c300f1 -faker==25.8.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4c40b34a9c569018d4f9d6366d71a4da8a883d5ddf2b23197be5370f29b7e1b6 \ - --hash=sha256:bdec5f2fb057d244ebef6e0ed318fea4dcbdf32c3a1a010766fc45f5d68fc68d +faker==26.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:7b123090774deff5f2cd3eb92a84dcbbf1e163f30a6d07321b7852c11bfe6a75 \ + --hash=sha256:81768de19012147521140f0d8bf5353e501ac42c1065d25e0cac455d3615c0a7 fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d -googleapis-common-protos==1.63.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877 \ - --hash=sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a -greenlet==3.0.3 ; python_version >= "3.10" and python_version < "4.0" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") \ +googleapis-common-protos==1.63.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945 \ + --hash=sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87 +greenlet==3.0.3 ; python_version < "3.13" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version >= "3.10" \ --hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \ --hash=sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6 \ --hash=sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257 \ @@ -152,53 +175,53 @@ greenlet==3.0.3 ; python_version >= "3.10" and python_version < "4.0" and (platf --hash=sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf \ --hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \ --hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33 -grpcio==1.64.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b43d0ccf99c557ec671c7dede64f023c7da9bb632ac65dbc57f166e4970040 \ - --hash=sha256:0a12ddb1678ebc6a84ec6b0487feac020ee2b1659cbe69b80f06dbffdb249122 \ - --hash=sha256:0a2813093ddb27418a4c99f9b1c223fab0b053157176a64cc9db0f4557b69bd9 \ - --hash=sha256:0cc79c982ccb2feec8aad0e8fb0d168bcbca85bc77b080d0d3c5f2f15c24ea8f \ - --hash=sha256:1257b76748612aca0f89beec7fa0615727fd6f2a1ad580a9638816a4b2eb18fd \ - --hash=sha256:1262402af5a511c245c3ae918167eca57342c72320dffae5d9b51840c4b2f86d \ - --hash=sha256:19264fc964576ddb065368cae953f8d0514ecc6cb3da8903766d9fb9d4554c33 \ - --hash=sha256:198908f9b22e2672a998870355e226a725aeab327ac4e6ff3a1399792ece4762 \ - --hash=sha256:1de403fc1305fd96cfa75e83be3dee8538f2413a6b1685b8452301c7ba33c294 \ - --hash=sha256:20405cb8b13fd779135df23fabadc53b86522d0f1cba8cca0e87968587f50650 \ - --hash=sha256:2981c7365a9353f9b5c864595c510c983251b1ab403e05b1ccc70a3d9541a73b \ - --hash=sha256:2c3c1b90ab93fed424e454e93c0ed0b9d552bdf1b0929712b094f5ecfe7a23ad \ - --hash=sha256:39b9d0acaa8d835a6566c640f48b50054f422d03e77e49716d4c4e8e279665a1 \ - --hash=sha256:3b64ae304c175671efdaa7ec9ae2cc36996b681eb63ca39c464958396697daff \ - --hash=sha256:4657d24c8063e6095f850b68f2d1ba3b39f2b287a38242dcabc166453e950c59 \ - --hash=sha256:4d6dab6124225496010bd22690f2d9bd35c7cbb267b3f14e7a3eb05c911325d4 \ - --hash=sha256:55260032b95c49bee69a423c2f5365baa9369d2f7d233e933564d8a47b893027 \ - --hash=sha256:55697ecec192bc3f2f3cc13a295ab670f51de29884ca9ae6cd6247df55df2502 \ - --hash=sha256:5841dd1f284bd1b3d8a6eca3a7f062b06f1eec09b184397e1d1d43447e89a7ae \ - --hash=sha256:58b1041e7c870bb30ee41d3090cbd6f0851f30ae4eb68228955d973d3efa2e61 \ - --hash=sha256:5e42634a989c3aa6049f132266faf6b949ec2a6f7d302dbb5c15395b77d757eb \ - --hash=sha256:5e56462b05a6f860b72f0fa50dca06d5b26543a4e88d0396259a07dc30f4e5aa \ - --hash=sha256:5f8b75f64d5d324c565b263c67dbe4f0af595635bbdd93bb1a88189fc62ed2e5 \ - --hash=sha256:62b4e6eb7bf901719fce0ca83e3ed474ae5022bb3827b0a501e056458c51c0a1 \ - --hash=sha256:6503b64c8b2dfad299749cad1b595c650c91e5b2c8a1b775380fcf8d2cbba1e9 \ - --hash=sha256:6c024ffc22d6dc59000faf8ad781696d81e8e38f4078cb0f2630b4a3cf231a90 \ - --hash=sha256:73819689c169417a4f978e562d24f2def2be75739c4bed1992435d007819da1b \ - --hash=sha256:75dbbf415026d2862192fe1b28d71f209e2fd87079d98470db90bebe57b33179 \ - --hash=sha256:8caee47e970b92b3dd948371230fcceb80d3f2277b3bf7fbd7c0564e7d39068e \ - --hash=sha256:8d51dd1c59d5fa0f34266b80a3805ec29a1f26425c2a54736133f6d87fc4968a \ - --hash=sha256:940e3ec884520155f68a3b712d045e077d61c520a195d1a5932c531f11883489 \ - --hash=sha256:a011ac6c03cfe162ff2b727bcb530567826cec85eb8d4ad2bfb4bd023287a52d \ - --hash=sha256:a3a035c37ce7565b8f4f35ff683a4db34d24e53dc487e47438e434eb3f701b2a \ - --hash=sha256:a5e771d0252e871ce194d0fdcafd13971f1aae0ddacc5f25615030d5df55c3a2 \ - --hash=sha256:ac15b6c2c80a4d1338b04d42a02d376a53395ddf0ec9ab157cbaf44191f3ffdd \ - --hash=sha256:b1a82e0b9b3022799c336e1fc0f6210adc019ae84efb7321d668129d28ee1efb \ - --hash=sha256:bac71b4b28bc9af61efcdc7630b166440bbfbaa80940c9a697271b5e1dabbc61 \ - --hash=sha256:bbc5b1d78a7822b0a84c6f8917faa986c1a744e65d762ef6d8be9d75677af2ca \ - --hash=sha256:c1a786ac592b47573a5bb7e35665c08064a5d77ab88a076eec11f8ae86b3e3f6 \ - --hash=sha256:c84ad903d0d94311a2b7eea608da163dace97c5fe9412ea311e72c3684925602 \ - --hash=sha256:d4d29cc612e1332237877dfa7fe687157973aab1d63bd0f84cf06692f04c0367 \ - --hash=sha256:e3d9f8d1221baa0ced7ec7322a981e28deb23749c76eeeb3d33e18b72935ab62 \ - --hash=sha256:e7cd5c1325f6808b8ae31657d281aadb2a51ac11ab081ae335f4f7fc44c1721d \ - --hash=sha256:ed6091fa0adcc7e4ff944090cf203a52da35c37a130efa564ded02b7aff63bcd \ - --hash=sha256:ee73a2f5ca4ba44fa33b4d7d2c71e2c8a9e9f78d53f6507ad68e7d2ad5f64a22 \ - --hash=sha256:f10193c69fc9d3d726e83bbf0f3d316f1847c3071c8c93d8090cf5f326b14309 +grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ + --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ + --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ + --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ + --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ + --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ + --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ + --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ + --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ + --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ + --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ + --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ + --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ + --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ + --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ + --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ + --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ + --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ + --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ + --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ + --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ + --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ + --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ + --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ + --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ + --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ + --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ + --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ + --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ + --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ + --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ + --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ + --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ + --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ + --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ + --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ + --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ + --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ + --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ + --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ + --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ + --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ + --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ + --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ + --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ + --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -211,9 +234,9 @@ httpx==0.27.0 ; python_version >= "3.10" and python_version < "4.0" \ idna==3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 -importlib-metadata==7.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7 \ - --hash=sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67 +importlib-metadata==8.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f \ + --hash=sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812 iniconfig==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \ --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 @@ -413,18 +436,18 @@ pluggy==1.5.0 ; python_version >= "3.10" and python_version < "4.0" \ prometheus-client==0.19.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4585b0d1223148c27a225b10dbec5ae9bc4c81a99a3fa80774fa6209935324e1 \ --hash=sha256:c88b1e6ecf6b41cd8fb5731c7ae919bf66df6ec6fafa555cd6c0e16ca169ae92 -protobuf==4.25.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4 \ - --hash=sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8 \ - --hash=sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c \ - --hash=sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d \ - --hash=sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4 \ - --hash=sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa \ - --hash=sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c \ - --hash=sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019 \ - --hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \ - --hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \ - --hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2 +protobuf==4.25.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:051e97ce9fa6067a4546e75cb14f90cf0232dcb3e3d508c448b8d0e4265b61c1 \ + --hash=sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d \ + --hash=sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040 \ + --hash=sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835 \ + --hash=sha256:7e372cbbda66a63ebca18f8ffaa6948455dfecc4e9c1029312f6c2edcd86c4e1 \ + --hash=sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca \ + --hash=sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f \ + --hash=sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d \ + --hash=sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978 \ + --hash=sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4 \ + --hash=sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b psutil==5.9.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d \ --hash=sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73 \ @@ -546,85 +569,88 @@ pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 -pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ - --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic-settings==2.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315 \ + --hash=sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88 pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 pytest-cov==5.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652 \ --hash=sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857 -pytest==8.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343 \ - --hash=sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977 +pytest==8.3.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5 \ + --hash=sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce python-dateutil==2.9.0.post0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a +pytz==2024.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812 \ + --hash=sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319 retry2==0.9.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f7fee13b1e15d0611c462910a6aa72a8919823988dd0412152bc3719c89a4e55 -setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ - --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 +setuptools==72.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1 \ + --hash=sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc -sqlalchemy==2.0.30 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0094c5dc698a5f78d3d1539853e8ecec02516b62b8223c970c86d44e7a80f6c7 \ - --hash=sha256:0138c5c16be3600923fa2169532205d18891b28afa817cb49b50e08f62198bb8 \ - --hash=sha256:0a089e218654e740a41388893e090d2e2c22c29028c9d1353feb38638820bbeb \ - --hash=sha256:0b3f4c438e37d22b83e640f825ef0f37b95db9aa2d68203f2c9549375d0b2260 \ - --hash=sha256:16863e2b132b761891d6c49f0a0f70030e0bcac4fd208117f6b7e053e68668d0 \ - --hash=sha256:1f9a727312ff6ad5248a4367358e2cf7e625e98b1028b1d7ab7b806b7d757513 \ - --hash=sha256:2383146973a15435e4717f94c7509982770e3e54974c71f76500a0136f22810b \ - --hash=sha256:2753743c2afd061bb95a61a51bbb6a1a11ac1c44292fad898f10c9839a7f75b2 \ - --hash=sha256:296230899df0b77dec4eb799bcea6fbe39a43707ce7bb166519c97b583cfcab3 \ - --hash=sha256:2a4f4da89c74435f2bc61878cd08f3646b699e7d2eba97144030d1be44e27584 \ - --hash=sha256:2b1708916730f4830bc69d6f49d37f7698b5bd7530aca7f04f785f8849e95255 \ - --hash=sha256:2ecabd9ccaa6e914e3dbb2aa46b76dede7eadc8cbf1b8083c94d936bcd5ffb49 \ - --hash=sha256:311710f9a2ee235f1403537b10c7687214bb1f2b9ebb52702c5aa4a77f0b3af7 \ - --hash=sha256:37a4b4fb0dd4d2669070fb05b8b8824afd0af57587393015baee1cf9890242d9 \ - --hash=sha256:3a365eda439b7a00732638f11072907c1bc8e351c7665e7e5da91b169af794af \ - --hash=sha256:3b48154678e76445c7ded1896715ce05319f74b1e73cf82d4f8b59b46e9c0ddc \ - --hash=sha256:3b69e934f0f2b677ec111b4d83f92dc1a3210a779f69bf905273192cf4ed433e \ - --hash=sha256:3cb5a646930c5123f8461f6468901573f334c2c63c795b9af350063a736d0134 \ - --hash=sha256:408f8b0e2c04677e9c93f40eef3ab22f550fecb3011b187f66a096395ff3d9fd \ - --hash=sha256:40ad017c672c00b9b663fcfcd5f0864a0a97828e2ee7ab0c140dc84058d194cf \ - --hash=sha256:5a79d65395ac5e6b0c2890935bad892eabb911c4aa8e8015067ddb37eea3d56c \ - --hash=sha256:5a8e3b0a7e09e94be7510d1661339d6b52daf202ed2f5b1f9f48ea34ee6f2d57 \ - --hash=sha256:69c9db1ce00e59e8dd09d7bae852a9add716efdc070a3e2068377e6ff0d6fdaa \ - --hash=sha256:7108d569d3990c71e26a42f60474b4c02c8586c4681af5fd67e51a044fdea86a \ - --hash=sha256:77d2edb1f54aff37e3318f611637171e8ec71472f1fdc7348b41dcb226f93d90 \ - --hash=sha256:7d74336c65705b986d12a7e337ba27ab2b9d819993851b140efdf029248e818e \ - --hash=sha256:8409de825f2c3b62ab15788635ccaec0c881c3f12a8af2b12ae4910a0a9aeef6 \ - --hash=sha256:955991a09f0992c68a499791a753523f50f71a6885531568404fa0f231832aa0 \ - --hash=sha256:99650e9f4cf3ad0d409fed3eec4f071fadd032e9a5edc7270cd646a26446feeb \ - --hash=sha256:9a5baf9267b752390252889f0c802ea13b52dfee5e369527da229189b8bd592e \ - --hash=sha256:a0ef36b28534f2a5771191be6edb44cc2673c7b2edf6deac6562400288664221 \ - --hash=sha256:a1429a4b0f709f19ff3b0cf13675b2b9bfa8a7e79990003207a011c0db880a13 \ - --hash=sha256:a7bfc726d167f425d4c16269a9a10fe8630ff6d14b683d588044dcef2d0f6be7 \ - --hash=sha256:a943d297126c9230719c27fcbbeab57ecd5d15b0bd6bfd26e91bfcfe64220621 \ - --hash=sha256:ae8c62fe2480dd61c532ccafdbce9b29dacc126fe8be0d9a927ca3e699b9491a \ - --hash=sha256:b60203c63e8f984df92035610c5fb76d941254cf5d19751faab7d33b21e5ddc0 \ - --hash=sha256:b6bf767d14b77f6a18b6982cbbf29d71bede087edae495d11ab358280f304d8e \ - --hash=sha256:b6c7ec2b1f4969fc19b65b7059ed00497e25f54069407a8701091beb69e591a5 \ - --hash=sha256:bba002a9447b291548e8d66fd8c96a6a7ed4f2def0bb155f4f0a1309fd2735d5 \ - --hash=sha256:bc0c53579650a891f9b83fa3cecd4e00218e071d0ba00c4890f5be0c34887ed3 \ - --hash=sha256:c4f61ada6979223013d9ab83a3ed003ded6959eae37d0d685db2c147e9143797 \ - --hash=sha256:c62d401223f468eb4da32627bffc0c78ed516b03bb8a34a58be54d618b74d472 \ - --hash=sha256:e42203d8d20dc704604862977b1470a122e4892791fe3ed165f041e4bf447a1b \ - --hash=sha256:edc16a50f5e1b7a06a2dcc1f2205b0b961074c123ed17ebda726f376a5ab0953 \ - --hash=sha256:efedba7e13aa9a6c8407c48facfdfa108a5a4128e35f4c68f20c3407e4376aa9 \ - --hash=sha256:f1dc3eabd8c0232ee8387fbe03e0a62220a6f089e278b1f0aaf5e2d6210741ad \ - --hash=sha256:f69e4c756ee2686767eb80f94c0125c8b0a0b87ede03eacc5c8ae3b54b99dc46 \ - --hash=sha256:f7703c2010355dd28f53deb644a05fc30f796bd8598b43f0ba678878780b6e4c \ - --hash=sha256:fa561138a64f949f3e889eb9ab8c58e1504ab351d6cf55259dc4c248eaa19da6 +sqlalchemy==2.0.32 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01438ebcdc566d58c93af0171c74ec28efe6a29184b773e378a385e6215389da \ + --hash=sha256:0c1c9b673d21477cec17ab10bc4decb1322843ba35b481585facd88203754fc5 \ + --hash=sha256:0c9045ecc2e4db59bfc97b20516dfdf8e41d910ac6fb667ebd3a79ea54084619 \ + --hash=sha256:0d322cc9c9b2154ba7e82f7bf25ecc7c36fbe2d82e2933b3642fc095a52cfc78 \ + --hash=sha256:0ef18a84e5116340e38eca3e7f9eeaaef62738891422e7c2a0b80feab165905f \ + --hash=sha256:1467940318e4a860afd546ef61fefb98a14d935cd6817ed07a228c7f7c62f389 \ + --hash=sha256:14e09e083a5796d513918a66f3d6aedbc131e39e80875afe81d98a03312889e6 \ + --hash=sha256:167e7497035c303ae50651b351c28dc22a40bb98fbdb8468cdc971821b1ae533 \ + --hash=sha256:19d98f4f58b13900d8dec4ed09dd09ef292208ee44cc9c2fe01c1f0a2fe440e9 \ + --hash=sha256:21b053be28a8a414f2ddd401f1be8361e41032d2ef5884b2f31d31cb723e559f \ + --hash=sha256:251f0d1108aab8ea7b9aadbd07fb47fb8e3a5838dde34aa95a3349876b5a1f1d \ + --hash=sha256:295ff8689544f7ee7e819529633d058bd458c1fd7f7e3eebd0f9268ebc56c2a0 \ + --hash=sha256:2b6be53e4fde0065524f1a0a7929b10e9280987b320716c1509478b712a7688c \ + --hash=sha256:306fe44e754a91cd9d600a6b070c1f2fadbb4a1a257b8781ccf33c7067fd3e4d \ + --hash=sha256:31983018b74908ebc6c996a16ad3690301a23befb643093fcfe85efd292e384d \ + --hash=sha256:328429aecaba2aee3d71e11f2477c14eec5990fb6d0e884107935f7fb6001632 \ + --hash=sha256:3bd1cae7519283ff525e64645ebd7a3e0283f3c038f461ecc1c7b040a0c932a1 \ + --hash=sha256:3cd33c61513cb1b7371fd40cf221256456d26a56284e7d19d1f0b9f1eb7dd7e8 \ + --hash=sha256:3eb6a97a1d39976f360b10ff208c73afb6a4de86dd2a6212ddf65c4a6a2347d5 \ + --hash=sha256:4363ed245a6231f2e2957cccdda3c776265a75851f4753c60f3004b90e69bfeb \ + --hash=sha256:4488120becf9b71b3ac718f4138269a6be99a42fe023ec457896ba4f80749525 \ + --hash=sha256:49496b68cd190a147118af585173ee624114dfb2e0297558c460ad7495f9dfe2 \ + --hash=sha256:4979dc80fbbc9d2ef569e71e0896990bc94df2b9fdbd878290bd129b65ab579c \ + --hash=sha256:52fec964fba2ef46476312a03ec8c425956b05c20220a1a03703537824b5e8e1 \ + --hash=sha256:5954463675cb15db8d4b521f3566a017c8789222b8316b1e6934c811018ee08b \ + --hash=sha256:62e23d0ac103bcf1c5555b6c88c114089587bc64d048fef5bbdb58dfd26f96da \ + --hash=sha256:6bab3db192a0c35e3c9d1560eb8332463e29e5507dbd822e29a0a3c48c0a8d92 \ + --hash=sha256:6c742be912f57586ac43af38b3848f7688863a403dfb220193a882ea60e1ec3a \ + --hash=sha256:723a40ee2cc7ea653645bd4cf024326dea2076673fc9d3d33f20f6c81db83e1d \ + --hash=sha256:78c03d0f8a5ab4f3034c0e8482cfcc415a3ec6193491cfa1c643ed707d476f16 \ + --hash=sha256:7d6ba0497c1d066dd004e0f02a92426ca2df20fac08728d03f67f6960271feec \ + --hash=sha256:7dd8583df2f98dea28b5cd53a1beac963f4f9d087888d75f22fcc93a07cf8d84 \ + --hash=sha256:85a01b5599e790e76ac3fe3aa2f26e1feba56270023d6afd5550ed63c68552b3 \ + --hash=sha256:8a37e4d265033c897892279e8adf505c8b6b4075f2b40d77afb31f7185cd6ecd \ + --hash=sha256:8bd63d051f4f313b102a2af1cbc8b80f061bf78f3d5bd0843ff70b5859e27924 \ + --hash=sha256:916a798f62f410c0b80b63683c8061f5ebe237b0f4ad778739304253353bc1cb \ + --hash=sha256:9365a3da32dabd3e69e06b972b1ffb0c89668994c7e8e75ce21d3e5e69ddef28 \ + --hash=sha256:99db65e6f3ab42e06c318f15c98f59a436f1c78179e6a6f40f529c8cc7100b22 \ + --hash=sha256:aaf04784797dcdf4c0aa952c8d234fa01974c4729db55c45732520ce12dd95b4 \ + --hash=sha256:acd9b73c5c15f0ec5ce18128b1fe9157ddd0044abc373e6ecd5ba376a7e5d961 \ + --hash=sha256:ada0102afff4890f651ed91120c1120065663506b760da4e7823913ebd3258be \ + --hash=sha256:b178e875a7a25b5938b53b006598ee7645172fccafe1c291a706e93f48499ff5 \ + --hash=sha256:b27dfb676ac02529fb6e343b3a482303f16e6bc3a4d868b73935b8792edb52d0 \ + --hash=sha256:b8afd5b26570bf41c35c0121801479958b4446751a3971fb9a480c1afd85558e \ + --hash=sha256:bf2360a5e0f7bd75fa80431bf8ebcfb920c9f885e7956c7efde89031695cafb8 \ + --hash=sha256:c1b88cc8b02b6a5f0efb0345a03672d4c897dc7d92585176f88c67346f565ea8 \ + --hash=sha256:c41a2b9ca80ee555decc605bd3c4520cc6fef9abde8fd66b1cf65126a6922d65 \ + --hash=sha256:c750987fc876813f27b60d619b987b057eb4896b81117f73bb8d9918c14f1cad \ + --hash=sha256:e567a8793a692451f706b363ccf3c45e056b67d90ead58c3bc9471af5d212202 starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 @@ -634,6 +660,9 @@ structlog==23.3.0 ; python_version >= "3.10" and python_version < "4.0" \ tomli==2.0.1 ; python_version >= "3.10" and python_full_version <= "3.11.0a6" \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f +types-croniter==3.0.3.20240731 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:7a170660642da662c704a463b011e31c049f5a218d27d30199a80ac5e8d15002 \ + --hash=sha256:da039d543e07b1db4ad93680cb837afd0f5c64974970287da8c6432d19441b71 typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 diff --git a/mula/requirements.txt b/mula/requirements.txt index 4b3897ff456..79b67b42d03 100644 --- a/mula/requirements.txt +++ b/mula/requirements.txt @@ -1,6 +1,6 @@ -alembic==1.13.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43 \ - --hash=sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595 +alembic==1.13.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef \ + --hash=sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953 annotated-types==0.7.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \ --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89 @@ -19,22 +19,25 @@ click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows" \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 +croniter==3.0.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:34117ec1741f10a7bd0ec3ad7d8f0eb8fa457a2feb9be32e6a2250e158957668 \ + --hash=sha256:b3bd11f270dc54ccd1f2397b813436015a86d30ffc5a7a9438eec1ed916f2101 decorator==5.1.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330 \ --hash=sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186 deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \ --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3 -exceptiongroup==1.2.1 ; python_version >= "3.10" and python_version < "3.11" \ - --hash=sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad \ - --hash=sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16 +exceptiongroup==1.2.2 ; python_version >= "3.10" and python_version < "3.11" \ + --hash=sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b \ + --hash=sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d -googleapis-common-protos==1.63.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877 \ - --hash=sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a -greenlet==3.0.3 ; python_version >= "3.10" and python_version < "4.0" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") \ +googleapis-common-protos==1.63.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945 \ + --hash=sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87 +greenlet==3.0.3 ; python_version < "3.13" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version >= "3.10" \ --hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \ --hash=sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6 \ --hash=sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257 \ @@ -93,53 +96,53 @@ greenlet==3.0.3 ; python_version >= "3.10" and python_version < "4.0" and (platf --hash=sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf \ --hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \ --hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33 -grpcio==1.64.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:03b43d0ccf99c557ec671c7dede64f023c7da9bb632ac65dbc57f166e4970040 \ - --hash=sha256:0a12ddb1678ebc6a84ec6b0487feac020ee2b1659cbe69b80f06dbffdb249122 \ - --hash=sha256:0a2813093ddb27418a4c99f9b1c223fab0b053157176a64cc9db0f4557b69bd9 \ - --hash=sha256:0cc79c982ccb2feec8aad0e8fb0d168bcbca85bc77b080d0d3c5f2f15c24ea8f \ - --hash=sha256:1257b76748612aca0f89beec7fa0615727fd6f2a1ad580a9638816a4b2eb18fd \ - --hash=sha256:1262402af5a511c245c3ae918167eca57342c72320dffae5d9b51840c4b2f86d \ - --hash=sha256:19264fc964576ddb065368cae953f8d0514ecc6cb3da8903766d9fb9d4554c33 \ - --hash=sha256:198908f9b22e2672a998870355e226a725aeab327ac4e6ff3a1399792ece4762 \ - --hash=sha256:1de403fc1305fd96cfa75e83be3dee8538f2413a6b1685b8452301c7ba33c294 \ - --hash=sha256:20405cb8b13fd779135df23fabadc53b86522d0f1cba8cca0e87968587f50650 \ - --hash=sha256:2981c7365a9353f9b5c864595c510c983251b1ab403e05b1ccc70a3d9541a73b \ - --hash=sha256:2c3c1b90ab93fed424e454e93c0ed0b9d552bdf1b0929712b094f5ecfe7a23ad \ - --hash=sha256:39b9d0acaa8d835a6566c640f48b50054f422d03e77e49716d4c4e8e279665a1 \ - --hash=sha256:3b64ae304c175671efdaa7ec9ae2cc36996b681eb63ca39c464958396697daff \ - --hash=sha256:4657d24c8063e6095f850b68f2d1ba3b39f2b287a38242dcabc166453e950c59 \ - --hash=sha256:4d6dab6124225496010bd22690f2d9bd35c7cbb267b3f14e7a3eb05c911325d4 \ - --hash=sha256:55260032b95c49bee69a423c2f5365baa9369d2f7d233e933564d8a47b893027 \ - --hash=sha256:55697ecec192bc3f2f3cc13a295ab670f51de29884ca9ae6cd6247df55df2502 \ - --hash=sha256:5841dd1f284bd1b3d8a6eca3a7f062b06f1eec09b184397e1d1d43447e89a7ae \ - --hash=sha256:58b1041e7c870bb30ee41d3090cbd6f0851f30ae4eb68228955d973d3efa2e61 \ - --hash=sha256:5e42634a989c3aa6049f132266faf6b949ec2a6f7d302dbb5c15395b77d757eb \ - --hash=sha256:5e56462b05a6f860b72f0fa50dca06d5b26543a4e88d0396259a07dc30f4e5aa \ - --hash=sha256:5f8b75f64d5d324c565b263c67dbe4f0af595635bbdd93bb1a88189fc62ed2e5 \ - --hash=sha256:62b4e6eb7bf901719fce0ca83e3ed474ae5022bb3827b0a501e056458c51c0a1 \ - --hash=sha256:6503b64c8b2dfad299749cad1b595c650c91e5b2c8a1b775380fcf8d2cbba1e9 \ - --hash=sha256:6c024ffc22d6dc59000faf8ad781696d81e8e38f4078cb0f2630b4a3cf231a90 \ - --hash=sha256:73819689c169417a4f978e562d24f2def2be75739c4bed1992435d007819da1b \ - --hash=sha256:75dbbf415026d2862192fe1b28d71f209e2fd87079d98470db90bebe57b33179 \ - --hash=sha256:8caee47e970b92b3dd948371230fcceb80d3f2277b3bf7fbd7c0564e7d39068e \ - --hash=sha256:8d51dd1c59d5fa0f34266b80a3805ec29a1f26425c2a54736133f6d87fc4968a \ - --hash=sha256:940e3ec884520155f68a3b712d045e077d61c520a195d1a5932c531f11883489 \ - --hash=sha256:a011ac6c03cfe162ff2b727bcb530567826cec85eb8d4ad2bfb4bd023287a52d \ - --hash=sha256:a3a035c37ce7565b8f4f35ff683a4db34d24e53dc487e47438e434eb3f701b2a \ - --hash=sha256:a5e771d0252e871ce194d0fdcafd13971f1aae0ddacc5f25615030d5df55c3a2 \ - --hash=sha256:ac15b6c2c80a4d1338b04d42a02d376a53395ddf0ec9ab157cbaf44191f3ffdd \ - --hash=sha256:b1a82e0b9b3022799c336e1fc0f6210adc019ae84efb7321d668129d28ee1efb \ - --hash=sha256:bac71b4b28bc9af61efcdc7630b166440bbfbaa80940c9a697271b5e1dabbc61 \ - --hash=sha256:bbc5b1d78a7822b0a84c6f8917faa986c1a744e65d762ef6d8be9d75677af2ca \ - --hash=sha256:c1a786ac592b47573a5bb7e35665c08064a5d77ab88a076eec11f8ae86b3e3f6 \ - --hash=sha256:c84ad903d0d94311a2b7eea608da163dace97c5fe9412ea311e72c3684925602 \ - --hash=sha256:d4d29cc612e1332237877dfa7fe687157973aab1d63bd0f84cf06692f04c0367 \ - --hash=sha256:e3d9f8d1221baa0ced7ec7322a981e28deb23749c76eeeb3d33e18b72935ab62 \ - --hash=sha256:e7cd5c1325f6808b8ae31657d281aadb2a51ac11ab081ae335f4f7fc44c1721d \ - --hash=sha256:ed6091fa0adcc7e4ff944090cf203a52da35c37a130efa564ded02b7aff63bcd \ - --hash=sha256:ee73a2f5ca4ba44fa33b4d7d2c71e2c8a9e9f78d53f6507ad68e7d2ad5f64a22 \ - --hash=sha256:f10193c69fc9d3d726e83bbf0f3d316f1847c3071c8c93d8090cf5f326b14309 +grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ + --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ + --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ + --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ + --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ + --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ + --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ + --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ + --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ + --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ + --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ + --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ + --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ + --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ + --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ + --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ + --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ + --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ + --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ + --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ + --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ + --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ + --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ + --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ + --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ + --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ + --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ + --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ + --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ + --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ + --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ + --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ + --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ + --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ + --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ + --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ + --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ + --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ + --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ + --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ + --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ + --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ + --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ + --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ + --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ + --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -152,9 +155,9 @@ httpx==0.27.0 ; python_version >= "3.10" and python_version < "4.0" \ idna==3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 -importlib-metadata==7.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7 \ - --hash=sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67 +importlib-metadata==8.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f \ + --hash=sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812 mako==1.3.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a \ --hash=sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc @@ -345,18 +348,18 @@ pika==1.3.2 ; python_version >= "3.10" and python_version < "4.0" \ prometheus-client==0.19.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4585b0d1223148c27a225b10dbec5ae9bc4c81a99a3fa80774fa6209935324e1 \ --hash=sha256:c88b1e6ecf6b41cd8fb5731c7ae919bf66df6ec6fafa555cd6c0e16ca169ae92 -protobuf==4.25.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4 \ - --hash=sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8 \ - --hash=sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c \ - --hash=sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d \ - --hash=sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4 \ - --hash=sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa \ - --hash=sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c \ - --hash=sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019 \ - --hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \ - --hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \ - --hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2 +protobuf==4.25.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:051e97ce9fa6067a4546e75cb14f90cf0232dcb3e3d508c448b8d0e4265b61c1 \ + --hash=sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d \ + --hash=sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040 \ + --hash=sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835 \ + --hash=sha256:7e372cbbda66a63ebca18f8ffaa6948455dfecc4e9c1029312f6c2edcd86c4e1 \ + --hash=sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca \ + --hash=sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f \ + --hash=sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d \ + --hash=sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978 \ + --hash=sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4 \ + --hash=sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b psycopg2==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981 \ --hash=sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516 \ @@ -461,79 +464,91 @@ pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 -pydantic-settings==2.3.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ - --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 +pydantic-settings==2.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315 \ + --hash=sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88 pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 +python-dateutil==2.9.0.post0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ + --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a +pytz==2024.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812 \ + --hash=sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319 retry2==0.9.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f7fee13b1e15d0611c462910a6aa72a8919823988dd0412152bc3719c89a4e55 -setuptools==71.0.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ - --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 +setuptools==72.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1 \ + --hash=sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec +six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ + --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc -sqlalchemy==2.0.30 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0094c5dc698a5f78d3d1539853e8ecec02516b62b8223c970c86d44e7a80f6c7 \ - --hash=sha256:0138c5c16be3600923fa2169532205d18891b28afa817cb49b50e08f62198bb8 \ - --hash=sha256:0a089e218654e740a41388893e090d2e2c22c29028c9d1353feb38638820bbeb \ - --hash=sha256:0b3f4c438e37d22b83e640f825ef0f37b95db9aa2d68203f2c9549375d0b2260 \ - --hash=sha256:16863e2b132b761891d6c49f0a0f70030e0bcac4fd208117f6b7e053e68668d0 \ - --hash=sha256:1f9a727312ff6ad5248a4367358e2cf7e625e98b1028b1d7ab7b806b7d757513 \ - --hash=sha256:2383146973a15435e4717f94c7509982770e3e54974c71f76500a0136f22810b \ - --hash=sha256:2753743c2afd061bb95a61a51bbb6a1a11ac1c44292fad898f10c9839a7f75b2 \ - --hash=sha256:296230899df0b77dec4eb799bcea6fbe39a43707ce7bb166519c97b583cfcab3 \ - --hash=sha256:2a4f4da89c74435f2bc61878cd08f3646b699e7d2eba97144030d1be44e27584 \ - --hash=sha256:2b1708916730f4830bc69d6f49d37f7698b5bd7530aca7f04f785f8849e95255 \ - --hash=sha256:2ecabd9ccaa6e914e3dbb2aa46b76dede7eadc8cbf1b8083c94d936bcd5ffb49 \ - --hash=sha256:311710f9a2ee235f1403537b10c7687214bb1f2b9ebb52702c5aa4a77f0b3af7 \ - --hash=sha256:37a4b4fb0dd4d2669070fb05b8b8824afd0af57587393015baee1cf9890242d9 \ - --hash=sha256:3a365eda439b7a00732638f11072907c1bc8e351c7665e7e5da91b169af794af \ - --hash=sha256:3b48154678e76445c7ded1896715ce05319f74b1e73cf82d4f8b59b46e9c0ddc \ - --hash=sha256:3b69e934f0f2b677ec111b4d83f92dc1a3210a779f69bf905273192cf4ed433e \ - --hash=sha256:3cb5a646930c5123f8461f6468901573f334c2c63c795b9af350063a736d0134 \ - --hash=sha256:408f8b0e2c04677e9c93f40eef3ab22f550fecb3011b187f66a096395ff3d9fd \ - --hash=sha256:40ad017c672c00b9b663fcfcd5f0864a0a97828e2ee7ab0c140dc84058d194cf \ - --hash=sha256:5a79d65395ac5e6b0c2890935bad892eabb911c4aa8e8015067ddb37eea3d56c \ - --hash=sha256:5a8e3b0a7e09e94be7510d1661339d6b52daf202ed2f5b1f9f48ea34ee6f2d57 \ - --hash=sha256:69c9db1ce00e59e8dd09d7bae852a9add716efdc070a3e2068377e6ff0d6fdaa \ - --hash=sha256:7108d569d3990c71e26a42f60474b4c02c8586c4681af5fd67e51a044fdea86a \ - --hash=sha256:77d2edb1f54aff37e3318f611637171e8ec71472f1fdc7348b41dcb226f93d90 \ - --hash=sha256:7d74336c65705b986d12a7e337ba27ab2b9d819993851b140efdf029248e818e \ - --hash=sha256:8409de825f2c3b62ab15788635ccaec0c881c3f12a8af2b12ae4910a0a9aeef6 \ - --hash=sha256:955991a09f0992c68a499791a753523f50f71a6885531568404fa0f231832aa0 \ - --hash=sha256:99650e9f4cf3ad0d409fed3eec4f071fadd032e9a5edc7270cd646a26446feeb \ - --hash=sha256:9a5baf9267b752390252889f0c802ea13b52dfee5e369527da229189b8bd592e \ - --hash=sha256:a0ef36b28534f2a5771191be6edb44cc2673c7b2edf6deac6562400288664221 \ - --hash=sha256:a1429a4b0f709f19ff3b0cf13675b2b9bfa8a7e79990003207a011c0db880a13 \ - --hash=sha256:a7bfc726d167f425d4c16269a9a10fe8630ff6d14b683d588044dcef2d0f6be7 \ - --hash=sha256:a943d297126c9230719c27fcbbeab57ecd5d15b0bd6bfd26e91bfcfe64220621 \ - --hash=sha256:ae8c62fe2480dd61c532ccafdbce9b29dacc126fe8be0d9a927ca3e699b9491a \ - --hash=sha256:b60203c63e8f984df92035610c5fb76d941254cf5d19751faab7d33b21e5ddc0 \ - --hash=sha256:b6bf767d14b77f6a18b6982cbbf29d71bede087edae495d11ab358280f304d8e \ - --hash=sha256:b6c7ec2b1f4969fc19b65b7059ed00497e25f54069407a8701091beb69e591a5 \ - --hash=sha256:bba002a9447b291548e8d66fd8c96a6a7ed4f2def0bb155f4f0a1309fd2735d5 \ - --hash=sha256:bc0c53579650a891f9b83fa3cecd4e00218e071d0ba00c4890f5be0c34887ed3 \ - --hash=sha256:c4f61ada6979223013d9ab83a3ed003ded6959eae37d0d685db2c147e9143797 \ - --hash=sha256:c62d401223f468eb4da32627bffc0c78ed516b03bb8a34a58be54d618b74d472 \ - --hash=sha256:e42203d8d20dc704604862977b1470a122e4892791fe3ed165f041e4bf447a1b \ - --hash=sha256:edc16a50f5e1b7a06a2dcc1f2205b0b961074c123ed17ebda726f376a5ab0953 \ - --hash=sha256:efedba7e13aa9a6c8407c48facfdfa108a5a4128e35f4c68f20c3407e4376aa9 \ - --hash=sha256:f1dc3eabd8c0232ee8387fbe03e0a62220a6f089e278b1f0aaf5e2d6210741ad \ - --hash=sha256:f69e4c756ee2686767eb80f94c0125c8b0a0b87ede03eacc5c8ae3b54b99dc46 \ - --hash=sha256:f7703c2010355dd28f53deb644a05fc30f796bd8598b43f0ba678878780b6e4c \ - --hash=sha256:fa561138a64f949f3e889eb9ab8c58e1504ab351d6cf55259dc4c248eaa19da6 +sqlalchemy==2.0.32 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01438ebcdc566d58c93af0171c74ec28efe6a29184b773e378a385e6215389da \ + --hash=sha256:0c1c9b673d21477cec17ab10bc4decb1322843ba35b481585facd88203754fc5 \ + --hash=sha256:0c9045ecc2e4db59bfc97b20516dfdf8e41d910ac6fb667ebd3a79ea54084619 \ + --hash=sha256:0d322cc9c9b2154ba7e82f7bf25ecc7c36fbe2d82e2933b3642fc095a52cfc78 \ + --hash=sha256:0ef18a84e5116340e38eca3e7f9eeaaef62738891422e7c2a0b80feab165905f \ + --hash=sha256:1467940318e4a860afd546ef61fefb98a14d935cd6817ed07a228c7f7c62f389 \ + --hash=sha256:14e09e083a5796d513918a66f3d6aedbc131e39e80875afe81d98a03312889e6 \ + --hash=sha256:167e7497035c303ae50651b351c28dc22a40bb98fbdb8468cdc971821b1ae533 \ + --hash=sha256:19d98f4f58b13900d8dec4ed09dd09ef292208ee44cc9c2fe01c1f0a2fe440e9 \ + --hash=sha256:21b053be28a8a414f2ddd401f1be8361e41032d2ef5884b2f31d31cb723e559f \ + --hash=sha256:251f0d1108aab8ea7b9aadbd07fb47fb8e3a5838dde34aa95a3349876b5a1f1d \ + --hash=sha256:295ff8689544f7ee7e819529633d058bd458c1fd7f7e3eebd0f9268ebc56c2a0 \ + --hash=sha256:2b6be53e4fde0065524f1a0a7929b10e9280987b320716c1509478b712a7688c \ + --hash=sha256:306fe44e754a91cd9d600a6b070c1f2fadbb4a1a257b8781ccf33c7067fd3e4d \ + --hash=sha256:31983018b74908ebc6c996a16ad3690301a23befb643093fcfe85efd292e384d \ + --hash=sha256:328429aecaba2aee3d71e11f2477c14eec5990fb6d0e884107935f7fb6001632 \ + --hash=sha256:3bd1cae7519283ff525e64645ebd7a3e0283f3c038f461ecc1c7b040a0c932a1 \ + --hash=sha256:3cd33c61513cb1b7371fd40cf221256456d26a56284e7d19d1f0b9f1eb7dd7e8 \ + --hash=sha256:3eb6a97a1d39976f360b10ff208c73afb6a4de86dd2a6212ddf65c4a6a2347d5 \ + --hash=sha256:4363ed245a6231f2e2957cccdda3c776265a75851f4753c60f3004b90e69bfeb \ + --hash=sha256:4488120becf9b71b3ac718f4138269a6be99a42fe023ec457896ba4f80749525 \ + --hash=sha256:49496b68cd190a147118af585173ee624114dfb2e0297558c460ad7495f9dfe2 \ + --hash=sha256:4979dc80fbbc9d2ef569e71e0896990bc94df2b9fdbd878290bd129b65ab579c \ + --hash=sha256:52fec964fba2ef46476312a03ec8c425956b05c20220a1a03703537824b5e8e1 \ + --hash=sha256:5954463675cb15db8d4b521f3566a017c8789222b8316b1e6934c811018ee08b \ + --hash=sha256:62e23d0ac103bcf1c5555b6c88c114089587bc64d048fef5bbdb58dfd26f96da \ + --hash=sha256:6bab3db192a0c35e3c9d1560eb8332463e29e5507dbd822e29a0a3c48c0a8d92 \ + --hash=sha256:6c742be912f57586ac43af38b3848f7688863a403dfb220193a882ea60e1ec3a \ + --hash=sha256:723a40ee2cc7ea653645bd4cf024326dea2076673fc9d3d33f20f6c81db83e1d \ + --hash=sha256:78c03d0f8a5ab4f3034c0e8482cfcc415a3ec6193491cfa1c643ed707d476f16 \ + --hash=sha256:7d6ba0497c1d066dd004e0f02a92426ca2df20fac08728d03f67f6960271feec \ + --hash=sha256:7dd8583df2f98dea28b5cd53a1beac963f4f9d087888d75f22fcc93a07cf8d84 \ + --hash=sha256:85a01b5599e790e76ac3fe3aa2f26e1feba56270023d6afd5550ed63c68552b3 \ + --hash=sha256:8a37e4d265033c897892279e8adf505c8b6b4075f2b40d77afb31f7185cd6ecd \ + --hash=sha256:8bd63d051f4f313b102a2af1cbc8b80f061bf78f3d5bd0843ff70b5859e27924 \ + --hash=sha256:916a798f62f410c0b80b63683c8061f5ebe237b0f4ad778739304253353bc1cb \ + --hash=sha256:9365a3da32dabd3e69e06b972b1ffb0c89668994c7e8e75ce21d3e5e69ddef28 \ + --hash=sha256:99db65e6f3ab42e06c318f15c98f59a436f1c78179e6a6f40f529c8cc7100b22 \ + --hash=sha256:aaf04784797dcdf4c0aa952c8d234fa01974c4729db55c45732520ce12dd95b4 \ + --hash=sha256:acd9b73c5c15f0ec5ce18128b1fe9157ddd0044abc373e6ecd5ba376a7e5d961 \ + --hash=sha256:ada0102afff4890f651ed91120c1120065663506b760da4e7823913ebd3258be \ + --hash=sha256:b178e875a7a25b5938b53b006598ee7645172fccafe1c291a706e93f48499ff5 \ + --hash=sha256:b27dfb676ac02529fb6e343b3a482303f16e6bc3a4d868b73935b8792edb52d0 \ + --hash=sha256:b8afd5b26570bf41c35c0121801479958b4446751a3971fb9a480c1afd85558e \ + --hash=sha256:bf2360a5e0f7bd75fa80431bf8ebcfb920c9f885e7956c7efde89031695cafb8 \ + --hash=sha256:c1b88cc8b02b6a5f0efb0345a03672d4c897dc7d92585176f88c67346f565ea8 \ + --hash=sha256:c41a2b9ca80ee555decc605bd3c4520cc6fef9abde8fd66b1cf65126a6922d65 \ + --hash=sha256:c750987fc876813f27b60d619b987b057eb4896b81117f73bb8d9918c14f1cad \ + --hash=sha256:e567a8793a692451f706b363ccf3c45e056b67d90ead58c3bc9471af5d212202 starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 structlog==23.3.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:24b42b914ac6bc4a4e6f716e82ac70d7fb1e8c3b1035a765591953bfc37101a5 \ --hash=sha256:d6922a88ceabef5b13b9eda9c4043624924f60edbb00397f4d193bd754cde60a +types-croniter==3.0.3.20240731 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:7a170660642da662c704a463b011e31c049f5a218d27d30199a80ac5e8d15002 \ + --hash=sha256:da039d543e07b1db4ad93680cb837afd0f5c64974970287da8c6432d19441b71 typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 diff --git a/mula/scheduler/alembic/versions/0008_add_task_schedule.py b/mula/scheduler/alembic/versions/0008_add_task_schedule.py new file mode 100644 index 00000000000..19e711b4e1a --- /dev/null +++ b/mula/scheduler/alembic/versions/0008_add_task_schedule.py @@ -0,0 +1,182 @@ +"""add_task_schedule + +Revision ID: 0008 +Revises: 0007 +Create Date: 2024-07-17 09:53:20.673139 + +""" + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.dialects import postgresql + +import scheduler + +# revision identifiers, used by Alembic. +revision = "0008" +down_revision = "0007" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.execute('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";') + + op.create_table( + "schedules", + sa.Column("id", scheduler.utils.datastore.GUID(), nullable=False), + sa.Column("scheduler_id", sa.String(), nullable=False), + sa.Column("hash", sa.String(length=32), nullable=True), + sa.Column("data", postgresql.JSONB(astext_type=sa.Text()), nullable=False), + sa.Column("enabled", sa.Boolean(), nullable=False), + sa.Column("schedule", sa.String(), nullable=True), + sa.Column("deadline_at", sa.DateTime(timezone=True), nullable=True), + sa.Column( + "created_at", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.Column( + "modified_at", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("hash"), + ) + + op.drop_index("ix_items_hash", table_name="items") + op.drop_table("items") + + op.add_column( + "tasks", + sa.Column("schedule_id", scheduler.utils.datastore.GUID(), nullable=True), + ) + op.add_column("tasks", sa.Column("hash", sa.String(length=32), nullable=True)) + op.add_column("tasks", sa.Column("priority", sa.Integer(), nullable=True)) + op.add_column( + "tasks", + sa.Column("data", postgresql.JSONB(astext_type=sa.Text()), nullable=True), + ) + + # Migrate data from p_item to columns + op.execute("""UPDATE tasks SET data = p_item -> 'data'""") + op.execute("""UPDATE tasks SET priority = (p_item ->> 'priority')::integer""") + op.execute("""UPDATE tasks SET hash = p_item ->> 'hash'""") + + op.alter_column("tasks", "data", nullable=False) + + op.alter_column("tasks", "scheduler_id", existing_type=sa.VARCHAR(), nullable=False) + op.alter_column("tasks", "type", existing_type=sa.VARCHAR(), nullable=False) + + op.drop_index("ix_tasks_p_item_hash", table_name="tasks") + + op.create_index(op.f("ix_tasks_hash"), "tasks", ["hash"], unique=False) + op.create_foreign_key(None, "tasks", "schedules", ["schedule_id"], ["id"], ondelete="SET NULL") + + op.drop_column("tasks", "p_item") + + # Create schedules from tasks + op.execute( + """ + INSERT INTO schedules (id, scheduler_id, hash, data, enabled, schedule, deadline_at, created_at, modified_at) + SELECT DISTINCT ON (scheduler_id, hash) uuid_generate_v4(), scheduler_id, hash, data, true, '0 0 * * *', + now() + INTERVAL '1 day' * random(), now(), now() + FROM tasks ORDER BY scheduler_id, hash, created_at DESC + """ + ) + + # Update tasks with schedule_id + op.execute( + """ + UPDATE tasks + SET schedule_id = schedules.id + FROM schedules + WHERE tasks.hash = schedules.hash + """ + ) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column( + "tasks", + sa.Column( + "p_item", + postgresql.JSONB(astext_type=sa.Text()), + autoincrement=False, + nullable=False, + ), + ) + + op.execute( + """ + UPDATE tasks + SET p_item = jsonb_set(p_item, '{data}', data) + """ + ) + + op.execute( + """ + UPDATE tasks + SET p_item = jsonb_set(p_item, '{priority}', to_jsonb(priority)) + """ + ) + + op.execute( + """ + UPDATE tasks + SET p_item = jsonb_set(p_item, '{hash}', to_jsonb(hash)) + """ + ) + + op.drop_constraint(None, "tasks", type_="foreignkey") + op.drop_index(op.f("ix_tasks_hash"), table_name="tasks") + op.create_index( + "ix_tasks_p_item_hash", + "tasks", + [sa.text("(p_item ->> 'hash'::text)"), sa.text("created_at DESC")], + unique=False, + ) + op.alter_column("tasks", "type", existing_type=sa.VARCHAR(), nullable=True) + op.alter_column("tasks", "scheduler_id", existing_type=sa.VARCHAR(), nullable=True) + op.drop_column("tasks", "data") + op.drop_column("tasks", "priority") + op.drop_column("tasks", "hash") + op.drop_column("tasks", "schedule_id") + op.create_table( + "items", + sa.Column("id", sa.UUID(), autoincrement=False, nullable=False), + sa.Column("scheduler_id", sa.VARCHAR(), autoincrement=False, nullable=True), + sa.Column("hash", sa.VARCHAR(length=32), autoincrement=False, nullable=True), + sa.Column("priority", sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column( + "data", + postgresql.JSONB(astext_type=sa.Text()), + autoincrement=False, + nullable=False, + ), + sa.Column( + "created_at", + postgresql.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + autoincrement=False, + nullable=False, + ), + sa.Column( + "modified_at", + postgresql.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + autoincrement=False, + nullable=False, + ), + sa.PrimaryKeyConstraint("id", name="items_pkey"), + ) + op.create_index("ix_items_hash", "items", ["hash"], unique=False) + op.drop_table("schedules") + # ### end Alembic commands ### diff --git a/mula/scheduler/connectors/services/octopoes.py b/mula/scheduler/connectors/services/octopoes.py index 90688db5a58..04d7b9f33f0 100644 --- a/mula/scheduler/connectors/services/octopoes.py +++ b/mula/scheduler/connectors/services/octopoes.py @@ -88,7 +88,7 @@ def get_random_objects(self, organisation_id: str, n: int, scan_level: list[int] @exception_handler def get_object(self, organisation_id: str, reference: str) -> OOI: """Get an ooi from octopoes""" - url = f"{self.host}/{organisation_id}" + url = f"{self.host}/{organisation_id}/object" response = self.get( url, params={"reference": reference, "valid_time": datetime.now(timezone.utc)}, diff --git a/mula/scheduler/context/context.py b/mula/scheduler/context/context.py index 9b1f885f795..92e3b823221 100644 --- a/mula/scheduler/context/context.py +++ b/mula/scheduler/context/context.py @@ -153,7 +153,10 @@ def __init__(self) -> None: # Database connection try: - dbconn = storage.DBConn(str(self.config.db_uri)) + dbconn = storage.DBConn( + dsn=str(self.config.db_uri), + pool_size=self.config.db_connection_pool_size, + ) dbconn.connect() except storage.errors.StorageError: self.logger.exception("Failed to connect to database") @@ -165,6 +168,7 @@ def __init__(self) -> None: # Datastores, SimpleNamespace allows us to use dot notation self.datastores: SimpleNamespace = SimpleNamespace( **{ + storage.ScheduleStore.name: storage.ScheduleStore(dbconn), storage.TaskStore.name: storage.TaskStore(dbconn), storage.PriorityQueueStore.name: storage.PriorityQueueStore(dbconn), } diff --git a/mula/scheduler/models/__init__.py b/mula/scheduler/models/__init__.py index 894fb0de555..ed1a7fa177a 100644 --- a/mula/scheduler/models/__init__.py +++ b/mula/scheduler/models/__init__.py @@ -6,7 +6,7 @@ from .ooi import OOI, MutationOperationType, ScanProfile, ScanProfileMutation from .organisation import Organisation from .plugin import Plugin -from .queue import PrioritizedItem, PrioritizedItemDB, Queue -from .request import PrioritizedItemRequest +from .queue import Queue +from .schedule import Schedule, ScheduleDB from .scheduler import Scheduler -from .tasks import BoefjeTask, NormalizerTask, Task, TaskDB, TaskStatus +from .task import BoefjeTask, NormalizerTask, Task, TaskDB, TaskStatus diff --git a/mula/scheduler/models/errors.py b/mula/scheduler/models/errors.py new file mode 100644 index 00000000000..15e676c5dfe --- /dev/null +++ b/mula/scheduler/models/errors.py @@ -0,0 +1,2 @@ +class ValidationError(Exception): + pass diff --git a/mula/scheduler/models/queue.py b/mula/scheduler/models/queue.py index d71df6e455e..af87149c874 100644 --- a/mula/scheduler/models/queue.py +++ b/mula/scheduler/models/queue.py @@ -1,65 +1,6 @@ -import uuid -from datetime import datetime, timezone +from pydantic import BaseModel -from pydantic import BaseModel, ConfigDict, Field -from sqlalchemy import Column, DateTime, Integer, String -from sqlalchemy.dialects.postgresql import JSONB -from sqlalchemy.sql import func - -from scheduler.utils import GUID - -from .base import Base - - -class PrioritizedItem(BaseModel): - """Representation of an queue.PrioritizedItem on the priority queue. Used - for unmarshalling of priority queue prioritized items to a JSON - representation. - """ - - model_config = ConfigDict(from_attributes=True) - - id: uuid.UUID = Field(default_factory=uuid.uuid4) - - scheduler_id: str | None = None - - # A unique generated identifier for the object contained in data - hash: str | None = Field(None, max_length=32) - - priority: int | None = 0 - - data: dict = Field(default_factory=dict) - - created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) - - modified_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) - - -class PrioritizedItemDB(Base): - __tablename__ = "items" - - id = Column(GUID, primary_key=True) - - scheduler_id = Column(String) - - hash = Column(String(32), index=True) - - priority = Column(Integer) - - data = Column(JSONB, nullable=False) - - created_at = Column( - DateTime(timezone=True), - nullable=False, - server_default=func.now(), - ) - - modified_at = Column( - DateTime(timezone=True), - nullable=False, - server_default=func.now(), - onupdate=func.now(), - ) +from .task import Task class Queue(BaseModel): @@ -70,4 +11,4 @@ class Queue(BaseModel): allow_replace: bool allow_updates: bool allow_priority_updates: bool - pq: list[PrioritizedItem] | None = None + pq: list[Task] | None = None diff --git a/mula/scheduler/models/raw_data.py b/mula/scheduler/models/raw_data.py index e498d84e46e..b544279a814 100644 --- a/mula/scheduler/models/raw_data.py +++ b/mula/scheduler/models/raw_data.py @@ -9,5 +9,5 @@ class RawData(BaseModel): id: uuid.UUID boefje_meta: BoefjeMeta mime_types: list[dict[str, str]] - secure_hash: str | None - hash_retrieval_link: str | None + secure_hash: str | None = None + hash_retrieval_link: str | None = None diff --git a/mula/scheduler/models/request.py b/mula/scheduler/models/request.py deleted file mode 100644 index 327439daa21..00000000000 --- a/mula/scheduler/models/request.py +++ /dev/null @@ -1,8 +0,0 @@ -from pydantic import BaseModel, Field - - -class PrioritizedItemRequest(BaseModel): - """Request model for prioritized items used in the server.""" - - priority: int - data: dict = Field(default_factory=dict) diff --git a/mula/scheduler/models/schedule.py b/mula/scheduler/models/schedule.py new file mode 100644 index 00000000000..9f91e6f38df --- /dev/null +++ b/mula/scheduler/models/schedule.py @@ -0,0 +1,84 @@ +import uuid +from datetime import datetime, timezone + +from pydantic import BaseModel, ConfigDict, Field, field_validator +from sqlalchemy import Boolean, Column, DateTime, String +from sqlalchemy.dialects.postgresql import JSONB +from sqlalchemy.orm import relationship +from sqlalchemy.sql import func + +from scheduler.utils import GUID, cron + +from .base import Base +from .task import Task + + +class Schedule(BaseModel): + model_config = ConfigDict(from_attributes=True, validate_assignment=True) + + id: uuid.UUID = Field(default_factory=uuid.uuid4) + + scheduler_id: str + + hash: str | None = Field(None, max_length=32) + + data: dict | None = None + + enabled: bool = True + + schedule: str | None = None + + tasks: list[Task] = [] + + deadline_at: datetime | None = None + created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) + modified_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) + + @field_validator("schedule") + @classmethod + def validate_schedule(cls, value: str) -> str: + """Validate the schedule cron expression.""" + if value is None: + return value + + try: + cron.next_run(value) + return value + except Exception as exc: + raise ValueError(f"Invalid cron expression: {value}") from exc + + +class ScheduleDB(Base): + __tablename__ = "schedules" + + id = Column(GUID, primary_key=True) + + scheduler_id = Column(String, nullable=False) + + hash = Column(String(32), nullable=True, unique=True) + + data = Column(JSONB, nullable=False) + + enabled = Column(Boolean, nullable=False, default=True) + + schedule = Column(String, nullable=True) + + tasks = relationship("TaskDB", back_populates="schedule") + + deadline_at = Column( + DateTime(timezone=True), + nullable=True, + ) + + created_at = Column( + DateTime(timezone=True), + nullable=False, + server_default=func.now(), + ) + + modified_at = Column( + DateTime(timezone=True), + nullable=False, + server_default=func.now(), + onupdate=func.now(), + ) diff --git a/mula/scheduler/models/tasks.py b/mula/scheduler/models/task.py similarity index 79% rename from mula/scheduler/models/tasks.py rename to mula/scheduler/models/task.py index 80cedd12891..cf0c9a95834 100644 --- a/mula/scheduler/models/tasks.py +++ b/mula/scheduler/models/task.py @@ -5,18 +5,16 @@ import mmh3 from pydantic import BaseModel, ConfigDict, Field -from sqlalchemy import Column, DateTime, Enum, String +from sqlalchemy import Column, DateTime, Enum, ForeignKey, Integer, String from sqlalchemy.dialects.postgresql import JSONB -from sqlalchemy.schema import Index +from sqlalchemy.orm import relationship from sqlalchemy.sql import func -from sqlalchemy.sql.expression import text from scheduler.utils import GUID from .base import Base from .boefje import Boefje from .normalizer import Normalizer -from .queue import PrioritizedItem from .raw_data import RawData @@ -47,22 +45,24 @@ class TaskStatus(str, enum.Enum): class Task(BaseModel): model_config = ConfigDict(from_attributes=True, use_enum_values=True) - id: uuid.UUID + id: uuid.UUID = Field(default_factory=uuid.uuid4) - scheduler_id: str + scheduler_id: str | None = None - type: str + schedule_id: uuid.UUID | None = None - p_item: PrioritizedItem + priority: int | None = 0 - status: TaskStatus + status: TaskStatus = TaskStatus.PENDING - created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) + type: str | None = None - modified_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) + hash: str | None = Field(None, max_length=32) + + data: dict | None = None - def __repr__(self): - return f"Task(id={self.id}, scheduler_id={self.scheduler_id}, type={self.type}, status={self.status})" + created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) + modified_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) class TaskDB(Base): @@ -70,11 +70,18 @@ class TaskDB(Base): id = Column(GUID, primary_key=True) - scheduler_id = Column(String) + scheduler_id = Column(String, nullable=False) - type = Column(String) + schedule_id = Column(GUID, ForeignKey("schedules.id", ondelete="SET NULL"), nullable=True) + schedule = relationship("ScheduleDB", back_populates="tasks") - p_item = Column(JSONB, nullable=False) + type = Column(String, nullable=False) + + hash = Column(String(32), index=True) + + priority = Column(Integer) + + data = Column(JSONB, nullable=False) status = Column( Enum(TaskStatus), @@ -95,14 +102,6 @@ class TaskDB(Base): onupdate=func.now(), ) - __table_args__ = ( - Index( - "ix_p_item_hash", - text("(p_item->>'hash')"), - created_at.desc(), - ), - ) - class NormalizerTask(BaseModel): """NormalizerTask represent data needed for a Normalizer to run.""" @@ -130,7 +129,7 @@ class BoefjeTask(BaseModel): id: uuid.UUID | None = Field(default_factory=uuid.uuid4) boefje: Boefje - input_ooi: str | None + input_ooi: str | None = None organization: str dispatches: list[Normalizer] = Field(default_factory=list) diff --git a/mula/scheduler/queues/__init__.py b/mula/scheduler/queues/__init__.py index 50d51f48471..b8461bf08e8 100644 --- a/mula/scheduler/queues/__init__.py +++ b/mula/scheduler/queues/__init__.py @@ -1,4 +1,2 @@ -from .boefje import BoefjePriorityQueue -from .errors import InvalidPrioritizedItemError, NotAllowedError, QueueEmptyError, QueueFullError -from .normalizer import NormalizerPriorityQueue +from .errors import InvalidItemError, ItemNotFoundError, NotAllowedError, QueueEmptyError, QueueFullError from .pq import PriorityQueue diff --git a/mula/scheduler/queues/boefje.py b/mula/scheduler/queues/boefje.py deleted file mode 100644 index 9177d97e9e8..00000000000 --- a/mula/scheduler/queues/boefje.py +++ /dev/null @@ -1,24 +0,0 @@ -import mmh3 - -from scheduler import models -from scheduler.utils import dict_utils - -from .pq import PriorityQueue - - -class BoefjePriorityQueue(PriorityQueue): - def create_hash(self, p_item: models.PrioritizedItem) -> str: - """Create a hash for the given item. This hash is used to determine if - the item is already in the queue. - - Args: - p_item: A PrioritizedItem model. - - Returns: - A string representing the hash. - """ - boefje_id = dict_utils.deep_get(p_item.model_dump(), ["data", "boefje", "id"]) - input_ooi = dict_utils.deep_get(p_item.model_dump(), ["data", "input_ooi"]) - organization = dict_utils.deep_get(p_item.model_dump(), ["data", "organization"]) - - return mmh3.hash_bytes(f"{input_ooi}-{boefje_id}-{organization}").hex() diff --git a/mula/scheduler/queues/errors.py b/mula/scheduler/queues/errors.py index dd98e55c6ea..2b73340ce79 100644 --- a/mula/scheduler/queues/errors.py +++ b/mula/scheduler/queues/errors.py @@ -9,7 +9,7 @@ class NotAllowedError(Exception): pass -class InvalidPrioritizedItemError(ValueError): +class InvalidItemError(ValueError): pass @@ -17,5 +17,5 @@ class QueueFullError(Full): pass -class PrioritizedItemNotFoundError(Exception): +class ItemNotFoundError(Exception): pass diff --git a/mula/scheduler/queues/normalizer.py b/mula/scheduler/queues/normalizer.py deleted file mode 100644 index 90cc7b86fa1..00000000000 --- a/mula/scheduler/queues/normalizer.py +++ /dev/null @@ -1,35 +0,0 @@ -import mmh3 - -from scheduler import models -from scheduler.utils import dict_utils - -from .pq import PriorityQueue - - -class NormalizerPriorityQueue(PriorityQueue): - def create_hash(self, p_item: models.PrioritizedItem) -> str: - """Create a hash for the given item. This hash is used to determine if - the item is already in the queue. - - Args: - p_item: A PrioritizedItem model. - - Returns: - A string representing the hash. - """ - normalizer_id = dict_utils.deep_get( - p_item.model_dump(), - ["data", "normalizer", "id"], - ) - - boefje_meta_id = dict_utils.deep_get( - p_item.model_dump(), - ["data", "raw_data", "boefje_meta", "id"], - ) - - organization = dict_utils.deep_get( - p_item.model_dump(), - ["data", "raw_data", "boefje_meta", "organization"], - ) - - return mmh3.hash_bytes(f"{normalizer_id}-{boefje_meta_id}-{organization}").hex() diff --git a/mula/scheduler/queues/pq.py b/mula/scheduler/queues/pq.py index 5fb525edf42..7cb160c7c2e 100644 --- a/mula/scheduler/queues/pq.py +++ b/mula/scheduler/queues/pq.py @@ -10,13 +10,7 @@ from scheduler import models, storage -from .errors import ( - InvalidPrioritizedItemError, - NotAllowedError, - PrioritizedItemNotFoundError, - QueueEmptyError, - QueueFullError, -) +from .errors import InvalidItemError, ItemNotFoundError, NotAllowedError, QueueEmptyError, QueueFullError def with_lock(method): @@ -54,6 +48,9 @@ class PriorityQueue(abc.ABC): pq_store: A PriorityQueueStore instance that will be used to store the items in a persistent way. + lock: + A threading.Lock instance that will be used to lock the queue + operations. """ def __init__( @@ -100,7 +97,7 @@ def __init__( self.pq_store: storage.PriorityQueueStore = pq_store self.lock: threading.Lock = threading.Lock() - def pop(self, filters: storage.filters.FilterRequest | None = None) -> models.PrioritizedItem | None: + def pop(self, filters: storage.filters.FilterRequest | None = None) -> models.Task | None: """Remove and return the highest priority item from the queue. Optionally apply filters to the queue. @@ -120,15 +117,16 @@ def pop(self, filters: storage.filters.FilterRequest | None = None) -> models.Pr if item is None: return None - self.remove(item) + item.status = models.TaskStatus.DISPATCHED + self.pq_store.update(self.pq_id, item) return item - def push(self, p_item: models.PrioritizedItem) -> models.PrioritizedItem | None: + def push(self, task: models.Task) -> models.Task: """Push an item onto the queue. Args: - p_item: The item to be pushed onto the queue. + task: The item to be pushed onto the queue. Returns: The item that was pushed onto the queue. @@ -136,35 +134,35 @@ def push(self, p_item: models.PrioritizedItem) -> models.PrioritizedItem | None: Raises: NotAllowedError: If the item is not allowed to be pushed. - InvalidPrioritizedItemError: If the item is not valid. + InvalidItemError: If the item is not valid. QueueFullError: If the queue is full. - PrioritizedItemNotFoundError: If the item is not found on the queue. + ItemNotFoundError: If the item is not found on the queue. """ - if not isinstance(p_item, models.PrioritizedItem): - raise InvalidPrioritizedItemError("The item is not a PrioritizedItem") + if not isinstance(task, models.Task): + raise InvalidItemError("The item is not of type Task") - if not self._is_valid_item(p_item.data): - raise InvalidPrioritizedItemError(f"PrioritizedItem must be of type {self.item_type}") + if not self._is_valid_item(task.data): + raise InvalidItemError(f"Task must be of type {self.item_type}") - if not p_item.priority: - raise InvalidPrioritizedItemError("PrioritizedItem must have a priority") + if not task.priority: + raise InvalidItemError("Task must have a priority") - if self.full() and p_item.priority > 1: + if self.full() and task.priority > 1: raise QueueFullError(f"Queue {self.pq_id} is full.") # We try to get the item from the queue by a specified identifier of # that item by the implementation of the queue. We don't do this by # the item itself or its hash because this might have been changed # and we might need to update that. - item_on_queue = self.get_p_item_by_identifier(p_item) + item_on_queue = self.get_item_by_identifier(task) # Item on queue and data changed - item_changed = item_on_queue and p_item.data != item_on_queue.data + item_changed = item_on_queue and task.data != item_on_queue.data # Item on queue and priority changed - priority_changed = item_on_queue and p_item.priority != item_on_queue.priority + priority_changed = item_on_queue and task.priority != item_on_queue.priority allowed = any( ( @@ -176,7 +174,7 @@ def push(self, p_item: models.PrioritizedItem) -> models.PrioritizedItem | None: ) if not allowed: - message = f"Item {p_item} already on queue {self.pq_id}." + message = f"Item {task} already on queue {self.pq_id}." if item_on_queue and not self.allow_replace: message = "Item already on queue, we're not allowed to replace the item that is already on the queue." @@ -199,20 +197,21 @@ def push(self, p_item: models.PrioritizedItem) -> models.PrioritizedItem | None: # If already on queue update the item, else create a new one item_db = None if not item_on_queue: - identifier = self.create_hash(p_item) - p_item.hash = identifier - item_db = self.pq_store.push(self.pq_id, p_item) + identifier = self.create_hash(task) + task.hash = identifier + task.status = models.TaskStatus.QUEUED + item_db = self.pq_store.push(task) else: - self.pq_store.update(self.pq_id, p_item) - item_db = self.get_p_item_by_identifier(p_item) + self.pq_store.update(self.pq_id, task) + item_db = self.get_item_by_identifier(task) if not item_db: - raise PrioritizedItemNotFoundError(f"Item {p_item} not found in datastore {self.pq_id}") + raise ItemNotFoundError(f"Item {task} not found in datastore {self.pq_id}") return item_db @with_lock - def peek(self, index: int) -> models.PrioritizedItem | None: + def peek(self, index: int) -> models.Task | None: """Return the item at index without removing it. Args: @@ -224,16 +223,16 @@ def peek(self, index: int) -> models.PrioritizedItem | None: return self.pq_store.peek(self.pq_id, index) @with_lock - def remove(self, p_item: models.PrioritizedItem) -> None: + def remove(self, task: models.Task) -> None: """Remove an item from the queue. Args: - p_item: The item to be removed from the queue. + task: The item to be removed from the queue. Returns: The item that was removed from the queue. """ - self.pq_store.remove(self.pq_id, p_item.id) + self.pq_store.remove(self.pq_id, task.id) @with_lock def clear(self) -> None: @@ -258,16 +257,16 @@ def full(self) -> bool: return current_size >= self.maxsize - def is_item_on_queue(self, p_item: models.PrioritizedItem) -> bool: + def is_item_on_queue(self, task: models.Task) -> bool: """Check if an item is on the queue. Args: - p_item: The item to be checked. + task: The item to be checked. Returns: True if the item is on the queue, False otherwise. """ - identifier = self.create_hash(p_item) + identifier = self.create_hash(task) item = self.pq_store.get_item_by_hash(self.pq_id, identifier) if item is None: return False @@ -288,16 +287,16 @@ def is_item_on_queue_by_hash(self, item_hash: str) -> bool: return item is not None @with_lock - def get_p_item_by_identifier(self, p_item: models.PrioritizedItem) -> models.PrioritizedItem | None: + def get_item_by_identifier(self, task: models.Task) -> models.Task | None: """Get an item from the queue by its identifier. Args: - p_item: The item to be checked. + task: The item to be checked. Returns: The item if found, None otherwise. """ - identifier = self.create_hash(p_item) + identifier = self.create_hash(task) item = self.pq_store.get_item_by_hash(self.pq_id, identifier) return item @@ -334,8 +333,7 @@ def dict(self, include_pq: bool = True) -> dict[str, Any]: return response - @abc.abstractmethod - def create_hash(self, p_item: models.PrioritizedItem) -> str: + def create_hash(self, task: models.Task) -> str: """Create a hash for the given item. This hash is used to determine if the item is already in the queue. @@ -344,9 +342,10 @@ def create_hash(self, p_item: models.PrioritizedItem) -> str: the queue. Args: - p_item: The item to be hashed. + task: The item to be hashed. Returns: A string representing the hash of the item. """ - raise NotImplementedError + item = self.item_type(**task.data) + return item.hash diff --git a/mula/scheduler/schedulers/boefje.py b/mula/scheduler/schedulers/boefje.py index 5c90451b628..fcf618aa6dd 100644 --- a/mula/scheduler/schedulers/boefje.py +++ b/mula/scheduler/schedulers/boefje.py @@ -1,12 +1,14 @@ +import uuid from collections.abc import Callable from concurrent import futures from datetime import datetime, timedelta, timezone from types import SimpleNamespace +from typing import Any import structlog from opentelemetry import trace -from scheduler import context, models, queues, rankers +from scheduler import context, queues, rankers, storage from scheduler.connectors import listeners from scheduler.connectors.errors import ExternalServiceError from scheduler.models import ( @@ -16,8 +18,8 @@ MutationOperationType, Organisation, Plugin, - PrioritizedItem, ScanProfileMutation, + Task, TaskStatus, ) from scheduler.storage import filters @@ -36,6 +38,8 @@ class BoefjeScheduler(Scheduler): organisation: The organisation that this scheduler is for. """ + ITEM_TYPE: Any = BoefjeTask + def __init__( self, ctx: context.AppContext, @@ -44,13 +48,22 @@ def __init__( queue: queues.PriorityQueue | None = None, callback: Callable[..., None] | None = None, ): - self.logger = structlog.getLogger(__name__) + """Initializes the BoefjeScheduler. + + Args: + ctx: The application context. + scheduler_id: The id of the scheduler. + organisation: The organisation that this scheduler is for. + queue: The queue to use for this scheduler. + callback: The callback function to call when a task is completed. + """ + self.logger: structlog.BoundLogger = structlog.getLogger(__name__) self.organisation: Organisation = organisation - self.queue = queue or queues.BoefjePriorityQueue( + self.queue = queue or queues.PriorityQueue( pq_id=scheduler_id, maxsize=ctx.config.pq_maxsize, - item_type=models.BoefjeTask, + item_type=self.ITEM_TYPE, allow_priority_updates=True, pq_store=ctx.datastores.pq_store, ) @@ -60,39 +73,36 @@ def __init__( queue=self.queue, scheduler_id=scheduler_id, callback=callback, + create_schedule=True, ) - self.ranker = rankers.BoefjeRanker( - ctx=self.ctx, - ) + # Priority ranker + self.priority_ranker = rankers.BoefjeRanker(self.ctx) def run(self) -> None: """The run method is called when the scheduler is started. It will start the listeners and the scheduling loops in separate threads. It is mainly tasked with populating the queue with tasks. - * Scan profile mutations; when a scan profile is updated for an ooi + - Scan profile mutations; when a scan profile is updated for an ooi e.g. the scan level is changed, we need to create new tasks for the ooi. We gather all boefjes that can run on the ooi and create tasks for them. - * New boefjes; when new boefjes are added or enabled we find the ooi's + - New boefjes; when new boefjes are added or enabled we find the ooi's that boefjes can run on, and create tasks for it. - * Random OOI's from Octopoes; every minute we get a random OOI from - Octopoes and create a task for it for the available boefjes for this - OOI. + - Rescheduling; when a task has passed its deadline, we need to + reschedule it. """ # Scan profile mutations - listener = listeners.ScanProfileMutation( + self.listeners["scan_profile_mutations"] = listeners.ScanProfileMutation( dsn=str(self.ctx.config.host_raw_data), queue=f"{self.organisation.id}__scan_profile_mutations", func=self.push_tasks_for_scan_profile_mutations, prefetch_count=self.ctx.config.rabbitmq_prefetch_count, ) - self.listeners["scan_profile_mutations"] = listener - self.run_in_thread( name=f"BoefjeScheduler-{self.scheduler_id}-mutations", target=self.listeners["scan_profile_mutations"].listen, @@ -106,10 +116,10 @@ def run(self) -> None: interval=60.0, ) - # Random OOI's from Octopoes + # Rescheduling self.run_in_thread( - name=f"BoefjeScheduler-{self.scheduler_id}-random", - target=self.push_tasks_for_random_objects, + name=f"scheduler-{self.scheduler_id}-reschedule", + target=self.push_tasks_for_rescheduling, interval=60.0, ) @@ -140,7 +150,7 @@ def push_tasks_for_scan_profile_mutations(self, body: bytes) -> None: scheduler_id=self.scheduler_id, ) - # Should be an OOI in value + # There should be an OOI in value ooi = mutation.value if ooi is None: self.logger.debug( @@ -170,15 +180,7 @@ def push_tasks_for_scan_profile_mutations(self, body: bytes) -> None: # Delete all items for this ooi, update all tasks for this ooi # to cancelled. for item in items: - self.ctx.datastores.pq_store.remove( - scheduler_id=self.scheduler_id, - item_id=item.id, - ) - - if item.hash is None: - continue - - task = self.ctx.datastores.task_store.get_latest_task_by_hash(item.hash) + task = self.ctx.datastores.task_store.get_task(item.id) if task is None: continue @@ -202,10 +204,25 @@ def push_tasks_for_scan_profile_mutations(self, body: bytes) -> None: thread_name_prefix=f"BoefjeScheduler-TPE-{self.scheduler_id}-mutations" ) as executor: for boefje in boefjes: + if not self.has_boefje_permission_to_run(boefje, ooi): + self.logger.debug( + "Boefje not allowed to run on ooi", + boefje_id=boefje.id, + ooi_primary_key=ooi.primary_key, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + continue + + boefje_task = BoefjeTask( + boefje=Boefje.parse_obj(boefje.dict()), + input_ooi=ooi.primary_key if ooi else None, + organization=self.organisation.id, + ) + executor.submit( - self.push_task, - boefje, - ooi, + self.push_boefje_task, + boefje_task, self.push_tasks_for_scan_profile_mutations.__name__, ) @@ -273,16 +290,30 @@ def push_tasks_for_new_boefjes(self) -> None: thread_name_prefix=f"BoefjeScheduler-TPE-{self.scheduler_id}-new_boefjes" ) as executor: for ooi in oois_by_object_type: + if not self.has_boefje_permission_to_run(boefje, ooi): + self.logger.debug( + "Boefje not allowed to run on ooi", + boefje_id=boefje.id, + ooi_primary_key=ooi.primary_key, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + continue + + boefje_task = BoefjeTask( + boefje=Boefje.parse_obj(boefje.dict()), + input_ooi=ooi.primary_key, + organization=self.organisation.id, + ) + executor.submit( - self.push_task, - boefje, - ooi, + self.push_boefje_task, + boefje_task, self.push_tasks_for_new_boefjes.__name__, ) - @tracer.start_as_current_span("boefje_push_tasks_for_random_objects") - def push_tasks_for_random_objects(self) -> None: - """Push tasks for random ooi's from octopoes to the queue.""" + @tracer.start_as_current_span("boefje_push_tasks_for_rescheduling") + def push_tasks_for_rescheduling(self): if self.queue.full(): self.logger.warning( "Boefjes queue is full, not populating with new tasks", @@ -293,62 +324,330 @@ def push_tasks_for_random_objects(self) -> None: return try: - random_oois = self.ctx.services.octopoes.get_random_objects( - organisation_id=self.organisation.id, - n=self.ctx.config.pq_max_random_objects, - scan_level=[1, 2, 3, 4], + schedules, _ = self.ctx.datastores.schedule_store.get_schedules( + filters=filters.FilterRequest( + filters=[ + filters.Filter( + column="scheduler_id", + operator="eq", + value=self.scheduler_id, + ), + filters.Filter( + column="deadline_at", + operator="lt", + value=datetime.now(timezone.utc), + ), + filters.Filter( + column="enabled", + operator="eq", + value=True, + ), + ] + ) ) - except ExternalServiceError: - self.logger.exception( - "Could not get random oois for organisation: %s from octopoes", - self.organisation.name, + except storage.errors.StorageError as exc_db: + self.logger.error( + "Could not get schedules for rescheduling %s", + self.scheduler_id, + scheduler_id=self.scheduler_id, organisation_id=self.organisation.id, + exc_info=exc_db, + ) + raise exc_db + + if not schedules: + self.logger.debug( + "No schedules tasks found for scheduler: %s", + self.scheduler_id, scheduler_id=self.scheduler_id, + organisation_id=self.organisation.id, ) return - if not random_oois: - self.logger.debug( - "No random oois for organisation: %s", - self.organisation.name, + with futures.ThreadPoolExecutor( + thread_name_prefix=f"BoefjeScheduler-TPE-{self.scheduler_id}-rescheduling" + ) as executor: + for schedule in schedules: + boefje_task = BoefjeTask.parse_obj(schedule.data) + + # Plugin still exists? + plugin = self.ctx.services.katalogus.get_plugin_by_id_and_org_id( + boefje_task.boefje.id, + self.organisation.id, + ) + if not plugin: + self.logger.debug( + "Boefje does not exist anymore, skipping", + boefje_id=boefje_task.boefje.id, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + schedule.enabled = False + self.ctx.datastores.schedule_store.update_schedule(schedule) + continue + + # Plugin still enabled? + if not plugin.enabled: + self.logger.debug( + "Boefje is disabled, skipping", + boefje_id=boefje_task.boefje.id, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + schedule.enabled = False + self.ctx.datastores.schedule_store.update_schedule(schedule) + continue + + # Plugin a boefje? + if plugin.type != "boefje": + # We don't disable the schedule, since we should've gotten + # schedules for boefjes only. + self.logger.warning( + "Plugin is not a boefje, skipping", + plugin_id=plugin.id, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + continue + + # When the boefje task has an ooi, we need to do some additional + # checks. + ooi = None + if boefje_task.input_ooi: + # OOI still exists? + ooi = self.ctx.services.octopoes.get_object(boefje_task.organization, boefje_task.input_ooi) + if not ooi: + self.logger.debug( + "OOI does not exist anymore, skipping", + ooi_primary_key=boefje_task.input_ooi, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + schedule.enabled = False + self.ctx.datastores.schedule_store.update_schedule(schedule) + continue + + # Boefje still consuming ooi type? + if ooi.object_type not in plugin.consumes: + self.logger.debug( + "Boefje does not consume ooi anymore, skipping", + boefje_id=boefje_task.boefje.id, + ooi_primary_key=ooi.primary_key, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + schedule.enabled = False + self.ctx.datastores.schedule_store.update_schedule(schedule) + continue + + # TODO: do we want to disable the schedule when a + # boefje is not allowed to scan an ooi? + + # Boefje allowed to scan ooi? + if not self.has_boefje_permission_to_run(plugin, ooi): + self.logger.debug( + "Boefje not allowed to scan ooi, skipping", + boefje_id=boefje_task.boefje.id, + ooi_primary_key=ooi.primary_key, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + schedule.enabled = False + self.ctx.datastores.schedule_store.update_schedule(schedule) + continue + + new_boefje_task = BoefjeTask( + boefje=Boefje.parse_obj(plugin.dict()), + input_ooi=ooi.primary_key if ooi else None, + organization=self.organisation.id, + ) + + executor.submit( + self.push_boefje_task, + new_boefje_task, + self.push_tasks_for_rescheduling.__name__, + ) + + @tracer.start_as_current_span("boefje_push_task") + def push_boefje_task( + self, + boefje_task: BoefjeTask, + caller: str = "", + ) -> None: + """Given a Boefje and OOI create a BoefjeTask and push it onto + the queue. + + Args: + boefje: Boefje to run. + ooi: OOI to run Boefje on. + caller: The name of the function that called this function, used for logging. + + """ + self.logger.debug( + "Pushing boefje task", + task_hash=boefje_task.hash, + boefje_id=boefje_task.boefje.id, + ooi_primary_key=boefje_task.input_ooi, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + ) + + try: + grace_period_passed = self.has_boefje_task_grace_period_passed(boefje_task) + if not grace_period_passed: + self.logger.debug( + "Task has not passed grace period: %s", + boefje_task.hash, + task_hash=boefje_task.hash, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + ) + return + except Exception as exc_grace_period: + self.logger.warning( + "Could not check if grace period has passed: %s", + boefje_task.hash, + task_hash=boefje_task.hash, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, + caller=caller, + exc_info=exc_grace_period, ) return - for ooi in random_oois: - self.logger.debug( - "Checking random ooi %s for rescheduling of tasks", - ooi.primary_key, - ooi_primary_key=ooi.primary_key, + try: + is_stalled = self.has_boefje_task_stalled(boefje_task) + if is_stalled: + self.logger.debug( + "Task is stalled: %s", + boefje_task.hash, + task_hash=boefje_task.hash, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + ) + + # Update task in datastore to be failed + task_db = self.ctx.datastores.task_store.get_latest_task_by_hash(boefje_task.hash) + task_db.status = TaskStatus.FAILED + self.ctx.datastores.task_store.update_task(task_db) + except Exception as exc_stalled: + self.logger.warning( + "Could not check if task is stalled: %s", + boefje_task.hash, + boefje_task_hash=boefje_task.hash, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, + caller=caller, + exc_info=exc_stalled, ) + return - boefjes = self.get_boefjes_for_ooi(ooi) - if boefjes is None or not boefjes: + try: + is_running = self.has_boefje_task_started_running(boefje_task) + if is_running: self.logger.debug( - "No boefjes available for ooi %s, skipping", - ooi.primary_key, - ooi_primary_key=ooi, + "Task is still running: %s", + boefje_task.hash, + task_hash=boefje_task.hash, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, + caller=caller, ) - continue + return + except Exception as exc_running: + self.logger.warning( + "Could not check if task is running: %s", + boefje_task.hash, + task_hash=boefje_task.hash, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + exc_info=exc_running, + ) + return - with futures.ThreadPoolExecutor( - thread_name_prefix=f"BoefjeScheduler-TPE-{self.scheduler_id}-random" - ) as executor: - for boefje in boefjes: - executor.submit( - self.push_task, - boefje, - ooi, - self.push_tasks_for_random_objects.__name__, - ) + if self.is_item_on_queue_by_hash(boefje_task.hash): + self.logger.debug( + "Task is already on queue: %s", + boefje_task.hash, + task_hash=boefje_task.hash, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + exc_info=True, + ) + return + + prior_tasks = self.ctx.datastores.task_store.get_tasks_by_hash(boefje_task.hash) + score = self.priority_ranker.rank( + SimpleNamespace( + prior_tasks=prior_tasks, + task=boefje_task, + ) + ) + + task = Task( + id=boefje_task.id, + scheduler_id=self.scheduler_id, + type=self.ITEM_TYPE.type, + priority=score, + hash=boefje_task.hash, + data=boefje_task.model_dump(), + ) + + try: + self.push_item_to_queue_with_timeout( + task, + self.max_tries, + ) + except queues.QueueFullError: + self.logger.warning( + "Could not add task to queue, queue was full: %s", + boefje_task.hash, + task_hash=boefje_task.hash, + queue_qsize=self.queue.qsize(), + queue_maxsize=self.queue.maxsize, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + ) + return + + self.logger.info( + "Created boefje task", + task_id=task.id, + task_hash=task.hash, + boefje_id=boefje_task.boefje.id, + ooi_primary_key=boefje_task.input_ooi, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + ) + + def push_item_to_queue(self, item: Task) -> Task: + """Some boefje scheduler specific logic before pushing the item to the + queue.""" + boefje_task = BoefjeTask.parse_obj(item.data) - @tracer.start_as_current_span("boefje_is_task_allowed_to_run") - def is_task_allowed_to_run(self, boefje: Plugin, ooi: OOI) -> bool: + # Check if id's are unique and correctly set. Same id's are necessary + # for the task runner. + if item.id != boefje_task.id or self.ctx.datastores.task_store.get_task(item.id): + new_id = uuid.uuid4() + boefje_task.id = new_id + item.id = new_id + item.data = boefje_task.model_dump() + + return super().push_item_to_queue(item) + + @tracer.start_as_current_span("boefje_has_boefje_permission_to_run") + def has_boefje_permission_to_run( + self, + boefje: Plugin, + ooi: OOI, + ) -> bool: """Checks whether a boefje is allowed to run on an ooi. Args: @@ -368,6 +667,21 @@ def is_task_allowed_to_run(self, boefje: Plugin, ooi: OOI) -> bool: ) return False + boefje_scan_level = boefje.scan_level + if boefje_scan_level is None: + self.logger.warning( + "No scan level found for boefje: %s", + boefje.id, + boefje_id=boefje.id, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + return False + + # We allow boefjes without an ooi to run. + if ooi is None: + return True + if ooi.scan_profile is None: self.logger.debug( "No scan_profile found for ooi: %s", @@ -389,17 +703,6 @@ def is_task_allowed_to_run(self, boefje: Plugin, ooi: OOI) -> bool: ) return False - boefje_scan_level = boefje.scan_level - if boefje_scan_level is None: - self.logger.warning( - "No scan level found for boefje: %s", - boefje.id, - boefje_id=boefje.id, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - ) - return False - # Boefje intensity score ooi clearance level, range # from 0 to 4. 4 being the highest intensity, and 0 being # the lowest. OOI clearance level defines what boefje @@ -420,8 +723,8 @@ def is_task_allowed_to_run(self, boefje: Plugin, ooi: OOI) -> bool: return True - @tracer.start_as_current_span("boefje_is_task_running") - def is_task_running(self, task: BoefjeTask) -> bool: + @tracer.start_as_current_span("boefje_has_boefje_task_started_running") + def has_boefje_task_started_running(self, task: BoefjeTask) -> bool: """Check if the same task is already running. Args: @@ -511,7 +814,7 @@ def is_task_running(self, task: BoefjeTask) -> bool: return False @tracer.start_as_current_span("boefje_is_task_stalled") - def is_task_stalled(self, task: BoefjeTask) -> bool: + def has_boefje_task_stalled(self, task: BoefjeTask) -> bool: """Check if the same task is stalled. Args: @@ -547,180 +850,8 @@ def is_task_stalled(self, task: BoefjeTask) -> bool: return False - @tracer.start_as_current_span("boefje_push_task") - def push_task(self, boefje: Plugin, ooi: OOI, caller: str = "") -> None: - """Given a Boefje and OOI create a BoefjeTask and push it onto - the queue. - - Args: - boefje: Boefje to run. - ooi: OOI to run Boefje on. - caller: The name of the function that called this function, used for logging. - - """ - task = BoefjeTask( - boefje=Boefje.parse_obj(boefje.dict()), - input_ooi=ooi.primary_key, - organization=self.organisation.id, - ) - - if not self.is_task_allowed_to_run(boefje, ooi): - self.logger.debug( - "Task is not allowed to run: %s", - task.id, - task_id=task.id, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - caller=caller, - ) - return - - try: - grace_period_passed = self.has_grace_period_passed(task) - if not grace_period_passed: - self.logger.debug( - "Task has not passed grace period: %s", - task.id, - task_id=task.id, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - caller=caller, - ) - return - except Exception as exc_grace_period: - self.logger.warning( - "Could not check if grace period has passed: %s", - task.id, - task_id=task.id, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - caller=caller, - exc_info=exc_grace_period, - ) - return - - try: - is_stalled = self.is_task_stalled(task) - if is_stalled: - self.logger.debug( - "Task is stalled: %s", - task.id, - task_id=task.id, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - caller=caller, - ) - - # Update task in datastore to be failed - task_db = self.ctx.datastores.task_store.get_latest_task_by_hash(task.hash) - task_db.status = TaskStatus.FAILED - self.ctx.datastores.task_store.update_task(task_db) - except Exception as exc_stalled: - self.logger.warning( - "Could not check if task is stalled: %s", - task.id, - task_id=task.id, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - caller=caller, - exc_info=exc_stalled, - ) - return - - try: - is_running = self.is_task_running(task) - if is_running: - self.logger.debug( - "Task is still running: %s", - task.id, - task_id=task.id, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - caller=caller, - ) - return - except Exception as exc_running: - self.logger.warning( - "Could not check if task is running: %s", - task.id, - task_id=task.id, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - caller=caller, - exc_info=exc_running, - ) - return - - try: - if self.is_item_on_queue_by_hash(task.hash): - self.logger.debug( - 'Task "%s" is already enqueued', - task.id, - task_id=task.id, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - caller=caller, - ) - return - except Exception: - self.logger.warning( - "Could not check if task is running: %s", - task.id, - task_id=task.id, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - caller=caller, - exc_info=True, - ) - return - - prior_tasks = self.ctx.datastores.task_store.get_tasks_by_hash(task.hash) - score = self.ranker.rank( - SimpleNamespace( - prior_tasks=prior_tasks, - task=task, - ) - ) - - # We need to create a PrioritizedItem for this task, to push - # it to the priority queue. - p_item = PrioritizedItem( - id=task.id, - scheduler_id=self.scheduler_id, - priority=score, - data=task.model_dump(), - hash=task.hash, - ) - - try: - self.push_item_to_queue_with_timeout(p_item, self.max_tries) - except queues.QueueFullError: - self.logger.warning( - "Could not add task to queue, queue was full: %s", - task.id, - task_id=task.id, - queue_qsize=self.queue.qsize(), - queue_maxsize=self.queue.maxsize, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - caller=caller, - ) - return - - self.logger.info( - "Created boefje task: %s for ooi: %s", - task.id, - ooi.primary_key, - task_id=task.id, - boefje_id=boefje.id, - ooi_primary_key=ooi.primary_key, - organisation_id=self.organisation.id, - scheduler_id=self.scheduler_id, - caller=caller, - ) - - @tracer.start_as_current_span("boefje_has_grace_period_passed") - def has_grace_period_passed(self, task: BoefjeTask) -> bool: + @tracer.start_as_current_span("boefje_has_boefje_task_grace_period_passed") + def has_boefje_task_grace_period_passed(self, task: BoefjeTask) -> bool: """Check if the grace period has passed for a task in both the datastore and bytes. diff --git a/mula/scheduler/schedulers/normalizer.py b/mula/scheduler/schedulers/normalizer.py index cc32f98572d..43ec0432f20 100644 --- a/mula/scheduler/schedulers/normalizer.py +++ b/mula/scheduler/schedulers/normalizer.py @@ -1,23 +1,16 @@ +import uuid from collections.abc import Callable from concurrent import futures from types import SimpleNamespace +from typing import Any import structlog from opentelemetry import trace -from scheduler import context, queues, rankers +from scheduler import context, models, queues, rankers from scheduler.connectors import listeners from scheduler.connectors.errors import ExternalServiceError -from scheduler.models import ( - Normalizer, - NormalizerTask, - Organisation, - Plugin, - PrioritizedItem, - RawData, - RawDataReceivedEvent, - TaskStatus, -) +from scheduler.models import Normalizer, NormalizerTask, Organisation, Plugin, RawDataReceivedEvent, Task, TaskStatus from .scheduler import Scheduler @@ -33,6 +26,8 @@ class NormalizerScheduler(Scheduler): organisation: The organisation that this scheduler is for. """ + ITEM_TYPE: Any = NormalizerTask + def __init__( self, ctx: context.AppContext, @@ -41,13 +36,14 @@ def __init__( queue: queues.PriorityQueue | None = None, callback: Callable[..., None] | None = None, ): - self.logger = structlog.getLogger(__name__) + self.logger: structlog.BoundLogger = structlog.getLogger(__name__) self.organisation: Organisation = organisation + self.create_schedule = False - self.queue = queue or queues.NormalizerPriorityQueue( + self.queue = queue or queues.PriorityQueue( pq_id=scheduler_id, maxsize=ctx.config.pq_maxsize, - item_type=NormalizerTask, + item_type=self.ITEM_TYPE, allow_priority_updates=True, pq_store=ctx.datastores.pq_store, ) @@ -131,7 +127,7 @@ def push_tasks_for_received_raw_data(self, body: bytes) -> None: return # Get all normalizers for the mime types of the raw data - normalizers: dict[str, Normalizer] = {} + normalizers: dict[str, Plugin] = {} for mime_type in latest_raw_data.raw_data.mime_types: normalizers_by_mime_type: list[Plugin] = self.get_normalizers_for_mime_type(mime_type.get("value")) @@ -151,15 +147,29 @@ def push_tasks_for_received_raw_data(self, body: bytes) -> None: thread_name_prefix=f"NormalizerScheduler-TPE-{self.scheduler_id}-raw_data" ) as executor: for normalizer in normalizers.values(): + if not self.has_normalizer_permission_to_run(normalizer): + self.logger.debug( + "Normalizer is not allowed to run: %s", + normalizer.id, + normalizer_id=normalizer.id, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + continue + + normalizer_task = NormalizerTask( + normalizer=Normalizer.parse_obj(normalizer.dict()), + raw_data=latest_raw_data.raw_data, + ) + executor.submit( - self.push_task, - normalizer, - latest_raw_data.raw_data, + self.push_normalizer_task, + normalizer_task, self.push_tasks_for_received_raw_data.__name__, ) @tracer.start_as_current_span("normalizer_push_task") - def push_task(self, normalizer: Plugin, raw_data: RawData, caller: str = "") -> None: + def push_normalizer_task(self, normalizer_task: models.NormalizerTask, caller: str = "") -> None: """Given a normalizer and raw data, create a task and push it to the queue. @@ -168,16 +178,24 @@ def push_task(self, normalizer: Plugin, raw_data: RawData, caller: str = "") -> raw_data: The raw data to create a task for. caller: The name of the function that called this function, used for logging. """ - task = NormalizerTask( - normalizer=Normalizer(id=normalizer.id), - raw_data=raw_data, + self.logger.debug( + "Pushing normalizer task", + task_id=normalizer_task.id, + normalizer_id=normalizer_task.normalizer.id, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, ) - if not self.is_task_allowed_to_run(normalizer): + plugin = self.ctx.services.katalogus.get_plugin_by_id_and_org_id( + normalizer_task.normalizer.id, + self.organisation.id, + ) + if not self.has_normalizer_permission_to_run(plugin): self.logger.debug( "Task is not allowed to run: %s", - task.id, - task_id=task.id, + normalizer_task.id, + task_id=normalizer_task.id, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, caller=caller, @@ -185,11 +203,11 @@ def push_task(self, normalizer: Plugin, raw_data: RawData, caller: str = "") -> return try: - if self.is_task_running(task): + if self.has_normalizer_task_started_running(normalizer_task): self.logger.debug( "Task is still running: %s", - task.id, - task_id=task.id, + normalizer_task.id, + task_id=normalizer_task.id, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, caller=caller, @@ -198,8 +216,8 @@ def push_task(self, normalizer: Plugin, raw_data: RawData, caller: str = "") -> except Exception: self.logger.warning( "Could not check if task is running: %s", - task.id, - task_id=task.id, + normalizer_task.id, + task_id=normalizer_task.id, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, caller=caller, @@ -207,11 +225,11 @@ def push_task(self, normalizer: Plugin, raw_data: RawData, caller: str = "") -> ) return - if self.is_item_on_queue_by_hash(task.hash): + if self.is_item_on_queue_by_hash(normalizer_task.hash): self.logger.debug( "Task is already on queue: %s", - task.id, - task_id=task.id, + normalizer_task.id, + task_id=normalizer_task.id, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, caller=caller, @@ -220,23 +238,22 @@ def push_task(self, normalizer: Plugin, raw_data: RawData, caller: str = "") -> score = self.ranker.rank( SimpleNamespace( - raw_data=raw_data, - task=task, + raw_data=normalizer_task.raw_data, + task=normalizer_task, ), ) - # We need to create a PrioritizedItem for this task, to - # push it to the priority queue. - p_item = PrioritizedItem( - id=task.id, + task = Task( + id=normalizer_task.id, scheduler_id=self.scheduler_id, + type=self.ITEM_TYPE.type, priority=score, - data=task.model_dump(), - hash=task.hash, + hash=normalizer_task.hash, + data=normalizer_task.model_dump(), ) try: - self.push_item_to_queue_with_timeout(p_item, self.max_tries) + self.push_item_to_queue_with_timeout(task, self.max_tries) except queues.QueueFullError: self.logger.warning( "Could not add task to queue, queue was full: %s", @@ -251,65 +268,36 @@ def push_task(self, normalizer: Plugin, raw_data: RawData, caller: str = "") -> return self.logger.info( - "Created normalizer task: %s for raw data: %s", - task.id, - raw_data.id, + "Created normalizer task", task_id=task.id, - normalizer_id=normalizer.id, - raw_data_id=raw_data.id, + task_hash=task.hash, + normalizer_id=normalizer_task.normalizer.id, + raw_data_id=normalizer_task.raw_data.id, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, caller=caller, ) - def get_normalizers_for_mime_type(self, mime_type: str) -> list[Plugin]: - """Get available normalizers for a given mime type. - - Args: - mime_type : The mime type to get normalizers for. + def push_item_to_queue(self, item: Task) -> Task: + """Some normalizer scheduler specific logic before pushing the item to the + queue.""" + normalizer_task = NormalizerTask.parse_obj(item.data) - Returns: - A list of normalizers for the given mime type. - """ - try: - normalizers = self.ctx.services.katalogus.get_normalizers_by_org_id_and_type( - self.organisation.id, - mime_type, - ) - except ExternalServiceError: - self.logger.warning( - "Could not get normalizers for mime_type: %s [mime_type=%s, organisation_id=%s, scheduler_id=%s]", - mime_type, - mime_type, - self.organisation.id, - self.scheduler_id, - ) - return [] + # Check if id's are unique and correctly set. Same id's are necessary + # for the task runner. + if item.id != normalizer_task.id or self.ctx.datastores.task_store.get_task(item.id): + new_id = uuid.uuid4() + normalizer_task.id = new_id + item.id = new_id + item.data = normalizer_task.model_dump() - if normalizers is None: - self.logger.debug( - "No normalizer found for mime_type: %s [mime_type=%s, organisation_id=%s, scheduler_id=%s]", - mime_type, - mime_type, - self.organisation.id, - self.scheduler_id, - ) - return [] + return super().push_item_to_queue(item) - self.logger.debug( - "Found %d normalizers for mime_type: %s", - len(normalizers), - mime_type, - mime_type=mime_type, - normalizers=[normalizer.id for normalizer in normalizers], - organisation=self.organisation.id, - scheduler_id=self.scheduler_id, - ) - - return normalizers - - @tracer.start_as_current_span("normalizer_is_task_allowed_to_run") - def is_task_allowed_to_run(self, normalizer: Plugin) -> bool: + @tracer.start_as_current_span("normalizer_has_normalizer_permission_to_run") + def has_normalizer_permission_to_run( + self, + normalizer: Plugin, + ) -> bool: """Check if the task is allowed to run. Args: @@ -330,8 +318,8 @@ def is_task_allowed_to_run(self, normalizer: Plugin) -> bool: return True - @tracer.start_as_current_span("normalizer_is_task_running") - def is_task_running(self, task: NormalizerTask) -> bool: + @tracer.start_as_current_span("normalizer_has_normalizer_task_started_running") + def has_normalizer_task_started_running(self, task: NormalizerTask) -> bool: """Check if the same task is already running. Args: @@ -361,13 +349,58 @@ def is_task_running(self, task: NormalizerTask) -> bool: TaskStatus.FAILED, ]: self.logger.debug( - "Task is still running, according to the datastore " - "[task_id=%s, task_hash=%s, organisation_id=%s, scheduler_id=%s]", - task_db.id, - task.hash, - self.organisation.id, - self.scheduler_id, + "Task is still running, according to the datastore", + task_id=task_db.id, + task_hash=task.hash, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, ) return True return False + + def get_normalizers_for_mime_type(self, mime_type: str) -> list[Plugin]: + """Get available normalizers for a given mime type. + + Args: + mime_type : The mime type to get normalizers for. + + Returns: + A list of Plugins of type normalizer for the given mime type. + """ + try: + normalizers = self.ctx.services.katalogus.get_normalizers_by_org_id_and_type( + self.organisation.id, + mime_type, + ) + except ExternalServiceError: + self.logger.warning( + "Could not get normalizers for mime_type: %s [mime_type=%s, organisation_id=%s, scheduler_id=%s]", + mime_type, + mime_type, + self.organisation.id, + self.scheduler_id, + ) + return [] + + if normalizers is None: + self.logger.debug( + "No normalizer found for mime_type: %s", + mime_type, + mime_type=mime_type, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + return [] + + self.logger.debug( + "Found %d normalizers for mime_type: %s", + len(normalizers), + mime_type, + mime_type=mime_type, + normalizers=[normalizer.id for normalizer in normalizers], + organisation_=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + + return normalizers diff --git a/mula/scheduler/schedulers/scheduler.py b/mula/scheduler/schedulers/scheduler.py index db9fd04fcc9..90c535b328f 100644 --- a/mula/scheduler/schedulers/scheduler.py +++ b/mula/scheduler/schedulers/scheduler.py @@ -1,15 +1,16 @@ import abc +import random import threading import time from collections.abc import Callable -from datetime import datetime, timezone +from datetime import datetime, timedelta, timezone from typing import Any import structlog from opentelemetry import trace from scheduler import connectors, context, models, queues, storage, utils -from scheduler.utils import thread +from scheduler.utils import cron, thread tracer = trace.get_tracer(__name__) @@ -24,29 +25,42 @@ class Scheduler(abc.ABC): ctx: Application context of shared data (e.g. configuration, external services connections). - enabled: - Whether the scheduler is enabled or not. - scheduler_id: - The id of the scheduler. queue: A queues.PriorityQueue instance - threads: - A dict of ThreadRunner instances, used for running processes - concurrently. - stop_event: A threading.Event object used for communicating a stop - event across threads. + callback: + A callback function to call when the scheduler is stopped. + scheduler_id: + The id of the scheduler. + max_tries: + The maximum number of retries for an item to be pushed to + the queue. + enabled: + Whether the scheduler is enabled or not. + _last_activity: + The last activity of the scheduler. listeners: A dict of connector.Listener instances, used for listening to external events. + lock: + A threading.Lock instance used for locking + stop_event_threads: + A threading.Event object used for communicating a stop + event across threads. + threads: + A dict of ThreadRunner instances, used for running processes + concurrently. """ + ITEM_TYPE: Any = None + def __init__( self, ctx: context.AppContext, scheduler_id: str, - queue: queues.PriorityQueue, + queue: queues.PriorityQueue | None = None, callback: Callable[..., None] | None = None, max_tries: int = -1, + create_schedule: bool = False, ): """Initialize the Scheduler. @@ -58,22 +72,32 @@ def __init__( The id of the scheduler. queue: A queues.PriorityQueue instance - ranker: - A rankers.Ranker instance. + callback: + A callback function to call when the scheduler is stopped. max_tries: - The maximum number of retries for a task to be pushed to + The maximum number of retries for an item to be pushed to the queue. """ self.logger: structlog.BoundLogger = structlog.getLogger(__name__) self.ctx: context.AppContext = ctx - self.enabled: bool = True + self.callback: Callable[[], Any] | None = callback + + # Properties self.scheduler_id: str = scheduler_id - self.queue: queues.PriorityQueue = queue self.max_tries: int = max_tries - self.callback: Callable[[], Any] | None = callback + self.enabled: bool = True + self.create_schedule: bool = create_schedule self._last_activity: datetime | None = None + # Queue + self.queue = queue or queues.PriorityQueue( + pq_id=scheduler_id, + maxsize=self.ctx.config.pq_maxsize, + item_type=self.ITEM_TYPE, + pq_store=self.ctx.datastores.pq_store, + ) + # Listeners self.listeners: dict[str, connectors.listeners.Listener] = {} @@ -86,147 +110,157 @@ def __init__( def run(self) -> None: raise NotImplementedError - def post_push(self, p_item: models.PrioritizedItem) -> None: - """When a boefje task is being added to the queue. We - persist a task to the datastore with the status QUEUED. + def run_in_thread( + self, + name: str, + target: Callable[[], Any], + interval: float = 0.01, + daemon: bool = False, + loop: bool = True, + ) -> None: + """Make a function run in a thread, and add it to the dict of threads. Args: - p_item: The prioritized item from the priority queue. + name: The name of the thread. + target: The function to run in the thread. + interval: The interval to run the function. + daemon: Whether the thread should be a daemon. + loop: Whether the thread should loop. """ - # NOTE: we set the id of the task the same as the p_item, for easier - # lookup. - task = models.Task( - id=p_item.id, - scheduler_id=self.scheduler_id, - type=self.queue.item_type.type, - p_item=p_item, - status=models.TaskStatus.QUEUED, - created_at=datetime.now(timezone.utc), - modified_at=datetime.now(timezone.utc), + t = utils.ThreadRunner( + name=name, + target=target, + stop_event=self.stop_event_threads, + interval=interval, + daemon=daemon, + loop=loop, ) + t.start() - task_db = self.ctx.datastores.task_store.get_task(str(p_item.id)) - if task_db is not None: - self.ctx.datastores.task_store.update_task(task) - return - - self.ctx.datastores.task_store.create_task(task) - - self.last_activity = datetime.now(timezone.utc) + self.threads.append(t) - def post_pop(self, p_item: models.PrioritizedItem) -> None: - """When a boefje task is being removed from the queue. We - persist a task to the datastore with the status RUNNING + def push_items_to_queue(self, items: list[models.Task]) -> None: + """Push multiple items to the queue. Args: - p_item: The prioritized item from the priority queue. + items: A list of items to push to the queue. """ - # NOTE: we set the id of the task the same as the p_item, for easier - # lookup. - task = self.ctx.datastores.task_store.get_task(str(p_item.id)) - if task is None: - self.logger.warning( - "PrioritizedItem %s popped from %s, task %s not found in datastore, could not update task status", - p_item.id, - self.queue.pq_id, - p_item.data.get("id"), - p_item_id=p_item.id, - task_id=p_item.data.get("id"), - queue_id=self.queue.pq_id, - scheduler_id=self.scheduler_id, - ) - return - - task.status = models.TaskStatus.DISPATCHED - self.ctx.datastores.task_store.update_task(task) + count = 0 + for item in items: + try: + self.push_item_to_queue(item) + except ( + queues.errors.NotAllowedError, + queues.errors.QueueFullError, + queues.errors.InvalidItemError, + ) as exc: + self.logger.debug( + "Unable to push item %s to queue %s (%s)", + item.id, + self.queue.pq_id, + exc, + item_id=item.id, + queue_id=self.queue.pq_id, + scheduler_id=self.scheduler_id, + ) + continue + except Exception as exc: + self.logger.error( + "Unable to push item %s to queue %s", + item.id, + self.queue.pq_id, + item_id=item.id, + queue_id=self.queue.pq_id, + scheduler_id=self.scheduler_id, + ) + raise exc - self.last_activity = datetime.now(timezone.utc) + count += 1 - @tracer.start_as_current_span("scheduler_pop_item_from_queue") - def pop_item_from_queue( - self, filters: storage.filters.FilterRequest | None = None - ) -> models.PrioritizedItem | None: - """Pop an item from the queue. + def push_item_to_queue_with_timeout( + self, + item: models.Task, + max_tries: int = 5, + timeout: int = 1, + ) -> None: + """Push an item to the queue, with a timeout. Args: - filters: A FilterRequest instance to filter the - prioritized items from the queue. + item: The item to push to the queue. + timeout: The timeout in seconds. + max_tries: The maximum number of tries. Set to -1 for infinite tries. - Returns: - A PrioritizedItem instance. + Raises: + QueueFullError: When the queue is full. """ - if not self.is_enabled(): - self.logger.warning( - "Scheduler is disabled, not popping item from queue", - queue_id=self.queue.pq_id, - queue_qsize=self.queue.qsize(), - scheduler_id=self.scheduler_id, - ) - raise queues.errors.NotAllowedError("Scheduler is disabled") - - try: - p_item = self.queue.pop(filters) - except queues.QueueEmptyError as exc: - raise exc - - if p_item is not None: + tries = 0 + while not self.is_space_on_queue() and (tries < max_tries or max_tries == -1): self.logger.debug( - "Popped item %s from queue %s with priority %s", - p_item.id, - self.queue.pq_id, - p_item.priority, - p_item_id=p_item.id, + "Queue %s is full, waiting for space", queue_id=self.queue.pq_id, + queue_qsize=self.queue.qsize(), scheduler_id=self.scheduler_id, ) + time.sleep(timeout) + tries += 1 - self.post_pop(p_item) + if tries >= max_tries and max_tries != -1: + raise queues.errors.QueueFullError() - return p_item + self.push_item_to_queue(item) - @tracer.start_as_current_span("scheduler_push_item_to_queue") - def push_item_to_queue(self, p_item: models.PrioritizedItem) -> None: - """Push a PrioritizedItem to the queue. + def push_item_to_queue(self, item: models.Task) -> models.Task: + """Push a Task to the queue. Args: - p_item: The PrioritizedItem to push to the queue. + item: The item to push to the queue. + + Raises: + NotAllowedError: When the scheduler is disabled. + QueueFullError: When the queue is full. + InvalidItemError: When the item is invalid. """ if not self.is_enabled(): self.logger.warning( "Scheduler is disabled, not pushing item to queue %s", self.queue.pq_id, - p_item_id=p_item.id, + item_id=item.id, queue_id=self.queue.pq_id, scheduler_id=self.scheduler_id, ) raise queues.errors.NotAllowedError("Scheduler is disabled") try: - self.queue.push(p_item) + if item.type is None: + item.type = self.ITEM_TYPE.type + item.status = models.TaskStatus.QUEUED + item = self.queue.push(item) except queues.errors.NotAllowedError as exc: self.logger.warning( - "Not allowed to push to queue %s", + "Not allowed to push to queue %s (%s)", self.queue.pq_id, - p_item_id=p_item.id, + exc, + item_id=item.id, queue_id=self.queue.pq_id, scheduler_id=self.scheduler_id, ) raise exc except queues.errors.QueueFullError as exc: self.logger.warning( - "Queue %s is full, not pushing new items", + "Queue %s is full, not pushing new items (%s)", self.queue.pq_id, - p_item_id=p_item.id, + exc, + item_id=item.id, queue_id=self.queue.pq_id, queue_qsize=self.queue.qsize(), scheduler_id=self.scheduler_id, ) raise exc - except queues.errors.InvalidPrioritizedItemError as exc: + except queues.errors.InvalidItemError as exc: self.logger.warning( - "Invalid prioritized item %s", - p_item.id, - p_item_id=p_item.id, + "Invalid item %s", + item.id, + item_id=item.id, queue_id=self.queue.pq_id, queue_qsize=self.queue.qsize(), scheduler_id=self.scheduler_id, @@ -235,129 +269,178 @@ def push_item_to_queue(self, p_item: models.PrioritizedItem) -> None: self.logger.debug( "Pushed item %s to queue %s with priority %s ", - p_item.id, + item.id, self.queue.pq_id, - p_item.priority, - p_item_id=p_item.id, + item.priority, + item_id=item.id, + item_hash=item.hash, queue_id=self.queue.pq_id, scheduler_id=self.scheduler_id, ) - self.post_push(p_item) + item = self.post_push(item) + + return item - def push_items_to_queue(self, p_items: list[models.PrioritizedItem]) -> None: - """Push multiple PrioritizedItems to the queue. + def post_push(self, item: models.Task) -> models.Task: + """After an in item is pushed to the queue, we execute this function Args: - p_items: The list PrioritzedItem to add to the queue. + item: The item from the priority queue. """ - count = 0 - for p_item in p_items: - try: - self.push_item_to_queue(p_item) - except ( - queues.errors.NotAllowedError, - queues.errors.QueueFullError, - queues.errors.InvalidPrioritizedItemError, - ): - self.logger.debug( - "Unable to push item %s to queue %s", - p_item.id, - self.queue.pq_id, - p_item_id=p_item.id, - queue_id=self.queue.pq_id, - scheduler_id=self.scheduler_id, - ) - continue - except Exception as exc: - self.logger.error( - "Unable to push item %s to queue %s", - p_item.id, - self.queue.pq_id, - p_item_id=p_item.id, - queue_id=self.queue.pq_id, + self.last_activity = datetime.now(timezone.utc) + + if self.create_schedule is False: + self.logger.debug( + "Not creating schedule for item %s", + item.id, + item_id=item.id, + queue_id=self.queue.pq_id, + scheduler_id=self.scheduler_id, + ) + return item + + schedule_db = None + if item.schedule_id is None: + schedule_db = self.ctx.datastores.schedule_store.get_schedule_by_hash(item.hash) + if schedule_db is None: + deadline_at = self.calculate_deadline(item) + cron_expression = f"{deadline_at.minute} {deadline_at.hour} * * *" + + schedule = models.Schedule( scheduler_id=self.scheduler_id, + hash=item.hash, + schedule=cron_expression, + deadline_at=deadline_at, + data=item.data, ) - raise exc + schedule_db = self.ctx.datastores.schedule_store.create_schedule(schedule) + item.schedule_id = schedule_db.id + self.ctx.datastores.task_store.update_task(item) + return item + + item.schedule_id = schedule_db.id + self.ctx.datastores.task_store.update_task(item) + else: + schedule_db = self.ctx.datastores.schedule_store.get_schedule(item.schedule_id) + if schedule_db is None: + raise ValueError(f"Schedule with id {item.schedule_id} not found for item {item.id}") + + if not schedule_db.enabled: + self.logger.debug( + "Schedule %s is disabled, not updating deadline", + schedule_db.id, + schedule_id=schedule_db.id, + item_id=item.id, + queue_id=self.queue.pq_id, + scheduler_id=self.scheduler_id, + ) + return item - count += 1 + schedule_db.deadline_at = cron.next_run(schedule_db.schedule) + self.ctx.datastores.schedule_store.update_schedule(schedule_db) - def push_item_to_queue_with_timeout( - self, - p_item: models.PrioritizedItem, - max_tries: int = 5, - timeout: int = 1, - ) -> None: - """Push an item to the queue, with a timeout. + return item + + def pop_item_from_queue(self, filters: storage.filters.FilterRequest | None = None) -> models.Task | None: + """Pop an item from the queue. Args: - p_item: The item to push to the queue. - timeout: The timeout in seconds. - max_tries: The maximum number of tries. Set to -1 for infinite tries. + filters: Optional filters to apply when popping an item. + + Returns: + An item from the queue Raises: - QueueFullError: When the queue is full. + NotAllowedError: When the scheduler is disabled. + QueueEmptyError: When the queue is empty. """ - tries = 0 - while not self.is_space_on_queue() and (tries < max_tries or max_tries == -1): - self.logger.debug( - "Queue %s is full, waiting for space", + if not self.is_enabled(): + self.logger.warning( + "Scheduler is disabled, not popping item from queue", queue_id=self.queue.pq_id, queue_qsize=self.queue.qsize(), scheduler_id=self.scheduler_id, ) - time.sleep(timeout) - tries += 1 + raise queues.errors.NotAllowedError("Scheduler is disabled") - if tries >= max_tries and max_tries != -1: - raise queues.errors.QueueFullError() + try: + item = self.queue.pop(filters) + except queues.QueueEmptyError as exc: + raise exc - self.push_item_to_queue(p_item) + if item is not None: + self.logger.debug( + "Popped item %s from queue %s with priority %s", + item.id, + self.queue.pq_id, + item.priority, + item_id=item.id, + queue_id=self.queue.pq_id, + scheduler_id=self.scheduler_id, + ) - def run_in_thread( - self, - name: str, - target: Callable[[], Any], - interval: float = 0.01, - daemon: bool = False, - loop: bool = True, - ) -> None: - """Make a function run in a thread, and add it to the dict of threads. + self.post_pop(item) + + return item + + def post_pop(self, item: models.Task) -> None: + """After an item is popped from the queue, we execute this function Args: - name: The name of the thread. - target: The function to run in the thread. - interval: The interval to run the function. - daemon: Whether the thread should be a daemon. - loop: Whether the thread should loop. + item: An item from the queue """ - t = utils.ThreadRunner( - name=name, - target=target, - stop_event=self.stop_event_threads, - interval=interval, - daemon=daemon, - loop=loop, - ) - t.start() + self.last_activity = datetime.now(timezone.utc) - self.threads.append(t) + def calculate_deadline(self, task: models.Task) -> datetime: + """Calculate the deadline for a task. - def is_space_on_queue(self) -> bool: - """Check if there is space on the queue. + NOTE: This is a simple implementation, you can override this method + to implement a more complex logic. - NOTE: maxsize 0 means unlimited + Args: + task: The task to calculate the deadline for. Returns: - True if there is space on the queue, False otherwise. + The deadline for the task. """ - if (self.queue.maxsize - self.queue.qsize()) <= 0 and self.queue.maxsize != 0: - return False + # We at least delay a job by the grace period + minimum = self.ctx.config.pq_grace_period + deadline = datetime.now(timezone.utc) + timedelta(seconds=minimum) - return True + # We want to delay the job by a random amount of time, in a range of 5 hours + jitter_range_seconds = 5 * 60 * 60 + jitter = timedelta(seconds=random.uniform(0, jitter_range_seconds)) # noqa - def is_item_on_queue_by_hash(self, item_hash: str) -> bool: - return self.queue.is_item_on_queue_by_hash(item_hash) + # Check if the adjusted time is earlier than the minimum, and + # ensure that the adjusted time is not earlier than the deadline + adjusted_time = deadline + jitter + + return adjusted_time + + def enable(self) -> None: + """Enable the scheduler. + + This will start the scheduler, and start all listeners and threads. + """ + if self.is_enabled(): + self.logger.debug("Scheduler is already enabled") + return + + self.logger.info( + "Enabling scheduler: %s", + self.scheduler_id, + scheduler_id=self.scheduler_id, + ) + self.enabled = True + self.stop_event_threads.clear() + self.run() + + self.logger.info( + "Enabled scheduler: %s", + self.scheduler_id, + scheduler_id=self.scheduler_id, + ) def disable(self) -> None: """Disable the scheduler. @@ -378,7 +461,6 @@ def disable(self) -> None: self.stop_listeners() self.stop_threads() - self.queue.clear() # Get all tasks that were on the queue and set them to CANCELLED @@ -389,33 +471,11 @@ def disable(self) -> None: task_ids = [task.id for task in tasks] self.ctx.datastores.task_store.cancel_tasks(scheduler_id=self.scheduler_id, task_ids=task_ids) - self.logger.info("Disabled scheduler: %s", self.scheduler_id, scheduler_id=self.scheduler_id) - - def enable(self) -> None: - """Enable the scheduler. - - This will start the scheduler, and start all listeners and threads. - """ - if self.is_enabled(): - self.logger.debug("Scheduler is already enabled") - return - - self.logger.info("Enabling scheduler: %s", self.scheduler_id, scheduler_id=self.scheduler_id) - self.enabled = True - - self.stop_event_threads.clear() - - self.run() - - self.logger.info("Enabled scheduler: %s", self.scheduler_id, scheduler_id=self.scheduler_id) - - def is_enabled(self) -> bool: - """Check if the scheduler is enabled. - - Returns: - True if the scheduler is enabled, False otherwise. - """ - return self.enabled + self.logger.info( + "Disabled scheduler: %s", + self.scheduler_id, + scheduler_id=self.scheduler_id, + ) def stop(self, callback: bool = True) -> None: """Stop the scheduler. @@ -423,7 +483,11 @@ def stop(self, callback: bool = True) -> None: Args: callback: Whether to call the callback function. """ - self.logger.info("Stopping scheduler: %s", self.scheduler_id, scheduler_id=self.scheduler_id) + self.logger.info( + "Stopping scheduler: %s", + self.scheduler_id, + scheduler_id=self.scheduler_id, + ) # First, stop the listeners, when those are running in a thread and # they're using rabbitmq, they will block. Setting the stop event @@ -434,7 +498,11 @@ def stop(self, callback: bool = True) -> None: if self.callback and callback: self.callback(self.scheduler_id) # type: ignore [call-arg] - self.logger.info("Stopped scheduler: %s", self.scheduler_id, scheduler_id=self.scheduler_id) + self.logger.info( + "Stopped scheduler: %s", + self.scheduler_id, + scheduler_id=self.scheduler_id, + ) def stop_listeners(self) -> None: """Stop the listeners.""" @@ -450,6 +518,30 @@ def stop_threads(self) -> None: self.threads = [] + def is_enabled(self) -> bool: + """Check if the scheduler is enabled. + + Returns: + True if the scheduler is enabled, False otherwise. + """ + return self.enabled + + def is_space_on_queue(self) -> bool: + """Check if there is space on the queue. + + NOTE: maxsize 0 means unlimited + + Returns: + True if there is space on the queue, False otherwise. + """ + if (self.queue.maxsize - self.queue.qsize()) <= 0 and self.queue.maxsize != 0: + return False + + return True + + def is_item_on_queue_by_hash(self, item_hash: str) -> bool: + return self.queue.is_item_on_queue_by_hash(item_hash) + @property def last_activity(self) -> datetime | None: """Get the last activity of the scheduler.""" diff --git a/mula/scheduler/server/handlers/__init__.py b/mula/scheduler/server/handlers/__init__.py index e28364f102a..302806efaa3 100644 --- a/mula/scheduler/server/handlers/__init__.py +++ b/mula/scheduler/server/handlers/__init__.py @@ -3,4 +3,5 @@ from .queues import QueueAPI from .root import RootAPI from .schedulers import SchedulerAPI +from .schedules import ScheduleAPI from .tasks import TaskAPI diff --git a/mula/scheduler/server/handlers/queues.py b/mula/scheduler/server/handlers/queues.py index 8608d56d656..a9a89d83c16 100644 --- a/mula/scheduler/server/handlers/queues.py +++ b/mula/scheduler/server/handlers/queues.py @@ -43,7 +43,7 @@ def __init__( path="/queues/{queue_id}/pop", endpoint=self.pop, methods=["POST"], - response_model=models.PrioritizedItem | None, + response_model=models.Task | None, status_code=status.HTTP_200_OK, description="Pop an item from a queue", ) @@ -52,7 +52,7 @@ def __init__( path="/queues/{queue_id}/push", endpoint=self.push, methods=["POST"], - response_model=models.PrioritizedItem | None, + response_model=models.Task | None, status_code=status.HTTP_201_CREATED, description="Push an item to a queue", ) @@ -96,9 +96,9 @@ def pop(self, queue_id: str, filters: storage.filters.FilterRequest | None = Non detail="could not pop item from queue, check your filters", ) - return models.PrioritizedItem(**p_item.model_dump()) + return models.Task(**p_item.model_dump()) - def push(self, queue_id: str, item: serializers.PrioritizedItem) -> Any: + def push(self, queue_id: str, item_in: serializers.Task) -> Any: s = self.schedulers.get(queue_id) if s is None: raise fastapi.HTTPException( @@ -108,22 +108,11 @@ def push(self, queue_id: str, item: serializers.PrioritizedItem) -> Any: try: # Load default values - p_item = models.PrioritizedItem() + new_item = models.Task(**item_in.model_dump(exclude_unset=True)) # Set values - if p_item.scheduler_id is None: - p_item.scheduler_id = s.scheduler_id - - p_item.priority = item.priority - - if s.queue.item_type == models.BoefjeTask: - p_item.data = models.BoefjeTask(**item.data).dict() - p_item.id = p_item.data["id"] - elif s.queue.item_type == models.NormalizerTask: - p_item.data = models.NormalizerTask(**item.data).dict() - p_item.id = p_item.data["id"] - else: - p_item.data = item.data + if new_item.scheduler_id is None: + new_item.scheduler_id = s.scheduler_id except Exception as exc: self.logger.exception(exc) raise fastapi.HTTPException( @@ -132,11 +121,11 @@ def push(self, queue_id: str, item: serializers.PrioritizedItem) -> Any: ) from exc try: - s.push_item_to_queue(p_item) + pushed_item = s.push_item_to_queue(new_item) except ValueError as exc_value: raise fastapi.HTTPException( status_code=fastapi.status.HTTP_400_BAD_REQUEST, - detail="malformed item", + detail=f"malformed item: {exc_value}", ) from exc_value except queues.QueueFullError as exc_full: raise fastapi.HTTPException( @@ -149,5 +138,11 @@ def push(self, queue_id: str, item: serializers.PrioritizedItem) -> Any: status_code=fastapi.status.HTTP_409_CONFLICT, detail=str(exc_not_allowed), ) from exc_not_allowed + except Exception as exc: + self.logger.exception(exc) + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=str(exc), + ) from exc - return p_item + return pushed_item diff --git a/mula/scheduler/server/handlers/schedules.py b/mula/scheduler/server/handlers/schedules.py new file mode 100644 index 00000000000..5b4d175386e --- /dev/null +++ b/mula/scheduler/server/handlers/schedules.py @@ -0,0 +1,184 @@ +import datetime +import uuid +from typing import Any + +import fastapi +import pydantic +import structlog + +from scheduler import context, models, storage +from scheduler.server import serializers, utils + + +class ScheduleAPI: + def __init__(self, api: fastapi.FastAPI, ctx: context.AppContext) -> None: + self.logger: structlog.BoundLogger = structlog.getLogger(__name__) + self.api = api + self.ctx = ctx + + self.api.add_api_route( + path="/schedules", + endpoint=self.list, + methods=["GET", "POST"], + response_model=utils.PaginatedResponse, + status_code=200, + description="List all schedules", + ) + + self.api.add_api_route( + path="/schedules/{schedule_id}", + endpoint=self.get, + methods=["GET"], + response_model=models.Schedule, + status_code=200, + description="Get a schedule", + ) + + self.api.add_api_route( + path="/schedules/{schedule_id}", + endpoint=self.patch, + methods=["PATCH"], + response_model=models.Schedule, + response_model_exclude_unset=True, + status_code=200, + description="Update a schedule", + ) + + def list( + self, + request: fastapi.Request, + schedule_hash: str | None = None, + enabled: bool | None = True, + offset: int = 0, + limit: int = 10, + min_deadline_at: datetime.datetime | None = None, + max_deadline_at: datetime.datetime | None = None, + min_created_at: datetime.datetime | None = None, + max_created_at: datetime.datetime | None = None, + ) -> Any: + if (min_created_at is not None and max_created_at is not None) and min_created_at > max_created_at: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_400_BAD_REQUEST, + detail="min_created_at must be less than max_created_at", + ) + + if (min_deadline_at is not None and max_deadline_at is not None) and min_deadline_at > max_deadline_at: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_400_BAD_REQUEST, + detail="min_deadline_at must be less than max_deadline_at", + ) + + try: + results, count = self.ctx.datastores.schedule_store.get_schedules( + schedule_hash=schedule_hash, + enabled=enabled, + min_deadline_at=min_deadline_at, + max_deadline_at=max_deadline_at, + min_created_at=min_created_at, + max_created_at=max_created_at, + offset=offset, + limit=limit, + ) + except storage.filters.errors.FilterError as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_400_BAD_REQUEST, + detail=f"invalid filter(s) [exception: {exc}]", + ) from exc + except storage.errors.StorageError as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"error occurred while accessing the database [exception: {exc}]", + ) from exc + except Exception as exc: + self.logger.exception(exc) + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="failed to get schedules", + ) from exc + + return utils.paginate(request, results, count, offset, limit) + + def get(self, schedule_id: uuid.UUID) -> Any: + try: + schedule = self.ctx.datastores.schedule_store.get_schedule(schedule_id) + except storage.errors.StorageError as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"error occurred while accessing the database [exception: {exc}]", + ) from exc + except Exception as exc: + self.logger.exception(exc) + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"failed to get schedule [exception: {exc}]", + ) from exc + + if schedule is None: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_404_NOT_FOUND, + detail="schedule not found", + ) + + return schedule + + def patch(self, schedule_id: uuid.UUID, schedule: serializers.Schedule) -> Any: + try: + schedule_db = self.ctx.datastores.schedule_store.get_schedule(schedule_id) + except storage.errors.StorageError as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"error occurred while accessing the database [exception: {exc}]", + ) from exc + except Exception as exc: + self.logger.exception(exc) + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"failed to get schedule [exception: {exc}]", + ) from exc + + if schedule_db is None: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_404_NOT_FOUND, + detail="schedule not found", + ) + + patch_data = schedule.model_dump(exclude_unset=True) + if len(patch_data) == 0: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_400_BAD_REQUEST, + detail="no data to patch", + ) + + # Update schedule + updated_schedule = schedule_db.model_copy(update=patch_data) + + # Validate schedule, model_copy() does not validate the model + try: + models.Schedule(**updated_schedule.dict()) + except pydantic.ValidationError as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_400_BAD_REQUEST, + detail=f"invalid schedule [exception: {exc}]", + ) from exc + except Exception as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_400_BAD_REQUEST, + detail=f"failed to update schedule [exception: {exc}]", + ) from exc + + # Update schedule in database + try: + self.ctx.datastores.schedule_store.update_schedule(updated_schedule) + except storage.errors.StorageError as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"error occurred while accessing the database [exception: {exc}]", + ) from exc + except Exception as exc: + self.logger.exception(exc) + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"failed to update schedule [exception: {exc}]", + ) from exc + + return updated_schedule diff --git a/mula/scheduler/server/handlers/tasks.py b/mula/scheduler/server/handlers/tasks.py index 7846b92099e..db3391dc2d6 100644 --- a/mula/scheduler/server/handlers/tasks.py +++ b/mula/scheduler/server/handlers/tasks.py @@ -88,8 +88,8 @@ def list( f_ooi = { "and": [ storage.filters.Filter( - column="p_item", - field="data__input_ooi", + column="data", + field="input_ooi", operator="eq", value=input_ooi, ) @@ -99,8 +99,8 @@ def list( f_ooi = { "and": [ storage.filters.Filter( - column="p_item", - field="data__raw_data__boefje_meta__input_ooi", + column="data", + field="raw_data__boefje_meta__input_ooi", operator="eq", value=input_ooi, ) @@ -110,14 +110,14 @@ def list( f_ooi = { "or": [ storage.filters.Filter( - column="p_item", - field="data__input_ooi", + column="data", + field="input_ooi", operator="eq", value=input_ooi, ), storage.filters.Filter( - column="p_item", - field="data__raw_data__boefje_meta__input_ooi", + column="data", + field="raw_data__boefje_meta__input_ooi", operator="eq", value=input_ooi, ), @@ -131,8 +131,8 @@ def list( f_plugin = { "and": [ storage.filters.Filter( - column="p_item", - field="data__boefje__id", + column="data", + field="boefje__id", operator="eq", value=plugin_id, ) @@ -140,8 +140,8 @@ def list( } elif task_type == "normalizer": f_plugin = storage.filters.Filter( - column="p_item", - field="data_normalizer__id", + column="data", + field="normalizer__id", operator="eq", value=plugin_id, ) @@ -149,14 +149,14 @@ def list( f_plugin = { "or": [ storage.filters.Filter( - column="p_item", - field="data_boefje__id", + column="data", + field="boefje__id", operator="eq", value=plugin_id, ), storage.filters.Filter( - column="p_item", - field="data_normalizer__id", + column="data", + field="normalizer__id", operator="eq", value=plugin_id, ), @@ -218,8 +218,6 @@ def get(self, task_id: uuid.UUID) -> Any: return task - # NOTE: serializers.Task instead of models.Task is needed for patch - # endpoints # to allow for partial updates. def patch(self, task_id: uuid.UUID, item: serializers.Task) -> Any: try: task_db = self.ctx.datastores.task_store.get_task(task_id) @@ -248,9 +246,9 @@ def patch(self, task_id: uuid.UUID, item: serializers.Task) -> Any: detail="no data to patch", ) + # Update task updated_task = task_db.model_copy(update=patch_data) - # Update task in database try: self.ctx.datastores.task_store.update_task(updated_task) except storage.errors.StorageError as exc: diff --git a/mula/scheduler/server/pagination.py b/mula/scheduler/server/pagination.py deleted file mode 100644 index 3659c49a860..00000000000 --- a/mula/scheduler/server/pagination.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Any - -from fastapi import Request -from pydantic import BaseModel - - -class PaginatedResponse(BaseModel): - count: int - next: str | None - previous: str | None - results: list[Any] - - -def create_next_url(request: Request, offset: int, limit: int, count: int) -> str | None: - if offset + limit <= count: - return str(request.url.include_query_params(limit=limit, offset=offset + limit)) - - return None - - -def create_previous_url(request: Request, offset: int, limit: int) -> str | None: - if offset - limit >= 0: - return str(request.url.include_query_params(limit=limit, offset=offset - limit)) - - return None - - -def paginate(request: Request, items: list[Any], count: int, offset: int, limit: int) -> PaginatedResponse: - return PaginatedResponse( - count=count, - next=create_next_url(request, offset, limit, count), - previous=create_previous_url(request, offset, limit), - results=items, - ) diff --git a/mula/scheduler/server/serializers/__init__.py b/mula/scheduler/server/serializers/__init__.py index 6e405534bc6..95ce4c26876 100644 --- a/mula/scheduler/server/serializers/__init__.py +++ b/mula/scheduler/server/serializers/__init__.py @@ -1,2 +1,2 @@ -from .p_item import PrioritizedItem +from .schedule import Schedule from .task import Task, TaskStatus diff --git a/mula/scheduler/server/serializers/p_item.py b/mula/scheduler/server/serializers/p_item.py deleted file mode 100644 index 457ae2f4458..00000000000 --- a/mula/scheduler/server/serializers/p_item.py +++ /dev/null @@ -1,8 +0,0 @@ -from pydantic import BaseModel, Field - - -class PrioritizedItem(BaseModel): - """Request model for prioritized items used in the server.""" - - priority: int - data: dict = Field(default_factory=dict) diff --git a/mula/scheduler/server/serializers/schedule.py b/mula/scheduler/server/serializers/schedule.py new file mode 100644 index 00000000000..f30c723c699 --- /dev/null +++ b/mula/scheduler/server/serializers/schedule.py @@ -0,0 +1,18 @@ +from datetime import datetime + +from pydantic import BaseModel, ConfigDict, Field + + +# NOTE: model added for support of partial updates +class Schedule(BaseModel): + model_config = ConfigDict(from_attributes=True) + + hash: str | None = Field(None, max_length=32) + + data: dict | None = None + + enabled: bool | None = None + + schedule: str | None = None + + deadline_at: datetime | None = None diff --git a/mula/scheduler/server/serializers/task.py b/mula/scheduler/server/serializers/task.py index 351c21efb1e..3a4e6fc3846 100644 --- a/mula/scheduler/server/serializers/task.py +++ b/mula/scheduler/server/serializers/task.py @@ -1,10 +1,9 @@ import enum import uuid +from datetime import datetime from pydantic import BaseModel, ConfigDict -from .p_item import PrioritizedItem - class TaskStatus(str, enum.Enum): # Task has been created but not yet queued @@ -30,6 +29,7 @@ class TaskStatus(str, enum.Enum): CANCELLED = "cancelled" +# NOTE: model added for support of partial updates class Task(BaseModel): model_config = ConfigDict(from_attributes=True, use_enum_values=True) @@ -37,8 +37,18 @@ class Task(BaseModel): scheduler_id: str | None = None - type: str | None = None + schedule_id: uuid.UUID | None = None - p_item: PrioritizedItem | None = None + priority: int | None = None status: TaskStatus | None = None + + type: str | None = None + + hash: str | None = None + + data: dict | None = None + + created_at: datetime | None = None + + modified_at: datetime | None = None diff --git a/mula/scheduler/server/server.py b/mula/scheduler/server/server.py index 3d6da73bf51..414e78e7785 100644 --- a/mula/scheduler/server/server.py +++ b/mula/scheduler/server/server.py @@ -41,6 +41,7 @@ def __init__( # Set up API endpoints handlers.SchedulerAPI(self.api, self.ctx, s) handlers.QueueAPI(self.api, self.ctx, s) + handlers.ScheduleAPI(self.api, self.ctx) handlers.TaskAPI(self.api, self.ctx) handlers.MetricsAPI(self.api, self.ctx) handlers.HealthAPI(self.api, self.ctx) diff --git a/mula/scheduler/storage/__init__.py b/mula/scheduler/storage/__init__.py index bab61e233f6..7ef0497775c 100644 --- a/mula/scheduler/storage/__init__.py +++ b/mula/scheduler/storage/__init__.py @@ -1,5 +1,6 @@ from .filters import apply_filter from .pq_store import PriorityQueueStore +from .schedule_store import ScheduleStore from .storage import DBConn from .task_store import TaskStore from .utils import retry diff --git a/mula/scheduler/storage/filters/comparison.py b/mula/scheduler/storage/filters/comparison.py index e8fab58641d..0dbac198c50 100644 --- a/mula/scheduler/storage/filters/comparison.py +++ b/mula/scheduler/storage/filters/comparison.py @@ -1,3 +1,5 @@ +import datetime + from sqlalchemy.sql.elements import BinaryExpression @@ -58,7 +60,20 @@ def __init__(self, operator: str): def compare( self, x: BinaryExpression, - y: str | int | float | bool | None | list[str] | list[int] | list[float] | list[bool] | list[None], + y: ( + str + | int + | float + | bool + | datetime.datetime + | None + | list[str] + | list[int] + | list[float] + | list[bool] + | list[datetime.datetime] + | list[None] + ), ) -> BinaryExpression: """Compare two values using the operator specified in the constructor. diff --git a/mula/scheduler/storage/filters/filters.py b/mula/scheduler/storage/filters/filters.py index 1cf9c4c54be..178c1ee2cc1 100644 --- a/mula/scheduler/storage/filters/filters.py +++ b/mula/scheduler/storage/filters/filters.py @@ -1,3 +1,4 @@ +import datetime from typing import Literal from pydantic import BaseModel @@ -47,7 +48,20 @@ class Filter(BaseModel): "@?", "@@", ] - value: str | int | float | bool | None | list[str] | list[int] | list[float] | list[bool] | list[None] + value: ( + str + | int + | float + | bool + | datetime.datetime + | None + | list[str] + | list[int] + | list[float] + | list[bool] + | list[datetime.datetime] + | list[None] + ) class FilterRequest(BaseModel): diff --git a/mula/scheduler/storage/pq_store.py b/mula/scheduler/storage/pq_store.py index b61e2f2ad2f..8f2b379456c 100644 --- a/mula/scheduler/storage/pq_store.py +++ b/mula/scheduler/storage/pq_store.py @@ -16,40 +16,45 @@ def __init__(self, dbconn: DBConn) -> None: @retry() @exception_handler - def pop(self, scheduler_id: str, filters: FilterRequest | None = None) -> models.PrioritizedItem | None: + def pop(self, scheduler_id: str, filters: FilterRequest | None = None) -> models.Task | None: with self.dbconn.session.begin() as session: - query = session.query(models.PrioritizedItemDB).filter( - models.PrioritizedItemDB.scheduler_id == scheduler_id + query = ( + session.query(models.TaskDB) + .filter(models.TaskDB.status == models.TaskStatus.QUEUED) + .order_by(models.TaskDB.priority.asc()) + .order_by(models.TaskDB.created_at.asc()) + .filter(models.TaskDB.scheduler_id == scheduler_id) ) if filters is not None: - query = apply_filter(models.PrioritizedItemDB, query, filters) + query = apply_filter(models.TaskDB, query, filters) item_orm = query.first() if item_orm is None: return None - return models.PrioritizedItem.model_validate(item_orm) + return models.Task.model_validate(item_orm) @retry() @exception_handler - def push(self, scheduler_id: str, item: models.PrioritizedItem) -> models.PrioritizedItem | None: + def push(self, item: models.Task) -> models.Task | None: with self.dbconn.session.begin() as session: - item_orm = models.PrioritizedItemDB(**item.model_dump()) + item_orm = models.TaskDB(**item.model_dump()) session.add(item_orm) - return models.PrioritizedItem.model_validate(item_orm) + return models.Task.model_validate(item_orm) @retry() @exception_handler - def peek(self, scheduler_id: str, index: int) -> models.PrioritizedItem | None: + def peek(self, scheduler_id: str, index: int) -> models.Task | None: with self.dbconn.session.begin() as session: item_orm = ( - session.query(models.PrioritizedItemDB) - .filter(models.PrioritizedItemDB.scheduler_id == scheduler_id) - .order_by(models.PrioritizedItemDB.priority.asc()) - .order_by(models.PrioritizedItemDB.created_at.asc()) + session.query(models.TaskDB) + .filter(models.TaskDB.status == models.TaskStatus.QUEUED) + .filter(models.TaskDB.scheduler_id == scheduler_id) + .order_by(models.TaskDB.priority.asc()) + .order_by(models.TaskDB.created_at.asc()) .offset(index) .first() ) @@ -57,16 +62,17 @@ def peek(self, scheduler_id: str, index: int) -> models.PrioritizedItem | None: if item_orm is None: return None - return models.PrioritizedItem.model_validate(item_orm) + return models.Task.model_validate(item_orm) @retry() @exception_handler - def update(self, scheduler_id: str, item: models.PrioritizedItem) -> None: + def update(self, scheduler_id: str, item: models.Task) -> None: with self.dbconn.session.begin() as session: ( - session.query(models.PrioritizedItemDB) - .filter(models.PrioritizedItemDB.scheduler_id == scheduler_id) - .filter(models.PrioritizedItemDB.id == item.id) + session.query(models.TaskDB) + .filter(models.TaskDB.status == models.TaskStatus.QUEUED) + .filter(models.TaskDB.scheduler_id == scheduler_id) + .filter(models.TaskDB.id == item.id) .update(item.model_dump()) ) @@ -75,35 +81,38 @@ def update(self, scheduler_id: str, item: models.PrioritizedItem) -> None: def remove(self, scheduler_id: str, item_id: UUID) -> None: with self.dbconn.session.begin() as session: ( - session.query(models.PrioritizedItemDB) - .filter(models.PrioritizedItemDB.scheduler_id == scheduler_id) - .filter(models.PrioritizedItemDB.id == str(item_id)) + session.query(models.TaskDB) + .filter(models.TaskDB.status == models.TaskStatus.QUEUED) + .filter(models.TaskDB.scheduler_id == scheduler_id) + .filter(models.TaskDB.id == str(item_id)) .delete() ) @retry() @exception_handler - def get(self, scheduler_id, item_id: UUID) -> models.PrioritizedItem | None: + def get(self, scheduler_id, item_id: UUID) -> models.Task | None: with self.dbconn.session.begin() as session: item_orm = ( - session.query(models.PrioritizedItemDB) - .filter(models.PrioritizedItemDB.scheduler_id == scheduler_id) - .filter(models.PrioritizedItemDB.id == str(item_id)) + session.query(models.TaskDB) + .filter(models.TaskDB.status == models.TaskStatus.QUEUED) + .filter(models.TaskDB.scheduler_id == scheduler_id) + .filter(models.TaskDB.id == str(item_id)) .first() ) if item_orm is None: return None - return models.PrioritizedItem.model_validate(item_orm) + return models.Task.model_validate(item_orm) @retry() @exception_handler def empty(self, scheduler_id: str) -> bool: with self.dbconn.session.begin() as session: count = ( - session.query(models.PrioritizedItemDB) - .filter(models.PrioritizedItemDB.scheduler_id == scheduler_id) + session.query(models.TaskDB) + .filter(models.TaskDB.status == models.TaskStatus.QUEUED) + .filter(models.TaskDB.scheduler_id == scheduler_id) .count() ) return count == 0 @@ -113,8 +122,9 @@ def empty(self, scheduler_id: str) -> bool: def qsize(self, scheduler_id: str) -> int: with self.dbconn.session.begin() as session: count = ( - session.query(models.PrioritizedItemDB) - .filter(models.PrioritizedItemDB.scheduler_id == scheduler_id) + session.query(models.TaskDB) + .filter(models.TaskDB.status == models.TaskStatus.QUEUED) + .filter(models.TaskDB.scheduler_id == scheduler_id) .count() ) @@ -126,58 +136,63 @@ def get_items( self, scheduler_id: str, filters: FilterRequest | None, - ) -> tuple[list[models.PrioritizedItem], int]: + ) -> tuple[list[models.Task], int]: with self.dbconn.session.begin() as session: - query = session.query(models.PrioritizedItemDB).filter( - models.PrioritizedItemDB.scheduler_id == scheduler_id + query = ( + session.query(models.TaskDB) + .filter(models.TaskDB.status == models.TaskStatus.QUEUED) + .filter(models.TaskDB.scheduler_id == scheduler_id) ) if filters is not None: - query = apply_filter(models.PrioritizedItemDB, query, filters) + query = apply_filter(models.TaskDB, query, filters) count = query.count() items_orm = query.all() return ( - [models.PrioritizedItem.model_validate(item_orm) for item_orm in items_orm], + [models.Task.model_validate(item_orm) for item_orm in items_orm], count, ) @retry() @exception_handler - def get_item_by_hash(self, scheduler_id: str, item_hash: str) -> models.PrioritizedItem | None: + def get_item_by_hash(self, scheduler_id: str, item_hash: str) -> models.Task | None: with self.dbconn.session.begin() as session: item_orm = ( - session.query(models.PrioritizedItemDB) - .order_by(models.PrioritizedItemDB.created_at.desc()) - .filter(models.PrioritizedItemDB.scheduler_id == scheduler_id) - .filter(models.PrioritizedItemDB.hash == item_hash) + session.query(models.TaskDB) + .filter(models.TaskDB.status == models.TaskStatus.QUEUED) + .order_by(models.TaskDB.created_at.desc()) + .filter(models.TaskDB.scheduler_id == scheduler_id) + .filter(models.TaskDB.hash == item_hash) .first() ) if item_orm is None: return None - return models.PrioritizedItem.model_validate(item_orm) + return models.Task.model_validate(item_orm) @retry() @exception_handler - def get_items_by_scheduler_id(self, scheduler_id: str) -> list[models.PrioritizedItem]: + def get_items_by_scheduler_id(self, scheduler_id: str) -> list[models.Task]: with self.dbconn.session.begin() as session: items_orm = ( - session.query(models.PrioritizedItemDB) - .filter(models.PrioritizedItemDB.scheduler_id == scheduler_id) + session.query(models.TaskDB) + .filter(models.TaskDB.status == models.TaskStatus.QUEUED) + .filter(models.TaskDB.scheduler_id == scheduler_id) .all() ) - return [models.PrioritizedItem.model_validate(item_orm) for item_orm in items_orm] + return [models.Task.model_validate(item_orm) for item_orm in items_orm] @retry() @exception_handler def clear(self, scheduler_id: str) -> None: with self.dbconn.session.begin() as session: ( - session.query(models.PrioritizedItemDB) - .filter(models.PrioritizedItemDB.scheduler_id == scheduler_id) - .delete() + session.query(models.TaskDB) + .filter(models.TaskDB.status == models.TaskStatus.QUEUED) + .filter(models.TaskDB.scheduler_id == scheduler_id) + .delete(), ) diff --git a/mula/scheduler/storage/schedule_store.py b/mula/scheduler/storage/schedule_store.py new file mode 100644 index 00000000000..c7f72533d68 --- /dev/null +++ b/mula/scheduler/storage/schedule_store.py @@ -0,0 +1,120 @@ +from datetime import datetime + +from sqlalchemy import exc + +from scheduler import models + +from .errors import StorageError, exception_handler +from .filters import FilterRequest, apply_filter +from .storage import DBConn +from .utils import retry + + +class ScheduleStore: + name: str = "schedule_store" + + def __init__(self, dbconn: DBConn) -> None: + self.dbconn = dbconn + + @retry() + @exception_handler + def get_schedules( + self, + scheduler_id: str | None = None, + schedule_hash: str | None = None, + enabled: bool | None = True, + min_deadline_at: datetime | None = None, + max_deadline_at: datetime | None = None, + min_created_at: datetime | None = None, + max_created_at: datetime | None = None, + offset: int = 0, + limit: int = 100, + filters: FilterRequest | None = None, + ) -> tuple[list[models.Schedule], int]: + with self.dbconn.session.begin() as session: + query = session.query(models.ScheduleDB) + + if scheduler_id is not None: + query = query.filter(models.ScheduleDB.scheduler_id == scheduler_id) + + if enabled is not None: + query = query.filter(models.ScheduleDB.enabled == enabled) + + if schedule_hash is not None: + query = query.filter(models.ScheduleDB.hash == schedule_hash) + + if min_deadline_at is not None: + query = query.filter(models.ScheduleDB.deadline_at >= min_deadline_at) + + if max_deadline_at is not None: + query = query.filter(models.ScheduleDB.deadline_at <= max_deadline_at) + + if min_created_at is not None: + query = query.filter(models.ScheduleDB.created_at >= min_created_at) + + if max_created_at is not None: + query = query.filter(models.ScheduleDB.created_at <= max_created_at) + + if filters is not None: + query = apply_filter(models.ScheduleDB, query, filters) + + try: + count = query.count() + schedules_orm = query.order_by(models.ScheduleDB.created_at.desc()).offset(offset).limit(limit).all() + except exc.ProgrammingError as e: + raise StorageError(f"Invalid filter: {e}") from e + + schedules = [models.Schedule.model_validate(schedule_orm) for schedule_orm in schedules_orm] + + return schedules, count + + @retry() + @exception_handler + def get_schedule(self, schedule_id: str) -> models.Schedule | None: + with self.dbconn.session.begin() as session: + schedule_orm = session.query(models.ScheduleDB).filter(models.ScheduleDB.id == schedule_id).one_or_none() + + if schedule_orm is None: + return None + + return models.Schedule.model_validate(schedule_orm) + + @retry() + @exception_handler + def get_schedule_by_hash(self, schedule_hash: str) -> models.Schedule | None: + with self.dbconn.session.begin() as session: + schedule_orm = ( + session.query(models.ScheduleDB).filter(models.ScheduleDB.hash == schedule_hash).one_or_none() + ) + + if schedule_orm is None: + return None + + return models.Schedule.model_validate(schedule_orm) + + @retry() + @exception_handler + def create_schedule(self, schedule: models.Schedule) -> models.Schedule: + with self.dbconn.session.begin() as session: + schedule_orm = models.ScheduleDB(**schedule.model_dump()) + session.add(schedule_orm) + + created_schedule = models.Schedule.model_validate(schedule_orm) + + return created_schedule + + @retry() + @exception_handler + def update_schedule(self, schedule: models.Schedule) -> None: + with self.dbconn.session.begin() as session: + ( + session.query(models.ScheduleDB) + .filter(models.ScheduleDB.id == schedule.id) + .update(schedule.model_dump(exclude={"tasks"})) + ) + + @retry() + @exception_handler + def delete_schedule(self, schedule_id: str) -> None: + with self.dbconn.session.begin() as session: + session.query(models.ScheduleDB).filter(models.ScheduleDB.id == schedule_id).delete() diff --git a/mula/scheduler/storage/task_store.py b/mula/scheduler/storage/task_store.py index 5b58438a611..d8593d4809f 100644 --- a/mula/scheduler/storage/task_store.py +++ b/mula/scheduler/storage/task_store.py @@ -78,7 +78,7 @@ def get_tasks_by_hash(self, task_hash: str) -> list[models.Task] | None: with self.dbconn.session.begin() as session: tasks_orm = ( session.query(models.TaskDB) - .filter(models.TaskDB.p_item["hash"].as_string() == task_hash) + .filter(models.TaskDB.hash == task_hash) .order_by(models.TaskDB.created_at.desc()) .all() ) @@ -96,7 +96,7 @@ def get_latest_task_by_hash(self, task_hash: str) -> models.Task | None: with self.dbconn.session.begin() as session: task_orm = ( session.query(models.TaskDB) - .filter(models.TaskDB.p_item["hash"].as_string() == task_hash) + .filter(models.TaskDB.hash == task_hash) .order_by(models.TaskDB.created_at.desc()) .first() ) diff --git a/mula/scheduler/utils/cron.py b/mula/scheduler/utils/cron.py new file mode 100644 index 00000000000..ac632c9ab71 --- /dev/null +++ b/mula/scheduler/utils/cron.py @@ -0,0 +1,11 @@ +from datetime import datetime, timezone + +from croniter import croniter # type: ignore + + +def next_run(expression: str, start_time: datetime | None = None) -> datetime: + if start_time is None: + start_time = datetime.now(timezone.utc) + + cron = croniter(expression, start_time) + return cron.get_next(datetime) diff --git a/mula/tests/integration/test_api.py b/mula/tests/integration/test_api.py index 9aae22ae114..c73fce5ed2b 100644 --- a/mula/tests/integration/test_api.py +++ b/mula/tests/integration/test_api.py @@ -1,18 +1,19 @@ -import copy import unittest import uuid from datetime import datetime, timedelta, timezone from types import SimpleNamespace from unittest import mock +from urllib.parse import quote from fastapi.testclient import TestClient from scheduler import config, models, server, storage +from scheduler.server import serializers from tests.factories import OrganisationFactory from tests.mocks import queue as mock_queue from tests.mocks import scheduler as mock_scheduler from tests.utils import functions -from tests.utils.functions import create_p_item_request +from tests.utils.functions import create_task_in class APITemplateTestCase(unittest.TestCase): @@ -31,6 +32,7 @@ def setUp(self): **{ storage.TaskStore.name: storage.TaskStore(self.dbconn), storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn), + storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn), } ) @@ -50,6 +52,7 @@ def setUp(self): ctx=self.mock_ctx, scheduler_id=self.organisation.id, queue=queue, + create_schedule=True, ) # API server and Test Client @@ -98,10 +101,10 @@ def test_patch_scheduler_disable(self): self.assertFalse(self.scheduler.is_enabled()) # Try to push to queue - item = create_p_item_request(0) + item = create_task_in(0) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=item.model_dump_json(), + data=item, ) self.assertNotEqual(response.status_code, 201) self.assertEqual(0, self.scheduler.queue.qsize()) @@ -122,9 +125,12 @@ def test_patch_scheduler_enable(self): # Try to push to queue self.assertEqual(0, self.scheduler.queue.qsize()) - item = create_p_item_request(1) + item = create_task_in(1) - response = self.client.post(f"/queues/{self.scheduler.scheduler_id}/push", data=item.model_dump_json()) + response = self.client.post( + f"/queues/{self.scheduler.scheduler_id}/push", + data=item, + ) self.assertEqual(response.status_code, 201) self.assertEqual(1, self.scheduler.queue.qsize()) @@ -141,15 +147,28 @@ def test_get_queue_malformed_id(self): response = self.client.get("/queues/123.123") self.assertEqual(response.status_code, 404) - def test_push_queue(self): + def test_push_queue__(self): self.assertEqual(0, self.scheduler.queue.qsize()) - item = create_p_item_request(1) + item = create_task_in(1) - response = self.client.post(f"/queues/{self.scheduler.scheduler_id}/push", data=item.model_dump_json()) - self.assertEqual(response.status_code, 201) + response_post = self.client.post( + f"/queues/{self.scheduler.scheduler_id}/push", + data=item, + ) + self.assertEqual(201, response_post.status_code) self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertIsNotNone(response.json().get("id")) + self.assertIsNotNone(response_post.json().get("id")) + + # Task should be created + response_get_task = self.client.get(f"/tasks/{response_post.json().get('id')}") + self.assertEqual(200, response_get_task.status_code) + self.assertEqual(response_post.json().get("id"), response_get_task.json().get("id")) + + # Schedule should be created, and schedule_id should be in the + # response of the post request + response_get_schedule = self.client.get(f"/schedules/{response_post.json().get('schedule_id')}") + self.assertEqual(200, response_get_schedule.status_code) def test_push_incorrect_item_type(self): response = self.client.post( @@ -163,19 +182,19 @@ def test_push_queue_full(self): self.scheduler.queue.maxsize = 1 # Add one task to the queue - first_item = create_p_item_request(1) + first_item = create_task_in(1) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=first_item.model_dump_json(), + data=first_item, ) self.assertEqual(response.status_code, 201) self.assertEqual(1, self.scheduler.queue.qsize()) # Try to add another task to the queue through the api - second_item = create_p_item_request(2) + second_item = create_task_in(2) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=second_item.model_dump_json(), + data=second_item, ) self.assertEqual(response.status_code, 429) self.assertEqual(1, self.scheduler.queue.qsize()) @@ -185,19 +204,19 @@ def test_push_queue_full_high_priority(self): self.scheduler.queue.maxsize = 1 # Add one task to the queue - first_item = create_p_item_request(1) + first_item = create_task_in(1) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=first_item.model_dump_json(), + data=first_item, ) self.assertEqual(response.status_code, 201) self.assertEqual(1, self.scheduler.queue.qsize()) # Try to add another task to the queue through the api - second_item = create_p_item_request(1) + second_item = create_task_in(1) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=second_item.model_dump_json(), + data=second_item, ) self.assertEqual(response.status_code, 201) self.assertEqual(2, self.scheduler.queue.qsize()) @@ -212,10 +231,10 @@ def test_push_replace_not_allowed(self): self.scheduler.queue.allow_priority_updates = False # Add one task to the queue - initial_item = create_p_item_request(1) + initial_item = create_task_in(1) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=initial_item.model_dump_json(), + data=initial_item, ) self.assertEqual(response.status_code, 201) self.assertEqual(1, self.scheduler.queue.qsize()) @@ -223,7 +242,7 @@ def test_push_replace_not_allowed(self): # Add the same item again through the api response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=initial_item.model_dump_json(), + data=initial_item, ) # The queue should still have one item @@ -239,10 +258,10 @@ def test_push_replace_allowed(self): self.scheduler.queue.allow_replace = True # Add one task to the queue - initial_item = create_p_item_request(1) + initial_item = create_task_in(1) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=initial_item.model_dump_json(), + data=initial_item, ) self.assertEqual(response.status_code, 201) self.assertEqual(1, self.scheduler.queue.qsize()) @@ -267,16 +286,16 @@ def test_push_updates_not_allowed(self): self.scheduler.queue.allow_priority_updates = False # Add one task to the queue - initial_item = create_p_item_request(1) + initial_item = create_task_in(1) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=initial_item.model_dump_json(), + data=initial_item, ) self.assertEqual(response.status_code, 201) self.assertEqual(1, self.scheduler.queue.qsize()) # Update the item - updated_item = models.PrioritizedItem(**response.json()) + updated_item = serializers.Task(**response.json()) updated_item.data["name"] = "updated-name" # Try to update the item through the api @@ -299,16 +318,16 @@ def test_push_updates_allowed(self): self.scheduler.queue.allow_updates = True # Add one task to the queue - initial_item = create_p_item_request(1) + initial_item = create_task_in(1) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=initial_item.model_dump_json(), + data=initial_item, ) self.assertEqual(response.status_code, 201) self.assertEqual(1, self.scheduler.queue.qsize()) # Update the item - updated_item = models.PrioritizedItem(**response.json()) + updated_item = serializers.Task(**response.json()) updated_item.data["name"] = "updated-name" # Try to update the item through the api @@ -335,16 +354,16 @@ def test_push_priority_updates_not_allowed(self): self.scheduler.queue.allow_priority_updates = False # Add one task to the queue - initial_item = create_p_item_request(1) + initial_item = create_task_in(1) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=initial_item.model_dump_json(), + data=initial_item, ) self.assertEqual(response.status_code, 201) self.assertEqual(1, self.scheduler.queue.qsize()) # Update the item - updated_item = copy.deepcopy(initial_item) + updated_item = serializers.Task(**response.json()) updated_item.priority = 2 # Try to update the item through the api @@ -372,15 +391,15 @@ def test_update_priority_higher(self): self.scheduler.queue.allow_priority_updates = True # Add one task to the queue - initial_item = create_p_item_request(2) + initial_item = create_task_in(2) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=initial_item.model_dump_json(), + data=initial_item, ) self.assertEqual(response.status_code, 201) # Update priority of the item - updated_item = models.PrioritizedItem(**response.json()) + updated_item = serializers.Task(**response.json()) updated_item.priority = 1 # Try to update the item through the api @@ -409,15 +428,15 @@ def test_update_priority_lower(self): self.scheduler.queue.allow_priority_updates = True # Add one task to the queue - initial_item = create_p_item_request(1) + initial_item = create_task_in(1) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=initial_item.model_dump_json(), + data=initial_item, ) self.assertEqual(response.status_code, 201) # Update priority of the item - updated_item = models.PrioritizedItem(**response.json()) + updated_item = serializers.Task(**response.json()) updated_item.priority = 2 # Try to update the item through the api @@ -438,10 +457,10 @@ def test_update_priority_lower(self): def test_pop_queue(self): # Add one task to the queue - initial_item = create_p_item_request(1) + initial_item = create_task_in(1) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=initial_item.model_dump_json(), + data=initial_item, ) initial_item_id = response.json().get("id") self.assertEqual(response.status_code, 201) @@ -454,20 +473,20 @@ def test_pop_queue(self): def test_pop_queue_filters(self): # Add one task to the queue - first_item = create_p_item_request(1, data=functions.TestModel(id="123", name="test")) + first_item = create_task_in(1, data=functions.TestModel(id="123", name="test")) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=first_item.model_dump_json(), + data=first_item, ) first_item_id = response.json().get("id") self.assertEqual(response.status_code, 201) self.assertEqual(1, self.scheduler.queue.qsize()) # Add second item to the queue - second_item = create_p_item_request(2, data=functions.TestModel(id="456", name="test")) + second_item = create_task_in(2, data=functions.TestModel(id="456", name="test")) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=second_item.model_dump_json(), + data=second_item, ) second_item_id = response.json().get("id") self.assertEqual(response.status_code, 201) @@ -532,7 +551,7 @@ def setUp(self): super().setUp() # Add one task to the queue - first_item = create_p_item_request( + first_item = create_task_in( 1, data=functions.TestModel( id="123", @@ -542,7 +561,7 @@ def setUp(self): ) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=first_item.model_dump_json(), + data=first_item, ) initial_item_id = response.json().get("id") self.assertEqual(response.status_code, 201) @@ -551,13 +570,13 @@ def setUp(self): self.first_item_api = self.client.get(f"/tasks/{initial_item_id}").json() # Add second item to the queue - second_item = create_p_item_request( + second_item = create_task_in( 1, data=functions.TestModel(id="456", name="test"), ) response = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=second_item.model_dump_json(), + data=second_item, ) second_item_id = response.json().get("id") self.assertEqual(response.status_code, 201) @@ -566,14 +585,30 @@ def setUp(self): self.second_item_api = self.client.get(f"/tasks/{second_item_id}").json() def test_create_task(self): - item = create_p_item_request(1) - response_post = self.client.post(f"/queues/{self.scheduler.scheduler_id}/push", data=item.model_dump_json()) + item = create_task_in(1) + response_post = self.client.post( + f"/queues/{self.scheduler.scheduler_id}/push", + data=item, + ) self.assertEqual(201, response_post.status_code) initial_item_id = response_post.json().get("id") response_get = self.client.get(f"/tasks/{initial_item_id}") self.assertEqual(200, response_get.status_code) + # Task should be created + response_get_task = self.client.get(f"/tasks/{initial_item_id}") + self.assertEqual(200, response_get_task.status_code) + self.assertEqual(initial_item_id, response_get_task.json().get("id")) + + # Schedule should be created + response_get_schedule = self.client.get(f"/schedules?hash{response_post.json().get('hash')}") + self.assertEqual(200, response_get_schedule.status_code) + self.assertEqual( + response_post.json().get("hash"), + response_get_schedule.json().get("results")[0].get("hash"), + ) + def test_get_tasks(self): response = self.client.get("/tasks") self.assertEqual(200, response.status_code) @@ -582,11 +617,11 @@ def test_get_tasks(self): def test_get_task(self): # First add a task - item = create_p_item_request(1) + item = create_task_in(1) response_post = self.client.post( f"/queues/{self.scheduler.scheduler_id}/push", - data=item.model_dump_json(), + data=item, ) self.assertEqual(201, response_post.status_code) initial_item_id = response_post.json().get("id") @@ -677,8 +712,8 @@ def test_get_tasks_filtered(self): json={ "filters": [ { - "column": "p_item", - "field": "data__name", + "column": "data", + "field": "name", "operator": "eq", "value": "test", } @@ -693,8 +728,8 @@ def test_get_tasks_filtered(self): json={ "filters": [ { - "column": "p_item", - "field": "data__id", + "column": "data", + "field": "id", "operator": "eq", "value": "123", } @@ -709,8 +744,8 @@ def test_get_tasks_filtered(self): json={ "filters": [ { - "column": "p_item", - "field": "data__child__name", + "column": "data", + "field": "child__name", "operator": "eq", "value": "test.child", } @@ -763,3 +798,169 @@ def test_get_tasks_stats(self): response = self.client.get(f"/tasks/stats/{self.first_item_api.get('scheduler_id')}") self.assertEqual(200, response.status_code) + + +class APIScheduleEndpointTestCase(APITemplateTestCase): + def setUp(self): + super().setUp() + + first_item = functions.create_item(self.scheduler.scheduler_id, 1) + self.first_schedule = self.mock_ctx.datastores.schedule_store.create_schedule( + models.Schedule( + scheduler_id=self.scheduler.scheduler_id, + hash=first_item.hash, + data=first_item.data, + deadline_at=datetime.now(timezone.utc) + timedelta(days=1), + ) + ) + + second_item = functions.create_item(self.scheduler.scheduler_id, 1) + self.second_schedule = self.mock_ctx.datastores.schedule_store.create_schedule( + models.Schedule( + scheduler_id=self.scheduler.scheduler_id, + hash=second_item.hash, + data=second_item.data, + deadline_at=datetime.now(timezone.utc) + timedelta(days=2), + ) + ) + + def test_list_schedules(self): + response = self.client.get("/schedules") + self.assertEqual(200, response.status_code) + self.assertEqual(2, response.json()["count"]) + self.assertEqual(2, len(response.json()["results"])) + + def test_list_schedules_enabled(self): + response = self.client.get("/schedules?enabled=true") + self.assertEqual(200, response.status_code) + self.assertEqual(2, response.json()["count"]) + self.assertEqual(2, len(response.json()["results"])) + + response = self.client.get("/schedules?enabled=false") + self.assertEqual(200, response.status_code) + self.assertEqual(0, response.json()["count"]) + self.assertEqual(0, len(response.json()["results"])) + + def test_list_schedules_min_deadline(self): + response = self.client.get(f"/schedules?min_deadline_at={quote(self.first_schedule.deadline_at.isoformat())}") + self.assertEqual(200, response.status_code) + self.assertEqual(2, response.json()["count"]) + self.assertEqual(2, len(response.json()["results"])) + + response = self.client.get(f"/schedules?min_deadline_at={quote(self.second_schedule.deadline_at.isoformat())}") + self.assertEqual(200, response.status_code) + self.assertEqual(1, response.json()["count"]) + self.assertEqual(1, len(response.json()["results"])) + self.assertEqual(str(self.second_schedule.id), response.json()["results"][0]["id"]) + + def test_list_schedules_max_deadline(self): + response = self.client.get(f"/schedules?max_deadline_at={quote(self.second_schedule.deadline_at.isoformat())}") + self.assertEqual(200, response.status_code) + self.assertEqual(2, response.json()["count"]) + self.assertEqual(2, len(response.json()["results"])) + + response = self.client.get(f"/schedules?max_deadline_at={quote(self.first_schedule.deadline_at.isoformat())}") + self.assertEqual(200, response.status_code) + self.assertEqual(1, response.json()["count"]) + self.assertEqual(1, len(response.json()["results"])) + self.assertEqual(str(self.first_schedule.id), response.json()["results"][0]["id"]) + + def test_list_schedules_min_and_max_deadline(self): + response = self.client.get( + f"/schedules?min_deadline_at={quote(self.first_schedule.deadline_at.isoformat())}&max_deadline_at={quote(self.second_schedule.deadline_at.isoformat())}" + ) + + self.assertEqual(200, response.status_code) + self.assertEqual(2, response.json()["count"]) + self.assertEqual(2, len(response.json()["results"])) + + response = self.client.get( + f"/schedules?min_deadline_at={quote(self.first_schedule.deadline_at.isoformat())}&max_deadline_at={quote(self.first_schedule.deadline_at.isoformat())}" + ) + self.assertEqual(200, response.status_code) + self.assertEqual(1, response.json()["count"]) + self.assertEqual(1, len(response.json()["results"])) + self.assertEqual(str(self.first_schedule.id), response.json()["results"][0]["id"]) + + def test_list_schedules_min_greater_than_max_deadline(self): + response = self.client.get( + f"/schedules?min_deadline_at={quote(self.second_schedule.deadline_at.isoformat())}&max_deadline_at={quote(self.first_schedule.deadline_at.isoformat())}" + ) + self.assertEqual(400, response.status_code) + self.assertEqual( + "min_deadline_at must be less than max_deadline_at", + response.json().get("detail"), + ) + + def test_list_schedules_hash(self): + response = self.client.get(f"/schedules?schedule_hash={self.first_schedule.hash}") + self.assertEqual(200, response.status_code) + self.assertEqual(1, response.json()["count"]) + self.assertEqual(1, len(response.json()["results"])) + self.assertEqual(str(self.first_schedule.id), response.json()["results"][0]["id"]) + + def test_list_schedules_min_created_at(self): + response = self.client.get(f"/schedules?min_created_at={quote(self.first_schedule.created_at.isoformat())}") + self.assertEqual(200, response.status_code) + self.assertEqual(2, response.json()["count"]) + self.assertEqual(2, len(response.json()["results"])) + + response = self.client.get(f"/schedules?min_created_at={quote(self.second_schedule.created_at.isoformat())}") + self.assertEqual(200, response.status_code) + self.assertEqual(1, response.json()["count"]) + self.assertEqual(1, len(response.json()["results"])) + self.assertEqual(str(self.second_schedule.id), response.json()["results"][0]["id"]) + + def test_list_schedules_max_created_at(self): + response = self.client.get(f"/schedules?max_created_at={quote(self.second_schedule.created_at.isoformat())}") + self.assertEqual(200, response.status_code) + self.assertEqual(2, response.json()["count"]) + self.assertEqual(2, len(response.json()["results"])) + + response = self.client.get(f"/schedules?max_created_at={quote(self.first_schedule.created_at.isoformat())}") + self.assertEqual(200, response.status_code) + self.assertEqual(1, response.json()["count"]) + self.assertEqual(1, len(response.json()["results"])) + self.assertEqual(str(self.first_schedule.id), response.json()["results"][0]["id"]) + + def test_list_schedules_min_and_max_created_at(self): + response = self.client.get( + f"/schedules?min_created_at={quote(self.first_schedule.created_at.isoformat())}&max_created_at={quote(self.second_schedule.created_at.isoformat())}" + ) + self.assertEqual(200, response.status_code) + self.assertEqual(2, response.json()["count"]) + self.assertEqual(2, len(response.json()["results"])) + + response = self.client.get( + f"/schedules?min_created_at={quote(self.first_schedule.created_at.isoformat())}&max_created_at={quote(self.first_schedule.created_at.isoformat())}" + ) + self.assertEqual(200, response.status_code) + self.assertEqual(1, response.json()["count"]) + self.assertEqual(1, len(response.json()["results"])) + self.assertEqual(str(self.first_schedule.id), response.json()["results"][0]["id"]) + + def test_get_schedule(self): + response = self.client.get(f"/schedules/{str(self.first_schedule.id)}") + self.assertEqual(200, response.status_code) + self.assertEqual(str(self.first_schedule.id), response.json().get("id")) + + def test_patch_schedule(self): + response = self.client.patch(f"/schedules/{str(self.first_schedule.id)}", json={"enabled": False}) + self.assertEqual(200, response.status_code) + self.assertEqual(False, response.json().get("enabled")) + + def test_patch_schedule_validate_schedule(self): + response = self.client.patch( + f"/schedules/{str(self.first_schedule.id)}", + json={"schedule": "*/5 * * * *"}, + ) + self.assertEqual(200, response.status_code) + self.assertEqual("*/5 * * * *", response.json().get("schedule")) + + def test_patch_schedule_validate_malformed_schedule(self): + response = self.client.patch( + f"/schedules/{str(self.first_schedule.id)}", + json={"schedule": "malformed"}, + ) + self.assertEqual(400, response.status_code) + self.assertIn("validation error", response.json().get("detail")) diff --git a/mula/tests/integration/test_boefje_scheduler.py b/mula/tests/integration/test_boefje_scheduler.py index 01cd8777b1d..06589ac749c 100644 --- a/mula/tests/integration/test_boefje_scheduler.py +++ b/mula/tests/integration/test_boefje_scheduler.py @@ -59,6 +59,7 @@ def setUp(self): self.mock_ctx.datastores = SimpleNamespace( **{ + storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn), storage.TaskStore.name: storage.TaskStore(self.dbconn), storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn), } @@ -90,14 +91,41 @@ def setUp(self): "scheduler.context.AppContext.services.bytes.get_last_run_boefje" ).start() + self.mock_get_plugin = mock.patch( + "scheduler.context.AppContext.services.katalogus.get_plugin_by_id_and_org_id", + ).start() + + self.mock_get_object = mock.patch("scheduler.context.AppContext.services.octopoes.get_object").start() + + def tearDown(self): + mock.patch.stopall() + def test_is_allowed_to_run(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + + # Act + allowed_to_run = self.scheduler.has_boefje_permission_to_run( + plugin, + ooi, + ) + + # Assert + self.assertTrue(allowed_to_run) + + def test_is_allowed_to_run_no_ooi(self): + # Arrange + scan_profile = ScanProfileFactory(level=0) + ooi = OOIFactory(scan_profile=scan_profile) + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type]) # Act - allowed_to_run = self.scheduler.is_task_allowed_to_run(ooi=ooi, boefje=boefje) + allowed_to_run = self.scheduler.has_boefje_permission_to_run( + plugin, + ooi, + ) # Assert self.assertTrue(allowed_to_run) @@ -106,11 +134,14 @@ def test_is_not_allowed_to_run(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=4, consumes=[ooi.object_type]) + plugin = PluginFactory(scan_level=4, consumes=[ooi.object_type]) # Act with capture_logs() as cm: - allowed_to_run = self.scheduler.is_task_allowed_to_run(ooi=ooi, boefje=boefje) + allowed_to_run = self.scheduler.has_boefje_permission_to_run( + plugin, + ooi, + ) # Assert self.assertFalse(allowed_to_run) @@ -124,7 +155,7 @@ def test_is_task_not_running(self): scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) boefje = BoefjeFactory() - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=boefje, input_ooi=ooi.primary_key, organization=self.organisation.id, @@ -135,12 +166,12 @@ def test_is_task_not_running(self): self.mock_get_last_run_boefje.return_value = None # Act - is_running = self.scheduler.is_task_running(task) + is_running = self.scheduler.has_boefje_task_started_running(boefje_task) # Assert self.assertFalse(is_running) - def test_is_task_running_datastore_running(self): + def test_has_boefje_task_started_running_datastore_running(self): """When the task is found in the datastore and the status isn't failed or completed, then the task is still running. """ @@ -148,41 +179,28 @@ def test_is_task_running_datastore_running(self): scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) boefje = BoefjeFactory() - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=boefje, input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = models.PrioritizedItem( - id=task.id, - scheduler_id=self.scheduler.scheduler_id, - priority=1, - data=task.model_dump(), - hash=task.hash, - ) - - task_db = models.Task( - id=p_item.id, + task = functions.create_task( scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, - status=models.TaskStatus.QUEUED, - created_at=datetime.utcnow(), - modified_at=datetime.utcnow(), + data=boefje_task, ) # Mock - self.mock_get_latest_task_by_hash.return_value = task_db + self.mock_get_latest_task_by_hash.return_value = task self.mock_get_last_run_boefje.return_value = None # Act - is_running = self.scheduler.is_task_running(task) + is_running = self.scheduler.has_boefje_task_started_running(task) # Assert self.assertTrue(is_running) - def test_is_task_running_datastore_not_running(self): + def test_has_boefje_task_started_running_datastore_not_running(self): """When the task is found in the datastore and the status is failed or completed, then the task is not running. """ @@ -190,35 +208,29 @@ def test_is_task_running_datastore_not_running(self): scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) boefje = BoefjeFactory() - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=boefje, input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = models.PrioritizedItem( - id=task.id, - scheduler_id=self.scheduler.scheduler_id, - priority=1, - data=task.model_dump(), - hash=task.hash, - ) - task_db_first = models.Task( - id=p_item.id, scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, + priority=1, status=models.TaskStatus.COMPLETED, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), created_at=datetime.now(timezone.utc), modified_at=datetime.now(timezone.utc), ) task_db_second = models.Task( - id=p_item.id, scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, + priority=1, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), status=models.TaskStatus.FAILED, created_at=datetime.now(timezone.utc), modified_at=datetime.now(timezone.utc), @@ -238,14 +250,14 @@ def test_is_task_running_datastore_not_running(self): self.mock_get_last_run_boefje.return_value = last_run_boefje # First run - is_running = self.scheduler.is_task_running(task) + is_running = self.scheduler.has_boefje_task_started_running(boefje_task) self.assertFalse(is_running) # Second run - is_running = self.scheduler.is_task_running(task) + is_running = self.scheduler.has_boefje_task_started_running(boefje_task) self.assertFalse(is_running) - def test_is_task_running_datastore_exception(self): + def test_has_boefje_task_started_running_datastore_exception(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) @@ -262,9 +274,9 @@ def test_is_task_running_datastore_exception(self): # Act with self.assertRaises(Exception): - self.scheduler.is_task_running(task) + self.scheduler.has_boefje_task_started_running(task) - def test_is_task_running_bytes_running(self): + def test_has_boefje_task_started_running_bytes_running(self): """When task is found in bytes and the started_at field is not None, and the ended_at field is None. The task is still running.""" # Arrange @@ -287,12 +299,12 @@ def test_is_task_running_bytes_running(self): self.mock_get_last_run_boefje.return_value = last_run_boefje # Act - is_running = self.scheduler.is_task_running(task) + is_running = self.scheduler.has_boefje_task_started_running(task) # Assert self.assertTrue(is_running) - def test_is_task_running_bytes_not_running(self): + def test_has_boefje_task_started_running_bytes_not_running(self): """When task is found in bytes and the started_at field is not None, and the ended_at field is not None. The task is not running.""" # Arrange @@ -315,12 +327,12 @@ def test_is_task_running_bytes_not_running(self): self.mock_get_last_run_boefje.return_value = last_run_boefje # Act - is_running = self.scheduler.is_task_running(task) + is_running = self.scheduler.has_boefje_task_started_running(task) # Assert self.assertFalse(is_running) - def test_is_task_running_bytes_exception(self): + def test_has_boefje_task_started_running_bytes_exception(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) @@ -337,31 +349,24 @@ def test_is_task_running_bytes_exception(self): # Act with self.assertRaises(Exception): - self.scheduler.is_task_running(task) + self.scheduler.has_boefje_task_started_running(task) - def test_is_task_running_stalled_before_grace_period(self): + def test_has_boefje_task_started_running_stalled_before_grace_period(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=BoefjeFactory(), input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = models.PrioritizedItem( - id=task.id, - scheduler_id=self.scheduler.scheduler_id, - priority=1, - data=task.model_dump(), - hash=task.hash, - ) - task_db = models.Task( - id=p_item.id, scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, + priority=1, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), status=models.TaskStatus.DISPATCHED, created_at=datetime.now(timezone.utc), modified_at=datetime.now(timezone.utc), @@ -372,32 +377,25 @@ def test_is_task_running_stalled_before_grace_period(self): self.mock_get_last_run_boefje.return_value = None # Act - self.assertFalse(self.scheduler.is_task_stalled(task)) + self.assertFalse(self.scheduler.has_boefje_task_stalled(boefje_task)) - def test_is_task_running_stalled_after_grace_period(self): + def test_has_boefje_task_started_running_stalled_after_grace_period(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=BoefjeFactory(), input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = models.PrioritizedItem( - id=task.id, - scheduler_id=self.scheduler.scheduler_id, - priority=1, - data=task.model_dump(), - hash=task.hash, - ) - task_db = models.Task( - id=p_item.id, scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, + priority=1, status=models.TaskStatus.DISPATCHED, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), created_at=datetime.now(timezone.utc), modified_at=datetime.now(timezone.utc) - timedelta(seconds=self.mock_ctx.config.pq_grace_period), ) @@ -407,35 +405,28 @@ def test_is_task_running_stalled_after_grace_period(self): self.mock_get_last_run_boefje.return_value = None # Act - self.assertTrue(self.scheduler.is_task_stalled(task)) + self.assertTrue(self.scheduler.has_boefje_task_stalled(boefje_task)) - def test_is_task_running_mismatch_before_grace_period(self): + def test_has_boefje_task_started_running_mismatch_before_grace_period(self): """When a task has finished according to the datastore, (e.g. failed or completed), but there are no results in bytes, we have a problem. """ # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=BoefjeFactory(), input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = models.PrioritizedItem( - id=task.id, - scheduler_id=self.scheduler.scheduler_id, - priority=1, - data=task.model_dump(), - hash=task.hash, - ) - task_db = models.Task( - id=p_item.id, scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, + priority=1, status=models.TaskStatus.COMPLETED, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), created_at=datetime.now(timezone.utc), modified_at=datetime.now(timezone.utc), ) @@ -446,9 +437,9 @@ def test_is_task_running_mismatch_before_grace_period(self): # Act with self.assertRaises(RuntimeError): - self.scheduler.is_task_running(task) + self.scheduler.has_boefje_task_started_running(boefje_task) - def test_is_task_running_mismatch_after_grace_period(self): + def test_has_boefje_task_started_running_mismatch_after_grace_period(self): """When a task has finished according to the datastore, (e.g. failed or completed), but there are no results in bytes, we have a problem. However when the grace period has been reached we should not raise @@ -457,26 +448,19 @@ def test_is_task_running_mismatch_after_grace_period(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=BoefjeFactory(), input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = models.PrioritizedItem( - id=task.id, - scheduler_id=self.scheduler.scheduler_id, - priority=1, - data=task.model_dump(), - hash=task.hash, - ) - task_db = models.Task( - id=p_item.id, scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, + priority=1, status=models.TaskStatus.COMPLETED, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), created_at=datetime.now(timezone.utc), modified_at=datetime.now(timezone.utc) - timedelta(seconds=self.mock_ctx.config.pq_grace_period), ) @@ -486,33 +470,26 @@ def test_is_task_running_mismatch_after_grace_period(self): self.mock_get_last_run_boefje.return_value = None # Act - self.assertFalse(self.scheduler.is_task_running(task)) + self.assertFalse(self.scheduler.has_boefje_task_started_running(boefje_task)) - def test_has_grace_period_passed_datastore_passed(self): + def test_has_boefje_task_grace_period_passed_datastore_passed(self): """Grace period passed according to datastore, and the status is completed""" # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=BoefjeFactory(), input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = models.PrioritizedItem( - id=task.id, - scheduler_id=self.scheduler.scheduler_id, - priority=1, - data=task.model_dump(), - hash=task.hash, - ) - task_db = models.Task( - id=p_item.id, scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, + priority=1, status=models.TaskStatus.COMPLETED, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), created_at=datetime.now(timezone.utc), modified_at=datetime.now(timezone.utc) - timedelta(seconds=self.mock_ctx.config.pq_grace_period), ) @@ -522,36 +499,29 @@ def test_has_grace_period_passed_datastore_passed(self): self.mock_get_last_run_boefje.return_value = None # Act - has_passed = self.scheduler.has_grace_period_passed(task) + has_passed = self.scheduler.has_boefje_task_grace_period_passed(boefje_task) # Assert self.assertTrue(has_passed) - def test_has_grace_period_passed_datastore_not_passed(self): + def test_has_boefje_task_grace_period_passed_datastore_not_passed(self): """Grace period not passed according to datastore.""" # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=BoefjeFactory(), input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = models.PrioritizedItem( - id=task.id, - scheduler_id=self.scheduler.scheduler_id, - priority=1, - data=task.model_dump(), - hash=task.hash, - ) - task_db = models.Task( - id=p_item.id, scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, + priority=1, status=models.TaskStatus.COMPLETED, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), created_at=datetime.now(timezone.utc), modified_at=datetime.now(timezone.utc), ) @@ -561,36 +531,29 @@ def test_has_grace_period_passed_datastore_not_passed(self): self.mock_get_last_run_boefje.return_value = None # Act - has_passed = self.scheduler.has_grace_period_passed(task) + has_passed = self.scheduler.has_boefje_task_grace_period_passed(boefje_task) # Assert self.assertFalse(has_passed) - def test_has_grace_period_passed_bytes_passed(self): + def test_has_boefje_task_grace_period_passed_bytes_passed(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) boefje = BoefjeFactory() - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=boefje, input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = models.PrioritizedItem( - id=task.id, - scheduler_id=self.scheduler.scheduler_id, - priority=1, - data=task.model_dump(), - hash=task.hash, - ) - task_db = models.Task( - id=p_item.id, scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, + priority=1, status=models.TaskStatus.COMPLETED, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), created_at=datetime.now(timezone.utc), modified_at=datetime.now(timezone.utc) - timedelta(seconds=self.mock_ctx.config.pq_grace_period), ) @@ -606,36 +569,29 @@ def test_has_grace_period_passed_bytes_passed(self): self.mock_get_last_run_boefje.return_value = last_run_boefje # Act - has_passed = self.scheduler.has_grace_period_passed(task) + has_passed = self.scheduler.has_boefje_task_grace_period_passed(boefje_task) # Assert self.assertTrue(has_passed) - def test_has_grace_period_passed_bytes_not_passed(self): + def test_has_boefje_task_grace_period_passed_bytes_not_passed(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) boefje = BoefjeFactory() - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=boefje, input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = models.PrioritizedItem( - id=task.id, - scheduler_id=self.scheduler.scheduler_id, - priority=1, - data=task.model_dump(), - hash=task.hash, - ) - task_db = models.Task( - id=p_item.id, scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, + priority=1, status=models.TaskStatus.COMPLETED, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), created_at=datetime.now(timezone.utc), modified_at=datetime.now(timezone.utc) - timedelta(seconds=self.mock_ctx.config.pq_grace_period), ) @@ -651,66 +607,114 @@ def test_has_grace_period_passed_bytes_not_passed(self): self.mock_get_last_run_boefje.return_value = last_run_boefje # Act - has_passed = self.scheduler.has_grace_period_passed(task) + has_passed = self.scheduler.has_boefje_task_grace_period_passed(boefje_task) # Assert self.assertFalse(has_passed) - @mock.patch("scheduler.schedulers.BoefjeScheduler.is_task_running") - @mock.patch("scheduler.schedulers.BoefjeScheduler.is_task_allowed_to_run") - @mock.patch("scheduler.schedulers.BoefjeScheduler.has_grace_period_passed") + def test_push_task(self): + # Arrange + scan_profile = ScanProfileFactory(level=0) + ooi = OOIFactory(scan_profile=scan_profile) + boefje = BoefjeFactory() + + boefje_task = models.BoefjeTask( + boefje=models.Boefje.parse_obj(boefje.dict()), + input_ooi=ooi.primary_key, + organization=self.organisation.id, + ) + + # Mocks + self.mock_get_latest_task_by_hash.return_value = None + self.mock_get_last_run_boefje.return_value = None + + # Act + self.scheduler.push_boefje_task(boefje_task) + + # Assert + self.assertEqual(1, self.scheduler.queue.qsize()) + + def test_push_task_no_ooi(self): + # Arrange + boefje = BoefjeFactory() + + boefje_task = models.BoefjeTask( + boefje=models.Boefje.parse_obj(boefje.dict()), + input_ooi=None, + organization=self.organisation.id, + ) + + # Mocks + self.mock_get_latest_task_by_hash.return_value = None + self.mock_get_last_run_boefje.return_value = None + + # Act + self.scheduler.push_boefje_task(boefje_task) + + # Assert + self.assertEqual(1, self.scheduler.queue.qsize()) + + @mock.patch("scheduler.schedulers.BoefjeScheduler.has_boefje_task_started_running") + @mock.patch("scheduler.schedulers.BoefjeScheduler.has_boefje_permission_to_run") + @mock.patch("scheduler.schedulers.BoefjeScheduler.has_boefje_task_grace_period_passed") @mock.patch("scheduler.schedulers.BoefjeScheduler.is_item_on_queue_by_hash") @mock.patch("scheduler.context.AppContext.datastores.task_store.get_tasks_by_hash") def test_push_task_queue_full( self, mock_get_tasks_by_hash, mock_is_item_on_queue_by_hash, - mock_has_grace_period_passed, - mock_is_task_allowed_to_run, - mock_is_task_running, + mock_has_boefje_task_grace_period_passed, + mock_has_boefje_permission_to_run, + mock_has_boefje_task_started_running, ): """When the task queue is full, the task should not be pushed""" # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + + boefje_task = models.BoefjeTask( + boefje=models.Boefje.parse_obj(plugin.dict()), + input_ooi=ooi.primary_key, + organization=self.organisation.id, + ) self.scheduler.queue.maxsize = 1 self.scheduler.max_tries = 1 # Mocks - mock_is_task_allowed_to_run.return_value = True - mock_is_task_running.return_value = False - mock_has_grace_period_passed.return_value = True + mock_has_boefje_permission_to_run.return_value = True + mock_has_boefje_task_started_running.return_value = False + mock_has_boefje_task_grace_period_passed.return_value = True mock_is_item_on_queue_by_hash.return_value = False mock_get_tasks_by_hash.return_value = None # Act - self.scheduler.push_task(boefje, ooi) + self.scheduler.push_boefje_task(boefje_task) # Assert self.assertEqual(1, self.scheduler.queue.qsize()) with capture_logs() as cm: - self.scheduler.push_task(boefje, ooi) + self.scheduler.push_boefje_task(boefje_task) self.assertIn("Could not add task to queue, queue was full", cm[-1].get("event")) self.assertEqual(1, self.scheduler.queue.qsize()) - @mock.patch("scheduler.schedulers.BoefjeScheduler.is_task_stalled") - @mock.patch("scheduler.schedulers.BoefjeScheduler.is_task_running") - @mock.patch("scheduler.schedulers.BoefjeScheduler.is_task_allowed_to_run") - @mock.patch("scheduler.schedulers.BoefjeScheduler.has_grace_period_passed") + @mock.patch("scheduler.schedulers.BoefjeScheduler.has_boefje_task_stalled") + @mock.patch("scheduler.schedulers.BoefjeScheduler.has_boefje_task_started_running") + @mock.patch("scheduler.schedulers.BoefjeScheduler.has_boefje_permission_to_run") + @mock.patch("scheduler.schedulers.BoefjeScheduler.has_boefje_task_grace_period_passed") @mock.patch("scheduler.schedulers.BoefjeScheduler.is_item_on_queue_by_hash") @mock.patch("scheduler.context.AppContext.datastores.task_store.get_tasks_by_hash") def test_push_task_stalled( self, mock_get_tasks_by_hash, mock_is_item_on_queue_by_hash, - mock_has_grace_period_passed, - mock_is_task_allowed_to_run, - mock_is_task_running, - mock_is_task_stalled, + mock_has_boefje_task_grace_period_passed, + mock_has_boefje_permission_to_run, + mock_has_boefje_task_started_running, + mock_has_boefje_task_stalled, ): """When a task has stalled it should be set to failed.""" # Arrange @@ -718,92 +722,112 @@ def test_push_task_stalled( ooi = OOIFactory(scan_profile=scan_profile) boefje = BoefjeFactory() - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=boefje, input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = functions.create_p_item( + + task = models.Task( + scheduler_id=self.scheduler.scheduler_id, + priority=1, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), + created_at=datetime.now(timezone.utc), + modified_at=datetime.now(timezone.utc), + ) + + item = functions.create_item( scheduler_id=self.organisation.id, priority=1, - data=task, + task=task, ) # Act - self.scheduler.push_item_to_queue(p_item) + self.scheduler.push_item_to_queue(item) # Assert: task should be on priority queue task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) self.assertEqual(1, self.scheduler.queue.qsize()) self.assertEqual(ooi.primary_key, task_pq.input_ooi) - self.assertEqual(task.boefje.id, task_pq.boefje.id) + self.assertEqual(boefje_task.boefje.id, task_pq.boefje.id) # Assert: task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(p_item.id) - self.assertEqual(task_db.id, p_item.id) + task_db = self.mock_ctx.datastores.task_store.get_task(item.id) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.QUEUED) # Act self.scheduler.pop_item_from_queue() # Assert: task should be in datastore, and dispatched - task_db = self.mock_ctx.datastores.task_store.get_task(p_item.id) - self.assertEqual(task_db.id, p_item.id) + task_db = self.mock_ctx.datastores.task_store.get_task(item.id) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.DISPATCHED) # Mocks - mock_is_task_allowed_to_run.return_value = True - mock_has_grace_period_passed.return_value = True - mock_is_task_stalled.return_value = True - mock_is_task_running.return_value = False + mock_has_boefje_permission_to_run.return_value = True + mock_has_boefje_task_grace_period_passed.return_value = True + mock_has_boefje_task_stalled.return_value = True + mock_has_boefje_task_started_running.return_value = False self.mock_get_latest_task_by_hash.return_value = task_db mock_is_item_on_queue_by_hash.return_value = False mock_get_tasks_by_hash.return_value = None # Act - self.scheduler.push_task(boefje, ooi) + self.scheduler.push_boefje_task(boefje_task) # Assert: task should be in datastore, and failed - task_db = self.mock_ctx.datastores.task_store.get_task(p_item.id) - self.assertEqual(task_db.id, p_item.id) + task_db = self.mock_ctx.datastores.task_store.get_task(item.id) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.FAILED) # Assert: new task should be queued task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) self.assertEqual(1, self.scheduler.queue.qsize()) - - # Assert: task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(task_pq.id) - self.assertEqual(task_db.status, models.TaskStatus.QUEUED) + self.assertEqual(ooi.primary_key, task_pq.input_ooi) + self.assertEqual(boefje_task.boefje.id, task_pq.boefje.id) def test_post_push(self): """When a task is added to the queue, it should be added to the database""" # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=BoefjeFactory(), input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = functions.create_p_item( + + task = models.Task( + scheduler_id=self.scheduler.scheduler_id, + priority=1, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), + created_at=datetime.now(timezone.utc), + modified_at=datetime.now(timezone.utc), + ) + + item = functions.create_item( scheduler_id=self.organisation.id, priority=1, - data=task, + task=task, ) # Act - self.scheduler.push_item_to_queue(p_item) + self.scheduler.push_item_to_queue(item) # Task should be on priority queue task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) self.assertEqual(1, self.scheduler.queue.qsize()) self.assertEqual(ooi.primary_key, task_pq.input_ooi) - self.assertEqual(task.boefje.id, task_pq.boefje.id) + self.assertEqual(boefje_task.boefje.id, task_pq.boefje.id) # Task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(p_item.id) - self.assertEqual(task_db.id, p_item.id) + task_db = self.mock_ctx.datastores.task_store.get_task(item.id) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.QUEUED) def test_post_pop(self): @@ -811,37 +835,48 @@ def test_post_pop(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=BoefjeFactory(), input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = functions.create_p_item( + + task = models.Task( + scheduler_id=self.scheduler.scheduler_id, + priority=1, + type=models.BoefjeTask.type, + hash=boefje_task.hash, + data=boefje_task.model_dump(), + created_at=datetime.now(timezone.utc), + modified_at=datetime.now(timezone.utc), + ) + + item = functions.create_item( scheduler_id=self.organisation.id, priority=1, - data=task, + task=task, ) # Act - self.scheduler.push_item_to_queue(p_item) + self.scheduler.push_item_to_queue(item) # Assert: task should be on priority queue task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) self.assertEqual(1, self.scheduler.queue.qsize()) self.assertEqual(ooi.primary_key, task_pq.input_ooi) - self.assertEqual(task.boefje.id, task_pq.boefje.id) + self.assertEqual(boefje_task.boefje.id, task_pq.boefje.id) # Assert: task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(p_item.id) - self.assertEqual(task_db.id, p_item.id) + task_db = self.mock_ctx.datastores.task_store.get_task(item.id) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.QUEUED) # Act self.scheduler.pop_item_from_queue() - # Assert: task should be in datastore, and dispatched - task_db = self.mock_ctx.datastores.task_store.get_task(p_item.id) - self.assertEqual(task_db.id, p_item.id) + # Assert: task should be in datastore, and queued + task_db = self.mock_ctx.datastores.task_store.get_task(item.id) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.DISPATCHED) def test_disable_scheduler(self): @@ -851,26 +886,31 @@ def test_disable_scheduler(self): # Arrange: add tasks scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - task = models.BoefjeTask( + boefje_task = models.BoefjeTask( boefje=BoefjeFactory(), input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = functions.create_p_item( + task = functions.create_task( + scheduler_id=self.scheduler.scheduler_id, + data=boefje_task, + ) + + item = functions.create_item( scheduler_id=self.organisation.id, priority=1, - data=task, + task=task, ) - self.scheduler.push_item_to_queue(p_item) + self.scheduler.push_item_to_queue(item) # Assert: task should be on priority queue - pq_p_item = self.scheduler.queue.peek(0) + pq_item = self.scheduler.queue.peek(0) self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertEqual(pq_p_item.id, p_item.id) + self.assertEqual(pq_item.id, item.id) # Assert: task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(p_item.id) - self.assertEqual(task_db.id, p_item.id) + task_db = self.mock_ctx.datastores.task_store.get_task(item.id) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.QUEUED) # Assert: listeners should be running @@ -934,85 +974,85 @@ def test_enable_scheduler(self): # Stop the scheduler self.scheduler.stop() - def test_is_task_allowed_to_run(self): + def test_has_boefje_permission_to_run(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type]) # Act - is_allowed = self.scheduler.is_task_allowed_to_run(boefje, ooi) + is_allowed = self.scheduler.has_boefje_permission_to_run(plugin, ooi) # Assert self.assertTrue(is_allowed) - def test_is_task_allowed_to_run_boefje_disabled(self): + def test_has_boefje_permission_to_run_boefje_disabled(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=0, consumes=[ooi.object_type], enabled=False) + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type], enabled=False) # Act - is_allowed = self.scheduler.is_task_allowed_to_run(boefje, ooi) + is_allowed = self.scheduler.has_boefje_permission_to_run(plugin, ooi) # Assert self.assertFalse(is_allowed) - def test_is_task_allowed_to_run_scan_profile_is_none(self): + def test_has_boefje_permission_to_run_scan_profile_is_none(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type]) ooi.scan_profile = None # Act - is_allowed = self.scheduler.is_task_allowed_to_run(boefje, ooi) + is_allowed = self.scheduler.has_boefje_permission_to_run(plugin, ooi) # Assert self.assertFalse(is_allowed) - def test_is_task_allowed_to_run_ooi_scan_level_is_none(self): + def test_has_boefje_permission_to_run_ooi_scan_level_is_none(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type]) ooi.scan_profile.level = None # Act - is_allowed = self.scheduler.is_task_allowed_to_run(boefje, ooi) + is_allowed = self.scheduler.has_boefje_permission_to_run(plugin, ooi) # Assert self.assertFalse(is_allowed) - def test_is_task_allowed_to_run_boefje_scan_level_is_none(self): + def test_has_boefje_permission_to_run_boefje_scan_level_is_none(self): # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=None, consumes=[ooi.object_type]) + plugin = PluginFactory(scan_level=None, consumes=[ooi.object_type]) # Act - is_allowed = self.scheduler.is_task_allowed_to_run(boefje, ooi) + is_allowed = self.scheduler.has_boefje_permission_to_run(plugin, ooi) # Assert self.assertFalse(is_allowed) -class ScanProfileTestCase(BoefjeSchedulerBaseTestCase): +class ScanProfileMutationTestCase(BoefjeSchedulerBaseTestCase): def setUp(self): super().setUp() - self.mock_is_task_running = mock.patch( - "scheduler.schedulers.BoefjeScheduler.is_task_running", + self.mock_has_boefje_task_started_running = mock.patch( + "scheduler.schedulers.BoefjeScheduler.has_boefje_task_started_running", return_value=False, ).start() - self.mock_is_task_allowed_to_run = mock.patch( - "scheduler.schedulers.BoefjeScheduler.is_task_allowed_to_run", + self.mock_has_boefje_permission_to_run = mock.patch( + "scheduler.schedulers.BoefjeScheduler.has_boefje_permission_to_run", return_value=True, ).start() - self.mock_has_grace_period_passed = mock.patch( - "scheduler.schedulers.BoefjeScheduler.has_grace_period_passed", + self.mock_has_boefje_task_grace_period_passed = mock.patch( + "scheduler.schedulers.BoefjeScheduler.has_boefje_task_grace_period_passed", return_value=True, ).start() @@ -1020,6 +1060,9 @@ def setUp(self): "scheduler.schedulers.BoefjeScheduler.get_boefjes_for_ooi", ).start() + def tearDown(self): + mock.patch.stopall() + def test_push_tasks_for_scan_profile_mutations(self): """Scan level change""" # Arrange @@ -1037,14 +1080,15 @@ def test_push_tasks_for_scan_profile_mutations(self): self.scheduler.push_tasks_for_scan_profile_mutations(mutation) # Task should be on priority queue - task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) + item = self.scheduler.queue.peek(0) + task_pq = models.BoefjeTask(**item.data) self.assertEqual(1, self.scheduler.queue.qsize()) self.assertEqual(ooi.primary_key, task_pq.input_ooi) self.assertEqual(boefje.id, task_pq.boefje.id) # Task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(task_pq.id) - self.assertEqual(task_db.id, task_pq.id) + task_db = self.mock_ctx.datastores.task_store.get_task(item.id) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.QUEUED) def test_push_tasks_for_scan_profile_mutations_value_empty(self): @@ -1088,7 +1132,7 @@ def test_push_tasks_for_scan_profile_mutations_not_allowed_to_run(self): # Mocks self.mock_get_boefjes_for_ooi.return_value = [boefje] - self.mock_is_task_allowed_to_run.return_value = False + self.mock_has_boefje_permission_to_run.return_value = False # Act self.scheduler.push_tasks_for_scan_profile_mutations(mutation) @@ -1108,7 +1152,7 @@ def test_push_tasks_for_scan_profile_mutations_still_running(self): # Mocks self.mock_get_boefjes_for_ooi.return_value = [boefje] - self.mock_is_task_running.return_value = True + self.mock_has_boefje_task_started_running.return_value = True # Act self.scheduler.push_tasks_for_scan_profile_mutations(mutation) @@ -1137,17 +1181,17 @@ def test_push_tasks_for_scan_profile_mutations_item_on_queue(self): self.scheduler.push_tasks_for_scan_profile_mutations(mutation2) # Task should be on priority queue (only one) - task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) + task_pq = self.scheduler.queue.peek(0) + boefje_task_pq = models.BoefjeTask(**task_pq.data) self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertEqual(ooi.primary_key, task_pq.input_ooi) - self.assertEqual(boefje.id, task_pq.boefje.id) + self.assertEqual(ooi.primary_key, boefje_task_pq.input_ooi) + self.assertEqual(boefje.id, boefje_task_pq.boefje.id) # Task should be in datastore, and queued task_db = self.mock_ctx.datastores.task_store.get_task(task_pq.id) - self.assertEqual(task_db.id, task_pq.id) self.assertEqual(task_db.status, models.TaskStatus.QUEUED) - def test_push_task_for_scan_profile_mutations_delete(self): + def test_push_tasks_for_scan_profile_mutations_delete(self): """When an OOI is deleted it should not create tasks""" # Arrange scan_profile = ScanProfileFactory(level=0) @@ -1169,7 +1213,7 @@ def test_push_task_for_scan_profile_mutations_delete(self): # Assert self.assertEqual(0, self.scheduler.queue.qsize()) - def test_push_task_for_scan_profile_mutations_delete_on_queue(self): + def test_push_tasks_for_scan_profile_mutations_delete_on_queue(self): """When an OOI is deleted, and tasks associated with that ooi should be removed from the queue """ @@ -1184,32 +1228,20 @@ def test_push_task_for_scan_profile_mutations_delete_on_queue(self): value=ooi, ).model_dump_json() - mutation2 = models.ScanProfileMutation( - operation=models.MutationOperationType.CREATE, - primary_key=ooi.primary_key, - value=ooi, - ).model_dump_json() - - models.ScanProfileMutation( - operation=models.MutationOperationType.CREATE, - primary_key=ooi.primary_key, - value=ooi, - ).model_dump_json() - # Mocks self.mock_get_boefjes_for_ooi.return_value = [boefje] # Act self.scheduler.push_tasks_for_scan_profile_mutations(mutation1) - # Assert - task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) + # Assert: task should be on priority queue + item = self.scheduler.queue.peek(0) + task_pq = models.BoefjeTask(**item.data) self.assertEqual(1, self.scheduler.queue.qsize()) self.assertEqual(ooi.primary_key, task_pq.input_ooi) self.assertEqual(boefje.id, task_pq.boefje.id) # Arrange - ooi.scan_profile.level = 1 mutation2 = models.ScanProfileMutation( operation=models.MutationOperationType.DELETE, primary_key=ooi.primary_key, @@ -1225,7 +1257,7 @@ def test_push_task_for_scan_profile_mutations_delete_on_queue(self): self.assertEqual(ooi.primary_key, task_pq.input_ooi) self.assertEqual(boefje.id, task_pq.boefje.id) - task_db = self.mock_ctx.datastores.task_store.get_task(task_pq.id) + task_db = self.mock_ctx.datastores.task_store.get_task(item.id) self.assertEqual(task_db.status, models.TaskStatus.CANCELLED) @@ -1233,18 +1265,18 @@ class NewBoefjesTestCase(BoefjeSchedulerBaseTestCase): def setUp(self): super().setUp() - self.mock_is_task_running = mock.patch( - "scheduler.schedulers.BoefjeScheduler.is_task_running", + self.mock_has_boefje_task_started_running = mock.patch( + "scheduler.schedulers.BoefjeScheduler.has_boefje_task_started_running", return_value=False, ).start() - self.mock_is_task_allowed_to_run = mock.patch( - "scheduler.schedulers.BoefjeScheduler.is_task_allowed_to_run", + self.mock_has_boefje_permission_to_run = mock.patch( + "scheduler.schedulers.BoefjeScheduler.has_boefje_permission_to_run", return_value=True, ).start() - self.mock_has_grace_period_passed = mock.patch( - "scheduler.schedulers.BoefjeScheduler.has_grace_period_passed", + self.mock_has_boefje_task_grace_period_passed = mock.patch( + "scheduler.schedulers.BoefjeScheduler.has_boefje_task_grace_period_passed", return_value=True, ).start() @@ -1256,6 +1288,9 @@ def setUp(self): "scheduler.context.AppContext.services.octopoes.get_objects_by_object_types" ).start() + def tearDown(self): + mock.patch.stopall() + def test_push_tasks_for_new_boefjes(self): # Arrange scan_profile = ScanProfileFactory(level=0) @@ -1270,10 +1305,11 @@ def test_push_tasks_for_new_boefjes(self): self.scheduler.push_tasks_for_new_boefjes() # Task should be on priority queue - task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) + task_pq = self.scheduler.queue.peek(0) + boefje_task_pq = models.BoefjeTask(**task_pq.data) self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertEqual(ooi.primary_key, task_pq.input_ooi) - self.assertEqual(boefje.id, task_pq.boefje.id) + self.assertEqual(ooi.primary_key, boefje_task_pq.input_ooi) + self.assertEqual(boefje.id, boefje_task_pq.boefje.id) # Task should be in datastore, and queued task_db = self.mock_ctx.datastores.task_store.get_task(task_pq.id) @@ -1390,7 +1426,7 @@ def test_push_tasks_for_new_boefjes_not_allowed_to_run(self): # Mocks self.mock_get_objects_by_object_types.return_value = [ooi] self.mock_get_new_boefjes_by_org_id.return_value = [boefje] - self.mock_is_task_allowed_to_run.return_value = False + self.mock_has_boefje_permission_to_run.return_value = False # Act self.scheduler.push_tasks_for_new_boefjes() @@ -1407,7 +1443,7 @@ def test_push_tasks_for_new_boefjes_still_running(self): # Mocks self.mock_get_objects_by_object_types.return_value = [ooi] self.mock_get_new_boefjes_by_org_id.return_value = [boefje] - self.mock_is_task_running.return_value = True + self.mock_has_boefje_task_started_running.return_value = True # Act self.scheduler.push_tasks_for_new_boefjes() @@ -1429,10 +1465,11 @@ def test_push_tasks_for_new_boefjes_item_on_queue(self): self.scheduler.push_tasks_for_new_boefjes() # Task should be on priority queue - task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) + task_pq = self.scheduler.queue.peek(0) + boefje_task_pq = models.BoefjeTask(**task_pq.data) self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertEqual(ooi.primary_key, task_pq.input_ooi) - self.assertEqual(boefje.id, task_pq.boefje.id) + self.assertEqual(ooi.primary_key, boefje_task_pq.input_ooi) + self.assertEqual(boefje.id, boefje_task_pq.boefje.id) # Task should be in datastore, and queued task_db = self.mock_ctx.datastores.task_store.get_task(task_pq.id) @@ -1447,226 +1484,298 @@ def test_push_tasks_for_new_boefjes_item_on_queue(self): self.assertEqual(1, self.scheduler.queue.qsize()) -class RandomObjectsTestCase(BoefjeSchedulerBaseTestCase): +class RescheduleTestCase(BoefjeSchedulerBaseTestCase): def setUp(self): super().setUp() - self.mock_is_task_running = mock.patch( - "scheduler.schedulers.BoefjeScheduler.is_task_running", + self.mock_has_boefje_task_started_running = mock.patch( + "scheduler.schedulers.BoefjeScheduler.has_boefje_task_started_running", return_value=False, ).start() - self.mock_is_task_allowed_to_run = mock.patch( - "scheduler.schedulers.BoefjeScheduler.is_task_allowed_to_run", + self.mock_has_boefje_task_grace_period_passed = mock.patch( + "scheduler.schedulers.BoefjeScheduler.has_boefje_task_grace_period_passed", return_value=True, ).start() - self.mock_has_grace_period_passed = mock.patch( - "scheduler.schedulers.BoefjeScheduler.has_grace_period_passed", - return_value=True, + self.mock_get_schedules = mock.patch( + "scheduler.context.AppContext.datastores.schedule_store.get_schedules", ).start() - self.mock_get_boefjes_for_ooi = mock.patch("scheduler.schedulers.BoefjeScheduler.get_boefjes_for_ooi").start() + self.mock_get_object = mock.patch( + "scheduler.context.AppContext.services.octopoes.get_object", + ).start() - self.mock_get_random_objects = mock.patch( - "scheduler.context.AppContext.services.octopoes.get_random_objects" + self.mock_get_plugin = mock.patch( + "scheduler.context.AppContext.services.katalogus.get_plugin_by_id_and_org_id", ).start() - def test_push_tasks_for_random_objects(self): + def tearDown(self): + mock.patch.stopall() + + def test_push_tasks_for_rescheduling_scheduler_id(self): + pass + + def test_push_tasks_for_rescheduling(self): + """When the deadline of schedules have passed, the resulting task should be added to the queue""" # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + + boefje_task = models.BoefjeTask( + boefje=models.Boefje.parse_obj(plugin.model_dump()), + input_ooi=ooi.primary_key, + organization=self.organisation.id, + ) + + schedule = models.Schedule( + scheduler_id=self.scheduler.scheduler_id, + hash=boefje_task.hash, + data=boefje_task.model_dump(), + ) + + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) # Mocks - self.mock_get_random_objects.side_effect = [[ooi], [], [], []] - self.mock_get_boefjes_for_ooi.return_value = [boefje] + self.mock_get_schedules.return_value = ([schedule_db], 1) + self.mock_get_object.return_value = ooi + self.mock_get_plugin.return_value = plugin # Act - self.scheduler.push_tasks_for_random_objects() + self.scheduler.push_tasks_for_rescheduling() - # Task should be on priority queue - task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) + # Assert: new item should be on queue self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertEqual(ooi.primary_key, task_pq.input_ooi) - self.assertEqual(boefje.id, task_pq.boefje.id) - # Task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(task_pq.id) - self.assertEqual(task_db.id, task_pq.id) - self.assertEqual(task_db.status, models.TaskStatus.QUEUED) + # Assert: new item is created with a similar task + peek = self.scheduler.queue.peek(0) + self.assertEqual(schedule.hash, peek.hash) + + # Assert: task should be created, and should be the one that is queued + task_db = self.mock_ctx.datastores.task_store.get_task(peek.id) + self.assertIsNotNone(task_db) + self.assertEqual(peek.id, task_db.id) - def test_push_tasks_for_random_objects_queue_full(self): + def test_push_tasks_for_rescheduling_no_ooi(self): + """When the deadline has passed, and when the resulting tasks doesn't + have an OOI, it should create a task. + """ # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - PluginFactory(scan_level=0, consumes=[ooi.object_type]) - - self.scheduler.queue.maxsize = 1 - self.scheduler.max_tries = 1 + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type]) - self.scheduler.push_tasks_for_random_objects() - self.assertEqual(0, self.scheduler.queue.qsize()) - - # Act - self.scheduler.push_tasks_for_random_objects() + boefje_task = models.BoefjeTask( + boefje=models.Boefje.parse_obj(plugin.model_dump()), + input_ooi=ooi.primary_key, + organization=self.organisation.id, + ) - # Assert: task should not be on priority queue - self.assertEqual(0, self.scheduler.queue.qsize()) + schedule = models.Schedule( + scheduler_id=self.scheduler.scheduler_id, + hash=boefje_task.hash, + data=boefje_task.model_dump(), + ) - def test_push_tasks_for_random_objects_request_exception(self): - # Arrange - scan_profile = ScanProfileFactory(level=0) - ooi = OOIFactory(scan_profile=scan_profile) - PluginFactory(scan_level=0, consumes=[ooi.object_type]) + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) # Mocks - self.mock_get_random_objects.side_effect = [ - connectors.errors.ExternalServiceError("External service is not available."), - connectors.errors.ExternalServiceError("External service is not available."), - ] + self.mock_get_schedules.return_value = ([schedule_db], 1) + self.mock_get_object.return_value = ooi + self.mock_get_plugin.return_value = plugin # Act - self.scheduler.push_tasks_for_random_objects() - self.scheduler.push_tasks_for_random_objects() + self.scheduler.push_tasks_for_rescheduling() - # Assert: task should not be on priority queue - self.assertEqual(0, self.scheduler.queue.qsize()) + # Assert: new item should be on queue + self.assertEqual(1, self.scheduler.queue.qsize()) + + # Assert: new item is created with a similar task + peek = self.scheduler.queue.peek(0) + self.assertEqual(schedule_db.hash, peek.hash) - def test_push_tasks_for_random_objects_no_random_oois(self): + # Assert: task should be created, and should be the one that is queued + task_db = self.mock_ctx.datastores.task_store.get_task(peek.id) + self.assertIsNotNone(task_db) + self.assertEqual(peek.id, task_db.id) + + def test_push_tasks_for_rescheduling_ooi_not_found(self): + """When ooi isn't found anymore for the schedule, we disable the schedule""" # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - PluginFactory(scan_level=0, consumes=[ooi.object_type]) + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + + boefje_task = models.BoefjeTask( + boefje=models.Boefje.parse_obj(plugin.model_dump()), + input_ooi=ooi.primary_key, + organization=self.organisation.id, + ) + + schedule = models.Schedule( + scheduler_id=self.scheduler.scheduler_id, + hash=boefje_task.hash, + data=boefje_task.model_dump(), + ) + + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) # Mocks - self.mock_get_random_objects.return_value = [] + self.mock_get_schedules.return_value = ([schedule_db], 1) + self.mock_get_object.return_value = None + self.mock_get_plugin.return_value = plugin # Act - self.scheduler.push_tasks_for_random_objects() + self.scheduler.push_tasks_for_rescheduling() - # Assert: task should not be on priority queue + # Assert: item should not be on queue self.assertEqual(0, self.scheduler.queue.qsize()) - @mock.patch("scheduler.context.AppContext.datastores.task_store.get_tasks_by_hash") - def test_push_tasks_for_random_objects_prior_tasks(self, mock_get_tasks_by_hash): + # Assert: schedule should be disabled + schedule_db_disabled = self.mock_ctx.datastores.schedule_store.get_schedule(schedule.id) + self.assertFalse(schedule_db_disabled.enabled) + + def test_push_tasks_for_rescheduling_boefje_not_found(self): + """When boefje isn't found anymore for the schedule, we disable the schedule""" # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = BoefjeFactory() - task = models.BoefjeTask( - boefje=boefje, + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + + boefje_task = models.BoefjeTask( + boefje=models.Boefje.parse_obj(plugin.model_dump()), input_ooi=ooi.primary_key, organization=self.organisation.id, ) - p_item = models.PrioritizedItem( - id=task.id, + schedule = models.Schedule( scheduler_id=self.scheduler.scheduler_id, - priority=1, - data=task.model_dump(), - hash=task.hash, + hash=boefje_task.hash, + data=boefje_task.model_dump(), ) - task_db = models.Task( - id=p_item.id, - scheduler_id=self.scheduler.scheduler_id, - type="boefje", - p_item=p_item, - status=models.TaskStatus.COMPLETED, - created_at=datetime.now(timezone.utc), - modified_at=datetime.now(timezone.utc), - ) + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) # Mocks - self.mock_get_random_objects.side_effect = [[ooi], [], [], []] - self.mock_get_boefjes_for_ooi.return_value = [boefje] - - mock_get_tasks_by_hash.return_value = [task_db] + self.mock_get_schedules.return_value = ([schedule_db], 1) + self.mock_get_object.return_value = ooi + self.mock_get_plugin.return_value = None # Act - self.scheduler.push_tasks_for_random_objects() + self.scheduler.push_tasks_for_rescheduling() - # Task should be on priority queue - task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) - self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertEqual(ooi.primary_key, task_pq.input_ooi) - self.assertEqual(boefje.id, task_pq.boefje.id) + # Assert: item should not be on queue + self.assertEqual(0, self.scheduler.queue.qsize()) - # Task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(task_pq.id) - self.assertEqual(task_db.id, task_pq.id) - self.assertEqual(task_db.status, models.TaskStatus.QUEUED) + # Assert: schedule should be disabled + schedule_db_disabled = self.mock_ctx.datastores.schedule_store.get_schedule(schedule.id) + self.assertFalse(schedule_db_disabled.enabled) - def test_push_tasks_for_random_objects_no_boefjes_found(self): + def test_push_tasks_for_rescheduling_boefje_disabled(self): + """When boefje disabled for the schedule, we disable the schedule""" # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) + plugin = PluginFactory(scan_level=0, consumes=[ooi.object_type], enabled=False) - # Mocks - self.mock_get_random_objects.side_effect = [[ooi], [], [], []] - self.mock_get_boefjes_for_ooi.return_value = [] + boefje_task = models.BoefjeTask( + boefje=models.Boefje.parse_obj(plugin.model_dump()), + input_ooi=ooi.primary_key, + organization=self.organisation.id, + ) - # Act - self.scheduler.push_tasks_for_random_objects() + schedule = models.Schedule( + scheduler_id=self.scheduler.scheduler_id, + hash=boefje_task.hash, + data=boefje_task.model_dump(), + ) - # Task should not be on priority queue - self.assertEqual(0, self.scheduler.queue.qsize()) - - def test_push_tasks_for_random_objects_not_allowed_to_run(self): - # Arrange - scan_profile = ScanProfileFactory(level=0) - ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) # Mocks - self.mock_get_random_objects.side_effect = [[ooi], [], [], []] - self.mock_get_boefjes_for_ooi.return_value = [boefje] - self.mock_is_task_allowed_to_run.return_value = False + self.mock_get_schedules.return_value = ([schedule_db], 1) + self.mock_get_object.return_value = ooi + self.mock_get_plugin.return_value = plugin # Act - self.scheduler.push_tasks_for_random_objects() + self.scheduler.push_tasks_for_rescheduling() - # Task should not be on priority queue + # Assert: item should not be on queue self.assertEqual(0, self.scheduler.queue.qsize()) - def test_push_tasks_for_random_objects_still_running(self): + # Assert: schedule should be disabled + schedule_db_disabled = self.mock_ctx.datastores.schedule_store.get_schedule(schedule.id) + self.assertFalse(schedule_db_disabled.enabled) + + def test_push_tasks_for_rescheduling_boefje_doesnt_consume_ooi(self): + """When boefje doesn't consume the ooi, we disable the schedule""" # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + plugin = PluginFactory(scan_level=0, consumes=[]) + + boefje_task = models.BoefjeTask( + boefje=models.Boefje.parse_obj(plugin.model_dump()), + input_ooi=ooi.primary_key, + organization=self.organisation.id, + ) + + schedule = models.Schedule( + scheduler_id=self.scheduler.scheduler_id, + hash=boefje_task.hash, + data=boefje_task.model_dump(), + ) + + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) # Mocks - self.mock_get_random_objects.side_effect = [[ooi], [], [], []] - self.mock_get_boefjes_for_ooi.return_value = [boefje] - self.mock_is_task_running.return_value = True + self.mock_get_schedules.return_value = ([schedule_db], 1) + self.mock_get_object.return_value = ooi + self.mock_get_plugin.return_value = plugin # Act - self.scheduler.push_tasks_for_random_objects() + self.scheduler.push_tasks_for_rescheduling() - # Task should not be on priority queue + # Assert: item should not be on queue self.assertEqual(0, self.scheduler.queue.qsize()) - def test_push_tasks_for_random_objects_item_on_queue(self): + # Assert: schedule should be disabled + schedule_db_disabled = self.mock_ctx.datastores.schedule_store.get_schedule(schedule.id) + self.assertFalse(schedule_db_disabled.enabled) + + def test_push_tasks_for_rescheduling_boefje_cannot_scan_ooi(self): + """When boefje cannot scan the ooi, we disable the schedule""" # Arrange scan_profile = ScanProfileFactory(level=0) ooi = OOIFactory(scan_profile=scan_profile) - boefje = PluginFactory(scan_level=0, consumes=[ooi.object_type]) + plugin = PluginFactory(scan_level=1, consumes=[ooi.object_type]) + + boefje_task = models.BoefjeTask( + boefje=models.Boefje.parse_obj(plugin.model_dump()), + input_ooi=ooi.primary_key, + organization=self.organisation.id, + ) + + schedule = models.Schedule( + scheduler_id=self.scheduler.scheduler_id, + hash=boefje_task.hash, + data=boefje_task.model_dump(), + ) + + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) # Mocks - self.mock_get_random_objects.side_effect = [[ooi], [], [], []] - self.mock_get_boefjes_for_ooi.return_value = [boefje] + self.mock_get_schedules.return_value = ([schedule_db], 1) + self.mock_get_object.return_value = ooi + self.mock_get_plugin.return_value = plugin # Act - self.scheduler.push_tasks_for_random_objects() + self.scheduler.push_tasks_for_rescheduling() - # Task should be on priority queue - task_pq = models.BoefjeTask(**self.scheduler.queue.peek(0).data) - self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertEqual(ooi.primary_key, task_pq.input_ooi) - self.assertEqual(boefje.id, task_pq.boefje.id) + # Assert: item should not be on queue + self.assertEqual(0, self.scheduler.queue.qsize()) - # Task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(task_pq.id) - self.assertEqual(task_db.id, task_pq.id) - self.assertEqual(task_db.status, models.TaskStatus.QUEUED) + # Assert: schedule should be disabled + schedule_db_disabled = self.mock_ctx.datastores.schedule_store.get_schedule(schedule.id) + self.assertFalse(schedule_db_disabled.enabled) diff --git a/mula/tests/integration/test_normalizer_scheduler.py b/mula/tests/integration/test_normalizer_scheduler.py index a55eb9548d8..27ee59b6ccd 100644 --- a/mula/tests/integration/test_normalizer_scheduler.py +++ b/mula/tests/integration/test_normalizer_scheduler.py @@ -35,6 +35,7 @@ def setUp(self): **{ storage.TaskStore.name: storage.TaskStore(self.dbconn), storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn), + storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn), } ) @@ -60,6 +61,10 @@ def setUp(self): "scheduler.context.AppContext.datastores.task_store.get_latest_task_by_hash" ).start() + self.mock_get_plugin = mock.patch( + "scheduler.context.AppContext.services.katalogus.get_plugin_by_id_and_org_id", + ).start() + def test_disable_scheduler(self): # Act self.scheduler.disable() @@ -113,24 +118,30 @@ def test_enable_scheduler(self): def test_is_allowed_to_run(self): # Arrange - normalizer = PluginFactory() + plugin = PluginFactory(type="normalizer", consumes=["text/plain"]) + + # Mocks + self.mock_get_plugin.return_value = plugin # Act - result = self.scheduler.is_task_allowed_to_run(normalizer) + allowed_to_run = self.scheduler.has_normalizer_permission_to_run(plugin) # Assert - self.assertTrue(result) + self.assertTrue(allowed_to_run) def test_is_not_allowed_to_run(self): # Arrange - normalizer = PluginFactory() - normalizer.enabled = False + plugin = PluginFactory(type="normalizer", consumes=["text/plain"]) + plugin.enabled = False + + # Mocks + self.mock_get_plugin.return_value = plugin # Act - result = self.scheduler.is_task_allowed_to_run(normalizer) + allowed_to_run = self.scheduler.has_normalizer_permission_to_run(plugin) # Assert - self.assertFalse(result) + self.assertFalse(allowed_to_run) @mock.patch("scheduler.context.AppContext.services.katalogus.get_normalizers_by_org_id_and_type") def test_get_normalizers_for_mime_type(self, mock_get_normalizers_by_org_id_and_type): @@ -177,13 +188,13 @@ class RawFileReceivedTestCase(NormalizerSchedulerBaseTestCase): def setUp(self): super().setUp() - self.mock_is_task_running = mock.patch( - "scheduler.schedulers.NormalizerScheduler.is_task_running", + self.mock_has_normalizer_task_started_running = mock.patch( + "scheduler.schedulers.NormalizerScheduler.has_normalizer_task_started_running", return_value=False, ).start() - self.mock_is_task_allowed_to_run = mock.patch( - "scheduler.schedulers.NormalizerScheduler.is_task_allowed_to_run", + self.mock_has_normalizer_permission_to_run = mock.patch( + "scheduler.schedulers.NormalizerScheduler.has_normalizer_permission_to_run", return_value=True, ).start() @@ -193,25 +204,14 @@ def setUp(self): def test_push_tasks_for_received_raw_file(self): # Arrange - scan_profile = ScanProfileFactory(level=0) - ooi = OOIFactory(scan_profile=scan_profile) + ooi = OOIFactory(scan_profile=ScanProfileFactory(level=0)) boefje = BoefjeFactory() - boefje_task = models.BoefjeTask( - boefje=boefje, - input_ooi=ooi.primary_key, - organization=self.organisation.id, - ) - - p_item = functions.create_p_item(scheduler_id=self.scheduler.scheduler_id, priority=1, data=boefje_task) - task = functions.create_task(p_item) - self.mock_ctx.datastores.task_store.create_task(task) - boefje_meta = BoefjeMetaFactory( - id=p_item.id, boefje=boefje, input_ooi=ooi.primary_key, ) + # Arrange: create the RawDataReceivedEvent raw_data_event = models.RawDataReceivedEvent( raw_data=RawDataFactory( boefje_meta=boefje_meta, @@ -222,15 +222,14 @@ def test_push_tasks_for_received_raw_file(self): ).model_dump_json() # Mocks - self.mock_get_normalizers_for_mime_type.return_value = [ - NormalizerFactory(), - ] + plugin = PluginFactory(type="normalizer", consumes=["text/plain"]) + self.mock_get_normalizers_for_mime_type.return_value = [plugin] # Act self.scheduler.push_tasks_for_received_raw_data(raw_data_event) # Task should be on priority queue - task_pq = models.NormalizerTask(**self.scheduler.queue.peek(0).data) + task_pq = self.scheduler.queue.peek(0) self.assertEqual(1, self.scheduler.queue.qsize()) # Task should be in datastore @@ -240,21 +239,9 @@ def test_push_tasks_for_received_raw_file(self): def test_push_tasks_for_received_raw_file_no_normalizers_found(self): # Arrange - scan_profile = ScanProfileFactory(level=0) - ooi = OOIFactory(scan_profile=scan_profile) + ooi = OOIFactory(scan_profile=ScanProfileFactory(level=0)) boefje = BoefjeFactory() - boefje_task = models.BoefjeTask( - boefje=boefje, - input_ooi=ooi.primary_key, - organization=self.organisation.id, - ) - - p_item = functions.create_p_item(scheduler_id=self.scheduler.scheduler_id, priority=1, data=boefje_task) - task = functions.create_task(p_item) - self.mock_ctx.datastores.task_store.create_task(task) - boefje_meta = BoefjeMetaFactory( - id=p_item.id, boefje=boefje, input_ooi=ooi.primary_key, ) @@ -288,12 +275,13 @@ def test_push_tasks_for_received_raw_file_not_allowed_to_run(self): organization=self.organisation.id, ) - p_item = functions.create_p_item(scheduler_id=self.scheduler.scheduler_id, priority=1, data=boefje_task) - task = functions.create_task(p_item) + task = functions.create_task( + scheduler_id=self.scheduler.scheduler_id, + data=boefje_task, + ) self.mock_ctx.datastores.task_store.create_task(task) boefje_meta = BoefjeMetaFactory( - id=p_item.id, boefje=boefje, input_ooi=ooi.primary_key, ) @@ -311,7 +299,7 @@ def test_push_tasks_for_received_raw_file_not_allowed_to_run(self): self.mock_get_normalizers_for_mime_type.return_value = [ NormalizerFactory(), ] - self.mock_is_task_allowed_to_run.return_value = False + self.mock_has_normalizer_permission_to_run.return_value = False # Act self.scheduler.push_tasks_for_received_raw_data(raw_data_event) @@ -330,12 +318,13 @@ def test_push_tasks_for_received_raw_file_still_running(self): organization=self.organisation.id, ) - p_item = functions.create_p_item(scheduler_id=self.scheduler.scheduler_id, priority=1, data=boefje_task) - task = functions.create_task(p_item) + task = functions.create_task( + scheduler_id=self.scheduler.scheduler_id, + data=boefje_task, + ) self.mock_ctx.datastores.task_store.create_task(task) boefje_meta = BoefjeMetaFactory( - id=p_item.id, boefje=boefje, input_ooi=ooi.primary_key, ) @@ -353,8 +342,8 @@ def test_push_tasks_for_received_raw_file_still_running(self): self.mock_get_normalizers_for_mime_type.return_value = [ NormalizerFactory(), ] - self.mock_is_task_allowed_to_run.return_value = True - self.mock_is_task_running.return_value = True + self.mock_has_normalizer_permission_to_run.return_value = True + self.mock_has_normalizer_task_started_running.return_value = True # Act self.scheduler.push_tasks_for_received_raw_data(raw_data_event) @@ -373,12 +362,13 @@ def test_push_tasks_for_received_raw_file_still_running_exception(self): organization=self.organisation.id, ) - p_item = functions.create_p_item(scheduler_id=self.scheduler.scheduler_id, priority=1, data=boefje_task) - task = functions.create_task(p_item) + task = functions.create_task( + scheduler_id=self.scheduler.scheduler_id, + data=boefje_task, + ) self.mock_ctx.datastores.task_store.create_task(task) boefje_meta = BoefjeMetaFactory( - id=p_item.id, boefje=boefje, input_ooi=ooi.primary_key, ) @@ -396,8 +386,8 @@ def test_push_tasks_for_received_raw_file_still_running_exception(self): self.mock_get_normalizers_for_mime_type.return_value = [ NormalizerFactory(), ] - self.mock_is_task_allowed_to_run.return_value = True - self.mock_is_task_running.side_effect = Exception("Something went wrong") + self.mock_has_normalizer_permission_to_run.return_value = True + self.mock_has_normalizer_task_started_running.side_effect = Exception("Something went wrong") # Act self.scheduler.push_tasks_for_received_raw_data(raw_data_event) @@ -407,26 +397,13 @@ def test_push_tasks_for_received_raw_file_still_running_exception(self): def test_push_tasks_for_received_raw_file_item_on_queue(self): # Arrange - scan_profile = ScanProfileFactory(level=0) - ooi = OOIFactory(scan_profile=scan_profile) + ooi = OOIFactory(scan_profile=ScanProfileFactory(level=0)) boefje = BoefjeFactory() - boefje_task = models.BoefjeTask( - boefje=boefje, - input_ooi=ooi.primary_key, - organization=self.organisation.id, - ) - - p_item = functions.create_p_item(scheduler_id=self.scheduler.scheduler_id, priority=1, data=boefje_task) - task = functions.create_task(p_item) - self.mock_ctx.datastores.task_store.create_task(task) - boefje_meta = BoefjeMetaFactory( - id=p_item.id, boefje=boefje, input_ooi=ooi.primary_key, ) - # Mocks raw_data_event1 = models.RawDataReceivedEvent( raw_data=RawDataFactory( boefje_meta=boefje_meta, @@ -445,6 +422,7 @@ def test_push_tasks_for_received_raw_file_item_on_queue(self): created_at=datetime.datetime.now(), ).model_dump_json() + # Mocks self.mock_get_normalizers_for_mime_type.return_value = [ NormalizerFactory(), ] @@ -454,10 +432,10 @@ def test_push_tasks_for_received_raw_file_item_on_queue(self): self.scheduler.push_tasks_for_received_raw_data(raw_data_event2) # Task should be on priority queue (only one) - task_pq = models.NormalizerTask(**self.scheduler.queue.peek(0).data) + task_pq = self.scheduler.queue.peek(0) self.assertEqual(1, self.scheduler.queue.qsize()) - # Task should be in datastore + # Task should be in datastore, and queued task_db = self.mock_ctx.datastores.task_store.get_task(task_pq.id) self.assertEqual(task_db.id, task_pq.id) self.assertEqual(task_db.status, models.TaskStatus.QUEUED) @@ -473,12 +451,13 @@ def test_push_tasks_for_received_raw_file_error_mimetype(self): organization=self.organisation.id, ) - p_item = functions.create_p_item(scheduler_id=self.scheduler.scheduler_id, priority=1, data=boefje_task) - task = functions.create_task(p_item) + task = functions.create_task( + scheduler_id=self.scheduler.scheduler_id, + data=boefje_task, + ) self.mock_ctx.datastores.task_store.create_task(task) boefje_meta = BoefjeMetaFactory( - id=p_item.id, boefje=boefje, input_ooi=ooi.primary_key, ) @@ -510,13 +489,13 @@ def test_push_tasks_for_received_raw_file_queue_full(self): input_ooi=ooi.primary_key, organization=self.organisation.id, ) - - p_item = functions.create_p_item(scheduler_id=self.scheduler.scheduler_id, priority=1, data=boefje_task) - task = functions.create_task(p_item) + task = functions.create_task( + scheduler_id=self.scheduler.scheduler_id, + data=boefje_task, + ) self.mock_ctx.datastores.task_store.create_task(task) boefje_meta = BoefjeMetaFactory( - id=p_item.id, boefje=boefje, input_ooi=ooi.primary_key, ) diff --git a/mula/tests/integration/test_pq_store.py b/mula/tests/integration/test_pq_store.py new file mode 100644 index 00000000000..6ebefce88ce --- /dev/null +++ b/mula/tests/integration/test_pq_store.py @@ -0,0 +1,84 @@ +import unittest +import uuid +from types import SimpleNamespace +from unittest import mock + +from scheduler import config, models, storage + +from tests.factories import OrganisationFactory +from tests.utils import functions + + +class PriorityQueueStoreTestCase(unittest.TestCase): + def setUp(self): + # Application Context + self.mock_ctx = mock.patch("scheduler.context.AppContext").start() + self.mock_ctx.config = config.settings.Settings() + + # Database + self.dbconn = storage.DBConn(str(self.mock_ctx.config.db_uri)) + self.dbconn.connect() + models.Base.metadata.drop_all(self.dbconn.engine) + models.Base.metadata.create_all(self.dbconn.engine) + + self.mock_ctx.datastores = SimpleNamespace( + **{ + storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn), + storage.TaskStore.name: storage.TaskStore(self.dbconn), + } + ) + + # Organisation + self.organisation = OrganisationFactory() + + def tearDown(self): + models.Base.metadata.drop_all(self.dbconn.engine) + self.dbconn.engine.dispose() + + def test_push(self): + # Arrange + item = functions.create_item(scheduler_id=uuid.uuid4().hex, priority=1) + item.status = models.TaskStatus.QUEUED + created_item = self.mock_ctx.datastores.pq_store.push(item) + + item_db = self.mock_ctx.datastores.pq_store.get(scheduler_id=item.scheduler_id, item_id=item.id) + + # Assert + self.assertIsNotNone(created_item) + self.assertIsNotNone(item_db) + self.assertEqual(item_db.id, created_item.id) + + def test_push_status_not_queued(self): + item = functions.create_item(scheduler_id=uuid.uuid4().hex, priority=1) + item.status = models.TaskStatus.PENDING + created_item = self.mock_ctx.datastores.pq_store.push(item) + + item_db = self.mock_ctx.datastores.pq_store.get(scheduler_id=item.scheduler_id, item_id=item.id) + + # Assert + self.assertIsNotNone(created_item) + self.assertIsNone(item_db) + + def test_pop(self): + # Arrange + item = functions.create_item(scheduler_id=uuid.uuid4().hex, priority=1) + item.status = models.TaskStatus.QUEUED + created_item = self.mock_ctx.datastores.pq_store.push(item) + + popped_item = self.mock_ctx.datastores.pq_store.pop(item.scheduler_id) + + # Assert + self.assertIsNotNone(popped_item) + self.assertEqual(popped_item.id, created_item.id) + + def test_pop_status_not_queued(self): + # Arrange + item = functions.create_item(scheduler_id=uuid.uuid4().hex, priority=1) + item.status = models.TaskStatus.PENDING + created_item = self.mock_ctx.datastores.pq_store.push(item) + + popped_item = self.mock_ctx.datastores.pq_store.pop(item.scheduler_id) + + # Assert + self.assertIsNotNone(created_item) + self.assertIsNone(popped_item) diff --git a/mula/tests/integration/test_schedule_store.py b/mula/tests/integration/test_schedule_store.py new file mode 100644 index 00000000000..9fa884bb61a --- /dev/null +++ b/mula/tests/integration/test_schedule_store.py @@ -0,0 +1,258 @@ +import unittest +from types import SimpleNamespace +from unittest import mock + +from scheduler import config, models, storage +from scheduler.storage import filters + +from tests.utils import functions + + +class ScheduleStoreTestCase(unittest.TestCase): + def setUp(self): + # Application Context + self.mock_ctx = mock.patch("scheduler.context.AppContext").start() + self.mock_ctx.config = config.settings.Settings() + + # Database + self.dbconn = storage.DBConn(str(self.mock_ctx.config.db_uri)) + self.dbconn.connect() + models.Base.metadata.drop_all(self.dbconn.engine) + models.Base.metadata.create_all(self.dbconn.engine) + + self.mock_ctx.datastores = SimpleNamespace( + **{ + storage.TaskStore.name: storage.TaskStore(self.dbconn), + storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn), + } + ) + + def tearDown(self): + models.Base.metadata.drop_all(self.dbconn.engine) + self.dbconn.engine.dispose() + + def test_create_schedule(self): + # Arrange + scheduler_id = "test_scheduler_id" + + task = functions.create_item(scheduler_id, 1) + schedule = models.Schedule( + scheduler_id=scheduler_id, + hash=task.hash, + data=task.model_dump(), + ) + + # Act + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + # Assert + self.assertEqual(schedule, schedule_db) + + def test_get_schedules(self): + # Arrange + scheduler_one = "test_scheduler_one" + for i in range(5): + task = functions.create_item(scheduler_one, 1) + schedule = models.Schedule( + scheduler_id=scheduler_one, + hash=task.hash, + data=task.model_dump(), + ) + self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + scheduler_two = "test_scheduler_two" + for i in range(5): + task = functions.create_item(scheduler_two, 1) + schedule = models.Schedule( + scheduler_id=scheduler_two, + hash=task.hash, + data=task.model_dump(), + ) + self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + schedules_scheduler_one, schedules_scheduler_one_count = self.mock_ctx.datastores.schedule_store.get_schedules( + filters=storage.filters.FilterRequest( + filters={ + "and": [ + storage.filters.Filter( + column="scheduler_id", + operator="eq", + value=scheduler_one, + ) + ] + } + ) + ) + schedules_scheduler_two, schedules_scheduler_two_count = self.mock_ctx.datastores.schedule_store.get_schedules( + filters=storage.filters.FilterRequest( + filters={ + "and": [ + storage.filters.Filter( + column="scheduler_id", + operator="eq", + value=scheduler_two, + ) + ] + } + ) + ) + + # Assert + self.assertEqual(5, len(schedules_scheduler_one)) + self.assertEqual(5, schedules_scheduler_one_count) + self.assertEqual(5, len(schedules_scheduler_two)) + self.assertEqual(5, schedules_scheduler_two_count) + + def test_get_schedule(self): + # Arrange + scheduler_id = "test_scheduler_id" + task = functions.create_item(scheduler_id, 1) + schedule = models.Schedule( + scheduler_id=scheduler_id, + hash=task.hash, + data=task.model_dump(), + ) + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + # Act + schedule_by_id = self.mock_ctx.datastores.schedule_store.get_schedule(schedule_db.id) + + # Assert + self.assertEqual(schedule_by_id.id, schedule_db.id) + + def test_get_schedule_by_hash(self): + # Arrange + scheduler_id = "test_scheduler_id" + data = functions.create_test_model() + schedule = models.Schedule( + scheduler_id=scheduler_id, + hash=data.hash, + data=data.model_dump(), + ) + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + # Act + schedule_by_hash = self.mock_ctx.datastores.schedule_store.get_schedule_by_hash(schedule_db.hash) + + # Assert + self.assertEqual(schedule_by_hash.id, schedule_db.id) + self.assertEqual(schedule_by_hash.data, schedule_db.data) + self.assertEqual(schedule_by_hash.hash, schedule_db.hash) + + def test_update_schedule(self): + # Arrange + scheduler_id = "test_scheduler_id" + task = functions.create_item(scheduler_id, 1) + schedule = models.Schedule( + scheduler_id=scheduler_id, + hash=task.hash, + data=task.model_dump(), + ) + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + # Assert + self.assertEqual(schedule_db.enabled, True) + + # Act + schedule_db.enabled = False + self.mock_ctx.datastores.schedule_store.update_schedule(schedule_db) + + # Assert + schedule_db_updated = self.mock_ctx.datastores.schedule_store.get_schedule(schedule_db.id) + self.assertEqual(schedule_db_updated.enabled, False) + + def test_delete_schedule(self): + # Arrange + scheduler_id = "test_scheduler_id" + task = functions.create_item(scheduler_id, 1) + schedule = models.Schedule( + scheduler_id=scheduler_id, + hash=task.hash, + data=task.model_dump(), + ) + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + # Act + self.mock_ctx.datastores.schedule_store.delete_schedule(schedule_db.id) + + # Assert + is_schedule_deleted = self.mock_ctx.datastores.schedule_store.get_schedule(schedule_db.id) + self.assertEqual(is_schedule_deleted, None) + + def test_delete_schedule_ondelete(self): + """When a schedule is deleted, its tasks should NOT be deleted.""" + # Arrange + scheduler_id = "test_scheduler_id" + task = functions.create_item(scheduler_id, 1) + schedule = models.Schedule( + scheduler_id=scheduler_id, + hash=task.hash, + data=task.model_dump(), + ) + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + task.schedule_id = schedule_db.id + task_db = self.mock_ctx.datastores.task_store.create_task(task) + + # Act + self.mock_ctx.datastores.schedule_store.delete_schedule(schedule_db.id) + + # Assert + is_schedule_deleted = self.mock_ctx.datastores.schedule_store.get_schedule(schedule_db.id) + self.assertEqual(is_schedule_deleted, None) + + is_task_deleted = self.mock_ctx.datastores.task_store.get_task(task_db.id) + self.assertIsNotNone(is_task_deleted) + self.assertIsNone(is_task_deleted.schedule_id) + + def test_relationship_schedule_tasks(self): + # Arrange + scheduler_id = "test_scheduler_id" + task = functions.create_task(scheduler_id) + schedule = models.Schedule( + scheduler_id=scheduler_id, + hash=task.hash, + data=task.model_dump(), + ) + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + task.schedule_id = schedule_db.id + task_db = self.mock_ctx.datastores.task_store.create_task(task) + + # Act + schedule_tasks = self.mock_ctx.datastores.schedule_store.get_schedule(schedule_db.id).tasks + + # Assert + self.assertEqual(len(schedule_tasks), 1) + self.assertEqual(schedule_tasks[0].id, task_db.id) + + def test_get_tasks_filter_related(self): + # Arrange + scheduler_id = "test_scheduler_id" + task = functions.create_task(scheduler_id) + schedule = models.Schedule( + scheduler_id=scheduler_id, + hash=task.hash, + data=task.model_dump(), + ) + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + task.schedule_id = schedule_db.id + created_task = self.mock_ctx.datastores.task_store.create_task(task) + + f_req = filters.FilterRequest( + filters={ + "and": [ + filters.Filter( + column="id", + operator="eq", + value=created_task.id.hex, + ), + ] + } + ) + + tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) + self.assertEqual(count, 1) + self.assertEqual(len(tasks), 1) + self.assertEqual(tasks[0].schedule_id, schedule_db.id) diff --git a/mula/tests/integration/test_scheduler.py b/mula/tests/integration/test_scheduler.py index ebec8d990b6..3f347045fe3 100644 --- a/mula/tests/integration/test_scheduler.py +++ b/mula/tests/integration/test_scheduler.py @@ -1,13 +1,15 @@ import unittest import uuid +from datetime import datetime, timezone from types import SimpleNamespace from unittest import mock from scheduler import config, models, queues, storage +from structlog.testing import capture_logs +from tests.mocks import item as mock_item from tests.mocks import queue as mock_queue from tests.mocks import scheduler as mock_scheduler -from tests.mocks import task as mock_task from tests.utils import functions @@ -15,10 +17,10 @@ class SchedulerTestCase(unittest.TestCase): def setUp(self): # Application Context self.mock_ctx = mock.patch("scheduler.context.AppContext").start() - cfg = config.settings.Settings() + self.mock_ctx.config = config.settings.Settings() # Database - self.dbconn = storage.DBConn(str(cfg.db_uri)) + self.dbconn = storage.DBConn(str(self.mock_ctx.config.db_uri)) self.dbconn.connect() models.Base.metadata.drop_all(self.dbconn.engine) models.Base.metadata.create_all(self.dbconn.engine) @@ -27,6 +29,7 @@ def setUp(self): **{ storage.TaskStore.name: storage.TaskStore(self.dbconn), storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn), + storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn), } ) @@ -34,8 +37,8 @@ def setUp(self): queue = mock_queue.MockPriorityQueue( pq_id=identifier, - maxsize=cfg.pq_maxsize, - item_type=mock_task.MockTask, + maxsize=self.mock_ctx.config.pq_maxsize, + item_type=mock_item.MockData, allow_priority_updates=True, pq_store=self.mock_ctx.datastores.pq_store, ) @@ -44,6 +47,7 @@ def setUp(self): ctx=self.mock_ctx, scheduler_id=identifier, queue=queue, + create_schedule=True, ) def tearDown(self): @@ -51,46 +55,299 @@ def tearDown(self): models.Base.metadata.drop_all(self.dbconn.engine) self.dbconn.engine.dispose() - def test_post_push(self): - """When a task is added to the queue, it should be added to the database""" + def test_push_items_to_queue(self): + # Arrange + items = [] + for i in range(10): + item = functions.create_item( + scheduler_id=self.scheduler.scheduler_id, + priority=i + 1, + ) + items.append(item) + + # Act + self.scheduler.push_items_to_queue(items) + + # Assert + self.assertEqual(10, self.scheduler.queue.qsize()) + + for i, item in enumerate(items): + # Task should be on priority queue + pq_item = self.scheduler.queue.peek(i) + self.assertEqual(pq_item.id, item.id) + + # Task should be in datastore, and queued + task_db = self.mock_ctx.datastores.task_store.get_task(str(item.id)) + self.assertEqual(task_db.id, item.id) + self.assertEqual(task_db.status, models.TaskStatus.QUEUED) + + # Schedule should be in datastore + schedule_db = self.mock_ctx.datastores.schedule_store.get_schedule(task_db.schedule_id) + self.assertIsNotNone(schedule_db) + self.assertEqual(schedule_db.id, task_db.schedule_id) + + def test_push_item_to_queue(self): # Arrange - p_item = functions.create_p_item( + item = functions.create_item( scheduler_id=self.scheduler.scheduler_id, priority=1, ) # Act - self.scheduler.push_item_to_queue(p_item) + self.scheduler.push_item_to_queue(item) # Task should be on priority queue - pq_p_item = self.scheduler.queue.peek(0) + pq_item = self.scheduler.queue.peek(0) self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertEqual(pq_p_item.id, p_item.id) + self.assertEqual(pq_item.id, item.id) # Task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(p_item.id) - self.assertEqual(task_db.id, p_item.id) + task_db = self.mock_ctx.datastores.task_store.get_task(str(item.id)) + self.assertEqual(task_db.id, item.id) + self.assertEqual(task_db.status, models.TaskStatus.QUEUED) + + # Schedule should be in datastore + schedule_db = self.mock_ctx.datastores.schedule_store.get_schedule(task_db.schedule_id) + self.assertIsNotNone(schedule_db) + self.assertEqual(schedule_db.id, task_db.schedule_id) + + def test_push_item_to_queue_create_schedule_false(self): + # Arrange + self.scheduler.create_schedule = False + + item = functions.create_item( + scheduler_id=self.scheduler.scheduler_id, + priority=1, + ) + + # Act + self.scheduler.push_item_to_queue(item) + + # Task should be on priority queue + pq_item = self.scheduler.queue.peek(0) + self.assertEqual(1, self.scheduler.queue.qsize()) + self.assertEqual(pq_item.id, item.id) + + # Task should be in datastore, and queued + task_db = self.mock_ctx.datastores.task_store.get_task(str(item.id)) + self.assertEqual(task_db.id, item.id) + self.assertEqual(task_db.status, models.TaskStatus.QUEUED) + self.assertIsNone(task_db.schedule_id) + + # Schedule should not be in datastore + schedule_db = self.mock_ctx.datastores.schedule_store.get_schedule_by_hash( + task_db.hash, + ) + self.assertIsNone(schedule_db) + + def test_push_item_to_queue_full(self): + # Arrange + item = functions.create_item( + scheduler_id=self.scheduler.scheduler_id, + priority=1, + ) + + self.scheduler.queue.maxsize = 1 + + # Act + self.scheduler.push_item_to_queue_with_timeout(item=item, max_tries=1) + + # Assert + self.assertEqual(1, self.scheduler.queue.qsize()) + + with self.assertRaises(queues.errors.QueueFullError): + self.scheduler.push_item_to_queue_with_timeout(item=item, max_tries=1) + + self.assertEqual(1, self.scheduler.queue.qsize()) + + def test_push_item_to_queue_invalid(self): + # Arrange + item = functions.create_item( + scheduler_id=self.scheduler.scheduler_id, + priority=1, + ) + item.data = {"invalid": "data"} + + # Assert + with self.assertRaises(queues.errors.InvalidItemError): + self.scheduler.push_item_to_queue(item) + + def test_pop_item_from_queue(self): + # Arrange + item = functions.create_item( + scheduler_id=self.scheduler.scheduler_id, + priority=1, + ) + + self.scheduler.push_item_to_queue(item) + + # Act + popped_item = self.scheduler.pop_item_from_queue() + + # Assert + self.assertEqual(0, self.scheduler.queue.qsize()) + self.assertEqual(item.id, popped_item.id) + + def test_pop_item_from_queue_empty(self): + self.assertEqual(0, self.scheduler.queue.qsize()) + with self.assertRaises(queues.errors.QueueEmptyError): + self.scheduler.pop_item_from_queue() + + def test_post_push(self): + """When a task is added to the queue, it should be added to the database""" + # Arrange + item = functions.create_item( + scheduler_id=self.scheduler.scheduler_id, + priority=1, + ) + + # Act + self.scheduler.push_item_to_queue(item) + + # Assert: Task should be on priority queue + pq_item = self.scheduler.queue.peek(0) + self.assertEqual(1, self.scheduler.queue.qsize()) + self.assertEqual(pq_item.id, item.id) + + # Assert: Task should be in datastore, and queued + task_db = self.mock_ctx.datastores.task_store.get_task(str(item.id)) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.QUEUED) + # Assert: Schedule should be in datastore + schedule_db = self.mock_ctx.datastores.schedule_store.get_schedule(task_db.schedule_id) + self.assertIsNotNone(schedule_db) + self.assertEqual(schedule_db.id, task_db.schedule_id) + + # Assert: schedule should have a deadline + self.assertIsNotNone(schedule_db.deadline_at) + self.assertIsNotNone(schedule_db.schedule) + + # Assert: deadline should be in the future, at least later than the + # grace period + self.assertGreater( + schedule_db.deadline_at, + datetime.now(timezone.utc), + ) + + def test_post_push_schedule_enabled(self): + # Arrange + item = functions.create_item( + scheduler_id=self.scheduler.scheduler_id, + priority=1, + ) + + # Act + self.scheduler.push_item_to_queue(item) + + # Assert: Task should be on priority queue + pq_item = self.scheduler.queue.peek(0) + self.assertEqual(1, self.scheduler.queue.qsize()) + self.assertEqual(pq_item.id, item.id) + + # Assert: Task should be in datastore, and queued + task_db = self.mock_ctx.datastores.task_store.get_task(str(item.id)) + self.assertEqual(task_db.id, item.id) + self.assertEqual(task_db.status, models.TaskStatus.QUEUED) + + # Assert: Schedule should be in datastore + schedule_db = self.mock_ctx.datastores.schedule_store.get_schedule(task_db.schedule_id) + self.assertIsNotNone(schedule_db) + self.assertEqual(schedule_db.id, task_db.schedule_id) + + # Assert: schedule should have a deadline + self.assertIsNotNone(schedule_db.deadline_at) + self.assertIsNotNone(schedule_db.schedule) + + # Assert: deadline should be in the future, at least later than the + # grace period + self.assertGreater( + schedule_db.deadline_at, + datetime.now(timezone.utc), + ) + + def test_post_push_schedule_disabled(self): + # Arrange + first_item = functions.create_item( + scheduler_id=self.scheduler.scheduler_id, + priority=1, + ) + + # Act + first_item_db = self.scheduler.push_item_to_queue(first_item) + + initial_schedule_db = self.mock_ctx.datastores.schedule_store.get_schedule(first_item_db.schedule_id) + + # Pop + self.scheduler.pop_item_from_queue() + + # Disable this schedule + initial_schedule_db.enabled = False + self.mock_ctx.datastores.schedule_store.update_schedule( + initial_schedule_db, + ) + + # Act + second_item = first_item_db.copy() + second_item.id = uuid.uuid4() + second_item_db = self.scheduler.push_item_to_queue(second_item) + + with capture_logs() as cm: + self.scheduler.post_push(second_item_db) + + self.assertIn("is disabled, not updating deadline", cm[-1].get("event")) + + def test_post_push_schedule_update_schedule(self): + # Arrange + first_item = functions.create_item( + scheduler_id=self.scheduler.scheduler_id, + priority=1, + ) + + # Act + first_item_db = self.scheduler.push_item_to_queue(first_item) + + initial_schedule_db = self.mock_ctx.datastores.schedule_store.get_schedule(first_item_db.schedule_id) + + # Pop + self.scheduler.pop_item_from_queue() + + # Act + second_item = first_item_db.copy() + second_item.id = uuid.uuid4() + second_item_db = self.scheduler.push_item_to_queue(second_item) + + updated_schedule_db = self.mock_ctx.datastores.schedule_store.get_schedule(second_item_db.schedule_id) + + # Assert + self.assertEqual(initial_schedule_db.id, updated_schedule_db.id) + self.assertNotEqual(updated_schedule_db.deadline_at, initial_schedule_db.deadline_at) + + # There should be only one schedule + schedules, _ = self.mock_ctx.datastores.schedule_store.get_schedules(scheduler_id=self.scheduler.scheduler_id) + + self.assertEqual(1, len(schedules)) + def test_post_pop(self): """When a task is popped from the queue, it should be removed from the database""" # Arrange - p_item = functions.create_p_item( + item = functions.create_item( scheduler_id=self.scheduler.scheduler_id, priority=1, + task=functions.create_task(self.scheduler.scheduler_id), ) # Act - self.scheduler.push_item_to_queue(p_item) + self.scheduler.push_item_to_queue(item) # Assert: task should be on priority queue - pq_p_item = self.scheduler.queue.peek(0) + pq_item = self.scheduler.queue.peek(0) self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertEqual(pq_p_item.id, p_item.id) + self.assertEqual(pq_item.id, item.id) # Assert: task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(p_item.id) - self.assertEqual(task_db.id, p_item.id) + task_db = self.mock_ctx.datastores.task_store.get_task(str(item.id)) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.QUEUED) # Act @@ -98,8 +355,8 @@ def test_post_pop(self): # Assert: task should be in datastore, and dispatched self.assertEqual(0, self.scheduler.queue.qsize()) - task_db = self.mock_ctx.datastores.task_store.get_task(p_item.id) - self.assertEqual(task_db.id, p_item.id) + task_db = self.mock_ctx.datastores.task_store.get_task(str(item.id)) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.DISPATCHED) def test_disable_scheduler(self): @@ -107,20 +364,20 @@ def test_disable_scheduler(self): self.scheduler.run() # Arrange: add tasks - p_item = functions.create_p_item( + item = functions.create_item( scheduler_id=self.scheduler.scheduler_id, priority=1, ) - self.scheduler.push_item_to_queue(p_item) + self.scheduler.push_item_to_queue(item) # Assert: task should be on priority queue - pq_p_item = self.scheduler.queue.peek(0) + pq_item = self.scheduler.queue.peek(0) self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertEqual(pq_p_item.id, p_item.id) + self.assertEqual(pq_item.id, item.id) # Assert: task should be in datastore, and queued - task_db = self.mock_ctx.datastores.task_store.get_task(p_item.id) - self.assertEqual(task_db.id, p_item.id) + task_db = self.mock_ctx.datastores.task_store.get_task(str(item.id)) + self.assertEqual(task_db.id, item.id) self.assertEqual(task_db.status, models.TaskStatus.QUEUED) # Assert: listeners should be running @@ -150,18 +407,18 @@ def test_disable_scheduler(self): self.assertFalse(self.scheduler.is_enabled()) with self.assertRaises(queues.errors.NotAllowedError): - self.scheduler.push_item_to_queue(p_item) + self.scheduler.push_item_to_queue(item) def test_enable_scheduler(self): # Arrange: start scheduler self.scheduler.run() # Arrange: add tasks - p_item = functions.create_p_item( + item = functions.create_item( scheduler_id=self.scheduler.scheduler_id, priority=1, ) - self.scheduler.push_item_to_queue(p_item) + self.scheduler.push_item_to_queue(item) # Assert: listeners should be running self.assertGreater(len(self.scheduler.listeners), 0) @@ -196,12 +453,12 @@ def test_enable_scheduler(self): self.assertTrue(self.scheduler.is_enabled()) # Push item to the queue - self.scheduler.push_item_to_queue(p_item) + self.scheduler.push_item_to_queue(item) # Assert: task should be on priority queue - pq_p_item = self.scheduler.queue.peek(0) + pq_item = self.scheduler.queue.peek(0) self.assertEqual(1, self.scheduler.queue.qsize()) - self.assertEqual(pq_p_item.id, p_item.id) + self.assertEqual(pq_item.id, item.id) # Stop the scheduler self.scheduler.stop() diff --git a/mula/tests/integration/test_task_store.py b/mula/tests/integration/test_task_store.py index 5f4bdea9585..03c7941336b 100644 --- a/mula/tests/integration/test_task_store.py +++ b/mula/tests/integration/test_task_store.py @@ -1,18 +1,15 @@ -import json import unittest -import uuid from datetime import datetime, timedelta, timezone from types import SimpleNamespace from unittest import mock from scheduler import config, models, storage -from scheduler.storage import filters from tests.factories import OrganisationFactory from tests.utils import functions -class TaskStoreTestCase(unittest.TestCase): +class StoreTestCase(unittest.TestCase): def setUp(self): # Application Context self.mock_ctx = mock.patch("scheduler.context.AppContext").start() @@ -26,8 +23,8 @@ def setUp(self): self.mock_ctx.datastores = SimpleNamespace( **{ - storage.TaskStore.name: storage.TaskStore(self.dbconn), storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn), + storage.TaskStore.name: storage.TaskStore(self.dbconn), } ) @@ -38,6 +35,111 @@ def tearDown(self): models.Base.metadata.drop_all(self.dbconn.engine) self.dbconn.engine.dispose() + def test_create_task(self): + task = functions.create_task(scheduler_id=self.organisation.id) + created_task = self.mock_ctx.datastores.task_store.create_task(task) + self.assertIsNotNone(created_task) + + def test_get_tasks(self): + # Arrange + for i in range(5): + task = functions.create_task(scheduler_id=self.organisation.id) + self.mock_ctx.datastores.task_store.create_task(task) + + # Act + tasks, count = self.mock_ctx.datastores.task_store.get_tasks(scheduler_id=self.organisation.id) + + # Assert + self.assertEqual(len(tasks), 5) + self.assertEqual(count, 5) + + def get_tasks_by_type(self): + # Arrange + for i in range(5): + task = functions.create_task(scheduler_id=self.organisation.id) + self.mock_ctx.datastores.task_store.create_task(task) + + # Act + tasks, count = self.mock_ctx.datastores.task_store.get_tasks( + scheduler_id=self.organisation.id, task_type=functions.TestModel.type + ) + + # Assert + self.assertEqual(len(tasks), 5) + self.assertEqual(count, 5) + + def test_get_tasks_by_hash(self): + # Arrange + hashes = [] + data = functions.create_test_model() + for i in range(5): + task = functions.create_task(scheduler_id=self.organisation.id, data=data) + self.mock_ctx.datastores.task_store.create_task(task) + hashes.append(task.hash) + + # Every task should have the same hash + self.assertEqual(len(set(hashes)), 1) + + # Act + tasks = self.mock_ctx.datastores.task_store.get_tasks_by_hash(data.hash) + + # Assert + self.assertEqual(len(tasks), 5) + + def test_get_task(self): + # Arrange + task = functions.create_task(scheduler_id=self.organisation.id) + created_task = self.mock_ctx.datastores.task_store.create_task(task) + + # Act + task = self.mock_ctx.datastores.task_store.get_task(created_task.id) + + # Assert + self.assertIsNotNone(task) + + def test_get_latest_task_by_hash(self): + # Arrange + hashes = [] + data = functions.create_test_model() + for i in range(5): + task = functions.create_task(scheduler_id=self.organisation.id, data=data) + self.mock_ctx.datastores.task_store.create_task(task) + hashes.append(task.hash) + + # Every task should have the same hash + self.assertEqual(len(set(hashes)), 1) + + # Act + task = self.mock_ctx.datastores.task_store.get_latest_task_by_hash(data.hash) + + # Assert + self.assertIsNotNone(task) + + def test_update_task(self): + # Arrange + task = functions.create_task(scheduler_id=self.organisation.id) + created_task = self.mock_ctx.datastores.task_store.create_task(task) + + # Act + created_task.status = models.TaskStatus.COMPLETED + self.mock_ctx.datastores.task_store.update_task(created_task) + + # Assert + updated_task = self.mock_ctx.datastores.task_store.get_task(created_task.id) + self.assertEqual(updated_task.status, models.TaskStatus.COMPLETED) + + def test_cancel_task(self): + # Arrange + task = functions.create_task(scheduler_id=self.organisation.id) + created_task = self.mock_ctx.datastores.task_store.create_task(task) + + # Act + self.mock_ctx.datastores.task_store.cancel_tasks(self.organisation.id, [created_task.id]) + + # Assert + updated_task = self.mock_ctx.datastores.task_store.get_task(created_task.id) + self.assertEqual(updated_task.status, models.TaskStatus.CANCELLED) + def test_get_status_counts(self): # Arrange one_hour = datetime.now(timezone.utc) - timedelta(hours=1) @@ -69,14 +171,14 @@ def test_get_status_counts(self): ), ): for _ in r: - p_item = functions.create_p_item(self.organisation.id, 1) + data = functions.create_test_model() task = models.Task( - id=p_item.id, - hash=p_item.hash, - type=functions.TestModel.type, - scheduler_id=p_item.scheduler_id, - p_item=p_item, + scheduler_id=self.organisation.id, + priority=1, status=status, + type=functions.TestModel.type, + hash=data.hash, + data=data.model_dump(), modified_at=modified_at, ) self.mock_ctx.datastores.task_store.create_task(task) @@ -121,14 +223,14 @@ def test_get_status_count_per_hour(self): ), ): for _ in r: - p_item = functions.create_p_item(self.organisation.id, 1) + data = functions.create_test_model() task = models.Task( - id=p_item.id, - hash=p_item.hash, - type=functions.TestModel.type, - scheduler_id=p_item.scheduler_id, - p_item=p_item, + scheduler_id=self.organisation.id, + priority=1, status=status, + type=functions.TestModel.type, + hash=data.hash, + data=data.model_dump(), modified_at=modified_at, ) self.mock_ctx.datastores.task_store.create_task(task) @@ -144,840 +246,3 @@ def test_get_status_count_per_hour(self): self.assertEqual(results.get(keys[1]).get("completed"), 2) self.assertEqual(results.get(keys[1]).get("total"), 2) self.assertEqual(results.get(keys[2]).get("queued"), 2) - - def test_get_tasks_filter_multiple_and(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - f_req = filters.FilterRequest( - filters={ - "and": [ - filters.Filter( - column="id", - field=None, - operator="eq", - value=first_task.id.hex, - ), - filters.Filter( - column="p_item", - field="data__id", - operator="eq", - value=first_p_item.data.get("id"), - ), - ] - }, - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, first_task.id) - - def test_get_tasks_filter_multiple_or(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters={ - "or": [ - filters.Filter( - column="id", - field=None, - operator="eq", - value=first_task.id.hex, - ), - filters.Filter( - column="id", - field=None, - operator="eq", - value=second_task.id.hex, - ), - ] - }, - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 2) - self.assertEqual(len(tasks), 2) - self.assertEqual(tasks[0].id, second_task.id) - self.assertEqual(tasks[1].id, first_task.id) - - def test_get_tasks_filter_multiple_not(self): - # Arrange - first_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel( - id=uuid.uuid4().hex, - name=uuid.uuid4().hex, - count=1, - categories=["test-a", "test-b"], - ), - ) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel( - id=uuid.uuid4().hex, - name=uuid.uuid4().hex, - count=2, - categories=["test-a"], - ), - ) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - third_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel( - id=uuid.uuid4().hex, - name=uuid.uuid4().hex, - count=3, - categories=["test-b"], - ), - ) - third_task = functions.create_task(third_p_item) - self.mock_ctx.datastores.task_store.create_task(third_task) - - f_req = filters.FilterRequest( - filters={ - "and": [ - filters.Filter( - column="id", - field=None, - operator="eq", - value=first_task.id.hex, - ), - filters.Filter( - column="p_item", - field="data", - operator="@>", - value=json.dumps({"categories": ["test-a"]}), - ), - ], - "not": [ - filters.Filter( - column="p_item", - field="data__count", - operator=">", - value=1, - ), - ], - }, - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, first_task.id) - - def test_get_tasks_filter_eq(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="id", - field=None, - operator="eq", - value=first_task.id.hex, - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, first_task.id) - - def test_get_tasks_filter_ne(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="id", - field=None, - operator="ne", - value=first_task.id.hex, - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, second_task.id) - - def test_get_tasks_filter_json_eq(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__id", - operator="eq", - value=first_p_item.data.get("id"), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].p_item.data["id"], first_p_item.data.get("id")) - - # Arrange - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__id", - operator="==", - value=first_p_item.data.get("id"), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].p_item.data["id"], first_p_item.data.get("id")) - - def test_get_tasks_filter_json_ne(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__id", - operator="ne", - value=second_p_item.data.get("id"), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].p_item.data["id"], first_p_item.data.get("id")) - - def test_get_tasks_filter_json_gt(self): - # Arrange - first_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel(id=uuid.uuid4().hex, name=uuid.uuid4().hex, count=1), - ) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel(id=uuid.uuid4().hex, name=uuid.uuid4().hex, count=2), - ) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__count", - operator="gt", - value=first_p_item.data.get("count"), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, second_task.id) - - # Arrange - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__count", - operator=">", - value=first_p_item.data.get("count"), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, second_task.id) - - def test_get_tasks_filter_json_gte(self): - # Arrange - first_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel(id=uuid.uuid4().hex, name=uuid.uuid4().hex, count=1), - ) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel(id=uuid.uuid4().hex, name=uuid.uuid4().hex, count=2), - ) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__count", - operator="gte", - value=first_p_item.data.get("count"), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 2) - self.assertEqual(len(tasks), 2) - self.assertEqual(tasks[0].id, second_task.id) - self.assertEqual(tasks[1].id, first_task.id) - - # Arrange - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__count", - operator=">=", - value=first_p_item.data.get("count"), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 2) - self.assertEqual(len(tasks), 2) - self.assertEqual(tasks[0].id, second_task.id) - self.assertEqual(tasks[1].id, first_task.id) - - def test_get_tasks_filter_json_lt(self): - # Arrange - first_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel(id=uuid.uuid4().hex, name=uuid.uuid4().hex, count=2), - ) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel(id=uuid.uuid4().hex, name=uuid.uuid4().hex, count=1), - ) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__count", - operator="lt", - value=first_p_item.data.get("count"), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, second_task.id) - - # Arrange - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__count", - operator="<", - value=first_p_item.data.get("count"), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, second_task.id) - - def test_get_tasks_filter_json_lte(self): - # Arrange - first_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel(id=uuid.uuid4().hex, name=uuid.uuid4().hex, count=2), - ) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel(id=uuid.uuid4().hex, name=uuid.uuid4().hex, count=1), - ) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__count", - operator="lte", - value=first_p_item.data.get("count"), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 2) - self.assertEqual(len(tasks), 2) - self.assertEqual(tasks[0].id, second_task.id) - self.assertEqual(tasks[1].id, first_task.id) - - # Arrange - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__count", - operator="<=", - value=first_p_item.data.get("count"), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 2) - self.assertEqual(len(tasks), 2) - self.assertEqual(tasks[0].id, second_task.id) - self.assertEqual(tasks[1].id, first_task.id) - - def test_get_tasks_filter_json_like(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__name", - operator="like", - value=f"%{first_p_item.data.get('name')[0:10]}%", - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, first_task.id) - - def test_get_tasks_filter_json_not_like(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__name", - operator="not_like", - value=f"%{first_p_item.data.get('name')[0:10]}%", - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, second_task.id) - - def test_get_tasks_filter_json_ilike(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__name", - operator="ilike", - value=f"%{first_p_item.data.get('name')[0:10].upper()}%", - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, first_task.id) - - def test_get_tasks_filter_json_not_ilike(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__name", - operator="not_ilike", - value=f"%{first_p_item.data.get('name')[0:10].upper()}%", - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, second_task.id) - - def test_get_tasks_filter_json_in(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__name", - operator="in", - value=[ - first_p_item.data.get("name"), - second_p_item.data.get("name"), - ], - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 2) - self.assertEqual(len(tasks), 2) - self.assertEqual(tasks[0].id, second_task.id) - self.assertEqual(tasks[1].id, first_task.id) - - def test_get_tasks_filter_json_not_in(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__name", - operator="not_in", - value=[first_p_item.data.get("name")], - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, second_task.id) - - def test_get_tasks_filter_json_contains(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__name", - operator="contains", - value=first_p_item.data.get("name")[0:10], - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, first_task.id) - - def test_get_tasks_filter_json_starts_with(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__name", - operator="starts_with", - value=first_p_item.data.get("name")[0:10], - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 1) - self.assertEqual(len(tasks), 1) - self.assertEqual(tasks[0].id, first_task.id) - - def test_get_tasks_filter_jsonb_contains(self): - # Arrange - first_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel( - id=uuid.uuid4().hex, - name=uuid.uuid4().hex, - count=1, - categories=["test-a", "test-b"], - ), - ) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel( - id=uuid.uuid4().hex, - name=uuid.uuid4().hex, - count=2, - categories=["test-a"], - ), - ) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - third_p_item = functions.create_p_item( - self.organisation.id, - 0, - functions.TestModel( - id=uuid.uuid4().hex, - name=uuid.uuid4().hex, - count=3, - categories=["test-b"], - ), - ) - third_task = functions.create_task(third_p_item) - self.mock_ctx.datastores.task_store.create_task(third_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data", - operator="@>", - value=json.dumps({"categories": ["test-a"]}), - ) - ], - ) - - # Act - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) - - # Assert - self.assertEqual(count, 2) - self.assertEqual(len(tasks), 2) - self.assertEqual(tasks[0].id, second_task.id) - self.assertEqual(tasks[1].id, first_task.id) - - def test_get_tasks_filter_json_mismatch(self): - # Arrange - first_p_item = functions.create_p_item(self.organisation.id, 0) - first_task = functions.create_task(first_p_item) - self.mock_ctx.datastores.task_store.create_task(first_task) - - second_p_item = functions.create_p_item(self.organisation.id, 0) - second_task = functions.create_task(second_p_item) - self.mock_ctx.datastores.task_store.create_task(second_task) - - f_req = filters.FilterRequest( - filters=[ - filters.Filter( - column="p_item", - field="data__id", - operator="eq", - value=False, - ) - ], - ) - - # Act - with self.assertRaises(storage.errors.StorageError): - tasks, count = self.mock_ctx.datastores.task_store.get_tasks(filters=f_req) diff --git a/mula/tests/mocks/item.py b/mula/tests/mocks/item.py new file mode 100644 index 00000000000..f63aa28422b --- /dev/null +++ b/mula/tests/mocks/item.py @@ -0,0 +1,23 @@ +from typing import Any, ClassVar + +import mmh3 +import pydantic + + +class MockData(pydantic.BaseModel): + type: ClassVar[str] = "test-model" + id: str + name: str + count: int = 0 + categories: list[str] | None = None + child: Any = None + + def __init__(self, **data: Any): + super().__init__(**data) + + if self.categories is None: + self.categories = [] + + @property + def hash(self) -> str: + return mmh3.hash_bytes(f"{self.id}-{self.name}").hex() diff --git a/mula/tests/mocks/queue.py b/mula/tests/mocks/queue.py index 334444e4706..426ae5a46b9 100644 --- a/mula/tests/mocks/queue.py +++ b/mula/tests/mocks/queue.py @@ -3,5 +3,5 @@ class MockPriorityQueue(queues.PriorityQueue): - def create_hash(self, p_item: models.PrioritizedItem) -> str: + def create_hash(self, p_item: models.Task) -> str: return dict_utils.deep_get(p_item.model_dump(), ["data", "id"]) diff --git a/mula/tests/mocks/scheduler.py b/mula/tests/mocks/scheduler.py index 1aaae2d212f..b745f97bdf6 100644 --- a/mula/tests/mocks/scheduler.py +++ b/mula/tests/mocks/scheduler.py @@ -2,13 +2,18 @@ from scheduler import schedulers +from tests.utils import functions + from . import listener class MockScheduler(schedulers.Scheduler): + ITEM_TYPE = functions.TestModel + def run(self) -> None: # Listener self.listeners["mock-listener"] = listener.MockListener() + self.run_in_thread( name="mock-listener", target=self.listeners["mock-listener"].listen, diff --git a/mula/tests/scripts/.gitignore b/mula/tests/scripts/.gitignore deleted file mode 100644 index 2ef021797f3..00000000000 --- a/mula/tests/scripts/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -data.csv -logs.txt diff --git a/mula/tests/scripts/__init__.py b/mula/tests/scripts/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/mula/tests/scripts/benchmark.py b/mula/tests/scripts/benchmark.py deleted file mode 100644 index 4449af1dff1..00000000000 --- a/mula/tests/scripts/benchmark.py +++ /dev/null @@ -1,173 +0,0 @@ -import argparse -import logging -import subprocess -import threading -import time -from pathlib import Path - -import httpx - -SCHEDULER_API = "http://localhost:8004" -TIMEOUT_FOR_LOG_CAPTURE = 5 - -logger = logging.getLogger(__name__) - - -def are_tasks_done() -> bool: - response = httpx.get( - url=f"{SCHEDULER_API}/tasks/stats", - timeout=30, - ) - - try: - response.raise_for_status() - except httpx.HTTPError: - logger.error("Error getting tasks") - raise - - tasks_stats = response.json() - - return all(tasks_stats[hour].get("queued") <= 0 for hour in tasks_stats) - - -def parse_stats() -> None: - resp_tasks_stats = httpx.get( - url=f"{SCHEDULER_API}/tasks/stats", - timeout=30, - ) - - try: - resp_tasks_stats.raise_for_status() - except httpx.HTTPError: - logger.error("Error getting tasks") - raise - - tasks_stats = resp_tasks_stats.json() - for hour in tasks_stats: - queued = tasks_stats[hour].get("queued") - running = tasks_stats[hour].get("running") - failed = tasks_stats[hour].get("failed") - completed = tasks_stats[hour].get("completed") - - logger.info( - "HOUR %s, QUEUED %s, RUNNING %s, FAILED %s, COMPLETED %s", - hour, - queued, - running, - failed, - completed, - ) - - -def capture_logs(container_id: str, output_file: str) -> None: - # Capture logs - with Path.open(output_file, "w", encoding="utf-8") as file: - subprocess.run( - ["docker", "logs", container_id], - stdout=file, - stderr=file, - check=True, - ) - - -def parse_logs(path: str) -> None: - # Check if there were any errors in the logs - count = 0 - with Path.open(path, encoding="utf-8") as file: - for line in file: - if line.startswith("ERROR") or line.startswith("Traceback"): - count += 1 - logger.info(line) - - if count > 0: - logger.error("Found %d errors in the logs", count) - - -def collect_cpu(container_id: str) -> str: - return ( - subprocess.run( - ["docker", "stats", "--no-stream", "--format", "{{.CPUPerc}}", container_id], - capture_output=True, - check=True, - ) - .stdout.decode("utf-8") - .strip("%\n") - ) - - -def collect_memory(container_id: str) -> str: - return ( - subprocess.run( - ["docker", "stats", "--no-stream", "--format", "{{.MemUsage}}", container_id], - capture_output=True, - check=True, - ) - .stdout.decode("utf-8") - .split("/")[0] - .strip("MiB\n") - ) - - -def run(container_id: str) -> None: - # Start capturing logs - if container_id is not None: - thread = threading.Thread(target=capture_logs, args=(container_id, "logs.txt")) - thread.start() - - # Wait for tasks to finish - while not are_tasks_done(): - logger.debug("Tasks are not done yet") - - cpu = collect_cpu(container_id) - memory = collect_memory(container_id) - logger.info("CPU %s, MEMORY %s", cpu, memory) - - # Parse stats - parse_stats() - - time.sleep(10) - continue - - logger.debug("Tasks are done") - - # Stop capturing logs - thread.join(timeout=TIMEOUT_FOR_LOG_CAPTURE) - - # Parse stats - parse_stats() - - # Parse logs - parse_logs("logs.txt") - - -if __name__ == "__main__": - # Setup command line interface - parser = argparse.ArgumentParser(description="Benchmark the scheduler.") - - # Add arguments - parser.add_argument("--verbose", "-v", action="store_true", help="Set to enable verbose logging.") - - parser.add_argument( - "--container-id", - "-c", - type=str, - required=False, - help="The container id of the process to monitor.", - ) - - # Parse arguments - args = parser.parse_args() - - # Configure logging level, if the -v (verbose) flag was given this will - # set the log-level to DEBUG (printing all debug messages and higher), - # if -v was not given it defaults to printing level warning and higher. - level = logging.INFO - if args.verbose: - default_loglevel = logging.DEBUG - - logging.basicConfig( - level=level, - format="%(asctime)s %(name)-10s %(levelname)-8s %(message)s", - ) - - run(args.container_id) diff --git a/mula/tests/scripts/load.py b/mula/tests/scripts/load.py deleted file mode 100644 index 01f3b02b598..00000000000 --- a/mula/tests/scripts/load.py +++ /dev/null @@ -1,145 +0,0 @@ -import argparse -import csv -import uuid -from datetime import datetime, timezone -from pathlib import Path -from typing import Any - -import httpx - -OCTOPOES_API = "http://localhost:8001" -KATALOGUS_API = "http://localhost:8003" -SCHEDULER_API = "http://localhost:8004" - - -def run(org_num: int = 1): - # Create organisations - orgs: list[dict[str, Any]] = [] - for n in range(0, org_num): - org = { - "id": f"org-{n}", - "name": f"Organisation {n}", - } - orgs.append(org) - - resp_katalogus = httpx.post( - url=f"{KATALOGUS_API}/v1/organisations/", - json=org, - timeout=30, - ) - - try: - resp_katalogus.raise_for_status() - except httpx.HTTPError: - if resp_katalogus.status_code != 404: - print("Error creating organisation ", org) - raise - - if resp_katalogus.status_code == 404: - print("Organisation already exists in katalogus", org) - - try: - httpx.post( - url=f"{OCTOPOES_API}/{org.get('id')}/node/", - timeout=30, - ) - except httpx.HTTPError: - print("Error creating organisation ", org) - raise - - print("Created organisation ", org) - - # Enable boefjes for organisation - boefjes = ("dns-records", "dns-sec", "dns-zone") - for boefje_id in boefjes: - resp_enable_boefje = httpx.patch( - url=f"{KATALOGUS_API}/v1/organisations/{org.get('id')}/repositories/LOCAL/plugins/{boefje_id}", - json={"enabled": True}, - timeout=30, - ) - - try: - resp_enable_boefje.raise_for_status() - except httpx.HTTPError: - print("Error enabling boefje ", boefje_id) - raise - - print("Enabled boefje ", boefje_id) - - declarations: list[dict[str, Any]] = [] - - # Check if data file exists - if not Path("data.csv").exists(): - print("data.csv file not found") - return - - with Path("data.csv").open(newline="", encoding="utf-8") as csv_file: - csv_reader = csv.DictReader(csv_file, delimiter=",", quotechar='"') - for row in csv_reader: - name = row["name"] - declaration = { - "ooi": { - "object_type": "Hostname", - "primary_key": f"Hostname|internet|{name}", - "network": "Network|internet", - "name": f"{name}", - "dns_zone": None, - "scan_profile": { - "scan_profile_type": "declared", - "level": 1, - "reference": f"Hostname|internet|{name}", - }, - }, - "valid_time": datetime.now(timezone.utc).isoformat(), - "method": None, - "task_id": str(uuid.uuid4()), - } - declarations.append(declaration) - - for org in orgs: - for declaration in declarations: - resp_octopoes_decl = httpx.post( - f"{OCTOPOES_API}/{org.get('id')}/declarations", json=declaration, timeout=30 - ) - - try: - resp_octopoes_decl.raise_for_status() - except httpx.HTTPError: - print("Error creating declaration ", declaration) - print(resp_octopoes_decl.text) - raise - - print("Org", org.get("id"), "created declaration ", declaration) - - resp_octopoes_scan_profile = httpx.put( - url=f"{OCTOPOES_API}/{org.get('id')}/scan_profiles", - params={"valid_time": str(datetime.now(timezone.utc))}, - json={ - "scan_profile_type": "declared", - "reference": declaration.get("ooi").get("scan_profile").get("reference"), - "level": declaration.get("ooi").get("scan_profile").get("level"), - }, - timeout=30, - ) - - try: - resp_octopoes_scan_profile.raise_for_status() - except httpx.HTTPError: - print("Error creating scan profile", declaration.get("ooi").get("scan_profile")) - print(resp_octopoes_scan_profile.text) - raise - - print("Org {org.get('id')} created scan profile", declaration.get("ooi").get("scan_profile")) - - -if __name__ == "__main__": - # Setup command line interface - parser = argparse.ArgumentParser(description="Load test the scheduler") - - # Add arguments - parser.add_argument("--orgs", type=int, default=1, help="Number of organisations to create") - - # Parse arguments - args = parser.parse_args() - - run(org_num=args.orgs) diff --git a/mula/tests/simulation/test_simulation.py b/mula/tests/simulation/test_simulation.py index cbaaf00dde8..23d34175f9e 100644 --- a/mula/tests/simulation/test_simulation.py +++ b/mula/tests/simulation/test_simulation.py @@ -1,3 +1,4 @@ +# NOTE: This file is DEPRECATED import unittest import uuid from unittest import mock @@ -69,7 +70,12 @@ def create_boefje_scheduler_for_organisation(self, organisation): @mock.patch("scheduler.context.AppContext.services.scan_profile.get_latest_object") @mock.patch("scheduler.context.AppContext.services.octopoes.get_random_objects") @mock.patch("scheduler.schedulers.BoefjeScheduler.create_tasks_for_oois") - def test_simulation_boefje_queue(self, mock_create_tasks_for_oois, mock_get_random_objects, mock_get_latest_object): + def test_simulation_boefje_queue( + self, + mock_create_tasks_for_oois, + mock_get_random_objects, + mock_get_latest_object, + ): iterations = 1000 oois = [OOIFactory(scan_profile=ScanProfileFactory(level=0)) for _ in range(iterations)] diff --git a/mula/tests/unit/test_queue.py b/mula/tests/unit/test_queue.py index 066d5247a4b..b2bc5d66a87 100644 --- a/mula/tests/unit/test_queue.py +++ b/mula/tests/unit/test_queue.py @@ -44,8 +44,8 @@ def _check_queue_empty(self): def test_push(self): """When adding an item to the priority queue, the item should be added""" - item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=item) + item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(item) item_db = self.pq_store.get(self.pq.pq_id, item.id) self.assertIsNotNone(item_db) @@ -58,40 +58,41 @@ def test_push_item_not_found_in_db(self, mock_push): """When adding an item to the priority queue, but the item is not found in the database, the item shouldn't be added. """ - item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) + item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) mock_push.return_value = None - with self.assertRaises(queues.errors.PrioritizedItemNotFoundError): - self.pq.push(p_item=item) + with self.assertRaises(queues.errors.ItemNotFoundError): + self.pq.push(item) self.assertEqual(0, self.pq.qsize()) + item_db = self.pq_store.get(self.pq.pq_id, item.id) self.assertIsNone(item_db) - def test_push_incorrect_p_item_type(self): + def test_push_incorrect_item_type(self): """When pushing an item that is not of the correct type, the item shouldn't be pushed. """ - p_item = { + item = { "priority": 1, "data": functions.TestModel(id=uuid.uuid4().hex, name=uuid.uuid4().hex), } - with self.assertRaises(queues.errors.InvalidPrioritizedItemError): - self.pq.push(p_item=p_item) + with self.assertRaises(queues.errors.InvalidItemError): + self.pq.push(item) self.assertEqual(0, self.pq.qsize()) - def test_push_invalid_p_item(self): + def test_push_invalid_item(self): """When pushing an item that can not be validated, the item shouldn't be pushed. """ - p_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - p_item.data = {"invalid": "data"} + item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + item.data = {"invalid": "data"} - with self.assertRaises(queues.errors.InvalidPrioritizedItemError): - self.pq.push(p_item=p_item) + with self.assertRaises(queues.errors.InvalidItemError): + self.pq.push(item) self.assertEqual(0, self.pq.qsize()) @@ -103,14 +104,14 @@ def test_push_replace_not_allowed(self): self.pq.allow_replace = False # Add an item to the queue - initial_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=initial_item) + initial_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(initial_item) self.assertEqual(1, self.pq.qsize()) # Add the same item again with self.assertRaises(queues.errors.NotAllowedError): - self.pq.push(p_item=initial_item) + self.pq.push(initial_item) self.assertEqual(1, self.pq.qsize()) @@ -122,12 +123,12 @@ def test_push_replace_allowed(self): self.pq.allow_replace = True # Add an item to the queue - initial_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=initial_item) + initial_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(initial_item) self.assertEqual(1, self.pq.qsize()) # Add the same item again - self.pq.push(p_item=initial_item) + self.pq.push(initial_item) self.assertEqual(1, self.pq.qsize()) # Check if the item on the queue is the replaced item @@ -142,8 +143,8 @@ def test_push_updates_not_allowed(self): self.pq.allow_updates = False # Add an item to the queue - initial_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=initial_item) + initial_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(initial_item) self.assertEqual(1, self.pq.qsize()) # Update the item @@ -152,7 +153,7 @@ def test_push_updates_not_allowed(self): # Add the same item again with self.assertRaises(queues.errors.NotAllowedError): - self.pq.push(p_item=updated_item) + self.pq.push(updated_item) self.assertEqual(1, self.pq.qsize()) @@ -167,8 +168,8 @@ def test_push_updates_allowed(self): self.pq.allow_updates = True # Add an item to the queue - initial_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=initial_item) + initial_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(initial_item) self.assertEqual(1, self.pq.qsize()) @@ -177,7 +178,7 @@ def test_push_updates_allowed(self): updated_item.data["name"] = "updated-name" # Add the same item again - self.pq.push(p_item=updated_item) + self.pq.push(updated_item) self.assertEqual(1, self.pq.qsize()) @@ -192,8 +193,8 @@ def test_push_priority_updates_not_allowed(self): self.pq.allow_priority_updates = False # Add an item to the queue - initial_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=initial_item) + initial_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(initial_item) self.assertEqual(1, self.pq.qsize()) @@ -203,7 +204,7 @@ def test_push_priority_updates_not_allowed(self): # Add the same item again with self.assertRaises(queues.errors.NotAllowedError): - self.pq.push(p_item=updated_item) + self.pq.push(updated_item) self.assertEqual(1, self.pq.qsize()) @@ -218,8 +219,8 @@ def test_push_priority_updates_allowed(self): self.pq.allow_priority_updates = True # Add an item to the queue - initial_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=initial_item) + initial_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(initial_item) self.assertEqual(1, self.pq.qsize()) @@ -228,7 +229,7 @@ def test_push_priority_updates_allowed(self): updated_item.priority = 100 # Add the same item again - self.pq.push(p_item=updated_item) + self.pq.push(updated_item) self.assertEqual(1, self.pq.qsize()) @@ -240,8 +241,8 @@ def test_remove_item(self): removed, and the item should be removed from the entry_finder. """ # Add an item to the queue - item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=item) + item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(item) self.assertEqual(1, self.pq.qsize()) @@ -258,13 +259,13 @@ def test_push_maxsize_not_allowed(self): self.pq.maxsize = 1 # Add an item to the queue - first_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=first_item) + first_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(first_item) # Add another item to the queue - second_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=2) + second_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=2) with self.assertRaises(_queue.Full): - self.pq.push(p_item=second_item) + self.pq.push(second_item) # The queue should now have 1 item self.assertEqual(1, self.pq.qsize()) @@ -283,12 +284,12 @@ def test_push_maxsize_allowed(self): self.pq.maxsize = 0 # Add an item to the queue - first_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=first_item) + first_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(first_item) # Add another item to the queue - second_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=2) - self.pq.push(p_item=second_item) + second_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=2) + self.pq.push(second_item) # The queue should now have 2 items self.assertEqual(2, self.pq.qsize()) @@ -313,12 +314,12 @@ def test_push_maxsize_allowed_high_priority(self): self.pq.maxsize = 1 # Add an item to the queue - first_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=first_item) + first_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(first_item) # Add another item to the queue - second_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=second_item) + second_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(second_item) # The queue should now have 2 items self.assertEqual(2, self.pq.qsize()) @@ -343,13 +344,13 @@ def test_push_maxsize_not_allowed_low_priority(self): self.pq.maxsize = 1 # Add an item to the queue - first_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=first_item) + first_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(first_item) # Add another item to the queue - second_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=2) + second_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=2) with self.assertRaises(_queue.Full): - self.pq.push(p_item=second_item) + self.pq.push(second_item) # The queue should now have 1 item self.assertEqual(1, self.pq.qsize()) @@ -365,8 +366,8 @@ def test_pop(self): it from the queue. """ # Add an item to the queue - first_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=first_item) + first_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(first_item) # The queue should now have 1 item self.assertEqual(1, self.pq.qsize()) @@ -383,10 +384,10 @@ def test_pop_with_lock(self): thread to pop an item. """ # Arrange - first_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - second_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=first_item) - self.pq.push(p_item=second_item) + first_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + second_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(first_item) + self.pq.push(second_item) event = threading.Event() queue = _queue.Queue() @@ -433,10 +434,10 @@ def test_pop_without_lock(self): NOTE: Here we test the procedure when a lock isn't set. """ # Arrange - first_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - second_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=first_item) - self.pq.push(p_item=second_item) + first_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + second_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(first_item) + self.pq.push(second_item) event = threading.Event() queue = _queue.Queue() @@ -487,12 +488,12 @@ def test_pop_highest_priority(self): priority """ # Add an item to the queue - first_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=first_item) + first_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(first_item) # Add another item to the queue - second_item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=2) - self.pq.push(p_item=second_item) + second_item = functions.create_item(scheduler_id=self.pq.pq_id, priority=2) + self.pq.push(second_item) # The queue should now have 2 items self.assertEqual(2, self.pq.qsize()) @@ -506,8 +507,8 @@ def test_is_item_on_queue(self): the item is on the queue, and False if it isn't. """ # Add an item to the queue - item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) - self.pq.push(p_item=item) + item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) + self.pq.push(item) # Check if the item is on the queue self.assertTrue(self.pq.is_item_on_queue(item)) @@ -517,7 +518,7 @@ def test_is_item_not_on_queue(self): the item is on the queue, and False if it isn't. """ # Add an item to the queue - item = functions.create_p_item(scheduler_id=self.pq.pq_id, priority=1) + item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1) # Check if the item is on the queue self.assertFalse(self.pq.is_item_on_queue(item)) diff --git a/mula/tests/utils/__init__.py b/mula/tests/utils/__init__.py index 43d8652922c..5c404729fae 100644 --- a/mula/tests/utils/__init__.py +++ b/mula/tests/utils/__init__.py @@ -1 +1,2 @@ +from .json import UUIDEncoder from .memory import profile_memory diff --git a/mula/tests/utils/functions.py b/mula/tests/utils/functions.py index af08da29598..6fc7f13cf82 100644 --- a/mula/tests/utils/functions.py +++ b/mula/tests/utils/functions.py @@ -1,18 +1,22 @@ +import json import uuid from typing import Any, ClassVar +import mmh3 import pydantic from scheduler import models from sqlalchemy.dialects import postgresql from sqlalchemy.orm import Query +from tests import factories + class TestModel(pydantic.BaseModel): type: ClassVar[str] = "test-model" id: str name: str count: int = 0 - categories: list[str] = None + categories: list[str] | None = None child: Any = None def __init__(self, **data: Any): @@ -21,43 +25,75 @@ def __init__(self, **data: Any): if self.categories is None: self.categories = [] + @property + def hash(self) -> str: + return mmh3.hash_bytes(f"{self.id}-{self.name}").hex() + + +def create_test_model() -> TestModel: + return TestModel( + id=uuid.uuid4().hex, + name=uuid.uuid4().hex, + ) + -def create_p_item_request(priority: int, data: TestModel | None = None) -> models.PrioritizedItemRequest: +def create_task_in(priority: int, data: TestModel | None = None) -> str: if data is None: data = TestModel( id=uuid.uuid4().hex, name=uuid.uuid4().hex, ) - return models.PrioritizedItemRequest( - priority=priority, - data=data.model_dump(), + return json.dumps( + { + "priority": priority, + "data": data.model_dump(), + } ) -def create_p_item(scheduler_id: str, priority: int, data: TestModel | None = None) -> models.PrioritizedItem: +def create_item(scheduler_id: str, priority: int, task: models.Task | None = None) -> models.Task: + if task is None: + task = create_task(scheduler_id) + + item = models.Task( + **task.dict(), + ) + + if priority is not None: + item.priority = priority + + return item + + +def create_schedule(scheduler_id: str, data: Any | None = None) -> models.Schedule: + item = data or create_test_model() + return models.Schedule( + scheduler_id=scheduler_id, + hash=item.hash, + data=item.model_dump(), + ) + + +def create_task(scheduler_id: str, data: Any | None = None) -> models.Task: if data is None: data = TestModel( id=uuid.uuid4().hex, name=uuid.uuid4().hex, ) - return models.PrioritizedItem( + return models.Task( scheduler_id=scheduler_id, - priority=priority, + type=TestModel.type, + hash=data.hash, data=data.model_dump(), ) -def create_task(p_item: models.PrioritizedItem) -> models.Task: - return models.Task( - id=p_item.id, - hash=p_item.hash, - type=TestModel.type, - scheduler_id=p_item.scheduler_id, - p_item=p_item, - status=models.TaskStatus.QUEUED, - ) +def create_boefje() -> models.Boefje: + scan_profile = factories.ScanProfileFactory(level=0) + ooi = factories.OOIFactory(scan_profile=scan_profile) + return factories.PluginFactory(scan_level=0, consumes=[ooi.object_type]) def compile_query(query: Query) -> str: diff --git a/mula/tests/utils/json.py b/mula/tests/utils/json.py new file mode 100644 index 00000000000..bec91f1a326 --- /dev/null +++ b/mula/tests/utils/json.py @@ -0,0 +1,9 @@ +import json +from uuid import UUID + + +class UUIDEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, UUID): + return obj.hex + return json.JSONEncoder.default(self, obj) diff --git a/rocky/rocky/scheduler.py b/rocky/rocky/scheduler.py index e4f2df0e743..416aebbc648 100644 --- a/rocky/rocky/scheduler.py +++ b/rocky/rocky/scheduler.py @@ -63,54 +63,61 @@ class NormalizerMeta(BaseModel): class NormalizerTask(BaseModel): """NormalizerTask represent data needed for a Normalizer to run.""" + type: str = "normalizer" + id: uuid.UUID | None = None normalizer: Normalizer raw_data: RawData - type: str = "normalizer" class BoefjeTask(BaseModel): """BoefjeTask represent data needed for a Boefje to run.""" + type: str = "boefje" + id: uuid.UUID | None = None boefje: Boefje input_ooi: str | None = None organization: str - type: str = "boefje" - - -class PrioritizedItem(BaseModel): - """Representation of a queue.PrioritizedItem on the priority queue. Used - for unmarshalling of priority queue prioritized items to a JSON - representation. - """ - - id: uuid.UUID | None = None - hash: str | None = None - priority: int - data: SerializeAsAny[BoefjeTask | NormalizerTask] class TaskStatus(Enum): - """Status of a task.""" - + # Task has been created but not yet queued PENDING = "pending" + + # Task has been pushed onto queue and is ready to be picked up QUEUED = "queued" + + # Task has been picked up by a worker DISPATCHED = "dispatched" + + # Task has been picked up by a worker, and the worker indicates that it is + # running. RUNNING = "running" + + # Task has been completed COMPLETED = "completed" + + # Task has failed FAILED = "failed" + # Task has been cancelled + CANCELLED = "cancelled" + class Task(BaseModel): + model_config = ConfigDict(from_attributes=True) + id: uuid.UUID | None = None scheduler_id: str - type: str - p_item: PrioritizedItem - status: TaskStatus - created_at: datetime.datetime - modified_at: datetime.datetime - model_config = ConfigDict(from_attributes=True) + schedule_id: str | None = None + priority: int + status: TaskStatus | None = TaskStatus.PENDING + type: str | None = None + hash: str | None = None + data: SerializeAsAny[BoefjeTask | NormalizerTask] + created_at: datetime.datetime | None = None + modified_at: datetime.datetime | None = None class PaginatedTasksResponse(BaseModel): @@ -231,9 +238,9 @@ def get_task_details(self, task_id: str) -> Task: task_details = Task.model_validate_json(res.content) if task_details.type == "normalizer": - organization = task_details.p_item.data.raw_data.boefje_meta.organization + organization = task_details.data.raw_data.boefje_meta.organization else: - organization = task_details.p_item.data.organization + organization = task_details.data.organization if organization != self.organization_code: raise SchedulerTaskNotFound() @@ -242,12 +249,12 @@ def get_task_details(self, task_id: str) -> Task: except ConnectError: raise SchedulerConnectError() - def push_task(self, prioritized_item: PrioritizedItem) -> None: + def push_task(self, item: Task) -> None: try: - queue_name = f"{prioritized_item.data.type}-{self.organization_code}" + queue_name = f"{item.data.type}-{self.organization_code}" res = self._client.post( f"/queues/{queue_name}/push", - content=prioritized_item.json(), + content=item.json(exclude_none=True), headers={"Content-Type": "application/json"}, ) res.raise_for_status() diff --git a/rocky/rocky/templates/tasks/boefje_task_detail.html b/rocky/rocky/templates/tasks/boefje_task_detail.html index 6a1f1beb4fe..c843202bb17 100644 --- a/rocky/rocky/templates/tasks/boefje_task_detail.html +++ b/rocky/rocky/templates/tasks/boefje_task_detail.html @@ -9,7 +9,7 @@
-

"{{ task.p_item.data.boefje.id }}" @ {{ task.p_item.data.input_ooi }}

+

"{{ task.data.boefje.id }}" @ {{ task.data.input_ooi }}

{{ task.created_at }}

{% blocktranslate trimmed %} @@ -28,7 +28,7 @@

RAW file

{% translate "Input object" %}

- {{ task.p_item.data.input_ooi }} + {{ task.data.input_ooi }}

diff --git a/rocky/rocky/templates/tasks/boefjes.html b/rocky/rocky/templates/tasks/boefjes.html index 7b8ee24d0e4..b9a1920a992 100644 --- a/rocky/rocky/templates/tasks/boefjes.html +++ b/rocky/rocky/templates/tasks/boefjes.html @@ -36,14 +36,14 @@

{% translate "Boefjes" %}

{% for task in task_list %} - {{ task.p_item.data.boefje.name }} + {{ task.data.boefje.name }}  {{ task.status.value|capfirst }} {{ task.created_at }} - {{ task.p_item.data.input_ooi }} + {{ task.data.input_ooi }}

{% for task in task_list %} - {{ task.p_item.data.normalizer.id }} + {{ task.data.normalizer.id }}  {{ task.status.value|capfirst }} {{ task.created_at }} - {{ task.p_item.data.raw_data.boefje_meta.boefje.id }} + {{ task.data.raw_data.boefje_meta.boefje.id }} - {{ task.p_item.data.raw_data.boefje_meta.input_ooi }} + {{ task.data.raw_data.boefje_meta.input_ooi }} - +
diff --git a/rocky/reports/templates/partials/report_header.html b/rocky/reports/templates/partials/report_header.html index e6bbdc9fa97..cc651048d09 100644 --- a/rocky/reports/templates/partials/report_header.html +++ b/rocky/reports/templates/partials/report_header.html @@ -8,13 +8,15 @@

{{ report_name }}

- +
diff --git a/rocky/rocky/templates/organizations/organization_member_list.html b/rocky/rocky/templates/organizations/organization_member_list.html index 2488b71724c..75097051116 100644 --- a/rocky/rocky/templates/organizations/organization_member_list.html +++ b/rocky/rocky/templates/organizations/organization_member_list.html @@ -18,17 +18,19 @@

{% translate "Members" %}

{% if perms.tools.add_organizationmember %}
{% endif %} diff --git a/rocky/rocky/templates/partials/ooi_list_toolbar.html b/rocky/rocky/templates/partials/ooi_list_toolbar.html index 004de033f44..bfa1718da2c 100644 --- a/rocky/rocky/templates/partials/ooi_list_toolbar.html +++ b/rocky/rocky/templates/partials/ooi_list_toolbar.html @@ -7,34 +7,38 @@ - +
{% endspaceless %} diff --git a/rocky/rocky/templates/partials/organizations_menu_dropdown.html b/rocky/rocky/templates/partials/organizations_menu_dropdown.html index 3ce1f6e21f9..675458ef252 100644 --- a/rocky/rocky/templates/partials/organizations_menu_dropdown.html +++ b/rocky/rocky/templates/partials/organizations_menu_dropdown.html @@ -10,17 +10,19 @@ {% endif %} - + {% endif %} From 70d64b4f68201fc704a0adab54e66906416f21e8 Mon Sep 17 00:00:00 2001 From: ammar92 Date: Thu, 15 Aug 2024 16:27:05 +0200 Subject: [PATCH 065/112] Package Updates (#3374) --- boefjes/poetry.lock | 154 +++++++++++++++++----------------- boefjes/requirements-dev.txt | 154 +++++++++++++++++----------------- boefjes/requirements.txt | 154 +++++++++++++++++----------------- bytes/poetry.lock | 127 +++++++++++----------------- bytes/requirements-dev.txt | 123 +++++++++++---------------- bytes/requirements.txt | 123 +++++++++++---------------- keiko/poetry.lock | 106 +++++++++++------------ keiko/requirements-dev.txt | 102 +++++++++++----------- keiko/requirements.txt | 102 +++++++++++----------- octopoes/poetry.lock | 115 ++++++++++++------------- octopoes/requirements-dev.txt | 111 +++++++++++------------- octopoes/requirements.txt | 105 +++++++++++------------ 12 files changed, 669 insertions(+), 807 deletions(-) diff --git a/boefjes/poetry.lock b/boefjes/poetry.lock index bc80d4d6270..fcd021764f5 100644 --- a/boefjes/poetry.lock +++ b/boefjes/poetry.lock @@ -13,87 +13,87 @@ files = [ [[package]] name = "aiohttp" -version = "3.10.1" +version = "3.10.3" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:47b4c2412960e64d97258f40616efddaebcb34ff664c8a972119ed38fac2a62c"}, - {file = "aiohttp-3.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7dbf637f87dd315fa1f36aaed8afa929ee2c607454fb7791e74c88a0d94da59"}, - {file = "aiohttp-3.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c8fb76214b5b739ce59e2236a6489d9dc3483649cfd6f563dbf5d8e40dbdd57d"}, - {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c577cdcf8f92862363b3d598d971c6a84ed8f0bf824d4cc1ce70c2fb02acb4a"}, - {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:777e23609899cb230ad2642b4bdf1008890f84968be78de29099a8a86f10b261"}, - {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b07286a1090483799599a2f72f76ac396993da31f6e08efedb59f40876c144fa"}, - {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9db600a86414a9a653e3c1c7f6a2f6a1894ab8f83d11505247bd1b90ad57157"}, - {file = "aiohttp-3.10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c3f1eb280008e51965a8d160a108c333136f4a39d46f516c64d2aa2e6a53f2"}, - {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f5dd109a925fee4c9ac3f6a094900461a2712df41745f5d04782ebcbe6479ccb"}, - {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8c81ff4afffef9b1186639506d70ea90888218f5ddfff03870e74ec80bb59970"}, - {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2a384dfbe8bfebd203b778a30a712886d147c61943675f4719b56725a8bbe803"}, - {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:b9fb6508893dc31cfcbb8191ef35abd79751db1d6871b3e2caee83959b4d91eb"}, - {file = "aiohttp-3.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:88596384c3bec644a96ae46287bb646d6a23fa6014afe3799156aef42669c6bd"}, - {file = "aiohttp-3.10.1-cp310-cp310-win32.whl", hash = "sha256:68164d43c580c2e8bf8e0eb4960142919d304052ccab92be10250a3a33b53268"}, - {file = "aiohttp-3.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d6bbe2c90c10382ca96df33b56e2060404a4f0f88673e1e84b44c8952517e5f3"}, - {file = "aiohttp-3.10.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f6979b4f20d3e557a867da9d9227de4c156fcdcb348a5848e3e6190fd7feb972"}, - {file = "aiohttp-3.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03c0c380c83f8a8d4416224aafb88d378376d6f4cadebb56b060688251055cd4"}, - {file = "aiohttp-3.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c2b104e81b3c3deba7e6f5bc1a9a0e9161c380530479970766a6655b8b77c7c"}, - {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b023b68c61ab0cd48bd38416b421464a62c381e32b9dc7b4bdfa2905807452a4"}, - {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a07c76a82390506ca0eabf57c0540cf5a60c993c442928fe4928472c4c6e5e6"}, - {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:41d8dab8c64ded1edf117d2a64f353efa096c52b853ef461aebd49abae979f16"}, - {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:615348fab1a9ef7d0960a905e83ad39051ae9cb0d2837da739b5d3a7671e497a"}, - {file = "aiohttp-3.10.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:256ee6044214ee9d66d531bb374f065ee94e60667d6bbeaa25ca111fc3997158"}, - {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7d5bb926805022508b7ddeaad957f1fce7a8d77532068d7bdb431056dc630cd"}, - {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:028faf71b338f069077af6315ad54281612705d68889f5d914318cbc2aab0d50"}, - {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:5c12310d153b27aa630750be44e79313acc4e864c421eb7d2bc6fa3429c41bf8"}, - {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:de1a91d5faded9054957ed0a9e01b9d632109341942fc123947ced358c5d9009"}, - {file = "aiohttp-3.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9c186b270979fb1dee3ababe2d12fb243ed7da08b30abc83ebac3a928a4ddb15"}, - {file = "aiohttp-3.10.1-cp311-cp311-win32.whl", hash = "sha256:4a9ce70f5e00380377aac0e568abd075266ff992be2e271765f7b35d228a990c"}, - {file = "aiohttp-3.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:a77c79bac8d908d839d32c212aef2354d2246eb9deb3e2cb01ffa83fb7a6ea5d"}, - {file = "aiohttp-3.10.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2212296cdb63b092e295c3e4b4b442e7b7eb41e8a30d0f53c16d5962efed395d"}, - {file = "aiohttp-3.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4dcb127ca3eb0a61205818a606393cbb60d93b7afb9accd2fd1e9081cc533144"}, - {file = "aiohttp-3.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb8b79a65332e1a426ccb6290ce0409e1dc16b4daac1cc5761e059127fa3d134"}, - {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68cc24f707ed9cb961f6ee04020ca01de2c89b2811f3cf3361dc7c96a14bfbcc"}, - {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cb54f5725b4b37af12edf6c9e834df59258c82c15a244daa521a065fbb11717"}, - {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:51d03e948e53b3639ce4d438f3d1d8202898ec6655cadcc09ec99229d4adc2a9"}, - {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:786299d719eb5d868f161aeec56d589396b053925b7e0ce36e983d30d0a3e55c"}, - {file = "aiohttp-3.10.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abda4009a30d51d3f06f36bc7411a62b3e647fa6cc935ef667e3e3d3a7dd09b1"}, - {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:67f7639424c313125213954e93a6229d3a1d386855d70c292a12628f600c7150"}, - {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8e5a26d7aac4c0d8414a347da162696eea0629fdce939ada6aedf951abb1d745"}, - {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:120548d89f14b76a041088b582454d89389370632ee12bf39d919cc5c561d1ca"}, - {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f5293726943bdcea24715b121d8c4ae12581441d22623b0e6ab12d07ce85f9c4"}, - {file = "aiohttp-3.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1f8605e573ed6c44ec689d94544b2c4bb1390aaa723a8b5a2cc0a5a485987a68"}, - {file = "aiohttp-3.10.1-cp312-cp312-win32.whl", hash = "sha256:e7168782621be4448d90169a60c8b37e9b0926b3b79b6097bc180c0a8a119e73"}, - {file = "aiohttp-3.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fbf8c0ded367c5c8eaf585f85ca8dd85ff4d5b73fb8fe1e6ac9e1b5e62e11f7"}, - {file = "aiohttp-3.10.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:54b7f4a20d7cc6bfa4438abbde069d417bb7a119f870975f78a2b99890226d55"}, - {file = "aiohttp-3.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2fa643ca990323db68911b92f3f7a0ca9ae300ae340d0235de87c523601e58d9"}, - {file = "aiohttp-3.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d8311d0d690487359fe2247ec5d2cac9946e70d50dced8c01ce9e72341c21151"}, - {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222821c60b8f6a64c5908cb43d69c0ee978a1188f6a8433d4757d39231b42cdb"}, - {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7b55d9ede66af7feb6de87ff277e0ccf6d51c7db74cc39337fe3a0e31b5872d"}, - {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a95151a5567b3b00368e99e9c5334a919514f60888a6b6d2054fea5e66e527e"}, - {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e9e9171d2fe6bfd9d3838a6fe63b1e91b55e0bf726c16edf265536e4eafed19"}, - {file = "aiohttp-3.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a57e73f9523e980f6101dc9a83adcd7ac0006ea8bf7937ca3870391c7bb4f8ff"}, - {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0df51a3d70a2bfbb9c921619f68d6d02591f24f10e9c76de6f3388c89ed01de6"}, - {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:b0de63ff0307eac3961b4af74382d30220d4813f36b7aaaf57f063a1243b4214"}, - {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:8db9b749f589b5af8e4993623dbda6716b2b7a5fcb0fa2277bf3ce4b278c7059"}, - {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6b14c19172eb53b63931d3e62a9749d6519f7c121149493e6eefca055fcdb352"}, - {file = "aiohttp-3.10.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5cd57ad998e3038aa87c38fe85c99ed728001bf5dde8eca121cadee06ee3f637"}, - {file = "aiohttp-3.10.1-cp38-cp38-win32.whl", hash = "sha256:df31641e3f02b77eb3c5fb63c0508bee0fc067cf153da0e002ebbb0db0b6d91a"}, - {file = "aiohttp-3.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:93094eba50bc2ad4c40ff4997ead1fdcd41536116f2e7d6cfec9596a8ecb3615"}, - {file = "aiohttp-3.10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:440954ddc6b77257e67170d57b1026aa9545275c33312357472504eef7b4cc0b"}, - {file = "aiohttp-3.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f9f8beed277488a52ee2b459b23c4135e54d6a819eaba2e120e57311015b58e9"}, - {file = "aiohttp-3.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d8a8221a63602008550022aa3a4152ca357e1dde7ab3dd1da7e1925050b56863"}, - {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a702bd3663b5cbf3916e84bf332400d24cdb18399f0877ca6b313ce6c08bfb43"}, - {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1988b370536eb14f0ce7f3a4a5b422ab64c4e255b3f5d7752c5f583dc8c967fc"}, - {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ccf1f0a304352c891d124ac1a9dea59b14b2abed1704aaa7689fc90ef9c5be1"}, - {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc3ea6ef2a83edad84bbdb5d96e22f587b67c68922cd7b6f9d8f24865e655bcf"}, - {file = "aiohttp-3.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89b47c125ab07f0831803b88aeb12b04c564d5f07a1c1a225d4eb4d2f26e8b5e"}, - {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:21778552ef3d44aac3278cc6f6d13a6423504fa5f09f2df34bfe489ed9ded7f5"}, - {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bde0693073fd5e542e46ea100aa6c1a5d36282dbdbad85b1c3365d5421490a92"}, - {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:bf66149bb348d8e713f3a8e0b4f5b952094c2948c408e1cfef03b49e86745d60"}, - {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:587237571a85716d6f71f60d103416c9df7d5acb55d96d3d3ced65f39bff9c0c"}, - {file = "aiohttp-3.10.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bfe33cba6e127d0b5b417623c9aa621f0a69f304742acdca929a9fdab4593693"}, - {file = "aiohttp-3.10.1-cp39-cp39-win32.whl", hash = "sha256:9fbff00646cf8211b330690eb2fd64b23e1ce5b63a342436c1d1d6951d53d8dd"}, - {file = "aiohttp-3.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:5951c328f9ac42d7bce7a6ded535879bc9ae13032818d036749631fa27777905"}, - {file = "aiohttp-3.10.1.tar.gz", hash = "sha256:8b0d058e4e425d3b45e8ec70d49b402f4d6b21041e674798b1f91ba027c73f28"}, + {file = "aiohttp-3.10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc36cbdedf6f259371dbbbcaae5bb0e95b879bc501668ab6306af867577eb5db"}, + {file = "aiohttp-3.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85466b5a695c2a7db13eb2c200af552d13e6a9313d7fa92e4ffe04a2c0ea74c1"}, + {file = "aiohttp-3.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:71bb1d97bfe7e6726267cea169fdf5df7658831bb68ec02c9c6b9f3511e108bb"}, + {file = "aiohttp-3.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baec1eb274f78b2de54471fc4c69ecbea4275965eab4b556ef7a7698dee18bf2"}, + {file = "aiohttp-3.10.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13031e7ec1188274bad243255c328cc3019e36a5a907978501256000d57a7201"}, + {file = "aiohttp-3.10.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2bbc55a964b8eecb341e492ae91c3bd0848324d313e1e71a27e3d96e6ee7e8e8"}, + {file = "aiohttp-3.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8cc0564b286b625e673a2615ede60a1704d0cbbf1b24604e28c31ed37dc62aa"}, + {file = "aiohttp-3.10.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f817a54059a4cfbc385a7f51696359c642088710e731e8df80d0607193ed2b73"}, + {file = "aiohttp-3.10.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8542c9e5bcb2bd3115acdf5adc41cda394e7360916197805e7e32b93d821ef93"}, + {file = "aiohttp-3.10.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:671efce3a4a0281060edf9a07a2f7e6230dca3a1cbc61d110eee7753d28405f7"}, + {file = "aiohttp-3.10.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0974f3b5b0132edcec92c3306f858ad4356a63d26b18021d859c9927616ebf27"}, + {file = "aiohttp-3.10.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:44bb159b55926b57812dca1b21c34528e800963ffe130d08b049b2d6b994ada7"}, + {file = "aiohttp-3.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6ae9ae382d1c9617a91647575255ad55a48bfdde34cc2185dd558ce476bf16e9"}, + {file = "aiohttp-3.10.3-cp310-cp310-win32.whl", hash = "sha256:aed12a54d4e1ee647376fa541e1b7621505001f9f939debf51397b9329fd88b9"}, + {file = "aiohttp-3.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:b51aef59370baf7444de1572f7830f59ddbabd04e5292fa4218d02f085f8d299"}, + {file = "aiohttp-3.10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e021c4c778644e8cdc09487d65564265e6b149896a17d7c0f52e9a088cc44e1b"}, + {file = "aiohttp-3.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:24fade6dae446b183e2410a8628b80df9b7a42205c6bfc2eff783cbeedc224a2"}, + {file = "aiohttp-3.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bc8e9f15939dacb0e1f2d15f9c41b786051c10472c7a926f5771e99b49a5957f"}, + {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5a9ec959b5381271c8ec9310aae1713b2aec29efa32e232e5ef7dcca0df0279"}, + {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a5d0ea8a6467b15d53b00c4e8ea8811e47c3cc1bdbc62b1aceb3076403d551f"}, + {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9ed607dbbdd0d4d39b597e5bf6b0d40d844dfb0ac6a123ed79042ef08c1f87e"}, + {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3e66d5b506832e56add66af88c288c1d5ba0c38b535a1a59e436b300b57b23e"}, + {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fda91ad797e4914cca0afa8b6cccd5d2b3569ccc88731be202f6adce39503189"}, + {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:61ccb867b2f2f53df6598eb2a93329b5eee0b00646ee79ea67d68844747a418e"}, + {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6d881353264e6156f215b3cb778c9ac3184f5465c2ece5e6fce82e68946868ef"}, + {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b031ce229114825f49cec4434fa844ccb5225e266c3e146cb4bdd025a6da52f1"}, + {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5337cc742a03f9e3213b097abff8781f79de7190bbfaa987bd2b7ceb5bb0bdec"}, + {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ab3361159fd3dcd0e48bbe804006d5cfb074b382666e6c064112056eb234f1a9"}, + {file = "aiohttp-3.10.3-cp311-cp311-win32.whl", hash = "sha256:05d66203a530209cbe40f102ebaac0b2214aba2a33c075d0bf825987c36f1f0b"}, + {file = "aiohttp-3.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:70b4a4984a70a2322b70e088d654528129783ac1ebbf7dd76627b3bd22db2f17"}, + {file = "aiohttp-3.10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:166de65e2e4e63357cfa8417cf952a519ac42f1654cb2d43ed76899e2319b1ee"}, + {file = "aiohttp-3.10.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7084876352ba3833d5d214e02b32d794e3fd9cf21fdba99cff5acabeb90d9806"}, + {file = "aiohttp-3.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d98c604c93403288591d7d6d7d6cc8a63459168f8846aeffd5b3a7f3b3e5e09"}, + {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d73b073a25a0bb8bf014345374fe2d0f63681ab5da4c22f9d2025ca3e3ea54fc"}, + {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8da6b48c20ce78f5721068f383e0e113dde034e868f1b2f5ee7cb1e95f91db57"}, + {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a9dcdccf50284b1b0dc72bc57e5bbd3cc9bf019060dfa0668f63241ccc16aa7"}, + {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56fb94bae2be58f68d000d046172d8b8e6b1b571eb02ceee5535e9633dcd559c"}, + {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bf75716377aad2c718cdf66451c5cf02042085d84522aec1f9246d3e4b8641a6"}, + {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6c51ed03e19c885c8e91f574e4bbe7381793f56f93229731597e4a499ffef2a5"}, + {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b84857b66fa6510a163bb083c1199d1ee091a40163cfcbbd0642495fed096204"}, + {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c124b9206b1befe0491f48185fd30a0dd51b0f4e0e7e43ac1236066215aff272"}, + {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3461d9294941937f07bbbaa6227ba799bc71cc3b22c40222568dc1cca5118f68"}, + {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:08bd0754d257b2db27d6bab208c74601df6f21bfe4cb2ec7b258ba691aac64b3"}, + {file = "aiohttp-3.10.3-cp312-cp312-win32.whl", hash = "sha256:7f9159ae530297f61a00116771e57516f89a3de6ba33f314402e41560872b50a"}, + {file = "aiohttp-3.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:e1128c5d3a466279cb23c4aa32a0f6cb0e7d2961e74e9e421f90e74f75ec1edf"}, + {file = "aiohttp-3.10.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d1100e68e70eb72eadba2b932b185ebf0f28fd2f0dbfe576cfa9d9894ef49752"}, + {file = "aiohttp-3.10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a541414578ff47c0a9b0b8b77381ea86b0c8531ab37fc587572cb662ccd80b88"}, + {file = "aiohttp-3.10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d5548444ef60bf4c7b19ace21f032fa42d822e516a6940d36579f7bfa8513f9c"}, + {file = "aiohttp-3.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba2e838b5e6a8755ac8297275c9460e729dc1522b6454aee1766c6de6d56e5e"}, + {file = "aiohttp-3.10.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48665433bb59144aaf502c324694bec25867eb6630fcd831f7a893ca473fcde4"}, + {file = "aiohttp-3.10.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bac352fceed158620ce2d701ad39d4c1c76d114255a7c530e057e2b9f55bdf9f"}, + {file = "aiohttp-3.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b0f670502100cdc567188c49415bebba947eb3edaa2028e1a50dd81bd13363f"}, + {file = "aiohttp-3.10.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43b09f38a67679e32d380fe512189ccb0b25e15afc79b23fbd5b5e48e4fc8fd9"}, + {file = "aiohttp-3.10.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:cd788602e239ace64f257d1c9d39898ca65525583f0fbf0988bcba19418fe93f"}, + {file = "aiohttp-3.10.3-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:214277dcb07ab3875f17ee1c777d446dcce75bea85846849cc9d139ab8f5081f"}, + {file = "aiohttp-3.10.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:32007fdcaab789689c2ecaaf4b71f8e37bf012a15cd02c0a9db8c4d0e7989fa8"}, + {file = "aiohttp-3.10.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:123e5819bfe1b87204575515cf448ab3bf1489cdeb3b61012bde716cda5853e7"}, + {file = "aiohttp-3.10.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:812121a201f0c02491a5db335a737b4113151926a79ae9ed1a9f41ea225c0e3f"}, + {file = "aiohttp-3.10.3-cp38-cp38-win32.whl", hash = "sha256:b97dc9a17a59f350c0caa453a3cb35671a2ffa3a29a6ef3568b523b9113d84e5"}, + {file = "aiohttp-3.10.3-cp38-cp38-win_amd64.whl", hash = "sha256:3731a73ddc26969d65f90471c635abd4e1546a25299b687e654ea6d2fc052394"}, + {file = "aiohttp-3.10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38d91b98b4320ffe66efa56cb0f614a05af53b675ce1b8607cdb2ac826a8d58e"}, + {file = "aiohttp-3.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9743fa34a10a36ddd448bba8a3adc2a66a1c575c3c2940301bacd6cc896c6bf1"}, + {file = "aiohttp-3.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7c126f532caf238031c19d169cfae3c6a59129452c990a6e84d6e7b198a001dc"}, + {file = "aiohttp-3.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:926e68438f05703e500b06fe7148ef3013dd6f276de65c68558fa9974eeb59ad"}, + {file = "aiohttp-3.10.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:434b3ab75833accd0b931d11874e206e816f6e6626fd69f643d6a8269cd9166a"}, + {file = "aiohttp-3.10.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d35235a44ec38109b811c3600d15d8383297a8fab8e3dec6147477ec8636712a"}, + {file = "aiohttp-3.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59c489661edbd863edb30a8bd69ecb044bd381d1818022bc698ba1b6f80e5dd1"}, + {file = "aiohttp-3.10.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50544fe498c81cb98912afabfc4e4d9d85e89f86238348e3712f7ca6a2f01dab"}, + {file = "aiohttp-3.10.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:09bc79275737d4dc066e0ae2951866bb36d9c6b460cb7564f111cc0427f14844"}, + {file = "aiohttp-3.10.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:af4dbec58e37f5afff4f91cdf235e8e4b0bd0127a2a4fd1040e2cad3369d2f06"}, + {file = "aiohttp-3.10.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b22cae3c9dd55a6b4c48c63081d31c00fc11fa9db1a20c8a50ee38c1a29539d2"}, + {file = "aiohttp-3.10.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ba562736d3fbfe9241dad46c1a8994478d4a0e50796d80e29d50cabe8fbfcc3f"}, + {file = "aiohttp-3.10.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f25d6c4e82d7489be84f2b1c8212fafc021b3731abdb61a563c90e37cced3a21"}, + {file = "aiohttp-3.10.3-cp39-cp39-win32.whl", hash = "sha256:b69d832e5f5fa15b1b6b2c8eb6a9fd2c0ec1fd7729cb4322ed27771afc9fc2ac"}, + {file = "aiohttp-3.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:673bb6e3249dc8825df1105f6ef74e2eab779b7ff78e96c15cadb78b04a83752"}, + {file = "aiohttp-3.10.3.tar.gz", hash = "sha256:21650e7032cc2d31fc23d353d7123e771354f2a3d5b05a5647fc30fea214e696"}, ] [package.dependencies] diff --git a/boefjes/requirements-dev.txt b/boefjes/requirements-dev.txt index bdaacd0c071..3d257eb1585 100644 --- a/boefjes/requirements-dev.txt +++ b/boefjes/requirements-dev.txt @@ -1,83 +1,83 @@ aiohappyeyeballs==2.3.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4d6dea59215537dbc746e93e779caea8178c866856a721c9c660d7a5a7b8be03 \ --hash=sha256:6fa48b9f1317254f122a07a131a86b71ca6946ca989ce6326fff54a99a920105 -aiohttp==3.10.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01c3f1eb280008e51965a8d160a108c333136f4a39d46f516c64d2aa2e6a53f2 \ - --hash=sha256:028faf71b338f069077af6315ad54281612705d68889f5d914318cbc2aab0d50 \ - --hash=sha256:03c0c380c83f8a8d4416224aafb88d378376d6f4cadebb56b060688251055cd4 \ - --hash=sha256:0df51a3d70a2bfbb9c921619f68d6d02591f24f10e9c76de6f3388c89ed01de6 \ - --hash=sha256:120548d89f14b76a041088b582454d89389370632ee12bf39d919cc5c561d1ca \ - --hash=sha256:1988b370536eb14f0ce7f3a4a5b422ab64c4e255b3f5d7752c5f583dc8c967fc \ - --hash=sha256:1a07c76a82390506ca0eabf57c0540cf5a60c993c442928fe4928472c4c6e5e6 \ - --hash=sha256:1c2b104e81b3c3deba7e6f5bc1a9a0e9161c380530479970766a6655b8b77c7c \ - --hash=sha256:1c577cdcf8f92862363b3d598d971c6a84ed8f0bf824d4cc1ce70c2fb02acb4a \ - --hash=sha256:1f8605e573ed6c44ec689d94544b2c4bb1390aaa723a8b5a2cc0a5a485987a68 \ - --hash=sha256:21778552ef3d44aac3278cc6f6d13a6423504fa5f09f2df34bfe489ed9ded7f5 \ - --hash=sha256:2212296cdb63b092e295c3e4b4b442e7b7eb41e8a30d0f53c16d5962efed395d \ - --hash=sha256:222821c60b8f6a64c5908cb43d69c0ee978a1188f6a8433d4757d39231b42cdb \ - --hash=sha256:256ee6044214ee9d66d531bb374f065ee94e60667d6bbeaa25ca111fc3997158 \ - --hash=sha256:2a384dfbe8bfebd203b778a30a712886d147c61943675f4719b56725a8bbe803 \ - --hash=sha256:2fa643ca990323db68911b92f3f7a0ca9ae300ae340d0235de87c523601e58d9 \ - --hash=sha256:41d8dab8c64ded1edf117d2a64f353efa096c52b853ef461aebd49abae979f16 \ - --hash=sha256:440954ddc6b77257e67170d57b1026aa9545275c33312357472504eef7b4cc0b \ - --hash=sha256:47b4c2412960e64d97258f40616efddaebcb34ff664c8a972119ed38fac2a62c \ - --hash=sha256:4a9ce70f5e00380377aac0e568abd075266ff992be2e271765f7b35d228a990c \ - --hash=sha256:4dcb127ca3eb0a61205818a606393cbb60d93b7afb9accd2fd1e9081cc533144 \ - --hash=sha256:4e9e9171d2fe6bfd9d3838a6fe63b1e91b55e0bf726c16edf265536e4eafed19 \ - --hash=sha256:51d03e948e53b3639ce4d438f3d1d8202898ec6655cadcc09ec99229d4adc2a9 \ - --hash=sha256:54b7f4a20d7cc6bfa4438abbde069d417bb7a119f870975f78a2b99890226d55 \ - --hash=sha256:587237571a85716d6f71f60d103416c9df7d5acb55d96d3d3ced65f39bff9c0c \ - --hash=sha256:5951c328f9ac42d7bce7a6ded535879bc9ae13032818d036749631fa27777905 \ - --hash=sha256:5a95151a5567b3b00368e99e9c5334a919514f60888a6b6d2054fea5e66e527e \ - --hash=sha256:5c12310d153b27aa630750be44e79313acc4e864c421eb7d2bc6fa3429c41bf8 \ - --hash=sha256:5cd57ad998e3038aa87c38fe85c99ed728001bf5dde8eca121cadee06ee3f637 \ - --hash=sha256:615348fab1a9ef7d0960a905e83ad39051ae9cb0d2837da739b5d3a7671e497a \ - --hash=sha256:67f7639424c313125213954e93a6229d3a1d386855d70c292a12628f600c7150 \ - --hash=sha256:68164d43c580c2e8bf8e0eb4960142919d304052ccab92be10250a3a33b53268 \ - --hash=sha256:68cc24f707ed9cb961f6ee04020ca01de2c89b2811f3cf3361dc7c96a14bfbcc \ - --hash=sha256:6b14c19172eb53b63931d3e62a9749d6519f7c121149493e6eefca055fcdb352 \ - --hash=sha256:777e23609899cb230ad2642b4bdf1008890f84968be78de29099a8a86f10b261 \ - --hash=sha256:786299d719eb5d868f161aeec56d589396b053925b7e0ce36e983d30d0a3e55c \ - --hash=sha256:7ccf1f0a304352c891d124ac1a9dea59b14b2abed1704aaa7689fc90ef9c5be1 \ - --hash=sha256:88596384c3bec644a96ae46287bb646d6a23fa6014afe3799156aef42669c6bd \ - --hash=sha256:89b47c125ab07f0831803b88aeb12b04c564d5f07a1c1a225d4eb4d2f26e8b5e \ - --hash=sha256:8b0d058e4e425d3b45e8ec70d49b402f4d6b21041e674798b1f91ba027c73f28 \ - --hash=sha256:8c81ff4afffef9b1186639506d70ea90888218f5ddfff03870e74ec80bb59970 \ - --hash=sha256:8db9b749f589b5af8e4993623dbda6716b2b7a5fcb0fa2277bf3ce4b278c7059 \ - --hash=sha256:8e5a26d7aac4c0d8414a347da162696eea0629fdce939ada6aedf951abb1d745 \ - --hash=sha256:8fbf8c0ded367c5c8eaf585f85ca8dd85ff4d5b73fb8fe1e6ac9e1b5e62e11f7 \ - --hash=sha256:93094eba50bc2ad4c40ff4997ead1fdcd41536116f2e7d6cfec9596a8ecb3615 \ - --hash=sha256:9c186b270979fb1dee3ababe2d12fb243ed7da08b30abc83ebac3a928a4ddb15 \ - --hash=sha256:9cb54f5725b4b37af12edf6c9e834df59258c82c15a244daa521a065fbb11717 \ - --hash=sha256:9fbff00646cf8211b330690eb2fd64b23e1ce5b63a342436c1d1d6951d53d8dd \ - --hash=sha256:a57e73f9523e980f6101dc9a83adcd7ac0006ea8bf7937ca3870391c7bb4f8ff \ - --hash=sha256:a702bd3663b5cbf3916e84bf332400d24cdb18399f0877ca6b313ce6c08bfb43 \ - --hash=sha256:a77c79bac8d908d839d32c212aef2354d2246eb9deb3e2cb01ffa83fb7a6ea5d \ - --hash=sha256:abda4009a30d51d3f06f36bc7411a62b3e647fa6cc935ef667e3e3d3a7dd09b1 \ - --hash=sha256:b023b68c61ab0cd48bd38416b421464a62c381e32b9dc7b4bdfa2905807452a4 \ - --hash=sha256:b07286a1090483799599a2f72f76ac396993da31f6e08efedb59f40876c144fa \ - --hash=sha256:b0de63ff0307eac3961b4af74382d30220d4813f36b7aaaf57f063a1243b4214 \ - --hash=sha256:b7d5bb926805022508b7ddeaad957f1fce7a8d77532068d7bdb431056dc630cd \ - --hash=sha256:b9db600a86414a9a653e3c1c7f6a2f6a1894ab8f83d11505247bd1b90ad57157 \ - --hash=sha256:b9fb6508893dc31cfcbb8191ef35abd79751db1d6871b3e2caee83959b4d91eb \ - --hash=sha256:bc3ea6ef2a83edad84bbdb5d96e22f587b67c68922cd7b6f9d8f24865e655bcf \ - --hash=sha256:bde0693073fd5e542e46ea100aa6c1a5d36282dbdbad85b1c3365d5421490a92 \ - --hash=sha256:bf66149bb348d8e713f3a8e0b4f5b952094c2948c408e1cfef03b49e86745d60 \ - --hash=sha256:bfe33cba6e127d0b5b417623c9aa621f0a69f304742acdca929a9fdab4593693 \ - --hash=sha256:c8fb76214b5b739ce59e2236a6489d9dc3483649cfd6f563dbf5d8e40dbdd57d \ - --hash=sha256:cb8b79a65332e1a426ccb6290ce0409e1dc16b4daac1cc5761e059127fa3d134 \ - --hash=sha256:d6bbe2c90c10382ca96df33b56e2060404a4f0f88673e1e84b44c8952517e5f3 \ - --hash=sha256:d8311d0d690487359fe2247ec5d2cac9946e70d50dced8c01ce9e72341c21151 \ - --hash=sha256:d8a8221a63602008550022aa3a4152ca357e1dde7ab3dd1da7e1925050b56863 \ - --hash=sha256:de1a91d5faded9054957ed0a9e01b9d632109341942fc123947ced358c5d9009 \ - --hash=sha256:df31641e3f02b77eb3c5fb63c0508bee0fc067cf153da0e002ebbb0db0b6d91a \ - --hash=sha256:e7168782621be4448d90169a60c8b37e9b0926b3b79b6097bc180c0a8a119e73 \ - --hash=sha256:e7b55d9ede66af7feb6de87ff277e0ccf6d51c7db74cc39337fe3a0e31b5872d \ - --hash=sha256:e7dbf637f87dd315fa1f36aaed8afa929ee2c607454fb7791e74c88a0d94da59 \ - --hash=sha256:f5293726943bdcea24715b121d8c4ae12581441d22623b0e6ab12d07ce85f9c4 \ - --hash=sha256:f5dd109a925fee4c9ac3f6a094900461a2712df41745f5d04782ebcbe6479ccb \ - --hash=sha256:f6979b4f20d3e557a867da9d9227de4c156fcdcb348a5848e3e6190fd7feb972 \ - --hash=sha256:f9f8beed277488a52ee2b459b23c4135e54d6a819eaba2e120e57311015b58e9 +aiohttp==3.10.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:05d66203a530209cbe40f102ebaac0b2214aba2a33c075d0bf825987c36f1f0b \ + --hash=sha256:08bd0754d257b2db27d6bab208c74601df6f21bfe4cb2ec7b258ba691aac64b3 \ + --hash=sha256:0974f3b5b0132edcec92c3306f858ad4356a63d26b18021d859c9927616ebf27 \ + --hash=sha256:09bc79275737d4dc066e0ae2951866bb36d9c6b460cb7564f111cc0427f14844 \ + --hash=sha256:123e5819bfe1b87204575515cf448ab3bf1489cdeb3b61012bde716cda5853e7 \ + --hash=sha256:13031e7ec1188274bad243255c328cc3019e36a5a907978501256000d57a7201 \ + --hash=sha256:166de65e2e4e63357cfa8417cf952a519ac42f1654cb2d43ed76899e2319b1ee \ + --hash=sha256:214277dcb07ab3875f17ee1c777d446dcce75bea85846849cc9d139ab8f5081f \ + --hash=sha256:21650e7032cc2d31fc23d353d7123e771354f2a3d5b05a5647fc30fea214e696 \ + --hash=sha256:24fade6dae446b183e2410a8628b80df9b7a42205c6bfc2eff783cbeedc224a2 \ + --hash=sha256:2a5d0ea8a6467b15d53b00c4e8ea8811e47c3cc1bdbc62b1aceb3076403d551f \ + --hash=sha256:2b0f670502100cdc567188c49415bebba947eb3edaa2028e1a50dd81bd13363f \ + --hash=sha256:2bbc55a964b8eecb341e492ae91c3bd0848324d313e1e71a27e3d96e6ee7e8e8 \ + --hash=sha256:32007fdcaab789689c2ecaaf4b71f8e37bf012a15cd02c0a9db8c4d0e7989fa8 \ + --hash=sha256:3461d9294941937f07bbbaa6227ba799bc71cc3b22c40222568dc1cca5118f68 \ + --hash=sha256:3731a73ddc26969d65f90471c635abd4e1546a25299b687e654ea6d2fc052394 \ + --hash=sha256:38d91b98b4320ffe66efa56cb0f614a05af53b675ce1b8607cdb2ac826a8d58e \ + --hash=sha256:3a9dcdccf50284b1b0dc72bc57e5bbd3cc9bf019060dfa0668f63241ccc16aa7 \ + --hash=sha256:434b3ab75833accd0b931d11874e206e816f6e6626fd69f643d6a8269cd9166a \ + --hash=sha256:43b09f38a67679e32d380fe512189ccb0b25e15afc79b23fbd5b5e48e4fc8fd9 \ + --hash=sha256:44bb159b55926b57812dca1b21c34528e800963ffe130d08b049b2d6b994ada7 \ + --hash=sha256:48665433bb59144aaf502c324694bec25867eb6630fcd831f7a893ca473fcde4 \ + --hash=sha256:50544fe498c81cb98912afabfc4e4d9d85e89f86238348e3712f7ca6a2f01dab \ + --hash=sha256:5337cc742a03f9e3213b097abff8781f79de7190bbfaa987bd2b7ceb5bb0bdec \ + --hash=sha256:56fb94bae2be58f68d000d046172d8b8e6b1b571eb02ceee5535e9633dcd559c \ + --hash=sha256:59c489661edbd863edb30a8bd69ecb044bd381d1818022bc698ba1b6f80e5dd1 \ + --hash=sha256:5ba2e838b5e6a8755ac8297275c9460e729dc1522b6454aee1766c6de6d56e5e \ + --hash=sha256:61ccb867b2f2f53df6598eb2a93329b5eee0b00646ee79ea67d68844747a418e \ + --hash=sha256:671efce3a4a0281060edf9a07a2f7e6230dca3a1cbc61d110eee7753d28405f7 \ + --hash=sha256:673bb6e3249dc8825df1105f6ef74e2eab779b7ff78e96c15cadb78b04a83752 \ + --hash=sha256:6ae9ae382d1c9617a91647575255ad55a48bfdde34cc2185dd558ce476bf16e9 \ + --hash=sha256:6c51ed03e19c885c8e91f574e4bbe7381793f56f93229731597e4a499ffef2a5 \ + --hash=sha256:6d881353264e6156f215b3cb778c9ac3184f5465c2ece5e6fce82e68946868ef \ + --hash=sha256:7084876352ba3833d5d214e02b32d794e3fd9cf21fdba99cff5acabeb90d9806 \ + --hash=sha256:70b4a4984a70a2322b70e088d654528129783ac1ebbf7dd76627b3bd22db2f17 \ + --hash=sha256:71bb1d97bfe7e6726267cea169fdf5df7658831bb68ec02c9c6b9f3511e108bb \ + --hash=sha256:7c126f532caf238031c19d169cfae3c6a59129452c990a6e84d6e7b198a001dc \ + --hash=sha256:7f9159ae530297f61a00116771e57516f89a3de6ba33f314402e41560872b50a \ + --hash=sha256:812121a201f0c02491a5db335a737b4113151926a79ae9ed1a9f41ea225c0e3f \ + --hash=sha256:8542c9e5bcb2bd3115acdf5adc41cda394e7360916197805e7e32b93d821ef93 \ + --hash=sha256:85466b5a695c2a7db13eb2c200af552d13e6a9313d7fa92e4ffe04a2c0ea74c1 \ + --hash=sha256:8d98c604c93403288591d7d6d7d6cc8a63459168f8846aeffd5b3a7f3b3e5e09 \ + --hash=sha256:8da6b48c20ce78f5721068f383e0e113dde034e868f1b2f5ee7cb1e95f91db57 \ + --hash=sha256:926e68438f05703e500b06fe7148ef3013dd6f276de65c68558fa9974eeb59ad \ + --hash=sha256:9743fa34a10a36ddd448bba8a3adc2a66a1c575c3c2940301bacd6cc896c6bf1 \ + --hash=sha256:a541414578ff47c0a9b0b8b77381ea86b0c8531ab37fc587572cb662ccd80b88 \ + --hash=sha256:ab3361159fd3dcd0e48bbe804006d5cfb074b382666e6c064112056eb234f1a9 \ + --hash=sha256:aed12a54d4e1ee647376fa541e1b7621505001f9f939debf51397b9329fd88b9 \ + --hash=sha256:af4dbec58e37f5afff4f91cdf235e8e4b0bd0127a2a4fd1040e2cad3369d2f06 \ + --hash=sha256:b031ce229114825f49cec4434fa844ccb5225e266c3e146cb4bdd025a6da52f1 \ + --hash=sha256:b22cae3c9dd55a6b4c48c63081d31c00fc11fa9db1a20c8a50ee38c1a29539d2 \ + --hash=sha256:b51aef59370baf7444de1572f7830f59ddbabd04e5292fa4218d02f085f8d299 \ + --hash=sha256:b69d832e5f5fa15b1b6b2c8eb6a9fd2c0ec1fd7729cb4322ed27771afc9fc2ac \ + --hash=sha256:b84857b66fa6510a163bb083c1199d1ee091a40163cfcbbd0642495fed096204 \ + --hash=sha256:b97dc9a17a59f350c0caa453a3cb35671a2ffa3a29a6ef3568b523b9113d84e5 \ + --hash=sha256:ba562736d3fbfe9241dad46c1a8994478d4a0e50796d80e29d50cabe8fbfcc3f \ + --hash=sha256:bac352fceed158620ce2d701ad39d4c1c76d114255a7c530e057e2b9f55bdf9f \ + --hash=sha256:baec1eb274f78b2de54471fc4c69ecbea4275965eab4b556ef7a7698dee18bf2 \ + --hash=sha256:bc8e9f15939dacb0e1f2d15f9c41b786051c10472c7a926f5771e99b49a5957f \ + --hash=sha256:bf75716377aad2c718cdf66451c5cf02042085d84522aec1f9246d3e4b8641a6 \ + --hash=sha256:c124b9206b1befe0491f48185fd30a0dd51b0f4e0e7e43ac1236066215aff272 \ + --hash=sha256:c9ed607dbbdd0d4d39b597e5bf6b0d40d844dfb0ac6a123ed79042ef08c1f87e \ + --hash=sha256:cc36cbdedf6f259371dbbbcaae5bb0e95b879bc501668ab6306af867577eb5db \ + --hash=sha256:cd788602e239ace64f257d1c9d39898ca65525583f0fbf0988bcba19418fe93f \ + --hash=sha256:d1100e68e70eb72eadba2b932b185ebf0f28fd2f0dbfe576cfa9d9894ef49752 \ + --hash=sha256:d35235a44ec38109b811c3600d15d8383297a8fab8e3dec6147477ec8636712a \ + --hash=sha256:d3e66d5b506832e56add66af88c288c1d5ba0c38b535a1a59e436b300b57b23e \ + --hash=sha256:d5548444ef60bf4c7b19ace21f032fa42d822e516a6940d36579f7bfa8513f9c \ + --hash=sha256:d5a9ec959b5381271c8ec9310aae1713b2aec29efa32e232e5ef7dcca0df0279 \ + --hash=sha256:d73b073a25a0bb8bf014345374fe2d0f63681ab5da4c22f9d2025ca3e3ea54fc \ + --hash=sha256:e021c4c778644e8cdc09487d65564265e6b149896a17d7c0f52e9a088cc44e1b \ + --hash=sha256:e1128c5d3a466279cb23c4aa32a0f6cb0e7d2961e74e9e421f90e74f75ec1edf \ + --hash=sha256:e8cc0564b286b625e673a2615ede60a1704d0cbbf1b24604e28c31ed37dc62aa \ + --hash=sha256:f25d6c4e82d7489be84f2b1c8212fafc021b3731abdb61a563c90e37cced3a21 \ + --hash=sha256:f817a54059a4cfbc385a7f51696359c642088710e731e8df80d0607193ed2b73 \ + --hash=sha256:fda91ad797e4914cca0afa8b6cccd5d2b3569ccc88731be202f6adce39503189 aioresponses==0.7.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d2c26defbb9b440ea2685ec132e90700907fd10bcca3e85ec2f157219f0d26f7 \ --hash=sha256:f795d9dbda2d61774840e7e32f5366f45752d1adc1b74c9362afd017296c7ee1 diff --git a/boefjes/requirements.txt b/boefjes/requirements.txt index 095b0a7ca16..4ad7647fb2d 100644 --- a/boefjes/requirements.txt +++ b/boefjes/requirements.txt @@ -1,83 +1,83 @@ aiohappyeyeballs==2.3.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4d6dea59215537dbc746e93e779caea8178c866856a721c9c660d7a5a7b8be03 \ --hash=sha256:6fa48b9f1317254f122a07a131a86b71ca6946ca989ce6326fff54a99a920105 -aiohttp==3.10.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01c3f1eb280008e51965a8d160a108c333136f4a39d46f516c64d2aa2e6a53f2 \ - --hash=sha256:028faf71b338f069077af6315ad54281612705d68889f5d914318cbc2aab0d50 \ - --hash=sha256:03c0c380c83f8a8d4416224aafb88d378376d6f4cadebb56b060688251055cd4 \ - --hash=sha256:0df51a3d70a2bfbb9c921619f68d6d02591f24f10e9c76de6f3388c89ed01de6 \ - --hash=sha256:120548d89f14b76a041088b582454d89389370632ee12bf39d919cc5c561d1ca \ - --hash=sha256:1988b370536eb14f0ce7f3a4a5b422ab64c4e255b3f5d7752c5f583dc8c967fc \ - --hash=sha256:1a07c76a82390506ca0eabf57c0540cf5a60c993c442928fe4928472c4c6e5e6 \ - --hash=sha256:1c2b104e81b3c3deba7e6f5bc1a9a0e9161c380530479970766a6655b8b77c7c \ - --hash=sha256:1c577cdcf8f92862363b3d598d971c6a84ed8f0bf824d4cc1ce70c2fb02acb4a \ - --hash=sha256:1f8605e573ed6c44ec689d94544b2c4bb1390aaa723a8b5a2cc0a5a485987a68 \ - --hash=sha256:21778552ef3d44aac3278cc6f6d13a6423504fa5f09f2df34bfe489ed9ded7f5 \ - --hash=sha256:2212296cdb63b092e295c3e4b4b442e7b7eb41e8a30d0f53c16d5962efed395d \ - --hash=sha256:222821c60b8f6a64c5908cb43d69c0ee978a1188f6a8433d4757d39231b42cdb \ - --hash=sha256:256ee6044214ee9d66d531bb374f065ee94e60667d6bbeaa25ca111fc3997158 \ - --hash=sha256:2a384dfbe8bfebd203b778a30a712886d147c61943675f4719b56725a8bbe803 \ - --hash=sha256:2fa643ca990323db68911b92f3f7a0ca9ae300ae340d0235de87c523601e58d9 \ - --hash=sha256:41d8dab8c64ded1edf117d2a64f353efa096c52b853ef461aebd49abae979f16 \ - --hash=sha256:440954ddc6b77257e67170d57b1026aa9545275c33312357472504eef7b4cc0b \ - --hash=sha256:47b4c2412960e64d97258f40616efddaebcb34ff664c8a972119ed38fac2a62c \ - --hash=sha256:4a9ce70f5e00380377aac0e568abd075266ff992be2e271765f7b35d228a990c \ - --hash=sha256:4dcb127ca3eb0a61205818a606393cbb60d93b7afb9accd2fd1e9081cc533144 \ - --hash=sha256:4e9e9171d2fe6bfd9d3838a6fe63b1e91b55e0bf726c16edf265536e4eafed19 \ - --hash=sha256:51d03e948e53b3639ce4d438f3d1d8202898ec6655cadcc09ec99229d4adc2a9 \ - --hash=sha256:54b7f4a20d7cc6bfa4438abbde069d417bb7a119f870975f78a2b99890226d55 \ - --hash=sha256:587237571a85716d6f71f60d103416c9df7d5acb55d96d3d3ced65f39bff9c0c \ - --hash=sha256:5951c328f9ac42d7bce7a6ded535879bc9ae13032818d036749631fa27777905 \ - --hash=sha256:5a95151a5567b3b00368e99e9c5334a919514f60888a6b6d2054fea5e66e527e \ - --hash=sha256:5c12310d153b27aa630750be44e79313acc4e864c421eb7d2bc6fa3429c41bf8 \ - --hash=sha256:5cd57ad998e3038aa87c38fe85c99ed728001bf5dde8eca121cadee06ee3f637 \ - --hash=sha256:615348fab1a9ef7d0960a905e83ad39051ae9cb0d2837da739b5d3a7671e497a \ - --hash=sha256:67f7639424c313125213954e93a6229d3a1d386855d70c292a12628f600c7150 \ - --hash=sha256:68164d43c580c2e8bf8e0eb4960142919d304052ccab92be10250a3a33b53268 \ - --hash=sha256:68cc24f707ed9cb961f6ee04020ca01de2c89b2811f3cf3361dc7c96a14bfbcc \ - --hash=sha256:6b14c19172eb53b63931d3e62a9749d6519f7c121149493e6eefca055fcdb352 \ - --hash=sha256:777e23609899cb230ad2642b4bdf1008890f84968be78de29099a8a86f10b261 \ - --hash=sha256:786299d719eb5d868f161aeec56d589396b053925b7e0ce36e983d30d0a3e55c \ - --hash=sha256:7ccf1f0a304352c891d124ac1a9dea59b14b2abed1704aaa7689fc90ef9c5be1 \ - --hash=sha256:88596384c3bec644a96ae46287bb646d6a23fa6014afe3799156aef42669c6bd \ - --hash=sha256:89b47c125ab07f0831803b88aeb12b04c564d5f07a1c1a225d4eb4d2f26e8b5e \ - --hash=sha256:8b0d058e4e425d3b45e8ec70d49b402f4d6b21041e674798b1f91ba027c73f28 \ - --hash=sha256:8c81ff4afffef9b1186639506d70ea90888218f5ddfff03870e74ec80bb59970 \ - --hash=sha256:8db9b749f589b5af8e4993623dbda6716b2b7a5fcb0fa2277bf3ce4b278c7059 \ - --hash=sha256:8e5a26d7aac4c0d8414a347da162696eea0629fdce939ada6aedf951abb1d745 \ - --hash=sha256:8fbf8c0ded367c5c8eaf585f85ca8dd85ff4d5b73fb8fe1e6ac9e1b5e62e11f7 \ - --hash=sha256:93094eba50bc2ad4c40ff4997ead1fdcd41536116f2e7d6cfec9596a8ecb3615 \ - --hash=sha256:9c186b270979fb1dee3ababe2d12fb243ed7da08b30abc83ebac3a928a4ddb15 \ - --hash=sha256:9cb54f5725b4b37af12edf6c9e834df59258c82c15a244daa521a065fbb11717 \ - --hash=sha256:9fbff00646cf8211b330690eb2fd64b23e1ce5b63a342436c1d1d6951d53d8dd \ - --hash=sha256:a57e73f9523e980f6101dc9a83adcd7ac0006ea8bf7937ca3870391c7bb4f8ff \ - --hash=sha256:a702bd3663b5cbf3916e84bf332400d24cdb18399f0877ca6b313ce6c08bfb43 \ - --hash=sha256:a77c79bac8d908d839d32c212aef2354d2246eb9deb3e2cb01ffa83fb7a6ea5d \ - --hash=sha256:abda4009a30d51d3f06f36bc7411a62b3e647fa6cc935ef667e3e3d3a7dd09b1 \ - --hash=sha256:b023b68c61ab0cd48bd38416b421464a62c381e32b9dc7b4bdfa2905807452a4 \ - --hash=sha256:b07286a1090483799599a2f72f76ac396993da31f6e08efedb59f40876c144fa \ - --hash=sha256:b0de63ff0307eac3961b4af74382d30220d4813f36b7aaaf57f063a1243b4214 \ - --hash=sha256:b7d5bb926805022508b7ddeaad957f1fce7a8d77532068d7bdb431056dc630cd \ - --hash=sha256:b9db600a86414a9a653e3c1c7f6a2f6a1894ab8f83d11505247bd1b90ad57157 \ - --hash=sha256:b9fb6508893dc31cfcbb8191ef35abd79751db1d6871b3e2caee83959b4d91eb \ - --hash=sha256:bc3ea6ef2a83edad84bbdb5d96e22f587b67c68922cd7b6f9d8f24865e655bcf \ - --hash=sha256:bde0693073fd5e542e46ea100aa6c1a5d36282dbdbad85b1c3365d5421490a92 \ - --hash=sha256:bf66149bb348d8e713f3a8e0b4f5b952094c2948c408e1cfef03b49e86745d60 \ - --hash=sha256:bfe33cba6e127d0b5b417623c9aa621f0a69f304742acdca929a9fdab4593693 \ - --hash=sha256:c8fb76214b5b739ce59e2236a6489d9dc3483649cfd6f563dbf5d8e40dbdd57d \ - --hash=sha256:cb8b79a65332e1a426ccb6290ce0409e1dc16b4daac1cc5761e059127fa3d134 \ - --hash=sha256:d6bbe2c90c10382ca96df33b56e2060404a4f0f88673e1e84b44c8952517e5f3 \ - --hash=sha256:d8311d0d690487359fe2247ec5d2cac9946e70d50dced8c01ce9e72341c21151 \ - --hash=sha256:d8a8221a63602008550022aa3a4152ca357e1dde7ab3dd1da7e1925050b56863 \ - --hash=sha256:de1a91d5faded9054957ed0a9e01b9d632109341942fc123947ced358c5d9009 \ - --hash=sha256:df31641e3f02b77eb3c5fb63c0508bee0fc067cf153da0e002ebbb0db0b6d91a \ - --hash=sha256:e7168782621be4448d90169a60c8b37e9b0926b3b79b6097bc180c0a8a119e73 \ - --hash=sha256:e7b55d9ede66af7feb6de87ff277e0ccf6d51c7db74cc39337fe3a0e31b5872d \ - --hash=sha256:e7dbf637f87dd315fa1f36aaed8afa929ee2c607454fb7791e74c88a0d94da59 \ - --hash=sha256:f5293726943bdcea24715b121d8c4ae12581441d22623b0e6ab12d07ce85f9c4 \ - --hash=sha256:f5dd109a925fee4c9ac3f6a094900461a2712df41745f5d04782ebcbe6479ccb \ - --hash=sha256:f6979b4f20d3e557a867da9d9227de4c156fcdcb348a5848e3e6190fd7feb972 \ - --hash=sha256:f9f8beed277488a52ee2b459b23c4135e54d6a819eaba2e120e57311015b58e9 +aiohttp==3.10.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:05d66203a530209cbe40f102ebaac0b2214aba2a33c075d0bf825987c36f1f0b \ + --hash=sha256:08bd0754d257b2db27d6bab208c74601df6f21bfe4cb2ec7b258ba691aac64b3 \ + --hash=sha256:0974f3b5b0132edcec92c3306f858ad4356a63d26b18021d859c9927616ebf27 \ + --hash=sha256:09bc79275737d4dc066e0ae2951866bb36d9c6b460cb7564f111cc0427f14844 \ + --hash=sha256:123e5819bfe1b87204575515cf448ab3bf1489cdeb3b61012bde716cda5853e7 \ + --hash=sha256:13031e7ec1188274bad243255c328cc3019e36a5a907978501256000d57a7201 \ + --hash=sha256:166de65e2e4e63357cfa8417cf952a519ac42f1654cb2d43ed76899e2319b1ee \ + --hash=sha256:214277dcb07ab3875f17ee1c777d446dcce75bea85846849cc9d139ab8f5081f \ + --hash=sha256:21650e7032cc2d31fc23d353d7123e771354f2a3d5b05a5647fc30fea214e696 \ + --hash=sha256:24fade6dae446b183e2410a8628b80df9b7a42205c6bfc2eff783cbeedc224a2 \ + --hash=sha256:2a5d0ea8a6467b15d53b00c4e8ea8811e47c3cc1bdbc62b1aceb3076403d551f \ + --hash=sha256:2b0f670502100cdc567188c49415bebba947eb3edaa2028e1a50dd81bd13363f \ + --hash=sha256:2bbc55a964b8eecb341e492ae91c3bd0848324d313e1e71a27e3d96e6ee7e8e8 \ + --hash=sha256:32007fdcaab789689c2ecaaf4b71f8e37bf012a15cd02c0a9db8c4d0e7989fa8 \ + --hash=sha256:3461d9294941937f07bbbaa6227ba799bc71cc3b22c40222568dc1cca5118f68 \ + --hash=sha256:3731a73ddc26969d65f90471c635abd4e1546a25299b687e654ea6d2fc052394 \ + --hash=sha256:38d91b98b4320ffe66efa56cb0f614a05af53b675ce1b8607cdb2ac826a8d58e \ + --hash=sha256:3a9dcdccf50284b1b0dc72bc57e5bbd3cc9bf019060dfa0668f63241ccc16aa7 \ + --hash=sha256:434b3ab75833accd0b931d11874e206e816f6e6626fd69f643d6a8269cd9166a \ + --hash=sha256:43b09f38a67679e32d380fe512189ccb0b25e15afc79b23fbd5b5e48e4fc8fd9 \ + --hash=sha256:44bb159b55926b57812dca1b21c34528e800963ffe130d08b049b2d6b994ada7 \ + --hash=sha256:48665433bb59144aaf502c324694bec25867eb6630fcd831f7a893ca473fcde4 \ + --hash=sha256:50544fe498c81cb98912afabfc4e4d9d85e89f86238348e3712f7ca6a2f01dab \ + --hash=sha256:5337cc742a03f9e3213b097abff8781f79de7190bbfaa987bd2b7ceb5bb0bdec \ + --hash=sha256:56fb94bae2be58f68d000d046172d8b8e6b1b571eb02ceee5535e9633dcd559c \ + --hash=sha256:59c489661edbd863edb30a8bd69ecb044bd381d1818022bc698ba1b6f80e5dd1 \ + --hash=sha256:5ba2e838b5e6a8755ac8297275c9460e729dc1522b6454aee1766c6de6d56e5e \ + --hash=sha256:61ccb867b2f2f53df6598eb2a93329b5eee0b00646ee79ea67d68844747a418e \ + --hash=sha256:671efce3a4a0281060edf9a07a2f7e6230dca3a1cbc61d110eee7753d28405f7 \ + --hash=sha256:673bb6e3249dc8825df1105f6ef74e2eab779b7ff78e96c15cadb78b04a83752 \ + --hash=sha256:6ae9ae382d1c9617a91647575255ad55a48bfdde34cc2185dd558ce476bf16e9 \ + --hash=sha256:6c51ed03e19c885c8e91f574e4bbe7381793f56f93229731597e4a499ffef2a5 \ + --hash=sha256:6d881353264e6156f215b3cb778c9ac3184f5465c2ece5e6fce82e68946868ef \ + --hash=sha256:7084876352ba3833d5d214e02b32d794e3fd9cf21fdba99cff5acabeb90d9806 \ + --hash=sha256:70b4a4984a70a2322b70e088d654528129783ac1ebbf7dd76627b3bd22db2f17 \ + --hash=sha256:71bb1d97bfe7e6726267cea169fdf5df7658831bb68ec02c9c6b9f3511e108bb \ + --hash=sha256:7c126f532caf238031c19d169cfae3c6a59129452c990a6e84d6e7b198a001dc \ + --hash=sha256:7f9159ae530297f61a00116771e57516f89a3de6ba33f314402e41560872b50a \ + --hash=sha256:812121a201f0c02491a5db335a737b4113151926a79ae9ed1a9f41ea225c0e3f \ + --hash=sha256:8542c9e5bcb2bd3115acdf5adc41cda394e7360916197805e7e32b93d821ef93 \ + --hash=sha256:85466b5a695c2a7db13eb2c200af552d13e6a9313d7fa92e4ffe04a2c0ea74c1 \ + --hash=sha256:8d98c604c93403288591d7d6d7d6cc8a63459168f8846aeffd5b3a7f3b3e5e09 \ + --hash=sha256:8da6b48c20ce78f5721068f383e0e113dde034e868f1b2f5ee7cb1e95f91db57 \ + --hash=sha256:926e68438f05703e500b06fe7148ef3013dd6f276de65c68558fa9974eeb59ad \ + --hash=sha256:9743fa34a10a36ddd448bba8a3adc2a66a1c575c3c2940301bacd6cc896c6bf1 \ + --hash=sha256:a541414578ff47c0a9b0b8b77381ea86b0c8531ab37fc587572cb662ccd80b88 \ + --hash=sha256:ab3361159fd3dcd0e48bbe804006d5cfb074b382666e6c064112056eb234f1a9 \ + --hash=sha256:aed12a54d4e1ee647376fa541e1b7621505001f9f939debf51397b9329fd88b9 \ + --hash=sha256:af4dbec58e37f5afff4f91cdf235e8e4b0bd0127a2a4fd1040e2cad3369d2f06 \ + --hash=sha256:b031ce229114825f49cec4434fa844ccb5225e266c3e146cb4bdd025a6da52f1 \ + --hash=sha256:b22cae3c9dd55a6b4c48c63081d31c00fc11fa9db1a20c8a50ee38c1a29539d2 \ + --hash=sha256:b51aef59370baf7444de1572f7830f59ddbabd04e5292fa4218d02f085f8d299 \ + --hash=sha256:b69d832e5f5fa15b1b6b2c8eb6a9fd2c0ec1fd7729cb4322ed27771afc9fc2ac \ + --hash=sha256:b84857b66fa6510a163bb083c1199d1ee091a40163cfcbbd0642495fed096204 \ + --hash=sha256:b97dc9a17a59f350c0caa453a3cb35671a2ffa3a29a6ef3568b523b9113d84e5 \ + --hash=sha256:ba562736d3fbfe9241dad46c1a8994478d4a0e50796d80e29d50cabe8fbfcc3f \ + --hash=sha256:bac352fceed158620ce2d701ad39d4c1c76d114255a7c530e057e2b9f55bdf9f \ + --hash=sha256:baec1eb274f78b2de54471fc4c69ecbea4275965eab4b556ef7a7698dee18bf2 \ + --hash=sha256:bc8e9f15939dacb0e1f2d15f9c41b786051c10472c7a926f5771e99b49a5957f \ + --hash=sha256:bf75716377aad2c718cdf66451c5cf02042085d84522aec1f9246d3e4b8641a6 \ + --hash=sha256:c124b9206b1befe0491f48185fd30a0dd51b0f4e0e7e43ac1236066215aff272 \ + --hash=sha256:c9ed607dbbdd0d4d39b597e5bf6b0d40d844dfb0ac6a123ed79042ef08c1f87e \ + --hash=sha256:cc36cbdedf6f259371dbbbcaae5bb0e95b879bc501668ab6306af867577eb5db \ + --hash=sha256:cd788602e239ace64f257d1c9d39898ca65525583f0fbf0988bcba19418fe93f \ + --hash=sha256:d1100e68e70eb72eadba2b932b185ebf0f28fd2f0dbfe576cfa9d9894ef49752 \ + --hash=sha256:d35235a44ec38109b811c3600d15d8383297a8fab8e3dec6147477ec8636712a \ + --hash=sha256:d3e66d5b506832e56add66af88c288c1d5ba0c38b535a1a59e436b300b57b23e \ + --hash=sha256:d5548444ef60bf4c7b19ace21f032fa42d822e516a6940d36579f7bfa8513f9c \ + --hash=sha256:d5a9ec959b5381271c8ec9310aae1713b2aec29efa32e232e5ef7dcca0df0279 \ + --hash=sha256:d73b073a25a0bb8bf014345374fe2d0f63681ab5da4c22f9d2025ca3e3ea54fc \ + --hash=sha256:e021c4c778644e8cdc09487d65564265e6b149896a17d7c0f52e9a088cc44e1b \ + --hash=sha256:e1128c5d3a466279cb23c4aa32a0f6cb0e7d2961e74e9e421f90e74f75ec1edf \ + --hash=sha256:e8cc0564b286b625e673a2615ede60a1704d0cbbf1b24604e28c31ed37dc62aa \ + --hash=sha256:f25d6c4e82d7489be84f2b1c8212fafc021b3731abdb61a563c90e37cced3a21 \ + --hash=sha256:f817a54059a4cfbc385a7f51696359c642088710e731e8df80d0607193ed2b73 \ + --hash=sha256:fda91ad797e4914cca0afa8b6cccd5d2b3569ccc88731be202f6adce39503189 aioresponses==0.7.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d2c26defbb9b440ea2685ec132e90700907fd10bcca3e85ec2f157219f0d26f7 \ --hash=sha256:f795d9dbda2d61774840e7e32f5366f45752d1adc1b74c9362afd017296c7ee1 diff --git a/bytes/poetry.lock b/bytes/poetry.lock index bd33141683c..03c8c961fe8 100644 --- a/bytes/poetry.lock +++ b/bytes/poetry.lock @@ -514,69 +514,61 @@ test = ["objgraph", "psutil"] [[package]] name = "grpcio" -version = "1.62.0" +version = "1.65.4" description = "HTTP/2-based RPC framework" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "grpcio-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271"}, - {file = "grpcio-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6"}, - {file = "grpcio-1.62.0-cp310-cp310-win32.whl", hash = "sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc"}, - {file = "grpcio-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa"}, - {file = "grpcio-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f"}, - {file = "grpcio-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e"}, - {file = "grpcio-1.62.0-cp311-cp311-win32.whl", hash = "sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd"}, - {file = "grpcio-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334"}, - {file = "grpcio-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8"}, - {file = "grpcio-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388"}, - {file = "grpcio-1.62.0-cp312-cp312-win32.whl", hash = "sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701"}, - {file = "grpcio-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842"}, - {file = "grpcio-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9"}, - {file = "grpcio-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b"}, - {file = "grpcio-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b"}, - {file = "grpcio-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35"}, - {file = "grpcio-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38"}, - {file = "grpcio-1.62.0-cp38-cp38-win32.whl", hash = "sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe"}, - {file = "grpcio-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270"}, - {file = "grpcio-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170"}, - {file = "grpcio-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a"}, - {file = "grpcio-1.62.0-cp39-cp39-win32.whl", hash = "sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93"}, - {file = "grpcio-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5"}, - {file = "grpcio-1.62.0.tar.gz", hash = "sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7"}, + {file = "grpcio-1.65.4-cp310-cp310-linux_armv7l.whl", hash = "sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c"}, + {file = "grpcio-1.65.4-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e"}, + {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de"}, + {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d"}, + {file = "grpcio-1.65.4-cp310-cp310-win32.whl", hash = "sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1"}, + {file = "grpcio-1.65.4-cp310-cp310-win_amd64.whl", hash = "sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec"}, + {file = "grpcio-1.65.4-cp311-cp311-linux_armv7l.whl", hash = "sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef"}, + {file = "grpcio-1.65.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4"}, + {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e"}, + {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5"}, + {file = "grpcio-1.65.4-cp311-cp311-win32.whl", hash = "sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b"}, + {file = "grpcio-1.65.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558"}, + {file = "grpcio-1.65.4-cp312-cp312-linux_armv7l.whl", hash = "sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56"}, + {file = "grpcio-1.65.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63"}, + {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a"}, + {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28"}, + {file = "grpcio-1.65.4-cp312-cp312-win32.whl", hash = "sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0"}, + {file = "grpcio-1.65.4-cp312-cp312-win_amd64.whl", hash = "sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416"}, + {file = "grpcio-1.65.4-cp38-cp38-linux_armv7l.whl", hash = "sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021"}, + {file = "grpcio-1.65.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816"}, + {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524"}, + {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7"}, + {file = "grpcio-1.65.4-cp38-cp38-win32.whl", hash = "sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a"}, + {file = "grpcio-1.65.4-cp38-cp38-win_amd64.whl", hash = "sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f"}, + {file = "grpcio-1.65.4-cp39-cp39-linux_armv7l.whl", hash = "sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733"}, + {file = "grpcio-1.65.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b"}, + {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2"}, + {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257"}, + {file = "grpcio-1.65.4-cp39-cp39-win32.whl", hash = "sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d"}, + {file = "grpcio-1.65.4-cp39-cp39-win_amd64.whl", hash = "sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9"}, + {file = "grpcio-1.65.4.tar.gz", hash = "sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.62.0)"] +protobuf = ["grpcio-tools (>=1.65.4)"] [[package]] name = "h11" @@ -1487,51 +1479,30 @@ description = "Database Abstraction Library" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.51-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:1a09d5bd1a40d76ad90e5570530e082ddc000e1d92de495746f6257dc08f166b"}, {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2be4e6294c53f2ec8ea36486b56390e3bcaa052bf3a9a47005687ccf376745d1"}, {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca484ca11c65e05639ffe80f20d45e6be81fbec7683d6c9a15cd421e6e8b340"}, {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0535d5b57d014d06ceeaeffd816bb3a6e2dddeb670222570b8c4953e2d2ea678"}, {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af55cc207865d641a57f7044e98b08b09220da3d1b13a46f26487cc2f898a072"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-win32.whl", hash = "sha256:7af40425ac535cbda129d9915edcaa002afe35d84609fd3b9d6a8c46732e02ee"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-win_amd64.whl", hash = "sha256:8d1d7d63e5d2f4e92a39ae1e897a5d551720179bb8d1254883e7113d3826d43c"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eaeeb2464019765bc4340214fca1143081d49972864773f3f1e95dba5c7edc7d"}, {file = "SQLAlchemy-1.4.51-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7deeae5071930abb3669b5185abb6c33ddfd2398f87660fafdb9e6a5fb0f3f2f"}, {file = "SQLAlchemy-1.4.51-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0892e7ac8bc76da499ad3ee8de8da4d7905a3110b952e2a35a940dab1ffa550e"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-win32.whl", hash = "sha256:50e074aea505f4427151c286955ea025f51752fa42f9939749336672e0674c81"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-win_amd64.whl", hash = "sha256:3b0cd89a7bd03f57ae58263d0f828a072d1b440c8c2949f38f3b446148321171"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a33cb3f095e7d776ec76e79d92d83117438b6153510770fcd57b9c96f9ef623d"}, {file = "SQLAlchemy-1.4.51-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cacc0b2dd7d22a918a9642fc89840a5d3cee18a0e1fe41080b1141b23b10916"}, {file = "SQLAlchemy-1.4.51-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:245c67c88e63f1523e9216cad6ba3107dea2d3ee19adc359597a628afcabfbcb"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-win32.whl", hash = "sha256:8e702e7489f39375601c7ea5a0bef207256828a2bc5986c65cb15cd0cf097a87"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-win_amd64.whl", hash = "sha256:0525c4905b4b52d8ccc3c203c9d7ab2a80329ffa077d4bacf31aefda7604dc65"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:1980e6eb6c9be49ea8f89889989127daafc43f0b1b6843d71efab1514973cca0"}, {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ec7a0ed9b32afdf337172678a4a0e6419775ba4e649b66f49415615fa47efbd"}, {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352df882088a55293f621328ec33b6ffca936ad7f23013b22520542e1ab6ad1b"}, {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:86a22143a4001f53bf58027b044da1fb10d67b62a785fc1390b5c7f089d9838c"}, {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c37bc677690fd33932182b85d37433845de612962ed080c3e4d92f758d1bd894"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-win32.whl", hash = "sha256:d0a83afab5e062abffcdcbcc74f9d3ba37b2385294dd0927ad65fc6ebe04e054"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-win_amd64.whl", hash = "sha256:a61184c7289146c8cff06b6b41807c6994c6d437278e72cf00ff7fe1c7a263d1"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:3f0ef620ecbab46e81035cf3dedfb412a7da35340500ba470f9ce43a1e6c423b"}, {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c55040d8ea65414de7c47f1a23823cd9f3fad0dc93e6b6b728fee81230f817b"}, {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ef80328e3fee2be0a1abe3fe9445d3a2e52a1282ba342d0dab6edf1fef4707"}, {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f8cafa6f885a0ff5e39efa9325195217bb47d5929ab0051636610d24aef45ade"}, {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8f2df79a46e130235bc5e1bbef4de0583fb19d481eaa0bffa76e8347ea45ec6"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-win32.whl", hash = "sha256:f2e5b6f5cf7c18df66d082604a1d9c7a2d18f7d1dbe9514a2afaccbb51cc4fc3"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-win_amd64.whl", hash = "sha256:5e180fff133d21a800c4f050733d59340f40d42364fcb9d14f6a67764bdc48d2"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7d8139ca0b9f93890ab899da678816518af74312bb8cd71fb721436a93a93298"}, {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb18549b770351b54e1ab5da37d22bc530b8bfe2ee31e22b9ebe650640d2ef12"}, {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55e699466106d09f028ab78d3c2e1f621b5ef2c8694598242259e4515715da7c"}, {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2ad16880ccd971ac8e570550fbdef1385e094b022d6fc85ef3ce7df400dddad3"}, {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b97fd5bb6b7c1a64b7ac0632f7ce389b8ab362e7bd5f60654c2a418496be5d7f"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-win32.whl", hash = "sha256:cecb66492440ae8592797dd705a0cbaa6abe0555f4fa6c5f40b078bd2740fc6b"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-win_amd64.whl", hash = "sha256:39b02b645632c5fe46b8dd30755682f629ffbb62ff317ecc14c998c21b2896ff"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b03850c290c765b87102959ea53299dc9addf76ca08a06ea98383348ae205c99"}, {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e646b19f47d655261b22df9976e572f588185279970efba3d45c377127d35349"}, {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3cf56cc36d42908495760b223ca9c2c0f9f0002b4eddc994b24db5fcb86a9e4"}, {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0d661cff58c91726c601cc0ee626bf167b20cc4d7941c93c5f3ac28dc34ddbea"}, {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3823dda635988e6744d4417e13f2e2b5fe76c4bf29dd67e95f98717e1b094cad"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-win32.whl", hash = "sha256:b00cf0471888823b7a9f722c6c41eb6985cf34f077edcf62695ac4bed6ec01ee"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-win_amd64.whl", hash = "sha256:a055ba17f4675aadcda3005df2e28a86feb731fdcc865e1f6b4f209ed1225cba"}, {file = "SQLAlchemy-1.4.51.tar.gz", hash = "sha256:e7908c2025eb18394e32d65dd02d2e37e17d733cdbe7d78231c2b6d7eb20cdb9"}, ] diff --git a/bytes/requirements-dev.txt b/bytes/requirements-dev.txt index f69232d60b7..c7ef092702d 100644 --- a/bytes/requirements-dev.txt +++ b/bytes/requirements-dev.txt @@ -298,61 +298,53 @@ greenlet==3.0.3 ; python_version >= "3.10" and (platform_machine == "aarch64" or --hash=sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf \ --hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \ --hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33 -grpcio==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701 \ - --hash=sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e \ - --hash=sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532 \ - --hash=sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a \ - --hash=sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271 \ - --hash=sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f \ - --hash=sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7 \ - --hash=sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b \ - --hash=sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4 \ - --hash=sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839 \ - --hash=sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6 \ - --hash=sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb \ - --hash=sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e \ - --hash=sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93 \ - --hash=sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f \ - --hash=sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6 \ - --hash=sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1 \ - --hash=sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35 \ - --hash=sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842 \ - --hash=sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6 \ - --hash=sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c \ - --hash=sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873 \ - --hash=sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7 \ - --hash=sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c \ - --hash=sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928 \ - --hash=sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9 \ - --hash=sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c \ - --hash=sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021 \ - --hash=sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa \ - --hash=sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38 \ - --hash=sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc \ - --hash=sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe \ - --hash=sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8 \ - --hash=sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402 \ - --hash=sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388 \ - --hash=sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0 \ - --hash=sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b \ - --hash=sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b \ - --hash=sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2 \ - --hash=sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b \ - --hash=sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5 \ - --hash=sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829 \ - --hash=sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2 \ - --hash=sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6 \ - --hash=sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd \ - --hash=sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0 \ - --hash=sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8 \ - --hash=sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334 \ - --hash=sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee \ - --hash=sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c \ - --hash=sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72 \ - --hash=sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4 \ - --hash=sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270 \ - --hash=sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170 +grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ + --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ + --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ + --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ + --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ + --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ + --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ + --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ + --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ + --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ + --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ + --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ + --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ + --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ + --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ + --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ + --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ + --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ + --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ + --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ + --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ + --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ + --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ + --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ + --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ + --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ + --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ + --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ + --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ + --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ + --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ + --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ + --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ + --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ + --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ + --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ + --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ + --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ + --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ + --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ + --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ + --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ + --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ + --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ + --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ + --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -665,12 +657,9 @@ sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0525c4905b4b52d8ccc3c203c9d7ab2a80329ffa077d4bacf31aefda7604dc65 \ --hash=sha256:0535d5b57d014d06ceeaeffd816bb3a6e2dddeb670222570b8c4953e2d2ea678 \ --hash=sha256:0892e7ac8bc76da499ad3ee8de8da4d7905a3110b952e2a35a940dab1ffa550e \ --hash=sha256:0d661cff58c91726c601cc0ee626bf167b20cc4d7941c93c5f3ac28dc34ddbea \ - --hash=sha256:1980e6eb6c9be49ea8f89889989127daafc43f0b1b6843d71efab1514973cca0 \ - --hash=sha256:1a09d5bd1a40d76ad90e5570530e082ddc000e1d92de495746f6257dc08f166b \ --hash=sha256:245c67c88e63f1523e9216cad6ba3107dea2d3ee19adc359597a628afcabfbcb \ --hash=sha256:2ad16880ccd971ac8e570550fbdef1385e094b022d6fc85ef3ce7df400dddad3 \ --hash=sha256:2be4e6294c53f2ec8ea36486b56390e3bcaa052bf3a9a47005687ccf376745d1 \ @@ -678,38 +667,20 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:352df882088a55293f621328ec33b6ffca936ad7f23013b22520542e1ab6ad1b \ --hash=sha256:3823dda635988e6744d4417e13f2e2b5fe76c4bf29dd67e95f98717e1b094cad \ --hash=sha256:38ef80328e3fee2be0a1abe3fe9445d3a2e52a1282ba342d0dab6edf1fef4707 \ - --hash=sha256:39b02b645632c5fe46b8dd30755682f629ffbb62ff317ecc14c998c21b2896ff \ - --hash=sha256:3b0cd89a7bd03f57ae58263d0f828a072d1b440c8c2949f38f3b446148321171 \ --hash=sha256:3ec7a0ed9b32afdf337172678a4a0e6419775ba4e649b66f49415615fa47efbd \ - --hash=sha256:3f0ef620ecbab46e81035cf3dedfb412a7da35340500ba470f9ce43a1e6c423b \ - --hash=sha256:50e074aea505f4427151c286955ea025f51752fa42f9939749336672e0674c81 \ --hash=sha256:55e699466106d09f028ab78d3c2e1f621b5ef2c8694598242259e4515715da7c \ - --hash=sha256:5e180fff133d21a800c4f050733d59340f40d42364fcb9d14f6a67764bdc48d2 \ --hash=sha256:6cacc0b2dd7d22a918a9642fc89840a5d3cee18a0e1fe41080b1141b23b10916 \ - --hash=sha256:7af40425ac535cbda129d9915edcaa002afe35d84609fd3b9d6a8c46732e02ee \ - --hash=sha256:7d8139ca0b9f93890ab899da678816518af74312bb8cd71fb721436a93a93298 \ --hash=sha256:7deeae5071930abb3669b5185abb6c33ddfd2398f87660fafdb9e6a5fb0f3f2f \ --hash=sha256:86a22143a4001f53bf58027b044da1fb10d67b62a785fc1390b5c7f089d9838c \ --hash=sha256:8ca484ca11c65e05639ffe80f20d45e6be81fbec7683d6c9a15cd421e6e8b340 \ - --hash=sha256:8d1d7d63e5d2f4e92a39ae1e897a5d551720179bb8d1254883e7113d3826d43c \ - --hash=sha256:8e702e7489f39375601c7ea5a0bef207256828a2bc5986c65cb15cd0cf097a87 \ - --hash=sha256:a055ba17f4675aadcda3005df2e28a86feb731fdcc865e1f6b4f209ed1225cba \ - --hash=sha256:a33cb3f095e7d776ec76e79d92d83117438b6153510770fcd57b9c96f9ef623d \ - --hash=sha256:a61184c7289146c8cff06b6b41807c6994c6d437278e72cf00ff7fe1c7a263d1 \ --hash=sha256:af55cc207865d641a57f7044e98b08b09220da3d1b13a46f26487cc2f898a072 \ - --hash=sha256:b00cf0471888823b7a9f722c6c41eb6985cf34f077edcf62695ac4bed6ec01ee \ - --hash=sha256:b03850c290c765b87102959ea53299dc9addf76ca08a06ea98383348ae205c99 \ --hash=sha256:b97fd5bb6b7c1a64b7ac0632f7ce389b8ab362e7bd5f60654c2a418496be5d7f \ --hash=sha256:c37bc677690fd33932182b85d37433845de612962ed080c3e4d92f758d1bd894 \ - --hash=sha256:cecb66492440ae8592797dd705a0cbaa6abe0555f4fa6c5f40b078bd2740fc6b \ - --hash=sha256:d0a83afab5e062abffcdcbcc74f9d3ba37b2385294dd0927ad65fc6ebe04e054 \ --hash=sha256:d3cf56cc36d42908495760b223ca9c2c0f9f0002b4eddc994b24db5fcb86a9e4 \ --hash=sha256:e646b19f47d655261b22df9976e572f588185279970efba3d45c377127d35349 \ --hash=sha256:e7908c2025eb18394e32d65dd02d2e37e17d733cdbe7d78231c2b6d7eb20cdb9 \ --hash=sha256:e8f2df79a46e130235bc5e1bbef4de0583fb19d481eaa0bffa76e8347ea45ec6 \ - --hash=sha256:eaeeb2464019765bc4340214fca1143081d49972864773f3f1e95dba5c7edc7d \ --hash=sha256:eb18549b770351b54e1ab5da37d22bc530b8bfe2ee31e22b9ebe650640d2ef12 \ - --hash=sha256:f2e5b6f5cf7c18df66d082604a1d9c7a2d18f7d1dbe9514a2afaccbb51cc4fc3 \ --hash=sha256:f8cafa6f885a0ff5e39efa9325195217bb47d5929ab0051636610d24aef45ade starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ diff --git a/bytes/requirements.txt b/bytes/requirements.txt index bbf17a5d180..d3d077cc7d0 100644 --- a/bytes/requirements.txt +++ b/bytes/requirements.txt @@ -298,61 +298,53 @@ greenlet==3.0.3 ; python_version >= "3.10" and (platform_machine == "aarch64" or --hash=sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf \ --hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \ --hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33 -grpcio==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701 \ - --hash=sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e \ - --hash=sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532 \ - --hash=sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a \ - --hash=sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271 \ - --hash=sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f \ - --hash=sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7 \ - --hash=sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b \ - --hash=sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4 \ - --hash=sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839 \ - --hash=sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6 \ - --hash=sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb \ - --hash=sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e \ - --hash=sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93 \ - --hash=sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f \ - --hash=sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6 \ - --hash=sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1 \ - --hash=sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35 \ - --hash=sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842 \ - --hash=sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6 \ - --hash=sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c \ - --hash=sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873 \ - --hash=sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7 \ - --hash=sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c \ - --hash=sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928 \ - --hash=sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9 \ - --hash=sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c \ - --hash=sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021 \ - --hash=sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa \ - --hash=sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38 \ - --hash=sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc \ - --hash=sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe \ - --hash=sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8 \ - --hash=sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402 \ - --hash=sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388 \ - --hash=sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0 \ - --hash=sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b \ - --hash=sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b \ - --hash=sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2 \ - --hash=sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b \ - --hash=sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5 \ - --hash=sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829 \ - --hash=sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2 \ - --hash=sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6 \ - --hash=sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd \ - --hash=sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0 \ - --hash=sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8 \ - --hash=sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334 \ - --hash=sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee \ - --hash=sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c \ - --hash=sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72 \ - --hash=sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4 \ - --hash=sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270 \ - --hash=sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170 +grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ + --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ + --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ + --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ + --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ + --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ + --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ + --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ + --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ + --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ + --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ + --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ + --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ + --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ + --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ + --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ + --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ + --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ + --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ + --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ + --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ + --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ + --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ + --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ + --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ + --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ + --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ + --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ + --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ + --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ + --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ + --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ + --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ + --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ + --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ + --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ + --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ + --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ + --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ + --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ + --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ + --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ + --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ + --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ + --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ + --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -650,12 +642,9 @@ sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0525c4905b4b52d8ccc3c203c9d7ab2a80329ffa077d4bacf31aefda7604dc65 \ --hash=sha256:0535d5b57d014d06ceeaeffd816bb3a6e2dddeb670222570b8c4953e2d2ea678 \ --hash=sha256:0892e7ac8bc76da499ad3ee8de8da4d7905a3110b952e2a35a940dab1ffa550e \ --hash=sha256:0d661cff58c91726c601cc0ee626bf167b20cc4d7941c93c5f3ac28dc34ddbea \ - --hash=sha256:1980e6eb6c9be49ea8f89889989127daafc43f0b1b6843d71efab1514973cca0 \ - --hash=sha256:1a09d5bd1a40d76ad90e5570530e082ddc000e1d92de495746f6257dc08f166b \ --hash=sha256:245c67c88e63f1523e9216cad6ba3107dea2d3ee19adc359597a628afcabfbcb \ --hash=sha256:2ad16880ccd971ac8e570550fbdef1385e094b022d6fc85ef3ce7df400dddad3 \ --hash=sha256:2be4e6294c53f2ec8ea36486b56390e3bcaa052bf3a9a47005687ccf376745d1 \ @@ -663,38 +652,20 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:352df882088a55293f621328ec33b6ffca936ad7f23013b22520542e1ab6ad1b \ --hash=sha256:3823dda635988e6744d4417e13f2e2b5fe76c4bf29dd67e95f98717e1b094cad \ --hash=sha256:38ef80328e3fee2be0a1abe3fe9445d3a2e52a1282ba342d0dab6edf1fef4707 \ - --hash=sha256:39b02b645632c5fe46b8dd30755682f629ffbb62ff317ecc14c998c21b2896ff \ - --hash=sha256:3b0cd89a7bd03f57ae58263d0f828a072d1b440c8c2949f38f3b446148321171 \ --hash=sha256:3ec7a0ed9b32afdf337172678a4a0e6419775ba4e649b66f49415615fa47efbd \ - --hash=sha256:3f0ef620ecbab46e81035cf3dedfb412a7da35340500ba470f9ce43a1e6c423b \ - --hash=sha256:50e074aea505f4427151c286955ea025f51752fa42f9939749336672e0674c81 \ --hash=sha256:55e699466106d09f028ab78d3c2e1f621b5ef2c8694598242259e4515715da7c \ - --hash=sha256:5e180fff133d21a800c4f050733d59340f40d42364fcb9d14f6a67764bdc48d2 \ --hash=sha256:6cacc0b2dd7d22a918a9642fc89840a5d3cee18a0e1fe41080b1141b23b10916 \ - --hash=sha256:7af40425ac535cbda129d9915edcaa002afe35d84609fd3b9d6a8c46732e02ee \ - --hash=sha256:7d8139ca0b9f93890ab899da678816518af74312bb8cd71fb721436a93a93298 \ --hash=sha256:7deeae5071930abb3669b5185abb6c33ddfd2398f87660fafdb9e6a5fb0f3f2f \ --hash=sha256:86a22143a4001f53bf58027b044da1fb10d67b62a785fc1390b5c7f089d9838c \ --hash=sha256:8ca484ca11c65e05639ffe80f20d45e6be81fbec7683d6c9a15cd421e6e8b340 \ - --hash=sha256:8d1d7d63e5d2f4e92a39ae1e897a5d551720179bb8d1254883e7113d3826d43c \ - --hash=sha256:8e702e7489f39375601c7ea5a0bef207256828a2bc5986c65cb15cd0cf097a87 \ - --hash=sha256:a055ba17f4675aadcda3005df2e28a86feb731fdcc865e1f6b4f209ed1225cba \ - --hash=sha256:a33cb3f095e7d776ec76e79d92d83117438b6153510770fcd57b9c96f9ef623d \ - --hash=sha256:a61184c7289146c8cff06b6b41807c6994c6d437278e72cf00ff7fe1c7a263d1 \ --hash=sha256:af55cc207865d641a57f7044e98b08b09220da3d1b13a46f26487cc2f898a072 \ - --hash=sha256:b00cf0471888823b7a9f722c6c41eb6985cf34f077edcf62695ac4bed6ec01ee \ - --hash=sha256:b03850c290c765b87102959ea53299dc9addf76ca08a06ea98383348ae205c99 \ --hash=sha256:b97fd5bb6b7c1a64b7ac0632f7ce389b8ab362e7bd5f60654c2a418496be5d7f \ --hash=sha256:c37bc677690fd33932182b85d37433845de612962ed080c3e4d92f758d1bd894 \ - --hash=sha256:cecb66492440ae8592797dd705a0cbaa6abe0555f4fa6c5f40b078bd2740fc6b \ - --hash=sha256:d0a83afab5e062abffcdcbcc74f9d3ba37b2385294dd0927ad65fc6ebe04e054 \ --hash=sha256:d3cf56cc36d42908495760b223ca9c2c0f9f0002b4eddc994b24db5fcb86a9e4 \ --hash=sha256:e646b19f47d655261b22df9976e572f588185279970efba3d45c377127d35349 \ --hash=sha256:e7908c2025eb18394e32d65dd02d2e37e17d733cdbe7d78231c2b6d7eb20cdb9 \ --hash=sha256:e8f2df79a46e130235bc5e1bbef4de0583fb19d481eaa0bffa76e8347ea45ec6 \ - --hash=sha256:eaeeb2464019765bc4340214fca1143081d49972864773f3f1e95dba5c7edc7d \ --hash=sha256:eb18549b770351b54e1ab5da37d22bc530b8bfe2ee31e22b9ebe650640d2ef12 \ - --hash=sha256:f2e5b6f5cf7c18df66d082604a1d9c7a2d18f7d1dbe9514a2afaccbb51cc4fc3 \ --hash=sha256:f8cafa6f885a0ff5e39efa9325195217bb47d5929ab0051636610d24aef45ade starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ diff --git a/keiko/poetry.lock b/keiko/poetry.lock index ec7ce83a107..41d2ffd2026 100644 --- a/keiko/poetry.lock +++ b/keiko/poetry.lock @@ -255,69 +255,61 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "grpcio" -version = "1.62.0" +version = "1.65.4" description = "HTTP/2-based RPC framework" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "grpcio-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271"}, - {file = "grpcio-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6"}, - {file = "grpcio-1.62.0-cp310-cp310-win32.whl", hash = "sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc"}, - {file = "grpcio-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa"}, - {file = "grpcio-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f"}, - {file = "grpcio-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e"}, - {file = "grpcio-1.62.0-cp311-cp311-win32.whl", hash = "sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd"}, - {file = "grpcio-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334"}, - {file = "grpcio-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8"}, - {file = "grpcio-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388"}, - {file = "grpcio-1.62.0-cp312-cp312-win32.whl", hash = "sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701"}, - {file = "grpcio-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842"}, - {file = "grpcio-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9"}, - {file = "grpcio-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b"}, - {file = "grpcio-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b"}, - {file = "grpcio-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35"}, - {file = "grpcio-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38"}, - {file = "grpcio-1.62.0-cp38-cp38-win32.whl", hash = "sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe"}, - {file = "grpcio-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270"}, - {file = "grpcio-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170"}, - {file = "grpcio-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a"}, - {file = "grpcio-1.62.0-cp39-cp39-win32.whl", hash = "sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93"}, - {file = "grpcio-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5"}, - {file = "grpcio-1.62.0.tar.gz", hash = "sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7"}, + {file = "grpcio-1.65.4-cp310-cp310-linux_armv7l.whl", hash = "sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c"}, + {file = "grpcio-1.65.4-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e"}, + {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de"}, + {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d"}, + {file = "grpcio-1.65.4-cp310-cp310-win32.whl", hash = "sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1"}, + {file = "grpcio-1.65.4-cp310-cp310-win_amd64.whl", hash = "sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec"}, + {file = "grpcio-1.65.4-cp311-cp311-linux_armv7l.whl", hash = "sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef"}, + {file = "grpcio-1.65.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4"}, + {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e"}, + {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5"}, + {file = "grpcio-1.65.4-cp311-cp311-win32.whl", hash = "sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b"}, + {file = "grpcio-1.65.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558"}, + {file = "grpcio-1.65.4-cp312-cp312-linux_armv7l.whl", hash = "sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56"}, + {file = "grpcio-1.65.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63"}, + {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a"}, + {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28"}, + {file = "grpcio-1.65.4-cp312-cp312-win32.whl", hash = "sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0"}, + {file = "grpcio-1.65.4-cp312-cp312-win_amd64.whl", hash = "sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416"}, + {file = "grpcio-1.65.4-cp38-cp38-linux_armv7l.whl", hash = "sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021"}, + {file = "grpcio-1.65.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816"}, + {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524"}, + {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7"}, + {file = "grpcio-1.65.4-cp38-cp38-win32.whl", hash = "sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a"}, + {file = "grpcio-1.65.4-cp38-cp38-win_amd64.whl", hash = "sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f"}, + {file = "grpcio-1.65.4-cp39-cp39-linux_armv7l.whl", hash = "sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733"}, + {file = "grpcio-1.65.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b"}, + {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2"}, + {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257"}, + {file = "grpcio-1.65.4-cp39-cp39-win32.whl", hash = "sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d"}, + {file = "grpcio-1.65.4-cp39-cp39-win_amd64.whl", hash = "sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9"}, + {file = "grpcio-1.65.4.tar.gz", hash = "sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.62.0)"] +protobuf = ["grpcio-tools (>=1.65.4)"] [[package]] name = "h11" diff --git a/keiko/requirements-dev.txt b/keiko/requirements-dev.txt index 6554f943a3a..fe6eaf46f5b 100644 --- a/keiko/requirements-dev.txt +++ b/keiko/requirements-dev.txt @@ -119,61 +119,53 @@ fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ googleapis-common-protos==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07 \ --hash=sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277 -grpcio==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701 \ - --hash=sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e \ - --hash=sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532 \ - --hash=sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a \ - --hash=sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271 \ - --hash=sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f \ - --hash=sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7 \ - --hash=sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b \ - --hash=sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4 \ - --hash=sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839 \ - --hash=sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6 \ - --hash=sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb \ - --hash=sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e \ - --hash=sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93 \ - --hash=sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f \ - --hash=sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6 \ - --hash=sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1 \ - --hash=sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35 \ - --hash=sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842 \ - --hash=sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6 \ - --hash=sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c \ - --hash=sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873 \ - --hash=sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7 \ - --hash=sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c \ - --hash=sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928 \ - --hash=sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9 \ - --hash=sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c \ - --hash=sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021 \ - --hash=sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa \ - --hash=sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38 \ - --hash=sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc \ - --hash=sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe \ - --hash=sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8 \ - --hash=sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402 \ - --hash=sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388 \ - --hash=sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0 \ - --hash=sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b \ - --hash=sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b \ - --hash=sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2 \ - --hash=sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b \ - --hash=sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5 \ - --hash=sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829 \ - --hash=sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2 \ - --hash=sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6 \ - --hash=sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd \ - --hash=sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0 \ - --hash=sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8 \ - --hash=sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334 \ - --hash=sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee \ - --hash=sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c \ - --hash=sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72 \ - --hash=sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4 \ - --hash=sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270 \ - --hash=sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170 +grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ + --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ + --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ + --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ + --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ + --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ + --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ + --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ + --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ + --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ + --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ + --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ + --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ + --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ + --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ + --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ + --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ + --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ + --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ + --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ + --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ + --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ + --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ + --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ + --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ + --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ + --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ + --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ + --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ + --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ + --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ + --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ + --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ + --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ + --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ + --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ + --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ + --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ + --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ + --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ + --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ + --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ + --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ + --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ + --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ + --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 diff --git a/keiko/requirements.txt b/keiko/requirements.txt index 4b81b80619b..e597f6fd8bc 100644 --- a/keiko/requirements.txt +++ b/keiko/requirements.txt @@ -25,61 +25,53 @@ fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ googleapis-common-protos==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07 \ --hash=sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277 -grpcio==1.62.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701 \ - --hash=sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e \ - --hash=sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532 \ - --hash=sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a \ - --hash=sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271 \ - --hash=sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f \ - --hash=sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7 \ - --hash=sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b \ - --hash=sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4 \ - --hash=sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839 \ - --hash=sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6 \ - --hash=sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb \ - --hash=sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e \ - --hash=sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93 \ - --hash=sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f \ - --hash=sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6 \ - --hash=sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1 \ - --hash=sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35 \ - --hash=sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842 \ - --hash=sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6 \ - --hash=sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c \ - --hash=sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873 \ - --hash=sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7 \ - --hash=sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c \ - --hash=sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928 \ - --hash=sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9 \ - --hash=sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c \ - --hash=sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021 \ - --hash=sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa \ - --hash=sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38 \ - --hash=sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc \ - --hash=sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe \ - --hash=sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8 \ - --hash=sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402 \ - --hash=sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388 \ - --hash=sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0 \ - --hash=sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b \ - --hash=sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b \ - --hash=sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2 \ - --hash=sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b \ - --hash=sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5 \ - --hash=sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829 \ - --hash=sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2 \ - --hash=sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6 \ - --hash=sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd \ - --hash=sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0 \ - --hash=sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8 \ - --hash=sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334 \ - --hash=sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee \ - --hash=sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c \ - --hash=sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72 \ - --hash=sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4 \ - --hash=sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270 \ - --hash=sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170 +grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ + --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ + --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ + --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ + --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ + --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ + --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ + --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ + --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ + --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ + --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ + --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ + --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ + --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ + --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ + --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ + --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ + --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ + --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ + --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ + --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ + --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ + --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ + --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ + --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ + --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ + --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ + --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ + --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ + --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ + --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ + --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ + --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ + --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ + --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ + --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ + --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ + --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ + --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ + --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ + --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ + --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ + --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ + --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ + --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ + --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 diff --git a/octopoes/poetry.lock b/octopoes/poetry.lock index 1a299329105..2fa635345fc 100644 --- a/octopoes/poetry.lock +++ b/octopoes/poetry.lock @@ -599,69 +599,61 @@ test = ["objgraph", "psutil"] [[package]] name = "grpcio" -version = "1.62.2" +version = "1.65.4" description = "HTTP/2-based RPC framework" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "grpcio-1.62.2-cp310-cp310-linux_armv7l.whl", hash = "sha256:66344ea741124c38588a664237ac2fa16dfd226964cca23ddc96bd4accccbde5"}, - {file = "grpcio-1.62.2-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:5dab7ac2c1e7cb6179c6bfad6b63174851102cbe0682294e6b1d6f0981ad7138"}, - {file = "grpcio-1.62.2-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:3ad00f3f0718894749d5a8bb0fa125a7980a2f49523731a9b1fabf2b3522aa43"}, - {file = "grpcio-1.62.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e72ddfee62430ea80133d2cbe788e0d06b12f865765cb24a40009668bd8ea05"}, - {file = "grpcio-1.62.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53d3a59a10af4c2558a8e563aed9f256259d2992ae0d3037817b2155f0341de1"}, - {file = "grpcio-1.62.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1511a303f8074f67af4119275b4f954189e8313541da7b88b1b3a71425cdb10"}, - {file = "grpcio-1.62.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b94d41b7412ef149743fbc3178e59d95228a7064c5ab4760ae82b562bdffb199"}, - {file = "grpcio-1.62.2-cp310-cp310-win32.whl", hash = "sha256:a75af2fc7cb1fe25785be7bed1ab18cef959a376cdae7c6870184307614caa3f"}, - {file = "grpcio-1.62.2-cp310-cp310-win_amd64.whl", hash = "sha256:80407bc007754f108dc2061e37480238b0dc1952c855e86a4fc283501ee6bb5d"}, - {file = "grpcio-1.62.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:c1624aa686d4b36790ed1c2e2306cc3498778dffaf7b8dd47066cf819028c3ad"}, - {file = "grpcio-1.62.2-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:1c1bb80299bdef33309dff03932264636450c8fdb142ea39f47e06a7153d3063"}, - {file = "grpcio-1.62.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:db068bbc9b1fa16479a82e1ecf172a93874540cb84be69f0b9cb9b7ac3c82670"}, - {file = "grpcio-1.62.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2cc8a308780edbe2c4913d6a49dbdb5befacdf72d489a368566be44cadaef1a"}, - {file = "grpcio-1.62.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0695ae31a89f1a8fc8256050329a91a9995b549a88619263a594ca31b76d756"}, - {file = "grpcio-1.62.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88b4f9ee77191dcdd8810241e89340a12cbe050be3e0d5f2f091c15571cd3930"}, - {file = "grpcio-1.62.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2a0204532aa2f1afd467024b02b4069246320405bc18abec7babab03e2644e75"}, - {file = "grpcio-1.62.2-cp311-cp311-win32.whl", hash = "sha256:6e784f60e575a0de554ef9251cbc2ceb8790914fe324f11e28450047f264ee6f"}, - {file = "grpcio-1.62.2-cp311-cp311-win_amd64.whl", hash = "sha256:112eaa7865dd9e6d7c0556c8b04ae3c3a2dc35d62ad3373ab7f6a562d8199200"}, - {file = "grpcio-1.62.2-cp312-cp312-linux_armv7l.whl", hash = "sha256:65034473fc09628a02fb85f26e73885cf1ed39ebd9cf270247b38689ff5942c5"}, - {file = "grpcio-1.62.2-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:d2c1771d0ee3cf72d69bb5e82c6a82f27fbd504c8c782575eddb7839729fbaad"}, - {file = "grpcio-1.62.2-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:3abe6838196da518863b5d549938ce3159d809218936851b395b09cad9b5d64a"}, - {file = "grpcio-1.62.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5ffeb269f10cedb4f33142b89a061acda9f672fd1357331dbfd043422c94e9e"}, - {file = "grpcio-1.62.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404d3b4b6b142b99ba1cff0b2177d26b623101ea2ce51c25ef6e53d9d0d87bcc"}, - {file = "grpcio-1.62.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:262cda97efdabb20853d3b5a4c546a535347c14b64c017f628ca0cc7fa780cc6"}, - {file = "grpcio-1.62.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17708db5b11b966373e21519c4c73e5a750555f02fde82276ea2a267077c68ad"}, - {file = "grpcio-1.62.2-cp312-cp312-win32.whl", hash = "sha256:b7ec9e2f8ffc8436f6b642a10019fc513722858f295f7efc28de135d336ac189"}, - {file = "grpcio-1.62.2-cp312-cp312-win_amd64.whl", hash = "sha256:aa787b83a3cd5e482e5c79be030e2b4a122ecc6c5c6c4c42a023a2b581fdf17b"}, - {file = "grpcio-1.62.2-cp37-cp37m-linux_armv7l.whl", hash = "sha256:cfd23ad29bfa13fd4188433b0e250f84ec2c8ba66b14a9877e8bce05b524cf54"}, - {file = "grpcio-1.62.2-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:af15e9efa4d776dfcecd1d083f3ccfb04f876d613e90ef8432432efbeeac689d"}, - {file = "grpcio-1.62.2-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:f4aa94361bb5141a45ca9187464ae81a92a2a135ce2800b2203134f7a1a1d479"}, - {file = "grpcio-1.62.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82af3613a219512a28ee5c95578eb38d44dd03bca02fd918aa05603c41018051"}, - {file = "grpcio-1.62.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55ddaf53474e8caeb29eb03e3202f9d827ad3110475a21245f3c7712022882a9"}, - {file = "grpcio-1.62.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c79b518c56dddeec79e5500a53d8a4db90da995dfe1738c3ac57fe46348be049"}, - {file = "grpcio-1.62.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a5eb4844e5e60bf2c446ef38c5b40d7752c6effdee882f716eb57ae87255d20a"}, - {file = "grpcio-1.62.2-cp37-cp37m-win_amd64.whl", hash = "sha256:aaae70364a2d1fb238afd6cc9fcb10442b66e397fd559d3f0968d28cc3ac929c"}, - {file = "grpcio-1.62.2-cp38-cp38-linux_armv7l.whl", hash = "sha256:1bcfe5070e4406f489e39325b76caeadab28c32bf9252d3ae960c79935a4cc36"}, - {file = "grpcio-1.62.2-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:da6a7b6b938c15fa0f0568e482efaae9c3af31963eec2da4ff13a6d8ec2888e4"}, - {file = "grpcio-1.62.2-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:41955b641c34db7d84db8d306937b72bc4968eef1c401bea73081a8d6c3d8033"}, - {file = "grpcio-1.62.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c772f225483905f675cb36a025969eef9712f4698364ecd3a63093760deea1bc"}, - {file = "grpcio-1.62.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07ce1f775d37ca18c7a141300e5b71539690efa1f51fe17f812ca85b5e73262f"}, - {file = "grpcio-1.62.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:26f415f40f4a93579fd648f48dca1c13dfacdfd0290f4a30f9b9aeb745026811"}, - {file = "grpcio-1.62.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:db707e3685ff16fc1eccad68527d072ac8bdd2e390f6daa97bc394ea7de4acea"}, - {file = "grpcio-1.62.2-cp38-cp38-win32.whl", hash = "sha256:589ea8e75de5fd6df387de53af6c9189c5231e212b9aa306b6b0d4f07520fbb9"}, - {file = "grpcio-1.62.2-cp38-cp38-win_amd64.whl", hash = "sha256:3c3ed41f4d7a3aabf0f01ecc70d6b5d00ce1800d4af652a549de3f7cf35c4abd"}, - {file = "grpcio-1.62.2-cp39-cp39-linux_armv7l.whl", hash = "sha256:162ccf61499c893831b8437120600290a99c0bc1ce7b51f2c8d21ec87ff6af8b"}, - {file = "grpcio-1.62.2-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:f27246d7da7d7e3bd8612f63785a7b0c39a244cf14b8dd9dd2f2fab939f2d7f1"}, - {file = "grpcio-1.62.2-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:2507006c8a478f19e99b6fe36a2464696b89d40d88f34e4b709abe57e1337467"}, - {file = "grpcio-1.62.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a90ac47a8ce934e2c8d71e317d2f9e7e6aaceb2d199de940ce2c2eb611b8c0f4"}, - {file = "grpcio-1.62.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99701979bcaaa7de8d5f60476487c5df8f27483624f1f7e300ff4669ee44d1f2"}, - {file = "grpcio-1.62.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:af7dc3f7a44f10863b1b0ecab4078f0a00f561aae1edbd01fd03ad4dcf61c9e9"}, - {file = "grpcio-1.62.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fa63245271920786f4cb44dcada4983a3516be8f470924528cf658731864c14b"}, - {file = "grpcio-1.62.2-cp39-cp39-win32.whl", hash = "sha256:c6ad9c39704256ed91a1cffc1379d63f7d0278d6a0bad06b0330f5d30291e3a3"}, - {file = "grpcio-1.62.2-cp39-cp39-win_amd64.whl", hash = "sha256:16da954692fd61aa4941fbeda405a756cd96b97b5d95ca58a92547bba2c1624f"}, - {file = "grpcio-1.62.2.tar.gz", hash = "sha256:c77618071d96b7a8be2c10701a98537823b9c65ba256c0b9067e0594cdbd954d"}, + {file = "grpcio-1.65.4-cp310-cp310-linux_armv7l.whl", hash = "sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c"}, + {file = "grpcio-1.65.4-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82"}, + {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e"}, + {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de"}, + {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d"}, + {file = "grpcio-1.65.4-cp310-cp310-win32.whl", hash = "sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1"}, + {file = "grpcio-1.65.4-cp310-cp310-win_amd64.whl", hash = "sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec"}, + {file = "grpcio-1.65.4-cp311-cp311-linux_armv7l.whl", hash = "sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef"}, + {file = "grpcio-1.65.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17"}, + {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4"}, + {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e"}, + {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5"}, + {file = "grpcio-1.65.4-cp311-cp311-win32.whl", hash = "sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b"}, + {file = "grpcio-1.65.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558"}, + {file = "grpcio-1.65.4-cp312-cp312-linux_armv7l.whl", hash = "sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56"}, + {file = "grpcio-1.65.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74"}, + {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63"}, + {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a"}, + {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28"}, + {file = "grpcio-1.65.4-cp312-cp312-win32.whl", hash = "sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0"}, + {file = "grpcio-1.65.4-cp312-cp312-win_amd64.whl", hash = "sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416"}, + {file = "grpcio-1.65.4-cp38-cp38-linux_armv7l.whl", hash = "sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021"}, + {file = "grpcio-1.65.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864"}, + {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816"}, + {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524"}, + {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7"}, + {file = "grpcio-1.65.4-cp38-cp38-win32.whl", hash = "sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a"}, + {file = "grpcio-1.65.4-cp38-cp38-win_amd64.whl", hash = "sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f"}, + {file = "grpcio-1.65.4-cp39-cp39-linux_armv7l.whl", hash = "sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733"}, + {file = "grpcio-1.65.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1"}, + {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b"}, + {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2"}, + {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257"}, + {file = "grpcio-1.65.4-cp39-cp39-win32.whl", hash = "sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d"}, + {file = "grpcio-1.65.4-cp39-cp39-win_amd64.whl", hash = "sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9"}, + {file = "grpcio-1.65.4.tar.gz", hash = "sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.62.2)"] +protobuf = ["grpcio-tools (>=1.65.4)"] [[package]] name = "h11" @@ -1551,7 +1543,6 @@ optional = false python-versions = "*" files = [ {file = "requests-file-2.0.0.tar.gz", hash = "sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972"}, - {file = "requests_file-2.0.0-py2.py3-none-any.whl", hash = "sha256:3e493d390adb44aa102ebea827a48717336d5268968c370eaf19abaf5cae13bf"}, ] [package.dependencies] @@ -1992,13 +1983,13 @@ files = [ [[package]] name = "webob" -version = "1.8.7" +version = "1.8.8" description = "WSGI request and response object" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "WebOb-1.8.7-py2.py3-none-any.whl", hash = "sha256:73aae30359291c14fa3b956f8b5ca31960e420c28c1bec002547fb04928cf89b"}, - {file = "WebOb-1.8.7.tar.gz", hash = "sha256:b64ef5141be559cfade448f044fa45c2260351edcb6a8ef6b7e00c7dcef0c323"}, + {file = "WebOb-1.8.8-py2.py3-none-any.whl", hash = "sha256:b60ba63f05c0cf61e086a10c3781a41fcfe30027753a8ae6d819c77592ce83ea"}, + {file = "webob-1.8.8.tar.gz", hash = "sha256:2abc1555e118fc251e705fc6dc66c7f5353bb9fbfab6d20e22f1c02b4b71bcee"}, ] [package.extras] diff --git a/octopoes/requirements-dev.txt b/octopoes/requirements-dev.txt index a642059ecd8..3ff6d499064 100644 --- a/octopoes/requirements-dev.txt +++ b/octopoes/requirements-dev.txt @@ -261,61 +261,53 @@ greenlet==3.0.3 ; python_version >= "3.10" and (platform_machine == "aarch64" or --hash=sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf \ --hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \ --hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33 -grpcio==1.62.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:07ce1f775d37ca18c7a141300e5b71539690efa1f51fe17f812ca85b5e73262f \ - --hash=sha256:112eaa7865dd9e6d7c0556c8b04ae3c3a2dc35d62ad3373ab7f6a562d8199200 \ - --hash=sha256:162ccf61499c893831b8437120600290a99c0bc1ce7b51f2c8d21ec87ff6af8b \ - --hash=sha256:16da954692fd61aa4941fbeda405a756cd96b97b5d95ca58a92547bba2c1624f \ - --hash=sha256:17708db5b11b966373e21519c4c73e5a750555f02fde82276ea2a267077c68ad \ - --hash=sha256:1bcfe5070e4406f489e39325b76caeadab28c32bf9252d3ae960c79935a4cc36 \ - --hash=sha256:1c1bb80299bdef33309dff03932264636450c8fdb142ea39f47e06a7153d3063 \ - --hash=sha256:2507006c8a478f19e99b6fe36a2464696b89d40d88f34e4b709abe57e1337467 \ - --hash=sha256:262cda97efdabb20853d3b5a4c546a535347c14b64c017f628ca0cc7fa780cc6 \ - --hash=sha256:26f415f40f4a93579fd648f48dca1c13dfacdfd0290f4a30f9b9aeb745026811 \ - --hash=sha256:2a0204532aa2f1afd467024b02b4069246320405bc18abec7babab03e2644e75 \ - --hash=sha256:2e72ddfee62430ea80133d2cbe788e0d06b12f865765cb24a40009668bd8ea05 \ - --hash=sha256:3abe6838196da518863b5d549938ce3159d809218936851b395b09cad9b5d64a \ - --hash=sha256:3ad00f3f0718894749d5a8bb0fa125a7980a2f49523731a9b1fabf2b3522aa43 \ - --hash=sha256:3c3ed41f4d7a3aabf0f01ecc70d6b5d00ce1800d4af652a549de3f7cf35c4abd \ - --hash=sha256:404d3b4b6b142b99ba1cff0b2177d26b623101ea2ce51c25ef6e53d9d0d87bcc \ - --hash=sha256:41955b641c34db7d84db8d306937b72bc4968eef1c401bea73081a8d6c3d8033 \ - --hash=sha256:53d3a59a10af4c2558a8e563aed9f256259d2992ae0d3037817b2155f0341de1 \ - --hash=sha256:55ddaf53474e8caeb29eb03e3202f9d827ad3110475a21245f3c7712022882a9 \ - --hash=sha256:589ea8e75de5fd6df387de53af6c9189c5231e212b9aa306b6b0d4f07520fbb9 \ - --hash=sha256:5dab7ac2c1e7cb6179c6bfad6b63174851102cbe0682294e6b1d6f0981ad7138 \ - --hash=sha256:65034473fc09628a02fb85f26e73885cf1ed39ebd9cf270247b38689ff5942c5 \ - --hash=sha256:66344ea741124c38588a664237ac2fa16dfd226964cca23ddc96bd4accccbde5 \ - --hash=sha256:6e784f60e575a0de554ef9251cbc2ceb8790914fe324f11e28450047f264ee6f \ - --hash=sha256:80407bc007754f108dc2061e37480238b0dc1952c855e86a4fc283501ee6bb5d \ - --hash=sha256:82af3613a219512a28ee5c95578eb38d44dd03bca02fd918aa05603c41018051 \ - --hash=sha256:88b4f9ee77191dcdd8810241e89340a12cbe050be3e0d5f2f091c15571cd3930 \ - --hash=sha256:99701979bcaaa7de8d5f60476487c5df8f27483624f1f7e300ff4669ee44d1f2 \ - --hash=sha256:a1511a303f8074f67af4119275b4f954189e8313541da7b88b1b3a71425cdb10 \ - --hash=sha256:a5eb4844e5e60bf2c446ef38c5b40d7752c6effdee882f716eb57ae87255d20a \ - --hash=sha256:a75af2fc7cb1fe25785be7bed1ab18cef959a376cdae7c6870184307614caa3f \ - --hash=sha256:a90ac47a8ce934e2c8d71e317d2f9e7e6aaceb2d199de940ce2c2eb611b8c0f4 \ - --hash=sha256:aa787b83a3cd5e482e5c79be030e2b4a122ecc6c5c6c4c42a023a2b581fdf17b \ - --hash=sha256:aaae70364a2d1fb238afd6cc9fcb10442b66e397fd559d3f0968d28cc3ac929c \ - --hash=sha256:af15e9efa4d776dfcecd1d083f3ccfb04f876d613e90ef8432432efbeeac689d \ - --hash=sha256:af7dc3f7a44f10863b1b0ecab4078f0a00f561aae1edbd01fd03ad4dcf61c9e9 \ - --hash=sha256:b7ec9e2f8ffc8436f6b642a10019fc513722858f295f7efc28de135d336ac189 \ - --hash=sha256:b94d41b7412ef149743fbc3178e59d95228a7064c5ab4760ae82b562bdffb199 \ - --hash=sha256:c1624aa686d4b36790ed1c2e2306cc3498778dffaf7b8dd47066cf819028c3ad \ - --hash=sha256:c5ffeb269f10cedb4f33142b89a061acda9f672fd1357331dbfd043422c94e9e \ - --hash=sha256:c6ad9c39704256ed91a1cffc1379d63f7d0278d6a0bad06b0330f5d30291e3a3 \ - --hash=sha256:c772f225483905f675cb36a025969eef9712f4698364ecd3a63093760deea1bc \ - --hash=sha256:c77618071d96b7a8be2c10701a98537823b9c65ba256c0b9067e0594cdbd954d \ - --hash=sha256:c79b518c56dddeec79e5500a53d8a4db90da995dfe1738c3ac57fe46348be049 \ - --hash=sha256:cfd23ad29bfa13fd4188433b0e250f84ec2c8ba66b14a9877e8bce05b524cf54 \ - --hash=sha256:d0695ae31a89f1a8fc8256050329a91a9995b549a88619263a594ca31b76d756 \ - --hash=sha256:d2c1771d0ee3cf72d69bb5e82c6a82f27fbd504c8c782575eddb7839729fbaad \ - --hash=sha256:da6a7b6b938c15fa0f0568e482efaae9c3af31963eec2da4ff13a6d8ec2888e4 \ - --hash=sha256:db068bbc9b1fa16479a82e1ecf172a93874540cb84be69f0b9cb9b7ac3c82670 \ - --hash=sha256:db707e3685ff16fc1eccad68527d072ac8bdd2e390f6daa97bc394ea7de4acea \ - --hash=sha256:e2cc8a308780edbe2c4913d6a49dbdb5befacdf72d489a368566be44cadaef1a \ - --hash=sha256:f27246d7da7d7e3bd8612f63785a7b0c39a244cf14b8dd9dd2f2fab939f2d7f1 \ - --hash=sha256:f4aa94361bb5141a45ca9187464ae81a92a2a135ce2800b2203134f7a1a1d479 \ - --hash=sha256:fa63245271920786f4cb44dcada4983a3516be8f470924528cf658731864c14b +grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ + --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ + --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ + --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ + --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ + --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ + --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ + --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ + --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ + --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ + --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ + --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ + --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ + --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ + --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ + --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ + --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ + --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ + --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ + --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ + --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ + --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ + --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ + --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ + --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ + --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ + --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ + --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ + --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ + --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ + --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ + --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ + --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ + --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ + --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ + --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ + --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ + --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ + --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ + --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ + --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ + --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ + --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ + --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ + --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ + --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -592,8 +584,7 @@ referencing==0.35.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:191e936b0c696d0af17ad7430a3dc68e88bc11be6514f4757dc890f04ab05889 \ --hash=sha256:8080727b30e364e5783152903672df9b6b091c926a146a759080b62ca3126cd6 requests-file==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 \ - --hash=sha256:3e493d390adb44aa102ebea827a48717336d5268968c370eaf19abaf5cae13bf + --hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 @@ -792,9 +783,9 @@ waitress==3.0.0 ; python_version >= "3.10" and python_version < "4" \ wcwidth==0.2.13 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \ --hash=sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5 -webob==1.8.7 ; python_version >= "3.10" and python_version < "4" \ - --hash=sha256:73aae30359291c14fa3b956f8b5ca31960e420c28c1bec002547fb04928cf89b \ - --hash=sha256:b64ef5141be559cfade448f044fa45c2260351edcb6a8ef6b7e00c7dcef0c323 +webob==1.8.8 ; python_version >= "3.10" and python_version < "4" \ + --hash=sha256:2abc1555e118fc251e705fc6dc66c7f5353bb9fbfab6d20e22f1c02b4b71bcee \ + --hash=sha256:b60ba63f05c0cf61e086a10c3781a41fcfe30027753a8ae6d819c77592ce83ea webtest==3.0.0 ; python_version >= "3.10" and python_version < "4" \ --hash=sha256:2a001a9efa40d2a7e5d9cd8d1527c75f41814eb6afce2c3d207402547b1e5ead \ --hash=sha256:54bd969725838d9861a9fa27f8d971f79d275d94ae255f5c501f53bb6d9929eb diff --git a/octopoes/requirements.txt b/octopoes/requirements.txt index 7d0512900fe..189ab9f5d88 100644 --- a/octopoes/requirements.txt +++ b/octopoes/requirements.txt @@ -205,61 +205,53 @@ greenlet==3.0.3 ; python_version >= "3.10" and (platform_machine == "aarch64" or --hash=sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf \ --hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \ --hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33 -grpcio==1.62.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:07ce1f775d37ca18c7a141300e5b71539690efa1f51fe17f812ca85b5e73262f \ - --hash=sha256:112eaa7865dd9e6d7c0556c8b04ae3c3a2dc35d62ad3373ab7f6a562d8199200 \ - --hash=sha256:162ccf61499c893831b8437120600290a99c0bc1ce7b51f2c8d21ec87ff6af8b \ - --hash=sha256:16da954692fd61aa4941fbeda405a756cd96b97b5d95ca58a92547bba2c1624f \ - --hash=sha256:17708db5b11b966373e21519c4c73e5a750555f02fde82276ea2a267077c68ad \ - --hash=sha256:1bcfe5070e4406f489e39325b76caeadab28c32bf9252d3ae960c79935a4cc36 \ - --hash=sha256:1c1bb80299bdef33309dff03932264636450c8fdb142ea39f47e06a7153d3063 \ - --hash=sha256:2507006c8a478f19e99b6fe36a2464696b89d40d88f34e4b709abe57e1337467 \ - --hash=sha256:262cda97efdabb20853d3b5a4c546a535347c14b64c017f628ca0cc7fa780cc6 \ - --hash=sha256:26f415f40f4a93579fd648f48dca1c13dfacdfd0290f4a30f9b9aeb745026811 \ - --hash=sha256:2a0204532aa2f1afd467024b02b4069246320405bc18abec7babab03e2644e75 \ - --hash=sha256:2e72ddfee62430ea80133d2cbe788e0d06b12f865765cb24a40009668bd8ea05 \ - --hash=sha256:3abe6838196da518863b5d549938ce3159d809218936851b395b09cad9b5d64a \ - --hash=sha256:3ad00f3f0718894749d5a8bb0fa125a7980a2f49523731a9b1fabf2b3522aa43 \ - --hash=sha256:3c3ed41f4d7a3aabf0f01ecc70d6b5d00ce1800d4af652a549de3f7cf35c4abd \ - --hash=sha256:404d3b4b6b142b99ba1cff0b2177d26b623101ea2ce51c25ef6e53d9d0d87bcc \ - --hash=sha256:41955b641c34db7d84db8d306937b72bc4968eef1c401bea73081a8d6c3d8033 \ - --hash=sha256:53d3a59a10af4c2558a8e563aed9f256259d2992ae0d3037817b2155f0341de1 \ - --hash=sha256:55ddaf53474e8caeb29eb03e3202f9d827ad3110475a21245f3c7712022882a9 \ - --hash=sha256:589ea8e75de5fd6df387de53af6c9189c5231e212b9aa306b6b0d4f07520fbb9 \ - --hash=sha256:5dab7ac2c1e7cb6179c6bfad6b63174851102cbe0682294e6b1d6f0981ad7138 \ - --hash=sha256:65034473fc09628a02fb85f26e73885cf1ed39ebd9cf270247b38689ff5942c5 \ - --hash=sha256:66344ea741124c38588a664237ac2fa16dfd226964cca23ddc96bd4accccbde5 \ - --hash=sha256:6e784f60e575a0de554ef9251cbc2ceb8790914fe324f11e28450047f264ee6f \ - --hash=sha256:80407bc007754f108dc2061e37480238b0dc1952c855e86a4fc283501ee6bb5d \ - --hash=sha256:82af3613a219512a28ee5c95578eb38d44dd03bca02fd918aa05603c41018051 \ - --hash=sha256:88b4f9ee77191dcdd8810241e89340a12cbe050be3e0d5f2f091c15571cd3930 \ - --hash=sha256:99701979bcaaa7de8d5f60476487c5df8f27483624f1f7e300ff4669ee44d1f2 \ - --hash=sha256:a1511a303f8074f67af4119275b4f954189e8313541da7b88b1b3a71425cdb10 \ - --hash=sha256:a5eb4844e5e60bf2c446ef38c5b40d7752c6effdee882f716eb57ae87255d20a \ - --hash=sha256:a75af2fc7cb1fe25785be7bed1ab18cef959a376cdae7c6870184307614caa3f \ - --hash=sha256:a90ac47a8ce934e2c8d71e317d2f9e7e6aaceb2d199de940ce2c2eb611b8c0f4 \ - --hash=sha256:aa787b83a3cd5e482e5c79be030e2b4a122ecc6c5c6c4c42a023a2b581fdf17b \ - --hash=sha256:aaae70364a2d1fb238afd6cc9fcb10442b66e397fd559d3f0968d28cc3ac929c \ - --hash=sha256:af15e9efa4d776dfcecd1d083f3ccfb04f876d613e90ef8432432efbeeac689d \ - --hash=sha256:af7dc3f7a44f10863b1b0ecab4078f0a00f561aae1edbd01fd03ad4dcf61c9e9 \ - --hash=sha256:b7ec9e2f8ffc8436f6b642a10019fc513722858f295f7efc28de135d336ac189 \ - --hash=sha256:b94d41b7412ef149743fbc3178e59d95228a7064c5ab4760ae82b562bdffb199 \ - --hash=sha256:c1624aa686d4b36790ed1c2e2306cc3498778dffaf7b8dd47066cf819028c3ad \ - --hash=sha256:c5ffeb269f10cedb4f33142b89a061acda9f672fd1357331dbfd043422c94e9e \ - --hash=sha256:c6ad9c39704256ed91a1cffc1379d63f7d0278d6a0bad06b0330f5d30291e3a3 \ - --hash=sha256:c772f225483905f675cb36a025969eef9712f4698364ecd3a63093760deea1bc \ - --hash=sha256:c77618071d96b7a8be2c10701a98537823b9c65ba256c0b9067e0594cdbd954d \ - --hash=sha256:c79b518c56dddeec79e5500a53d8a4db90da995dfe1738c3ac57fe46348be049 \ - --hash=sha256:cfd23ad29bfa13fd4188433b0e250f84ec2c8ba66b14a9877e8bce05b524cf54 \ - --hash=sha256:d0695ae31a89f1a8fc8256050329a91a9995b549a88619263a594ca31b76d756 \ - --hash=sha256:d2c1771d0ee3cf72d69bb5e82c6a82f27fbd504c8c782575eddb7839729fbaad \ - --hash=sha256:da6a7b6b938c15fa0f0568e482efaae9c3af31963eec2da4ff13a6d8ec2888e4 \ - --hash=sha256:db068bbc9b1fa16479a82e1ecf172a93874540cb84be69f0b9cb9b7ac3c82670 \ - --hash=sha256:db707e3685ff16fc1eccad68527d072ac8bdd2e390f6daa97bc394ea7de4acea \ - --hash=sha256:e2cc8a308780edbe2c4913d6a49dbdb5befacdf72d489a368566be44cadaef1a \ - --hash=sha256:f27246d7da7d7e3bd8612f63785a7b0c39a244cf14b8dd9dd2f2fab939f2d7f1 \ - --hash=sha256:f4aa94361bb5141a45ca9187464ae81a92a2a135ce2800b2203134f7a1a1d479 \ - --hash=sha256:fa63245271920786f4cb44dcada4983a3516be8f470924528cf658731864c14b +grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ + --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ + --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ + --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ + --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ + --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ + --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ + --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ + --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ + --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ + --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ + --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ + --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ + --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ + --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ + --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ + --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ + --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ + --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ + --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ + --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ + --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ + --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ + --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ + --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ + --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ + --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ + --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ + --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ + --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ + --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ + --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ + --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ + --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ + --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ + --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ + --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ + --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ + --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ + --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ + --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ + --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ + --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ + --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ + --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ + --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -506,8 +498,7 @@ referencing==0.35.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:191e936b0c696d0af17ad7430a3dc68e88bc11be6514f4757dc890f04ab05889 \ --hash=sha256:8080727b30e364e5783152903672df9b6b091c926a146a759080b62ca3126cd6 requests-file==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 \ - --hash=sha256:3e493d390adb44aa102ebea827a48717336d5268968c370eaf19abaf5cae13bf + --hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 From 9e880a80a21449b1354799c073096818de765e78 Mon Sep 17 00:00:00 2001 From: Jeroen Dekkers Date: Fri, 16 Aug 2024 10:41:57 +0200 Subject: [PATCH 066/112] Small flexible scheduling fixups (#3354) Co-authored-by: JP Bruins Slot Co-authored-by: Jan Klopper --- .pre-commit-config.yaml | 1 + mula/.ci/docker-compose.yml | 2 +- mula/poetry.lock | 13 +------------ mula/pyproject.toml | 2 -- mula/requirements-dev.txt | 3 --- mula/requirements.txt | 3 --- .../alembic/versions/0008_add_task_schedule.py | 4 +--- 7 files changed, 4 insertions(+), 24 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0219f936ad8..99f38a8cfc6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -91,6 +91,7 @@ repos: - httpx - types-python-dateutil - types-requests + - types-croniter exclude: | (?x)( ^boefjes/tools | diff --git a/mula/.ci/docker-compose.yml b/mula/.ci/docker-compose.yml index 162f07c27e4..061883211fb 100644 --- a/mula/.ci/docker-compose.yml +++ b/mula/.ci/docker-compose.yml @@ -28,7 +28,7 @@ services: - ci_rabbitmq ci_postgres: - image: postgres:15 + image: docker.io/library/postgres:15 command: ["postgres", "-c", "log_statement=all", "-c", "log_destination=stderr"] healthcheck: diff --git a/mula/poetry.lock b/mula/poetry.lock index f6c64ee22f8..1746a6b2ec4 100644 --- a/mula/poetry.lock +++ b/mula/poetry.lock @@ -1474,17 +1474,6 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -[[package]] -name = "types-croniter" -version = "3.0.3.20240731" -description = "Typing stubs for croniter" -optional = false -python-versions = ">=3.8" -files = [ - {file = "types-croniter-3.0.3.20240731.tar.gz", hash = "sha256:7a170660642da662c704a463b011e31c049f5a218d27d30199a80ac5e8d15002"}, - {file = "types_croniter-3.0.3.20240731-py3-none-any.whl", hash = "sha256:da039d543e07b1db4ad93680cb837afd0f5c64974970287da8c6432d19441b71"}, -] - [[package]] name = "typing-extensions" version = "4.12.2" @@ -1612,4 +1601,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "044202695a2ec6a10e479b05d6a2ba72b3ea78231fc2496b0e27918cfb253926" +content-hash = "04369c4a49bc4040c2a09e2e0fc4e1fad8dc7e1f1c8cf6268895647e3f242550" diff --git a/mula/pyproject.toml b/mula/pyproject.toml index 12258110ad2..f2f8e983c75 100644 --- a/mula/pyproject.toml +++ b/mula/pyproject.toml @@ -19,8 +19,6 @@ python-dotenv = "^1.0.0" retry2 = "^0.9.5" sqlalchemy = "^2.0.23" structlog = "^23.2.0" -types-croniter = "^3.0.3.20240731" -typing-extensions = "^4.8.0" uvicorn = "^0.29.0" httpx = "^0.27.0" diff --git a/mula/requirements-dev.txt b/mula/requirements-dev.txt index a8404516c76..eda3abc1dc0 100644 --- a/mula/requirements-dev.txt +++ b/mula/requirements-dev.txt @@ -660,9 +660,6 @@ structlog==23.3.0 ; python_version >= "3.10" and python_version < "4.0" \ tomli==2.0.1 ; python_version >= "3.10" and python_full_version <= "3.11.0a6" \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f -types-croniter==3.0.3.20240731 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7a170660642da662c704a463b011e31c049f5a218d27d30199a80ac5e8d15002 \ - --hash=sha256:da039d543e07b1db4ad93680cb837afd0f5c64974970287da8c6432d19441b71 typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 diff --git a/mula/requirements.txt b/mula/requirements.txt index 79b67b42d03..79db726f657 100644 --- a/mula/requirements.txt +++ b/mula/requirements.txt @@ -546,9 +546,6 @@ starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ structlog==23.3.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:24b42b914ac6bc4a4e6f716e82ac70d7fb1e8c3b1035a765591953bfc37101a5 \ --hash=sha256:d6922a88ceabef5b13b9eda9c4043624924f60edbb00397f4d193bd754cde60a -types-croniter==3.0.3.20240731 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7a170660642da662c704a463b011e31c049f5a218d27d30199a80ac5e8d15002 \ - --hash=sha256:da039d543e07b1db4ad93680cb837afd0f5c64974970287da8c6432d19441b71 typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 diff --git a/mula/scheduler/alembic/versions/0008_add_task_schedule.py b/mula/scheduler/alembic/versions/0008_add_task_schedule.py index 19e711b4e1a..4b58ec4b9c4 100644 --- a/mula/scheduler/alembic/versions/0008_add_task_schedule.py +++ b/mula/scheduler/alembic/versions/0008_add_task_schedule.py @@ -21,8 +21,6 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.execute('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";') - op.create_table( "schedules", sa.Column("id", scheduler.utils.datastore.GUID(), nullable=False), @@ -83,7 +81,7 @@ def upgrade(): op.execute( """ INSERT INTO schedules (id, scheduler_id, hash, data, enabled, schedule, deadline_at, created_at, modified_at) - SELECT DISTINCT ON (scheduler_id, hash) uuid_generate_v4(), scheduler_id, hash, data, true, '0 0 * * *', + SELECT DISTINCT ON (scheduler_id, hash) gen_random_uuid(), scheduler_id, hash, data, true, '0 0 * * *', now() + INTERVAL '1 day' * random(), now(), now() FROM tasks ORDER BY scheduler_id, hash, created_at DESC """ From 9e359e94e38ca1cb651a225a87b29d77394279cc Mon Sep 17 00:00:00 2001 From: Rieven Date: Fri, 16 Aug 2024 10:48:41 +0200 Subject: [PATCH 067/112] Fix generate findings report from ooi detail (#3369) Co-authored-by: Jan Klopper --- rocky/rocky/templates/partials/ooi_detail_toolbar.html | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/rocky/rocky/templates/partials/ooi_detail_toolbar.html b/rocky/rocky/templates/partials/ooi_detail_toolbar.html index b92189beca0..de282053b02 100644 --- a/rocky/rocky/templates/partials/ooi_detail_toolbar.html +++ b/rocky/rocky/templates/partials/ooi_detail_toolbar.html @@ -2,8 +2,14 @@ {% translate props.ooi_type as display_type %}
- {% translate "Generate findings report" %} +
+ {% csrf_token %} + + + +
{% if not ooi_past_due %} {% if ooi|is_finding and perms.tools.can_mute_findings %} Date: Mon, 19 Aug 2024 10:19:01 +0200 Subject: [PATCH 068/112] feat: :hammer: Add indemnification level from external DB (#3311) Co-authored-by: Jeroen Dekkers Co-authored-by: originalsouth Co-authored-by: Jan Klopper --- .../plugins/kat_external_db/normalize.py | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_external_db/normalize.py b/boefjes/boefjes/plugins/kat_external_db/normalize.py index e1b7fdb99c9..71595001f92 100644 --- a/boefjes/boefjes/plugins/kat_external_db/normalize.py +++ b/boefjes/boefjes/plugins/kat_external_db/normalize.py @@ -17,6 +17,8 @@ IP_ADDRESS_ITEM_PATH = ["address"] DOMAIN_LIST_PATH = ["domains"] DOMAIN_ITEM_PATH = ["name"] +INDEMNIFICATION_ITEM_PATH = ["indemnification_level"] +DEFAULT_INDEMNIFICATION_LEVEL = 3 def follow_path_in_dict(path, path_dict): @@ -29,6 +31,18 @@ def follow_path_in_dict(path, path_dict): return path_dict +def get_indemnification_level(path_dict): + """Return indemnification level from metadata or default.""" + try: + indemnification_level = int(follow_path_in_dict(path=INDEMNIFICATION_ITEM_PATH, path_dict=path_dict)) + if 0 <= indemnification_level < 5: + return indemnification_level + raise ValueError(f"Invalid indemnificationlevel {indemnification_level}, aborting.") + except KeyError: + logging.info("No integer indemnification level found, using default.") + return DEFAULT_INDEMNIFICATION_LEVEL + + def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: """Yields hostnames, IPv4/6 addresses or netblocks.""" results = json.loads(raw) @@ -37,6 +51,7 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: for address_item in follow_path_in_dict(path=IP_ADDRESS_LIST_PATH, path_dict=results): interface = ip_interface(follow_path_in_dict(path=IP_ADDRESS_ITEM_PATH, path_dict=address_item)) + indemnification_level = get_indemnification_level(path_dict=address_item) address, mask_str = interface.with_prefixlen.split("/") mask = int(mask_str) @@ -50,7 +65,7 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: ip_address = address_type(address=address, network=network.reference) yield ip_address - yield DeclaredScanProfile(reference=ip_address.reference, level=3) + yield DeclaredScanProfile(reference=ip_address.reference, level=indemnification_level) addresses_count += 1 if mask < interface.ip.max_prefixlen: @@ -60,15 +75,17 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: network=network.reference, ) yield block - yield DeclaredScanProfile(reference=block.reference, level=3) + yield DeclaredScanProfile(reference=block.reference, level=indemnification_level) blocks_count += 1 - for hostname in follow_path_in_dict(path=DOMAIN_LIST_PATH, path_dict=results): + for hostname_data in follow_path_in_dict(path=DOMAIN_LIST_PATH, path_dict=results): hostname = Hostname( - name=follow_path_in_dict(path=DOMAIN_ITEM_PATH, path_dict=hostname), network=network.reference + name=follow_path_in_dict(path=DOMAIN_ITEM_PATH, path_dict=hostname_data), network=network.reference ) yield hostname - yield DeclaredScanProfile(reference=hostname.reference, level=3) + yield DeclaredScanProfile( + reference=hostname.reference, level=get_indemnification_level(path_dict=hostname_data) + ) hostnames_count += 1 logging.info( From 822a5ae2e4c5cf1f9769b50d2b8c839e5a876c60 Mon Sep 17 00:00:00 2001 From: JP Bruins Slot Date: Tue, 20 Aug 2024 10:18:12 +0200 Subject: [PATCH 069/112] Add more handling of external services responses in scheduler (#3372) Co-authored-by: Jan Klopper Co-authored-by: Jeroen Dekkers --- mula/scheduler/connectors/services/bytes.py | 63 ++++++++++--------- .../connectors/services/katalogus.py | 51 +++++++++++---- .../scheduler/connectors/services/octopoes.py | 38 ++++++++--- .../scheduler/connectors/services/services.py | 24 ++----- mula/scheduler/schedulers/boefje.py | 63 ++++++++++++++----- mula/scheduler/schedulers/normalizer.py | 27 +++++--- 6 files changed, 168 insertions(+), 98 deletions(-) diff --git a/mula/scheduler/connectors/services/bytes.py b/mula/scheduler/connectors/services/bytes.py index ec92dcec2df..67a8ef93a37 100644 --- a/mula/scheduler/connectors/services/bytes.py +++ b/mula/scheduler/connectors/services/bytes.py @@ -86,40 +86,41 @@ def get_token(self) -> str: @exception_handler def get_last_run_boefje(self, boefje_id: str, input_ooi: str, organization_id: str) -> BoefjeMeta | None: url = f"{self.host}/bytes/boefje_meta" - response = self.get( - url=url, - params={ - "boefje_id": boefje_id, - "input_ooi": input_ooi, - "organization": organization_id, - "limit": 1, - "descending": "true", - }, - ) - - self._verify_response(response) - - if response.status_code == 200 and len(response.json()) > 0: - return BoefjeMeta(**response.json()[0]) - - return None + try: + response = self.get( + url=url, + params={ + "boefje_id": boefje_id, + "input_ooi": input_ooi, + "organization": organization_id, + "limit": 1, + "descending": "true", + }, + ) + if len(response.json()) > 0: + return BoefjeMeta(**response.json()[0]) + + return None + except httpx.HTTPStatusError as exc: + if exc.response.status_code == httpx.codes.NOT_FOUND: + return None + raise @retry_with_login @exception_handler def get_last_run_boefje_by_organisation_id(self, organization_id: str) -> BoefjeMeta | None: url = f"{self.host}/bytes/boefje_meta" - response = self.get( - url=url, - params={ - "organization": organization_id, - "limit": 1, - "descending": "true", - }, - ) - - self._verify_response(response) - - if response.status_code == 200 and response.content: + try: + response = self.get( + url=url, + params={ + "organization": organization_id, + "limit": 1, + "descending": "true", + }, + ) return BoefjeMeta(**response.json()[0]) - - return None + except httpx.HTTPStatusError as exc: + if exc.response.status_code == httpx.codes.NOT_FOUND: + return None + raise diff --git a/mula/scheduler/connectors/services/katalogus.py b/mula/scheduler/connectors/services/katalogus.py index 3ce82f098ce..8ea1028d526 100644 --- a/mula/scheduler/connectors/services/katalogus.py +++ b/mula/scheduler/connectors/services/katalogus.py @@ -1,5 +1,7 @@ import threading +import httpx + from scheduler.connectors.errors import exception_handler from scheduler.models import Boefje, Organisation, Plugin from scheduler.utils import dict_utils @@ -140,32 +142,57 @@ def flush_normalizer_cache(self) -> None: @exception_handler def get_boefjes(self) -> list[Boefje]: url = f"{self.host}/boefjes" - response = self.get(url) - return [Boefje(**boefje) for boefje in response.json()] + try: + response = self.get(url) + return [Boefje(**boefje) for boefje in response.json()] + except httpx.HTTPStatusError as e: + if e.response.status_code == httpx.codes.NOT_FOUND: + return [] + raise @exception_handler - def get_boefje(self, boefje_id: str) -> Boefje: + def get_boefje(self, boefje_id: str) -> Boefje | None: url = f"{self.host}/boefjes/{boefje_id}" - response = self.get(url) - return Boefje(**response.json()) + try: + response = self.get(url) + return Boefje(**response.json()) + except httpx.HTTPStatusError as e: + if e.response.status_code == httpx.codes.NOT_FOUND: + return None + raise @exception_handler - def get_organisation(self, organisation_id) -> Organisation: + def get_organisation(self, organisation_id) -> Organisation | None: url = f"{self.host}/v1/organisations/{organisation_id}" - response = self.get(url) - return Organisation(**response.json()) + try: + response = self.get(url) + return Organisation(**response.json()) + except httpx.HTTPStatusError as e: + if e.response.status_code == httpx.codes.NOT_FOUND: + return None + raise @exception_handler def get_organisations(self) -> list[Organisation]: url = f"{self.host}/v1/organisations" - response = self.get(url) - return [Organisation(**organisation) for organisation in response.json().values()] + try: + response = self.get(url) + return [Organisation(**organisation) for organisation in response.json().values()] + except httpx.HTTPStatusError as e: + if e.response.status_code == httpx.codes.NOT_FOUND: + return [] + raise @exception_handler def get_plugins_by_organisation(self, organisation_id: str) -> list[Plugin]: url = f"{self.host}/v1/organisations/{organisation_id}/plugins" - response = self.get(url) - return [Plugin(**plugin) for plugin in response.json()] + try: + response = self.get(url) + return [Plugin(**plugin) for plugin in response.json()] + except httpx.HTTPStatusError as e: + if e.response.status_code == httpx.codes.NOT_FOUND: + return [] + raise def get_plugins_by_org_id(self, organisation_id: str) -> list[Plugin]: def _get_from_cache() -> list[Plugin]: diff --git a/mula/scheduler/connectors/services/octopoes.py b/mula/scheduler/connectors/services/octopoes.py index 04d7b9f33f0..1e076da97c4 100644 --- a/mula/scheduler/connectors/services/octopoes.py +++ b/mula/scheduler/connectors/services/octopoes.py @@ -1,5 +1,6 @@ from datetime import datetime, timezone +import httpx from pydantic import BaseModel from scheduler.connectors.errors import exception_handler @@ -61,7 +62,14 @@ def get_objects_by_object_types( oois = [] for offset in range(0, count, limit): params["offset"] = offset - response = self.get(url, params=params) + + try: + response = self.get(url, params=params) + except httpx.HTTPStatusError as e: + if e.response.status_code == 404: + break + raise + list_objects = ListObjectsResponse(**response.json()) oois.extend([ooi for ooi in list_objects.items]) @@ -81,19 +89,29 @@ def get_random_objects(self, organisation_id: str, n: int, scan_level: list[int] "valid_time": datetime.now(timezone.utc), } - response = self.get(url, params=params) - - return [OOI(**ooi) for ooi in response.json()] + try: + response = self.get(url, params=params) + return [OOI(**ooi) for ooi in response.json()] + except httpx.HTTPStatusError as e: + if e.response.status_code == httpx.codes.NOT_FOUND: + return [] + raise @exception_handler - def get_object(self, organisation_id: str, reference: str) -> OOI: + def get_object(self, organisation_id: str, reference: str) -> OOI | None: """Get an ooi from octopoes""" url = f"{self.host}/{organisation_id}/object" - response = self.get( - url, - params={"reference": reference, "valid_time": datetime.now(timezone.utc)}, - ) - return OOI(**response.json()) + + try: + response = self.get( + url, + params={"reference": reference, "valid_time": datetime.now(timezone.utc)}, + ) + return OOI(**response.json()) + except httpx.HTTPStatusError as e: + if e.response.status_code == httpx.codes.NOT_FOUND: + return None + raise def is_healthy(self) -> bool: healthy = True diff --git a/mula/scheduler/connectors/services/services.py b/mula/scheduler/connectors/services/services.py index b539b454836..ceb59630b9b 100644 --- a/mula/scheduler/connectors/services/services.py +++ b/mula/scheduler/connectors/services/services.py @@ -4,7 +4,7 @@ import httpx import structlog -from httpx import HTTPError, HTTPTransport, Limits +from httpx import HTTPTransport, Limits from ..connector import Connector # noqa: TID252 @@ -110,6 +110,8 @@ def get( url=url, ) + response.raise_for_status() + return response def post( @@ -144,7 +146,7 @@ def post( payload=payload, ) - self._verify_response(response) + response.raise_for_status() return response @@ -196,21 +198,3 @@ def is_healthy(self) -> bool: return False return self.is_host_healthy(self.host, self.health_endpoint) - - def _verify_response(self, response: httpx.Response) -> None: - """Verify the received response from a request. - - Raises: - Exception - """ - try: - response.raise_for_status() - except HTTPError as e: - self.logger.error( - "Received bad response from %s.", - response.url, - name=self.name, - url=response.url, - response=str(response.content), - ) - raise e diff --git a/mula/scheduler/schedulers/boefje.py b/mula/scheduler/schedulers/boefje.py index fcf618aa6dd..16aa5022832 100644 --- a/mula/scheduler/schedulers/boefje.py +++ b/mula/scheduler/schedulers/boefje.py @@ -371,19 +371,32 @@ def push_tasks_for_rescheduling(self): boefje_task = BoefjeTask.parse_obj(schedule.data) # Plugin still exists? - plugin = self.ctx.services.katalogus.get_plugin_by_id_and_org_id( - boefje_task.boefje.id, - self.organisation.id, - ) - if not plugin: - self.logger.debug( - "Boefje does not exist anymore, skipping", + try: + plugin = self.ctx.services.katalogus.get_plugin_by_id_and_org_id( + boefje_task.boefje.id, + self.organisation.id, + ) + if not plugin: + self.logger.info( + "Boefje does not exist anymore, skipping and disabling schedule", + boefje_id=boefje_task.boefje.id, + schedule_id=schedule.id, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + schedule.enabled = False + self.ctx.datastores.schedule_store.update_schedule(schedule) + continue + except ExternalServiceError as exc_plugin: + self.logger.error( + "Could not get plugin %s from katalogus", + boefje_task.boefje.id, boefje_id=boefje_task.boefje.id, + schedule_id=schedule.id, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, + exc_info=exc_plugin, ) - schedule.enabled = False - self.ctx.datastores.schedule_store.update_schedule(schedule) continue # Plugin still enabled? @@ -391,6 +404,7 @@ def push_tasks_for_rescheduling(self): self.logger.debug( "Boefje is disabled, skipping", boefje_id=boefje_task.boefje.id, + schedule_id=schedule.id, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, ) @@ -405,6 +419,7 @@ def push_tasks_for_rescheduling(self): self.logger.warning( "Plugin is not a boefje, skipping", plugin_id=plugin.id, + schedule_id=schedule.id, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, ) @@ -415,16 +430,29 @@ def push_tasks_for_rescheduling(self): ooi = None if boefje_task.input_ooi: # OOI still exists? - ooi = self.ctx.services.octopoes.get_object(boefje_task.organization, boefje_task.input_ooi) - if not ooi: - self.logger.debug( - "OOI does not exist anymore, skipping", + try: + ooi = self.ctx.services.octopoes.get_object(boefje_task.organization, boefje_task.input_ooi) + if not ooi: + self.logger.info( + "OOI does not exist anymore, skipping and disabling schedule", + ooi_primary_key=boefje_task.input_ooi, + schedule_id=schedule.id, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + schedule.enabled = False + self.ctx.datastores.schedule_store.update_schedule(schedule) + continue + except ExternalServiceError as exc_ooi: + self.logger.error( + "Could not get ooi %s from octopoes", + boefje_task.input_ooi, ooi_primary_key=boefje_task.input_ooi, + schedule_id=schedule.id, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, + exc_info=exc_ooi, ) - schedule.enabled = False - self.ctx.datastores.schedule_store.update_schedule(schedule) continue # Boefje still consuming ooi type? @@ -445,10 +473,11 @@ def push_tasks_for_rescheduling(self): # Boefje allowed to scan ooi? if not self.has_boefje_permission_to_run(plugin, ooi): - self.logger.debug( - "Boefje not allowed to scan ooi, skipping", + self.logger.info( + "Boefje not allowed to scan ooi, skipping and disabling schedule", boefje_id=boefje_task.boefje.id, ooi_primary_key=ooi.primary_key, + schedule_id=schedule.id, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, ) diff --git a/mula/scheduler/schedulers/normalizer.py b/mula/scheduler/schedulers/normalizer.py index 43ec0432f20..9c9465c08c3 100644 --- a/mula/scheduler/schedulers/normalizer.py +++ b/mula/scheduler/schedulers/normalizer.py @@ -187,14 +187,25 @@ def push_normalizer_task(self, normalizer_task: models.NormalizerTask, caller: s caller=caller, ) - plugin = self.ctx.services.katalogus.get_plugin_by_id_and_org_id( - normalizer_task.normalizer.id, - self.organisation.id, - ) - if not self.has_normalizer_permission_to_run(plugin): - self.logger.debug( - "Task is not allowed to run: %s", - normalizer_task.id, + try: + plugin = self.ctx.services.katalogus.get_plugin_by_id_and_org_id( + normalizer_task.normalizer.id, + self.organisation.id, + ) + if not self.has_normalizer_permission_to_run(plugin): + self.logger.debug( + "Task is not allowed to run: %s", + normalizer_task.id, + task_id=normalizer_task.id, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + ) + return + except ExternalServiceError: + self.logger.warning( + "Could not get plugin by id: %s", + normalizer_task.normalizer.id, task_id=normalizer_task.id, organisation_id=self.organisation.id, scheduler_id=self.scheduler_id, From 917f33dc9946ba5c237f0ed0f73dd46a5068433f Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:42:31 +0200 Subject: [PATCH 070/112] Fix no certificate bug (#3382) --- boefjes/boefjes/plugins/kat_ssl_certificates/normalize.py | 4 ++-- boefjes/tests/test_sslcertificate_normalizer.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_ssl_certificates/normalize.py b/boefjes/boefjes/plugins/kat_ssl_certificates/normalize.py index 8d3daabb0a7..6ab49289ec7 100644 --- a/boefjes/boefjes/plugins/kat_ssl_certificates/normalize.py +++ b/boefjes/boefjes/plugins/kat_ssl_certificates/normalize.py @@ -9,7 +9,7 @@ from cryptography.hazmat.primitives.asymmetric import ec, rsa from dateutil.parser import parse -from boefjes.job_models import NormalizerOutput +from boefjes.job_models import NormalizerAffirmation, NormalizerOutput from octopoes.models import Reference from octopoes.models.ooi.certificate import ( AlgorithmType, @@ -73,7 +73,7 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: ) # update website - yield website + yield NormalizerAffirmation(ooi=website) # chain certificates together last_certificate = None diff --git a/boefjes/tests/test_sslcertificate_normalizer.py b/boefjes/tests/test_sslcertificate_normalizer.py index 1687ff3f6cd..429329b3819 100644 --- a/boefjes/tests/test_sslcertificate_normalizer.py +++ b/boefjes/tests/test_sslcertificate_normalizer.py @@ -22,4 +22,4 @@ def test_ssl_certificates_normalizer(): output = list(run(input_ooi, get_dummy_data("ssl-certificates.txt"))) - assert len([ooi for ooi in output if ooi.object_type == "X509Certificate"]) == 3 + assert len([ooi for ooi in output if hasattr(ooi, "object_type") and ooi.object_type == "X509Certificate"]) == 3 From 47866c0091a72132291a8e00c21d9014130d843c Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:46:41 +0200 Subject: [PATCH 071/112] Support setting a custom JSON schema for copied boefjes (#3344) Signed-off-by: Donny Peeters Co-authored-by: Jan Klopper Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> --- boefjes/boefjes/dependencies/plugins.py | 7 +- boefjes/boefjes/katalogus/plugins.py | 15 +- boefjes/boefjes/katalogus/root.py | 9 + boefjes/boefjes/local_repository.py | 5 +- ..._introduce_schema_field_to_boefje_model.py | 62 ++++++ ...de6eb7824b_introduce_boefjeconfig_model.py | 199 ++++++++++++------ boefjes/boefjes/models.py | 14 +- boefjes/boefjes/plugins/models.py | 13 ++ boefjes/boefjes/sql/db_models.py | 1 + boefjes/boefjes/sql/plugin_storage.py | 2 + boefjes/tests/integration/test_api.py | 57 ++++- .../test_migration_add_schema_field.py | 166 +++++++++++++++ .../test_remove_repository_migration.py | 7 +- ...est_settings_to_boefje_config_migration.py | 10 +- 14 files changed, 475 insertions(+), 92 deletions(-) create mode 100644 boefjes/boefjes/migrations/versions/5be152459a7b_introduce_schema_field_to_boefje_model.py create mode 100644 boefjes/tests/integration/test_migration_add_schema_field.py diff --git a/boefjes/boefjes/dependencies/plugins.py b/boefjes/boefjes/dependencies/plugins.py index c6f922ce9d4..ccb3187c0e2 100644 --- a/boefjes/boefjes/dependencies/plugins.py +++ b/boefjes/boefjes/dependencies/plugins.py @@ -158,7 +158,12 @@ def delete_settings(self, organisation_id: str, plugin_id: str): self.set_enabled_by_id(plugin_id, organisation_id, False) def schema(self, plugin_id: str) -> dict | None: - return self.local_repo.schema(plugin_id) + try: + boefje = self.plugin_storage.boefje_by_id(plugin_id) + + return boefje.schema + except PluginNotFound: + return self.local_repo.schema(plugin_id) def cover(self, plugin_id: str) -> Path: try: diff --git a/boefjes/boefjes/katalogus/plugins.py b/boefjes/boefjes/katalogus/plugins.py index 0928280af4a..134243ad963 100644 --- a/boefjes/boefjes/katalogus/plugins.py +++ b/boefjes/boefjes/katalogus/plugins.py @@ -3,7 +3,8 @@ from fastapi import APIRouter, Body, Depends, HTTPException, status from fastapi.responses import FileResponse, JSONResponse, Response -from pydantic import BaseModel, Field +from jsonschema.validators import Draft202012Validator +from pydantic import BaseModel, Field, field_validator from boefjes.dependencies.plugins import ( PluginService, @@ -90,6 +91,8 @@ def get_plugin( @router.post("/plugins", status_code=status.HTTP_201_CREATED) def add_plugin(plugin: PluginType, plugin_service: PluginService = Depends(get_plugin_service)): with plugin_service as service: + plugin.static = False # Creation through the API implies that these cannot be static + if plugin.type == "boefje": return service.create_boefje(plugin) @@ -124,9 +127,19 @@ class BoefjeIn(BaseModel): scan_level: int = 1 consumes: set[str] = Field(default_factory=set) produces: set[str] = Field(default_factory=set) + schema: dict | None = None oci_image: str | None = None oci_arguments: list[str] = Field(default_factory=list) + @field_validator("schema") + @classmethod + def json_schema_valid(cls, schema: dict | None) -> dict | None: + if schema is not None: + Draft202012Validator.check_schema(schema) + return schema + + return None + @router.patch("/boefjes/{boefje_id}", status_code=status.HTTP_204_NO_CONTENT) def update_boefje( diff --git a/boefjes/boefjes/katalogus/root.py b/boefjes/boefjes/katalogus/root.py index 5c62cea744b..8aa0c1683c5 100644 --- a/boefjes/boefjes/katalogus/root.py +++ b/boefjes/boefjes/katalogus/root.py @@ -5,6 +5,7 @@ import structlog from fastapi import APIRouter, FastAPI, Request, status from fastapi.responses import JSONResponse, RedirectResponse +from jsonschema.exceptions import SchemaError from opentelemetry import trace from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor @@ -96,6 +97,14 @@ def storage_error_handler(request: Request, exc: StorageError): ) +@app.exception_handler(SchemaError) +def schema_error_handler(request: Request, exc: StorageError): + return JSONResponse( + status_code=status.HTTP_400_BAD_REQUEST, + content={"message": "Invalid jsonschema provided"}, + ) + + class ServiceHealth(BaseModel): service: str healthy: bool = False diff --git a/boefjes/boefjes/local_repository.py b/boefjes/boefjes/local_repository.py index 4e53054fe43..a29fb92ba35 100644 --- a/boefjes/boefjes/local_repository.py +++ b/boefjes/boefjes/local_repository.py @@ -11,6 +11,7 @@ BOEFJES_DIR, ENTRYPOINT_NORMALIZERS, NORMALIZER_DEFINITION_FILE, + SCHEMA_FILE, BoefjeResource, ModuleException, NormalizerResource, @@ -52,10 +53,10 @@ def schema(self, id_: str) -> dict | None: if id_ not in boefjes: return None - path = boefjes[id_].path / "schema.json" + path = boefjes[id_].path / SCHEMA_FILE if not path.exists(): - logger.debug("Did not find schema for boefje %s", boefjes[id_]) + logger.debug("Did not find schema for boefje %s", id_) return None return json.loads(path.read_text()) diff --git a/boefjes/boefjes/migrations/versions/5be152459a7b_introduce_schema_field_to_boefje_model.py b/boefjes/boefjes/migrations/versions/5be152459a7b_introduce_schema_field_to_boefje_model.py new file mode 100644 index 00000000000..2cd63145aa5 --- /dev/null +++ b/boefjes/boefjes/migrations/versions/5be152459a7b_introduce_schema_field_to_boefje_model.py @@ -0,0 +1,62 @@ +"""Introduce schema field to Boefje model + +Revision ID: 5be152459a7b +Revises: f9de6eb7824b +Create Date: 2024-08-08 14:47:12.582017 + +""" + +import logging + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.orm import sessionmaker + +from boefjes.local_repository import get_local_repository +from boefjes.sql.plugin_storage import create_plugin_storage +from boefjes.storage.interfaces import PluginNotFound + +# revision identifiers, used by Alembic. +revision = "5be152459a7b" +down_revision = "f9de6eb7824b" +branch_labels = None +depends_on = None + +logger = logging.getLogger(__name__) + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column("boefje", sa.Column("schema", sa.JSON(), nullable=True)) + + local_repo = get_local_repository() + session = sessionmaker(bind=op.get_bind())() + + with create_plugin_storage(session) as storage: + plugins = local_repo.get_all() + logger.info("Found %s plugins", len(plugins)) + + for plugin in local_repo.get_all(): + schema = local_repo.schema(plugin.id) + + if schema: + try: + # This way we avoid the safeguard that updating static boefjes is not allowed + instance = storage._db_boefje_instance_by_id(plugin.id) + instance.schema = schema + storage.session.add(instance) + logger.info("Updated database entry for plugin %s", plugin.id) + except PluginNotFound: + logger.info("No database entry for plugin %s", plugin.id) + continue + else: + logger.info("No schema present for plugin %s", plugin.id) + + session.close() + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("boefje", "schema") + # ### end Alembic commands ### diff --git a/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py b/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py index ffa35930368..40a44d504d3 100644 --- a/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py +++ b/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py @@ -10,11 +10,12 @@ import sqlalchemy as sa from alembic import op -from sqlalchemy.orm import sessionmaker +from psycopg2._json import Json +from psycopg2.extensions import register_adapter +from psycopg2.extras import execute_values from boefjes.local_repository import get_local_repository -from boefjes.sql.plugin_storage import create_plugin_storage -from boefjes.storage.interfaces import PluginNotFound +from boefjes.models import Boefje, Normalizer # revision identifiers, used by Alembic. revision = "f9de6eb7824b" @@ -57,72 +58,136 @@ def upgrade() -> None: op.add_column("boefje", sa.Column("static", sa.Boolean(), server_default="false", nullable=False)) op.add_column("normalizer", sa.Column("static", sa.Boolean(), server_default="false", nullable=False)) + register_adapter(dict, Json) + local_plugins = {plugin.id: plugin for plugin in get_local_repository().get_all()} connection = op.get_bind() - session = sessionmaker(bind=connection)() - - with create_plugin_storage(session) as storage: - # Get unique plugin_ids from the settings table for boefjes that do not exist yet in the database - query = """ - SELECT DISTINCT s.plugin_id FROM settings s left join boefje b on b.plugin_id = s.plugin_id - where b.plugin_id IS NULL - """ - for plugin_id_output in op.get_bind().execute(query).fetchall(): - plugin_id = plugin_id_output[0] - if plugin_id not in local_plugins: - raise ValueError(f"Invalid plugin id found: {plugin_id}") - - # Since settings are boefje-only at this moment - if local_plugins[plugin_id].type != "boefje": - raise ValueError(f"Settings for normalizer or bit found: {plugin_id}. Remove these entries first.") - - try: - storage.boefje_by_id(plugin_id) - continue # The Boefje already exists - except PluginNotFound: - pass # The raw query bypasses the session "cache", so this just checks for duplicates - - storage.create_boefje(local_plugins[plugin_id]) # type: ignore - - query = """ - SELECT DISTINCT p.plugin_id FROM plugin_state p left join boefje b on b.plugin_id = p.plugin_id - where b.plugin_id IS NULL - """ - - for plugin_id_output in op.get_bind().execute(query).fetchall(): - plugin_id = plugin_id_output[0] - if plugin_id not in local_plugins: - logger.warning("Unknown plugin id found: %s. You might have to re-enable the plugin!", plugin_id) - continue - - try: - storage.boefje_by_id(plugin_id) - continue # The Boefje already exists - except PluginNotFound: - pass # The raw query bypasses the session "cache", so this just checks for duplicates - - if local_plugins[plugin_id].type == "boefje": - storage.create_boefje(local_plugins[plugin_id]) # type: ignore - - query = """ - SELECT DISTINCT p.plugin_id FROM plugin_state p left join normalizer n on n.plugin_id = p.plugin_id - where n.plugin_id IS NULL - """ - - for plugin_id_output in op.get_bind().execute(query).fetchall(): - plugin_id = plugin_id_output[0] - if plugin_id not in local_plugins: - logger.warning("Unknown plugin id found: %s. You might have to re-enable the plugin!", plugin_id) - continue - - try: - storage.normalizer_by_id(plugin_id) - continue # The Normalizer already exists - except PluginNotFound: - pass # The raw query bypasses the session "cache", so this just checks for duplicates - - if local_plugins[plugin_id].type == "normalizer": - storage.create_normalizer(local_plugins[plugin_id]) # type: ignore + + # Get unique plugin_ids from the settings table for boefjes that do not exist yet in the database + query = """ + SELECT DISTINCT s.plugin_id FROM settings s left join boefje b on b.plugin_id = s.plugin_id + where b.plugin_id IS NULL + """ # noqa: S608 + + to_insert: list[Boefje] = [] + + for plugin_id_output in connection.execute(query).fetchall(): + plugin_id = plugin_id_output[0] + if plugin_id not in local_plugins: + raise ValueError(f"Invalid plugin id found: {plugin_id}") + + # Since settings are boefje-only at this moment + if local_plugins[plugin_id].type != "boefje": + raise ValueError(f"Settings for normalizer or bit found: {plugin_id}. Remove these entries first.") + + res = connection.execute(f"SELECT id FROM boefje where plugin_id = '{plugin_id}'") # noqa: S608 + if res.fetchone() is not None: + continue # The Boefje already exists + + if local_plugins[plugin_id].type == "boefje": + to_insert.append(local_plugins[plugin_id]) + + entries = [ + ( + boefje.id, + boefje.name, + boefje.description, + str(boefje.scan_level), + list(boefje.consumes), + list(boefje.produces), + boefje.environment_keys, + boefje.oci_image, + boefje.oci_arguments, + boefje.version, + ) + for boefje in to_insert + ] + query = """INSERT INTO boefje (plugin_id, name, description, scan_level, consumes, produces, environment_keys, + oci_image, oci_arguments, version) values %s""" + + with connection.begin(): + cursor = connection.connection.cursor() + execute_values(cursor, query, entries) + + to_insert = [] + + query = """ + SELECT DISTINCT p.plugin_id FROM plugin_state p left join boefje b on b.plugin_id = p.plugin_id + where b.plugin_id IS NULL + """ + + for plugin_id_output in connection.execute(query).fetchall(): + plugin_id = plugin_id_output[0] + if plugin_id not in local_plugins: + logger.warning("Unknown plugin id found: %s. You might have to re-enable the plugin!", plugin_id) + continue + + res = connection.execute(f"SELECT id FROM boefje where plugin_id = '{plugin_id}'") # noqa: S608 + if res.fetchone() is not None: + continue # The Boefje already exists + + if local_plugins[plugin_id].type == "boefje": + to_insert.append(local_plugins[plugin_id]) + + entries = [ + ( + boefje.id, + boefje.name, + boefje.description, + str(boefje.scan_level), + list(boefje.consumes), + list(boefje.produces), + boefje.environment_keys, + boefje.oci_image, + boefje.oci_arguments, + boefje.version, + ) + for boefje in to_insert + ] + query = """INSERT INTO boefje (plugin_id, name, description, scan_level, consumes, produces, environment_keys, + oci_image, oci_arguments, version) values %s""" # noqa: S608 + + with connection.begin(): + cursor = connection.connection.cursor() + execute_values(cursor, query, entries) + + normalizers_to_insert: list[Normalizer] = [] + query = """ + SELECT DISTINCT p.plugin_id FROM plugin_state p left join normalizer n on n.plugin_id = p.plugin_id + where n.plugin_id IS NULL + """ # noqa: S608 + + for plugin_id_output in connection.execute(query).fetchall(): + plugin_id = plugin_id_output[0] + if plugin_id not in local_plugins: + logger.warning("Unknown plugin id found: %s. You might have to re-enable the plugin!", plugin_id) + continue + + res = connection.execute(f"SELECT id FROM normalizer where plugin_id = '{plugin_id}'") # noqa: S608 + if res.fetchone() is not None: + continue # The Normalizer already exists + + if local_plugins[plugin_id].type == "normalizer": + normalizers_to_insert.append(local_plugins[plugin_id]) + + normalizer_entries = [ + ( + normalizer.id, + normalizer.name, + normalizer.description, + normalizer.consumes, + normalizer.produces, + normalizer.environment_keys, + normalizer.version, + ) + for normalizer in normalizers_to_insert + ] + query = """INSERT INTO normalizer (plugin_id, name, description, consumes, produces, environment_keys, version) + values %s""" # noqa: S608 + + with connection.begin(): + cursor = connection.connection.cursor() + execute_values(cursor, query, normalizer_entries) with connection.begin(): connection.execute(""" diff --git a/boefjes/boefjes/models.py b/boefjes/boefjes/models.py index 69d8cc2c637..4881b26008a 100644 --- a/boefjes/boefjes/models.py +++ b/boefjes/boefjes/models.py @@ -2,7 +2,8 @@ from enum import Enum from typing import Literal -from pydantic import BaseModel, Field +from jsonschema.validators import Draft202012Validator +from pydantic import BaseModel, Field, field_validator class Organisation(BaseModel): @@ -29,10 +30,21 @@ class Boefje(Plugin): scan_level: int = 1 consumes: set[str] = Field(default_factory=set) produces: set[str] = Field(default_factory=set) + schema: dict | None = None runnable_hash: str | None = None oci_image: str | None = None oci_arguments: list[str] = Field(default_factory=list) + @field_validator("schema") + @classmethod + def json_schema_valid(cls, schema: dict) -> dict: + if schema is not None: + Draft202012Validator.check_schema(schema) + return schema + + class Config: + validate_assignment = True + class Normalizer(Plugin): type: Literal["normalizer"] = "normalizer" diff --git a/boefjes/boefjes/plugins/models.py b/boefjes/boefjes/plugins/models.py index 5a2669ffbc4..91af854f576 100644 --- a/boefjes/boefjes/plugins/models.py +++ b/boefjes/boefjes/plugins/models.py @@ -1,15 +1,20 @@ import hashlib +import json from enum import Enum from importlib import import_module from inspect import isfunction, signature +from json import JSONDecodeError from pathlib import Path from typing import Protocol +from jsonschema.exceptions import SchemaError + from boefjes.models import Boefje, Normalizer BOEFJES_DIR = Path(__file__).parent BOEFJE_DEFINITION_FILE = "boefje.json" +SCHEMA_FILE = "schema.json" NORMALIZER_DEFINITION_FILE = "normalizer.json" ENTRYPOINT_BOEFJES = "main.py" ENTRYPOINT_NORMALIZERS = "normalize.py" @@ -62,6 +67,14 @@ def __init__(self, path: Path, package: str): if (path / ENTRYPOINT_BOEFJES).exists(): self.module = get_runnable_module_from_package(package, ENTRYPOINT_BOEFJES, parameter_count=1) + if (path / SCHEMA_FILE).exists(): + try: + self.boefje.schema = json.load((path / SCHEMA_FILE).open()) + except JSONDecodeError as e: + raise ModuleException("Invalid schema file") from e + except SchemaError as e: + raise ModuleException("Invalid schema") from e + class NormalizerResource: """Represents a Normalizer package that we can run. Throws a ModuleException if any validation fails.""" diff --git a/boefjes/boefjes/sql/db_models.py b/boefjes/boefjes/sql/db_models.py index 1ecd0cc0086..e8e9740f8f4 100644 --- a/boefjes/boefjes/sql/db_models.py +++ b/boefjes/boefjes/sql/db_models.py @@ -76,6 +76,7 @@ class BoefjeInDB(SQL_BASE): consumes = Column(types.ARRAY(types.String(length=128)), default=lambda: [], nullable=False) produces = Column(types.ARRAY(types.String(length=128)), default=lambda: [], nullable=False) environment_keys = Column(types.ARRAY(types.String(length=128)), default=lambda: [], nullable=False) + schema = Column(types.JSON(), nullable=True) # Image specifications oci_image = Column(types.String(length=256), nullable=True) diff --git a/boefjes/boefjes/sql/plugin_storage.py b/boefjes/boefjes/sql/plugin_storage.py index 2dddd0ad822..c9bcffbaa2f 100644 --- a/boefjes/boefjes/sql/plugin_storage.py +++ b/boefjes/boefjes/sql/plugin_storage.py @@ -110,6 +110,7 @@ def to_boefje_in_db(boefje: Boefje) -> BoefjeInDB: scan_level=str(boefje.scan_level), consumes=boefje.consumes, produces=boefje.produces, + schema=boefje.schema, environment_keys=boefje.environment_keys, oci_image=boefje.oci_image, oci_arguments=boefje.oci_arguments, @@ -142,6 +143,7 @@ def to_boefje(boefje_in_db: BoefjeInDB) -> Boefje: scan_level=int(boefje_in_db.scan_level), consumes=boefje_in_db.consumes, produces=boefje_in_db.produces, + schema=boefje_in_db.schema, environment_keys=boefje_in_db.environment_keys, oci_image=boefje_in_db.oci_image, oci_arguments=boefje_in_db.oci_arguments, diff --git a/boefjes/tests/integration/test_api.py b/boefjes/tests/integration/test_api.py index b29060cf316..9c32af42f8a 100644 --- a/boefjes/tests/integration/test_api.py +++ b/boefjes/tests/integration/test_api.py @@ -60,7 +60,7 @@ def test_cannot_add_plugin_reserved_id(self): self.assertEqual(response.status_code, 400) self.assertEqual(response.json(), {"message": "Plugin id 'dns-records' is already used"}) - normalizer = Normalizer(id="kat_nmap_normalize", name="My test normalizer", static=False) + normalizer = Normalizer(id="kat_nmap_normalize", name="My test normalizer") response = self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=normalizer.json()) self.assertEqual(response.status_code, 400) self.assertEqual(response.json(), {"message": "Plugin id 'kat_nmap_normalize' is already used"}) @@ -115,8 +115,8 @@ def test_delete_normalizer(self): self.assertEqual(response.status_code, 404) def test_update_plugins(self): - normalizer = Normalizer(id="norm_id", name="My test normalizer", static=False) - boefje = Boefje(id="test_plugin", name="My test boefje", description="123", static=False) + normalizer = Normalizer(id="norm_id", name="My test normalizer") + boefje = Boefje(id="test_plugin", name="My test boefje", description="123") self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=boefje.json()) self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/{boefje.id}", json={"description": "4"}) @@ -126,6 +126,50 @@ def test_update_plugins(self): self.assertEqual(response.json()["description"], "4") self.assertTrue(response.json()["enabled"]) + self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=normalizer.json()) + self.client.patch(f"/v1/organisations/{self.org.id}/normalizers/{normalizer.id}", json={"version": "v1.2"}) + + response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/{normalizer.id}") + self.assertEqual(response.json()["version"], "v1.2") + + def test_cannot_create_boefje_with_invalid_schema(self): + boefje = Boefje(id="test_plugin", name="My test boefje", description="123").model_dump(mode="json") + boefje["schema"] = {"$schema": 3} + + r = self.client.post(f"/v1/organisations/{self.org.id}/plugins", json=boefje) + self.assertEqual(r.status_code, 400) + + def test_update_boefje_schema(self): + boefje = Boefje(id="test_plugin", name="My test boefje", description="123") + self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=boefje.json()) + + r = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/{boefje.id}", json={"schema": {"$schema": 3}}) + self.assertEqual(r.status_code, 400) + + valid_schema = { + "title": "Arguments", + "type": "object", + "properties": { + "MY_KEY": { + "title": "MY_KEY", + "type": "integer", + } + }, + "required": [], + } + r = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/{boefje.id}", json={"schema": valid_schema}) + self.assertEqual(r.status_code, 204) + + schema = self.client.get(f"/v1/organisations/{self.org.id}/plugins/{boefje.id}/schema.json").json() + assert schema == valid_schema + + api_boefje = self.client.get(f"/v1/organisations/{self.org.id}/plugins/{boefje.id}").json() + assert api_boefje["schema"] == valid_schema + + r = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/dns-records", json={"schema": valid_schema}) + self.assertEqual(r.status_code, 404) + + def test_cannot_update_static_plugins(self): r = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/dns-records", json={"id": "4", "version": "s"}) self.assertEqual(r.status_code, 404) r = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/dns-records", json={"name": "Overwrite name"}) @@ -136,13 +180,6 @@ def test_update_plugins(self): self.assertIsNone(response.json()["version"]) self.assertEqual(response.json()["id"], "dns-records") - self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=normalizer.json()) - self.client.patch(f"/v1/organisations/{self.org.id}/normalizers/{normalizer.id}", json={"version": "v1.2"}) - - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/{normalizer.id}") - self.assertEqual(response.json()["version"], "v1.2") - - def test_cannot_update_static_plugins(self): self.client.patch(f"/v1/organisations/{self.org.id}/plugins/dns-records", json={"enabled": True}) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/dns-records") self.assertTrue(response.json()["enabled"]) diff --git a/boefjes/tests/integration/test_migration_add_schema_field.py b/boefjes/tests/integration/test_migration_add_schema_field.py new file mode 100644 index 00000000000..26fa13f0a70 --- /dev/null +++ b/boefjes/tests/integration/test_migration_add_schema_field.py @@ -0,0 +1,166 @@ +import os +from unittest import TestCase, skipIf + +import alembic.config +from psycopg2.extras import execute_values +from sqlalchemy.orm import sessionmaker + +from boefjes.local_repository import get_local_repository +from boefjes.sql.db import SQL_BASE, get_engine + + +@skipIf(os.environ.get("CI") != "1", "Needs a CI database.") +class TestSettingsToBoefjeConfig(TestCase): + def setUp(self) -> None: + self.engine = get_engine() + + # To reset autoincrement ids + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "base"]) + # Set state to revision 6f99834a4a5a + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) + + dns_records = get_local_repository().by_id("dns-records") + nmap_udp = get_local_repository().by_id("nmap-udp") + + entries = [ + ( + boefje.id, + boefje.name, + boefje.description, + str(boefje.scan_level), + list(sorted(boefje.consumes)), + list(sorted(boefje.produces)), + boefje.environment_keys, + boefje.oci_image, + boefje.oci_arguments, + boefje.version, + ) + for boefje in [dns_records, nmap_udp] + ] + + connection = self.engine.connect() + query = """INSERT INTO boefje (plugin_id, name, description, scan_level, consumes, produces, environment_keys, + oci_image, oci_arguments, version) values %s""" + + with connection.begin(): + execute_values(connection.connection.cursor(), query, entries) + + def test_fail_on_wrong_plugin_ids(self): + assert self.engine.execute("SELECT * from boefje").fetchall() == [ + ( + 1, + "dns-records", + None, + "DnsRecords", + "Fetch the DNS record(s) of a hostname", + "1", + ["Hostname"], + ["boefje/dns-records"], + ["RECORD_TYPES", "REMOTE_NS"], + None, + [], + None, + False, + ), + ( + 2, + "nmap-udp", + None, + "Nmap UDP", + "Defaults to top 250 UDP ports. Includes service detection.", + "2", + ["IPAddressV4", "IPAddressV6"], + ["boefje/nmap-udp"], + ["TOP_PORTS_UDP"], + "ghcr.io/minvws/openkat/nmap:latest", + ["--open", "-T4", "-Pn", "-r", "-v10", "-sV", "-sU"], + None, + False, + ), + ] + + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "5be152459a7b"]) + + schema_dns = { + "title": "Arguments", + "type": "object", + "properties": { + "RECORD_TYPES": { + "title": "RECORD_TYPES", + "type": "string", + "description": "List of comma separated DNS record types to query for.", + "default": "A,AAAA,CAA,CERT,RP,SRV,TXT,MX,NS,CNAME,DNAME", + }, + "REMOTE_NS": { + "title": "REMOTE_NS", + "maxLength": 45, + "type": "string", + "description": "The IP address of the DNS resolver you want to use.", + "default": "1.1.1.1", + }, + }, + } + + schema_udp = { + "title": "Arguments", + "type": "object", + "properties": { + "TOP_PORTS_UDP": { + "title": "TOP_PORTS_UDP", + "type": "integer", + "minimum": 1, + "maximum": 65535, + "description": "Scan TOP_PORTS_UDP most common ports. Defaults to 250.", + } + }, + "required": [], + } + + self.assertListEqual( + self.engine.execute("SELECT * from boefje").fetchall(), + [ + ( + 1, + "dns-records", + None, + "DnsRecords", + "Fetch the DNS record(s) of a hostname", + "1", + ["Hostname"], + ["boefje/dns-records"], + ["RECORD_TYPES", "REMOTE_NS"], + None, + [], + None, + False, + schema_dns, + ), + ( + 2, + "nmap-udp", + None, + "Nmap UDP", + "Defaults to top 250 UDP ports. Includes service detection.", + "2", + ["IPAddressV4", "IPAddressV6"], + ["boefje/nmap-udp"], + ["TOP_PORTS_UDP"], + "ghcr.io/minvws/openkat/nmap:latest", + ["--open", "-T4", "-Pn", "-r", "-v10", "-sV", "-sU"], + None, + False, + schema_udp, + ), + ], + ) + + def tearDown(self) -> None: + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) + + session = sessionmaker(bind=get_engine())() + + for table in SQL_BASE.metadata.tables: + session.execute(f"DELETE FROM {table} CASCADE") # noqa: S608 + + session.commit() + session.close() diff --git a/boefjes/tests/integration/test_remove_repository_migration.py b/boefjes/tests/integration/test_remove_repository_migration.py index dd2ee7c8034..33379d42714 100644 --- a/boefjes/tests/integration/test_remove_repository_migration.py +++ b/boefjes/tests/integration/test_remove_repository_migration.py @@ -27,6 +27,8 @@ def setUp(self) -> None: storage.create(Organisation(id="dev1", name="Test 1 ")) storage.create(Organisation(id="dev2", name="Test 2 ")) + session.close() + entries = [(1, "LOCAL", "Repository Local", "https://local.com/")] query = f"INSERT INTO repository (pk, id, name, base_url) values {','.join(map(str, entries))}" # noqa: S608 self.engine.execute(text(query)) @@ -44,7 +46,6 @@ def setUp(self) -> None: f"INSERT INTO organisation_repository (repository_pk, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 ) self.engine.execute(text(query)) - session.close() def test_fail_on_non_unique(self): session = sessionmaker(bind=self.engine)() @@ -76,8 +77,6 @@ def test_fail_on_non_unique(self): session.close() def test_downgrade(self): - session = sessionmaker(bind=self.engine)() - self.engine.execute(text("DELETE FROM plugin_state WHERE id = 2")) # Fix unique constraint fails alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "7c88b9cd96aa"]) alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "-1"]) @@ -88,8 +87,6 @@ def test_downgrade(self): (1, "LOCAL", "Local Plugin Repository", "http://dev/null") ] - session.close() - def tearDown(self) -> None: self.engine.execute(text("DELETE FROM plugin_state")) # Fix unique constraint fails diff --git a/boefjes/tests/integration/test_settings_to_boefje_config_migration.py b/boefjes/tests/integration/test_settings_to_boefje_config_migration.py index 35e7670f614..261a965240c 100644 --- a/boefjes/tests/integration/test_settings_to_boefje_config_migration.py +++ b/boefjes/tests/integration/test_settings_to_boefje_config_migration.py @@ -10,7 +10,6 @@ from boefjes.sql.config_storage import SQLConfigStorage, create_encrypter from boefjes.sql.db import SQL_BASE, get_engine from boefjes.sql.organisation_storage import SQLOrganisationStorage -from boefjes.sql.plugin_storage import SQLPluginStorage @skipIf(os.environ.get("CI") != "1", "Needs a CI database.") @@ -29,6 +28,8 @@ def setUp(self) -> None: storage.create(Organisation(id="dev1", name="Test 1 ")) storage.create(Organisation(id="dev2", name="Test 2 ")) + session.close() + encrypter = create_encrypter() entries = [ (1, encrypter.encode('{"key1": "val1"}'), "dns-records", 1), @@ -44,8 +45,6 @@ def setUp(self) -> None: ) self.engine.execute(text(query)) - session.close() - def test_fail_on_wrong_plugin_ids(self): session = sessionmaker(bind=self.engine)() @@ -73,16 +72,17 @@ def test_fail_on_wrong_plugin_ids(self): alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) - assert SQLPluginStorage(session, settings).boefje_by_id("dns-records").id == "dns-records" + assert self.engine.execute(text("SELECT id FROM boefje WHERE plugin_id = 'dns-records'")).fetchall() == [(2,)] config_storage = SQLConfigStorage(session, encrypter) assert config_storage.get_all_settings("dev1", "dns-records") == {"key1": "val1"} - assert config_storage.get_all_settings("dev2", "dns-records") == {"key1": "val1", "key2": "val2"} assert config_storage.get_all_settings("dev1", "nmap-udp") == {} + assert config_storage.get_all_settings("dev2", "dns-records") == {"key1": "val1", "key2": "val2"} assert config_storage.is_enabled_by_id("dns-records", "dev1") assert config_storage.is_enabled_by_id("nmap-udp", "dev1") + session.commit() session.close() def test_downgrade(self): From b93157de143adfb01cdab9495b49cf7cb16594f8 Mon Sep 17 00:00:00 2001 From: Roelof Korporaal Date: Wed, 21 Aug 2024 16:31:44 +0200 Subject: [PATCH 072/112] Implement boefje details modal in report config flow (#3348) Co-authored-by: Heleen Co-authored-by: Jan Klopper --- .../css/components/scan-level-indicator.scss | 16 ++-- rocky/assets/css/components/state-tag.scss | 22 +++++ rocky/assets/css/main.scss | 1 + .../body-text-set.scss | 24 +++++ .../soft/fundamentals/border-radii.scss | 24 +++++ .../soft/{colors => fundamentals}/colors.scss | 0 .../{colors => fundamentals}/tag-colors.scss | 0 .../{colors => fundamentals}/tags-6-3.scss | 0 .../themes/soft/manon/application-base.scss | 6 +- .../css/themes/soft/manon/breadcrumb-bar.scss | 4 +- .../css/themes/soft/manon/de-emphasized.scss | 2 +- rocky/assets/css/themes/soft/report.scss | 4 +- rocky/assets/css/themes/soft/soft.scss | 8 +- .../css/vendor_overrides/manon/tile.scss | 4 +- rocky/components/modal/style.scss | 26 ++++-- .../templates/partials/plugin_tile.html | 22 +++-- .../templates/partials/plugin_tile_modal.html | 88 +++++++++++++++++++ rocky/rocky/locale/django.pot | 29 ++++-- 18 files changed, 244 insertions(+), 36 deletions(-) create mode 100644 rocky/assets/css/components/state-tag.scss rename rocky/assets/css/themes/soft/{manon => fundamentals}/body-text-set.scss (64%) create mode 100644 rocky/assets/css/themes/soft/fundamentals/border-radii.scss rename rocky/assets/css/themes/soft/{colors => fundamentals}/colors.scss (100%) rename rocky/assets/css/themes/soft/{colors => fundamentals}/tag-colors.scss (100%) rename rocky/assets/css/themes/soft/{colors => fundamentals}/tags-6-3.scss (100%) create mode 100644 rocky/katalogus/templates/partials/plugin_tile_modal.html diff --git a/rocky/assets/css/components/scan-level-indicator.scss b/rocky/assets/css/components/scan-level-indicator.scss index 68d83626466..8ed2015ee64 100644 --- a/rocky/assets/css/components/scan-level-indicator.scss +++ b/rocky/assets/css/components/scan-level-indicator.scss @@ -14,7 +14,7 @@ Markup: display: flex; flex-direction: row; line-height: 1rem; - gap: 0.25rem; + gap: var(--spacing-grid-100); background-color: transparent; padding: 0; @@ -27,26 +27,32 @@ Markup: padding: 0; &::before { - content: "\e900"; - font-family: kat-icons; - color: #cccccc; - font-size: 1rem; + content: "\eff9"; + font-family: tabler-icons; + color: var(--colors-grey-500); + font-size: 1.5rem; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } } &.l1 li:first-child::before { + content: "\f689"; color: var(--colors-purrple-500); } &.l2 li:nth-child(-n + 2)::before { + content: "\f689"; color: var(--colors-purrple-600); } &.l3 li:nth-child(-n + 3)::before { + content: "\f689"; color: var(--colors-purrple-700); } &.l4 li:nth-child(-n + 4)::before { + content: "\f689"; color: var(--colors-purrple-800); } diff --git a/rocky/assets/css/components/state-tag.scss b/rocky/assets/css/components/state-tag.scss new file mode 100644 index 00000000000..5dc71c413d7 --- /dev/null +++ b/rocky/assets/css/components/state-tag.scss @@ -0,0 +1,22 @@ +/* State tag */ + +.state-tag { + border: 0; + padding: var(--spacing-grid-050) var(--spacing-grid-100); + border-radius: var(--border-radius-s); + box-sizing: border-box; + font-size: var(--body-text-small-font-size); + line-height: var(--body-text-small-line-height); + font-weight: bold; + + &.enabled { + background-color: var(--colors-green-200); + color: var(--colors-green-700); + } + + &.disabled { + background-color: var(--colors-red-150); + color: var(--colors-red-700); + opacity: 1; + } +} diff --git a/rocky/assets/css/main.scss b/rocky/assets/css/main.scss index d03d64c7ccf..2a5cf8a1238 100644 --- a/rocky/assets/css/main.scss +++ b/rocky/assets/css/main.scss @@ -57,6 +57,7 @@ @import "components/risk-level-indicator"; @import "components/scan-level-indicator"; @import "components/select"; +@import "components/state-tag"; @import "components/stepper"; @import "components/sticky"; @import "components/state-tags"; diff --git a/rocky/assets/css/themes/soft/manon/body-text-set.scss b/rocky/assets/css/themes/soft/fundamentals/body-text-set.scss similarity index 64% rename from rocky/assets/css/themes/soft/manon/body-text-set.scss rename to rocky/assets/css/themes/soft/fundamentals/body-text-set.scss index ee0127dfb59..cf1d9a3769b 100644 --- a/rocky/assets/css/themes/soft/manon/body-text-set.scss +++ b/rocky/assets/css/themes/soft/fundamentals/body-text-set.scss @@ -36,3 +36,27 @@ /* Strong */ --body-text-small-strong-font-weight: var(--text-set-strong-font-weight); } + +.body-text-large { + font-size: var(--body-text-large-font-size); + font-weight: var(--body-text-large-font-weight); + line-height: var(--body-text-large-line-height); + color: var(--body-text-large-color); + text-align: var(--body-text-large-text-align); +} + +.body-text-normal { + font-size: var(--body-text-normal-font-size); + font-weight: var(--body-text-normal-font-weight); + line-height: var(--body-text-normal-line-height); + color: var(--body-text-normal-color); + text-align: var(--body-text-normal-text-align); +} + +.body-text-small { + font-size: var(--body-text-small-font-size); + font-weight: var(--body-text-small-font-weight); + line-height: var(--body-text-small-line-height); + color: var(--body-text-small-color); + text-align: var(--body-text-small-text-align); +} diff --git a/rocky/assets/css/themes/soft/fundamentals/border-radii.scss b/rocky/assets/css/themes/soft/fundamentals/border-radii.scss new file mode 100644 index 00000000000..6ca1b1c20b7 --- /dev/null +++ b/rocky/assets/css/themes/soft/fundamentals/border-radii.scss @@ -0,0 +1,24 @@ +/* Theme border radius */ + +:root { + --border-radius-s: 0.25rem; + --border-radius-m: 0.5rem; + --border-radius-l: 1.5rem; + --border-radius-round: 50%; +} + +.border-radius-s { + border-radius: var(--border-radius-s); +} + +.border-radius-m { + border-radius: var(--border-radius-m); +} + +.border-radius-l { + border-radius: var(--border-radius-l); +} + +.border-radius-round { + border-radius: var(--border-radius-round); +} diff --git a/rocky/assets/css/themes/soft/colors/colors.scss b/rocky/assets/css/themes/soft/fundamentals/colors.scss similarity index 100% rename from rocky/assets/css/themes/soft/colors/colors.scss rename to rocky/assets/css/themes/soft/fundamentals/colors.scss diff --git a/rocky/assets/css/themes/soft/colors/tag-colors.scss b/rocky/assets/css/themes/soft/fundamentals/tag-colors.scss similarity index 100% rename from rocky/assets/css/themes/soft/colors/tag-colors.scss rename to rocky/assets/css/themes/soft/fundamentals/tag-colors.scss diff --git a/rocky/assets/css/themes/soft/colors/tags-6-3.scss b/rocky/assets/css/themes/soft/fundamentals/tags-6-3.scss similarity index 100% rename from rocky/assets/css/themes/soft/colors/tags-6-3.scss rename to rocky/assets/css/themes/soft/fundamentals/tags-6-3.scss diff --git a/rocky/assets/css/themes/soft/manon/application-base.scss b/rocky/assets/css/themes/soft/manon/application-base.scss index acd11bbc456..3a0f7329d2c 100644 --- a/rocky/assets/css/themes/soft/manon/application-base.scss +++ b/rocky/assets/css/themes/soft/manon/application-base.scss @@ -9,8 +9,6 @@ --application-base-text-color: var(--text-color-dark); /* Accent color */ - --application-base-accent-color: var(--branding-color-1); - --application-base-accent-color-text-color: var( - --branding-color-1-text-color - ); + --application-base-accent-color: var(--colors-purrple-100); + --application-base-accent-color-text-color: var(--text-color-dark); } diff --git a/rocky/assets/css/themes/soft/manon/breadcrumb-bar.scss b/rocky/assets/css/themes/soft/manon/breadcrumb-bar.scss index 3e1ee94ae88..f45485f5314 100644 --- a/rocky/assets/css/themes/soft/manon/breadcrumb-bar.scss +++ b/rocky/assets/css/themes/soft/manon/breadcrumb-bar.scss @@ -4,8 +4,8 @@ /* Breadcrumb bar nav */ --breadcrumb-bar-padding-right: 0; --breadcrumb-bar-padding-left: 0; - --breadcrumb-bar-background-color: var(--branding-color-1-background-color); - --breadcrumb-bar-text-color: var(--branding-color-1-text-color); + --breadcrumb-bar-background-color: var(--colors-purrple-100); + --breadcrumb-bar-text-color: var(--text-color-dark); /* Content wrapper */ --breadcrumb-bar-content-block-max-width: var(--header-navigation-max-width); diff --git a/rocky/assets/css/themes/soft/manon/de-emphasized.scss b/rocky/assets/css/themes/soft/manon/de-emphasized.scss index 976c36fa7e9..abafd425e9a 100644 --- a/rocky/assets/css/themes/soft/manon/de-emphasized.scss +++ b/rocky/assets/css/themes/soft/manon/de-emphasized.scss @@ -1,6 +1,6 @@ /* De-emphasized - Variables */ :root { - --de-emphasized-text-color: var(--colors-grey-11); + --de-emphasized-text-color: var(--colors-grey-900); --de-emphasized-font-weight: 700; } diff --git a/rocky/assets/css/themes/soft/report.scss b/rocky/assets/css/themes/soft/report.scss index 54734a29af9..93ea2a9d7f5 100644 --- a/rocky/assets/css/themes/soft/report.scss +++ b/rocky/assets/css/themes/soft/report.scss @@ -4,8 +4,8 @@ @import "fonts/fonts"; /* Styling sets. E.g color sets */ -@import "colors/colors"; -@import "manon/body-text-set"; +@import "fundamentals/colors"; +@import "fundamentals/body-text-set"; /* Branding colors */ @import "manon/headings-base-set"; diff --git a/rocky/assets/css/themes/soft/soft.scss b/rocky/assets/css/themes/soft/soft.scss index ca54f20bc61..204b5a949c7 100644 --- a/rocky/assets/css/themes/soft/soft.scss +++ b/rocky/assets/css/themes/soft/soft.scss @@ -4,9 +4,11 @@ @import "fonts/fonts"; /* Styling sets. E.g color sets */ -@import "colors/colors"; -@import "colors/tag-colors"; -@import "manon/body-text-set"; +@import "fundamentals/body-text-set"; +@import "fundamentals/border-radii"; +@import "fundamentals/colors"; +@import "fundamentals/tag-colors"; +@import "fundamentals/tags-6-3"; @import "manon/spot-large"; @import "manon/headings-base-set"; @import "manon/text-colors"; diff --git a/rocky/assets/css/vendor_overrides/manon/tile.scss b/rocky/assets/css/vendor_overrides/manon/tile.scss index 981b443f5dc..d5a653201a7 100644 --- a/rocky/assets/css/vendor_overrides/manon/tile.scss +++ b/rocky/assets/css/vendor_overrides/manon/tile.scss @@ -61,8 +61,8 @@ ul.tiles { } .label-plugin-type { - padding: 4px 8px; - border-radius: 4px; + padding: var(--spacing-grid-050) var(--spacing-grid-100); + border-radius: var(--border-radius-s); &.boefje { background-color: $boefje-plugin-type-label-background; diff --git a/rocky/components/modal/style.scss b/rocky/components/modal/style.scss index 30d55050990..2ff1c050f94 100644 --- a/rocky/components/modal/style.scss +++ b/rocky/components/modal/style.scss @@ -1,5 +1,5 @@ dialog { - border: 1px solid var(--colors-grey-4); + border: 1px solid var(--colors-grey-200); border-radius: 8px; max-height: calc(100vh - 3rem); padding: 0; @@ -21,7 +21,7 @@ dialog { } &.dialog-medium { - width: 50rem; + width: 40rem; } &.dialog-large { @@ -37,18 +37,20 @@ dialog { flex-direction: column; max-height: inherit; position: relative; + gap: 0; .header { - padding: 1.5rem; + padding: var(--spacing-grid-300); display: flex; justify-content: space-between; flex-direction: row; - border-bottom: 1px solid var(--colors-grey-4); + border-bottom: 1px solid var(--colors-grey-200); position: sticky; background-color: white; top: 0; left: 0; right: 0; + gap: var(--spacing-grid-400); button { margin-right: -1.5rem; @@ -60,19 +62,29 @@ dialog { } .content { - padding: 1.5rem; + padding: var(--spacing-grid-400) var(--spacing-grid-300); flex-grow: 1; overflow: auto; + gap: var(--spacing-grid-400); + + > section { + gap: var(--spacing-grid-300); + + > div { + gap: var(--spacing-grid-100); + } + } } .footer { - padding: 1.5rem; - border-top: 1px solid var(--colors-grey-4); + padding: var(--spacing-grid-300); + border-top: 1px solid var(--colors-grey-200); position: sticky; background-color: white; bottom: 0; left: 0; right: 0; + gap: var(--spacing-grid-400); .toolbar { justify-content: flex-start; diff --git a/rocky/katalogus/templates/partials/plugin_tile.html b/rocky/katalogus/templates/partials/plugin_tile.html index a45e5cad7d6..543b9980421 100644 --- a/rocky/katalogus/templates/partials/plugin_tile.html +++ b/rocky/katalogus/templates/partials/plugin_tile.html @@ -1,5 +1,7 @@ {% load i18n %} {% load static %} +{% load compress %} +{% load component_tags %}
{% include "partials/enable_disable_plugin.html" with plugin=plugin %} - {% if plugin.type == "boefje" %} - {% translate "See details" %} + {% if show_report_types %} + {% include "partials/plugin_tile_modal.html" with plugin=plugin %} + {% else %} - {% translate "See details" %} + {% if plugin.type == "boefje" %} + {% translate "See details" %} + {% else %} + {% translate "See details" %} + {% endif %} {% endif %}
{% endif %} {% endif %}
+{% block html_at_end_body %} + {% compress js %} + + {% endcompress %} +{% endblock html_at_end_body %} diff --git a/rocky/katalogus/templates/partials/plugin_tile_modal.html b/rocky/katalogus/templates/partials/plugin_tile_modal.html new file mode 100644 index 00000000000..51479c5c035 --- /dev/null +++ b/rocky/katalogus/templates/partials/plugin_tile_modal.html @@ -0,0 +1,88 @@ +{% load i18n %} + +{% component "modal" size="dialog-medium" %} +{% fill "trigger" %} +{% translate "See details" %} +{% endfill %} +{% fill "header" %} +{% translate "Boefje details" %} +{% endfill %} +{% fill "content" %} +
+
+ +
+

{{ plugin.name }}

+ {% if plugin.enabled %} + {% translate "Enabled" %} + {% else %} + {% translate "Disabled" %} + {% endif %} +
+

{{ plugin.description }}

+
+
+ +
+ +

{% translate "Scan level" %}

+ {% if plugin.type == "boefje" %} +
+
    + {% for i in "1234"|make_list %}
  • {% endfor %} +
+
+ {% endif %} +
+ {% comment %} TODO: Implement Matching objects {% endcomment %} + {% comment %}
+ +

{% translate "Matching objects" %}

+
{% endcomment %} +
+
+
+
+ +

{% translate "Report types" %}

+

{% translate "This boefje is required by the following report types." %}

+

+ {% for plugin_id, report_types in plugin_report_types.items %} + {% if plugin_id == plugin.id %} + {% for report_type in report_types %} + {{ report_type.name }} + {% endfor %} + {% endif %} + {% endfor %} +

+
+
+
+ {% comment %} TODO: Implement consumable object types {% endcomment %} + {% comment %}
+ + {% if plugin.consumes %} +

{% translate "Consumes" %}

+
{% endcomment %} +
+ +

{% translate "Produces" %}

+

+ {% blocktranslate trimmed with plugin_name=plugin.name %} + {{ plugin_name }} can produce the following output: + {% endblocktranslate %} +

+

+

    + {% for mime_type in plugin.produces %}
  • {{ mime_type }}
  • {% endfor %} +
+

+
+
+{% endfill %} +{% fill "footer_buttons" %} +{% translate "Go to boefje detail page" %} +{% endfill %} +{% endcomponent %} +{% component_css_dependencies %} diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 1faac03bc93..2680e5a9d65 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-07 13:24+0000\n" +"POT-Creation-Date: 2024-08-20 07:53+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -604,11 +604,13 @@ msgid "Show all" msgstr "" #: katalogus/forms/katalogus_filter.py +#: katalogus/templates/partials/plugin_tile_modal.html #: reports/report_types/dns_report/report.html msgid "Enabled" msgstr "" #: katalogus/forms/katalogus_filter.py +#: katalogus/templates/partials/plugin_tile_modal.html msgid "Disabled" msgstr "" @@ -664,6 +666,7 @@ msgid "" msgstr "" #: katalogus/templates/boefje_detail.html +#: katalogus/templates/partials/plugin_tile_modal.html msgid "Scan level" msgstr "" @@ -697,11 +700,13 @@ msgstr "" #: katalogus/templates/boefje_detail.html #: katalogus/templates/normalizer_detail.html +#: katalogus/templates/partials/plugin_tile_modal.html msgid "Produces" msgstr "" #: katalogus/templates/boefje_detail.html #: katalogus/templates/normalizer_detail.html +#: katalogus/templates/partials/plugin_tile_modal.html #, python-format msgid "%(plugin_name)s can produce the following output:" msgstr "" @@ -853,6 +858,7 @@ msgstr "" #: katalogus/templates/partials/boefje_tile.html #: katalogus/templates/partials/plugin_tile.html +#: katalogus/templates/partials/plugin_tile_modal.html #: katalogus/templates/partials/plugins.html msgid "See details" msgstr "" @@ -973,6 +979,23 @@ msgstr "" msgid "Required for:" msgstr "" +#: katalogus/templates/partials/plugin_tile_modal.html +msgid "Boefje details" +msgstr "" + +#: katalogus/templates/partials/plugin_tile_modal.html reports/forms.py +#: reports/templates/report_overview/report_history_table.html +msgid "Report types" +msgstr "" + +#: katalogus/templates/partials/plugin_tile_modal.html +msgid "This boefje is required by the following report types." +msgstr "" + +#: katalogus/templates/partials/plugin_tile_modal.html +msgid "Go to boefje detail page" +msgstr "" + #: katalogus/templates/partials/plugins.html msgid "Plugins overview:" msgstr "" @@ -2121,10 +2144,6 @@ msgstr "" msgid "Filter by OOI types" msgstr "" -#: reports/forms.py reports/templates/report_overview/report_history_table.html -msgid "Report types" -msgstr "" - #: reports/report_types/aggregate_organisation_report/appendix.html #: reports/report_types/multi_organization_report/appendix.html #: reports/templates/partials/report_sidemenu.html From 929b44326887d5ded90f1f444b67e7f9e9570237 Mon Sep 17 00:00:00 2001 From: JP Bruins Slot Date: Thu, 22 Aug 2024 20:13:54 +0200 Subject: [PATCH 073/112] Add create schedule functionality to scheduler api (#3353) Co-authored-by: ammar92 --- mula/docs/openapi.json | 297 +++++++----------- mula/scheduler/models/schedule.py | 7 +- mula/scheduler/server/handlers/schedules.py | 97 +++++- mula/scheduler/server/serializers/__init__.py | 2 +- mula/scheduler/server/serializers/schedule.py | 12 +- mula/scheduler/server/server.py | 2 +- mula/scheduler/storage/schedule_store.py | 2 +- mula/tests/integration/test_api.py | 98 +++++- mula/tests/integration/test_schedule_store.py | 43 +++ 9 files changed, 367 insertions(+), 193 deletions(-) diff --git a/mula/docs/openapi.json b/mula/docs/openapi.json index 94069a59f99..107b273283e 100644 --- a/mula/docs/openapi.json +++ b/mula/docs/openapi.json @@ -307,7 +307,7 @@ "get": { "summary": "List", "description": "List all schedules", - "operationId": "list_schedules_post", + "operationId": "list_schedules_get", "parameters": [ { "name": "schedule_hash", @@ -338,7 +338,6 @@ "type": "null" } ], - "default": true, "title": "Enabled" } }, @@ -455,139 +454,26 @@ } }, "post": { - "summary": "List", - "description": "List all schedules", - "operationId": "list_schedules_post", - "parameters": [ - { - "name": "schedule_hash", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Schedule Hash" - } - }, - { - "name": "enabled", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": true, - "title": "Enabled" - } - }, - { - "name": "offset", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "default": 0, - "title": "Offset" - } - }, - { - "name": "limit", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "default": 10, - "title": "Limit" - } - }, - { - "name": "min_deadline_at", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Min Deadline At" - } - }, - { - "name": "max_deadline_at", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Max Deadline At" - } - }, - { - "name": "min_created_at", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Min Created At" - } - }, - { - "name": "max_created_at", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Max Created At" + "summary": "Create", + "description": "Create a schedule", + "operationId": "create_schedules_post", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScheduleCreate" + } } } - ], + }, "responses": { - "200": { + "201": { "description": "Successful Response", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PaginatedResponse" + "$ref": "#/components/schemas/Schedule" } } } @@ -628,7 +514,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Schedule-Output" + "$ref": "#/components/schemas/Schedule" } } } @@ -666,7 +552,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Schedule-Input" + "$ref": "#/components/schemas/SchedulePatch" } } } @@ -677,7 +563,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Schedule-Output" + "$ref": "#/components/schemas/Schedule" } } } @@ -1446,6 +1332,13 @@ }, "type": "array" }, + { + "items": { + "type": "string", + "format": "date-time" + }, + "type": "array" + }, { "items": { "type": "null" @@ -1611,8 +1504,17 @@ ], "title": "Queue" }, - "Schedule-Input": { + "Schedule": { "properties": { + "id": { + "type": "string", + "format": "uuid", + "title": "Id" + }, + "scheduler_id": { + "type": "string", + "title": "Scheduler Id" + }, "hash": { "anyOf": [ { @@ -1634,18 +1536,10 @@ "type": "null" } ], - "title": "Data", - "default": {} + "title": "Data" }, "enabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], + "type": "boolean", "title": "Enabled", "default": true }, @@ -1660,6 +1554,14 @@ ], "title": "Schedule" }, + "tasks": { + "items": { + "$ref": "#/components/schemas/Task-Output" + }, + "type": "array", + "title": "Tasks", + "default": [] + }, "deadline_at": { "anyOf": [ { @@ -1671,22 +1573,49 @@ } ], "title": "Deadline At" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At" + }, + "modified_at": { + "type": "string", + "format": "date-time", + "title": "Modified At" } }, "type": "object", + "required": [ + "scheduler_id" + ], "title": "Schedule" }, - "Schedule-Output": { + "ScheduleCreate": { "properties": { - "id": { - "type": "string", - "format": "uuid", - "title": "Id" - }, "scheduler_id": { "type": "string", "title": "Scheduler Id" }, + "data": { + "type": "object", + "title": "Data" + }, + "schedule": { + "type": "string", + "title": "Schedule" + } + }, + "type": "object", + "required": [ + "scheduler_id", + "data", + "schedule" + ], + "title": "ScheduleCreate" + }, + "SchedulePatch": { + "properties": { "hash": { "anyOf": [ { @@ -1708,13 +1637,18 @@ "type": "null" } ], - "title": "Data", - "default": {} + "title": "Data" }, "enabled": { - "type": "boolean", - "title": "Enabled", - "default": true + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Enabled" }, "schedule": { "anyOf": [ @@ -1727,14 +1661,6 @@ ], "title": "Schedule" }, - "tasks": { - "items": { - "$ref": "#/components/schemas/Task-Output" - }, - "type": "array", - "title": "Tasks", - "default": [] - }, "deadline_at": { "anyOf": [ { @@ -1746,23 +1672,10 @@ } ], "title": "Deadline At" - }, - "created_at": { - "type": "string", - "format": "date-time", - "title": "Created At" - }, - "modified_at": { - "type": "string", - "format": "date-time", - "title": "Modified At" } }, "type": "object", - "required": [ - "scheduler_id" - ], - "title": "Schedule" + "title": "SchedulePatch" }, "Scheduler": { "properties": { @@ -1910,16 +1823,28 @@ "type": "null" } ], - "title": "Priority", - "default": 0 + "title": "Priority" }, "status": { - "allOf": [ + "anyOf": [ { "$ref": "#/components/schemas/TaskStatus" + }, + { + "type": "null" + } + ] + }, + "type": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" } ], - "default": "pending" + "title": "Type" }, "hash": { "anyOf": [ @@ -2021,6 +1946,17 @@ ], "default": "pending" }, + "type": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Type" + }, "hash": { "anyOf": [ { @@ -2042,8 +1978,7 @@ "type": "null" } ], - "title": "Data", - "default": {} + "title": "Data" }, "created_at": { "type": "string", diff --git a/mula/scheduler/models/schedule.py b/mula/scheduler/models/schedule.py index 9f91e6f38df..26a8c16145a 100644 --- a/mula/scheduler/models/schedule.py +++ b/mula/scheduler/models/schedule.py @@ -34,10 +34,15 @@ class Schedule(BaseModel): created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) modified_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) + def model_post_init(self, context) -> None: + """Post init method to set the deadline_at if it is not set.""" + if self.deadline_at is None and self.schedule: + self.deadline_at = cron.next_run(self.schedule) + @field_validator("schedule") @classmethod def validate_schedule(cls, value: str) -> str: - """Validate the schedule cron expression.""" + """Custom validation for the schedule cron expression.""" if value is None: return value diff --git a/mula/scheduler/server/handlers/schedules.py b/mula/scheduler/server/handlers/schedules.py index 5b4d175386e..33bd17b5aa3 100644 --- a/mula/scheduler/server/handlers/schedules.py +++ b/mula/scheduler/server/handlers/schedules.py @@ -5,26 +5,42 @@ import fastapi import pydantic import structlog +from fastapi import status -from scheduler import context, models, storage +from scheduler import context, models, schedulers, storage from scheduler.server import serializers, utils class ScheduleAPI: - def __init__(self, api: fastapi.FastAPI, ctx: context.AppContext) -> None: - self.logger: structlog.BoundLogger = structlog.getLogger(__name__) + def __init__( + self, + api: fastapi.FastAPI, + ctx: context.AppContext, + schedulers: dict[str, schedulers.Scheduler], + ) -> None: + self.logger: structlog.BoundLogger = structlog.get_logger(__name__) self.api = api self.ctx = ctx + self.schedulers = schedulers self.api.add_api_route( path="/schedules", endpoint=self.list, - methods=["GET", "POST"], + methods=["GET"], response_model=utils.PaginatedResponse, status_code=200, description="List all schedules", ) + self.api.add_api_route( + path="/schedules", + endpoint=self.create, + methods=["POST"], + response_model=models.Schedule, + status_code=201, + description="Create a schedule", + ) + self.api.add_api_route( path="/schedules/{schedule_id}", endpoint=self.get, @@ -48,7 +64,7 @@ def list( self, request: fastapi.Request, schedule_hash: str | None = None, - enabled: bool | None = True, + enabled: bool | None = None, offset: int = 0, limit: int = 10, min_deadline_at: datetime.datetime | None = None, @@ -98,6 +114,75 @@ def list( return utils.paginate(request, results, count, offset, limit) + def create(self, schedule: serializers.ScheduleCreate) -> Any: + try: + new_schedule = models.Schedule(**schedule.dict()) + except pydantic.ValidationError as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_400_BAD_REQUEST, + detail=f"invalid schedule [exception: {exc}]", + ) from exc + except Exception as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_400_BAD_REQUEST, + detail=f"failed to create schedule [exception: {exc}]", + ) from exc + + s = self.schedulers.get(new_schedule.scheduler_id) + if s is None: + raise fastapi.HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="scheduler not found", + ) + + # Validate data with task type of the scheduler + try: + instance = s.ITEM_TYPE.model_validate(new_schedule.data) + except pydantic.ValidationError as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_400_BAD_REQUEST, + detail=f"invalid task data [exception: {exc}]", + ) from exc + + # Create hash for schedule with task type + try: + new_schedule.hash = instance.hash + except Exception as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_400_BAD_REQUEST, + detail=f"failed to create hash for schedule [exception: {exc}]", + ) from exc + + # Check if schedule with the same hash already exists + try: + schedule = self.ctx.datastores.schedule_store.get_schedule_by_hash(new_schedule.hash) + if schedule is not None: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_409_CONFLICT, + detail="schedule with the same hash already exists", + ) + except storage.errors.StorageError as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"error occurred while accessing the database [exception: {exc}]", + ) from exc + + try: + self.ctx.datastores.schedule_store.create_schedule(new_schedule) + except storage.errors.StorageError as exc: + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_400_BAD_REQUEST, + detail=f"error occurred while accessing the database [exception: {exc}]", + ) from exc + except Exception as exc: + self.logger.exception(exc) + raise fastapi.HTTPException( + status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"failed to create schedule [exception: {exc}]", + ) from exc + + return new_schedule + def get(self, schedule_id: uuid.UUID) -> Any: try: schedule = self.ctx.datastores.schedule_store.get_schedule(schedule_id) @@ -121,7 +206,7 @@ def get(self, schedule_id: uuid.UUID) -> Any: return schedule - def patch(self, schedule_id: uuid.UUID, schedule: serializers.Schedule) -> Any: + def patch(self, schedule_id: uuid.UUID, schedule: serializers.SchedulePatch) -> Any: try: schedule_db = self.ctx.datastores.schedule_store.get_schedule(schedule_id) except storage.errors.StorageError as exc: diff --git a/mula/scheduler/server/serializers/__init__.py b/mula/scheduler/server/serializers/__init__.py index 95ce4c26876..a4d3c0b20c4 100644 --- a/mula/scheduler/server/serializers/__init__.py +++ b/mula/scheduler/server/serializers/__init__.py @@ -1,2 +1,2 @@ -from .schedule import Schedule +from .schedule import ScheduleCreate, SchedulePatch from .task import Task, TaskStatus diff --git a/mula/scheduler/server/serializers/schedule.py b/mula/scheduler/server/serializers/schedule.py index f30c723c699..4333f36e672 100644 --- a/mula/scheduler/server/serializers/schedule.py +++ b/mula/scheduler/server/serializers/schedule.py @@ -3,8 +3,18 @@ from pydantic import BaseModel, ConfigDict, Field +class ScheduleCreate(BaseModel): + model_config = ConfigDict(from_attributes=True) + + scheduler_id: str + + data: dict + + schedule: str + + # NOTE: model added for support of partial updates -class Schedule(BaseModel): +class SchedulePatch(BaseModel): model_config = ConfigDict(from_attributes=True) hash: str | None = Field(None, max_length=32) diff --git a/mula/scheduler/server/server.py b/mula/scheduler/server/server.py index 414e78e7785..7178b48d3b1 100644 --- a/mula/scheduler/server/server.py +++ b/mula/scheduler/server/server.py @@ -41,7 +41,7 @@ def __init__( # Set up API endpoints handlers.SchedulerAPI(self.api, self.ctx, s) handlers.QueueAPI(self.api, self.ctx, s) - handlers.ScheduleAPI(self.api, self.ctx) + handlers.ScheduleAPI(self.api, self.ctx, s) handlers.TaskAPI(self.api, self.ctx) handlers.MetricsAPI(self.api, self.ctx) handlers.HealthAPI(self.api, self.ctx) diff --git a/mula/scheduler/storage/schedule_store.py b/mula/scheduler/storage/schedule_store.py index c7f72533d68..d26c10d5f5e 100644 --- a/mula/scheduler/storage/schedule_store.py +++ b/mula/scheduler/storage/schedule_store.py @@ -22,7 +22,7 @@ def get_schedules( self, scheduler_id: str | None = None, schedule_hash: str | None = None, - enabled: bool | None = True, + enabled: bool | None = None, min_deadline_at: datetime | None = None, max_deadline_at: datetime | None = None, min_created_at: datetime | None = None, diff --git a/mula/tests/integration/test_api.py b/mula/tests/integration/test_api.py index c73fce5ed2b..0511c200f52 100644 --- a/mula/tests/integration/test_api.py +++ b/mula/tests/integration/test_api.py @@ -6,7 +6,7 @@ from urllib.parse import quote from fastapi.testclient import TestClient -from scheduler import config, models, server, storage +from scheduler import config, models, server, storage, utils from scheduler.server import serializers from tests.factories import OrganisationFactory @@ -939,6 +939,102 @@ def test_list_schedules_min_and_max_created_at(self): self.assertEqual(1, len(response.json()["results"])) self.assertEqual(str(self.first_schedule.id), response.json()["results"][0]["id"]) + def test_post_schedule(self): + item = functions.create_item(self.scheduler.scheduler_id, 1) + response = self.client.post( + "/schedules", + json={ + "scheduler_id": item.scheduler_id, + "schedule": "*/5 * * * *", + "data": item.data, + }, + ) + self.assertEqual(201, response.status_code) + self.assertEqual(item.hash, response.json().get("hash")) + self.assertEqual(item.data, response.json().get("data")) + + # Deadline should be set to the next run of the schedule + self.assertEqual( + utils.cron.next_run("*/5 * * * *"), + # NOTE: Remove Z from the end of the string. Until 3.11 + # datetime.fromisoformat does not accept Z at the end of the string + datetime.fromisoformat(response.json().get("deadline_at")[:-1]).astimezone(timezone.utc), + ) + + def test_post_schedule_invalid_schedule(self): + item = functions.create_item(self.scheduler.scheduler_id, 1) + response = self.client.post( + "/schedules", + json={ + "scheduler_id": item.scheduler_id, + "schedule": "invalid", + "data": item.data, + }, + ) + self.assertEqual(400, response.status_code) + self.assertIn("validation error", response.json().get("detail")) + + def test_post_schedule_invalid_scheduler_id(self): + item = functions.create_item(self.scheduler.scheduler_id, 1) + response = self.client.post( + "/schedules", + json={ + "scheduler_id": "invalid", + "schedule": "*/5 * * * *", + "data": item.data, + }, + ) + self.assertEqual(404, response.status_code) + self.assertIn("scheduler not found", response.json().get("detail")) + + def test_post_schedule_invalid_data(self): + item = functions.create_item(self.scheduler.scheduler_id, 1) + response = self.client.post( + "/schedules", + json={ + "scheduler_id": item.scheduler_id, + "schedule": "*/5 * * * *", + "data": "invalid", + }, + ) + self.assertEqual(422, response.status_code) + + def test_post_schedule_invalid_data_type(self): + item = functions.create_item(self.scheduler.scheduler_id, 1) + response = self.client.post( + "/schedules", + json={ + "scheduler_id": item.scheduler_id, + "schedule": "*/5 * * * *", + "data": {"invalid": "invalid"}, + }, + ) + self.assertEqual(400, response.status_code) + self.assertIn("validation error", response.json().get("detail")) + + def test_post_schedule_hash_already_exists(self): + item = functions.create_item(self.scheduler.scheduler_id, 1) + response = self.client.post( + "/schedules", + json={ + "scheduler_id": item.scheduler_id, + "schedule": "*/5 * * * *", + "data": item.data, + }, + ) + self.assertEqual(201, response.status_code) + + response = self.client.post( + "/schedules", + json={ + "scheduler_id": item.scheduler_id, + "schedule": "*/5 * * * *", + "data": item.data, + }, + ) + self.assertEqual(409, response.status_code) + self.assertIn("schedule with the same hash already exists", response.json().get("detail")) + def test_get_schedule(self): response = self.client.get(f"/schedules/{str(self.first_schedule.id)}") self.assertEqual(200, response.status_code) diff --git a/mula/tests/integration/test_schedule_store.py b/mula/tests/integration/test_schedule_store.py index 9fa884bb61a..b58e08aa89f 100644 --- a/mula/tests/integration/test_schedule_store.py +++ b/mula/tests/integration/test_schedule_store.py @@ -1,4 +1,5 @@ import unittest +from datetime import datetime, timezone from types import SimpleNamespace from unittest import mock @@ -31,6 +32,48 @@ def tearDown(self): models.Base.metadata.drop_all(self.dbconn.engine) self.dbconn.engine.dispose() + def test_create_schedule_calculate_deadline_at(self): + """When a schedule is created, the deadline_at should be calculated.""" + schedule = models.Schedule( + scheduler_id="test_scheduler_id", + schedule="* * * * *", + data={}, + ) + + self.assertIsNotNone(schedule.deadline_at) + + def test_create_schedule_explicit_deadline_at(self): + """When a schedule is created, the deadline_at should be set if it is provided.""" + now = datetime.now(timezone.utc) + schedule = models.Schedule( + scheduler_id="test_scheduler_id", + data={}, + deadline_at=now, + ) + + self.assertEqual(schedule.deadline_at, now) + + def test_create_schedule_deadline_at_takes_precedence(self): + """When a schedule is created, the deadline_at should be set if it is provided.""" + now = datetime.now(timezone.utc) + schedule = models.Schedule( + scheduler_id="test_scheduler_id", + schedule="* * * * *", + data={}, + deadline_at=now, + ) + + self.assertEqual(schedule.deadline_at, now) + + def test_create_schedule_not_provided_schedule(self): + """When a schedule is created, the deadline_at should be None if schedule is not provided.""" + schedule = models.Schedule( + scheduler_id="test_scheduler_id", + data={}, + ) + + self.assertIsNone(schedule.deadline_at) + def test_create_schedule(self): # Arrange scheduler_id = "test_scheduler_id" From ed1b875c2f25f26df85dbe6735653eab25817ad3 Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Fri, 23 Aug 2024 10:36:49 +0200 Subject: [PATCH 074/112] Search and sorting OOIs (#3262) Co-authored-by: Jan Klopper Co-authored-by: Rieven Co-authored-by: Jeroen Dekkers --- octopoes/octopoes/api/router.py | 9 +++-- octopoes/octopoes/connector/octopoes.py | 10 +++++- octopoes/octopoes/core/service.py | 17 +++++++-- .../octopoes/repositories/ooi_repository.py | 35 ++++++++++++++++--- octopoes/tests/robot/02_list_objects.robot | 16 +++++++++ rocky/rocky/locale/django.pot | 10 +++--- .../elements/ooi_list_settings_form.html | 1 + rocky/rocky/views/mixins.py | 15 +++++++- rocky/rocky/views/ooi_list.py | 3 +- rocky/rocky/views/ooi_view.py | 2 ++ rocky/tests/objects/test_objects.py | 28 +++++++++++++++ rocky/tools/forms/ooi_form.py | 4 +++ 12 files changed, 134 insertions(+), 16 deletions(-) diff --git a/octopoes/octopoes/api/router.py b/octopoes/octopoes/api/router.py index 6e7d3971e4e..6b9c7c11ba7 100644 --- a/octopoes/octopoes/api/router.py +++ b/octopoes/octopoes/api/router.py @@ -5,7 +5,7 @@ from datetime import datetime from logging import getLogger from operator import itemgetter -from typing import Any +from typing import Any, Literal from asgiref.sync import sync_to_async from fastapi import APIRouter, Body, Depends, HTTPException, Path, Query, Request, status @@ -125,8 +125,13 @@ def list_objects( scan_profile_type: set[ScanProfileType] = Query(DEFAULT_SCAN_PROFILE_TYPE_FILTER), offset: int = 0, limit: int = 20, + search_string: str | None = None, + order_by: Literal["scan_level", "object_type"] = "object_type", + asc_desc: Literal["asc", "desc"] = "asc", ): - return octopoes.list_ooi(types, valid_time, offset, limit, scan_level, scan_profile_type) + return octopoes.list_ooi( + types, valid_time, offset, limit, scan_level, scan_profile_type, search_string, order_by, asc_desc + ) @router.get("/query", tags=["Objects"]) diff --git a/octopoes/octopoes/connector/octopoes.py b/octopoes/octopoes/connector/octopoes.py index ba319df63b3..9751fc3563c 100644 --- a/octopoes/octopoes/connector/octopoes.py +++ b/octopoes/octopoes/connector/octopoes.py @@ -1,6 +1,7 @@ import json from collections.abc import Sequence, Set from datetime import datetime +from typing import Literal from uuid import UUID import httpx @@ -72,15 +73,22 @@ def list_objects( limit: int = DEFAULT_LIMIT, scan_level: set[ScanLevel] = DEFAULT_SCAN_LEVEL_FILTER, scan_profile_type: set[ScanProfileType] = DEFAULT_SCAN_PROFILE_TYPE_FILTER, + search_string: str | None = None, + order_by: Literal["scan_level", "object_type"] = "object_type", + asc_desc: Literal["asc", "desc"] = "asc", ) -> Paginated[OOIType]: - params: dict[str, str | int | list[str | int]] = { + params: dict[str, str | int | list[str | int] | None] = { "types": [t.__name__ for t in types], "valid_time": str(valid_time), "offset": offset, "limit": limit, "scan_level": [s.value for s in scan_level], "scan_profile_type": [s.value for s in scan_profile_type], + "search_string": search_string, + "order_by": order_by, + "asc_desc": asc_desc, } + params = {k: v for k, v in params.items() if v is not None} # filter out None values res = self.session.get(f"/{self.client}/objects", params=params) return TypeAdapter(Paginated[OOIType]).validate_json(res.content) diff --git a/octopoes/octopoes/core/service.py b/octopoes/octopoes/core/service.py index 81f8ee9355f..cc7f64e00af 100644 --- a/octopoes/octopoes/core/service.py +++ b/octopoes/octopoes/core/service.py @@ -4,7 +4,7 @@ from datetime import datetime, timezone from logging import getLogger from time import perf_counter -from typing import overload +from typing import Literal, overload from bits.definitions import get_bit_definitions from bits.runner import BitRunner @@ -131,8 +131,21 @@ def list_ooi( offset: int = DEFAULT_OFFSET, scan_levels: set[ScanLevel] = DEFAULT_SCAN_LEVEL_FILTER, scan_profile_types: set[ScanProfileType] = DEFAULT_SCAN_PROFILE_TYPE_FILTER, + search_string: str | None = None, + order_by: Literal["scan_level", "object_type"] = "object_type", + asc_desc: Literal["asc", "desc"] = "asc", ) -> Paginated[OOI]: - paginated = self.ooi_repository.list_oois(types, valid_time, limit, offset, scan_levels, scan_profile_types) + paginated = self.ooi_repository.list_oois( + types, + valid_time, + limit, + offset, + scan_levels, + scan_profile_types, + search_string, + order_by, + asc_desc, + ) self._populate_scan_profiles(paginated.items, valid_time) return paginated diff --git a/octopoes/octopoes/repositories/ooi_repository.py b/octopoes/octopoes/repositories/ooi_repository.py index e00c6e72c03..2638cd7a638 100644 --- a/octopoes/octopoes/repositories/ooi_repository.py +++ b/octopoes/octopoes/repositories/ooi_repository.py @@ -1,9 +1,10 @@ from __future__ import annotations import json +import re from collections import Counter from datetime import datetime -from typing import Any, cast +from typing import Any, Literal, cast import structlog from bits.definitions import BitDefinition @@ -95,6 +96,9 @@ def list_oois( limit: int = 20, scan_levels: set[ScanLevel] = DEFAULT_SCAN_LEVEL_FILTER, scan_profile_types: set[ScanProfileType] = DEFAULT_SCAN_PROFILE_TYPE_FILTER, + search_string: str | None = None, + order_by: Literal["scan_level", "object_type"] = "object_type", + asc_desc: Literal["asc", "desc"] = "asc", ) -> Paginated[OOI]: raise NotImplementedError @@ -201,6 +205,11 @@ def to_reference_node(self, pk_prefix: str) -> ReferenceNode | None: datamodel = Datamodel(entities=entities) +def escape_string(string): + escaped_string = re.sub(r'(["\\])', r"\\\1", string) + return escaped_string + + class XTDBOOIRepository(OOIRepository): pk_prefix = "xt/id" @@ -296,9 +305,21 @@ def list_oois( limit: int = 20, scan_levels: set[ScanLevel] = DEFAULT_SCAN_LEVEL_FILTER, scan_profile_types: set[ScanProfileType] = DEFAULT_SCAN_PROFILE_TYPE_FILTER, + search_string: str | None = None, + order_by: Literal["scan_level", "object_type"] = "object_type", + asc_desc: Literal["asc", "desc"] = "asc", ) -> Paginated[OOI]: types = to_concrete(types) + search_statement = ( + f"""[?e :xt/id ?id] + [(clojure.string/includes? ?id \"{escape_string(search_string)}\")]""" + if search_string + else "" + ) + + order_statement = f":order-by [[_{order_by} :{asc_desc}]]" + count_query = """ {{ :query {{ @@ -308,7 +329,8 @@ def list_oois( [?scan_profile :type "ScanProfile"] [?scan_profile :reference ?e] [?scan_profile :level _scan_level] - [?scan_profile :scan_profile_type _scan_profile_type]] + [?scan_profile :scan_profile_type _scan_profile_type] + {search_statement}] }} :in-args [[{object_types}], [{scan_levels}], [{scan_profile_types}]] }} @@ -316,6 +338,7 @@ def list_oois( object_types=" ".join(map(lambda t: str_val(t.get_object_type()), types)), scan_levels=" ".join([str(scan_level.value) for scan_level in scan_levels]), scan_profile_types=" ".join([str_val(scan_profile_type.value) for scan_profile_type in scan_profile_types]), + search_statement=search_statement, ) res_count = self.session.client.query(count_query, valid_time) @@ -324,13 +347,15 @@ def list_oois( data_query = """ {{ :query {{ - :find [(pull ?e [*])] + :find [(pull ?e [*]) _object_type _scan_level] :in [[_object_type ...] [_scan_level ...] [_scan_profile_type ...]] :where [[?e :object_type _object_type] [?scan_profile :type "ScanProfile"] [?scan_profile :reference ?e] [?scan_profile :level _scan_level] - [?scan_profile :scan_profile_type _scan_profile_type]] + [?scan_profile :scan_profile_type _scan_profile_type] + {search_statement}] + {order_statement} :limit {limit} :offset {offset} }} @@ -340,6 +365,8 @@ def list_oois( object_types=" ".join(map(lambda t: str_val(t.get_object_type()), types)), scan_levels=" ".join([str(scan_level.value) for scan_level in scan_levels]), scan_profile_types=" ".join([str_val(scan_profile_type.value) for scan_profile_type in scan_profile_types]), + search_statement=search_statement, + order_statement=order_statement, limit=limit, offset=offset, ) diff --git a/octopoes/tests/robot/02_list_objects.robot b/octopoes/tests/robot/02_list_objects.robot index 2fbba6435bb..2c1eed6b0f9 100644 --- a/octopoes/tests/robot/02_list_objects.robot +++ b/octopoes/tests/robot/02_list_objects.robot @@ -17,6 +17,11 @@ List Objects With Filter Await Sync Verify Object List With Filter +List Objects With SearchString + Insert Normalizer Output + Await Sync + Verify Object List With SearchString + List Random Objects With Filter Insert Normalizer Output Await Sync @@ -48,6 +53,17 @@ Get Objects With ScanLevel 0 Should Be Equal As Integers ${response.status_code} 200 RETURN ${response_data} +Verify Object List With SearchString + ${response_data} Get Objects With SearchString example.com + Should Be Equal ${response_data["count"]} ${4} + +Get Objects With SearchString example.com + ${params} Create Dictionary search_string=example.com valid_time=${VALID_TIME} + ${response} Get ${OCTOPOES_URI}/objects params=${params} + ${response_data} Set Variable ${response.json()} + Should Be Equal As Integers ${response.status_code} 200 + RETURN ${response_data} + Length Of Random Object List With Filter Should Be [Arguments] ${scan_levels} ${expected_length} ${params} Create Dictionary scan_level=${scan_levels} amount=10 valid_time=${VALID_TIME} diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 2680e5a9d65..e3ae5a7cbe5 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-20 07:53+0000\n" +"POT-Creation-Date: 2024-08-22 09:47+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -4183,6 +4183,10 @@ msgstr "" msgid "Filter by clearance type" msgstr "" +#: tools/forms/ooi_form.py tools/forms/scheduler.py +msgid "Search" +msgstr "" + #: tools/forms/scheduler.py msgid "From" msgstr "" @@ -4219,10 +4223,6 @@ msgstr "" msgid "Running" msgstr "" -#: tools/forms/scheduler.py -msgid "Search" -msgstr "" - #: tools/forms/scheduler.py msgid "Search by object name" msgstr "" diff --git a/rocky/rocky/templates/partials/elements/ooi_list_settings_form.html b/rocky/rocky/templates/partials/elements/ooi_list_settings_form.html index 0eda577994c..498ff9fefc9 100644 --- a/rocky/rocky/templates/partials/elements/ooi_list_settings_form.html +++ b/rocky/rocky/templates/partials/elements/ooi_list_settings_form.html @@ -14,6 +14,7 @@ data-toggle-target="ooi_type">{% translate "Toggle all OOI types" %} {% endif %} {% include "partials/form/fieldset.html" with fields=clearance_level_filter_form %} + {% include "partials/form/fieldset.html" with fields=ooi_search_form %}
int: @@ -223,6 +229,7 @@ def count(self) -> int: limit=0, scan_level=self.scan_level, scan_profile_type=self.scan_profile_type, + search_string=self.search_string, ).count def __len__(self): @@ -242,6 +249,9 @@ def __getitem__(self, key: int | slice) -> list[OOI]: limit=limit, scan_level=self.scan_level, scan_profile_type=self.scan_profile_type, + search_string=self.search_string, + order_by=self.order_by, + asc_desc=self.asc_desc, ).items elif isinstance(key, int): @@ -252,6 +262,9 @@ def __getitem__(self, key: int | slice) -> list[OOI]: limit=1, scan_level=self.scan_level, scan_profile_type=self.scan_profile_type, + search_string=self.search_string, + order_by=self.order_by, + asc_desc=self.asc_desc, ).items diff --git a/rocky/rocky/views/ooi_list.py b/rocky/rocky/views/ooi_list.py index 191eab8b2f4..f1e07ffe45a 100644 --- a/rocky/rocky/views/ooi_list.py +++ b/rocky/rocky/views/ooi_list.py @@ -11,7 +11,7 @@ from httpx import HTTPError from tools.enums import CUSTOM_SCAN_LEVEL from tools.forms.ooi import SelectOOIForm -from tools.forms.ooi_form import OOITypeMultiCheckboxForm +from tools.forms.ooi_form import OOISearchForm, OOITypeMultiCheckboxForm from tools.models import Indemnification from tools.view_helpers import get_mandatory_fields @@ -40,6 +40,7 @@ def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["ooi_type_form"] = OOITypeMultiCheckboxForm(self.request.GET) + context["ooi_search_form"] = OOISearchForm(self.request.GET) context["mandatory_fields"] = get_mandatory_fields(self.request, params=["observed_at"]) context["select_oois_form"] = SelectOOIForm( context.get("ooi_list", []), diff --git a/rocky/rocky/views/ooi_view.py b/rocky/rocky/views/ooi_view.py index 5722858273a..3eaca0b7845 100644 --- a/rocky/rocky/views/ooi_view.py +++ b/rocky/rocky/views/ooi_view.py @@ -37,6 +37,7 @@ def setup(self, request, *args, **kwargs): self.filtered_ooi_types = request.GET.getlist("ooi_type", []) self.clearance_levels = request.GET.getlist("clearance_level", []) self.clearance_types = request.GET.getlist("clearance_type", []) + self.search_string = request.GET.get("search", "") def get_active_filters(self) -> dict[str, str]: active_filters = {} @@ -92,6 +93,7 @@ def get_queryset(self) -> OOIList: valid_time=self.observed_at, scan_level=self.get_ooi_scan_levels(), scan_profile_type=self.get_ooi_profile_types(), + search_string=self.search_string, ) def get_context_data(self, **kwargs): diff --git a/rocky/tests/objects/test_objects.py b/rocky/tests/objects/test_objects.py index f96d927c314..2946f3629d9 100644 --- a/rocky/tests/objects/test_objects.py +++ b/rocky/tests/objects/test_objects.py @@ -9,6 +9,7 @@ from octopoes.models import ScanLevel, ScanProfileType from octopoes.models.exception import ObjectNotFoundException +from octopoes.models.ooi.dns.zone import Hostname from octopoes.models.ooi.network import Network from octopoes.models.pagination import Paginated from octopoes.models.types import OOIType @@ -72,6 +73,33 @@ def test_ooi_list_with_clearance_type_filter_and_clearance_level_filter( assertContains(response, "Showing 150 of 200 objects") +def test_ooi_list_search(rf, client_member, mock_organization_view_octopoes): + kwargs = {"organization_code": client_member.organization.code} + url = reverse("ooi_list", kwargs=kwargs) + request = rf.get( + url, + {"search": "testnetwork"}, + ) + request.resolver_match = resolve(url) + + setup_request(request, client_member.user) + + network = Network(name="testnetwork") + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=2, items=[network, Hostname(name="example.com", network=network.reference)] + ) + + response = OOIListView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 + + list_call_1 = mock_organization_view_octopoes().list_objects.call_args_list[0] + assert list_call_1.kwargs["search_string"] == "testnetwork" + + assertContains(response, "Showing 2 of 2 objects") + + def test_ooi_list_delete_multiple(rf, client_member, mock_organization_view_octopoes): kwargs = {"organization_code": client_member.organization.code} url = reverse("ooi_list", kwargs=kwargs) diff --git a/rocky/tools/forms/ooi_form.py b/rocky/tools/forms/ooi_form.py index 992edc08e96..a6ff3fad5ae 100644 --- a/rocky/tools/forms/ooi_form.py +++ b/rocky/tools/forms/ooi_form.py @@ -214,3 +214,7 @@ class OOITypeMultiCheckboxForm(BaseRockyForm): choices=OOI_TYPE_CHOICES, widget=forms.CheckboxSelectMultiple, ) + + +class OOISearchForm(BaseRockyForm): + search = forms.CharField(label=_("Search"), required=False, max_length=256, help_text="Object ID contains") From 4fa0bd9e63baeb6a879a93d8b73e9ebe17ba6be4 Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Wed, 28 Aug 2024 09:15:14 +0200 Subject: [PATCH 075/112] Generic Finding normalizer (#3383) Co-authored-by: Jan Klopper Co-authored-by: Jeroen Dekkers --- .../plugins/kat_cve_2023_34039/main.py | 3 +- .../plugins/kat_cve_2023_34039/normalize.py | 19 -------- .../kat_finding_normalizer/__init__.py | 0 .../kat_finding_normalizer/normalize.py | 38 +++++++++++++++ .../normalizer.json | 4 +- .../tests/test_generic_finding_normalizer.py | 48 +++++++++++++++++++ .../development_tutorial/creating_a_boefje.md | 2 + 7 files changed, 92 insertions(+), 22 deletions(-) delete mode 100644 boefjes/boefjes/plugins/kat_cve_2023_34039/normalize.py create mode 100644 boefjes/boefjes/plugins/kat_finding_normalizer/__init__.py create mode 100644 boefjes/boefjes/plugins/kat_finding_normalizer/normalize.py rename boefjes/boefjes/plugins/{kat_cve_2023_34039 => kat_finding_normalizer}/normalizer.json (56%) create mode 100644 boefjes/tests/test_generic_finding_normalizer.py diff --git a/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py b/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py index f6e580e1468..d5bd7f4795a 100644 --- a/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py +++ b/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py @@ -57,7 +57,8 @@ def run(boefje_meta: BoefjeMeta) -> list[tuple[set, str | bytes]]: "\n".join( (str(coutput), f"{key_file} is allowed access to vRealize Network Insight on {ip}:{port}") ), - ) + ), + ({"openkat/finding"}, "CVE-2023-34039"), ] except Exception: # noqa: S112 diff --git a/boefjes/boefjes/plugins/kat_cve_2023_34039/normalize.py b/boefjes/boefjes/plugins/kat_cve_2023_34039/normalize.py deleted file mode 100644 index b379e8158f1..00000000000 --- a/boefjes/boefjes/plugins/kat_cve_2023_34039/normalize.py +++ /dev/null @@ -1,19 +0,0 @@ -from collections.abc import Iterable - -from boefjes.job_models import NormalizerOutput -from octopoes.models import Reference -from octopoes.models.ooi.findings import CVEFindingType, Finding - - -def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: - ooi = Reference.from_str(input_ooi["primary_key"]) - - if "is allowed access to vRealize Network Insight " in raw.decode(): - finding_type = CVEFindingType(id="CVE-2023-34039") - finding = Finding( - finding_type=finding_type.reference, - ooi=ooi, - description="Service is most likely vulnerable to CVE-2023-34039", - ) - yield finding_type - yield finding diff --git a/boefjes/boefjes/plugins/kat_finding_normalizer/__init__.py b/boefjes/boefjes/plugins/kat_finding_normalizer/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/boefjes/boefjes/plugins/kat_finding_normalizer/normalize.py b/boefjes/boefjes/plugins/kat_finding_normalizer/normalize.py new file mode 100644 index 00000000000..e00cc7d08fb --- /dev/null +++ b/boefjes/boefjes/plugins/kat_finding_normalizer/normalize.py @@ -0,0 +1,38 @@ +import re +from collections.abc import Iterable + +from boefjes.job_models import NormalizerOutput +from octopoes.models import Reference +from octopoes.models.ooi.findings import CVEFindingType, Finding, KATFindingType, RetireJSFindingType, SnykFindingType + +CVE_PATTERN = re.compile(r"CVE-\d{4}-\d{4,}") + + +def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: + ooi = Reference.from_str(input_ooi["primary_key"]) + finding_ids_str = raw.decode() + finding_ids_list = [fid.strip().upper() for fid in finding_ids_str.split(",")] + + finding_type_mapping = { + "CVE": CVEFindingType, + "KAT": KATFindingType, + "SNYK": SnykFindingType, + "RETIREJS": RetireJSFindingType, + } + + for finding_id in finding_ids_list: + parts = finding_id.split("-") + prefix = parts[0] + + if prefix in finding_type_mapping: + if prefix == "CVE" and not CVE_PATTERN.match(finding_id): + raise ValueError(f"{finding_id} is not a valid CVE ID") + + finding_type = finding_type_mapping[prefix](id=finding_id) + finding = Finding( + finding_type=finding_type.reference, + ooi=ooi, + description=f"{finding_id} is found on this OOI", + ) + yield finding_type + yield finding diff --git a/boefjes/boefjes/plugins/kat_cve_2023_34039/normalizer.json b/boefjes/boefjes/plugins/kat_finding_normalizer/normalizer.json similarity index 56% rename from boefjes/boefjes/plugins/kat_cve_2023_34039/normalizer.json rename to boefjes/boefjes/plugins/kat_finding_normalizer/normalizer.json index 4cbb1bddda9..ec7e54b209c 100644 --- a/boefjes/boefjes/plugins/kat_cve_2023_34039/normalizer.json +++ b/boefjes/boefjes/plugins/kat_finding_normalizer/normalizer.json @@ -1,7 +1,7 @@ { - "id": "kat_cve_2023_normalize", + "id": "kat_generic_finding_normalize", "consumes": [ - "boefje/CVE-2023-34039" + "openkat/finding" ], "produces": [ "Finding", diff --git a/boefjes/tests/test_generic_finding_normalizer.py b/boefjes/tests/test_generic_finding_normalizer.py new file mode 100644 index 00000000000..9e8da108984 --- /dev/null +++ b/boefjes/tests/test_generic_finding_normalizer.py @@ -0,0 +1,48 @@ +from unittest import TestCase + +from boefjes.plugins.kat_finding_normalizer.normalize import run +from octopoes.models import Reference +from octopoes.models.ooi.findings import KATFindingType +from octopoes.models.types import CVEFindingType, Finding + + +class CVETest(TestCase): + maxDiff = None + + def test_single(self): + input_ooi = {"primary_key": "Network|internet"} + + oois = list(run(input_ooi, b"CVE-2021-00000")) + + expected = [ + CVEFindingType(id="CVE-2021-00000"), + Finding( + finding_type=CVEFindingType(id="CVE-2021-00000").reference, + ooi=Reference.from_str("Network|internet"), + description="CVE-2021-00000 is found on this OOI", + ), + ] + + self.assertEqual(expected, oois) + + def test_multiple(self): + input_ooi = {"primary_key": "Network|internet"} + + oois = list(run(input_ooi, b"CVE-2021-00000, KAT-MOCK-FINDING")) + + expected = [ + CVEFindingType(id="CVE-2021-00000"), + Finding( + finding_type=CVEFindingType(id="CVE-2021-00000").reference, + ooi=Reference.from_str("Network|internet"), + description="CVE-2021-00000 is found on this OOI", + ), + KATFindingType(id="KAT-MOCK-FINDING"), + Finding( + finding_type=KATFindingType(id="KAT-MOCK-FINDING").reference, + ooi=Reference.from_str("Network|internet"), + description="KAT-MOCK-FINDING is found on this OOI", + ), + ] + + self.assertEqual(expected, oois) diff --git a/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md b/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md index 719c885c7de..dbb2f3bdc70 100644 --- a/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md +++ b/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md @@ -126,6 +126,8 @@ def run(boefje_meta: dict) -> list[tuple[set, bytes | str]]: The most important part is the return value we send back. This is what will be used by our normalizer to create our new OOIs. +For ease of development, we added a generic finding normalizer. When we just want to create a CVE or other type of finding on the input OOI, we can return the CVE ID or KAT ID as a string with `openkat/finding` as mime-type. + --- The final task of creating a boefje is specifying what DockerFile our boefje should use. We can do this inside the file located in `boefjes/Makefile`. From 75a171f1e70bef911979fc0220d369d60d0178e7 Mon Sep 17 00:00:00 2001 From: zcrt <115991818+zcrt@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:09:20 +0200 Subject: [PATCH 076/112] feat: :chart_with_upwards_trend: default katalogus view to boefje (#3394) Co-authored-by: ammar92 Co-authored-by: Jan Klopper --- .../templates/partials/plugins_navigation.html | 6 +++--- rocky/katalogus/urls.py | 2 +- rocky/rocky/locale/django.pot | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/rocky/katalogus/templates/partials/plugins_navigation.html b/rocky/katalogus/templates/partials/plugins_navigation.html index 05a2ba9f403..bd35aeb0adb 100644 --- a/rocky/katalogus/templates/partials/plugins_navigation.html +++ b/rocky/katalogus/templates/partials/plugins_navigation.html @@ -3,15 +3,15 @@
+ {% endif %} +
{% block html_at_end_body %} {% compress js %} - {% endcompress %} {% endblock html_at_end_body %} diff --git a/rocky/reports/views/aggregate_report.py b/rocky/reports/views/aggregate_report.py index 2b7c82a37e3..623905542ba 100644 --- a/rocky/reports/views/aggregate_report.py +++ b/rocky/reports/views/aggregate_report.py @@ -190,7 +190,9 @@ class SaveAggregateReportView(SaveAggregateReportMixin, BreadcrumbsAggregateRepo def post(self, request, *args, **kwargs): old_report_names = request.POST.getlist("old_report_name") new_report_names = request.POST.getlist("report_name") - report_names = list(zip(old_report_names, new_report_names)) + reference_dates = request.POST.getlist("reference_date") + + report_names = list(zip(old_report_names, self.finalise_report_names(new_report_names, reference_dates))) report_ooi = self.save_report(report_names) return redirect( diff --git a/rocky/reports/views/base.py b/rocky/reports/views/base.py index cf6e720bff6..f84e12c15c0 100644 --- a/rocky/reports/views/base.py +++ b/rocky/reports/views/base.py @@ -329,6 +329,25 @@ def get_plugin_data(self): return plugin_data + @staticmethod + def finalise_report_names(report_names: list[str], reference_dates: list[str]) -> list[str]: + final_report_names = [] + + if len(report_names) == len(reference_dates): + for index, report_name in enumerate(report_names): + date_format = "" + if reference_dates[index] and reference_dates[index] != "": + date_format = " - " + if reference_dates[index] == "week": + date_format += _("Week %W, %Y") + else: + date_format += reference_dates[index] + final_report_name = f"{report_name} {date_format}".strip() + final_report_names.append(final_report_name) + if not final_report_names: + return report_names + return final_report_names + def save_report_raw(self, data: dict) -> str: report_data_raw_id = self.bytes_client.upload_raw( raw=ReportDataDict(data).model_dump_json().encode(), @@ -350,7 +369,7 @@ def save_report_ooi( if not name or name.isspace(): name = report_type.name report_ooi = ReportOOI( - name=name, + name=str(name), report_type=str(report_type.id), template=report_type.template_path, report_id=uuid4(), diff --git a/rocky/reports/views/generate_report.py b/rocky/reports/views/generate_report.py index 7a6bb11d2fd..cfd37c4ad05 100644 --- a/rocky/reports/views/generate_report.py +++ b/rocky/reports/views/generate_report.py @@ -2,6 +2,7 @@ from typing import Any from django.contrib import messages +from django.core.exceptions import SuspiciousOperation from django.http import HttpRequest, HttpResponse from django.shortcuts import redirect from django.urls import reverse @@ -170,15 +171,20 @@ class SaveGenerateReportView(SaveGenerateReportMixin, BreadcrumbsGenerateReportV def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: old_report_names = request.POST.getlist("old_report_name") - new_report_names = request.POST.getlist("report_name") - report_names = list(zip(old_report_names, new_report_names)) - report_ooi = self.save_report(report_names) - - return redirect( - reverse("view_report", kwargs={"organization_code": self.organization.code}) - + "?" - + urlencode({"report_id": report_ooi.reference}) - ) + report_names = request.POST.getlist("report_name") + reference_dates = request.POST.getlist("reference_date") + + if "" in report_names: + raise SuspiciousOperation(_("Empty name should not be possible.")) + else: + final_report_names = list(zip(old_report_names, self.finalise_report_names(report_names, reference_dates))) + report_ooi = self.save_report(final_report_names) + + return redirect( + reverse("view_report", kwargs={"organization_code": self.organization.code}) + + "?" + + urlencode({"report_id": report_ooi.reference}) + ) def create_report_names(oois_pk, report_types) -> dict[str, str]: diff --git a/rocky/reports/views/mixins.py b/rocky/reports/views/mixins.py index 99a8e5f37bf..cd72d658690 100644 --- a/rocky/reports/views/mixins.py +++ b/rocky/reports/views/mixins.py @@ -1,3 +1,4 @@ +from datetime import datetime from typing import Any from django.contrib import messages @@ -57,6 +58,7 @@ def save_report(self, report_names: list) -> ReportOOI: number_of_reports += 1 observed_at = self.get_observed_at() + now = datetime.utcnow() # if its not a single report, we need a parent if number_of_reports > 1: @@ -68,18 +70,19 @@ def save_report(self, report_names: list) -> ReportOOI: parent=None, has_parent=False, observed_at=observed_at, - name=report_names[0][1], + name=now.strftime(report_names[0][1]), ) + for report_type, ooi_data in report_data.items(): for ooi, data in ooi_data.items(): + name_to_save = "" + report_type_name = str(get_report_by_id(report_type).name) ooi_name = Reference.from_str(ooi).human_readable for default_name, updated_name in report_names: + # Use default_name to check if we're on the right index in the list to update the name to save. if ooi_name in default_name and report_type_name in default_name: - name = updated_name - break - else: - name = default_name + name_to_save = updated_name break raw_id = self.save_report_raw(data={"report_data": data["data"]}) @@ -91,7 +94,7 @@ def save_report(self, report_names: list) -> ReportOOI: parent=report_ooi.reference, has_parent=True, observed_at=observed_at, - name=name, + name=now.strftime(name_to_save), ) # if its a single report we can just save it as complete else: @@ -108,7 +111,7 @@ def save_report(self, report_names: list) -> ReportOOI: parent=None, has_parent=False, observed_at=observed_at, - name=report_names[0][1], + name=now.strftime(report_names[0][1]), ) # If OOI could not be found or the date is incorrect, it will be shown to the user as a message error if error_reports: @@ -171,6 +174,8 @@ def save_report(self, report_names: list) -> ReportOOI: } ) + now = datetime.utcnow() + # Create the report report_data_raw_id = self.save_report_raw(data=post_processed_data) report_ooi = self.save_report_ooi( @@ -180,7 +185,7 @@ def save_report(self, report_names: list) -> ReportOOI: parent=None, has_parent=False, observed_at=observed_at, - name=report_names[0][1], + name=now.strftime(report_names[0][1]), ) # Save the child reports to bytes diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 12e9687e218..a3916d88b23 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-27 13:18+0000\n" +"POT-Creation-Date: 2024-08-28 08:22+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -575,7 +575,6 @@ msgstr "" #: katalogus/templates/change_clearance_level.html #: katalogus/templates/confirmation_clone_settings.html #: katalogus/templates/plugin_settings_delete.html -#: reports/templates/partials/export_report_settings.html #: rocky/templates/oois/ooi_delete.html #: rocky/templates/oois/ooi_mute_finding.html #: rocky/templates/organizations/organization_edit.html @@ -631,7 +630,6 @@ msgid "Sorting options" msgstr "" #: katalogus/forms/plugin_settings.py -#: reports/templates/partials/export_report_settings.html msgid "This field is required." msgstr "" @@ -3379,7 +3377,11 @@ msgid "Report name" msgstr "" #: reports/templates/partials/export_report_settings.html -msgid "You can name individual reports." +msgid "" +"Give your report a custom name and optionally add the reports' reference " +"date to the name. To do so you can select a standard option or use a Python strftime code in " +"the report name." msgstr "" #: reports/templates/partials/export_report_settings.html @@ -3387,21 +3389,7 @@ msgid "Report names:" msgstr "" #: reports/templates/partials/export_report_settings.html -msgid "Edit " -msgstr "" - -#: reports/templates/partials/export_report_settings.html -msgid "" -"\n" -" Give your report " -"a custom name and optionally add the reports' reference date\n" -" to the name. To " -"do so you can select an option below.\n" -" " -msgstr "" - -#: reports/templates/partials/export_report_settings.html -msgid "Report name settings." +msgid "(Required)" msgstr "" #: reports/templates/partials/export_report_settings.html @@ -3409,7 +3397,8 @@ msgid "Add reference date" msgstr "" #: reports/templates/partials/export_report_settings.html -msgid "Select option" +#: rocky/views/scan_profile.py +msgid "Reset" msgstr "" #: reports/templates/partials/export_report_settings.html @@ -3432,10 +3421,6 @@ msgstr "" msgid "Year" msgstr "" -#: reports/templates/partials/export_report_settings.html -msgid "Confirm" -msgstr "" - #: reports/templates/partials/export_report_settings.html #: reports/templates/report_overview/report_overview_header.html #: reports/views/generate_report.py @@ -3946,6 +3931,14 @@ msgstr "" msgid "Report type '%s' does not exist." msgstr "" +#: reports/views/base.py +msgid "Week %W, %Y" +msgstr "" + +#: reports/views/generate_report.py +msgid "Empty name should not be possible." +msgstr "" + #: reports/views/generate_report.py #, python-brace-format msgid "Concatenated Report for {oois_count} objects" @@ -6698,10 +6691,6 @@ msgstr "" msgid "Can not reset scan level. Scan level of {ooi_name} not declared" msgstr "" -#: rocky/views/scan_profile.py -msgid "Reset" -msgstr "" - #: rocky/views/scheduler.py msgid "" "Your task is scheduled and will soon be started in the background. Results " From 77f868f9c28880d6f5d873bfe1e177b467d05ef3 Mon Sep 17 00:00:00 2001 From: HeleenSG Date: Wed, 28 Aug 2024 11:00:47 +0200 Subject: [PATCH 079/112] =?UTF-8?q?Styling=20fixes=20within=20filters,=20h?= =?UTF-8?q?ierarchy=20fix=20on=20organisation=20members=20b=E2=80=A6=20(#3?= =?UTF-8?q?322)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rieven Co-authored-by: Jan Klopper Co-authored-by: ammar92 Co-authored-by: Jeroen Dekkers --- .../css/themes/soft/manon/accordion.scss | 2 +- .../assets/css/themes/soft/manon/button.scss | 6 +- .../assets/css/themes/soft/manon/filter.scss | 50 +++++++++++++- rocky/assets/css/themes/soft/manon/form.scss | 6 +- .../css/themes/soft/manon/login-meta.scss | 2 +- .../css/themes/soft/manon/navigation.scss | 2 +- .../css/themes/soft/manon/sidemenu.scss | 6 +- rocky/assets/css/themes/soft/manon/table.scss | 2 +- .../templates/partials/katalogus_filter.html | 15 +++-- rocky/katalogus/views/katalogus.py | 8 +++ rocky/package.json | 3 +- .../templates/partials/report_ooi_list.html | 9 +-- rocky/rocky/locale/django.pot | 66 ++++++++++--------- .../templates/crisis_room/crisis_room.html | 2 +- .../templates/findings/finding_list.html | 2 +- .../templates/findings/findings_filter.html | 20 +++--- rocky/rocky/templates/oois/ooi_list.html | 10 +-- rocky/rocky/templates/oois/ooi_tree.html | 4 +- .../organization_crisis_room.html | 2 +- .../organization_member_list.html | 9 ++- .../elements/ooi_list_settings_form.html | 2 +- .../templates/partials/form/fieldset.html | 2 +- .../templates/partials/list_filters.html | 4 -- .../templates/partials/ooi_list_filters.html | 21 +++--- .../organization_member_list_filters.html | 20 +++--- .../templates/tasks/partials/task_filter.html | 8 ++- rocky/rocky/views/finding_list.py | 10 ++- rocky/rocky/views/ooi_tree.py | 12 +++- rocky/rocky/views/ooi_view.py | 19 ++++-- rocky/rocky/views/scheduler.py | 14 +++- rocky/rocky/views/tasks.py | 1 + rocky/tests/test_crisis_room.py | 10 +-- 32 files changed, 228 insertions(+), 121 deletions(-) diff --git a/rocky/assets/css/themes/soft/manon/accordion.scss b/rocky/assets/css/themes/soft/manon/accordion.scss index f621b8da4b3..fc77c6afbd0 100644 --- a/rocky/assets/css/themes/soft/manon/accordion.scss +++ b/rocky/assets/css/themes/soft/manon/accordion.scss @@ -33,7 +33,7 @@ --accordion-content-gap: 1.5rem; --accordion-content-border-width: 0 0 1px 0; --accordion-content-background-color: var(--colors-white); - --accordion-content-text-color: var(--colors-black); + --accordion-content-text-color: var(--application-base-text-color); --accordion-content-padding: 1.5rem 2rem 2rem 2rem; } diff --git a/rocky/assets/css/themes/soft/manon/button.scss b/rocky/assets/css/themes/soft/manon/button.scss index 8cc1d37ea2b..93c3c716d21 100644 --- a/rocky/assets/css/themes/soft/manon/button.scss +++ b/rocky/assets/css/themes/soft/manon/button.scss @@ -27,18 +27,18 @@ /* Hover */ --button-base-hover-background-color: var(--colors-yellow-300); - --button-base-hover-text-color: var(--colors-black); + --button-base-hover-text-color: var(--application-base-text-color); /* Active */ --button-base-active-background-color: var(--colors-yellow-300); - --button-base-active-text-color: var(--colors-black); + --button-base-active-text-color: var(--application-base-text-color); --button-base-active-border-style: var(--button-base-border-style); --button-base-active-border-color: var(--button-base-active-background-color); --button-base-active-border-width: var(--button-base-border-width); /* Focus */ --button-base-focus-background-color: var(--colors-yellow-300); - --button-base-focus-text-color: var(--colors-black); + --button-base-focus-text-color: var(--application-base-text-color); --button-base-focus-border-style: var(--button-base-border-style); --button-base-focus-border-color: var(--button-base-focus-background-color); --button-base-focus-border-width: var(--button-base-border-width); diff --git a/rocky/assets/css/themes/soft/manon/filter.scss b/rocky/assets/css/themes/soft/manon/filter.scss index f0022e419e5..cc7c320b7b0 100644 --- a/rocky/assets/css/themes/soft/manon/filter.scss +++ b/rocky/assets/css/themes/soft/manon/filter.scss @@ -1,10 +1,54 @@ /* Filter - Variables */ :root { + /* Intro */ + --filter-intro-border-width: 1px 0 0 0; + + /* Button */ --filter-button-font-size: 1rem; - --filter-button-font-weight: normal; - --filter-button-text-color: var(--application-base-accent-color-text-color); - --filter-intro-text-color: var(--application-base-text-color); + --filter-button-font-weight: bold; + --filter-button-text-color: var(--link-text-color); + --filter-button-margin-left: 0; + --filter-button-padding: var(--spacing-grid-150) var(--spacing-grid-100); + + /* Button icon */ --filter-button-icon-before-open-content: "\ea5f"; --filter-button-icon-before-close-content: "\ea62"; } + +.filter form { + background-color: transparent; + padding: 1.5rem 2rem 2rem; + border-bottom: 1px solid var(--colors-grey-200); +} + +/* Temporary fix, this needs to be updated after this issue has been solved in Manon */ +.filter > div button { + &::before, + &::after { + font-family: var(--filter-button-icon-font-family, inherit); + line-height: var(--filter-button-icon-line-height); + font-size: var(--filter-button-icon-font-size, inherit); + font-weight: var(--filter-button-icon-font-weight, inherit); + } + + &[aria-expanded="true"] { + &::before { + content: var(--filter-button-icon-before-close-content); + } + + &::after { + content: var(--filter-button-icon-after-close-content); + } + } + + &[aria-expanded="false"] { + &::before { + content: var(--filter-button-icon-before-open-content); + } + + &::after { + content: var(--filter-button-icon-after-open-content); + } + } +} diff --git a/rocky/assets/css/themes/soft/manon/form.scss b/rocky/assets/css/themes/soft/manon/form.scss index 26bbd7eb2d2..cdfbe4649f3 100644 --- a/rocky/assets/css/themes/soft/manon/form.scss +++ b/rocky/assets/css/themes/soft/manon/form.scss @@ -1,11 +1,13 @@ /* Form - Variables */ :root { + --form-base-text-color: var(--application-base-text-color); + /* Accent color */ --form-accent-color-color: var(--branding-color-2); /* Input */ - --form-base-input-text-color: var(--colors-black); + --form-base-input-text-color: var(--form-base-text-color); --form-input-border-width: 1px; --form-input-border-style: solid; --form-input-border-color: var(--colors-grey-200); @@ -16,7 +18,7 @@ --form-help-button-icon-font-family: var(--icon-font-family); /* Textarea */ - --form-textarea-text-color: var(--form-base-input-text-color); + --form-textarea-text-color: var(--form-base-text-color); --form-textarea-border-color: var(--colors-grey-200); /* Fieldset */ diff --git a/rocky/assets/css/themes/soft/manon/login-meta.scss b/rocky/assets/css/themes/soft/manon/login-meta.scss index 07fc5b6a0ed..9a4bf2e7026 100644 --- a/rocky/assets/css/themes/soft/manon/login-meta.scss +++ b/rocky/assets/css/themes/soft/manon/login-meta.scss @@ -2,5 +2,5 @@ :root { --login-meta-background-color: var(--colors-grey-100); - --login-meta-color: var(--colors-black); + --login-meta-color: var(--application-base-text-color); } diff --git a/rocky/assets/css/themes/soft/manon/navigation.scss b/rocky/assets/css/themes/soft/manon/navigation.scss index 8ee2227eb94..9b6ebc63e51 100644 --- a/rocky/assets/css/themes/soft/manon/navigation.scss +++ b/rocky/assets/css/themes/soft/manon/navigation.scss @@ -15,7 +15,7 @@ /* Collapsing menu */ --navigation-collapsible-menu-collapsing-menu-width: 100%; --navigation-collapsible-menu-list-item-collapsed-hover-background-color: var( - --colors-black + --application-base-text-color ); /* Collapsing menu item */ diff --git a/rocky/assets/css/themes/soft/manon/sidemenu.scss b/rocky/assets/css/themes/soft/manon/sidemenu.scss index a8a6b719872..c8a9c36558e 100644 --- a/rocky/assets/css/themes/soft/manon/sidemenu.scss +++ b/rocky/assets/css/themes/soft/manon/sidemenu.scss @@ -67,7 +67,7 @@ main.sidemenu { a:visited, a:focus, a:active { - color: var(--colors-black); + color: var(--application-base-text-color); text-decoration: none; } @@ -76,7 +76,7 @@ main.sidemenu { a:visited, a:focus, a:active { - color: var(--colors-black); + color: var(--application-base-text-color); text-decoration: none; font-style: italic; word-break: break-all; @@ -112,7 +112,7 @@ main.sidemenu { font-size: var(--sidemenu-toggle-button-font-size); border: 0; border-radius: 0; - color: var(--colors-black); + color: var(--application-base-text-color); /* Transition */ transition: margin-left 1s; diff --git a/rocky/assets/css/themes/soft/manon/table.scss b/rocky/assets/css/themes/soft/manon/table.scss index 850fab9beaa..c186d4cb9e3 100644 --- a/rocky/assets/css/themes/soft/manon/table.scss +++ b/rocky/assets/css/themes/soft/manon/table.scss @@ -50,7 +50,7 @@ a:visited, a:focus, a:hover { - color: var(--colors-black); + color: var(--application-base-text-color); text-decoration: none; } } diff --git a/rocky/katalogus/templates/partials/katalogus_filter.html b/rocky/katalogus/templates/partials/katalogus_filter.html index 6659197e6aa..935ecc39c4a 100644 --- a/rocky/katalogus/templates/partials/katalogus_filter.html +++ b/rocky/katalogus/templates/partials/katalogus_filter.html @@ -1,8 +1,15 @@ -{% extends "partials/list_filters.html" %} - {% load i18n %} -{% block filter_form %} +
+
+ +
{% include "partials/form/fieldset.html" with fields=form %} @@ -11,4 +18,4 @@ {% translate "Clear filter" %}
-{% endblock filter_form %} + diff --git a/rocky/katalogus/views/katalogus.py b/rocky/katalogus/views/katalogus.py index e63748b49a2..f40a3e9e7aa 100644 --- a/rocky/katalogus/views/katalogus.py +++ b/rocky/katalogus/views/katalogus.py @@ -52,10 +52,18 @@ def sort_queryset(self, queryset, sort_options): def sort_alphabetic_ascending(self, queryset): return sorted(queryset, key=lambda item: item.name.lower()) + def count_active_filters(self): + filter_options = self.request.GET.get("filter_options") + sortin_options = self.request.GET.get("sorting_options") + count_filter_options = 1 if filter_options and filter_options != "all" else 0 + count_sorting_options = 1 if sortin_options and sortin_options != "a-z" else 0 + return count_filter_options + count_sorting_options + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["view_type"] = self.kwargs.get("view_type", "grid") context["url_name"] = self.request.resolver_match.url_name + context["active_filters_counter"] = self.count_active_filters() context["breadcrumbs"] = [ { "url": reverse("katalogus", kwargs={"organization_code": self.organization.code}), diff --git a/rocky/package.json b/rocky/package.json index a9c7a0543fa..e1597de7b38 100644 --- a/rocky/package.json +++ b/rocky/package.json @@ -16,5 +16,6 @@ }, "browserslist": [ "last 1 Chrome version" - ] + ], + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/rocky/reports/templates/partials/report_ooi_list.html b/rocky/reports/templates/partials/report_ooi_list.html index 66b1fef5572..255f8d41b3b 100644 --- a/rocky/reports/templates/partials/report_ooi_list.html +++ b/rocky/reports/templates/partials/report_ooi_list.html @@ -11,15 +11,8 @@

{% endblocktranslate %}

{% translate "Select which objects you want to include in your report." %}

- {% translate "Filter" as filter_title %} - {% include "partials/ooi_list_filters.html" with title=filter_title clearance_level_filter_form=clearance_level_filter_form %} + {% include "partials/ooi_list_filters.html" %} -

- {% if active_filters %} - {% translate "Currently filtered on:" %} - {% for filter, value in active_filters.items %}{{ filter }}{{ value|title }} {% endfor %} - {% endif %} -

{% if not ooi_list %}

{% translate "No objects found." %}

diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index a3916d88b23..3bf00674a16 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-28 08:22+0000\n" +"POT-Creation-Date: 2024-08-28 08:40+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -874,6 +874,30 @@ msgstr "" msgid "You don't have permission to enable" msgstr "" +#: katalogus/templates/partials/katalogus_filter.html +#: rocky/templates/findings/findings_filter.html +#: rocky/templates/partials/ooi_list_filters.html +#: rocky/templates/partials/organization_member_list_filters.html +#: rocky/templates/tasks/partials/task_filter.html +msgid "Hide filters" +msgstr "" + +#: katalogus/templates/partials/katalogus_filter.html +#: rocky/templates/findings/findings_filter.html +#: rocky/templates/partials/ooi_list_filters.html +#: rocky/templates/partials/organization_member_list_filters.html +#: rocky/templates/tasks/partials/task_filter.html +msgid "Show filters" +msgstr "" + +#: katalogus/templates/partials/katalogus_filter.html +#: rocky/templates/findings/findings_filter.html +#: rocky/templates/partials/ooi_list_filters.html +#: rocky/templates/partials/organization_member_list_filters.html +#: rocky/templates/tasks/partials/task_filter.html +msgid "applied" +msgstr "" + #: katalogus/templates/partials/katalogus_filter.html msgid "Filter plugins" msgstr "" @@ -3513,17 +3537,6 @@ msgstr[1] "" msgid "Select which objects you want to include in your report." msgstr "" -#: reports/templates/partials/report_ooi_list.html -#: rocky/templates/admin/change_list.html rocky/templates/oois/ooi_list.html -#: rocky/templates/tasks/partials/task_filter.html -msgid "Filter" -msgstr "" - -#: reports/templates/partials/report_ooi_list.html -#: rocky/templates/oois/ooi_list.html -msgid "Currently filtered on:" -msgstr "" - #: reports/templates/partials/report_ooi_list.html msgid "No objects found." msgstr "" @@ -4380,7 +4393,6 @@ msgstr "" #: tools/view_helpers.py rocky/templates/header.html #: rocky/templates/organizations/organization_list.html #: rocky/templates/organizations/organization_member_list.html -#: rocky/templates/partials/organization_member_list_filters.html #: rocky/views/organization_member_edit.py msgid "Members" msgstr "" @@ -4613,6 +4625,10 @@ msgid_plural "Please correct the errors below." msgstr[0] "" msgstr[1] "" +#: rocky/templates/admin/change_list.html +msgid "Filter" +msgstr "" + #: rocky/templates/admin/change_list.html msgid "Hide counts" msgstr "" @@ -4935,7 +4951,9 @@ msgstr "" msgid "OpenKAT logo, go to the homepage of OpenKAT" msgstr "" -#: rocky/templates/header.html rocky/views/finding_list.py +#: rocky/templates/header.html +#: rocky/templates/organizations/organization_crisis_room.html +#: rocky/views/finding_list.py msgid "Crisis room" msgstr "" @@ -5402,14 +5420,6 @@ msgstr "" msgid "shows the same objects." msgstr "" -#: rocky/templates/oois/ooi_tree.html -msgid "Object tree" -msgstr "" - -#: rocky/templates/organizations/organization_crisis_room.html -msgid "Crisis room:" -msgstr "" - #: rocky/templates/organizations/organization_crisis_room.html #: rocky/templates/organizations/organization_settings.html msgid "indemnification warning" @@ -6142,14 +6152,6 @@ msgstr "" msgid "Download task data" msgstr "" -#: rocky/templates/tasks/partials/task_filter.html -msgid "Hide filters" -msgstr "" - -#: rocky/templates/tasks/partials/task_filter.html -msgid "Show filters" -msgstr "" - #: rocky/templates/two_factor/_wizard_actions.html msgid "Log in" msgstr "" @@ -6559,6 +6561,10 @@ msgstr "" msgid "Graph Visualisation" msgstr "" +#: rocky/views/ooi_view.py +msgid "Observed_at: " +msgstr "" + #: rocky/views/ooi_view.py msgid "OOI types: " msgstr "" diff --git a/rocky/rocky/templates/crisis_room/crisis_room.html b/rocky/rocky/templates/crisis_room/crisis_room.html index 2924b864ba5..f08a8efcccf 100644 --- a/rocky/rocky/templates/crisis_room/crisis_room.html +++ b/rocky/rocky/templates/crisis_room/crisis_room.html @@ -9,7 +9,7 @@
-

{% translate "Crisis Room" %}

+

{% translate "Crisis Room" %} @ {{ observed_at|date:'M d, Y' }}

{% translate "An overview of all (critical) findings OpenKAT found. Check the detail section for additional severity information." %}

diff --git a/rocky/rocky/templates/findings/finding_list.html b/rocky/rocky/templates/findings/finding_list.html index d9c5c47e65d..a23d6eb82b0 100644 --- a/rocky/rocky/templates/findings/finding_list.html +++ b/rocky/rocky/templates/findings/finding_list.html @@ -11,7 +11,7 @@
-

{% translate "Findings @ " %}{{ valid_time|date }}

+

{% translate "Findings @ " %}{{ observed_at|date }}

{% blocktranslate trimmed with organization.name as organization_name %} An overview of all findings OpenKAT found for organization {{ organization_name }}. diff --git a/rocky/rocky/templates/findings/findings_filter.html b/rocky/rocky/templates/findings/findings_filter.html index 599ad8dc3ed..971d3f373ba 100644 --- a/rocky/rocky/templates/findings/findings_filter.html +++ b/rocky/rocky/templates/findings/findings_filter.html @@ -1,13 +1,15 @@ -{% extends "partials/list_filters.html" %} - -{% load static %} {% load i18n %} -{% block title %} - {% if count %}{{ count }}{% endif %} - {{ title }} -{% endblock title %} -{% block filter_form %} +

+
+ +
{% include "partials/form/fieldset.html" with fields=observed_at_form %} @@ -22,4 +24,4 @@ {% translate "Clear filters" %}
-{% endblock filter_form %} +
diff --git a/rocky/rocky/templates/oois/ooi_list.html b/rocky/rocky/templates/oois/ooi_list.html index ac30802eb0b..17f316dba27 100644 --- a/rocky/rocky/templates/oois/ooi_list.html +++ b/rocky/rocky/templates/oois/ooi_list.html @@ -23,16 +23,8 @@

{% endblocktranslate %}

{% include "partials/ooi_list_toolbar.html" %} + {% include "partials/ooi_list_filters.html" %} - {% translate "Filter" as filter_title %} - {% include "partials/ooi_list_filters.html" with title=filter_title clearance_level_filter_form=clearance_level_filter_form %} - -

- {% if active_filters %} - {% translate "Currently filtered on:" %} - {% for filter, value in active_filters.items %}{{ filter }}{{ value|title }} {% endfor %} - {% endif %} -

{% blocktranslate with length=ooi_list|length total=total_oois %}Showing {{ length }} of {{ total }} objects{% endblocktranslate %}

diff --git a/rocky/rocky/templates/oois/ooi_tree.html b/rocky/rocky/templates/oois/ooi_tree.html index 191ca596590..eceed2a3dfd 100644 --- a/rocky/rocky/templates/oois/ooi_tree.html +++ b/rocky/rocky/templates/oois/ooi_tree.html @@ -11,9 +11,7 @@
{% include "partials/ooi_head.html" with ooi=ooi view="ooi_tree" %} - - {% translate "Object tree" as filter_title %} - {% include "partials/ooi_list_filters.html" with title=filter_title ooi_id=ooi.primary_key %} + {% include "partials/ooi_list_filters.html" with ooi_id=ooi.primary_key %} {% if tree_view == "table" %} {% include "partials/elements/ooi_tree_table.html" with list=tree ooi_id=ooi.primary_key %} diff --git a/rocky/rocky/templates/organizations/organization_crisis_room.html b/rocky/rocky/templates/organizations/organization_crisis_room.html index a38cb5e2e5e..9cd0d3e6ee9 100644 --- a/rocky/rocky/templates/organizations/organization_crisis_room.html +++ b/rocky/rocky/templates/organizations/organization_crisis_room.html @@ -9,7 +9,7 @@
-

{% translate "Crisis room:" %} {{ organization.name }}

+

{% translate "Crisis room" %} {{ organization.name }} @ {{ observed_at|date:'M d, Y' }}

{% if not indemnification_present %}

{% translate "Organization:" %} {{ organization.name }}

{% blocktranslate with organization_name=organization.name %} An overview of "{{ organization_name }}" its members. {% endblocktranslate %} -

{% translate "Members" %}

+

+ {% translate "Members" %} + {% if members.count %} + ({{ members.count }}) + {% else %} + (0) + {% endif %} +

{% if perms.tools.add_organizationmember %}
diff --git a/rocky/rocky/templates/tasks/partials/task_filter.html b/rocky/rocky/templates/tasks/partials/task_filter.html index 92b34d69a09..221c24f414e 100644 --- a/rocky/rocky/templates/tasks/partials/task_filter.html +++ b/rocky/rocky/templates/tasks/partials/task_filter.html @@ -2,9 +2,13 @@
-

{% translate "Filter" %}

+ data-hide-filters-label='{% translate "Hide filters" %}'> + {% translate "Show filters" %} + {% if active_filters_counter > 0 %} + ({{ active_filters_counter }} {% translate "applied" %}) + {% endif %} +
{% include "partials/form/fieldset.html" with fields=task_filter_form %} diff --git a/rocky/rocky/views/finding_list.py b/rocky/rocky/views/finding_list.py index 9b0430d2f7c..9f4e9ea2dc6 100644 --- a/rocky/rocky/views/finding_list.py +++ b/rocky/rocky/views/finding_list.py @@ -1,4 +1,5 @@ from collections.abc import Iterable +from datetime import datetime, timezone from typing import Any import structlog @@ -60,6 +61,12 @@ def setup(self, request, *args, **kwargs): self.exclude_muted = self.muted_findings == "non-muted" self.only_muted = self.muted_findings == "muted" + def count_observed_at_filter(self) -> int: + return 1 if datetime.now(timezone.utc).date() != self.observed_at.date() else 0 + + def count_active_filters(self): + return len(self.severities) + 1 if self.muted_findings else 0 + self.count_observed_at_filter() + def get_queryset(self) -> FindingList: return FindingList( octopoes_connector=self.octopoes_api_connector, @@ -72,10 +79,11 @@ def get_queryset(self) -> FindingList: def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["observed_at_form"] = self.get_connector_form() - context["valid_time"] = self.observed_at + context["observed_at"] = self.observed_at context["severity_filter"] = FindingSeverityMultiSelectForm({"severity": list(self.severities)}) context["muted_findings_filter"] = MutedFindingSelectionForm({"muted_findings": self.muted_findings}) context["only_muted"] = self.only_muted + context["active_filters_counter"] = self.count_active_filters() return context diff --git a/rocky/rocky/views/ooi_tree.py b/rocky/rocky/views/ooi_tree.py index e943980581d..b03151cbe5f 100644 --- a/rocky/rocky/views/ooi_tree.py +++ b/rocky/rocky/views/ooi_tree.py @@ -1,3 +1,5 @@ +from datetime import datetime, timezone + from django.utils.translation import gettext_lazy as _ from django.views.generic import TemplateView from tools.forms.ooi import OoiTreeSettingsForm @@ -18,6 +20,14 @@ def get_filtered_tree(self, tree_dict): filtered_types = self.request.GET.getlist("ooi_type", []) return filter_ooi_tree(tree_dict, filtered_types) + def count_observed_at_filter(self) -> int: + return 1 if datetime.now(timezone.utc).date() != self.observed_at.date() else 0 + + def count_active_filters(self): + count_depth_filter = len(self.request.GET.getlist("depth", [])) + count_ooi_type_filter = len(self.request.GET.getlist("ooi_type", [])) + return self.count_observed_at_filter() + count_depth_filter + count_ooi_type_filter + def get_connector_form_kwargs(self): kwargs = super().get_connector_form_kwargs() @@ -44,7 +54,7 @@ def get_context_data(self, **kwargs): context["tree"] = self.get_filtered_tree(self.get_tree_dict()) context["tree_view"] = self.request.GET.get("view", "condensed") context["observed_at_form"] = self.get_connector_form() - + context["active_filters_counter"] = self.count_active_filters() return context diff --git a/rocky/rocky/views/ooi_view.py b/rocky/rocky/views/ooi_view.py index 3eaca0b7845..55613017936 100644 --- a/rocky/rocky/views/ooi_view.py +++ b/rocky/rocky/views/ooi_view.py @@ -39,8 +39,13 @@ def setup(self, request, *args, **kwargs): self.clearance_types = request.GET.getlist("clearance_type", []) self.search_string = request.GET.get("search", "") + def count_observed_at_filter(self) -> int: + return 1 if datetime.now(timezone.utc).date() != self.observed_at.date() else 0 + def get_active_filters(self) -> dict[str, str]: active_filters = {} + if self.count_observed_at_filter() > 0: + active_filters[_("Observed_at: ")] = self.observed_at.strftime("%Y-%m-%d") if self.filtered_ooi_types: active_filters[_("OOI types: ")] = ", ".join(self.filtered_ooi_types) if self.clearance_levels: @@ -50,6 +55,14 @@ def get_active_filters(self) -> dict[str, str]: active_filters[_("Clearance type: ")] = ", ".join(self.clearance_types) return active_filters + def count_active_filters(self): + return ( + len(self.filtered_ooi_types) + + len(self.clearance_levels) + + len(self.clearance_types) + + self.count_observed_at_filter() + ) + def get_ooi_scan_levels(self) -> set[ScanLevel]: if not self.clearance_levels: return self.scan_levels @@ -69,15 +82,11 @@ def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["observed_at"] = self.observed_at context["observed_at_form"] = self.get_connector_form() - context["ooi_types_selection"] = self.filtered_ooi_types - context["clearance_levels_selection"] = self.clearance_levels context["clearance_level_filter_form"] = ClearanceFilterForm(self.request.GET) - context["clearance_types_selection"] = self.clearance_types - - context["active_filters"] = self.get_active_filters() + context["active_filters_counter"] = self.count_active_filters() return context diff --git a/rocky/rocky/views/scheduler.py b/rocky/rocky/views/scheduler.py index 4dd3898d107..1fb75f195a2 100644 --- a/rocky/rocky/views/scheduler.py +++ b/rocky/rocky/views/scheduler.py @@ -34,13 +34,23 @@ def get_task_filters(self) -> dict[str, Any]: "scheduler_id": f"{self.task_type}-{self.organization.code}", "task_type": self.task_type, "plugin_id": None, # plugin_id present and set at plugin detail - **self.get_form_data(), + **self.get_task_filter_form_data(), } - def get_form_data(self) -> dict[str, Any]: + def get_task_filter_form_data(self) -> dict[str, Any]: form_data = self.get_task_filter_form().data.dict() return {k: v for k, v in form_data.items() if v} + def count_active_task_filters(self): + form_data = self.get_task_filter_form_data() + + count = len(form_data) + for task_filter in form_data: + if task_filter in ("observed_at", "ooi_id"): + count -= 1 + + return count + def get_task_filter_form(self) -> TaskFilterForm: return self.task_filter_form(self.request.GET) diff --git a/rocky/rocky/views/tasks.py b/rocky/rocky/views/tasks.py index 8099d037496..698b1e15d7e 100644 --- a/rocky/rocky/views/tasks.py +++ b/rocky/rocky/views/tasks.py @@ -44,6 +44,7 @@ def post(self, request, *args, **kwargs): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["task_filter_form"] = self.get_task_filter_form() + context["active_filters_counter"] = self.count_active_task_filters() context["stats"] = self.get_task_statistics() context["breadcrumbs"] = [ { diff --git a/rocky/tests/test_crisis_room.py b/rocky/tests/test_crisis_room.py index ab5499e8550..fb52dcb483f 100644 --- a/rocky/tests/test_crisis_room.py +++ b/rocky/tests/test_crisis_room.py @@ -1,5 +1,3 @@ -from datetime import datetime, timezone - from crisis_room.views import CrisisRoomView, OrganizationFindingCountPerSeverity from django.urls import resolve, reverse from pytest_django.asserts import assertContains @@ -31,13 +29,17 @@ def test_crisis_room_observed_at(rf, client_member, mock_crisis_room_octopoes): request.resolver_match = resolve(reverse("crisis_room")) response = CrisisRoomView.as_view()(request) assert response.status_code == 200 - assertContains(response, "Jan 01, 2021") + assertContains(response, "Jan 01, 2021") # Next to title crisis room + assertContains(response, "2021-01-01") # Date Widget + +def test_crisis_room_observed_at_bad_format(rf, client_member, mock_crisis_room_octopoes): request = setup_request(rf.get("crisis_room", {"observed_at": "2021-bad-format"}), client_member.user) request.resolver_match = resolve(reverse("crisis_room")) response = CrisisRoomView.as_view()(request) assert response.status_code == 200 - assertContains(response, datetime.now(timezone.utc).date().strftime("%b %d, %Y")) + assertContains(response, "Can not parse date, falling back to show current date.") + assertContains(response, "Enter a valid date.") def test_org_finding_count_total(): From f21217dc86d07400c6cab317c176a1b8fdeb28ad Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:51:08 +0200 Subject: [PATCH 080/112] Use better paginator for finding list (#3407) Co-authored-by: Jan Klopper --- rocky/rocky/templates/findings/finding_list.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocky/rocky/templates/findings/finding_list.html b/rocky/rocky/templates/findings/finding_list.html index a23d6eb82b0..2e2025a2f56 100644 --- a/rocky/rocky/templates/findings/finding_list.html +++ b/rocky/rocky/templates/findings/finding_list.html @@ -130,7 +130,7 @@

{% translate "Risk score" %}

{% endif %} - {% include "partials/pagination.html" %} + {% include "partials/list_paginator.html" %}
From 9f2b02673e9cd4478b6ee8e42368fabe152444e2 Mon Sep 17 00:00:00 2001 From: zcrt <115991818+zcrt@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:59:18 +0200 Subject: [PATCH 081/112] Generic tasks view refactor (#3389) Co-authored-by: Jan Klopper Co-authored-by: Peter-Paul van Gemerden Co-authored-by: ammar92 --- rocky/assets/js/renderNormalizerOutputOOIs.js | 7 +- .../partials/single_action_form.html | 4 +- rocky/rocky/locale/django.pot | 21 ++++- rocky/rocky/scheduler.py | 84 ++++++++++++------- rocky/rocky/settings.py | 2 +- rocky/rocky/templates/header.html | 5 ++ rocky/rocky/templates/tasks/boefjes.html | 16 +++- rocky/rocky/templates/tasks/normalizers.html | 21 +++-- .../tasks/partials/tab_navigation.html | 12 ++- .../tasks/partials/task_actions.html | 19 +++-- rocky/rocky/urls.py | 10 ++- rocky/rocky/views/tasks.py | 52 +++++++++++- 12 files changed, 196 insertions(+), 57 deletions(-) diff --git a/rocky/assets/js/renderNormalizerOutputOOIs.js b/rocky/assets/js/renderNormalizerOutputOOIs.js index 1e7f71d37ea..e7d7fdcbefe 100644 --- a/rocky/assets/js/renderNormalizerOutputOOIs.js +++ b/rocky/assets/js/renderNormalizerOutputOOIs.js @@ -11,11 +11,14 @@ buttons.forEach((button) => { .closest("tr") .getAttribute("data-task-id") .replace(/-/g, ""); + const organization = + organization_code || + button.closest("tr").getAttribute("data-organization-code"); const json_url = "/" + language + "/" + - organization_code + + organization + "/tasks/normalizers/" + encodeURI(task_id); @@ -79,7 +82,7 @@ buttons.forEach((button) => { "/" + language + "/" + - escapeHTMLEntities(encodeURIComponent(organization_code)); + escapeHTMLEntities(encodeURIComponent(organization)); let object_list = ""; // set the observed at time a fews seconds into the future, as the job finish time is not the same as the ooi-creation time. Due to async reasons the object might be a bit slow. data["timestamp"] = Date.parse(data["valid_time"] + "Z"); diff --git a/rocky/katalogus/templates/partials/single_action_form.html b/rocky/katalogus/templates/partials/single_action_form.html index 7aada262413..cdcd087a872 100644 --- a/rocky/katalogus/templates/partials/single_action_form.html +++ b/rocky/katalogus/templates/partials/single_action_form.html @@ -1,4 +1,6 @@ -
+ {% csrf_token %} {% if key %}{% endif %} diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 3bf00674a16..6d1c6ed2ae2 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -4456,10 +4456,6 @@ msgstr "" msgid "Task list: " msgstr "" -#: rocky/scheduler.py -msgid "Task statistics: " -msgstr "" - #: rocky/settings.py msgid "Blue light" msgstr "" @@ -6088,12 +6084,20 @@ msgstr "" msgid "List of tasks for boefjes" msgstr "" +#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html +msgid "Organization Code" +msgstr "" + #: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html #: rocky/templates/tasks/ooi_detail_task_list.html #: rocky/templates/tasks/plugin_detail_task_list.html msgid "Created date" msgstr "" +#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html +msgid "Modified date" +msgstr "" + #: rocky/templates/tasks/normalizers.html msgid "There are no tasks for normalizers" msgstr "" @@ -6704,6 +6708,15 @@ msgid "" "refresh of the page may be needed to show the results." msgstr "" +#: rocky/views/tasks.py +#, python-brace-format +msgid "Fetching tasks failed: no connection with scheduler: {error}" +msgstr "" + +#: rocky/views/tasks.py +msgid "All Tasks" +msgstr "" + #: rocky/views/upload_csv.py msgid "" "For URL object type, a column 'raw' with URL values is required, starting " diff --git a/rocky/rocky/scheduler.py b/rocky/rocky/scheduler.py index 416aebbc648..f6c11d1cea0 100644 --- a/rocky/rocky/scheduler.py +++ b/rocky/rocky/scheduler.py @@ -1,7 +1,8 @@ from __future__ import annotations +import collections import datetime -import json +import logging import uuid from enum import Enum from functools import cached_property @@ -162,6 +163,7 @@ def __getitem__(self, key) -> list[Task]: else: raise TypeError("Invalid slice argument type.") + logging.info("Getting max %s lazy items at offset %s with filter %s", limit, offset, self.kwargs) res = self.scheduler_client.list_tasks( limit=limit, offset=offset, @@ -214,7 +216,7 @@ class SchedulerHTTPError(SchedulerError): class SchedulerClient: - def __init__(self, base_uri: str, organization_code: str): + def __init__(self, base_uri: str, organization_code: str | None): self._client = httpx.Client(base_url=base_uri) self.organization_code = organization_code @@ -223,8 +225,10 @@ def list_tasks( **kwargs, ) -> PaginatedTasksResponse: try: - kwargs = {k: v for k, v in kwargs.items() if v is not None} # filter Nones from kwargs - res = self._client.get("/tasks", params=kwargs) + filter_key = "filters" + params = {k: v for k, v in kwargs.items() if v is not None if k != filter_key} # filter Nones from kwargs + endpoint = "/tasks" + res = self._client.post(endpoint, params=params, json=kwargs.get(filter_key, None)) return PaginatedTasksResponse.model_validate_json(res.content) except ValidationError: raise SchedulerValidationError(extra_message=_("Task list: ")) @@ -232,22 +236,19 @@ def list_tasks( raise SchedulerConnectError(extra_message=_("Task list: ")) def get_task_details(self, task_id: str) -> Task: - try: - res = self._client.get(f"/tasks/{task_id}") - res.raise_for_status() - task_details = Task.model_validate_json(res.content) + if self.organization_code is None: + raise SchedulerTaskNotFound("No organization defined in client.") + task_details = Task.model_validate_json(self._get(f"/tasks/{task_id}", "content")) - if task_details.type == "normalizer": - organization = task_details.data.raw_data.boefje_meta.organization - else: - organization = task_details.data.organization + if task_details.type == "normalizer": + organization = task_details.data.raw_data.boefje_meta.organization + else: + organization = task_details.data.organization - if organization != self.organization_code: - raise SchedulerTaskNotFound() + if organization != self.organization_code: + raise SchedulerTaskNotFound() - return task_details - except ConnectError: - raise SchedulerConnectError() + return task_details def push_task(self, item: Task) -> None: try: @@ -270,24 +271,45 @@ def push_task(self, item: Task) -> None: raise SchedulerError() def health(self) -> ServiceHealth: - try: - health_endpoint = self._client.get("/health") - health_endpoint.raise_for_status() - return ServiceHealth.model_validate_json(health_endpoint.content) - except HTTPError: - raise SchedulerHTTPError() - except ConnectError: - raise SchedulerConnectError() + return ServiceHealth.model_validate_json(self._get("/health", return_type="content")) + + def _get_task_stats(self, scheduler_id: str) -> dict: + """Return task stats for specific scheduler.""" + return self._get(f"/tasks/stats/{scheduler_id}") # type: ignore def get_task_stats(self, task_type: str) -> dict: + """Return task stats for specific task type.""" + return self._get_task_stats(scheduler_id=f"{task_type}-{self.organization_code}") + + @staticmethod + def _merge_stat_dicts(dicts: list[dict]) -> dict: + """Merge multiple stats dicts.""" + stat_sum: dict[str, collections.Counter] = collections.defaultdict(collections.Counter) + for dct in dicts: + for timeslot, counts in dct.items(): + stat_sum[timeslot].update(counts) + return dict(stat_sum) + + def get_combined_schedulers_stats(self, scheduler_ids: list) -> dict: + """Return merged stats for a set of scheduler ids.""" + return SchedulerClient._merge_stat_dicts( + dicts=[self._get_task_stats(scheduler_id=scheduler_id) for scheduler_id in scheduler_ids] + ) + + def _get(self, path: str, return_type: str = "json") -> dict | bytes: + """Helper to do a get request and raise warning for path.""" try: - res = self._client.get(f"/tasks/stats/{task_type}-{self.organization_code}") + res = self._client.get(path) res.raise_for_status() - except ConnectError: - raise SchedulerConnectError(extra_message=_("Task statistics: ")) - task_stats = json.loads(res.content) - return task_stats + except HTTPError as exc: + raise SchedulerError(path) from exc + except ConnectError as exc: + raise SchedulerConnectError(path) from exc + + if return_type == "content": + return res.content + return res.json() -def scheduler_client(organization_code: str) -> SchedulerClient: +def scheduler_client(organization_code: str | None) -> SchedulerClient: return SchedulerClient(settings.SCHEDULER_API, organization_code) diff --git a/rocky/rocky/settings.py b/rocky/rocky/settings.py index 497bb9ee2c1..6040c32ca5c 100644 --- a/rocky/rocky/settings.py +++ b/rocky/rocky/settings.py @@ -78,7 +78,7 @@ "loggers": { "root": { "handlers": ["console"], - "level": "INFO", + "level": env("LOG_LEVEL", default="INFO").upper(), }, }, } diff --git a/rocky/rocky/templates/header.html b/rocky/rocky/templates/header.html index f96979c6c04..ca685e775f4 100644 --- a/rocky/rocky/templates/header.html +++ b/rocky/rocky/templates/header.html @@ -32,6 +32,11 @@ {% translate "Crisis room" %} +
  • + {% url "all_task_list" as index_url %} + {% translate "Tasks" %} +
  • {% else %}
  • {% url "organization_crisis_room" organization.code as index_url %} diff --git a/rocky/rocky/templates/tasks/boefjes.html b/rocky/rocky/templates/tasks/boefjes.html index b9a1920a992..e786c0acba9 100644 --- a/rocky/rocky/templates/tasks/boefjes.html +++ b/rocky/rocky/templates/tasks/boefjes.html @@ -25,9 +25,13 @@

    {% translate "Boefjes" %}

    + {% if not organization.code %} + + {% endif %} + @@ -35,15 +39,21 @@

    {% translate "Boefjes" %}

    {% for task in task_list %} + {% if not organization.code %} + + {% endif %} + - diff --git a/rocky/rocky/templates/tasks/normalizers.html b/rocky/rocky/templates/tasks/normalizers.html index 9062d970129..096327e328c 100644 --- a/rocky/rocky/templates/tasks/normalizers.html +++ b/rocky/rocky/templates/tasks/normalizers.html @@ -26,9 +26,13 @@

    {% translate "Normalizers" %}

    {% translate "Organization Code" %}{% translate "Boefje" %} {% translate "Status" %} {% translate "Created date" %}{% translate "Modified date" %} {% translate "Input Object" %} {% translate "Details" %}
    + {{ task.data.organization }} + - {{ task.data.boefje.name }} + {{ task.data.boefje.name }}  {{ task.status.value|capfirst }} {{ task.created_at }}{{ task.modified_at }} - {{ task.data.input_ooi }} + {{ task.data.input_ooi }}
    + {% include "tasks/partials/task_actions.html" %}
    + {% if not organization.code %} + + {% endif %} + @@ -36,19 +40,26 @@

    {% translate "Normalizers" %}

    {% for task in task_list %} - + + {% if not organization %} + + {% endif %} + - diff --git a/rocky/rocky/templates/tasks/partials/tab_navigation.html b/rocky/rocky/templates/tasks/partials/tab_navigation.html index dec34aab028..16754c651a4 100644 --- a/rocky/rocky/templates/tasks/partials/tab_navigation.html +++ b/rocky/rocky/templates/tasks/partials/tab_navigation.html @@ -3,10 +3,18 @@ diff --git a/rocky/rocky/templates/tasks/partials/task_actions.html b/rocky/rocky/templates/tasks/partials/task_actions.html index 1a894e2b364..017cf65b7fc 100644 --- a/rocky/rocky/templates/tasks/partials/task_actions.html +++ b/rocky/rocky/templates/tasks/partials/task_actions.html @@ -13,18 +13,25 @@

    {% translate "Yielded objects" %}

    {% if task.status.value in "completed,failed" %} {% if task.type == "normalizer" %} {% translate "Download meta and raw data" %} - {% include "partials/single_action_form.html" with btn_text=_("Reschedule") btn_class="ghost" btn_icon="icon ti-refresh" action="reschedule_task" key="task_id" value=task.id %} + href="{% url 'bytes_raw' organization_code=task.data.raw_data.boefje_meta.organization boefje_meta_id=task.data.raw_data.boefje_meta.id %}">{% translate "Download meta and raw data" %} + {% url 'task_list' organization_code=task.data.raw_data.boefje_meta.organization as taskurl %} + {% include "partials/single_action_form.html" with btn_text=_("Reschedule") btn_class="ghost" btn_icon="icon ti-refresh" action="reschedule_task" key="task_id" url=taskurl value=task.id %} {% elif task.type == "boefje" %} {% translate "Download meta and raw data" %} - {% include "partials/single_action_form.html" with btn_text=_("Reschedule") btn_class="ghost" btn_icon="icon ti-refresh" action="reschedule_task" key="task_id" value=task.id %} + href="{% url 'bytes_raw' organization_code=task.data.organization boefje_meta_id=task.id %}">{% translate "Download meta and raw data" %} + {% url 'task_list' organization_code=task.data.organization as taskurl %} + {% include "partials/single_action_form.html" with btn_text=_("Reschedule") btn_class="ghost" btn_icon="icon ti-refresh" action="reschedule_task" key="task_id" url=taskurl value=task.id %} {% endif %} {% else %} - {% translate "Download task data" %} + {% if task.type == "normalizer" %} + {% translate "Download task data" %} + {% elif task.type == "boefje" %} + {% translate "Download task data" %} + {% endif %} {% endif %} diff --git a/rocky/rocky/urls.py b/rocky/rocky/urls.py index bb1157c8409..1397c325969 100644 --- a/rocky/rocky/urls.py +++ b/rocky/rocky/urls.py @@ -40,7 +40,12 @@ from rocky.views.scan_profile import ScanProfileDetailView, ScanProfileResetView from rocky.views.scans import ScanListView from rocky.views.task_detail import BoefjeTaskDetailView, DownloadTaskDetail, NormalizerTaskJSONView -from rocky.views.tasks import BoefjesTaskListView, NormalizersTaskListView +from rocky.views.tasks import ( + AllBoefjesTaskListView, + AllNormalizersTaskListView, + BoefjesTaskListView, + NormalizersTaskListView, +) from rocky.views.upload_csv import UploadCSV from rocky.views.upload_raw import UploadRaw @@ -72,6 +77,9 @@ PrivacyStatementView.as_view(), name="privacy_statement", ), + path("tasks/", AllBoefjesTaskListView.as_view(), name="all_task_list"), + path("tasks/boefjes", AllBoefjesTaskListView.as_view(), name="all_boefjes_task_list"), + path("tasks/normalizers", AllNormalizersTaskListView.as_view(), name="all_normalizers_task_list"), path( "/settings/indemnifications/", IndemnificationAddView.as_view(), diff --git a/rocky/rocky/views/tasks.py b/rocky/rocky/views/tasks.py index 698b1e15d7e..3f6b9acfa3c 100644 --- a/rocky/rocky/views/tasks.py +++ b/rocky/rocky/views/tasks.py @@ -5,9 +5,10 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic.list import ListView from httpx import HTTPError +from tools.forms.scheduler import TaskFilterForm from rocky.paginator import RockyPaginator -from rocky.scheduler import SchedulerError +from rocky.scheduler import LazyTaskList, SchedulerError, scheduler_client from rocky.views.page_actions import PageActionsView from rocky.views.scheduler import SchedulerView @@ -63,3 +64,52 @@ class BoefjesTaskListView(TaskListView): class NormalizersTaskListView(TaskListView): template_name = "tasks/normalizers.html" task_type = "normalizer" + + +class AllTaskListView(SchedulerListView, PageActionsView): + paginator_class = RockyPaginator + paginate_by = 20 + context_object_name = "task_list" + client = scheduler_client(None) + task_filter_form = TaskFilterForm + + def get_queryset(self): + task_type = self.request.GET.get("type", self.task_type) + self.schedulers = [f"{task_type}-{o.code}" for o in self.request.user.organizations] + form_data = self.task_filter_form(self.request.GET).data.dict() + kwargs = {k: v for k, v in form_data.items() if v} + + try: + return LazyTaskList( + self.client, + task_type=task_type, + filters={"filters": [{"column": "scheduler_id", "operator": "in", "value": self.schedulers}]}, + **kwargs, + ) + + except HTTPError as error: + error_message = _(f"Fetching tasks failed: no connection with scheduler: {error}") + messages.add_message(self.request, messages.ERROR, error_message) + return [] + except SchedulerError as error: + messages.add_message(self.request, messages.ERROR, str(error)) + return [] + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["task_filter_form"] = self.task_filter_form(self.request.GET) + context["stats"] = self.client.get_combined_schedulers_stats(scheduler_ids=self.schedulers) + context["breadcrumbs"] = [ + {"url": reverse("all_task_list", kwargs={}), "text": _("All Tasks")}, + ] + return context + + +class AllBoefjesTaskListView(AllTaskListView): + template_name = "tasks/boefjes.html" + task_type = "boefje" + + +class AllNormalizersTaskListView(AllTaskListView): + template_name = "tasks/normalizers.html" + task_type = "normalizer" From 7a51134590709b645010a426e12f72e548e3691d Mon Sep 17 00:00:00 2001 From: zcrt <115991818+zcrt@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:04:40 +0200 Subject: [PATCH 082/112] feat: :memo: improve pagination (#3393) Co-authored-by: Jan Klopper --- rocky/katalogus/views/plugin_settings_list.py | 2 +- rocky/reports/views/report_overview.py | 4 ++-- rocky/rocky/views/finding_list.py | 2 +- rocky/rocky/views/tasks.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rocky/katalogus/views/plugin_settings_list.py b/rocky/katalogus/views/plugin_settings_list.py index 370e93a0bfc..f27b16f1d43 100644 --- a/rocky/katalogus/views/plugin_settings_list.py +++ b/rocky/katalogus/views/plugin_settings_list.py @@ -14,7 +14,7 @@ class PluginSettingsListView(SinglePluginView): """ paginator_class = RockyPaginator - paginate_by = 10 + paginate_by = 150 context_object_name = "plugin_settings" def get_plugin_settings(self) -> list[dict[str, Any]]: diff --git a/rocky/reports/views/report_overview.py b/rocky/reports/views/report_overview.py index b5f0f5cdca4..d181f3e38ff 100644 --- a/rocky/reports/views/report_overview.py +++ b/rocky/reports/views/report_overview.py @@ -30,7 +30,7 @@ class ReportHistoryView(BreadcrumbsReportOverviewView, OctopoesView, ListView): Shows all the reports that have ever been generated for the organization. """ - paginate_by = 20 + paginate_by = 30 breadcrumbs_step = 2 context_object_name = "reports" paginator = RockyPaginator @@ -53,7 +53,7 @@ class SubreportView(BreadcrumbsReportOverviewView, OctopoesView, ListView): Shows all the subreports that belong to the selected parent report. """ - paginate_by = 20 + paginate_by = 150 breadcrumbs_step = 3 context_object_name = "subreports" paginator = RockyPaginator diff --git a/rocky/rocky/views/finding_list.py b/rocky/rocky/views/finding_list.py index 9f4e9ea2dc6..480c97edba4 100644 --- a/rocky/rocky/views/finding_list.py +++ b/rocky/rocky/views/finding_list.py @@ -89,7 +89,7 @@ def get_context_data(self, **kwargs): class FindingListView(BreadcrumbsMixin, FindingListFilter): template_name = "findings/finding_list.html" - paginate_by = 20 + paginate_by = 150 def build_breadcrumbs(self): return [ diff --git a/rocky/rocky/views/tasks.py b/rocky/rocky/views/tasks.py index 3f6b9acfa3c..9194907a1a3 100644 --- a/rocky/rocky/views/tasks.py +++ b/rocky/rocky/views/tasks.py @@ -24,7 +24,7 @@ def get_context_data(self, **kwargs: Any) -> dict[str, Any]: class TaskListView(SchedulerView, SchedulerListView, PageActionsView): paginator_class = RockyPaginator - paginate_by = 20 + paginate_by = 150 context_object_name = "task_list" def get_queryset(self): From 876dded8a8ac07fcd7f0be5875fad179af3ba58e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:28:32 +0200 Subject: [PATCH 083/112] Bump myst-parser from 3.0.1 to 4.0.0 (#3346) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ammar Co-authored-by: Jan Klopper --- poetry.lock | 16 ++++++++-------- pyproject.toml | 2 +- requirements.txt | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/poetry.lock b/poetry.lock index 761ba6de69e..1733c92d963 100644 --- a/poetry.lock +++ b/poetry.lock @@ -369,22 +369,22 @@ files = [ [[package]] name = "myst-parser" -version = "3.0.1" +version = "4.0.0" description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "myst_parser-3.0.1-py3-none-any.whl", hash = "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1"}, - {file = "myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87"}, + {file = "myst_parser-4.0.0-py3-none-any.whl", hash = "sha256:b9317997552424448c6096c2558872fdb6f81d3ecb3a40ce84a7518798f3f28d"}, + {file = "myst_parser-4.0.0.tar.gz", hash = "sha256:851c9dfb44e36e56d15d05e72f02b80da21a9e0d07cba96baf5e2d476bb91531"}, ] [package.dependencies] -docutils = ">=0.18,<0.22" +docutils = ">=0.19,<0.22" jinja2 = "*" markdown-it-py = ">=3.0,<4.0" -mdit-py-plugins = ">=0.4,<1.0" +mdit-py-plugins = ">=0.4.1,<1.0" pyyaml = "*" -sphinx = ">=6,<8" +sphinx = ">=7,<9" [package.extras] code-style = ["pre-commit (>=3.0,<4.0)"] @@ -950,4 +950,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "71b725c644473a0939fa7fe7025afa25788c8926bf028a58207622d2af7677de" +content-hash = "0f799bca25a57baa2c08a56766cdd6542aadf19c96b32b4c54a05cbf8eb53538" diff --git a/pyproject.toml b/pyproject.toml index ab4e6fd3a40..9ded858460d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -103,7 +103,7 @@ python = "^3.10" sphinx = "^7.4.7" sphinx_rtd_theme = "2.0.0" sphinxcontrib-mermaid = "^0.9.2" -myst-parser = "^3.0.1" +myst-parser = "^4.0.0" settings-doc = "^4.0.1" colorama = "0.4.6" # Required on all platforms, not just win32 autodoc-pydantic = "^2.2.0" diff --git a/requirements.txt b/requirements.txt index 3c89cdbaeae..c8cfe26ac7a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -191,9 +191,9 @@ mdit-py-plugins==0.4.1 ; python_version >= "3.10" and python_version < "4.0" \ mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba -myst-parser==3.0.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1 \ - --hash=sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87 +myst-parser==4.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:851c9dfb44e36e56d15d05e72f02b80da21a9e0d07cba96baf5e2d476bb91531 \ + --hash=sha256:b9317997552424448c6096c2558872fdb6f81d3ecb3a40ce84a7518798f3f28d packaging==24.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 From c0aef69c3972cd5ceee130d827da644e635338b6 Mon Sep 17 00:00:00 2001 From: HeleenSG Date: Wed, 28 Aug 2024 18:24:18 +0200 Subject: [PATCH 084/112] Feat: Lazy loading on plugin images (#3414) Co-authored-by: Jan Klopper --- rocky/katalogus/templates/boefje_detail.html | 3 ++- rocky/katalogus/templates/normalizer_detail.html | 3 ++- rocky/katalogus/templates/partials/boefje_tile.html | 3 ++- rocky/katalogus/templates/partials/plugin_tile.html | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/rocky/katalogus/templates/boefje_detail.html b/rocky/katalogus/templates/boefje_detail.html index a6229151d6f..316262fd2bb 100644 --- a/rocky/katalogus/templates/boefje_detail.html +++ b/rocky/katalogus/templates/boefje_detail.html @@ -30,7 +30,8 @@

    {{ plugin.name }}

    - boefje placeholder image
    diff --git a/rocky/katalogus/templates/normalizer_detail.html b/rocky/katalogus/templates/normalizer_detail.html index dbb3d3cbc37..55d115d8db2 100644 --- a/rocky/katalogus/templates/normalizer_detail.html +++ b/rocky/katalogus/templates/normalizer_detail.html @@ -24,7 +24,8 @@

    {{ plugin.name }}

    - boefje placeholder image
    diff --git a/rocky/katalogus/templates/partials/boefje_tile.html b/rocky/katalogus/templates/partials/boefje_tile.html index 2eedda760df..08ad467167a 100644 --- a/rocky/katalogus/templates/partials/boefje_tile.html +++ b/rocky/katalogus/templates/partials/boefje_tile.html @@ -12,7 +12,8 @@ {% endif %} {% if widget %}{{ item|get_type_name }}{% endif %} - placeholder image for Boefje {{ item.name }} {% with scan_level=item.scan_level.value %}
    diff --git a/rocky/katalogus/templates/partials/plugin_tile.html b/rocky/katalogus/templates/partials/plugin_tile.html index 543b9980421..5110f091bbf 100644 --- a/rocky/katalogus/templates/partials/plugin_tile.html +++ b/rocky/katalogus/templates/partials/plugin_tile.html @@ -13,7 +13,8 @@ value="{{ plugin.id }}" {% if checked %}checked{% endif %} /> {% endif %} - boefje placeholder image

    {{ plugin.name }}{{ plugin.type|title }} From 28d8abd1c4c433ed1241bfa3318a06fdbe986b19 Mon Sep 17 00:00:00 2001 From: Jeroen Dekkers Date: Thu, 29 Aug 2024 13:45:50 +0200 Subject: [PATCH 085/112] Bump django-rest-framework jquery version (#3422) --- rocky/rocky/templates/rest_framework/api.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocky/rocky/templates/rest_framework/api.html b/rocky/rocky/templates/rest_framework/api.html index 47f01103893..e88d7e1043c 100644 --- a/rocky/rocky/templates/rest_framework/api.html +++ b/rocky/rocky/templates/rest_framework/api.html @@ -12,7 +12,7 @@ "csrfToken": "{% if request %}{{ csrf_token }}{% endif %}" } - + From 5dfcfa6a413202921f154c77b156cb4ab479830a Mon Sep 17 00:00:00 2001 From: Madelon Dohmen <99282220+madelondohmen@users.noreply.github.com> Date: Thu, 29 Aug 2024 13:52:35 +0200 Subject: [PATCH 086/112] Fix KAT-alogus navigation (#3415) Co-authored-by: Jan Klopper --- .../templates/partials/plugins_navigation.html | 2 +- rocky/katalogus/urls.py | 12 +++++++++--- rocky/katalogus/views/katalogus.py | 16 ++++++++++++++++ rocky/tests/katalogus/test_katalogus.py | 2 +- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/rocky/katalogus/templates/partials/plugins_navigation.html b/rocky/katalogus/templates/partials/plugins_navigation.html index bd35aeb0adb..d476968331a 100644 --- a/rocky/katalogus/templates/partials/plugins_navigation.html +++ b/rocky/katalogus/templates/partials/plugins_navigation.html @@ -10,7 +10,7 @@ {% translate "Normalizers" %}

  • - {% translate "All" %} + {% translate "All" %}
  • {% translate "About plugins" %} diff --git a/rocky/katalogus/urls.py b/rocky/katalogus/urls.py index 95c5ff69cc7..7a254ce01da 100644 --- a/rocky/katalogus/urls.py +++ b/rocky/katalogus/urls.py @@ -1,7 +1,13 @@ from django.urls import path from katalogus.views.change_clearance_level import ChangeClearanceLevel -from katalogus.views.katalogus import AboutPluginsView, BoefjeListView, KATalogusView, NormalizerListView +from katalogus.views.katalogus import ( + AboutPluginsView, + BoefjeListView, + KATalogusLandingView, + KATalogusView, + NormalizerListView, +) from katalogus.views.katalogus_settings import ConfirmCloneSettingsView, KATalogusSettingsView from katalogus.views.plugin_detail import BoefjeDetailView, NormalizerDetailView, PluginCoverImgView from katalogus.views.plugin_enable_disable import PluginEnableDisableView @@ -9,8 +15,7 @@ from katalogus.views.plugin_settings_delete import PluginSettingsDeleteView urlpatterns = [ - path("", BoefjeListView.as_view(), name="katalogus"), - path("view//", KATalogusView.as_view(), name="katalogus"), + path("", KATalogusLandingView.as_view(), name="katalogus"), path( "settings/", KATalogusSettingsView.as_view(), @@ -36,6 +41,7 @@ NormalizerListView.as_view(), name="normalizers_list", ), + path("plugins/all//", KATalogusView.as_view(), name="all_plugins_list"), path( "plugins/about-plugins/", AboutPluginsView.as_view(), diff --git a/rocky/katalogus/views/katalogus.py b/rocky/katalogus/views/katalogus.py index f40a3e9e7aa..3b6d97f5f37 100644 --- a/rocky/katalogus/views/katalogus.py +++ b/rocky/katalogus/views/katalogus.py @@ -1,6 +1,8 @@ from typing import Any from account.mixins import OrganizationView +from django.http import HttpRequest, HttpResponse +from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import gettext_lazy as _ from django.views.generic import FormView, ListView, TemplateView @@ -9,6 +11,20 @@ from katalogus.forms import KATalogusFilter +class KATalogusLandingView(OrganizationView): + """ + Landing page for KAT-alogus. + """ + + def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: + return redirect( + reverse( + "boefjes_list", + kwargs={"organization_code": self.organization.code, "view_type": self.kwargs.get("view_type", "grid")}, + ) + ) + + class BaseKATalogusView(OrganizationView, ListView, FormView): form_class = KATalogusFilter diff --git a/rocky/tests/katalogus/test_katalogus.py b/rocky/tests/katalogus/test_katalogus.py index 53cf9e612e7..c881109e143 100644 --- a/rocky/tests/katalogus/test_katalogus.py +++ b/rocky/tests/katalogus/test_katalogus.py @@ -118,7 +118,7 @@ def test_katalogus_plugin_listing_no_enable_disable_perm(rf, client_member, mock mock_requests.Client().get.return_value = mock_response mock_response.json.return_value = get_plugins_data() - request = rf.get("/en/test/kat-alogus/") + request = rf.get("/en/test/kat-alogus/plugins/all/grid/") request.resolver_match = resolve(request.path) response = KATalogusView.as_view()( setup_request(request, client_member.user), organization_code=client_member.organization.code From b0d62b91b7d93dc01d0d47f74ca55d03faf5ce22 Mon Sep 17 00:00:00 2001 From: Jeroen Dekkers Date: Thu, 29 Aug 2024 14:01:17 +0200 Subject: [PATCH 087/112] Move variables from utils.js to renderNormalizerOutputOOIs.js (#3412) Co-authored-by: Jan Klopper --- rocky/assets/js/renderNormalizerOutputOOIs.js | 4 +++- rocky/assets/js/utils.js | 5 ----- rocky/rocky/templates/tasks/normalizers.html | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/rocky/assets/js/renderNormalizerOutputOOIs.js b/rocky/assets/js/renderNormalizerOutputOOIs.js index e7d7fdcbefe..3e20cddab3f 100644 --- a/rocky/assets/js/renderNormalizerOutputOOIs.js +++ b/rocky/assets/js/renderNormalizerOutputOOIs.js @@ -1,4 +1,6 @@ -import { language, organization_code } from "./utils.js"; +const htmlElement = document.getElementsByTagName("html")[0]; +const language = htmlElement.getAttribute("lang"); +const organization_code = htmlElement.getAttribute("data-organization-code"); const buttons = document.querySelectorAll( ".expando-button.normalizer-list-table-row", diff --git a/rocky/assets/js/utils.js b/rocky/assets/js/utils.js index 225c265be1c..e69de29bb2d 100644 --- a/rocky/assets/js/utils.js +++ b/rocky/assets/js/utils.js @@ -1,5 +0,0 @@ -const htmlElement = document.getElementsByTagName("html")[0]; -const language = htmlElement.getAttribute("lang"); -const organization_code = htmlElement.getAttribute("data-organization-code"); - -export { language, organization_code }; diff --git a/rocky/rocky/templates/tasks/normalizers.html b/rocky/rocky/templates/tasks/normalizers.html index 096327e328c..340dad142de 100644 --- a/rocky/rocky/templates/tasks/normalizers.html +++ b/rocky/rocky/templates/tasks/normalizers.html @@ -93,6 +93,6 @@

    {% translate "Normalizers" %}

    {% block html_at_end_body %} {{ block.super }} {% compress js %} - + {% endcompress %} {% endblock html_at_end_body %} From e91ef99592e63ffe36d725ff186c7c05ffaa0c66 Mon Sep 17 00:00:00 2001 From: Jeroen Dekkers Date: Fri, 30 Aug 2024 09:44:50 +0200 Subject: [PATCH 088/112] Replace lru_cache with cache (#3413) Co-authored-by: ammar92 Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> --- bytes/bytes/config.py | 4 ++-- bytes/bytes/database/db.py | 4 ++-- bytes/bytes/rabbitmq.py | 4 ++-- octopoes/bits/definitions.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bytes/bytes/config.py b/bytes/bytes/config.py index 056f6fa3f39..4f9b61f1c97 100644 --- a/bytes/bytes/config.py +++ b/bytes/bytes/config.py @@ -1,6 +1,6 @@ import logging import os -from functools import lru_cache +from functools import cache from pathlib import Path from typing import Any, Literal @@ -155,7 +155,7 @@ def settings_customise_sources( return env_settings, init_settings, file_secret_settings, backwards_compatible_settings -@lru_cache +@cache def get_settings() -> Settings: return Settings() diff --git a/bytes/bytes/database/db.py b/bytes/bytes/database/db.py index 3df22afe107..922ea4ee499 100644 --- a/bytes/bytes/database/db.py +++ b/bytes/bytes/database/db.py @@ -1,4 +1,4 @@ -from functools import lru_cache +from functools import cache import structlog from sqlalchemy import create_engine @@ -10,7 +10,7 @@ SQL_BASE = declarative_base() -@lru_cache(maxsize=1) +@cache def get_engine(db_uri: str, pool_size: int) -> Engine: """Returns database engine according to config settings.""" db_uri_redacted = make_url(name_or_url=str(db_uri)).render_as_string(hide_password=True) diff --git a/bytes/bytes/rabbitmq.py b/bytes/bytes/rabbitmq.py index 75aebc4ab54..4ffa498ddd8 100644 --- a/bytes/bytes/rabbitmq.py +++ b/bytes/bytes/rabbitmq.py @@ -1,4 +1,4 @@ -from functools import lru_cache +from functools import cache import pika import pika.exceptions @@ -61,7 +61,7 @@ def publish(self, event: Event) -> None: pass -@lru_cache(maxsize=1) +@cache def create_event_manager() -> EventManager: settings = get_settings() diff --git a/octopoes/bits/definitions.py b/octopoes/bits/definitions.py index 58e82a19dcb..8c6dac010b9 100644 --- a/octopoes/bits/definitions.py +++ b/octopoes/bits/definitions.py @@ -1,6 +1,6 @@ import importlib import pkgutil -from functools import lru_cache +from functools import cache from logging import getLogger from pathlib import Path from types import ModuleType @@ -29,7 +29,7 @@ class BitDefinition(BaseModel): config_ooi_relation_path: str | None = None -@lru_cache(maxsize=32) +@cache def get_bit_definitions() -> dict[str, BitDefinition]: bit_definitions = {} From c728cac45917ae48d23a9279036266ff20beb365 Mon Sep 17 00:00:00 2001 From: Jan Klopper Date: Fri, 30 Aug 2024 13:46:49 +0200 Subject: [PATCH 089/112] Kat dns serverversion (#3291) Co-authored-by: ammar92 --- .../plugins/kat_dns_version/__init__.py | 0 .../plugins/kat_dns_version/boefje.json | 9 ++++ .../plugins/kat_dns_version/description.md | 3 ++ .../boefjes/plugins/kat_dns_version/main.py | 42 +++++++++++++++++++ .../plugins/kat_dns_version/normalize.py | 36 ++++++++++++++++ .../plugins/kat_dns_version/normalizer.json | 10 +++++ .../plugins/kat_dns_version/schema.json | 13 ++++++ boefjes/tests/integration/test_api.py | 8 ++-- 8 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 boefjes/boefjes/plugins/kat_dns_version/__init__.py create mode 100644 boefjes/boefjes/plugins/kat_dns_version/boefje.json create mode 100644 boefjes/boefjes/plugins/kat_dns_version/description.md create mode 100644 boefjes/boefjes/plugins/kat_dns_version/main.py create mode 100644 boefjes/boefjes/plugins/kat_dns_version/normalize.py create mode 100644 boefjes/boefjes/plugins/kat_dns_version/normalizer.json create mode 100644 boefjes/boefjes/plugins/kat_dns_version/schema.json diff --git a/boefjes/boefjes/plugins/kat_dns_version/__init__.py b/boefjes/boefjes/plugins/kat_dns_version/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/boefjes/boefjes/plugins/kat_dns_version/boefje.json b/boefjes/boefjes/plugins/kat_dns_version/boefje.json new file mode 100644 index 00000000000..3aa66ca3cfd --- /dev/null +++ b/boefjes/boefjes/plugins/kat_dns_version/boefje.json @@ -0,0 +1,9 @@ +{ + "id": "dns-bind-version", + "name": "DNS software version", + "description": "Uses the DNS VERSION.BIND command to attempt to learn the servers software.", + "consumes": [ + "IPService" + ], + "scan_level": 2 +} diff --git a/boefjes/boefjes/plugins/kat_dns_version/description.md b/boefjes/boefjes/plugins/kat_dns_version/description.md new file mode 100644 index 00000000000..5ac8b8ea5f2 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_dns_version/description.md @@ -0,0 +1,3 @@ +# Fetch DNS Server software version + +This boefje tries to detect the DNS Server version by doing a VERSION.BIND call. diff --git a/boefjes/boefjes/plugins/kat_dns_version/main.py b/boefjes/boefjes/plugins/kat_dns_version/main.py new file mode 100644 index 00000000000..40631e61f69 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_dns_version/main.py @@ -0,0 +1,42 @@ +"""Boefje script for getting namserver version""" + +import json +from os import getenv + +import dns +import dns.message +import dns.query + +from boefjes.job_models import BoefjeMeta + + +def run(boefje_meta: BoefjeMeta) -> list[tuple[set, str | bytes]]: + input_ = boefje_meta.arguments["input"] # input is IPService + ip_port = input_["ip_port"] + if input_["service"]["name"] != "domain": + return [({"boefje/error"}, "Not a DNS service")] + + ip = ip_port["address"]["address"] + port = int(ip_port["port"]) + protocol = ip_port["protocol"] + + timeout = float(getenv("TIMEOUT", 30)) + + method = dns.query.udp if protocol == "udp" else dns.query.tcp + + queries = [ + dns.message.make_query("VERSION.BIND", dns.rdatatype.TXT, dns.rdataclass.CHAOS), + dns.message.make_query("VERSION.SERVER", dns.rdatatype.TXT, dns.rdataclass.CHAOS), + ] + + results = [] + for query in queries: + response = method(query, where=ip, timeout=timeout, port=port) + + try: + answer = response.answer[0] + results.append(answer.to_rdataset().pop().strings[0].decode()) + except IndexError: + pass + + return [(set(), json.dumps(results))] diff --git a/boefjes/boefjes/plugins/kat_dns_version/normalize.py b/boefjes/boefjes/plugins/kat_dns_version/normalize.py new file mode 100644 index 00000000000..b3e805cc1c5 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_dns_version/normalize.py @@ -0,0 +1,36 @@ +import json +from collections.abc import Iterable + +from boefjes.job_models import NormalizerOutput +from octopoes.models import Reference +from octopoes.models.ooi.software import Software, SoftwareInstance + + +def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: + input_ooi_reference = Reference.from_str(input_ooi["primary_key"]) + + results = json.loads(raw) + for version in results: + if version.startswith("bind"): + name = "bind" + version_number = version.split("-")[1] + elif version.startswith("9."): + name = "bind" + version_number = version + elif version.startswith("Microsoft DNS"): + name = "Microsoft DNS" + version_number = version.replace("Microsoft DNS ", "").split(" ")[0] + elif version.startswith("dnsmasq"): + name = "dnsmasq" + version_number = version.split("-")[1] + elif version.startswith("PowerDNS"): + name = "PowerDNS" + version_number = version.replace("PowerDNS Authoritative Server ", "").split(" ")[0] + else: + name = None + version_number = None + + if name and version_number: + software = Software(name=name, version=version_number) + software_instance = SoftwareInstance(ooi=input_ooi_reference, software=software.reference) + yield from [software, software_instance] diff --git a/boefjes/boefjes/plugins/kat_dns_version/normalizer.json b/boefjes/boefjes/plugins/kat_dns_version/normalizer.json new file mode 100644 index 00000000000..0252c4fe250 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_dns_version/normalizer.json @@ -0,0 +1,10 @@ +{ + "id": "dns-bind-version-normalize", + "consumes": [ + "boefje/dns-bind-version" + ], + "produces": [ + "Software", + "SoftwareInstance" + ] +} diff --git a/boefjes/boefjes/plugins/kat_dns_version/schema.json b/boefjes/boefjes/plugins/kat_dns_version/schema.json new file mode 100644 index 00000000000..6a9fbe29348 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_dns_version/schema.json @@ -0,0 +1,13 @@ +{ + "title": "Arguments", + "type": "object", + "properties": { + "TIMEOUT": { + "title": "TIMEOUT", + "type": "integer", + "description": "Timeout for requests to the targeted dns servers", + "default": 30, + "minimum": 0 + } + } +} diff --git a/boefjes/tests/integration/test_api.py b/boefjes/tests/integration/test_api.py index 9c32af42f8a..ab67e466d98 100644 --- a/boefjes/tests/integration/test_api.py +++ b/boefjes/tests/integration/test_api.py @@ -47,9 +47,9 @@ def test_get_local_plugin(self): def test_filter_plugins(self): response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/") - self.assertEqual(len(response.json()), 97) + self.assertEqual(len(response.json()), 99) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins?plugin_type=boefje") - self.assertEqual(len(response.json()), 43) + self.assertEqual(len(response.json()), 44) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins?limit=10") self.assertEqual(len(response.json()), 10) @@ -74,7 +74,7 @@ def test_add_boefje(self): self.assertEqual(response.status_code, 422) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/?plugin_type=boefje") - self.assertEqual(len(response.json()), 44) + self.assertEqual(len(response.json()), 45) boefje_dict = boefje.dict() boefje_dict["consumes"] = list(boefje_dict["consumes"]) @@ -99,7 +99,7 @@ def test_add_normalizer(self): self.assertEqual(response.status_code, 201) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/?plugin_type=normalizer") - self.assertEqual(len(response.json()), 55) + self.assertEqual(len(response.json()), 56) response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/test_normalizer") self.assertEqual(response.json(), normalizer.dict()) From 25e4d5c6aef15ef49eeeac19e0a8c63656d60999 Mon Sep 17 00:00:00 2001 From: Rieven Date: Mon, 2 Sep 2024 16:30:35 +0200 Subject: [PATCH 090/112] Redirect to desired view when all plugins are enabled. (#3380) Co-authored-by: ammar92 Co-authored-by: Jeroen Dekkers --- .../templates/partials/return_button.html | 2 +- rocky/reports/views/aggregate_report.py | 16 ++++++++++++-- rocky/reports/views/generate_report.py | 14 +++++++++++-- rocky/tests/conftest.py | 21 +++++++++++++++++++ .../reports/test_aggregate_report_flow.py | 12 ++++++----- .../reports/test_generate_report_flow.py | 9 +++++--- rocky/tools/view_helpers.py | 5 +++++ 7 files changed, 66 insertions(+), 13 deletions(-) diff --git a/rocky/reports/templates/partials/return_button.html b/rocky/reports/templates/partials/return_button.html index ed038f61bd1..b86d6f6d58b 100644 --- a/rocky/reports/templates/partials/return_button.html +++ b/rocky/reports/templates/partials/return_button.html @@ -7,7 +7,7 @@ {% csrf_token %} {% include "forms/report_form_fields.html" %} - diff --git a/rocky/reports/views/aggregate_report.py b/rocky/reports/views/aggregate_report.py index 623905542ba..51d0f9da8b7 100644 --- a/rocky/reports/views/aggregate_report.py +++ b/rocky/reports/views/aggregate_report.py @@ -7,6 +7,7 @@ from django.urls import reverse from django.utils.http import urlencode from django.utils.translation import gettext_lazy as _ +from tools.view_helpers import PostRedirect from reports.report_types.aggregate_organisation_report.report import AggregateOrganisationReport from reports.report_types.definitions import AggregateReport, MultiReport, Report @@ -118,7 +119,7 @@ def setup(self, request, *args, **kwargs): def post(self, request, *args, **kwargs): if not self.selected_oois: messages.error(request, self.NONE_OOI_SELECTION_MESSAGE) - return redirect(self.get_previous()) + return PostRedirect(self.get_previous()) return self.get(request, *args, **kwargs) def get_report_types_for_aggregate_report( @@ -151,9 +152,17 @@ class SetupScanAggregateReportView( current_step = 3 def post(self, request, *args, **kwargs): + # If the user wants to change selection, but all plugins are enabled, it needs to go even further back if not self.selected_report_types: messages.error(request, self.NONE_REPORT_TYPE_SELECTION_MESSAGE) - return redirect(self.get_previous()) + return PostRedirect(self.get_previous()) + + if "return" in self.request.POST and self.plugins_enabled(): + return PostRedirect(self.get_previous()) + + if self.plugins_enabled(): + return PostRedirect(self.get_next()) + return self.get(request, *args, **kwargs) @@ -167,6 +176,9 @@ class ExportSetupAggregateReportView(AggregateReportStepsMixin, BreadcrumbsAggre current_step = 4 def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: + if not self.selected_report_types: + messages.error(request, self.NONE_REPORT_TYPE_SELECTION_MESSAGE) + return PostRedirect(self.get_previous()) return super().get(request, *args, **kwargs) def get_context_data(self, **kwargs): diff --git a/rocky/reports/views/generate_report.py b/rocky/reports/views/generate_report.py index cfd37c4ad05..a21e2557324 100644 --- a/rocky/reports/views/generate_report.py +++ b/rocky/reports/views/generate_report.py @@ -8,6 +8,7 @@ from django.urls import reverse from django.utils.http import urlencode from django.utils.translation import gettext_lazy as _ +from tools.view_helpers import PostRedirect from octopoes.models import Reference from reports.report_types.helpers import get_ooi_types_with_report, get_report_types_for_oois @@ -108,7 +109,7 @@ class ReportTypesSelectionGenerateReportView( def post(self, request, *args, **kwargs): if not self.selected_oois: messages.error(request, self.NONE_OOI_SELECTION_MESSAGE) - return redirect(self.get_previous()) + return PostRedirect(self.get_previous()) return self.get(request, *args, **kwargs) def get_context_data(self, **kwargs): @@ -135,7 +136,13 @@ class SetupScanGenerateReportView( def post(self, request, *args, **kwargs): if not self.selected_report_types: messages.error(request, self.NONE_REPORT_TYPE_SELECTION_MESSAGE) - return redirect(self.get_previous()) + return PostRedirect(self.get_previous()) + + if "return" in self.request.POST and self.plugins_enabled(): + return PostRedirect(self.get_previous()) + + if self.plugins_enabled(): + return PostRedirect(self.get_next()) return self.get(request, *args, **kwargs) @@ -150,6 +157,9 @@ class ExportSetupGenerateReportView(GenerateReportStepsMixin, BreadcrumbsGenerat reports: dict[str, str] = {} def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: + if not self.selected_report_types: + messages.error(request, self.NONE_REPORT_TYPE_SELECTION_MESSAGE) + return PostRedirect(self.get_previous()) self.reports = create_report_names(self.oois_pk, self.report_types) return super().get(request, *args, **kwargs) diff --git a/rocky/tests/conftest.py b/rocky/tests/conftest.py index a00690c900e..13b5c33b230 100644 --- a/rocky/tests/conftest.py +++ b/rocky/tests/conftest.py @@ -1785,3 +1785,24 @@ def boefje_dns_records(): runnable_hash=None, produces={"boefje/dns-records"}, ) + + +@pytest.fixture +def boefje_nmap_tcp(): + return Boefje( + id="nmap", + name="Nmap TCP", + version=None, + authors=None, + created=None, + description="Defaults to top 250 TCP ports. Includes service detection.", + environment_keys=None, + related=[], + enabled=True, + type="boefje", + scan_level=SCAN_LEVEL.L2, + consumes={IPAddressV4, IPAddressV6}, + options=None, + runnable_hash=None, + produces={"boefje/nmap"}, + ) diff --git a/rocky/tests/reports/test_aggregate_report_flow.py b/rocky/tests/reports/test_aggregate_report_flow.py index f3c6610cbf8..fca4d053401 100644 --- a/rocky/tests/reports/test_aggregate_report_flow.py +++ b/rocky/tests/reports/test_aggregate_report_flow.py @@ -177,7 +177,7 @@ def test_report_types_selection_nothing_selected( response = SetupScanAggregateReportView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 302 + assert response.status_code == 307 assert list(request._messages)[0].message == "Select at least one report type to proceed." @@ -189,6 +189,7 @@ def test_report_types_selection( listed_hostnames, mocker, boefje_dns_records, + boefje_nmap_tcp, rocky_health, mock_bytes_client, ): @@ -197,7 +198,7 @@ def test_report_types_selection( """ katalogus_mocker = mocker.patch("reports.views.base.get_katalogus")() - katalogus_mocker.get_plugins.return_value = [boefje_dns_records] + katalogus_mocker.get_plugins.return_value = [boefje_dns_records, boefje_nmap_tcp] rocky_health_mocker = mocker.patch("reports.report_types.aggregate_organisation_report.report.get_rocky_health")() rocky_health_mocker.return_value = rocky_health @@ -211,16 +212,17 @@ def test_report_types_selection( request = setup_request( rf.post( "aggregate_report_setup_scan", - {"observed_at": valid_time.strftime("%Y-%m-%d"), "report_type": "dns-report"}, + {"observed_at": valid_time.strftime("%Y-%m-%d"), "report_type": ["dns-report", "systems-report"]}, ), client_member.user, ) response = SetupScanAggregateReportView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 200 # if all plugins are enabled the view will auto redirect to generate report + assert response.status_code == 307 # if all plugins are enabled the view will auto redirect to generate report - assertContains(response, '', html=True) + # Redirect to export setup + assert response.headers["Location"] == "/en/test/reports/aggregate-report/export-setup/?" def test_save_aggregate_report_view( diff --git a/rocky/tests/reports/test_generate_report_flow.py b/rocky/tests/reports/test_generate_report_flow.py index 1271a69bff7..2cae8e51990 100644 --- a/rocky/tests/reports/test_generate_report_flow.py +++ b/rocky/tests/reports/test_generate_report_flow.py @@ -177,7 +177,8 @@ def test_report_types_selection_nothing_selected( response = SetupScanGenerateReportView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 302 + assert response.status_code == 307 + assert list(request._messages)[0].message == "Select at least one report type to proceed." @@ -214,8 +215,10 @@ def test_report_types_selection( response = SetupScanGenerateReportView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 200 - assertContains(response, '', html=True) + assert response.status_code == 307 + + # Redirect to export setup, all plugins are then enabled + assert response.headers["Location"] == "/en/test/reports/generate-report/export-setup/?" def test_save_generate_report_view( diff --git a/rocky/tools/view_helpers.py b/rocky/tools/view_helpers.py index e216d944334..9f7008662ed 100644 --- a/rocky/tools/view_helpers.py +++ b/rocky/tools/view_helpers.py @@ -4,6 +4,7 @@ from urllib.parse import urlencode, urlparse, urlunparse from django.http import HttpRequest +from django.http.response import HttpResponseRedirectBase from django.urls.base import reverse, reverse_lazy from django.utils.translation import gettext_lazy as _ @@ -163,3 +164,7 @@ def build_breadcrumbs(self): "text": _("Objects"), } ] + + +class PostRedirect(HttpResponseRedirectBase): + status_code = 307 From 85d3227ca322d2a06daccb00663f7b383a26fa1d Mon Sep 17 00:00:00 2001 From: Rieven Date: Tue, 3 Sep 2024 09:31:01 +0200 Subject: [PATCH 091/112] Fix findings overview overflow (#3439) --- .../report_severity_totals_table.html | 108 +++++++++--------- 1 file changed, 53 insertions(+), 55 deletions(-) diff --git a/rocky/reports/templates/partials/report_severity_totals_table.html b/rocky/reports/templates/partials/report_severity_totals_table.html index 2803dab932f..0074622bfc1 100644 --- a/rocky/reports/templates/partials/report_severity_totals_table.html +++ b/rocky/reports/templates/partials/report_severity_totals_table.html @@ -3,63 +3,61 @@

    {% translate "Findings overview" %}

    -
    -
    -
  • {% translate "Organization Code" %}{% translate "Normalizer" %} {% translate "Status" %} {% translate "Created date" %}{% translate "Modified date" %} {% translate "Boefje" %} {% translate "Boefje input OOI" %} {% translate "Details" %}
    + {{ task.data.raw_data.boefje_meta.organization }} + - {{ task.data.normalizer.id }} + {{ task.data.normalizer.id }}  {{ task.status.value|capfirst }} {{ task.created_at }}{{ task.modified_at }} - {{ task.data.raw_data.boefje_meta.boefje.id }} + {{ task.data.raw_data.boefje_meta.boefje.id }} - {{ task.data.raw_data.boefje_meta.input_ooi }} + {{ task.data.raw_data.boefje_meta.input_ooi }}
    + {% include "tasks/partials/task_actions.html" %}
    - - +
    +
    {% translate "Total per severity overview" %}
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    {% translate "Total per severity overview" %}
    {% translate "Risk level" %}{% translate "Findings" %}{% translate "Occurrences" %}
    + Critical + {{ data.total_by_severity_per_finding_type.critical }}{{ data.total_by_severity.critical }}
    + High + {{ data.total_by_severity_per_finding_type.high }}{{ data.total_by_severity.high }}
    + Medium + {{ data.total_by_severity_per_finding_type.medium }}{{ data.total_by_severity.medium }}
    + Low + {{ data.total_by_severity_per_finding_type.low }}{{ data.total_by_severity.low }}
    + Recommendation + {{ data.total_by_severity_per_finding_type.recommendation }}{{ data.total_by_severity.recommendation }}
    {% translate "Risk level" %}{% translate "Findings" %}{% translate "Occurrences" %}Total{{ data.total_finding_types }}{{ data.total_occurrences }}
    - Critical - {{ data.total_by_severity_per_finding_type.critical }}{{ data.total_by_severity.critical }}
    - High - {{ data.total_by_severity_per_finding_type.high }}{{ data.total_by_severity.high }}
    - Medium - {{ data.total_by_severity_per_finding_type.medium }}{{ data.total_by_severity.medium }}
    - Low - {{ data.total_by_severity_per_finding_type.low }}{{ data.total_by_severity.low }}
    - Recommendation - {{ data.total_by_severity_per_finding_type.recommendation }}{{ data.total_by_severity.recommendation }}
    Total{{ data.total_finding_types }}{{ data.total_occurrences }}
    -
  • + + +
    From 51897dd1b3c99648c336353af4db5deec47e0c12 Mon Sep 17 00:00:00 2001 From: Jeroen Dekkers Date: Tue, 3 Sep 2024 11:21:23 +0200 Subject: [PATCH 092/112] Add indemnification to API (#3423) Co-authored-by: Jan Klopper --- rocky/tests/conftest.py | 9 +++++ rocky/tests/test_api_organization.py | 53 ++++++++++++++++++++++++---- rocky/tools/viewsets.py | 28 +++++++++++++-- 3 files changed, 81 insertions(+), 9 deletions(-) diff --git a/rocky/tests/conftest.py b/rocky/tests/conftest.py index 13b5c33b230..f5bbb28dfac 100644 --- a/rocky/tests/conftest.py +++ b/rocky/tests/conftest.py @@ -1806,3 +1806,12 @@ def boefje_nmap_tcp(): runnable_hash=None, produces={"boefje/nmap"}, ) + + +@pytest.fixture +def drf_admin_client(create_drf_client, admin_user): + client = create_drf_client(admin_user) + # We need to set this so that the test client doesn't throw an + # exception, but will return error in the API we can test + client.raise_request_exception = False + return client diff --git a/rocky/tests/test_api_organization.py b/rocky/tests/test_api_organization.py index 9dbc2170a58..b3aa1155793 100644 --- a/rocky/tests/test_api_organization.py +++ b/rocky/tests/test_api_organization.py @@ -2,13 +2,16 @@ from unittest.mock import patch import pytest +from django.urls import reverse from httpx import HTTPError from pytest_assert_utils import assert_model_attrs from pytest_common_subject import precondition_fixture from pytest_drf import ( + APIViewTest, Returns200, Returns201, Returns204, + Returns409, Returns500, UsesDeleteMethod, UsesDetailEndpoint, @@ -51,13 +54,7 @@ def organizations(self): list_url = lambda_fixture(lambda: url_for("organization-list")) detail_url = lambda_fixture(lambda organization: url_for("organization-detail", organization.pk)) - @pytest.fixture - def client(self, create_drf_client, admin_user): - client = create_drf_client(admin_user) - # We need to set this so that the test client doesn't throw an - # exception, but will return error in the API we can test - client.raise_request_exception = False - return client + client = lambda_fixture("drf_admin_client") class TestList( UsesGetMethod, @@ -280,3 +277,45 @@ def test_it_returns_error(self, json): ], } assert json == expected + + +class TestGetIndemnification(APIViewTest, UsesGetMethod, Returns200): + # The superuser_member fixture creates the indemnification + url = lambda_fixture( + lambda organization, superuser_member: reverse("organization-indemnification", args=[organization.pk]) + ) + client = lambda_fixture("drf_admin_client") + + def test_it_returns_indemnification(self, json, superuser_member): + expected = {"indemnification": True, "user": superuser_member.user.id} + assert json == expected + + +class TestIndemnificationDoesNotExist(APIViewTest, UsesGetMethod, Returns200): + url = lambda_fixture(lambda organization: reverse("organization-indemnification", args=[organization.pk])) + client = lambda_fixture("drf_admin_client") + + def test_it_returns_no_indemnification(self, json): + expected = {"indemnification": False, "user": None} + assert json == expected + + +class TestSetIndemnification(APIViewTest, UsesPostMethod, Returns201): + url = lambda_fixture(lambda organization: reverse("organization-indemnification", args=[organization.pk])) + client = lambda_fixture("drf_admin_client") + + def test_it_sets_indemnification(self, json, admin_user): + expected = {"indemnification": True, "user": admin_user.id} + assert json == expected + + +class TestIndemnificationAlreadyExists(APIViewTest, UsesPostMethod, Returns409): + # The superuser_member fixture creates the indemnification + url = lambda_fixture( + lambda organization, superuser_member: reverse("organization-indemnification", args=[organization.pk]) + ) + client = lambda_fixture("drf_admin_client") + + def test_it_returns_indemnification(self, json, superuser_member): + expected = {"indemnification": True, "user": superuser_member.user.id} + assert json == expected diff --git a/rocky/tools/viewsets.py b/rocky/tools/viewsets.py index 9f3683f7303..52e5d492252 100644 --- a/rocky/tools/viewsets.py +++ b/rocky/tools/viewsets.py @@ -1,6 +1,8 @@ -from rest_framework import viewsets +from rest_framework import status, viewsets +from rest_framework.decorators import action +from rest_framework.response import Response -from tools.models import Organization +from tools.models import Indemnification, Organization from tools.serializers import OrganizationSerializer, OrganizationSerializerReadOnlyCode @@ -16,3 +18,25 @@ def get_serializer_class(self): if self.request.method != "POST": serializer_class = OrganizationSerializerReadOnlyCode return serializer_class + + @action(detail=True) + def indemnification(self, request, pk=None): + organization = self.get_object() + indemnification = Indemnification.objects.filter(organization=organization).first() + + if indemnification: + return Response({"indemnification": True, "user": indemnification.user.pk}) + else: + return Response({"indemnification": False, "user": None}) + + @indemnification.mapping.post + def set_indemnification(self, request, pk=None): + organization = self.get_object() + + indemnification = Indemnification.objects.filter(organization=organization).first() + if indemnification: + return Response({"indemnification": True, "user": indemnification.user.pk}, status=status.HTTP_409_CONFLICT) + + indemnification = Indemnification.objects.create(organization=organization, user=self.request.user) + + return Response({"indemnification": True, "user": indemnification.user.pk}, status=status.HTTP_201_CREATED) From 175bdce257f0da7806b98a20007a1b1662af0b8d Mon Sep 17 00:00:00 2001 From: originalsouth Date: Wed, 4 Sep 2024 09:07:35 +0200 Subject: [PATCH 093/112] Stop yielding network in certain normalizers (#3420) Co-authored-by: Jan Klopper Co-authored-by: ammar92 --- boefjes/boefjes/plugins/kat_crt_sh/normalize.py | 1 - boefjes/boefjes/plugins/kat_nmap_tcp/normalize.py | 1 - boefjes/tests/test_nmap.py | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_crt_sh/normalize.py b/boefjes/boefjes/plugins/kat_crt_sh/normalize.py index aba1315df12..3c430005fb9 100644 --- a/boefjes/boefjes/plugins/kat_crt_sh/normalize.py +++ b/boefjes/boefjes/plugins/kat_crt_sh/normalize.py @@ -16,7 +16,6 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: current = fqdn.lstrip(".") network = Network(name="internet") - yield network network_reference = network.reference unique_domains = set() diff --git a/boefjes/boefjes/plugins/kat_nmap_tcp/normalize.py b/boefjes/boefjes/plugins/kat_nmap_tcp/normalize.py index f4177a32b06..9a60c70e46f 100644 --- a/boefjes/boefjes/plugins/kat_nmap_tcp/normalize.py +++ b/boefjes/boefjes/plugins/kat_nmap_tcp/normalize.py @@ -53,7 +53,6 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: # Relevant network object is received from the normalizer_meta. network = Network(name=input_ooi["network"]["name"]) - yield network netblock_ref = None if "NetBlock" in input_ooi["object_type"]: diff --git a/boefjes/tests/test_nmap.py b/boefjes/tests/test_nmap.py index 8a5b9e29b9e..9d0de572fdf 100644 --- a/boefjes/tests/test_nmap.py +++ b/boefjes/tests/test_nmap.py @@ -9,7 +9,7 @@ class NmapTest(TestCase): def test_normalizer(self): input_ooi = IPAddressV4(network=Network(name="internet").reference, address="134.209.85.72") output = list(run(input_ooi.serialize(), get_dummy_data("raw/nmap_mispoes.xml"))) - self.assertEqual(16, len(output)) + self.assertEqual(15, len(output)) for i, out in enumerate(output[:-1]): if out.object_type == "IPPort" and output[i + 1].object_type == "Service": if out.port == 80: From a28863301cf5cbd7080caea2807776171a518a06 Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:10:29 +0200 Subject: [PATCH 094/112] Feature/finding sorting searching (#3405) --- octopoes/octopoes/api/router.py | 6 +++++ octopoes/octopoes/connector/octopoes.py | 10 +++++++- .../octopoes/repositories/ooi_repository.py | 23 ++++++++++++++++--- rocky/rocky/locale/django.pot | 14 +++++++---- .../templates/findings/findings_filter.html | 1 + rocky/rocky/views/finding_list.py | 6 ++++- rocky/rocky/views/mixins.py | 10 ++++++++ rocky/tools/forms/findings.py | 6 +++++ 8 files changed, 66 insertions(+), 10 deletions(-) diff --git a/octopoes/octopoes/api/router.py b/octopoes/octopoes/api/router.py index 6b9c7c11ba7..cb907f2c650 100644 --- a/octopoes/octopoes/api/router.py +++ b/octopoes/octopoes/api/router.py @@ -459,6 +459,9 @@ def list_findings( octopoes: OctopoesService = Depends(octopoes_service), valid_time: datetime = Depends(extract_valid_time), severities: set[RiskLevelSeverity] = Query(DEFAULT_SEVERITY_FILTER), + search_string: str | None = None, + order_by: Literal["score", "finding_type"] = "score", + asc_desc: Literal["asc", "desc"] = "desc", ) -> Paginated[Finding]: return octopoes.ooi_repository.list_findings( severities, @@ -467,6 +470,9 @@ def list_findings( only_muted, offset, limit, + search_string, + order_by, + asc_desc, ) diff --git a/octopoes/octopoes/connector/octopoes.py b/octopoes/octopoes/connector/octopoes.py index 9751fc3563c..0b346164d1e 100644 --- a/octopoes/octopoes/connector/octopoes.py +++ b/octopoes/octopoes/connector/octopoes.py @@ -265,15 +265,23 @@ def list_findings( only_muted: bool = False, offset: int = DEFAULT_OFFSET, limit: int = DEFAULT_LIMIT, + search_string: str | None = None, + order_by: Literal["score", "finding_type"] = "score", + asc_desc: Literal["asc", "desc"] = "desc", ) -> Paginated[Finding]: - params: dict[str, str | int | list[str]] = { + params: dict[str, str | int | list[str] | None] = { "valid_time": str(valid_time), "offset": offset, "limit": limit, "severities": [s.value for s in severities], "exclude_muted": exclude_muted, "only_muted": only_muted, + "search_string": search_string, + "order_by": order_by, + "asc_desc": asc_desc, } + + params = {k: v for k, v in params.items() if v is not None} # filter out None values res = self.session.get(f"/{self.client}/findings", params=params) return TypeAdapter(Paginated[Finding]).validate_json(res.content) diff --git a/octopoes/octopoes/repositories/ooi_repository.py b/octopoes/octopoes/repositories/ooi_repository.py index 2638cd7a638..40f05bc4fba 100644 --- a/octopoes/octopoes/repositories/ooi_repository.py +++ b/octopoes/octopoes/repositories/ooi_repository.py @@ -146,6 +146,9 @@ def list_findings( only_muted, offset, limit, + search_string, + order_by, + asc_desc, ) -> Paginated[Finding]: raise NotImplementedError @@ -729,6 +732,9 @@ def list_findings( only_muted=False, offset=DEFAULT_OFFSET, limit=DEFAULT_LIMIT, + search_string: str | None = None, + order_by: Literal["score", "finding_type"] = "score", + asc_desc: Literal["asc", "desc"] = "desc", ) -> Paginated[Finding]: # clause to find risk_severity concrete_finding_types = to_concrete({FindingType}) @@ -751,6 +757,15 @@ def list_findings( elif only_muted: muted_clause = "[?muted_finding :MutedFinding/finding ?finding]" + search_statement = ( + f"""[?finding :xt/id ?id] + [(clojure.string/includes? ?id \"{escape_string(search_string)}\")]""" + if search_string + else "" + ) + + order_statement = f":order-by [[?{order_by} :{asc_desc}]]" + severity_values = ", ".join([str_val(severity.value) for severity in severities]) count_query = f""" @@ -760,6 +775,7 @@ def list_findings( :in [[severities_ ...]] :where [[?finding :object_type "Finding"] [?finding :Finding/finding_type ?finding_type] + {search_statement} [(== ?severity severities_)] {or_severities} {muted_clause}] @@ -776,17 +792,18 @@ def list_findings( finding_query = f""" {{ :query {{ - :find [(pull ?finding [*]) ?score] + :find [(pull ?finding [*]) ?score ?finding_type] :in [[severities_ ...]] :where [[?finding :object_type "Finding"] [?finding :Finding/finding_type ?finding_type] [(== ?severity severities_)] {or_severities} {or_scores} - {muted_clause}] + {muted_clause} + {search_statement}] :limit {limit} :offset {offset} - :order-by [[?score :desc]] + {order_statement} }} :in-args [[{severity_values}]] }} diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 6d1c6ed2ae2..597592e2987 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-28 08:40+0000\n" +"POT-Creation-Date: 2024-09-04 08:55+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -4151,6 +4151,14 @@ msgstr "" msgid "Filter by muted findings" msgstr "" +#: tools/forms/findings.py tools/forms/ooi_form.py tools/forms/scheduler.py +msgid "Search" +msgstr "" + +#: tools/forms/findings.py +msgid "Object ID contains (case sensitive)" +msgstr "" + #: tools/forms/ooi.py msgid "Filter types" msgstr "" @@ -4189,10 +4197,6 @@ msgstr "" msgid "Filter by clearance type" msgstr "" -#: tools/forms/ooi_form.py tools/forms/scheduler.py -msgid "Search" -msgstr "" - #: tools/forms/scheduler.py msgid "From" msgstr "" diff --git a/rocky/rocky/templates/findings/findings_filter.html b/rocky/rocky/templates/findings/findings_filter.html index 971d3f373ba..7e9d7553713 100644 --- a/rocky/rocky/templates/findings/findings_filter.html +++ b/rocky/rocky/templates/findings/findings_filter.html @@ -16,6 +16,7 @@
    {% include "partials/form/fieldset.html" with fields=severity_filter fieldset_class="filter-fields-direction column" %} {% include "partials/form/fieldset.html" with fields=muted_findings_filter fieldset_class="filter-fields-direction column" %} + {% include "partials/form/fieldset.html" with fields=finding_search_form %}
    diff --git a/rocky/rocky/views/finding_list.py b/rocky/rocky/views/finding_list.py index 480c97edba4..bb7c346b168 100644 --- a/rocky/rocky/views/finding_list.py +++ b/rocky/rocky/views/finding_list.py @@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic import ListView from tools.forms.base import ObservedAtForm -from tools.forms.findings import FindingSeverityMultiSelectForm, MutedFindingSelectionForm +from tools.forms.findings import FindingSearchForm, FindingSeverityMultiSelectForm, MutedFindingSelectionForm from tools.view_helpers import BreadcrumbsMixin from octopoes.models.ooi.findings import RiskLevelSeverity @@ -61,6 +61,8 @@ def setup(self, request, *args, **kwargs): self.exclude_muted = self.muted_findings == "non-muted" self.only_muted = self.muted_findings == "muted" + self.search_string = request.GET.get("search", "") + def count_observed_at_filter(self) -> int: return 1 if datetime.now(timezone.utc).date() != self.observed_at.date() else 0 @@ -74,6 +76,7 @@ def get_queryset(self) -> FindingList: severities=self.severities, exclude_muted=self.exclude_muted, only_muted=self.only_muted, + search_string=self.search_string, ) def get_context_data(self, **kwargs): @@ -82,6 +85,7 @@ def get_context_data(self, **kwargs): context["observed_at"] = self.observed_at context["severity_filter"] = FindingSeverityMultiSelectForm({"severity": list(self.severities)}) context["muted_findings_filter"] = MutedFindingSelectionForm({"muted_findings": self.muted_findings}) + context["finding_search_form"] = FindingSearchForm(self.request.GET) context["only_muted"] = self.only_muted context["active_filters_counter"] = self.count_active_filters() return context diff --git a/rocky/rocky/views/mixins.py b/rocky/rocky/views/mixins.py index 6afe8d5f560..d8bc37268ed 100644 --- a/rocky/rocky/views/mixins.py +++ b/rocky/rocky/views/mixins.py @@ -278,6 +278,9 @@ def __init__( severities: set[RiskLevelSeverity], exclude_muted: bool = True, only_muted: bool = False, + search_string: str | None = None, + order_by: Literal["score", "finding_type"] = "score", + asc_desc: Literal["asc", "desc"] = "desc", ): self.octopoes_connector = octopoes_connector self.valid_time = valid_time @@ -286,6 +289,9 @@ def __init__( self.severities = severities self.exclude_muted = exclude_muted self.only_muted = only_muted + self.search_string = search_string + self.order_by = order_by + self.asc_desc = asc_desc @cached_property def count(self) -> int: @@ -295,6 +301,7 @@ def count(self) -> int: exclude_muted=self.exclude_muted, only_muted=self.only_muted, limit=0, + search_string=self.search_string, ).count def __len__(self): @@ -313,6 +320,9 @@ def __getitem__(self, key: int | slice) -> list[HydratedFinding]: only_muted=self.only_muted, offset=offset, limit=limit, + search_string=self.search_string, + order_by=self.order_by, + asc_desc=self.asc_desc, ).items ooi_references = {finding.ooi for finding in findings} finding_type_references = {finding.finding_type for finding in findings} diff --git a/rocky/tools/forms/findings.py b/rocky/tools/forms/findings.py index b19070fcd57..6d65bc8a775 100644 --- a/rocky/tools/forms/findings.py +++ b/rocky/tools/forms/findings.py @@ -32,3 +32,9 @@ class MutedFindingSelectionForm(BaseRockyForm): choices=MUTED_FINDINGS_CHOICES, widget=forms.RadioSelect, ) + + +class FindingSearchForm(BaseRockyForm): + search = forms.CharField( + label=_("Search"), required=False, max_length=256, help_text=_("Object ID contains (case sensitive)") + ) From 03fee11ef2f6a2924e6ed531e131725a4db5b143 Mon Sep 17 00:00:00 2001 From: HeleenSG Date: Wed, 4 Sep 2024 23:01:00 +0200 Subject: [PATCH 095/112] fix: notification width (#3450) Co-authored-by: Jan Klopper --- rocky/assets/css/main.scss | 1 + .../vendor_overrides/manon/notification.scss | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 rocky/assets/css/vendor_overrides/manon/notification.scss diff --git a/rocky/assets/css/main.scss b/rocky/assets/css/main.scss index fefaa3969a6..0e41f9ea21d 100644 --- a/rocky/assets/css/main.scss +++ b/rocky/assets/css/main.scss @@ -18,6 +18,7 @@ @import "vendor_overrides/manon/layout-fifty-fifty"; @import "vendor_overrides/manon/layout-form"; @import "vendor_overrides/manon/nested-section"; +@import "vendor_overrides/manon/notification"; @import "vendor_overrides/manon/table"; @import "vendor_overrides/manon/tile"; @import "vendor_overrides/two-factor"; diff --git a/rocky/assets/css/vendor_overrides/manon/notification.scss b/rocky/assets/css/vendor_overrides/manon/notification.scss new file mode 100644 index 00000000000..03b895c8acf --- /dev/null +++ b/rocky/assets/css/vendor_overrides/manon/notification.scss @@ -0,0 +1,18 @@ +p, +a, +span, +li, +h1, +h2, +h3, +h4, +h5, +h6 { + &.error, + &.warning, + &.explanation, + &.confirmation, + &.system { + max-width: var(--max-line-length-max-width); + } +} From 5b743b67968513ff96896e60c347782a2290e94a Mon Sep 17 00:00:00 2001 From: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> Date: Wed, 4 Sep 2024 23:07:36 +0200 Subject: [PATCH 096/112] Update katalogus boefje descriptions (#3444) Co-authored-by: Ammar Co-authored-by: Jan Klopper --- .../plugins/kat_adr_finding_types/boefje.json | 2 +- .../kat_adr_finding_types/normalizer.json | 2 ++ .../plugins/kat_adr_validator/boefje.json | 2 +- .../plugins/kat_adr_validator/normalizer.json | 2 ++ .../plugins/kat_answer_parser/normalizer.json | 2 ++ .../plugins/kat_binaryedge/boefje.json | 2 +- .../kat_binaryedge/containers/normalizer.json | 1 + .../kat_binaryedge/databases/normalizer.json | 1 + .../kat_binaryedge/http_web/normalizer.json | 1 + .../message_queues/normalizer.json | 1 + .../kat_binaryedge/protocols/normalizer.json | 1 + .../remote_desktop/normalizer.json | 1 + .../service_identification/normalizer.json | 1 + .../kat_binaryedge/services/normalizer.json | 1 + .../plugins/kat_burpsuite/normalizer.json | 2 +- .../plugins/kat_calvin/normalizer.json | 2 ++ .../boefjes/plugins/kat_censys/boefje.json | 2 +- .../plugins/kat_censys/normalizer.json | 1 + .../boefjes/plugins/kat_crt_sh/boefje.json | 2 +- .../plugins/kat_crt_sh/normalizer.json | 2 ++ .../plugins/kat_cve_2023_34039/boefje.json | 4 +-- .../plugins/kat_cve_2023_35078/boefje.json | 4 +-- .../kat_cve_2023_35078/normalizer.json | 2 ++ .../plugins/kat_cve_2024_6387/normalizer.json | 3 ++- .../plugins/kat_cve_finding_types/boefje.json | 2 +- .../kat_cve_finding_types/normalizer.json | 2 ++ .../plugins/kat_cwe_finding_types/boefje.json | 2 +- .../kat_cwe_finding_types/normalizer.json | 2 ++ boefjes/boefjes/plugins/kat_dicom/boefje.json | 2 +- .../boefjes/plugins/kat_dicom/normalizer.json | 2 ++ boefjes/boefjes/plugins/kat_dns/boefje.json | 4 +-- .../boefjes/plugins/kat_dns/normalizer.json | 2 ++ .../boefjes/plugins/kat_dns_zone/boefje.json | 2 +- .../plugins/kat_dns_zone/normalizer.json | 2 ++ .../boefjes/plugins/kat_dnssec/boefje.json | 2 +- .../plugins/kat_dnssec/normalizer.json | 2 ++ .../plugins/kat_external_db/boefje.json | 4 +-- .../plugins/kat_external_db/normalizer.json | 2 ++ .../boefjes/plugins/kat_fierce/boefje.json | 4 +-- .../plugins/kat_fierce/normalizer.json | 2 ++ .../kat_finding_normalizer/normalizer.json | 1 + .../plugins/kat_green_hosting/boefje.json | 2 +- .../plugins/kat_green_hosting/normalizer.json | 1 + .../kat_finding_types.json | 26 +++++++++---------- .../kat_kat_finding_types/normalizer.json | 1 + .../boefjes/plugins/kat_leakix/boefje.json | 2 +- .../plugins/kat_leakix/normalizer.json | 2 ++ .../boefjes/plugins/kat_log4shell/boefje.json | 2 +- .../plugins/kat_manual/csv/normalizer.json | 1 + .../plugins/kat_masscan/normalizer.json | 2 ++ .../plugins/kat_maxmind_geoip/boefje.json | 2 +- .../plugins/kat_maxmind_geoip/normalizer.json | 2 ++ .../plugins/kat_nmap_tcp/normalizer.json | 1 + .../plugins/kat_nuclei_cve/normalizer.json | 1 + .../kat_nuclei_exposed_panels/normalizer.json | 1 + .../kat_nuclei_take_over/normalizer.json | 1 + .../boefjes/plugins/kat_rdns/normalizer.json | 1 + .../plugins/kat_report_data/normalizer.json | 1 + .../normalizer.json | 1 + .../boefjes/plugins/kat_rpki/normalizer.json | 1 + .../normalizer.json | 1 + .../plugins/kat_shodan/normalizer.json | 1 + .../boefjes/plugins/kat_snyk/normalizer.json | 1 + .../kat_snyk_finding_types/normalizer.json | 1 + .../kat_ssl_certificates/normalizer.json | 1 + .../plugins/kat_ssl_scan/normalizer.json | 1 + .../kat_testssl_sh_ciphers/normalizer.json | 1 + .../plugins/kat_wappalyzer/normalizer.json | 1 + .../check_images/normalizer.json | 1 + .../find_images_in_html/normalizer.json | 1 + .../headers/normalizer.json | 1 + .../plugins/kat_wpscan/normalizer.json | 1 + .../plugins/pdio_subfinder/normalizer.json | 1 + boefjes/tests/integration/test_api.py | 2 +- .../test_migration_add_schema_field.py | 8 +++--- 75 files changed, 113 insertions(+), 44 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_adr_finding_types/boefje.json b/boefjes/boefjes/plugins/kat_adr_finding_types/boefje.json index e53d47f3982..93c2ae8ef7d 100644 --- a/boefjes/boefjes/plugins/kat_adr_finding_types/boefje.json +++ b/boefjes/boefjes/plugins/kat_adr_finding_types/boefje.json @@ -1,7 +1,7 @@ { "id": "adr-finding-types", "name": "ADR Finding Types", - "description": "Hydrate information of ADR finding types", + "description": "Hydrate information on API Design Rules (ADR) finding types for common design mistakes.", "consumes": [ "ADRFindingType" ], diff --git a/boefjes/boefjes/plugins/kat_adr_finding_types/normalizer.json b/boefjes/boefjes/plugins/kat_adr_finding_types/normalizer.json index 583b7714bed..fabda504805 100644 --- a/boefjes/boefjes/plugins/kat_adr_finding_types/normalizer.json +++ b/boefjes/boefjes/plugins/kat_adr_finding_types/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_adr_finding_types_normalize", + "name": "API Design Rules (ADR) Finding Types", + "description": "Parse API Design Rules (ADR) finding types.", "consumes": [ "boefje/adr-finding-types" ], diff --git a/boefjes/boefjes/plugins/kat_adr_validator/boefje.json b/boefjes/boefjes/plugins/kat_adr_validator/boefje.json index b782dbb5b5b..9d43ee60519 100644 --- a/boefjes/boefjes/plugins/kat_adr_validator/boefje.json +++ b/boefjes/boefjes/plugins/kat_adr_validator/boefje.json @@ -1,7 +1,7 @@ { "id": "adr-validator", "name": "API Design Rules validator", - "description": "Validate if an API conforms to the API Design Rules", + "description": "Validate if an API conforms to the API Design Rules (ADR).", "consumes": [ "RESTAPI" ], diff --git a/boefjes/boefjes/plugins/kat_adr_validator/normalizer.json b/boefjes/boefjes/plugins/kat_adr_validator/normalizer.json index 52c21e9a03e..f840cded2ad 100644 --- a/boefjes/boefjes/plugins/kat_adr_validator/normalizer.json +++ b/boefjes/boefjes/plugins/kat_adr_validator/normalizer.json @@ -1,5 +1,7 @@ { "id": "adr-validator-normalize", + "name": "API Design Rules validator", + "description": "TODO", "consumes": [ "boefje/adr-validator" ], diff --git a/boefjes/boefjes/plugins/kat_answer_parser/normalizer.json b/boefjes/boefjes/plugins/kat_answer_parser/normalizer.json index 41a89a217b0..922b333697f 100644 --- a/boefjes/boefjes/plugins/kat_answer_parser/normalizer.json +++ b/boefjes/boefjes/plugins/kat_answer_parser/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_answer_parser", + "name": "Answer Parser", + "description": "Parses the answers from Config objects.", "consumes": [ "answer" ], diff --git a/boefjes/boefjes/plugins/kat_binaryedge/boefje.json b/boefjes/boefjes/plugins/kat_binaryedge/boefje.json index 004015e0570..9dc2a85d8fb 100644 --- a/boefjes/boefjes/plugins/kat_binaryedge/boefje.json +++ b/boefjes/boefjes/plugins/kat_binaryedge/boefje.json @@ -1,7 +1,7 @@ { "id": "binaryedge", "name": "BinaryEdge", - "description": "Use BinaryEdge to find open ports with vulnerabilities that are found on that port", + "description": "Use BinaryEdge to find open ports with vulnerabilities. Requires a BinaryEdge API key.", "consumes": [ "IPAddressV4", "IPAddressV6" diff --git a/boefjes/boefjes/plugins/kat_binaryedge/containers/normalizer.json b/boefjes/boefjes/plugins/kat_binaryedge/containers/normalizer.json index 46a034d0d1c..086ce350160 100644 --- a/boefjes/boefjes/plugins/kat_binaryedge/containers/normalizer.json +++ b/boefjes/boefjes/plugins/kat_binaryedge/containers/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_binaryedge_containers", + "name": "BinaryEdge containers", "consumes": [ "boefje/binaryedge" ], diff --git a/boefjes/boefjes/plugins/kat_binaryedge/databases/normalizer.json b/boefjes/boefjes/plugins/kat_binaryedge/databases/normalizer.json index 22fd81eb927..2af3f47f891 100644 --- a/boefjes/boefjes/plugins/kat_binaryedge/databases/normalizer.json +++ b/boefjes/boefjes/plugins/kat_binaryedge/databases/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_binaryedge_databases", + "name": "BinaryEdge databases", "consumes": [ "boefje/binaryedge" ], diff --git a/boefjes/boefjes/plugins/kat_binaryedge/http_web/normalizer.json b/boefjes/boefjes/plugins/kat_binaryedge/http_web/normalizer.json index f0e5825f36d..f5cafc7560a 100644 --- a/boefjes/boefjes/plugins/kat_binaryedge/http_web/normalizer.json +++ b/boefjes/boefjes/plugins/kat_binaryedge/http_web/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_binaryedge_http_web", + "name": "BinaryEdge Websites", "consumes": [ "boefje/binaryedge" ], diff --git a/boefjes/boefjes/plugins/kat_binaryedge/message_queues/normalizer.json b/boefjes/boefjes/plugins/kat_binaryedge/message_queues/normalizer.json index 15ea3e250b0..caa59b56f4b 100644 --- a/boefjes/boefjes/plugins/kat_binaryedge/message_queues/normalizer.json +++ b/boefjes/boefjes/plugins/kat_binaryedge/message_queues/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_binaryedge_message_queues", + "name": "BinaryEdge message queues", "consumes": [ "boefje/binaryedge" ], diff --git a/boefjes/boefjes/plugins/kat_binaryedge/protocols/normalizer.json b/boefjes/boefjes/plugins/kat_binaryedge/protocols/normalizer.json index 34f17a681c1..30d0f02963e 100644 --- a/boefjes/boefjes/plugins/kat_binaryedge/protocols/normalizer.json +++ b/boefjes/boefjes/plugins/kat_binaryedge/protocols/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_binaryedge_protocols", + "name": "BinaryEdge protocols", "consumes": [ "boefje/binaryedge" ], diff --git a/boefjes/boefjes/plugins/kat_binaryedge/remote_desktop/normalizer.json b/boefjes/boefjes/plugins/kat_binaryedge/remote_desktop/normalizer.json index c28180a88c7..80e1837a499 100644 --- a/boefjes/boefjes/plugins/kat_binaryedge/remote_desktop/normalizer.json +++ b/boefjes/boefjes/plugins/kat_binaryedge/remote_desktop/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_binaryedge_remote_desktop", + "name": "Binary Edge remote desktop", "consumes": [ "boefje/binaryedge" ], diff --git a/boefjes/boefjes/plugins/kat_binaryedge/service_identification/normalizer.json b/boefjes/boefjes/plugins/kat_binaryedge/service_identification/normalizer.json index eaea2744052..d451a79b150 100644 --- a/boefjes/boefjes/plugins/kat_binaryedge/service_identification/normalizer.json +++ b/boefjes/boefjes/plugins/kat_binaryedge/service_identification/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_binaryedge_service_identification", + "name": "BinaryEdge service identification", "consumes": [ "boefje/binaryedge" ], diff --git a/boefjes/boefjes/plugins/kat_binaryedge/services/normalizer.json b/boefjes/boefjes/plugins/kat_binaryedge/services/normalizer.json index b2671be67a1..57a0f8dac16 100644 --- a/boefjes/boefjes/plugins/kat_binaryedge/services/normalizer.json +++ b/boefjes/boefjes/plugins/kat_binaryedge/services/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_binaryedge_services", + "name": "BinaryEdge services", "consumes": [ "boefje/binaryedge" ], diff --git a/boefjes/boefjes/plugins/kat_burpsuite/normalizer.json b/boefjes/boefjes/plugins/kat_burpsuite/normalizer.json index 44c8b40ab3e..c0b88e6a857 100644 --- a/boefjes/boefjes/plugins/kat_burpsuite/normalizer.json +++ b/boefjes/boefjes/plugins/kat_burpsuite/normalizer.json @@ -1,7 +1,7 @@ { "id": "kat_burpsuite_normalize", "name": "Burpsuite normalizer", - "description": "Parses Burpsuite XML output (reports). Check https://docs.openkat.nl on how to create the XML file.", + "description": "Parses Burpsuite XML output into findings. Check https://docs.openkat.nl/manual/normalizers.html#burp-suite on how to create the XML file.", "consumes": [ "xml/burp-export" ], diff --git a/boefjes/boefjes/plugins/kat_calvin/normalizer.json b/boefjes/boefjes/plugins/kat_calvin/normalizer.json index 601433e8681..c596dbdcd4a 100644 --- a/boefjes/boefjes/plugins/kat_calvin/normalizer.json +++ b/boefjes/boefjes/plugins/kat_calvin/normalizer.json @@ -1,5 +1,7 @@ { "id": "calvin-normalize", + "name": "Calvin", + "description": "Produces applications and incidents for Calvin.", "consumes": [ "boefje/calvin" ], diff --git a/boefjes/boefjes/plugins/kat_censys/boefje.json b/boefjes/boefjes/plugins/kat_censys/boefje.json index e8c15547c76..6aadac16fba 100644 --- a/boefjes/boefjes/plugins/kat_censys/boefje.json +++ b/boefjes/boefjes/plugins/kat_censys/boefje.json @@ -1,7 +1,7 @@ { "id": "censys", "name": "Censys", - "description": "Use Censys to discover open ports, services and certificates", + "description": "Use Censys to discover open ports, services and certificates. Requires and API key.", "consumes": [ "IPAddressV4", "IPAddressV6" diff --git a/boefjes/boefjes/plugins/kat_censys/normalizer.json b/boefjes/boefjes/plugins/kat_censys/normalizer.json index 446c55cd485..809fc7d7174 100644 --- a/boefjes/boefjes/plugins/kat_censys/normalizer.json +++ b/boefjes/boefjes/plugins/kat_censys/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_censys_normalize", + "name": "Censys", "consumes": [ "boefje/censys" ], diff --git a/boefjes/boefjes/plugins/kat_crt_sh/boefje.json b/boefjes/boefjes/plugins/kat_crt_sh/boefje.json index 72051dbb411..f9aa67e604e 100644 --- a/boefjes/boefjes/plugins/kat_crt_sh/boefje.json +++ b/boefjes/boefjes/plugins/kat_crt_sh/boefje.json @@ -1,7 +1,7 @@ { "id": "certificate-search", "name": "CRT", - "description": "Certificate search", + "description": "Searches for certificates and new hostnames in the transparency logs of crt.sh.", "consumes": [ "DNSZone" ], diff --git a/boefjes/boefjes/plugins/kat_crt_sh/normalizer.json b/boefjes/boefjes/plugins/kat_crt_sh/normalizer.json index 5fd671f9719..130bd2b8301 100644 --- a/boefjes/boefjes/plugins/kat_crt_sh/normalizer.json +++ b/boefjes/boefjes/plugins/kat_crt_sh/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_crt_sh_normalize", + "name": "Certificate Transparency logs (crt.sh)", + "description": "Parses data from certificate transparency logs (crt.sh) into hostnames and X509 certificates.", "consumes": [ "boefje/certificate-search" ], diff --git a/boefjes/boefjes/plugins/kat_cve_2023_34039/boefje.json b/boefjes/boefjes/plugins/kat_cve_2023_34039/boefje.json index 9c82a08ec66..0b0f6b6dc6e 100644 --- a/boefjes/boefjes/plugins/kat_cve_2023_34039/boefje.json +++ b/boefjes/boefjes/plugins/kat_cve_2023_34039/boefje.json @@ -1,7 +1,7 @@ { "id": "CVE-2023-34039", - "name": "CVE_2023_34039", - "description": "Check to see if known keys are usable on VMware CVE-2023-34039", + "name": "CVE-2023-34039 - VMware Aria Operations", + "description": "Checks if there are static SSH keys present that can be used for remote code execution on VWware Aria Operations (CVE-2023-34039). This vulnerability can be used to bypass SSH authentication and gain access to the Aria Operations for Networks CLI.", "consumes": [ "IPService" ], diff --git a/boefjes/boefjes/plugins/kat_cve_2023_35078/boefje.json b/boefjes/boefjes/plugins/kat_cve_2023_35078/boefje.json index 07525502bf3..52c93d41450 100644 --- a/boefjes/boefjes/plugins/kat_cve_2023_35078/boefje.json +++ b/boefjes/boefjes/plugins/kat_cve_2023_35078/boefje.json @@ -1,7 +1,7 @@ { "id": "CVE_2023_35078", - "name": "CVE_2023_35078", - "description": "Use NFIR script to find CVE-2023-35078", + "name": "CVE-2023-35078 - Ivanti EPMM", + "description": "Checks websites for the presents of the Ivanti EPMM interface and whether the interface is vulnerable to the remote unauthenticated API access vulnerability (CVE-2023-35078). Script contribution by NFIR.", "consumes": [ "Website" ], diff --git a/boefjes/boefjes/plugins/kat_cve_2023_35078/normalizer.json b/boefjes/boefjes/plugins/kat_cve_2023_35078/normalizer.json index 0b7413eede9..c735560eae4 100644 --- a/boefjes/boefjes/plugins/kat_cve_2023_35078/normalizer.json +++ b/boefjes/boefjes/plugins/kat_cve_2023_35078/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_CVE_2023_35078_normalize", + "name": "CVE-2023-35078 Ivanti EPMM", + "description": "Checks if the Ivanti EPMM website is vulnerable to CVE-2023-35078. Produces a finding if it is vulnerable.", "consumes": [ "boefje/CVE_2023_35078" ], diff --git a/boefjes/boefjes/plugins/kat_cve_2024_6387/normalizer.json b/boefjes/boefjes/plugins/kat_cve_2024_6387/normalizer.json index 1cf4c49e5bf..0e06b9d2362 100644 --- a/boefjes/boefjes/plugins/kat_cve_2024_6387/normalizer.json +++ b/boefjes/boefjes/plugins/kat_cve_2024_6387/normalizer.json @@ -1,9 +1,10 @@ { "id": "kat_cve_2024_6387_normalize", + "name": "CVE-2024-6387 OpenSSH", + "description": "Checks the service banner for a race condition in OpenSSH server which can result in an unauthenticated remote attacker to trigger that some signals are handled in an unsafe manner (CVE-2024-6387). Requires the Service-Banner-boefje to be enabled.", "consumes": [ "openkat/service-banner" ], - "description": "Checks service banner for CVE-2024-6387, enable service banner boefje to get the service banner", "produces": [ "Finding", "CVEFindingType" diff --git a/boefjes/boefjes/plugins/kat_cve_finding_types/boefje.json b/boefjes/boefjes/plugins/kat_cve_finding_types/boefje.json index 2b390197290..280ea27e565 100644 --- a/boefjes/boefjes/plugins/kat_cve_finding_types/boefje.json +++ b/boefjes/boefjes/plugins/kat_cve_finding_types/boefje.json @@ -1,7 +1,7 @@ { "id": "cve-finding-types", "name": "CVE Finding Types", - "description": "Hydrate information of CVE finding types from the CVE API", + "description": "Hydrate information of Common Vulnerabilities and Exposures (CVE) finding types from the CVE API", "consumes": [ "CVEFindingType" ], diff --git a/boefjes/boefjes/plugins/kat_cve_finding_types/normalizer.json b/boefjes/boefjes/plugins/kat_cve_finding_types/normalizer.json index 6e2d52291aa..6ae5590562d 100644 --- a/boefjes/boefjes/plugins/kat_cve_finding_types/normalizer.json +++ b/boefjes/boefjes/plugins/kat_cve_finding_types/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_cve_finding_types_normalize", + "name": "CVE finding types", + "description": "Parses CVE findings.", "consumes": [ "boefje/cve-finding-types" ], diff --git a/boefjes/boefjes/plugins/kat_cwe_finding_types/boefje.json b/boefjes/boefjes/plugins/kat_cwe_finding_types/boefje.json index a3656aa48c6..abeeaa7d9d0 100644 --- a/boefjes/boefjes/plugins/kat_cwe_finding_types/boefje.json +++ b/boefjes/boefjes/plugins/kat_cwe_finding_types/boefje.json @@ -1,7 +1,7 @@ { "id": "cwe-finding-types", "name": "CWE Finding Types", - "description": "Hydrate information of CWE finding types", + "description": "Hydrate information of Common Weakness Enumeration (CWE) finding types", "consumes": [ "CWEFindingType" ], diff --git a/boefjes/boefjes/plugins/kat_cwe_finding_types/normalizer.json b/boefjes/boefjes/plugins/kat_cwe_finding_types/normalizer.json index 7b19ddd4c99..9b939d07df5 100644 --- a/boefjes/boefjes/plugins/kat_cwe_finding_types/normalizer.json +++ b/boefjes/boefjes/plugins/kat_cwe_finding_types/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_cwe_finding_types_normalize", + "name": "CWE finding", + "description": "Parses CWE findings.", "consumes": [ "boefje/cwe-finding-types" ], diff --git a/boefjes/boefjes/plugins/kat_dicom/boefje.json b/boefjes/boefjes/plugins/kat_dicom/boefje.json index 437829787a9..6cfd4e76498 100644 --- a/boefjes/boefjes/plugins/kat_dicom/boefje.json +++ b/boefjes/boefjes/plugins/kat_dicom/boefje.json @@ -1,7 +1,7 @@ { "id": "dicom", "name": "DICOM", - "description": "Find exposed DICOM servers.", + "description": "Find exposed DICOM servers. DICOM servers are used to process medical imaging information.", "consumes": [ "IPAddressV4", "IPAddressV6" diff --git a/boefjes/boefjes/plugins/kat_dicom/normalizer.json b/boefjes/boefjes/plugins/kat_dicom/normalizer.json index b8e5f1dd49c..74519e6e96c 100644 --- a/boefjes/boefjes/plugins/kat_dicom/normalizer.json +++ b/boefjes/boefjes/plugins/kat_dicom/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_dicom_normalize", + "name": "DICOM servers", + "description": "Parses DICOM output into findings and identified software.", "consumes": [ "boefje/dicom" ], diff --git a/boefjes/boefjes/plugins/kat_dns/boefje.json b/boefjes/boefjes/plugins/kat_dns/boefje.json index 76c36ae1775..53391f0155d 100644 --- a/boefjes/boefjes/plugins/kat_dns/boefje.json +++ b/boefjes/boefjes/plugins/kat_dns/boefje.json @@ -1,7 +1,7 @@ { "id": "dns-records", - "name": "DnsRecords", - "description": "Fetch the DNS record(s) of a hostname", + "name": "DNS records", + "description": "Fetch the DNS record(s) of a hostname.", "consumes": [ "Hostname" ], diff --git a/boefjes/boefjes/plugins/kat_dns/normalizer.json b/boefjes/boefjes/plugins/kat_dns/normalizer.json index e4a2316eda0..fa9c8a73fa6 100644 --- a/boefjes/boefjes/plugins/kat_dns/normalizer.json +++ b/boefjes/boefjes/plugins/kat_dns/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_dns_normalize", + "name": "DNS records", + "description": "Parses the DNS records.", "consumes": [ "boefje/dns-records" ], diff --git a/boefjes/boefjes/plugins/kat_dns_zone/boefje.json b/boefjes/boefjes/plugins/kat_dns_zone/boefje.json index 25df0af7bcd..cc03e079bd1 100644 --- a/boefjes/boefjes/plugins/kat_dns_zone/boefje.json +++ b/boefjes/boefjes/plugins/kat_dns_zone/boefje.json @@ -1,6 +1,6 @@ { "id": "dns-zone", - "name": "DnsZone", + "name": "DNS zone", "description": "Fetch the parent DNS zone of a DNS zone", "consumes": [ "DNSZone" diff --git a/boefjes/boefjes/plugins/kat_dns_zone/normalizer.json b/boefjes/boefjes/plugins/kat_dns_zone/normalizer.json index c4060c833ec..e9e156f6d2c 100644 --- a/boefjes/boefjes/plugins/kat_dns_zone/normalizer.json +++ b/boefjes/boefjes/plugins/kat_dns_zone/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_dns_zone_normalize", + "name": "DNS zone", + "description": "Parses the parent DNS zone into new hostnames and DNS zones.", "consumes": [ "boefje/dns-zone" ], diff --git a/boefjes/boefjes/plugins/kat_dnssec/boefje.json b/boefjes/boefjes/plugins/kat_dnssec/boefje.json index 7b59b0fae25..8b4d156396e 100644 --- a/boefjes/boefjes/plugins/kat_dnssec/boefje.json +++ b/boefjes/boefjes/plugins/kat_dnssec/boefje.json @@ -1,6 +1,6 @@ { "id": "dns-sec", - "name": "Dnssec", + "name": "DNSSEC", "description": "Validates DNSSec of a hostname", "consumes": [ "Hostname" diff --git a/boefjes/boefjes/plugins/kat_dnssec/normalizer.json b/boefjes/boefjes/plugins/kat_dnssec/normalizer.json index 24877c2e897..670f16592f4 100644 --- a/boefjes/boefjes/plugins/kat_dnssec/normalizer.json +++ b/boefjes/boefjes/plugins/kat_dnssec/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_dnssec_normalize", + "name": "DNS records", + "description": "Parses DNSSEC data into findings.", "consumes": [ "boefje/dns-sec" ], diff --git a/boefjes/boefjes/plugins/kat_external_db/boefje.json b/boefjes/boefjes/plugins/kat_external_db/boefje.json index 1f27e7f9d2e..4de34b597ac 100644 --- a/boefjes/boefjes/plugins/kat_external_db/boefje.json +++ b/boefjes/boefjes/plugins/kat_external_db/boefje.json @@ -1,7 +1,7 @@ { "id": "external_db", - "name": "External Database", - "description": "Fetch hostnames and IP addresses/netblocks from an external database with API. See `description.md` for more information.", + "name": "External database host fetcher", + "description": "Fetch hostnames and IP addresses/netblocks from an external database with API. See `description.md` for more information. Useful if you have a large network.", "consumes": [ "Network" ], diff --git a/boefjes/boefjes/plugins/kat_external_db/normalizer.json b/boefjes/boefjes/plugins/kat_external_db/normalizer.json index 36d425db438..2d9e72d56e9 100644 --- a/boefjes/boefjes/plugins/kat_external_db/normalizer.json +++ b/boefjes/boefjes/plugins/kat_external_db/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_external_db_normalize", + "name": "External database hosts fetcher", + "description": "Parse data the fetched host data from the external database into hostnames and IP-addresses.", "consumes": [ "boefje/external_db" ], diff --git a/boefjes/boefjes/plugins/kat_fierce/boefje.json b/boefjes/boefjes/plugins/kat_fierce/boefje.json index c198875c8a1..1f7d5c677db 100644 --- a/boefjes/boefjes/plugins/kat_fierce/boefje.json +++ b/boefjes/boefjes/plugins/kat_fierce/boefje.json @@ -1,9 +1,9 @@ { "id": "fierce", "name": "Fierce", - "description": "Use a Fierce scan to find subdomains (with their ip)", + "description": "Perform DNS reconnaissance using Fierce, to help locate non-contiguous IP space and hostnames against specified hostnames. No exploitation is performed.", "consumes": [ "Hostname" ], - "scan_level": 3 + "scan_level": 1 } diff --git a/boefjes/boefjes/plugins/kat_fierce/normalizer.json b/boefjes/boefjes/plugins/kat_fierce/normalizer.json index 536944b4995..82589b6565d 100644 --- a/boefjes/boefjes/plugins/kat_fierce/normalizer.json +++ b/boefjes/boefjes/plugins/kat_fierce/normalizer.json @@ -1,5 +1,7 @@ { "id": "kat_fierce_normalize", + "name": "Fierce", + "description": "Parse the DNS reconnaissance data from Fierce into hostnames and/or IP addresses.", "consumes": [ "boefje/fierce" ], diff --git a/boefjes/boefjes/plugins/kat_finding_normalizer/normalizer.json b/boefjes/boefjes/plugins/kat_finding_normalizer/normalizer.json index ec7e54b209c..70adfd46c47 100644 --- a/boefjes/boefjes/plugins/kat_finding_normalizer/normalizer.json +++ b/boefjes/boefjes/plugins/kat_finding_normalizer/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_generic_finding_normalize", + "name": "Finding types", "consumes": [ "openkat/finding" ], diff --git a/boefjes/boefjes/plugins/kat_green_hosting/boefje.json b/boefjes/boefjes/plugins/kat_green_hosting/boefje.json index 9fe34d17ae8..846b05efa33 100644 --- a/boefjes/boefjes/plugins/kat_green_hosting/boefje.json +++ b/boefjes/boefjes/plugins/kat_green_hosting/boefje.json @@ -1,7 +1,7 @@ { "id": "green-hosting", "name": "GreenHosting", - "description": "Use the Green Web Foundation Partner API to check whether the website is hosted on a green server. Meaning it runs on renewable energy and/or offsets its carbon footprint", + "description": "Use the Green Web Foundation Partner API to check whether the website is hosted on a green server. Meaning it runs on renewable energy and/or offsets its carbon footprint. Does not require an API key.", "consumes": [ "Website" ], diff --git a/boefjes/boefjes/plugins/kat_green_hosting/normalizer.json b/boefjes/boefjes/plugins/kat_green_hosting/normalizer.json index 993413d85e4..92434280db5 100644 --- a/boefjes/boefjes/plugins/kat_green_hosting/normalizer.json +++ b/boefjes/boefjes/plugins/kat_green_hosting/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_green_hosting_normalize", + "description": "Parses the Green Hosting output into findings.", "consumes": [ "boefje/green-hosting" ], diff --git a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json index 31ff5bed15b..23ec1b70da7 100644 --- a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json +++ b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json @@ -21,14 +21,14 @@ "recommendation": "This header is not supported by default by Mozilla. If this header is required for your environment: Set the HTTP header X-Permitted-Cross- Domain-Policies: none in all HTTP responses. Use value master-only if a Flash or Acrobat cross- domain configuration file is used that is placed in the root of the web server" }, "KAT-NO-EXPLICIT-XSS-PROTECTION": { - "description": "This is a deprecated header previously used to prevent against Cross-Site-Scripting attacks. Support in modern browsers could introduce XSS attacks again.", + "description": "The 'X-XSS-Protection' header is a deprecated header previously used to prevent against Cross-Site-Scripting attacks. Support in modern browsers could introduce XSS attacks again.", "source": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection", "risk": "recommendation", "impact": "Reflected cross-site scripting attacks may not be blocked.", - "recommendation": "This header is deprecated and should not be used." + "recommendation": "Remove the deprecated header to reduce the chance of XSS attacks." }, "KAT-NO-X-FRAME-OPTIONS": { - "description": "HTTP header 'X-Frame-Options' is missing. It is possible that the website can be loaded via an