From 6a9f4bf89b45a686531846e85d4983e77df17d36 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Wed, 8 Feb 2023 07:29:02 +0800 Subject: [PATCH 01/54] gql minimum characters restriction for consistent behavior with frontend --- src/specklepy/api/resources/branch.py | 5 +++++ src/specklepy/api/resources/stream.py | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/specklepy/api/resources/branch.py b/src/specklepy/api/resources/branch.py index 100423d..a861c87 100644 --- a/src/specklepy/api/resources/branch.py +++ b/src/specklepy/api/resources/branch.py @@ -5,6 +5,7 @@ from gql import gql from specklepy.api.models import Branch from specklepy.api.resource import ResourceBase from specklepy.logging import metrics +from specklepy.logging.exceptions import SpeckleException NAME = "branch" @@ -41,6 +42,10 @@ class Resource(ResourceBase): } """ ) + if len(name) < 3: + return SpeckleException( + message="Branch Name must be at least 3 characters" + ) params = { "branch": { "streamId": stream_id, diff --git a/src/specklepy/api/resources/stream.py b/src/specklepy/api/resources/stream.py index 6868f57..0eff18f 100644 --- a/src/specklepy/api/resources/stream.py +++ b/src/specklepy/api/resources/stream.py @@ -167,7 +167,10 @@ class Resource(ResourceBase): } """ ) - + if len(name) < 3 and len(name) != 0: + return SpeckleException( + message="Stream Name must be at least 3 characters" + ) params = { "stream": {"name": name, "description": description, "isPublic": is_public} } From 541e3d961fc7c7bd39ea54099bd5fd1588c4083d Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Tue, 19 Sep 2023 10:56:39 +0100 Subject: [PATCH 02/54] moving restrictions to core --- src/specklepy/api/resources/branch.py | 1 - src/specklepy/core/api/resources/branch.py | 5 +++++ src/specklepy/core/api/resources/stream.py | 5 ++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/specklepy/api/resources/branch.py b/src/specklepy/api/resources/branch.py index 11b5022..e913390 100644 --- a/src/specklepy/api/resources/branch.py +++ b/src/specklepy/api/resources/branch.py @@ -5,7 +5,6 @@ from gql import gql from specklepy.api.models import Branch from specklepy.api.resource import ResourceBase from specklepy.logging import metrics -from specklepy.logging.exceptions import SpeckleException from specklepy.core.api.resources.branch import Resource as CoreResource diff --git a/src/specklepy/core/api/resources/branch.py b/src/specklepy/core/api/resources/branch.py index 94f6d29..f69415a 100644 --- a/src/specklepy/core/api/resources/branch.py +++ b/src/specklepy/core/api/resources/branch.py @@ -4,6 +4,7 @@ from gql import gql from specklepy.core.api.models import Branch from specklepy.core.api.resource import ResourceBase +from specklepy.logging.exceptions import SpeckleException NAME = "branch" @@ -39,6 +40,10 @@ class Resource(ResourceBase): } """ ) + if len(name) < 3: + return SpeckleException( + message="Branch Name must be at least 3 characters" + ) params = { "branch": { "streamId": stream_id, diff --git a/src/specklepy/core/api/resources/stream.py b/src/specklepy/core/api/resources/stream.py index 40b866b..bd1f05f 100644 --- a/src/specklepy/core/api/resources/stream.py +++ b/src/specklepy/core/api/resources/stream.py @@ -163,7 +163,10 @@ class Resource(ResourceBase): } """ ) - + if len(name) < 3 and len(name) != 0: + return SpeckleException( + message="Stream Name must be at least 3 characters" + ) params = { "stream": {"name": name, "description": description, "isPublic": is_public} } From f254defc6b58bb4e06d4dbc8b3d1a992c2bba65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Tue, 19 Sep 2023 20:11:32 +0200 Subject: [PATCH 03/54] feat: add speckle automate package with some basic sanity tests --- poetry.lock | 194 ++++++------ pyproject.toml | 4 +- src/speckle_automate/__init__.py | 23 ++ src/speckle_automate/automation_context.py | 278 ++++++++++++++++++ src/speckle_automate/runner.py | 155 ++++++++++ src/speckle_automate/schema.py | 73 +++++ .../intergration/speckle_automate/__init__.py | 0 .../test_automation_context.py | 263 +++++++++++++++++ 8 files changed, 880 insertions(+), 110 deletions(-) create mode 100644 src/speckle_automate/__init__.py create mode 100644 src/speckle_automate/automation_context.py create mode 100644 src/speckle_automate/runner.py create mode 100644 src/speckle_automate/schema.py create mode 100644 tests/intergration/speckle_automate/__init__.py create mode 100644 tests/intergration/speckle_automate/test_automation_context.py diff --git a/poetry.lock b/poetry.lock index 7cbb0de..ea2c4e8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -11,8 +11,26 @@ files = [ {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, ] +[[package]] +name = "anyio" +version = "4.0.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.0.0-py3-none-any.whl", hash = "sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f"}, + {file = "anyio-4.0.0.tar.gz", hash = "sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a"}, +] + [package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.22)"] [[package]] name = "appdirs" @@ -36,9 +54,6 @@ files = [ {file = "argcomplete-2.0.6.tar.gz", hash = "sha256:dc33528d96727882b576b24bc89ed038f3c6abbb6855ff9bb6be23384afff9d6"}, ] -[package.dependencies] -importlib-metadata = {version = ">=0.23,<6", markers = "python_version == \"3.7\""} - [package.extras] lint = ["flake8", "mypy"] test = ["coverage", "flake8", "mypy", "pexpect", "wheel"] @@ -56,7 +71,6 @@ files = [ [package.dependencies] lazy-object-proxy = ">=1.4.0" -typed-ast = {version = ">=1.4.0,<2.0", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} wrapt = [ {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, @@ -91,9 +105,6 @@ files = [ {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, ] -[package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} - [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] dev = ["attrs[docs,tests]", "pre-commit"] @@ -139,7 +150,6 @@ mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] @@ -197,7 +207,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" @@ -461,8 +470,60 @@ files = [ {file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"}, ] +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "0.18.0" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-0.18.0-py3-none-any.whl", hash = "sha256:adc5398ee0a476567bf87467063ee63584a8bce86078bf748e48754f60202ced"}, + {file = "httpcore-0.18.0.tar.gz", hash = "sha256:13b5e5cd1dca1a6636a6aaea212b19f4f85cd88c366a2b82304181b769aab3c9"}, +] + [package.dependencies] -typing-extensions = {version = ">=4.2,<5", markers = "python_version < \"3.8\""} +anyio = ">=3.0,<5.0" +certifi = "*" +h11 = ">=0.13,<0.15" +sniffio = "==1.*" + +[package.extras] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "httpx" +version = "0.25.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.25.0-py3-none-any.whl", hash = "sha256:181ea7f8ba3a82578be86ef4171554dd45fec26a02556a744db029a0a27b7100"}, + {file = "httpx-0.25.0.tar.gz", hash = "sha256:47ecda285389cb32bb2691cc6e069e3ab0205956f681c5b2ad2325719751d875"}, +] + +[package.dependencies] +certifi = "*" +httpcore = ">=0.18.0,<0.19.0" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] [[package]] name = "identify" @@ -489,26 +550,6 @@ files = [ {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] -[[package]] -name = "importlib-metadata" -version = "5.2.0" -description = "Read metadata from Python packages" -optional = false -python-versions = ">=3.7" -files = [ - {file = "importlib_metadata-5.2.0-py3-none-any.whl", hash = "sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f"}, - {file = "importlib_metadata-5.2.0.tar.gz", hash = "sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd"}, -] - -[package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] - [[package]] name = "iniconfig" version = "2.0.0" @@ -788,7 +829,6 @@ files = [ [package.dependencies] mypy-extensions = ">=0.4.3" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} typing-extensions = ">=3.10" [package.extras] @@ -854,9 +894,6 @@ files = [ {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.8\""} - [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] @@ -872,9 +909,6 @@ files = [ {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, ] -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} - [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] @@ -893,7 +927,6 @@ files = [ [package.dependencies] cfgv = ">=2.0.0" identify = ">=1.0.0" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" @@ -1092,7 +1125,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" @@ -1287,6 +1319,17 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "sniffio" +version = "1.3.0" +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"}, +] + [[package]] name = "stringcase" version = "1.2.0" @@ -1333,56 +1376,6 @@ files = [ {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, ] -[[package]] -name = "typed-ast" -version = "1.5.5" -description = "a fork of Python 2 and 3 ast modules with type comment support" -optional = false -python-versions = ">=3.6" -files = [ - {file = "typed_ast-1.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b"}, - {file = "typed_ast-1.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686"}, - {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769"}, - {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04"}, - {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d"}, - {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d"}, - {file = "typed_ast-1.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02"}, - {file = "typed_ast-1.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee"}, - {file = "typed_ast-1.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18"}, - {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88"}, - {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2"}, - {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9"}, - {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8"}, - {file = "typed_ast-1.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b"}, - {file = "typed_ast-1.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5"}, - {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c"}, - {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa"}, - {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f"}, - {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d"}, - {file = "typed_ast-1.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5"}, - {file = "typed_ast-1.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e"}, - {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e"}, - {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311"}, - {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2"}, - {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4"}, - {file = "typed_ast-1.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431"}, - {file = "typed_ast-1.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a"}, - {file = "typed_ast-1.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437"}, - {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede"}, - {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4"}, - {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6"}, - {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4"}, - {file = "typed_ast-1.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b"}, - {file = "typed_ast-1.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10"}, - {file = "typed_ast-1.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814"}, - {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8"}, - {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274"}, - {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a"}, - {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba"}, - {file = "typed_ast-1.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155"}, - {file = "typed_ast-1.5.5.tar.gz", hash = "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd"}, -] - [[package]] name = "types-deprecated" version = "1.2.9.3" @@ -1545,7 +1538,6 @@ files = [ [package.dependencies] distlib = ">=0.3.6,<1" filelock = ">=3.4.1,<4" -importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.8\""} platformdirs = ">=2.4,<4" [package.extras] @@ -1811,24 +1803,8 @@ files = [ [package.dependencies] idna = ">=2.0" multidict = ">=4.0" -typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} - -[[package]] -name = "zipp" -version = "3.15.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -optional = false -python-versions = ">=3.7" -files = [ - {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, - {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "2.0" -python-versions = ">=3.7.2, <4.0" -content-hash = "68b9e18f308a957906221e252919436a88f414a96bba50969afaa73293caa7ea" +python-versions = ">=3.9.0, <4.0" +content-hash = "2c37066950fbf65bc5aacf7eaa24f527e3757aec8305b9de8adf9bef5e17e78d" diff --git a/pyproject.toml b/pyproject.toml index 923d39f..6048767 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,11 +10,12 @@ documentation = "https://speckle.guide/dev/py-examples.html" homepage = "https://speckle.systems/" packages = [ { include = "specklepy", from = "src" }, + { include = "speckle_automate", from = "src" }, ] [tool.poetry.dependencies] -python = ">=3.7.2, <4.0" +python = ">=3.9.0, <4.0" pydantic = "^2.0" appdirs = "^1.4.4" gql = {extras = ["requests", "websockets"], version = "^3.3.0"} @@ -22,6 +23,7 @@ ujson = "^5.3.0" Deprecated = "^1.2.13" stringcase = "^1.2.0" attrs = "^23.1.0" +httpx = "^0.25.0" [tool.poetry.group.dev.dependencies] black = "^22.8.0" diff --git a/src/speckle_automate/__init__.py b/src/speckle_automate/__init__.py new file mode 100644 index 0000000..be29deb --- /dev/null +++ b/src/speckle_automate/__init__.py @@ -0,0 +1,23 @@ +"""This module contains an SDK for working with Speckle Automate.""" +from speckle_automate.automation_context import AutomationContext +from speckle_automate.runner import execute_automate_function, run_function +from speckle_automate.schema import ( + AutomateBase, + AutomationResult, + AutomationRunData, + AutomationStatus, + ObjectResult, + ObjectResultLevel, +) + +__all__ = [ + "AutomationContext", + "AutomateBase", + "AutomationStatus", + "AutomationResult", + "AutomationRunData", + "ObjectResult", + "ObjectResultLevel", + "run_function", + "execute_automate_function", +] diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py new file mode 100644 index 0000000..ff9082f --- /dev/null +++ b/src/speckle_automate/automation_context.py @@ -0,0 +1,278 @@ +"""This module provides an abstraction layer above the Speckle Automate runtime.""" +from dataclasses import dataclass, field +from pathlib import Path +import time +from typing import Optional, Union + +import httpx +from gql import gql +from specklepy.api import operations +from specklepy.api.client import SpeckleClient +from specklepy.objects import Base +from specklepy.transports.memory import MemoryTransport +from specklepy.transports.server import ServerTransport + +from speckle_automate.schema import ( + AutomateBase, + AutomationResult, + AutomationRunData, + AutomationStatus, + ObjectResult, + ObjectResultLevel, +) + + +@dataclass +class AutomationContext: + """A context helper class. + + This class exposes methods to work with the Speckle Automate context inside + Speckle Automate functions. + + An instance of AutomationContext is injected into every run of a function. + """ + + automation_run_data: AutomationRunData + speckle_client: SpeckleClient + _server_transport: ServerTransport + _speckle_token: str + + #: keep a memory transponrt at hand, to speed up things if needed + _memory_transport: MemoryTransport = field(default_factory=MemoryTransport) + + #: added for performance measuring + _init_time: float = field(default_factory=time.perf_counter) + _automation_result: AutomationResult = field(default_factory=AutomationResult) + + @classmethod + def initialize( + cls, automation_run_data: Union[str, AutomationRunData], speckle_token: str + ) -> "AutomationContext": + """Bootstrap the AutomateSDK from raw data. + + Todo: + ---- + * bootstrap a structlog logger instance + * expose a logger, that ppl can use instead of print + """ + # parse the json value if its not an initialized project data instance + automation_run_data = ( + automation_run_data + if isinstance(automation_run_data, AutomationRunData) + else AutomationRunData.model_validate_json(automation_run_data) + ) + speckle_client = SpeckleClient( + automation_run_data.speckle_server_url, + automation_run_data.speckle_server_url.startswith("https"), + ) + speckle_client.authenticate_with_token(speckle_token) + if not speckle_client.account: + msg = ( + f"Could not autenticate to {automation_run_data.speckle_server_url}", + "with the provided token", + ) + raise ValueError(msg) + server_transport = ServerTransport( + automation_run_data.project_id, speckle_client + ) + return cls(automation_run_data, speckle_client, server_transport, speckle_token) + + @property + def run_status(self) -> AutomationStatus: + """Get the status of the automation run.""" + return self._automation_result.run_status + + def elapsed(self) -> float: + """Return the elapsed time in seconds since the initialization time.""" + return time.perf_counter() - self._init_time + + def receive_version(self) -> Base: + """Receive the Speckle project version that triggered this automation run.""" + commit = self.speckle_client.commit.get( + self.automation_run_data.project_id, self.automation_run_data.version_id + ) + if not commit.referencedObject: + raise ValueError("The commit has no referencedObject, cannot receive it.") + base = operations.receive( + commit.referencedObject, self._server_transport, self._memory_transport + ) + print( + f"It took {self.elapsed():2f} seconds to receive", + f" the speckle version {self.automation_run_data.version_id}", + ) + return base + + def create_new_version_in_project( + self, root_object: Base, model_id: str, version_message: str = "" + ) -> None: + """Save a base model to a new version on the project. + + Args: + root_object (Base): The Speckle base object for the new version. + model_id (str): For now please use a `branchName`! + version_message (str): The message for the new version. + """ + if model_id == self.automation_run_data.model_id: + raise ValueError( + f"The target model id: {model_id} cannot match the model id" + f" that triggered this automation: {self.automation_run_data.model_id}" + ) + + root_object_id = operations.send( + root_object, + [self._server_transport, self._memory_transport], + use_default_cache=False, + ) + + version_id = self.speckle_client.commit.create( + stream_id=self.automation_run_data.project_id, + object_id=root_object_id, + branch_name=model_id, + message=version_message, + source_application="SpeckleAutomate", + ) + self._automation_result.result_versions.append(version_id) + + def report_run_status(self) -> None: + """Report the current run status to the project of this automation.""" + query = gql( + """ + mutation ReportFunctionRunStatus( + $automationId: String!, + $automationRevisionId: String!, + $automationRunId: String!, + $versionId: String!, + $functionId: String!, + $runStatus: AutomationRunStatus! + $elapsed: Float! + $resultVersionIds: [String!]! + $statusMessage: String + $objectResults: JSONObject + ){ + automationMutations { + functionRunStatusReport(input: { + automationId: $automationId + automationRevisionId: $automationRevisionId + automationRunId: $automationRunId + versionId: $versionId + functionRuns: [ + { + functionId: $functionId + status: $runStatus, + elapsed: $elapsed, + resultVersionIds: $resultVersionIds, + statusMessage: $statusMessage + results: $objectResults + }] + }) + } + } + """ + ) + if self.run_status in [AutomationStatus.SUCCEEDED, AutomationStatus.FAILED]: + object_results = { + "version": "1.0.0", + "values": { + "speckleObjects": self._automation_result.model_dump(by_alias=True)[ + "objectResults" + ], + "blobs": self._automation_result.blobs, + }, + } + else: + object_results = None + params = { + "automationId": self.automation_run_data.automation_id, + "automationRevisionId": self.automation_run_data.automation_revision_id, + "automationRunId": self.automation_run_data.automation_run_id, + "versionId": self.automation_run_data.version_id, + "functionId": self.automation_run_data.function_id, + "runStatus": self.run_status.value, + "statusMessage": self._automation_result.status_message, + "elapsed": self.elapsed(), + "resultVersionIds": self._automation_result.result_versions, + "objectResults": object_results, + } + self.speckle_client.httpclient.execute(query, params) + + def store_file_result(self, file_path: Union[Path, str]) -> None: + """Save a file attached to the project of this automation.""" + path_obj = ( + Path(file_path).resolve() if isinstance(file_path, str) else file_path + ) + + class UploadResult(AutomateBase): + blob_id: str + file_name: str + upload_status: int + + class BlobUploadResponse(AutomateBase): + upload_results: list[UploadResult] + + if not path_obj.exists(): + raise ValueError("The given file path doesn't exist") + files = {path_obj.name: open(str(path_obj), "rb")} + + url = ( + f"{self.automation_run_data.speckle_server_url}/api/stream/" + f"{self.automation_run_data.project_id}/blob" + ) + data = ( + httpx.post( + url, + files=files, + headers={"authorization": f"Bearer {self._speckle_token}"}, + ) + .raise_for_status() + .json() + ) + + upload_response = BlobUploadResponse.model_validate(data) + + if len(upload_response.upload_results) != 1: + raise ValueError("Expecting one upload result.") + + for upload_result in upload_response.upload_results: + self._automation_result.blobs.append(upload_result.blob_id) + + def mark_run_failed(self, status_message: str) -> None: + """Mark the current run a failure.""" + self._mark_run(AutomationStatus.FAILED, status_message) + + def mark_run_success(self, status_message: Optional[str]) -> None: + """Mark the current run a success with an optional message.""" + self._mark_run(AutomationStatus.SUCCEEDED, status_message) + + def _mark_run( + self, status: AutomationStatus, status_message: Optional[str] + ) -> None: + duration = self.elapsed() + self._automation_result.status_message = status_message + self._automation_result.run_status = status + self._automation_result.elapsed = duration + + msg = f"Automation run {status.value} after {duration:2f} seconds." + print("\n".join([msg, status_message]) if status_message else msg) + + def add_object_error(self, object_id: str, error_cause: str) -> None: + """Add an error to a given Speckle object.""" + self._add_object_result(object_id, ObjectResultLevel.ERROR, error_cause) + + def add_object_warning(self, object_id: str, warning: str) -> None: + """Add a warning to a given Speckle object.""" + self._add_object_result(object_id, ObjectResultLevel.WARNING, warning) + + def add_object_info(self, object_id: str, info: str) -> None: + """Add an info message to a given Speckle object.""" + self._add_object_result(object_id, ObjectResultLevel.INFO, info) + + def _add_object_result( + self, object_id: str, level: ObjectResultLevel, status_message: str + ) -> None: + print( + f"Object {object_id} was marked with {level.value.upper()}", + f" cause: {status_message}", + ) + self._automation_result.object_results[object_id].append( + ObjectResult(level=level, status_message=status_message) + ) diff --git a/src/speckle_automate/runner.py b/src/speckle_automate/runner.py new file mode 100644 index 0000000..90c91b9 --- /dev/null +++ b/src/speckle_automate/runner.py @@ -0,0 +1,155 @@ +"""Function execution module. + +Provides mechanisms to execute any function, + that conforms to the AutomateFunction "interface" +""" +import json +import os +import sys +import traceback +from pathlib import Path +from typing import Callable, Optional, TypeVar, Union, overload + +from speckle_automate.automation_context import AutomationContext +from speckle_automate.schema import AutomateBase, AutomationRunData, AutomationStatus + +T = TypeVar("T", bound=AutomateBase) + +AutomateFunction = Callable[[AutomationContext, T], None] +AutomateFunctionWithoutInputs = Callable[[AutomationContext], None] + + +@overload +def execute_automate_function( + automate_function: AutomateFunction[T], + input_schema: type[T], +) -> None: + ... + + +@overload +def execute_automate_function(automate_function: AutomateFunctionWithoutInputs) -> None: + ... + + +def execute_automate_function( + automate_function: Union[AutomateFunction[T], AutomateFunctionWithoutInputs], + input_schema: Optional[type[T]] = None, +): + """Runs the provided automate function with the input schema.""" + # first arg is the python file name, we do not need that + args = sys.argv[1:] + + if len(args) < 2: + raise ValueError("too few arguments specified need minimum 2") + + if len(args) > 4: + raise ValueError("too many arguments specified, max supported is 4") + + # we rely on a command name convention to decide what to do. + # this is here, so that the function authors do not see any of this + command = args[0] + + if command == "generate_schema": + path = Path(args[1]) + schema = json.dumps( + input_schema.model_json_schema(by_alias=True) if input_schema else {} + ) + path.write_text(schema) + + elif command == "run": + automation_run_data = args[1] + function_inputs = args[2] + + speckle_token = os.environ.get("SPECKLE_TOKEN", None) + if not speckle_token and len(args) != 4: + raise ValueError("Cannot get speckle token from arguments or environment") + + speckle_token = speckle_token if speckle_token else args[3] + + inputs = ( + input_schema.model_validate_json(function_inputs) + if input_schema + else input_schema + ) + + if inputs: + automation_context = run_function( + automate_function, # type: ignore + automation_run_data, + speckle_token, + inputs, + ) + else: + automation_context = run_function( + automate_function, # type: ignore + automation_run_data, + speckle_token, + ) + + exit_code = ( + 0 if automation_context.run_status == AutomationStatus.SUCCEEDED else 1 + ) + exit(exit_code) + + else: + raise NotImplementedError(f"Command: '{command}' is not supported.") + + +@overload +def run_function( + automate_function: AutomateFunction[T], + automation_run_data: Union[AutomationRunData, str], + speckle_token: str, + inputs: T, +) -> AutomationContext: + ... + + +@overload +def run_function( + automate_function: AutomateFunctionWithoutInputs, + automation_run_data: Union[AutomationRunData, str], + speckle_token: str, +) -> AutomationContext: + ... + + +def run_function( + automate_function: Union[AutomateFunction[T], AutomateFunctionWithoutInputs], + automation_run_data: Union[AutomationRunData, str], + speckle_token: str, + inputs: Optional[T] = None, +) -> AutomationContext: + """Run the provided function with the automate sdk context.""" + automation_context = AutomationContext.initialize( + automation_run_data, speckle_token + ) + automation_context.report_run_status() + + try: + # avoiding complex type gymnastics here on the internals. + # the external type overloads make this correct + if inputs: + automate_function(automation_context, inputs) # type: ignore + else: + automate_function(automation_context) # type: ignore + + # the function author forgot to mark the function success + if automation_context.run_status not in [ + AutomationStatus.FAILED, + AutomationStatus.SUCCEEDED, + ]: + automation_context.mark_run_success( + "WARNING: Automate assumed a success status," + " but it was not marked as so by the function." + ) + except Exception: + trace = traceback.format_exc() + print(trace) + automation_context.mark_run_failed( + "Function error. Check the automation run logs for details." + ) + finally: + automation_context.report_run_status() + return automation_context diff --git a/src/speckle_automate/schema.py b/src/speckle_automate/schema.py new file mode 100644 index 0000000..7309b86 --- /dev/null +++ b/src/speckle_automate/schema.py @@ -0,0 +1,73 @@ +"""""" +from collections import defaultdict +from enum import Enum +from typing import Optional + +from pydantic import BaseModel, ConfigDict, Field +from stringcase import camelcase + + +class AutomateBase(BaseModel): + """Use this class as a base model for automate related DTO.""" + + model_config = ConfigDict(alias_generator=camelcase, populate_by_name=True) + + +class AutomationRunData(BaseModel): + """Values of the project / model that triggered the run of this function.""" + + project_id: str + model_id: str + branch_name: str + version_id: str + speckle_server_url: str + + automation_id: str + automation_revision_id: str + automation_run_id: str + + function_id: str + function_revision: str + + model_config = ConfigDict( + alias_generator=camelcase, populate_by_name=True, protected_namespaces=() + ) + + +class AutomationStatus(str, Enum): + """Set the status of the automation.""" + + INITIALIZING = "INITIALIZING" + RUNNING = "RUNNING" + FAILED = "FAILED" + SUCCEEDED = "SUCCEEDED" + + +class ObjectResultLevel(str, Enum): + """Possible status message levels for object reports.""" + + INFO = "INFO" + WARNING = "WARNING" + ERROR = "ERROR" + + +class ObjectResult(AutomateBase): + """An object level result.""" + + level: ObjectResultLevel + status_message: str + + +class AutomationResult(AutomateBase): + """Schema accepted by the Speckle server as a result for an automation run.""" + + elapsed: float = 0 + result_view: Optional[str] = None + result_versions: list[str] = Field(default_factory=list) + blobs: list[str] = Field(default_factory=list) + run_status: AutomationStatus = AutomationStatus.RUNNING + status_message: Optional[str] = None + + object_results: dict[str, list[ObjectResult]] = Field( + default_factory=lambda: defaultdict(list) # typing: ignore + ) diff --git a/tests/intergration/speckle_automate/__init__.py b/tests/intergration/speckle_automate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/intergration/speckle_automate/test_automation_context.py b/tests/intergration/speckle_automate/test_automation_context.py new file mode 100644 index 0000000..9923d0b --- /dev/null +++ b/tests/intergration/speckle_automate/test_automation_context.py @@ -0,0 +1,263 @@ +"""Run integration tests with a speckle server.""" +import os +import secrets +import string +from pathlib import Path +from typing import Dict + +import pytest +from gql import gql +from speckle_automate.schema import AutomateBase +from specklepy.api import operations +from specklepy.api.client import SpeckleClient +from specklepy.objects.base import Base +from specklepy.transports.server import ServerTransport + +from speckle_automate import ( + AutomationContext, + AutomationRunData, + AutomationStatus, + run_function, +) + + +def crypto_random_string(length: int) -> str: + """Generate a semi crypto random string of a given length.""" + alphabet = string.ascii_letters + string.digits + return "".join(secrets.choice(alphabet) for _ in range(length)) + + +def register_new_automation( + project_id: str, + model_id: str, + speckle_client: SpeckleClient, + automation_id: str, + automation_name: str, + automation_revision_id: str, +): + """Register a new automation in the speckle server.""" + query = gql( + """ + mutation CreateAutomation( + $projectId: String! + $modelId: String! + $automationName: String! + $automationId: String! + $automationRevisionId: String! + ) { + automationMutations { + create( + input: { + projectId: $projectId + modelId: $modelId + automationName: $automationName + automationId: $automationId + automationRevisionId: $automationRevisionId + } + ) + } + } + """ + ) + params = { + "projectId": project_id, + "modelId": model_id, + "automationName": automation_name, + "automationId": automation_id, + "automationRevisionId": automation_revision_id, + } + speckle_client.httpclient.execute(query, params) + + +@pytest.fixture() +def speckle_token(user_dict: Dict[str, str]) -> str: + """Provide a speckle token for the test suite.""" + return user_dict["token"] + + +@pytest.fixture() +def speckle_server_url(host: str) -> str: + """Provide a speckle server url for the test suite, default to localhost.""" + return f"http://{host}" + + +@pytest.fixture() +def test_client(speckle_server_url: str, speckle_token: str) -> SpeckleClient: + """Initialize a SpeckleClient for testing.""" + test_client = SpeckleClient(speckle_server_url, use_ssl=False) + test_client.authenticate_with_token(speckle_token) + return test_client + + +@pytest.fixture() +def test_object() -> Base: + """Create a Base model for testing.""" + root_object = Base() + root_object.foo = "bar" + return root_object + + +@pytest.fixture() +def automation_run_data( + test_object: Base, test_client: SpeckleClient, speckle_server_url: str +) -> AutomationRunData: + """Set up an automation context for testing.""" + project_id = test_client.stream.create("Automate function e2e test") + branch_name = "main" + + model = test_client.branch.get(project_id, branch_name, commits_limit=1) + model_id: str = model.id + + root_obj_id = operations.send( + test_object, [ServerTransport(project_id, test_client)] + ) + version_id = test_client.commit.create(project_id, root_obj_id) + + automation_name = crypto_random_string(10) + automation_id = crypto_random_string(10) + automation_revision_id = crypto_random_string(10) + + register_new_automation( + project_id, + model_id, + test_client, + automation_id, + automation_name, + automation_revision_id, + ) + + automation_run_id = crypto_random_string(10) + function_id = crypto_random_string(10) + function_revision = crypto_random_string(10) + return AutomationRunData( + project_id=project_id, + model_id=model_id, + branch_name=branch_name, + version_id=version_id, + speckle_server_url=speckle_server_url, + automation_id=automation_id, + automation_revision_id=automation_revision_id, + automation_run_id=automation_run_id, + function_id=function_id, + function_revision=function_revision, + ) + + +def get_automation_status( + project_id: str, + model_id: str, + speckle_client: SpeckleClient, +): + query = gql( + """ +query AutomationRuns( + $projectId: String! + $modelId: String! + ) +{ + project(id: $projectId) { + model(id: $modelId) { + automationStatus { + id + status + statusMessage + automationRuns { + id + automationId + versionId + createdAt + updatedAt + status + functionRuns { + id + functionId + elapsed + status + contextView + statusMessage + results + resultVersions { + id + } + } + } + } + } + } +} + """ + ) + params = { + "projectId": project_id, + "modelId": model_id, + } + response = speckle_client.httpclient.execute(query, params) + return response["project"]["model"]["automationStatus"] + + +class FunctionInputs(AutomateBase): + forbidden_speckle_type: str + + +def automate_function( + automate_context: AutomationContext, + function_inputs: FunctionInputs, +) -> None: + """Hey, trying the automate sdk experience here.""" + version_root_object = automate_context.receive_version() + + count = 0 + if version_root_object.speckle_type == function_inputs.forbidden_speckle_type: + if not version_root_object.id: + raise ValueError("Cannot operate on objects without their id's.") + automate_context.add_object_error( + version_root_object.id, + "This project should not contain the type: " + f"{function_inputs.forbidden_speckle_type}", + ) + count += 1 + + if count > 0: + automate_context.mark_run_failed( + "Automation failed: " + f"Found {count} object that have a forbidden speckle type: " + f"{function_inputs.forbidden_speckle_type}" + ) + + else: + automate_context.mark_run_success("No forbidden types found.") + + +def test_function_run(automation_run_data: AutomationRunData, speckle_token: str): + """Run an integration test for the automate function.""" + automation_context = run_function( + automate_function, + automation_run_data, + speckle_token, + FunctionInputs(forbidden_speckle_type="Base"), + ) + + assert automation_context.run_status == AutomationStatus.FAILED + status = get_automation_status( + automation_run_data.project_id, + automation_run_data.model_id, + automation_context.speckle_client, + ) + assert status["status"] == automation_context.run_status + status_message = status["automationRuns"][0]["functionRuns"][0]["statusMessage"] + assert status_message == automation_context._automation_result.status_message + + +def test_file_uploads(automation_run_data: AutomationRunData, speckle_token: str): + """Test file store capabilities of the automate sdk.""" + automation_context = AutomationContext.initialize( + automation_run_data, speckle_token + ) + + path = Path(f"./{crypto_random_string(10)}").resolve() + path.write_text("foobar") + + automation_context.store_file_result(path) + + os.remove(path) + assert len(automation_context._automation_result.blobs) == 1 From 2e8943e96124b3e7e6850f8120023a445c1fe727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Tue, 19 Sep 2023 20:18:47 +0200 Subject: [PATCH 04/54] feat: test against latest --- docker-compose.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1649742..ec52659 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,7 +53,7 @@ services: # Speckle Server ####### speckle-frontend: - image: speckle/speckle-frontend:2 + image: speckle/speckle-frontend:latest restart: always ports: - "0.0.0.0:8080:8080" @@ -61,7 +61,7 @@ services: FILE_SIZE_LIMIT_MB: 100 speckle-server: - image: speckle/speckle-server:2 + image: speckle/speckle-server:latest restart: always healthcheck: test: @@ -112,7 +112,7 @@ services: ENABLE_MP: "false" preview-service: - image: speckle/speckle-preview-service:2 + image: speckle/speckle-preview-service:latest restart: always depends_on: speckle-server: @@ -124,7 +124,7 @@ services: PG_CONNECTION_STRING: "postgres://speckle:speckle@postgres/speckle" webhook-service: - image: speckle/speckle-webhook-service:2 + image: speckle/speckle-webhook-service:latest restart: always depends_on: speckle-server: @@ -135,7 +135,7 @@ services: WAIT_HOSTS: postgres:5432 fileimport-service: - image: speckle/speckle-fileimport-service:2 + image: speckle/speckle-fileimport-service:latest restart: always depends_on: speckle-server: From e4d087db3abdbcc9f8b7032ebd4bc0c1f88937cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Tue, 19 Sep 2023 20:21:46 +0200 Subject: [PATCH 05/54] fix: we still support py38 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6048767..2857319 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ packages = [ [tool.poetry.dependencies] -python = ">=3.9.0, <4.0" +python = ">=3.8.0, <4.0" pydantic = "^2.0" appdirs = "^1.4.4" gql = {extras = ["requests", "websockets"], version = "^3.3.0"} From 8ffe21911150171cf14d0119d67cfc55349ed39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Tue, 19 Sep 2023 20:22:57 +0200 Subject: [PATCH 06/54] chore: update deps --- poetry.lock | 354 +++++++++++++++++++++++++--------------------------- 1 file changed, 173 insertions(+), 181 deletions(-) diff --git a/poetry.lock b/poetry.lock index ea2c4e8..f6a6c9f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -11,6 +11,9 @@ files = [ {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + [[package]] name = "anyio" version = "4.0.0" @@ -79,17 +82,17 @@ wrapt = [ [[package]] name = "asttokens" -version = "2.2.1" +version = "2.4.0" description = "Annotate AST trees with source code positions" optional = false python-versions = "*" files = [ - {file = "asttokens-2.2.1-py2.py3-none-any.whl", hash = "sha256:6b0ac9e93fb0335014d382b8fa9b3afa7df546984258005da0b9e7095b3deb1c"}, - {file = "asttokens-2.2.1.tar.gz", hash = "sha256:4622110b2a6f30b77e1473affaa97e711bc2f07d3f10848420ff1898edbe94f3"}, + {file = "asttokens-2.4.0-py2.py3-none-any.whl", hash = "sha256:cf8fc9e61a86461aa9fb161a14a0841a03c405fa829ac6b202670b3495d2ce69"}, + {file = "asttokens-2.4.0.tar.gz", hash = "sha256:2e0171b991b2c959acc6c49318049236844a5da1d65ba2672c4880c1c894834e"}, ] [package.dependencies] -six = "*" +six = ">=1.12.0" [package.extras] test = ["astroid", "pytest"] @@ -171,13 +174,13 @@ files = [ [[package]] name = "cfgv" -version = "3.3.1" +version = "3.4.0" description = "Validate configuration and produce human readable error messages." optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.8" files = [ - {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, - {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, ] [[package]] @@ -245,71 +248,63 @@ typing-extensions = ">=4.0.1,<5.0.0" [[package]] name = "coverage" -version = "7.2.7" +version = "7.3.1" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, - {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, - {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, - {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, - {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, - {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, - {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, - {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, - {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, - {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, - {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, - {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, - {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, - {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, - {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, - {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, - {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, - {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, + {file = "coverage-7.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cd0f7429ecfd1ff597389907045ff209c8fdb5b013d38cfa7c60728cb484b6e3"}, + {file = "coverage-7.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:966f10df9b2b2115da87f50f6a248e313c72a668248be1b9060ce935c871f276"}, + {file = "coverage-7.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0575c37e207bb9b98b6cf72fdaaa18ac909fb3d153083400c2d48e2e6d28bd8e"}, + {file = "coverage-7.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:245c5a99254e83875c7fed8b8b2536f040997a9b76ac4c1da5bff398c06e860f"}, + {file = "coverage-7.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c96dd7798d83b960afc6c1feb9e5af537fc4908852ef025600374ff1a017392"}, + {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:de30c1aa80f30af0f6b2058a91505ea6e36d6535d437520067f525f7df123887"}, + {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:50dd1e2dd13dbbd856ffef69196781edff26c800a74f070d3b3e3389cab2600d"}, + {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9c0c19f70d30219113b18fe07e372b244fb2a773d4afde29d5a2f7930765136"}, + {file = "coverage-7.3.1-cp310-cp310-win32.whl", hash = "sha256:770f143980cc16eb601ccfd571846e89a5fe4c03b4193f2e485268f224ab602f"}, + {file = "coverage-7.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:cdd088c00c39a27cfa5329349cc763a48761fdc785879220d54eb785c8a38520"}, + {file = "coverage-7.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74bb470399dc1989b535cb41f5ca7ab2af561e40def22d7e188e0a445e7639e3"}, + {file = "coverage-7.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:025ded371f1ca280c035d91b43252adbb04d2aea4c7105252d3cbc227f03b375"}, + {file = "coverage-7.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6191b3a6ad3e09b6cfd75b45c6aeeffe7e3b0ad46b268345d159b8df8d835f9"}, + {file = "coverage-7.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7eb0b188f30e41ddd659a529e385470aa6782f3b412f860ce22b2491c89b8593"}, + {file = "coverage-7.3.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75c8f0df9dfd8ff745bccff75867d63ef336e57cc22b2908ee725cc552689ec8"}, + {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7eb3cd48d54b9bd0e73026dedce44773214064be93611deab0b6a43158c3d5a0"}, + {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ac3c5b7e75acac31e490b7851595212ed951889918d398b7afa12736c85e13ce"}, + {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b4ee7080878077af0afa7238df1b967f00dc10763f6e1b66f5cced4abebb0a3"}, + {file = "coverage-7.3.1-cp311-cp311-win32.whl", hash = "sha256:229c0dd2ccf956bf5aeede7e3131ca48b65beacde2029f0361b54bf93d36f45a"}, + {file = "coverage-7.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c6f55d38818ca9596dc9019eae19a47410d5322408140d9a0076001a3dcb938c"}, + {file = "coverage-7.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5289490dd1c3bb86de4730a92261ae66ea8d44b79ed3cc26464f4c2cde581fbc"}, + {file = "coverage-7.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ca833941ec701fda15414be400c3259479bfde7ae6d806b69e63b3dc423b1832"}, + {file = "coverage-7.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd694e19c031733e446c8024dedd12a00cda87e1c10bd7b8539a87963685e969"}, + {file = "coverage-7.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aab8e9464c00da5cb9c536150b7fbcd8850d376d1151741dd0d16dfe1ba4fd26"}, + {file = "coverage-7.3.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87d38444efffd5b056fcc026c1e8d862191881143c3aa80bb11fcf9dca9ae204"}, + {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8a07b692129b8a14ad7a37941a3029c291254feb7a4237f245cfae2de78de037"}, + {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2829c65c8faaf55b868ed7af3c7477b76b1c6ebeee99a28f59a2cb5907a45760"}, + {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f111a7d85658ea52ffad7084088277135ec5f368457275fc57f11cebb15607f"}, + {file = "coverage-7.3.1-cp312-cp312-win32.whl", hash = "sha256:c397c70cd20f6df7d2a52283857af622d5f23300c4ca8e5bd8c7a543825baa5a"}, + {file = "coverage-7.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:5ae4c6da8b3d123500f9525b50bf0168023313963e0e2e814badf9000dd6ef92"}, + {file = "coverage-7.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca70466ca3a17460e8fc9cea7123c8cbef5ada4be3140a1ef8f7b63f2f37108f"}, + {file = "coverage-7.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f2781fd3cabc28278dc982a352f50c81c09a1a500cc2086dc4249853ea96b981"}, + {file = "coverage-7.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6407424621f40205bbe6325686417e5e552f6b2dba3535dd1f90afc88a61d465"}, + {file = "coverage-7.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:04312b036580ec505f2b77cbbdfb15137d5efdfade09156961f5277149f5e344"}, + {file = "coverage-7.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9ad38204887349853d7c313f53a7b1c210ce138c73859e925bc4e5d8fc18e7"}, + {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:53669b79f3d599da95a0afbef039ac0fadbb236532feb042c534fbb81b1a4e40"}, + {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:614f1f98b84eb256e4f35e726bfe5ca82349f8dfa576faabf8a49ca09e630086"}, + {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1a317fdf5c122ad642db8a97964733ab7c3cf6009e1a8ae8821089993f175ff"}, + {file = "coverage-7.3.1-cp38-cp38-win32.whl", hash = "sha256:defbbb51121189722420a208957e26e49809feafca6afeef325df66c39c4fdb3"}, + {file = "coverage-7.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:f4f456590eefb6e1b3c9ea6328c1e9fa0f1006e7481179d749b3376fc793478e"}, + {file = "coverage-7.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f12d8b11a54f32688b165fd1a788c408f927b0960984b899be7e4c190ae758f1"}, + {file = "coverage-7.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f09195dda68d94a53123883de75bb97b0e35f5f6f9f3aa5bf6e496da718f0cb6"}, + {file = "coverage-7.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6601a60318f9c3945be6ea0f2a80571f4299b6801716f8a6e4846892737ebe4"}, + {file = "coverage-7.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d156269718670d00a3b06db2288b48527fc5f36859425ff7cec07c6b367745"}, + {file = "coverage-7.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:636a8ac0b044cfeccae76a36f3b18264edcc810a76a49884b96dd744613ec0b7"}, + {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5d991e13ad2ed3aced177f524e4d670f304c8233edad3210e02c465351f785a0"}, + {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:586649ada7cf139445da386ab6f8ef00e6172f11a939fc3b2b7e7c9082052fa0"}, + {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4aba512a15a3e1e4fdbfed2f5392ec221434a614cc68100ca99dcad7af29f3f8"}, + {file = "coverage-7.3.1-cp39-cp39-win32.whl", hash = "sha256:6bc6f3f4692d806831c136c5acad5ccedd0262aa44c087c46b7101c77e139140"}, + {file = "coverage-7.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:553d7094cb27db58ea91332e8b5681bac107e7242c23f7629ab1316ee73c4981"}, + {file = "coverage-7.3.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:220eb51f5fb38dfdb7e5d54284ca4d0cd70ddac047d750111a68ab1798945194"}, + {file = "coverage-7.3.1.tar.gz", hash = "sha256:6cb7fe1581deb67b782c153136541e20901aa312ceedaf1467dcb35255787952"}, ] [package.dependencies] @@ -416,18 +411,19 @@ files = [ [[package]] name = "filelock" -version = "3.12.2" +version = "3.12.4" description = "A platform independent file lock." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, + {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, + {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] +typing = ["typing-extensions (>=4.7.1)"] [[package]] name = "gql" @@ -527,13 +523,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "identify" -version = "2.5.24" +version = "2.5.29" description = "File identification library for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"}, - {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"}, + {file = "identify-2.5.29-py2.py3-none-any.whl", hash = "sha256:24437fbf6f4d3fe6efd0eb9d67e24dd9106db99af5ceb27996a5f7895f24bf1b"}, + {file = "identify-2.5.29.tar.gz", hash = "sha256:d43d52b86b15918c137e3a74fff5224f60385cd0e9c38e99d07c257f02f151a5"}, ] [package.extras] @@ -563,17 +559,17 @@ files = [ [[package]] name = "isort" -version = "5.11.5" +version = "5.12.0" description = "A Python utility / library to sort Python imports." optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" files = [ - {file = "isort-5.11.5-py3-none-any.whl", hash = "sha256:ba1d72fb2595a01c7895a5128f9585a5cc4b6d395f1c8d514989b9a7eb2a8746"}, - {file = "isort-5.11.5.tar.gz", hash = "sha256:6be1f76a507cb2ecf16c7cf14a37e41609ca082330be4e3436a18ef74add55db"}, + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, ] [package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] +colors = ["colorama (>=0.4.3)"] pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] plugins = ["setuptools"] requirements-deprecated-finder = ["pip-api", "pipreqs"] @@ -900,13 +896,13 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co [[package]] name = "pluggy" -version = "1.2.0" +version = "1.3.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, ] [package.extras] @@ -1113,13 +1109,13 @@ testutils = ["gitpython (>3)"] [[package]] name = "pytest" -version = "7.4.0" +version = "7.4.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, - {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, + {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, + {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, ] [package.dependencies] @@ -1294,19 +1290,19 @@ files = [ [[package]] name = "setuptools" -version = "68.0.0" +version = "68.2.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, - {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, + {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, + {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +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-hoverxref (<2)", "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-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "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"] [[package]] name = "six" @@ -1425,87 +1421,83 @@ files = [ [[package]] name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] [[package]] name = "ujson" -version = "5.7.0" +version = "5.8.0" description = "Ultra fast JSON encoder and decoder for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "ujson-5.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5eba5e69e4361ac3a311cf44fa71bc619361b6e0626768a494771aacd1c2f09b"}, - {file = "ujson-5.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aae4d9e1b4c7b61780f0a006c897a4a1904f862fdab1abb3ea8f45bd11aa58f3"}, - {file = "ujson-5.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2e43ccdba1cb5c6d3448eadf6fc0dae7be6c77e357a3abc968d1b44e265866d"}, - {file = "ujson-5.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54384ce4920a6d35fa9ea8e580bc6d359e3eb961fa7e43f46c78e3ed162d56ff"}, - {file = "ujson-5.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24ad1aa7fc4e4caa41d3d343512ce68e41411fb92adf7f434a4d4b3749dc8f58"}, - {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:afff311e9f065a8f03c3753db7011bae7beb73a66189c7ea5fcb0456b7041ea4"}, - {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e80f0d03e7e8646fc3d79ed2d875cebd4c83846e129737fdc4c2532dbd43d9e"}, - {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:137831d8a0db302fb6828ee21c67ad63ac537bddc4376e1aab1c8573756ee21c"}, - {file = "ujson-5.7.0-cp310-cp310-win32.whl", hash = "sha256:7df3fd35ebc14dafeea031038a99232b32f53fa4c3ecddb8bed132a43eefb8ad"}, - {file = "ujson-5.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:af4639f684f425177d09ae409c07602c4096a6287027469157bfb6f83e01448b"}, - {file = "ujson-5.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b0f2680ce8a70f77f5d70aaf3f013d53e6af6d7058727a35d8ceb4a71cdd4e9"}, - {file = "ujson-5.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a19fd8e7d8cc58a169bea99fed5666023adf707a536d8f7b0a3c51dd498abf"}, - {file = "ujson-5.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6abb8e6d8f1ae72f0ed18287245f5b6d40094e2656d1eab6d99d666361514074"}, - {file = "ujson-5.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8cd622c069368d5074bd93817b31bdb02f8d818e57c29e206f10a1f9c6337dd"}, - {file = "ujson-5.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14f9082669f90e18e64792b3fd0bf19f2b15e7fe467534a35ea4b53f3bf4b755"}, - {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d7ff6ebb43bc81b057724e89550b13c9a30eda0f29c2f506f8b009895438f5a6"}, - {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f7f241488879d91a136b299e0c4ce091996c684a53775e63bb442d1a8e9ae22a"}, - {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5593263a7fcfb934107444bcfba9dde8145b282de0ee9f61e285e59a916dda0f"}, - {file = "ujson-5.7.0-cp311-cp311-win32.whl", hash = "sha256:26c2b32b489c393106e9cb68d0a02e1a7b9d05a07429d875c46b94ee8405bdb7"}, - {file = "ujson-5.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:ed24406454bb5a31df18f0a423ae14beb27b28cdfa34f6268e7ebddf23da807e"}, - {file = "ujson-5.7.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18679484e3bf9926342b1c43a3bd640f93a9eeeba19ef3d21993af7b0c44785d"}, - {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee295761e1c6c30400641f0a20d381633d7622633cdf83a194f3c876a0e4b7e"}, - {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b738282e12a05f400b291966630a98d622da0938caa4bc93cf65adb5f4281c60"}, - {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00343501dbaa5172e78ef0e37f9ebd08040110e11c12420ff7c1f9f0332d939e"}, - {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c0d1f7c3908357ee100aa64c4d1cf91edf99c40ac0069422a4fd5fd23b263263"}, - {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a5d2f44331cf04689eafac7a6596c71d6657967c07ac700b0ae1c921178645da"}, - {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:16b2254a77b310f118717715259a196662baa6b1f63b1a642d12ab1ff998c3d7"}, - {file = "ujson-5.7.0-cp37-cp37m-win32.whl", hash = "sha256:6faf46fa100b2b89e4db47206cf8a1ffb41542cdd34dde615b2fc2288954f194"}, - {file = "ujson-5.7.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ff0004c3f5a9a6574689a553d1b7819d1a496b4f005a7451f339dc2d9f4cf98c"}, - {file = "ujson-5.7.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:75204a1dd7ec6158c8db85a2f14a68d2143503f4bafb9a00b63fe09d35762a5e"}, - {file = "ujson-5.7.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7312731c7826e6c99cdd3ac503cd9acd300598e7a80bcf41f604fee5f49f566c"}, - {file = "ujson-5.7.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b9dc5a90e2149643df7f23634fe202fed5ebc787a2a1be95cf23632b4d90651"}, - {file = "ujson-5.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6a6961fc48821d84b1198a09516e396d56551e910d489692126e90bf4887d29"}, - {file = "ujson-5.7.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b01a9af52a0d5c46b2c68e3f258fdef2eacaa0ce6ae3e9eb97983f5b1166edb6"}, - {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7316d3edeba8a403686cdcad4af737b8415493101e7462a70ff73dd0609eafc"}, - {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4ee997799a23227e2319a3f8817ce0b058923dbd31904761b788dc8f53bd3e30"}, - {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dda9aa4c33435147262cd2ea87c6b7a1ca83ba9b3933ff7df34e69fee9fced0c"}, - {file = "ujson-5.7.0-cp38-cp38-win32.whl", hash = "sha256:bea8d30e362180aafecabbdcbe0e1f0b32c9fa9e39c38e4af037b9d3ca36f50c"}, - {file = "ujson-5.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:c96e3b872bf883090ddf32cc41957edf819c5336ab0007d0cf3854e61841726d"}, - {file = "ujson-5.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6411aea4c94a8e93c2baac096fbf697af35ba2b2ed410b8b360b3c0957a952d3"}, - {file = "ujson-5.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d3b3499c55911f70d4e074c626acdb79a56f54262c3c83325ffb210fb03e44d"}, - {file = "ujson-5.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:341f891d45dd3814d31764626c55d7ab3fd21af61fbc99d070e9c10c1190680b"}, - {file = "ujson-5.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f242eec917bafdc3f73a1021617db85f9958df80f267db69c76d766058f7b19"}, - {file = "ujson-5.7.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3af9f9f22a67a8c9466a32115d9073c72a33ae627b11de6f592df0ee09b98b6"}, - {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a3d794afbf134df3056a813e5c8a935208cddeae975bd4bc0ef7e89c52f0ce0"}, - {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:800bf998e78dae655008dd10b22ca8dc93bdcfcc82f620d754a411592da4bbf2"}, - {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b5ac3d5c5825e30b438ea92845380e812a476d6c2a1872b76026f2e9d8060fc2"}, - {file = "ujson-5.7.0-cp39-cp39-win32.whl", hash = "sha256:cd90027e6d93e8982f7d0d23acf88c896d18deff1903dd96140613389b25c0dd"}, - {file = "ujson-5.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:523ee146cdb2122bbd827f4dcc2a8e66607b3f665186bce9e4f78c9710b6d8ab"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e87cec407ec004cf1b04c0ed7219a68c12860123dfb8902ef880d3d87a71c172"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bab10165db6a7994e67001733f7f2caf3400b3e11538409d8756bc9b1c64f7e8"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b522be14a28e6ac1cf818599aeff1004a28b42df4ed4d7bc819887b9dac915fc"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7592f40175c723c032cdbe9fe5165b3b5903604f774ab0849363386e99e1f253"}, - {file = "ujson-5.7.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ed22f9665327a981f288a4f758a432824dc0314e4195a0eaeb0da56a477da94d"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:adf445a49d9a97a5a4c9bb1d652a1528de09dd1c48b29f79f3d66cea9f826bf6"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64772a53f3c4b6122ed930ae145184ebaed38534c60f3d859d8c3f00911eb122"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35209cb2c13fcb9d76d249286105b4897b75a5e7f0efb0c0f4b90f222ce48910"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90712dfc775b2c7a07d4d8e059dd58636bd6ff1776d79857776152e693bddea6"}, - {file = "ujson-5.7.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0e4e8981c6e7e9e637e637ad8ffe948a09e5434bc5f52ecbb82b4b4cfc092bfb"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:581c945b811a3d67c27566539bfcb9705ea09cb27c4be0002f7a553c8886b817"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d36a807a24c7d44f71686685ae6fbc8793d784bca1adf4c89f5f780b835b6243"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b4257307e3662aa65e2644a277ca68783c5d51190ed9c49efebdd3cbfd5fa44"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea7423d8a2f9e160c5e011119741682414c5b8dce4ae56590a966316a07a4618"}, - {file = "ujson-5.7.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4c592eb91a5968058a561d358d0fef59099ed152cfb3e1cd14eee51a7a93879e"}, - {file = "ujson-5.7.0.tar.gz", hash = "sha256:e788e5d5dcae8f6118ac9b45d0b891a0d55f7ac480eddcb7f07263f2bcf37b23"}, + {file = "ujson-5.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f4511560d75b15ecb367eef561554959b9d49b6ec3b8d5634212f9fed74a6df1"}, + {file = "ujson-5.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9399eaa5d1931a0ead49dce3ffacbea63f3177978588b956036bfe53cdf6af75"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4e7bb7eba0e1963f8b768f9c458ecb193e5bf6977090182e2b4f4408f35ac76"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40931d7c08c4ce99adc4b409ddb1bbb01635a950e81239c2382cfe24251b127a"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d53039d39de65360e924b511c7ca1a67b0975c34c015dd468fca492b11caa8f7"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bdf04c6af3852161be9613e458a1fb67327910391de8ffedb8332e60800147a2"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a70f776bda2e5072a086c02792c7863ba5833d565189e09fabbd04c8b4c3abba"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f26629ac531d712f93192c233a74888bc8b8212558bd7d04c349125f10199fcf"}, + {file = "ujson-5.8.0-cp310-cp310-win32.whl", hash = "sha256:7ecc33b107ae88405aebdb8d82c13d6944be2331ebb04399134c03171509371a"}, + {file = "ujson-5.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:3b27a8da7a080add559a3b73ec9ebd52e82cc4419f7c6fb7266e62439a055ed0"}, + {file = "ujson-5.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:193349a998cd821483a25f5df30b44e8f495423840ee11b3b28df092ddfd0f7f"}, + {file = "ujson-5.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ddeabbc78b2aed531f167d1e70387b151900bc856d61e9325fcdfefb2a51ad8"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ce24909a9c25062e60653073dd6d5e6ec9d6ad7ed6e0069450d5b673c854405"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27a2a3c7620ebe43641e926a1062bc04e92dbe90d3501687957d71b4bdddaec4"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b852bdf920fe9f84e2a2c210cc45f1b64f763b4f7d01468b33f7791698e455e"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:20768961a6a706170497129960762ded9c89fb1c10db2989c56956b162e2a8a3"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e0147d41e9fb5cd174207c4a2895c5e24813204499fd0839951d4c8784a23bf5"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e3673053b036fd161ae7a5a33358ccae6793ee89fd499000204676baafd7b3aa"}, + {file = "ujson-5.8.0-cp311-cp311-win32.whl", hash = "sha256:a89cf3cd8bf33a37600431b7024a7ccf499db25f9f0b332947fbc79043aad879"}, + {file = "ujson-5.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:3659deec9ab9eb19e8646932bfe6fe22730757c4addbe9d7d5544e879dc1b721"}, + {file = "ujson-5.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:102bf31c56f59538cccdfec45649780ae00657e86247c07edac434cb14d5388c"}, + {file = "ujson-5.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:299a312c3e85edee1178cb6453645217ba23b4e3186412677fa48e9a7f986de6"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e385a7679b9088d7bc43a64811a7713cc7c33d032d020f757c54e7d41931ae"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad24ec130855d4430a682c7a60ca0bc158f8253ec81feed4073801f6b6cb681b"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16fde596d5e45bdf0d7de615346a102510ac8c405098e5595625015b0d4b5296"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6d230d870d1ce03df915e694dcfa3f4e8714369cce2346686dbe0bc8e3f135e7"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9571de0c53db5cbc265945e08f093f093af2c5a11e14772c72d8e37fceeedd08"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7cba16b26efe774c096a5e822e4f27097b7c81ed6fb5264a2b3f5fd8784bab30"}, + {file = "ujson-5.8.0-cp312-cp312-win32.whl", hash = "sha256:48c7d373ff22366eecfa36a52b9b55b0ee5bd44c2b50e16084aa88b9de038916"}, + {file = "ujson-5.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:5ac97b1e182d81cf395ded620528c59f4177eee024b4b39a50cdd7b720fdeec6"}, + {file = "ujson-5.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2a64cc32bb4a436e5813b83f5aab0889927e5ea1788bf99b930fad853c5625cb"}, + {file = "ujson-5.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e54578fa8838ddc722539a752adfce9372474114f8c127bb316db5392d942f8b"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9721cd112b5e4687cb4ade12a7b8af8b048d4991227ae8066d9c4b3a6642a582"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d9707e5aacf63fb919f6237d6490c4e0244c7f8d3dc2a0f84d7dec5db7cb54c"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0be81bae295f65a6896b0c9030b55a106fb2dec69ef877253a87bc7c9c5308f7"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae7f4725c344bf437e9b881019c558416fe84ad9c6b67426416c131ad577df67"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9ab282d67ef3097105552bf151438b551cc4bedb3f24d80fada830f2e132aeb9"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:94c7bd9880fa33fcf7f6d7f4cc032e2371adee3c5dba2922b918987141d1bf07"}, + {file = "ujson-5.8.0-cp38-cp38-win32.whl", hash = "sha256:bf5737dbcfe0fa0ac8fa599eceafae86b376492c8f1e4b84e3adf765f03fb564"}, + {file = "ujson-5.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:11da6bed916f9bfacf13f4fc6a9594abd62b2bb115acfb17a77b0f03bee4cfd5"}, + {file = "ujson-5.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:69b3104a2603bab510497ceabc186ba40fef38ec731c0ccaa662e01ff94a985c"}, + {file = "ujson-5.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9249fdefeb021e00b46025e77feed89cd91ffe9b3a49415239103fc1d5d9c29a"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2873d196725a8193f56dde527b322c4bc79ed97cd60f1d087826ac3290cf9207"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a4dafa9010c366589f55afb0fd67084acd8added1a51251008f9ff2c3e44042"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a42baa647a50fa8bed53d4e242be61023bd37b93577f27f90ffe521ac9dc7a3"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f3554eaadffe416c6f543af442066afa6549edbc34fe6a7719818c3e72ebfe95"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fb87decf38cc82bcdea1d7511e73629e651bdec3a43ab40985167ab8449b769c"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:407d60eb942c318482bbfb1e66be093308bb11617d41c613e33b4ce5be789adc"}, + {file = "ujson-5.8.0-cp39-cp39-win32.whl", hash = "sha256:0fe1b7edaf560ca6ab023f81cbeaf9946a240876a993b8c5a21a1c539171d903"}, + {file = "ujson-5.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:3f9b63530a5392eb687baff3989d0fb5f45194ae5b1ca8276282fb647f8dcdb3"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:efeddf950fb15a832376c0c01d8d7713479fbeceaed1eaecb2665aa62c305aec"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d8283ac5d03e65f488530c43d6610134309085b71db4f675e9cf5dff96a8282"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb0142f6f10f57598655340a3b2c70ed4646cbe674191da195eb0985a9813b83"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d459aca895eb17eb463b00441986b021b9312c6c8cc1d06880925c7f51009c"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d524a8c15cfc863705991d70bbec998456a42c405c291d0f84a74ad7f35c5109"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d6f84a7a175c75beecde53a624881ff618e9433045a69fcfb5e154b73cdaa377"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b748797131ac7b29826d1524db1cc366d2722ab7afacc2ce1287cdafccddbf1f"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e72ba76313d48a1a3a42e7dc9d1db32ea93fac782ad8dde6f8b13e35c229130"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f504117a39cb98abba4153bf0b46b4954cc5d62f6351a14660201500ba31fe7f"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8c91b6f4bf23f274af9002b128d133b735141e867109487d17e344d38b87d94"}, + {file = "ujson-5.8.0.tar.gz", hash = "sha256:78e318def4ade898a461b3d92a79f9441e7e0e4d2ad5419abed4336d702c7425"}, ] [[package]] @@ -1526,23 +1518,23 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "virtualenv" -version = "20.21.1" +version = "20.24.5" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.21.1-py3-none-any.whl", hash = "sha256:09ddbe1af0c8ed2bb4d6ed226b9e6415718ad18aef9fa0ba023d96b7a8356049"}, - {file = "virtualenv-20.21.1.tar.gz", hash = "sha256:4c104ccde994f8b108163cf9ba58f3d11511d9403de87fb9b4f52bf33dbc8668"}, + {file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"}, + {file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"}, ] [package.dependencies] -distlib = ">=0.3.6,<1" -filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<4" +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<4" [package.extras] -docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "wcwidth" @@ -1806,5 +1798,5 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" -python-versions = ">=3.9.0, <4.0" -content-hash = "2c37066950fbf65bc5aacf7eaa24f527e3757aec8305b9de8adf9bef5e17e78d" +python-versions = ">=3.8.0, <4.0" +content-hash = "f4b42bf68f4d232c8a6e551da3f9f3432627b8b65252e6ee0b04dd803af0179b" From fe92e49c593228ef26e8d1594a855ee5be624c57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Thu, 21 Sep 2023 15:24:04 +0200 Subject: [PATCH 07/54] refactor run automation to directly take in a context --- src/speckle_automate/automation_context.py | 5 ++++ src/speckle_automate/runner.py | 21 +++++--------- .../test_automation_context.py | 29 ++++++++++++------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index ff9082f..157b445 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -82,6 +82,11 @@ class AutomationContext: """Get the status of the automation run.""" return self._automation_result.run_status + @property + def status_message(self) -> str: + """Get the current status message.""" + return self._automation_result.status_message + def elapsed(self) -> float: """Return the elapsed time in seconds since the initialization time.""" return time.perf_counter() - self._init_time diff --git a/src/speckle_automate/runner.py b/src/speckle_automate/runner.py index 90c91b9..32f5ee7 100644 --- a/src/speckle_automate/runner.py +++ b/src/speckle_automate/runner.py @@ -66,6 +66,9 @@ def execute_automate_function( raise ValueError("Cannot get speckle token from arguments or environment") speckle_token = speckle_token if speckle_token else args[3] + automation_context = AutomationContext.initialize( + automation_run_data, speckle_token + ) inputs = ( input_schema.model_validate_json(function_inputs) @@ -75,16 +78,14 @@ def execute_automate_function( if inputs: automation_context = run_function( + automation_context, automate_function, # type: ignore - automation_run_data, - speckle_token, inputs, ) else: automation_context = run_function( + automation_context, automate_function, # type: ignore - automation_run_data, - speckle_token, ) exit_code = ( @@ -98,9 +99,8 @@ def execute_automate_function( @overload def run_function( + automation_context: AutomationContext, automate_function: AutomateFunction[T], - automation_run_data: Union[AutomationRunData, str], - speckle_token: str, inputs: T, ) -> AutomationContext: ... @@ -108,23 +108,18 @@ def run_function( @overload def run_function( + automation_context: AutomationContext, automate_function: AutomateFunctionWithoutInputs, - automation_run_data: Union[AutomationRunData, str], - speckle_token: str, ) -> AutomationContext: ... def run_function( + automation_context: AutomationContext, automate_function: Union[AutomateFunction[T], AutomateFunctionWithoutInputs], - automation_run_data: Union[AutomationRunData, str], - speckle_token: str, inputs: Optional[T] = None, ) -> AutomationContext: """Run the provided function with the automate sdk context.""" - automation_context = AutomationContext.initialize( - automation_run_data, speckle_token - ) automation_context.report_run_status() try: diff --git a/tests/intergration/speckle_automate/test_automation_context.py b/tests/intergration/speckle_automate/test_automation_context.py index 9923d0b..cf2565a 100644 --- a/tests/intergration/speckle_automate/test_automation_context.py +++ b/tests/intergration/speckle_automate/test_automation_context.py @@ -143,6 +143,14 @@ def automation_run_data( ) +@pytest.fixture() +def automation_context( + automation_run_data: AutomationRunData, speckle_token: str +) -> AutomationContext: + """Set up the run context.""" + return AutomationContext.initialize(automation_run_data, speckle_token) + + def get_automation_status( project_id: str, model_id: str, @@ -200,17 +208,17 @@ class FunctionInputs(AutomateBase): def automate_function( - automate_context: AutomationContext, + automation_context: AutomationContext, function_inputs: FunctionInputs, ) -> None: """Hey, trying the automate sdk experience here.""" - version_root_object = automate_context.receive_version() + version_root_object = automation_context.receive_version() count = 0 if version_root_object.speckle_type == function_inputs.forbidden_speckle_type: if not version_root_object.id: raise ValueError("Cannot operate on objects without their id's.") - automate_context.add_object_error( + automation_context.add_object_error( version_root_object.id, "This project should not contain the type: " f"{function_inputs.forbidden_speckle_type}", @@ -218,34 +226,33 @@ def automate_function( count += 1 if count > 0: - automate_context.mark_run_failed( + automation_context.mark_run_failed( "Automation failed: " f"Found {count} object that have a forbidden speckle type: " f"{function_inputs.forbidden_speckle_type}" ) else: - automate_context.mark_run_success("No forbidden types found.") + automation_context.mark_run_success("No forbidden types found.") -def test_function_run(automation_run_data: AutomationRunData, speckle_token: str): +def test_function_run(automation_context: AutomationContext, speckle_token: str): """Run an integration test for the automate function.""" automation_context = run_function( + automation_context, automate_function, - automation_run_data, - speckle_token, FunctionInputs(forbidden_speckle_type="Base"), ) assert automation_context.run_status == AutomationStatus.FAILED status = get_automation_status( - automation_run_data.project_id, - automation_run_data.model_id, + automation_context.automation_run_data.project_id, + automation_context.automation_run_data.model_id, automation_context.speckle_client, ) assert status["status"] == automation_context.run_status status_message = status["automationRuns"][0]["functionRuns"][0]["statusMessage"] - assert status_message == automation_context._automation_result.status_message + assert status_message == automation_context.status_message def test_file_uploads(automation_run_data: AutomationRunData, speckle_token: str): From d1ebd84ccaf805590ed13231e7d08872c7dbf70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Thu, 21 Sep 2023 19:02:42 +0200 Subject: [PATCH 08/54] extract useful functions to helpers module --- pyproject.toml | 2 +- src/speckle_automate/helpers.py | 54 ++++++++++++++++++ src/speckle_automate/schema.py | 2 +- .../test_automation_context.py | 57 ++----------------- 4 files changed, 60 insertions(+), 55 deletions(-) create mode 100644 src/speckle_automate/helpers.py diff --git a/pyproject.toml b/pyproject.toml index 2857319..8509653 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "specklepy" -version = "2.9.1" +version = "2.17.1" description = "The Python SDK for Speckle 2.0" readme = "README.md" authors = ["Speckle Systems "] diff --git a/src/speckle_automate/helpers.py b/src/speckle_automate/helpers.py new file mode 100644 index 0000000..9845aca --- /dev/null +++ b/src/speckle_automate/helpers.py @@ -0,0 +1,54 @@ +"""Some useful helpers for working with automation data.""" +import secrets +import string + +from specklepy.api.client import SpeckleClient +from gql import gql + + +def register_new_automation( + speckle_client: SpeckleClient, + project_id: str, + model_id: str, + automation_id: str, + automation_name: str, + automation_revision_id: str, +) -> bool: + """Register a new automation in the speckle server.""" + query = gql( + """ + mutation CreateAutomation( + $projectId: String! + $modelId: String! + $automationName: String! + $automationId: String! + $automationRevisionId: String! + ) { + automationMutations { + create( + input: { + projectId: $projectId + modelId: $modelId + automationName: $automationName + automationId: $automationId + automationRevisionId: $automationRevisionId + } + ) + } + } + """ + ) + params = { + "projectId": project_id, + "modelId": model_id, + "automationName": automation_name, + "automationId": automation_id, + "automationRevisionId": automation_revision_id, + } + return speckle_client.httpclient.execute(query, params) + + +def crypto_random_string(length: int) -> str: + """Generate a semi crypto random string of a given length.""" + alphabet = string.ascii_letters + string.digits + return "".join(secrets.choice(alphabet) for _ in range(length)) diff --git a/src/speckle_automate/schema.py b/src/speckle_automate/schema.py index 7309b86..54626a4 100644 --- a/src/speckle_automate/schema.py +++ b/src/speckle_automate/schema.py @@ -27,7 +27,7 @@ class AutomationRunData(BaseModel): automation_run_id: str function_id: str - function_revision: str + function_release: str model_config = ConfigDict( alias_generator=camelcase, populate_by_name=True, protected_namespaces=() diff --git a/tests/intergration/speckle_automate/test_automation_context.py b/tests/intergration/speckle_automate/test_automation_context.py index cf2565a..e461f35 100644 --- a/tests/intergration/speckle_automate/test_automation_context.py +++ b/tests/intergration/speckle_automate/test_automation_context.py @@ -1,13 +1,12 @@ """Run integration tests with a speckle server.""" import os -import secrets -import string from pathlib import Path from typing import Dict import pytest from gql import gql from speckle_automate.schema import AutomateBase +from speckle_automate.helpers import register_new_automation, crypto_random_string from specklepy.api import operations from specklepy.api.client import SpeckleClient from specklepy.objects.base import Base @@ -21,54 +20,6 @@ from speckle_automate import ( ) -def crypto_random_string(length: int) -> str: - """Generate a semi crypto random string of a given length.""" - alphabet = string.ascii_letters + string.digits - return "".join(secrets.choice(alphabet) for _ in range(length)) - - -def register_new_automation( - project_id: str, - model_id: str, - speckle_client: SpeckleClient, - automation_id: str, - automation_name: str, - automation_revision_id: str, -): - """Register a new automation in the speckle server.""" - query = gql( - """ - mutation CreateAutomation( - $projectId: String! - $modelId: String! - $automationName: String! - $automationId: String! - $automationRevisionId: String! - ) { - automationMutations { - create( - input: { - projectId: $projectId - modelId: $modelId - automationName: $automationName - automationId: $automationId - automationRevisionId: $automationRevisionId - } - ) - } - } - """ - ) - params = { - "projectId": project_id, - "modelId": model_id, - "automationName": automation_name, - "automationId": automation_id, - "automationRevisionId": automation_revision_id, - } - speckle_client.httpclient.execute(query, params) - - @pytest.fixture() def speckle_token(user_dict: Dict[str, str]) -> str: """Provide a speckle token for the test suite.""" @@ -118,9 +69,9 @@ def automation_run_data( automation_revision_id = crypto_random_string(10) register_new_automation( + test_client, project_id, model_id, - test_client, automation_id, automation_name, automation_revision_id, @@ -128,7 +79,7 @@ def automation_run_data( automation_run_id = crypto_random_string(10) function_id = crypto_random_string(10) - function_revision = crypto_random_string(10) + function_release = crypto_random_string(10) return AutomationRunData( project_id=project_id, model_id=model_id, @@ -139,7 +90,7 @@ def automation_run_data( automation_revision_id=automation_revision_id, automation_run_id=automation_run_id, function_id=function_id, - function_revision=function_revision, + function_release=function_release, ) From b1f979a10ad5e33ad001d95f098690bbbdc368f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Mon, 2 Oct 2023 14:00:34 +0200 Subject: [PATCH 09/54] WIP: rework result schema --- src/speckle_automate/__init__.py | 4 +- src/speckle_automate/automation_context.py | 160 ++++++++++++++---- src/speckle_automate/helpers.py | 2 +- src/speckle_automate/schema.py | 19 ++- src/specklepy/api/client.py | 18 +- src/specklepy/api/credentials.py | 21 ++- .../test_automation_context.py | 56 ++++-- 7 files changed, 208 insertions(+), 72 deletions(-) diff --git a/src/speckle_automate/__init__.py b/src/speckle_automate/__init__.py index be29deb..3a4a6cc 100644 --- a/src/speckle_automate/__init__.py +++ b/src/speckle_automate/__init__.py @@ -6,8 +6,8 @@ from speckle_automate.schema import ( AutomationResult, AutomationRunData, AutomationStatus, - ObjectResult, ObjectResultLevel, + ResultCase, ) __all__ = [ @@ -16,7 +16,7 @@ __all__ = [ "AutomationStatus", "AutomationResult", "AutomationRunData", - "ObjectResult", + "ResultCase", "ObjectResultLevel", "run_function", "execute_automate_function", diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index 157b445..bfac699 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -2,12 +2,13 @@ from dataclasses import dataclass, field from pathlib import Path import time -from typing import Optional, Union +from typing import Any, Dict, List, Optional, Union import httpx from gql import gql from specklepy.api import operations from specklepy.api.client import SpeckleClient +from specklepy.core.api.models import Branch from specklepy.objects import Base from specklepy.transports.memory import MemoryTransport from specklepy.transports.server import ServerTransport @@ -17,8 +18,8 @@ from speckle_automate.schema import ( AutomationResult, AutomationRunData, AutomationStatus, - ObjectResult, ObjectResultLevel, + ResultCase, ) @@ -83,13 +84,13 @@ class AutomationContext: return self._automation_result.run_status @property - def status_message(self) -> str: + def status_message(self) -> Optional[str]: """Get the current status message.""" return self._automation_result.status_message def elapsed(self) -> float: """Return the elapsed time in seconds since the initialization time.""" - return time.perf_counter() - self._init_time + return (time.perf_counter() - self._init_time) / 1000 def receive_version(self) -> Base: """Receive the Speckle project version that triggered this automation run.""" @@ -102,14 +103,14 @@ class AutomationContext: commit.referencedObject, self._server_transport, self._memory_transport ) print( - f"It took {self.elapsed():2f} seconds to receive", + f"It took {self.elapsed():.2f} seconds to receive", f" the speckle version {self.automation_run_data.version_id}", ) return base def create_new_version_in_project( self, root_object: Base, model_id: str, version_message: str = "" - ) -> None: + ) -> str: """Save a base model to a new version on the project. Args: @@ -117,12 +118,17 @@ class AutomationContext: model_id (str): For now please use a `branchName`! version_message (str): The message for the new version. """ + if model_id == self.automation_run_data.model_id: raise ValueError( f"The target model id: {model_id} cannot match the model id" f" that triggered this automation: {self.automation_run_data.model_id}" ) + branch = self._get_model(model_id) + if not branch.name: + raise ValueError(f"The model {model_id} has no name.") + root_object_id = operations.send( root_object, [self._server_transport, self._memory_transport], @@ -132,11 +138,30 @@ class AutomationContext: version_id = self.speckle_client.commit.create( stream_id=self.automation_run_data.project_id, object_id=root_object_id, - branch_name=model_id, + branch_name=branch.name, message=version_message, source_application="SpeckleAutomate", ) self._automation_result.result_versions.append(version_id) + return version_id + + def _get_model(self, model_id: str) -> Branch: + query = gql( + """ + query ProjectModel($projectId: String!, $modelId: String!){ + project(id: $projectId) { + model(id: $modelId) { + name + id + description + } + } + } + """ + ) + params = {"projectId": self.automation_run_data.project_id, "modelId": model_id} + response = self.speckle_client.httpclient.execute(query, params) + return Branch.model_validate(response["project"]["model"]) def report_run_status(self) -> None: """Report the current run status to the project of this automation.""" @@ -178,14 +203,15 @@ class AutomationContext: object_results = { "version": "1.0.0", "values": { - "speckleObjects": self._automation_result.model_dump(by_alias=True)[ + "objectResults": self._automation_result.model_dump(by_alias=True)[ "objectResults" ], - "blobs": self._automation_result.blobs, + "blobIds": self._automation_result.blobs, }, } else: object_results = None + params = { "automationId": self.automation_run_data.automation_id, "automationRevisionId": self.automation_run_data.automation_revision_id, @@ -237,8 +263,9 @@ class AutomationContext: if len(upload_response.upload_results) != 1: raise ValueError("Expecting one upload result.") - for upload_result in upload_response.upload_results: - self._automation_result.blobs.append(upload_result.blob_id) + self._automation_result.blobs.extend( + [upload_result.blob_id for upload_result in upload_response.upload_results] + ) def mark_run_failed(self, status_message: str) -> None: """Mark the current run a failure.""" @@ -256,28 +283,101 @@ class AutomationContext: self._automation_result.run_status = status self._automation_result.elapsed = duration - msg = f"Automation run {status.value} after {duration:2f} seconds." + msg = f"Automation run {status.value} after {duration:.2f} seconds." print("\n".join([msg, status_message]) if status_message else msg) - def add_object_error(self, object_id: str, error_cause: str) -> None: - """Add an error to a given Speckle object.""" - self._add_object_result(object_id, ObjectResultLevel.ERROR, error_cause) - - def add_object_warning(self, object_id: str, warning: str) -> None: - """Add a warning to a given Speckle object.""" - self._add_object_result(object_id, ObjectResultLevel.WARNING, warning) - - def add_object_info(self, object_id: str, info: str) -> None: - """Add an info message to a given Speckle object.""" - self._add_object_result(object_id, ObjectResultLevel.INFO, info) - - def _add_object_result( - self, object_id: str, level: ObjectResultLevel, status_message: str + def attach_error_to_objects( + self, + category: str, + object_ids: Union[str, List[str]], + message: Optional[str] = None, + metadata: Optional[Dict[str, Any]] = None, + visual_overrides: Optional[Dict[str, Any]] = None, ) -> None: + """Add a new error case to the run results. + + If the error cause has already created an error case, + the error will be extended with a new case refering to the causing objects. + Args: + error_tag (str): A short tag for the error type. + causing_object_ids (str[]): A list of object_id-s that are causing the error + error_messagge (Optional[str]): Optional error message. + metadata: User provided metadata key value pairs + visual_overrides: Case specific 3D visual overrides. + """ + self.attach_result_to_objects( + ObjectResultLevel.ERROR, + category, + object_ids, + message, + metadata, + visual_overrides, + ) + + def attach_warning_to_objects( + self, + category: str, + object_ids: Union[str, List[str]], + message: Optional[str] = None, + metadata: Optional[Dict[str, Any]] = None, + visual_overrides: Optional[Dict[str, Any]] = None, + ) -> None: + """Add a new warning case to the run results.""" + self.attach_result_to_objects( + ObjectResultLevel.WARNING, + category, + object_ids, + message, + metadata, + visual_overrides, + ) + + def attach_info_to_objects( + self, + category: str, + object_ids: Union[str, List[str]], + message: Optional[str] = None, + metadata: Optional[Dict[str, Any]] = None, + visual_overrides: Optional[Dict[str, Any]] = None, + ) -> None: + """Add a new info case to the run results.""" + self.attach_result_to_objects( + ObjectResultLevel.INFO, + category, + object_ids, + message, + metadata, + visual_overrides, + ) + + def attach_result_to_objects( + self, + level: ObjectResultLevel, + category: str, + object_ids: Union[str, List[str]], + message: Optional[str] = None, + metadata: Optional[Dict[str, Any]] = None, + visual_overrides: Optional[Dict[str, Any]] = None, + ) -> None: + if isinstance(object_ids, list): + if len(object_ids) < 1: + raise ValueError( + f"Need atleast one object_id to report a(n) {level.value.upper()}" + ) + id_list = object_ids + else: + id_list = [object_ids] print( - f"Object {object_id} was marked with {level.value.upper()}", - f" cause: {status_message}", + f"Object {', '.join(id_list)} was marked with {level.value.upper()}", + f"/{category} cause: {message}", ) - self._automation_result.object_results[object_id].append( - ObjectResult(level=level, status_message=status_message) + self._automation_result.object_results.append( + ResultCase( + category=category, + level=level, + object_ids=id_list, + message=message, + metadata=metadata, + visual_overrides=visual_overrides, + ) ) diff --git a/src/speckle_automate/helpers.py b/src/speckle_automate/helpers.py index 9845aca..8fe7870 100644 --- a/src/speckle_automate/helpers.py +++ b/src/speckle_automate/helpers.py @@ -51,4 +51,4 @@ def register_new_automation( def crypto_random_string(length: int) -> str: """Generate a semi crypto random string of a given length.""" alphabet = string.ascii_letters + string.digits - return "".join(secrets.choice(alphabet) for _ in range(length)) + return "".join(secrets.choice(alphabet) for _ in range(length)).lower() diff --git a/src/speckle_automate/schema.py b/src/speckle_automate/schema.py index 54626a4..8a914c4 100644 --- a/src/speckle_automate/schema.py +++ b/src/speckle_automate/schema.py @@ -1,7 +1,6 @@ """""" -from collections import defaultdict from enum import Enum -from typing import Optional +from typing import Any, Dict, List, Optional from pydantic import BaseModel, ConfigDict, Field from stringcase import camelcase @@ -28,6 +27,7 @@ class AutomationRunData(BaseModel): function_id: str function_release: str + function_name: str model_config = ConfigDict( alias_generator=camelcase, populate_by_name=True, protected_namespaces=() @@ -51,11 +51,15 @@ class ObjectResultLevel(str, Enum): ERROR = "ERROR" -class ObjectResult(AutomateBase): - """An object level result.""" +class ResultCase(AutomateBase): + """A result case.""" + category: str level: ObjectResultLevel - status_message: str + object_ids: List[str] + message: Optional[str] + metadata: Optional[Dict[str, Any]] + visual_overrides: Optional[Dict[str, Any]] class AutomationResult(AutomateBase): @@ -67,7 +71,4 @@ class AutomationResult(AutomateBase): blobs: list[str] = Field(default_factory=list) run_status: AutomationStatus = AutomationStatus.RUNNING status_message: Optional[str] = None - - object_results: dict[str, list[ObjectResult]] = Field( - default_factory=lambda: defaultdict(list) # typing: ignore - ) + object_results: list[ResultCase] = Field(default_factory=list) diff --git a/src/specklepy/api/client.py b/src/specklepy/api/client.py index ba63fab..c21a566 100644 --- a/src/specklepy/api/client.py +++ b/src/specklepy/api/client.py @@ -1,14 +1,8 @@ -import re -from typing import Dict -from warnings import warn - from deprecated import deprecated -from gql import Client from gql.transport.exceptions import TransportServerError from gql.transport.requests import RequestsHTTPTransport from gql.transport.websockets import WebsocketsTransport -from specklepy.api import resources from specklepy.api.credentials import Account, get_account_from_token from specklepy.api.resources import ( user, @@ -131,7 +125,9 @@ class SpeckleClient(CoreSpeckleClient): Arguments: token {str} -- an api token """ - metrics.track(metrics.SDK, self.account, {"name": "Client Authenticate_deprecated"}) + metrics.track( + metrics.SDK, self.account, {"name": "Client Authenticate_deprecated"} + ) return super().authenticate(token) def authenticate_with_token(self, token: str) -> None: @@ -143,7 +139,9 @@ class SpeckleClient(CoreSpeckleClient): Arguments: token {str} -- an api token """ - metrics.track(metrics.SDK, self.account, {"name": "Client Authenticate With Token"}) + metrics.track( + metrics.SDK, self.account, {"name": "Client Authenticate With Token"} + ) return super().authenticate_with_token(token) def authenticate_with_account(self, account: Account) -> None: @@ -155,5 +153,7 @@ class SpeckleClient(CoreSpeckleClient): account {Account} -- the account object which can be found with `get_default_account` or `get_local_accounts` """ - metrics.track(metrics.SDK, self.account, {"name": "Client Authenticate With Account"}) + metrics.track( + metrics.SDK, self.account, {"name": "Client Authenticate With Account"} + ) return super().authenticate_with_account(account) diff --git a/src/specklepy/api/credentials.py b/src/specklepy/api/credentials.py index e43f6c2..04ab00f 100644 --- a/src/specklepy/api/credentials.py +++ b/src/specklepy/api/credentials.py @@ -9,12 +9,15 @@ from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException from specklepy.transports.sqlite import SQLiteTransport -# following imports seem to be unnecessary, but they need to stay +# following imports seem to be unnecessary, but they need to stay # to not break the scripts using these functions as non-core -from specklepy.core.api.credentials import (Account, UserInfo, - StreamWrapper, # deprecated - get_local_accounts as core_get_local_accounts, - get_account_from_token as core_get_account_from_token) +from specklepy.core.api.credentials import ( + Account, + UserInfo, + StreamWrapper, # deprecated + get_local_accounts as core_get_local_accounts, + get_account_from_token as core_get_account_from_token, +) def get_local_accounts(base_path: Optional[str] = None) -> List[Account]: @@ -35,11 +38,12 @@ def get_local_accounts(base_path: Optional[str] = None) -> List[Account]: (acc for acc in accounts if acc.isDefault), accounts[0] if accounts else None, ), - {"name": "Get Local Accounts"} + {"name": "Get Local Accounts"}, ) return accounts + def get_default_account(base_path: Optional[str] = None) -> Optional[Account]: """ Gets this environment's default account if any. If there is no default, @@ -61,7 +65,8 @@ def get_default_account(base_path: Optional[str] = None) -> Optional[Account]: metrics.initialise_tracker(default) return default - + + def get_account_from_token(token: str, server_url: str = None) -> Account: """Gets the local account for the token if it exists Arguments: @@ -73,5 +78,5 @@ def get_account_from_token(token: str, server_url: str = None) -> Account: """ account = core_get_account_from_token(token, server_url) - metrics.track( metrics.SDK, account, {"name": "Get Account From Token"} ) + metrics.track(metrics.SDK, account, {"name": "Get Account From Token"}) return account diff --git a/tests/intergration/speckle_automate/test_automation_context.py b/tests/intergration/speckle_automate/test_automation_context.py index e461f35..f11df63 100644 --- a/tests/intergration/speckle_automate/test_automation_context.py +++ b/tests/intergration/speckle_automate/test_automation_context.py @@ -20,19 +20,19 @@ from speckle_automate import ( ) -@pytest.fixture() +@pytest.fixture def speckle_token(user_dict: Dict[str, str]) -> str: """Provide a speckle token for the test suite.""" return user_dict["token"] -@pytest.fixture() +@pytest.fixture def speckle_server_url(host: str) -> str: """Provide a speckle server url for the test suite, default to localhost.""" return f"http://{host}" -@pytest.fixture() +@pytest.fixture def test_client(speckle_server_url: str, speckle_token: str) -> SpeckleClient: """Initialize a SpeckleClient for testing.""" test_client = SpeckleClient(speckle_server_url, use_ssl=False) @@ -40,7 +40,7 @@ def test_client(speckle_server_url: str, speckle_token: str) -> SpeckleClient: return test_client -@pytest.fixture() +@pytest.fixture def test_object() -> Base: """Create a Base model for testing.""" root_object = Base() @@ -48,7 +48,7 @@ def test_object() -> Base: return root_object -@pytest.fixture() +@pytest.fixture def automation_run_data( test_object: Base, test_client: SpeckleClient, speckle_server_url: str ) -> AutomationRunData: @@ -91,10 +91,11 @@ def automation_run_data( automation_run_id=automation_run_id, function_id=function_id, function_release=function_release, + function_name="foobar", ) -@pytest.fixture() +@pytest.fixture def automation_context( automation_run_data: AutomationRunData, speckle_token: str ) -> AutomationContext: @@ -169,7 +170,8 @@ def automate_function( if version_root_object.speckle_type == function_inputs.forbidden_speckle_type: if not version_root_object.id: raise ValueError("Cannot operate on objects without their id's.") - automation_context.add_object_error( + automation_context.attach_error_to_objects( + "Forbidden speckle_type", version_root_object.id, "This project should not contain the type: " f"{function_inputs.forbidden_speckle_type}", @@ -187,7 +189,7 @@ def automate_function( automation_context.mark_run_success("No forbidden types found.") -def test_function_run(automation_context: AutomationContext, speckle_token: str): +def test_function_run(automation_context: AutomationContext) -> None: """Run an integration test for the automate function.""" automation_context = run_function( automation_context, @@ -206,16 +208,44 @@ def test_function_run(automation_context: AutomationContext, speckle_token: str) assert status_message == automation_context.status_message -def test_file_uploads(automation_run_data: AutomationRunData, speckle_token: str): +@pytest.fixture +def test_file_path(): + path = Path(f"./{crypto_random_string(10)}").resolve() + yield path + os.remove(path) + + +def test_file_uploads( + automation_run_data: AutomationRunData, speckle_token: str, test_file_path: Path +): """Test file store capabilities of the automate sdk.""" automation_context = AutomationContext.initialize( automation_run_data, speckle_token ) - path = Path(f"./{crypto_random_string(10)}").resolve() - path.write_text("foobar") + test_file_path.write_text("foobar") - automation_context.store_file_result(path) + automation_context.store_file_result(test_file_path) - os.remove(path) assert len(automation_context._automation_result.blobs) == 1 + + +def test_create_version_in_project_raises_error_for_same_model( + automation_context: AutomationContext, +) -> None: + with pytest.raises(ValueError): + automation_context.create_new_version_in_project( + Base(), automation_context.automation_run_data.model_id + ) + + +def test_create_version_in_project( + automation_context: AutomationContext, +) -> None: + model_id = automation_context.speckle_client.branch.create( + automation_context.automation_run_data.project_id, "foobar" + ) + root_object = Base() + root_object.foo = "bar" + version_id = automation_context.create_new_version_in_project(root_object, model_id) + assert version_id is not None From 6e7c36223fdddcad7dc415a73e60ad98f5e2d9c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Mon, 2 Oct 2023 14:03:07 +0200 Subject: [PATCH 10/54] fix(automate_sdk): functions have releases --- src/speckle_automate/schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/speckle_automate/schema.py b/src/speckle_automate/schema.py index 7309b86..54626a4 100644 --- a/src/speckle_automate/schema.py +++ b/src/speckle_automate/schema.py @@ -27,7 +27,7 @@ class AutomationRunData(BaseModel): automation_run_id: str function_id: str - function_revision: str + function_release: str model_config = ConfigDict( alias_generator=camelcase, populate_by_name=True, protected_namespaces=() From 6e8e08ae94b67b19fc52955e7534451915dd2e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Tue, 3 Oct 2023 08:13:40 +0200 Subject: [PATCH 11/54] fix(automate): support py >= 3.10 typing --- src/speckle_automate/schema.py | 8 ++++---- .../speckle_automate/test_automation_context.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/speckle_automate/schema.py b/src/speckle_automate/schema.py index 54626a4..c5b593a 100644 --- a/src/speckle_automate/schema.py +++ b/src/speckle_automate/schema.py @@ -1,7 +1,7 @@ """""" from collections import defaultdict from enum import Enum -from typing import Optional +from typing import Optional, List, Dict from pydantic import BaseModel, ConfigDict, Field from stringcase import camelcase @@ -63,11 +63,11 @@ class AutomationResult(AutomateBase): elapsed: float = 0 result_view: Optional[str] = None - result_versions: list[str] = Field(default_factory=list) - blobs: list[str] = Field(default_factory=list) + result_versions: List[str] = Field(default_factory=list) + blobs: List[str] = Field(default_factory=list) run_status: AutomationStatus = AutomationStatus.RUNNING status_message: Optional[str] = None - object_results: dict[str, list[ObjectResult]] = Field( + object_results: Dict[str, List[ObjectResult]] = Field( default_factory=lambda: defaultdict(list) # typing: ignore ) diff --git a/tests/intergration/speckle_automate/test_automation_context.py b/tests/intergration/speckle_automate/test_automation_context.py index 9923d0b..26f94df 100644 --- a/tests/intergration/speckle_automate/test_automation_context.py +++ b/tests/intergration/speckle_automate/test_automation_context.py @@ -128,7 +128,7 @@ def automation_run_data( automation_run_id = crypto_random_string(10) function_id = crypto_random_string(10) - function_revision = crypto_random_string(10) + function_release = crypto_random_string(10) return AutomationRunData( project_id=project_id, model_id=model_id, @@ -139,7 +139,7 @@ def automation_run_data( automation_revision_id=automation_revision_id, automation_run_id=automation_run_id, function_id=function_id, - function_revision=function_revision, + function_release=function_release, ) From 4ad37614786a7662a45861749554554ce5114eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Tue, 3 Oct 2023 15:28:50 +0200 Subject: [PATCH 12/54] fix(automate_sdk): make sure we throw for failed version create --- src/speckle_automate/automation_context.py | 5 +++++ src/specklepy/api/resources/commit.py | 11 +++++++---- src/specklepy/core/api/resources/commit.py | 7 ++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index ff9082f..2402f56 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -11,6 +11,7 @@ from specklepy.api.client import SpeckleClient from specklepy.objects import Base from specklepy.transports.memory import MemoryTransport from specklepy.transports.server import ServerTransport +from specklepy.logging.exceptions import SpeckleException from speckle_automate.schema import ( AutomateBase, @@ -131,6 +132,10 @@ class AutomationContext: message=version_message, source_application="SpeckleAutomate", ) + + if isinstance(version_id, SpeckleException): + raise version_id + self._automation_result.result_versions.append(version_id) def report_run_status(self) -> None: diff --git a/src/specklepy/api/resources/commit.py b/src/specklepy/api/resources/commit.py index 0f69bf7..8a0bc6a 100644 --- a/src/specklepy/api/resources/commit.py +++ b/src/specklepy/api/resources/commit.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List, Optional, Union from gql import gql @@ -7,6 +7,7 @@ from specklepy.api.resource import ResourceBase from specklepy.logging import metrics from specklepy.core.api.resources.commit import Resource as CoreResource +from specklepy.logging.exceptions import SpeckleException class Resource(CoreResource): @@ -55,8 +56,8 @@ class Resource(CoreResource): branch_name: str = "main", message: str = "", source_application: str = "python", - parents: List[str] = None, - ) -> str: + parents: Optional[List[str]] = None, + ) -> Union[str, SpeckleException]: """ Creates a commit on a branch @@ -76,7 +77,9 @@ class Resource(CoreResource): str -- the id of the created commit """ metrics.track(metrics.SDK, self.account, {"name": "Commit Create"}) - return super().create(stream_id, object_id, branch_name, message, source_application, parents) + return super().create( + stream_id, object_id, branch_name, message, source_application, parents + ) def update(self, stream_id: str, commit_id: str, message: str) -> bool: """ diff --git a/src/specklepy/core/api/resources/commit.py b/src/specklepy/core/api/resources/commit.py index 0f69151..4a076b1 100644 --- a/src/specklepy/core/api/resources/commit.py +++ b/src/specklepy/core/api/resources/commit.py @@ -1,9 +1,10 @@ -from typing import List, Optional +from typing import List, Optional, Union from gql import gql from specklepy.core.api.models import Commit from specklepy.core.api.resource import ResourceBase +from specklepy.logging.exceptions import SpeckleException NAME = "commit" @@ -106,8 +107,8 @@ class Resource(ResourceBase): branch_name: str = "main", message: str = "", source_application: str = "python", - parents: List[str] = None, - ) -> str: + parents: Optional[List[str]] = None, + ) -> Union[str, SpeckleException]: """ Creates a commit on a branch From 67cf41d72166bb823adea4abd5c8a30ab9e2b0a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Tue, 3 Oct 2023 16:04:22 +0200 Subject: [PATCH 13/54] fix(automate_sdk): get model name from id --- src/speckle_automate/automation_context.py | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index 2402f56..d293392 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -8,6 +8,7 @@ import httpx from gql import gql from specklepy.api import operations from specklepy.api.client import SpeckleClient +from specklepy.core.api.models import Branch from specklepy.objects import Base from specklepy.transports.memory import MemoryTransport from specklepy.transports.server import ServerTransport @@ -119,6 +120,10 @@ class AutomationContext: f" that triggered this automation: {self.automation_run_data.model_id}" ) + branch = self._get_model(model_id) + if not branch.name: + raise ValueError(f"The model {model_id} has no name.") + root_object_id = operations.send( root_object, [self._server_transport, self._memory_transport], @@ -138,6 +143,24 @@ class AutomationContext: self._automation_result.result_versions.append(version_id) + def _get_model(self, model_id: str) -> Branch: + query = gql( + """ + query ProjectModel($projectId: String!, $modelId: String!){ + project(id: $projectId) { + model(id: $modelId) { + name + id + description + } + } + } + """ + ) + params = {"projectId": self.automation_run_data.project_id, "modelId": model_id} + response = self.speckle_client.httpclient.execute(query, params) + return Branch.model_validate(response["project"]["model"]) + def report_run_status(self) -> None: """Report the current run status to the project of this automation.""" query = gql( From 9181440c62848800c992bf10a3e83787b9eaf665 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Wed, 4 Oct 2023 14:24:30 +0200 Subject: [PATCH 14/54] pass branch name to commit.create --- src/speckle_automate/automation_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index d293392..c839deb 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -133,7 +133,7 @@ class AutomationContext: version_id = self.speckle_client.commit.create( stream_id=self.automation_run_data.project_id, object_id=root_object_id, - branch_name=model_id, + branch_name=branch.name, message=version_message, source_application="SpeckleAutomate", ) From 2810598336171aee4edb35e81c12b522d5a68717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Mon, 9 Oct 2023 14:25:27 +0200 Subject: [PATCH 15/54] fix(objects): spiral turns should be optional floats --- src/specklepy/objects/geometry.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/specklepy/objects/geometry.py b/src/specklepy/objects/geometry.py index 922f3e1..9fbbed7 100644 --- a/src/specklepy/objects/geometry.py +++ b/src/specklepy/objects/geometry.py @@ -40,9 +40,9 @@ class Point(Base, speckle_type=GEOMETRY + "Point"): class Pointcloud( - Base, + Base, speckle_type=GEOMETRY + "Pointcloud", - chunkable={"points": 31250, "colors": 62500, "sizes": 62500}, + chunkable={"points": 31250, "colors": 62500, "sizes": 62500}, ): points: Optional[List[float]] = None colors: Optional[List[int]] = None @@ -319,7 +319,7 @@ class Spiral(Base, speckle_type=GEOMETRY + "Spiral", detachable={"displayValue"} startPoint: Optional[Point] = None endPoint: Optional[Point] plane: Optional[Plane] - turns: Optional[int] + turns: Optional[float] pitchAxis: Optional[Vector] = Vector() pitch: float = 0 spiralType: Optional[SpiralType] = None From 262be44423b128d412302902985dc5163794f327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Wed, 11 Oct 2023 09:54:44 +0200 Subject: [PATCH 16/54] chore: bump package version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8509653..7e8bb29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "specklepy" -version = "2.17.1" +version = "2.17.5" description = "The Python SDK for Speckle 2.0" readme = "README.md" authors = ["Speckle Systems "] From 11c6221972825f4f9263687c758f4a9c275b3bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Wed, 11 Oct 2023 10:59:12 +0200 Subject: [PATCH 17/54] ci: pin to new server image --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index ec52659..6dc2736 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -61,7 +61,7 @@ services: FILE_SIZE_LIMIT_MB: 100 speckle-server: - image: speckle/speckle-server:latest + image: speckle/speckle-server:2.16.1-alpha.56633 restart: always healthcheck: test: From 8f32aa014e107a70b6c01007348dd6997656b4df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Wed, 11 Oct 2023 11:03:08 +0200 Subject: [PATCH 18/54] ci: release the pin --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 6dc2736..ec52659 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -61,7 +61,7 @@ services: FILE_SIZE_LIMIT_MB: 100 speckle-server: - image: speckle/speckle-server:2.16.1-alpha.56633 + image: speckle/speckle-server:latest restart: always healthcheck: test: From 6a6b3d4c3d4aa989500469bc6beabf2e04b76f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Wed, 11 Oct 2023 11:06:30 +0200 Subject: [PATCH 19/54] ci: disable docker layer caching --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ce1032f..a465bf6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,7 +8,7 @@ jobs: test: machine: image: ubuntu-2204:2023.02.1 - docker_layer_caching: true + docker_layer_caching: false resource_class: medium parameters: tag: From 23a5087fbc54d463a89121071c8f478a2961f864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Wed, 25 Oct 2023 17:46:00 +0200 Subject: [PATCH 20/54] feat: migrate to new automate api --- src/speckle_automate/automation_context.py | 71 ++++++++-------------- src/speckle_automate/schema.py | 2 +- 2 files changed, 27 insertions(+), 46 deletions(-) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index d585a38..1176006 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -91,7 +91,7 @@ class AutomationContext: def elapsed(self) -> float: """Return the elapsed time in seconds since the initialization time.""" - return (time.perf_counter() - self._init_time) / 1000 + return time.perf_counter() - self._init_time def receive_version(self) -> Base: """Receive the Speckle project version that triggered this automation run.""" @@ -110,7 +110,7 @@ class AutomationContext: return base def create_new_version_in_project( - self, root_object: Base, model_id: str, version_message: str = "" + self, root_object: Base, model_name: str, version_message: str = "" ) -> str: """Save a base model to a new version on the project. @@ -120,15 +120,26 @@ class AutomationContext: version_message (str): The message for the new version. """ - if model_id == self.automation_run_data.model_id: + if model_name == self.automation_run_data.branch_name: raise ValueError( - f"The target model id: {model_id} cannot match the model id" - f" that triggered this automation: {self.automation_run_data.model_id}" + f"The target model: {model_name} cannot match the model" + f" that triggered this automation:" + f" {self.automation_run_data.model_id} /" + f" {self.automation_run_data.branch_name}" ) - branch = self._get_model(model_id) - if not branch.name: - raise ValueError(f"The model {model_id} has no name.") + branch = self.speckle_client.branch.get( + self.automation_run_data.project_id, model_name, 1 + ) + # we just check if it exists + if (not branch) or isinstance(branch, SpeckleException): + branch_create = self.speckle_client.branch.create( + self.automation_run_data.project_id, + model_name, + ) + print(branch_create) + if isinstance(branch_create, Exception): + raise branch_create root_object_id = operations.send( root_object, @@ -139,7 +150,7 @@ class AutomationContext: version_id = self.speckle_client.commit.create( stream_id=self.automation_run_data.project_id, object_id=root_object_id, - branch_name=branch.name, + branch_name=model_name, message=version_message, source_application="SpeckleAutomate", ) @@ -150,42 +161,6 @@ class AutomationContext: self._automation_result.result_versions.append(version_id) return version_id - def _get_model(self, model_id: str) -> Branch: - query = gql( - """ - query ProjectModel($projectId: String!, $modelId: String!){ - project(id: $projectId) { - model(id: $modelId) { - name - id - description - } - } - } - """ - ) - params = {"projectId": self.automation_run_data.project_id, "modelId": model_id} - response = self.speckle_client.httpclient.execute(query, params) - return Branch.model_validate(response["project"]["model"]) - - def _get_model(self, model_id: str) -> Branch: - query = gql( - """ - query ProjectModel($projectId: String!, $modelId: String!){ - project(id: $projectId) { - model(id: $modelId) { - name - id - description - } - } - } - """ - ) - params = {"projectId": self.automation_run_data.project_id, "modelId": model_id} - response = self.speckle_client.httpclient.execute(query, params) - return Branch.model_validate(response["project"]["model"]) - def report_run_status(self) -> None: """Report the current run status to the project of this automation.""" query = gql( @@ -196,6 +171,8 @@ class AutomationContext: $automationRunId: String!, $versionId: String!, $functionId: String!, + $functionName: String!, + $functionLogo: String, $runStatus: AutomationRunStatus! $elapsed: Float! $resultVersionIds: [String!]! @@ -211,6 +188,8 @@ class AutomationContext: functionRuns: [ { functionId: $functionId + functionName: $functionName + functionLogo: $functionLogo status: $runStatus, elapsed: $elapsed, resultVersionIds: $resultVersionIds, @@ -241,6 +220,8 @@ class AutomationContext: "automationRunId": self.automation_run_data.automation_run_id, "versionId": self.automation_run_data.version_id, "functionId": self.automation_run_data.function_id, + "functionName": self.automation_run_data.function_name, + "functionLogo": self.automation_run_data.function_logo, "runStatus": self.run_status.value, "statusMessage": self._automation_result.status_message, "elapsed": self.elapsed(), diff --git a/src/speckle_automate/schema.py b/src/speckle_automate/schema.py index d47de5d..6d0a8ac 100644 --- a/src/speckle_automate/schema.py +++ b/src/speckle_automate/schema.py @@ -26,8 +26,8 @@ class AutomationRunData(BaseModel): automation_run_id: str function_id: str - function_release: str function_name: str + function_logo: str | None model_config = ConfigDict( alias_generator=camelcase, populate_by_name=True, protected_namespaces=() From efe9551c5e11ca4080dc7c64ce13eaad1a220be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Wed, 25 Oct 2023 17:53:23 +0200 Subject: [PATCH 21/54] fix: legacy typing and tests --- src/speckle_automate/schema.py | 2 +- .../speckle_automate/test_automation_context.py | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/speckle_automate/schema.py b/src/speckle_automate/schema.py index 6d0a8ac..6970a5a 100644 --- a/src/speckle_automate/schema.py +++ b/src/speckle_automate/schema.py @@ -27,7 +27,7 @@ class AutomationRunData(BaseModel): function_id: str function_name: str - function_logo: str | None + function_logo: Optional[str] model_config = ConfigDict( alias_generator=camelcase, populate_by_name=True, protected_namespaces=() diff --git a/tests/intergration/speckle_automate/test_automation_context.py b/tests/intergration/speckle_automate/test_automation_context.py index f11df63..d32864d 100644 --- a/tests/intergration/speckle_automate/test_automation_context.py +++ b/tests/intergration/speckle_automate/test_automation_context.py @@ -79,7 +79,7 @@ def automation_run_data( automation_run_id = crypto_random_string(10) function_id = crypto_random_string(10) - function_release = crypto_random_string(10) + function_name = f"automate test {crypto_random_string(3)}" return AutomationRunData( project_id=project_id, model_id=model_id, @@ -90,8 +90,8 @@ def automation_run_data( automation_revision_id=automation_revision_id, automation_run_id=automation_run_id, function_id=function_id, - function_release=function_release, - function_name="foobar", + function_name=function_name, + function_logo=None, ) @@ -235,17 +235,14 @@ def test_create_version_in_project_raises_error_for_same_model( ) -> None: with pytest.raises(ValueError): automation_context.create_new_version_in_project( - Base(), automation_context.automation_run_data.model_id + Base(), automation_context.automation_run_data.branch_name ) def test_create_version_in_project( automation_context: AutomationContext, ) -> None: - model_id = automation_context.speckle_client.branch.create( - automation_context.automation_run_data.project_id, "foobar" - ) root_object = Base() root_object.foo = "bar" - version_id = automation_context.create_new_version_in_project(root_object, model_id) + version_id = automation_context.create_new_version_in_project(root_object, "foobar") assert version_id is not None From 1ff32455310e856dd89e4a0d6a8d7af2ccc87cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Thu, 26 Oct 2023 13:32:48 +0200 Subject: [PATCH 22/54] feat: automate sdk report context view --- src/speckle_automate/automation_context.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index 1176006..b8b9e98 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -175,6 +175,7 @@ class AutomationContext: $functionLogo: String, $runStatus: AutomationRunStatus! $elapsed: Float! + $contextView: String $resultVersionIds: [String!]! $statusMessage: String $objectResults: JSONObject @@ -191,6 +192,7 @@ class AutomationContext: functionName: $functionName functionLogo: $functionLogo status: $runStatus, + contextView: $contextView, elapsed: $elapsed, resultVersionIds: $resultVersionIds, statusMessage: $statusMessage @@ -224,6 +226,7 @@ class AutomationContext: "functionLogo": self.automation_run_data.function_logo, "runStatus": self.run_status.value, "statusMessage": self._automation_result.status_message, + "contextView": self._automation_result.result_view, "elapsed": self.elapsed(), "resultVersionIds": self._automation_result.result_versions, "objectResults": object_results, From a1831b57dbbd515a6044d1d542a08803c29a071c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Thu, 26 Oct 2023 15:00:03 +0200 Subject: [PATCH 23/54] feat: automation context result view reporting and creating --- src/speckle_automate/automation_context.py | 34 +++++++++++++++--- .../test_automation_context.py | 36 ++++++++++++++++++- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index b8b9e98..b3cecb2 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -2,7 +2,7 @@ from dataclasses import dataclass, field from pathlib import Path import time -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Tuple, Union import httpx from gql import gql @@ -111,7 +111,7 @@ class AutomationContext: def create_new_version_in_project( self, root_object: Base, model_name: str, version_message: str = "" - ) -> str: + ) -> Tuple[str, str]: """Save a base model to a new version on the project. Args: @@ -137,9 +137,11 @@ class AutomationContext: self.automation_run_data.project_id, model_name, ) - print(branch_create) if isinstance(branch_create, Exception): raise branch_create + model_id = branch_create + else: + model_id = branch.id root_object_id = operations.send( root_object, @@ -159,7 +161,31 @@ class AutomationContext: raise version_id self._automation_result.result_versions.append(version_id) - return version_id + return model_id, version_id + + def set_context_view( + self, + # f"{model_id}@{version_id} or {model_id} " + resource_ids: Optional[List[str]] = None, + include_source_model_version: bool = True, + ) -> None: + link_resources = ( + [ + f"{self.automation_run_data.model_id}@{self.automation_run_data.version_id}" + ] + if include_source_model_version + else [] + ) + if resource_ids: + link_resources.append(*resource_ids) + if not link_resources: + raise Exception( + "We do not have enough resource ids to compose a context view" + ) + self._automation_result.result_view = ( + f"{self.automation_run_data.speckle_server_url}/projects" + f"/{self.automation_run_data.project_id}/models/{','.join(link_resources)}" + ) def report_run_status(self) -> None: """Report the current run status to the project of this automation.""" diff --git a/tests/intergration/speckle_automate/test_automation_context.py b/tests/intergration/speckle_automate/test_automation_context.py index d32864d..42323c5 100644 --- a/tests/intergration/speckle_automate/test_automation_context.py +++ b/tests/intergration/speckle_automate/test_automation_context.py @@ -244,5 +244,39 @@ def test_create_version_in_project( ) -> None: root_object = Base() root_object.foo = "bar" - version_id = automation_context.create_new_version_in_project(root_object, "foobar") + model_id, version_id = automation_context.create_new_version_in_project( + root_object, "foobar" + ) + + assert model_id is not None assert version_id is not None + + +def test_set_context_view(automation_context: AutomationContext) -> None: + automation_context.set_context_view() + + assert automation_context._automation_result.result_view is not None + assert automation_context._automation_result.result_view.endswith( + f"models/{automation_context.automation_run_data.model_id}@{automation_context.automation_run_data.version_id}" + ) + + automation_context._automation_result.result_view = None + + dummy_context = "foo@bar" + automation_context.set_context_view([dummy_context]) + + assert automation_context._automation_result.result_view is not None + assert automation_context._automation_result.result_view.endswith( + f"models/{automation_context.automation_run_data.model_id}@{automation_context.automation_run_data.version_id},{dummy_context}" + ) + automation_context._automation_result.result_view = None + + dummy_context = "foo@baz" + automation_context.set_context_view( + [dummy_context], include_source_model_version=False + ) + + assert automation_context._automation_result.result_view is not None + assert automation_context._automation_result.result_view.endswith( + f"models/{dummy_context}" + ) From 2742c12e318ae0bcc3bb052799158054ae115aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Thu, 26 Oct 2023 15:35:39 +0200 Subject: [PATCH 24/54] fix: automate sdk context view is a realative url --- src/speckle_automate/automation_context.py | 4 ++-- .../intergration/speckle_automate/test_automation_context.py | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index b3cecb2..3e5f48e 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -183,8 +183,8 @@ class AutomationContext: "We do not have enough resource ids to compose a context view" ) self._automation_result.result_view = ( - f"{self.automation_run_data.speckle_server_url}/projects" - f"/{self.automation_run_data.project_id}/models/{','.join(link_resources)}" + f"/projects/{self.automation_run_data.project_id}" + f"/models/{','.join(link_resources)}" ) def report_run_status(self) -> None: diff --git a/tests/intergration/speckle_automate/test_automation_context.py b/tests/intergration/speckle_automate/test_automation_context.py index 42323c5..5f48ced 100644 --- a/tests/intergration/speckle_automate/test_automation_context.py +++ b/tests/intergration/speckle_automate/test_automation_context.py @@ -260,6 +260,8 @@ def test_set_context_view(automation_context: AutomationContext) -> None: f"models/{automation_context.automation_run_data.model_id}@{automation_context.automation_run_data.version_id}" ) + automation_context.report_run_status() + automation_context._automation_result.result_view = None dummy_context = "foo@bar" @@ -269,6 +271,8 @@ def test_set_context_view(automation_context: AutomationContext) -> None: assert automation_context._automation_result.result_view.endswith( f"models/{automation_context.automation_run_data.model_id}@{automation_context.automation_run_data.version_id},{dummy_context}" ) + automation_context.report_run_status() + automation_context._automation_result.result_view = None dummy_context = "foo@baz" @@ -280,3 +284,4 @@ def test_set_context_view(automation_context: AutomationContext) -> None: assert automation_context._automation_result.result_view.endswith( f"models/{dummy_context}" ) + automation_context.report_run_status() From d9b92490ecd93a611d0fcbf12176878549dc72fb Mon Sep 17 00:00:00 2001 From: oguzhankoral Date: Fri, 27 Oct 2023 16:33:02 +0300 Subject: [PATCH 25/54] Add text object definition --- src/specklepy/objects/other.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/specklepy/objects/other.py b/src/specklepy/objects/other.py index 3b9c120..c382840 100644 --- a/src/specklepy/objects/other.py +++ b/src/specklepy/objects/other.py @@ -1,7 +1,7 @@ from typing import Any, List, Optional from deprecated import deprecated -from specklepy.objects.geometry import Point, Vector +from specklepy.objects.geometry import Point, Vector, Plane from .base import Base @@ -71,6 +71,17 @@ class DisplayStyle(Base, speckle_type=OTHER + "DisplayStyle"): lineweight: float = 0 +class Text(Base, speckle_type=OTHER + "Text"): + """ + Text object to render it on viewer. + """ + plane: Plane + value: str + height: float + rotation: float + displayStyle: DisplayStyle + + class Transform( Base, speckle_type=OTHER + "Transform", From 45b50e4f26f15538dab2225eab9708de2d8b482a Mon Sep 17 00:00:00 2001 From: oguzhankoral Date: Mon, 30 Oct 2023 11:42:30 +0300 Subject: [PATCH 26/54] Add optional props of Objects.Other.Text --- src/specklepy/objects/other.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/specklepy/objects/other.py b/src/specklepy/objects/other.py index c382840..e74e127 100644 --- a/src/specklepy/objects/other.py +++ b/src/specklepy/objects/other.py @@ -1,7 +1,7 @@ from typing import Any, List, Optional from deprecated import deprecated -from specklepy.objects.geometry import Point, Vector, Plane +from specklepy.objects.geometry import Point, Vector, Plane, Polyline from .base import Base @@ -80,6 +80,8 @@ class Text(Base, speckle_type=OTHER + "Text"): height: float rotation: float displayStyle: DisplayStyle + displayValue: Optional[Polyline] = None + richText: Optional[str] = None class Transform( From e6131a79566b0b53467f6f1a9ac33a679994ffbf Mon Sep 17 00:00:00 2001 From: oguzhankoral Date: Mon, 30 Oct 2023 11:51:15 +0300 Subject: [PATCH 27/54] Fix typo on type of displayValue --- src/specklepy/objects/other.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/specklepy/objects/other.py b/src/specklepy/objects/other.py index e74e127..12d6663 100644 --- a/src/specklepy/objects/other.py +++ b/src/specklepy/objects/other.py @@ -80,7 +80,7 @@ class Text(Base, speckle_type=OTHER + "Text"): height: float rotation: float displayStyle: DisplayStyle - displayValue: Optional[Polyline] = None + displayValue: Optional[List[Polyline]] = None richText: Optional[str] = None From 6c223b6fb3cafbdc676ed27884c1943565de1f2a Mon Sep 17 00:00:00 2001 From: oguzhankoral Date: Mon, 30 Oct 2023 14:07:36 +0300 Subject: [PATCH 28/54] Exclude displayStyle from Text object It shouldn't be have displayStyle for general purpose Text object, because displayStyle more Rhino and AutoCAD specific --- src/specklepy/objects/other.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/specklepy/objects/other.py b/src/specklepy/objects/other.py index 12d6663..4878520 100644 --- a/src/specklepy/objects/other.py +++ b/src/specklepy/objects/other.py @@ -79,7 +79,6 @@ class Text(Base, speckle_type=OTHER + "Text"): value: str height: float rotation: float - displayStyle: DisplayStyle displayValue: Optional[List[Polyline]] = None richText: Optional[str] = None From 75e6f0229a662b886357a0f97790e69fd07fb29d Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Thu, 9 Nov 2023 17:34:57 +0000 Subject: [PATCH 29/54] update stream wrapper; add tests --- src/specklepy/core/api/wrapper.py | 50 ++++++++++++++++++++++++++++-- tests/intergration/test_wrapper.py | 21 +++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/specklepy/core/api/wrapper.py b/src/specklepy/core/api/wrapper.py index 6e22b97..6c84c44 100644 --- a/src/specklepy/core/api/wrapper.py +++ b/src/specklepy/core/api/wrapper.py @@ -1,5 +1,7 @@ +import re from urllib.parse import unquote, urlparse from warnings import warn +from gql import gql from specklepy.core.api.client import SpeckleClient from specklepy.core.api.credentials import ( @@ -81,13 +83,25 @@ class StreamWrapper: " provided." ) + # check for fe2 URL + if "/projects/" in parsed.path: + use_fe2 = True + else: + use_fe2 = False + while segments: segment = segments.pop(0) - if segments and segment.lower() == "streams": + if segments and ( + (use_fe2 is False and segment.lower() == "streams") + or (use_fe2 is True and segment.lower() == "projects") + ): self.stream_id = segments.pop(0) elif segments and segment.lower() == "commits": self.commit_id = segments.pop(0) - elif segments and segment.lower() == "branches": + elif segments and ( + (use_fe2 is False and segment.lower() == "branches") + or (use_fe2 is True and segment.lower() == "models") + ): self.branch_name = unquote(segments.pop(0)) elif segments and segment.lower() == "objects": self.object_id = segments.pop(0) @@ -101,6 +115,38 @@ class StreamWrapper: " provided." ) + if use_fe2 is True and self.branch_name is not None: + if "," in self.branch_name: + raise SpeckleException("Multi-model urls are not supported yet") + + if "@" in self.branch_name: + model_id = self.branch_name.split("@")[0] + self.commit_id = self.branch_name.split("@")[1] + else: + model_id = self.branch_name + + # get branch name + query = gql( + """ + query Project($project_id: String!, $model_id: String!) { + project(id: $project_id) { + id + model(id: $model_id) { + name + } + } + } + """ + ) + self._client = self.get_client() + params = {"project_id": self.stream_id, "model_id": model_id} + project = self._client.httpclient.execute(query, params) + + try: + self.branch_name = project["project"]["model"]["name"] + except KeyError as ke: + raise SpeckleException("Project model name is not found", ke) + if not self.stream_id: raise SpeckleException( f"Cannot parse {url} into a stream wrapper class - no stream id found." diff --git a/tests/intergration/test_wrapper.py b/tests/intergration/test_wrapper.py index e74c361..5ab0bb7 100644 --- a/tests/intergration/test_wrapper.py +++ b/tests/intergration/test_wrapper.py @@ -126,3 +126,24 @@ def test_wrapper_url_match(user_path) -> None: account = wrap.get_account() assert account.userInfo.email is None + + +def test_parse_project(): + wrap = StreamWrapper("https://latest.speckle.systems/projects/843d07eb10") + assert wrap.type == "stream" + + +def test_parse_model(): + wrap = StreamWrapper( + "https://latest.speckle.systems/projects/843d07eb10/models/d9eb4918c8" + ) + + assert wrap.branch_name == "building wrapper" + assert wrap.type == "branch" + + +def test_parse_version(): + wrap = StreamWrapper( + "https://latest.speckle.systems/projects/843d07eb10/models/4e7345c838@c42d5cbac1" + ) + assert wrap.type == "commit" From 5bde1bc2d685c26634c9c9fff39c87c696ac3cce Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Thu, 9 Nov 2023 17:36:06 +0000 Subject: [PATCH 30/54] remove library --- src/specklepy/core/api/wrapper.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/specklepy/core/api/wrapper.py b/src/specklepy/core/api/wrapper.py index 6c84c44..9f9a11e 100644 --- a/src/specklepy/core/api/wrapper.py +++ b/src/specklepy/core/api/wrapper.py @@ -1,4 +1,3 @@ -import re from urllib.parse import unquote, urlparse from warnings import warn from gql import gql From 71d3589e728b7a943fcef7cea9ba3f36a3c38f05 Mon Sep 17 00:00:00 2001 From: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com> Date: Fri, 10 Nov 2023 13:54:02 +0000 Subject: [PATCH 31/54] pinned MinIO version for integration test docker compose --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index ec52659..01f7e19 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,7 +33,7 @@ services: retries: 30 minio: - image: "minio/minio" + image: "minio/minio:RELEASE.2023-10-25T06-33-25Z" command: server /data --console-address ":9001" restart: always volumes: From c0dd88cbdb73bca8cf44ea8380860dc86037ba16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 10 Nov 2023 15:04:30 +0100 Subject: [PATCH 32/54] fix: pin minio release to fix tests --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index ec52659..01f7e19 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,7 +33,7 @@ services: retries: 30 minio: - image: "minio/minio" + image: "minio/minio:RELEASE.2023-10-25T06-33-25Z" command: server /data --console-address ":9001" restart: always volumes: From 10f49579fdde54726624edbbaeb062f0863ede45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Sat, 11 Nov 2023 08:29:16 +0100 Subject: [PATCH 33/54] fix: report relative url for context view --- pyproject.toml | 2 +- src/speckle_automate/automation_context.py | 4 ++++ src/speckle_automate/runner.py | 2 ++ .../speckle_automate/test_automation_context.py | 14 ++++++-------- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7e8bb29..9bc2528 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "specklepy" -version = "2.17.5" +version = "2.17.8" description = "The Python SDK for Speckle 2.0" readme = "README.md" authors = ["Speckle Systems "] diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index 3e5f48e..30b95f6 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -163,6 +163,10 @@ class AutomationContext: self._automation_result.result_versions.append(version_id) return model_id, version_id + @property + def context_view(self) -> Optional[str]: + return self._automation_result.result_view + def set_context_view( self, # f"{model_id}@{version_id} or {model_id} " diff --git a/src/speckle_automate/runner.py b/src/speckle_automate/runner.py index 32f5ee7..d60096a 100644 --- a/src/speckle_automate/runner.py +++ b/src/speckle_automate/runner.py @@ -146,5 +146,7 @@ def run_function( "Function error. Check the automation run logs for details." ) finally: + if not automation_context.context_view: + automation_context.set_context_view() automation_context.report_run_status() return automation_context diff --git a/tests/intergration/speckle_automate/test_automation_context.py b/tests/intergration/speckle_automate/test_automation_context.py index 5f48ced..2d6d2a0 100644 --- a/tests/intergration/speckle_automate/test_automation_context.py +++ b/tests/intergration/speckle_automate/test_automation_context.py @@ -255,8 +255,8 @@ def test_create_version_in_project( def test_set_context_view(automation_context: AutomationContext) -> None: automation_context.set_context_view() - assert automation_context._automation_result.result_view is not None - assert automation_context._automation_result.result_view.endswith( + assert automation_context.context_view is not None + assert automation_context.context_view.endswith( f"models/{automation_context.automation_run_data.model_id}@{automation_context.automation_run_data.version_id}" ) @@ -267,8 +267,8 @@ def test_set_context_view(automation_context: AutomationContext) -> None: dummy_context = "foo@bar" automation_context.set_context_view([dummy_context]) - assert automation_context._automation_result.result_view is not None - assert automation_context._automation_result.result_view.endswith( + assert automation_context.context_view is not None + assert automation_context.context_view.endswith( f"models/{automation_context.automation_run_data.model_id}@{automation_context.automation_run_data.version_id},{dummy_context}" ) automation_context.report_run_status() @@ -280,8 +280,6 @@ def test_set_context_view(automation_context: AutomationContext) -> None: [dummy_context], include_source_model_version=False ) - assert automation_context._automation_result.result_view is not None - assert automation_context._automation_result.result_view.endswith( - f"models/{dummy_context}" - ) + assert automation_context.context_view is not None + assert automation_context.context_view.endswith(f"models/{dummy_context}") automation_context.report_run_status() From f6ff484e660605865348c3ae78a2a65722d4c354 Mon Sep 17 00:00:00 2001 From: KatKatKateryna <89912278+KatKatKateryna@users.noreply.github.com> Date: Mon, 13 Nov 2023 04:53:03 +0800 Subject: [PATCH 34/54] handle "append" with incoming type "list" --- src/speckle_automate/automation_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index 30b95f6..fac058d 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -181,7 +181,7 @@ class AutomationContext: else [] ) if resource_ids: - link_resources.append(*resource_ids) + link_resources.extend(resource_ids) if not link_resources: raise Exception( "We do not have enough resource ids to compose a context view" From 04764b17eb45aed8865d3ae56ea7a0731f075ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Mon, 13 Nov 2023 09:14:06 +0100 Subject: [PATCH 35/54] feat: reduce log message context for object results --- src/speckle_automate/automation_context.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index fac058d..e315856 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -405,8 +405,8 @@ class AutomationContext: else: id_list = [object_ids] print( - f"Object {', '.join(id_list)} was marked with {level.value.upper()}", - f"/{category} cause: {message}", + f"Created new {level.value.upper()}" + f" category: {category} caused by: {message}" ) self._automation_result.object_results.append( ResultCase( From e3716f62061a37a9adbb0527cc66303e150f910c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Tue, 14 Nov 2023 16:23:10 +0100 Subject: [PATCH 36/54] feat: log reported run status --- src/speckle_automate/automation_context.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index fac058d..678a9ec 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -261,6 +261,7 @@ class AutomationContext: "resultVersionIds": self._automation_result.result_versions, "objectResults": object_results, } + print(f"Reporting run status with content: {params}") self.speckle_client.httpclient.execute(query, params) def store_file_result(self, file_path: Union[Path, str]) -> None: From 42737c4ed24e37fffd9728d71585637488b8dc6d Mon Sep 17 00:00:00 2001 From: Iain Sproat <68657+iainsproat@users.noreply.github.com> Date: Fri, 24 Nov 2023 15:52:30 +0000 Subject: [PATCH 37/54] feat(client): configurable certificate verification --- src/specklepy/core/api/client.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/specklepy/core/api/client.py b/src/specklepy/core/api/client.py index 197fcc9..eac8fd2 100644 --- a/src/specklepy/core/api/client.py +++ b/src/specklepy/core/api/client.py @@ -58,8 +58,9 @@ class SpeckleClient: DEFAULT_HOST = "speckle.xyz" USE_SSL = True + VERIFY_CERTIFICATE = True - def __init__(self, host: str = DEFAULT_HOST, use_ssl: bool = USE_SSL) -> None: + def __init__(self, host: str = DEFAULT_HOST, use_ssl: bool = USE_SSL, verify_certificate: bool = VERIFY_CERTIFICATE) -> None: ws_protocol = "ws" http_protocol = "http" @@ -74,9 +75,10 @@ class SpeckleClient: self.graphql = f"{self.url}/graphql" self.ws_url = f"{ws_protocol}://{host}/graphql" self.account = Account() + self.verify_certificate = verify_certificate self.httpclient = Client( - transport=RequestsHTTPTransport(url=self.graphql, verify=True, retries=3) + transport=RequestsHTTPTransport(url=self.graphql, verify=self.verify_certificate, retries=3) ) self.wsclient = None @@ -150,7 +152,7 @@ class SpeckleClient: "apollographql-client-version": metrics.HOST_APP_VERSION, } httptransport = RequestsHTTPTransport( - url=self.graphql, headers=headers, verify=True, retries=3 + url=self.graphql, headers=headers, verify=self.verify_certificate, retries=3 ) wstransport = WebsocketsTransport( url=self.ws_url, From 1ce61bdda868908bc666ad27b37b7e052879a43d Mon Sep 17 00:00:00 2001 From: Iain Sproat <68657+iainsproat@users.noreply.github.com> Date: Fri, 24 Nov 2023 16:37:51 +0000 Subject: [PATCH 38/54] ci(pre-commit): add a pre-commit job to CI --- .circleci/config.yml | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a465bf6..662eb1d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,10 +1,43 @@ version: 2.1 orbs: - python: circleci/python@2.0.3 - codecov: codecov/codecov@3.2.2 + codecov: codecov/codecov@3.3.0 jobs: + pre-commit: + parameters: + config_file: + default: ./.pre-commit-config.yaml + description: Optional, path to pre-commit config file. + type: string + cache_prefix: + default: '' + description: | + Optional cache prefix to be used on CircleCI. Can be used for cache busting or to ensure multiple jobs use different caches. + type: string + docker: + - image: speckle/pre-commit-runner:latest + resource_class: medium + steps: + - checkout + - restore_cache: + keys: + - cache-pre-commit-<>-{{ checksum "<>" }} + - run: + name: Install pre-commit hooks + command: pre-commit install-hooks --config <> + - save_cache: + key: cache-pre-commit-<>-{{ checksum "<>" }} + paths: + - ~/.cache/pre-commit + - run: + name: Run pre-commit + command: pre-commit run --all-files + - run: + command: git --no-pager diff + name: git diff + when: on_fail + test: machine: image: ubuntu-2204:2023.02.1 @@ -52,6 +85,10 @@ jobs: workflows: main: jobs: + - pre-commit: + filters: + tags: + only: /.*/ - test: matrix: parameters: @@ -62,6 +99,7 @@ workflows: - deploy: context: pypi requires: + - pre-commit - test filters: tags: From 357859288d0091dce285edc9a6b805a5b53fe16b Mon Sep 17 00:00:00 2001 From: Iain Sproat <68657+iainsproat@users.noreply.github.com> Date: Fri, 24 Nov 2023 16:41:47 +0000 Subject: [PATCH 39/54] chore(pre-commit autoupdate): install latest packages to prevent build errors --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 600e0fa..83f4105 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ repos: - repo: https://github.com/charliermarsh/ruff-pre-commit hooks: - id: ruff - rev: v0.0.186 + rev: v0.1.6 - repo: https://github.com/commitizen-tools/commitizen hooks: @@ -10,15 +10,15 @@ repos: - id: commitizen-branch stages: - push - rev: v2.38.0 + rev: 3.12.0 - repo: https://github.com/pycqa/isort - rev: v5.11.3 + rev: 5.12.0 hooks: - id: isort - repo: https://github.com/psf/black - rev: 22.12.0 + rev: 23.11.0 hooks: - id: black # It is recommended to specify the latest version of Python @@ -27,7 +27,7 @@ repos: # https://pre-commit.com/#top_level-default_language_version # language_version: python3.11 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace From 4dc148181ece616e215615b30fe5038dbb245790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Mon, 27 Nov 2023 12:21:26 +0100 Subject: [PATCH 40/54] chore: reformat --- src/specklepy/api/host_applications.py | 47 +++++++++--- src/specklepy/api/models.py | 23 ++++-- src/specklepy/api/operations.py | 11 ++- src/specklepy/api/resource.py | 13 ++-- src/specklepy/api/resources/active_user.py | 4 +- src/specklepy/api/resources/object.py | 1 - src/specklepy/api/resources/other_user.py | 5 +- src/specklepy/api/resources/server.py | 2 +- src/specklepy/api/resources/stream.py | 7 +- src/specklepy/api/resources/subscriptions.py | 9 ++- src/specklepy/api/resources/user.py | 15 ++-- src/specklepy/api/wrapper.py | 9 ++- src/specklepy/core/api/credentials.py | 2 +- src/specklepy/core/api/operations.py | 2 +- .../core/api/resources/active_user.py | 6 +- src/specklepy/core/api/resources/stream.py | 9 ++- src/specklepy/core/api/resources/user.py | 6 +- src/specklepy/logging/metrics.py | 4 +- src/specklepy/objects/GIS/CRS.py | 4 +- src/specklepy/objects/GIS/__init__.py | 13 +++- src/specklepy/objects/GIS/geometry.py | 45 +++++++++--- src/specklepy/objects/GIS/layers.py | 73 ++++++++++--------- .../graph_traversal/commit_object_builder.py | 64 +++++++++++----- .../objects/graph_traversal/traversal.py | 19 +++-- src/specklepy/objects/other.py | 18 ++--- src/specklepy/objects/structural/__init__.py | 5 +- src/specklepy/objects/units.py | 6 +- .../transports/server/batch_sender.py | 2 +- tests/unit/test_graph_traversal.py | 2 +- tests/unit/test_type_validation.py | 7 +- tests/unit/test_unit_scaling.py | 22 +++--- utils/installer.py | 31 ++++---- 32 files changed, 303 insertions(+), 183 deletions(-) diff --git a/src/specklepy/api/host_applications.py b/src/specklepy/api/host_applications.py index 8889e74..c9e2a55 100644 --- a/src/specklepy/api/host_applications.py +++ b/src/specklepy/api/host_applications.py @@ -2,17 +2,44 @@ from dataclasses import dataclass from enum import Enum from unicodedata import name -# following imports seem to be unnecessary, but they need to stay +# following imports seem to be unnecessary, but they need to stay # to not break the scripts using these functions as non-core -from specklepy.core.api.host_applications import (HostApplication, HostAppVersion, - get_host_app_from_string, - _app_name_host_app_mapping, - RHINO,GRASSHOPPER,REVIT,DYNAMO,UNITY,GSA, - CIVIL,AUTOCAD,MICROSTATION,OPENROADS, - OPENRAIL,OPENBUILDINGS,ETABS,SAP2000,CSIBRIDGE, - SAFE,TEKLASTRUCTURES,DXF,EXCEL,UNREAL,POWERBI, - BLENDER,QGIS,ARCGIS,SKETCHUP,ARCHICAD,TOPSOLID, - PYTHON,NET,OTHER) +from specklepy.core.api.host_applications import ( + HostApplication, + HostAppVersion, + get_host_app_from_string, + _app_name_host_app_mapping, + RHINO, + GRASSHOPPER, + REVIT, + DYNAMO, + UNITY, + GSA, + CIVIL, + AUTOCAD, + MICROSTATION, + OPENROADS, + OPENRAIL, + OPENBUILDINGS, + ETABS, + SAP2000, + CSIBRIDGE, + SAFE, + TEKLASTRUCTURES, + DXF, + EXCEL, + UNREAL, + POWERBI, + BLENDER, + QGIS, + ARCGIS, + SKETCHUP, + ARCHICAD, + TOPSOLID, + PYTHON, + NET, + OTHER, +) if __name__ == "__main__": print(HostAppVersion.v) diff --git a/src/specklepy/api/models.py b/src/specklepy/api/models.py index 8640d21..12346dd 100644 --- a/src/specklepy/api/models.py +++ b/src/specklepy/api/models.py @@ -3,10 +3,21 @@ from typing import List, Optional from pydantic import BaseModel, Field -# following imports seem to be unnecessary, but they need to stay +# following imports seem to be unnecessary, but they need to stay # to not break the scripts using these functions as non-core -from specklepy.core.api.models import (Collaborator, Commit, - Commits, Object, Branch, Branches, - Stream, Streams, User, LimitedUser, - PendingStreamCollaborator, Activity, - ActivityCollection, ServerInfo) +from specklepy.core.api.models import ( + Collaborator, + Commit, + Commits, + Object, + Branch, + Branches, + Stream, + Streams, + User, + LimitedUser, + PendingStreamCollaborator, + Activity, + ActivityCollection, + ServerInfo, +) diff --git a/src/specklepy/api/operations.py b/src/specklepy/api/operations.py index a86da77..489b65e 100644 --- a/src/specklepy/api/operations.py +++ b/src/specklepy/api/operations.py @@ -7,10 +7,12 @@ from specklepy.serialization.base_object_serializer import BaseObjectSerializer from specklepy.transports.abstract_transport import AbstractTransport from specklepy.transports.sqlite import SQLiteTransport -from specklepy.core.api.operations import (send as core_send, - receive as _untracked_receive, - serialize as core_serialize, - deserialize as core_deserialize) +from specklepy.core.api.operations import ( + send as core_send, + receive as _untracked_receive, + serialize as core_serialize, + deserialize as core_deserialize, +) def send( @@ -74,6 +76,7 @@ def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str metrics.track(metrics.SDK, custom_props={"name": "Serialize"}) return core_serialize(base, write_transports) + def deserialize( obj_string: str, read_transport: Optional[AbstractTransport] = None ) -> Base: diff --git a/src/specklepy/api/resource.py b/src/specklepy/api/resource.py index 0727b44..028bceb 100644 --- a/src/specklepy/api/resource.py +++ b/src/specklepy/api/resource.py @@ -14,7 +14,7 @@ from specklepy.logging.exceptions import ( from specklepy.serialization.base_object_serializer import BaseObjectSerializer from specklepy.transports.sqlite import SQLiteTransport -# following imports seem to be unnecessary, but they need to stay +# following imports seem to be unnecessary, but they need to stay # to not break the scripts using these functions as non-core from specklepy.core.api.resource import ResourceBase as CoreResourceBase @@ -29,10 +29,9 @@ class ResourceBase(CoreResourceBase): server_version: Optional[Tuple[Any, ...]] = None, ) -> None: super().__init__( - account = account, - basepath = basepath, - client = client, - name = name, - server_version = server_version + account=account, + basepath=basepath, + client=client, + name=name, + server_version=server_version, ) - \ No newline at end of file diff --git a/src/specklepy/api/resources/active_user.py b/src/specklepy/api/resources/active_user.py index 20a2ef0..c33d16b 100644 --- a/src/specklepy/api/resources/active_user.py +++ b/src/specklepy/api/resources/active_user.py @@ -97,7 +97,9 @@ class Resource(CoreResource): List[PendingStreamCollaborator] -- a list of pending invites for the current user """ - metrics.track(metrics.SDK, self.account, {"name": "User Active Invites All Get"}) + metrics.track( + metrics.SDK, self.account, {"name": "User Active Invites All Get"} + ) return super().get_all_pending_invites() def get_pending_invite( diff --git a/src/specklepy/api/resources/object.py b/src/specklepy/api/resources/object.py index 3cc5dca..b6683d3 100644 --- a/src/specklepy/api/resources/object.py +++ b/src/specklepy/api/resources/object.py @@ -58,4 +58,3 @@ class Resource(CoreResource): """ metrics.track(metrics.SDK, self.account, {"name": "Object Create"}) return super().create(stream_id, objects) - \ No newline at end of file diff --git a/src/specklepy/api/resources/other_user.py b/src/specklepy/api/resources/other_user.py index b277b0a..585afd4 100644 --- a/src/specklepy/api/resources/other_user.py +++ b/src/specklepy/api/resources/other_user.py @@ -54,7 +54,7 @@ class Resource(CoreResource): ) metrics.track(metrics.SDK, self.account, {"name": "Other User Search"}) - return super().search(search_query, limit) + return super().search(search_query, limit) def activity( self, @@ -83,5 +83,4 @@ class Resource(CoreResource): cursor {datetime} -- timestamp cursor for pagination """ metrics.track(metrics.SDK, self.account, {"name": "Other User Activity"}) - return super().activity(user_id, limit, action_type, before, after, cursor) - \ No newline at end of file + return super().activity(user_id, limit, action_type, before, after, cursor) diff --git a/src/specklepy/api/resources/server.py b/src/specklepy/api/resources/server.py index 1af78d0..74cc957 100644 --- a/src/specklepy/api/resources/server.py +++ b/src/specklepy/api/resources/server.py @@ -73,4 +73,4 @@ class Resource(CoreResource): bool -- True if the token was successfully deleted """ metrics.track(metrics.SDK, self.account, {"name": "Server Revoke Token"}) - return super().revoke_token(token) + return super().revoke_token(token) diff --git a/src/specklepy/api/resources/stream.py b/src/specklepy/api/resources/stream.py index 26b2a6c..3e5558a 100644 --- a/src/specklepy/api/resources/stream.py +++ b/src/specklepy/api/resources/stream.py @@ -256,7 +256,11 @@ class Resource(CoreResource): Returns: bool -- True if the operation was successful """ - metrics.track(metrics.SDK, self.account, {"name": "Stream Permission Update", "role": role}) + metrics.track( + metrics.SDK, + self.account, + {"name": "Stream Permission Update", "role": role}, + ) return super().update_permission(stream_id, user_id, role) def revoke_permission(self, stream_id: str, user_id: str): @@ -301,4 +305,3 @@ class Resource(CoreResource): """ metrics.track(metrics.SDK, self.account, {"name": "Stream Activity"}) return super().activity(stream_id, action_type, limit, before, after, cursor) - \ No newline at end of file diff --git a/src/specklepy/api/resources/subscriptions.py b/src/specklepy/api/resources/subscriptions.py index d8cbdc9..d8b11ee 100644 --- a/src/specklepy/api/resources/subscriptions.py +++ b/src/specklepy/api/resources/subscriptions.py @@ -11,6 +11,7 @@ from specklepy.logging.exceptions import SpeckleException from specklepy.logging import metrics from specklepy.core.api.resources.subscriptions import Resource as CoreResource + def check_wsclient(function): @wraps(function) async def check_wsclient_wrapper(self, *args, **kwargs): @@ -64,7 +65,9 @@ class Resource(CoreResource): Returns: Stream -- the update stream """ - metrics.track(metrics.SDK, self.account, {"name": "Subscription Stream Updated"}) + metrics.track( + metrics.SDK, self.account, {"name": "Subscription Stream Updated"} + ) return super().stream_updated(id, callback) @check_wsclient @@ -83,7 +86,9 @@ class Resource(CoreResource): Returns: dict -- dict containing 'id' of stream removed and optionally 'revokedBy' """ - metrics.track(metrics.SDK, self.account, {"name": "Subscription Stream Removed"}) + metrics.track( + metrics.SDK, self.account, {"name": "Subscription Stream Removed"} + ) return super().stream_removed(callback) @check_wsclient diff --git a/src/specklepy/api/resources/user.py b/src/specklepy/api/resources/user.py index 2aa2bf6..f603f87 100644 --- a/src/specklepy/api/resources/user.py +++ b/src/specklepy/api/resources/user.py @@ -46,7 +46,7 @@ class Resource(CoreResource): """ metrics.track(metrics.SDK, self.account, {"name": "User Get_deprecated"}) return super().get(id) - + @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_TEXT) def search( self, search_query: str, limit: int = 25 @@ -83,7 +83,7 @@ class Resource(CoreResource): Returns: bool -- True if your profile was updated successfully """ - #metrics.track(metrics.USER, self.account, {"name": "update"}) + # metrics.track(metrics.USER, self.account, {"name": "update"}) metrics.track(metrics.SDK, self.account, {"name": "User Update_deprecated"}) return super().update(name, company, bio, avatar) @@ -118,7 +118,6 @@ class Resource(CoreResource): """ metrics.track(metrics.SDK, self.account, {"name": "User Activity_deprecated"}) return super().activity(user_id, limit, action_type, before, after, cursor) - @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_TEXT) def get_all_pending_invites(self) -> List[PendingStreamCollaborator]: @@ -130,10 +129,11 @@ class Resource(CoreResource): List[PendingStreamCollaborator] -- a list of pending invites for the current user """ - #metrics.track(metrics.INVITE, self.account, {"name": "get"}) - metrics.track(metrics.SDK, self.account, {"name": "User GetAllInvites_deprecated"}) + # metrics.track(metrics.INVITE, self.account, {"name": "get"}) + metrics.track( + metrics.SDK, self.account, {"name": "User GetAllInvites_deprecated"} + ) return super().get_all_pending_invites() - @deprecated(version=DEPRECATION_VERSION, reason=DEPRECATION_TEXT) def get_pending_invite( @@ -152,7 +152,6 @@ class Resource(CoreResource): PendingStreamCollaborator -- the invite for the given stream (or None if it isn't found) """ - #metrics.track(metrics.INVITE, self.account, {"name": "get"}) + # metrics.track(metrics.INVITE, self.account, {"name": "get"}) metrics.track(metrics.SDK, self.account, {"name": "User GetInvite_deprecated"}) return super().get_pending_invite(stream_id, token) - \ No newline at end of file diff --git a/src/specklepy/api/wrapper.py b/src/specklepy/api/wrapper.py index eb480d1..7a3ae31 100644 --- a/src/specklepy/api/wrapper.py +++ b/src/specklepy/api/wrapper.py @@ -11,7 +11,8 @@ from specklepy.logging.exceptions import SpeckleException, SpeckleWarning from specklepy.transports.server.server import ServerTransport from specklepy.logging import metrics -from specklepy.core.api.wrapper import StreamWrapper as CoreStreamWrapper +from specklepy.core.api.wrapper import StreamWrapper as CoreStreamWrapper + class StreamWrapper(CoreStreamWrapper): """ @@ -51,7 +52,7 @@ class StreamWrapper(CoreStreamWrapper): _account: Account = None def __init__(self, url: str) -> None: - super().__init__(url = url) + super().__init__(url=url) def get_account(self, token: str = None) -> Account: """ @@ -90,5 +91,7 @@ class StreamWrapper(CoreStreamWrapper): ServerTransport -- constructed for this stream with a pre-authenticated client """ - metrics.track(metrics.SDK, custom_props={"name": "Stream Wrapper Get Transport"}) + metrics.track( + metrics.SDK, custom_props={"name": "Stream Wrapper Get Transport"} + ) return super().get_transport(token) diff --git a/src/specklepy/core/api/credentials.py b/src/specklepy/core/api/credentials.py index f83df89..eae4f1c 100644 --- a/src/specklepy/core/api/credentials.py +++ b/src/specklepy/core/api/credentials.py @@ -110,7 +110,7 @@ def get_default_account(base_path: Optional[str] = None) -> Optional[Account]: if not default: default = accounts[0] default.isDefault = True - #metrics.initialise_tracker(default) + # metrics.initialise_tracker(default) return default diff --git a/src/specklepy/core/api/operations.py b/src/specklepy/core/api/operations.py index a09bc48..9d5d4c8 100644 --- a/src/specklepy/core/api/operations.py +++ b/src/specklepy/core/api/operations.py @@ -1,6 +1,6 @@ from typing import List, Optional -#from specklepy.logging import metrics +# from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException from specklepy.objects.base import Base from specklepy.serialization.base_object_serializer import BaseObjectSerializer diff --git a/src/specklepy/core/api/resources/active_user.py b/src/specklepy/core/api/resources/active_user.py index 26616e5..8ce871e 100644 --- a/src/specklepy/core/api/resources/active_user.py +++ b/src/specklepy/core/api/resources/active_user.py @@ -3,7 +3,11 @@ from typing import List, Optional from gql import gql -from specklepy.core.api.models import ActivityCollection, PendingStreamCollaborator, User +from specklepy.core.api.models import ( + ActivityCollection, + PendingStreamCollaborator, + User, +) from specklepy.core.api.resource import ResourceBase from specklepy.logging.exceptions import SpeckleException diff --git a/src/specklepy/core/api/resources/stream.py b/src/specklepy/core/api/resources/stream.py index 40b866b..712851d 100644 --- a/src/specklepy/core/api/resources/stream.py +++ b/src/specklepy/core/api/resources/stream.py @@ -4,7 +4,11 @@ from typing import List, Optional from deprecated import deprecated from gql import gql -from specklepy.core.api.models import ActivityCollection, PendingStreamCollaborator, Stream +from specklepy.core.api.models import ( + ActivityCollection, + PendingStreamCollaborator, + Stream, +) from specklepy.core.api.resource import ResourceBase from specklepy.logging.exceptions import SpeckleException, UnsupportedException @@ -504,11 +508,10 @@ class Resource(ResourceBase): user_invites = [ {"streamId": stream_id, "message": message, "userId": user_id} - for user_id in (user_ids if user_ids is not None else []) + for user_id in (user_ids if user_ids is not None else []) if user_id is not None ] - params = {"input": [*email_invites, *user_invites]} return self.make_request( diff --git a/src/specklepy/core/api/resources/user.py b/src/specklepy/core/api/resources/user.py index c55b1e0..d17e755 100644 --- a/src/specklepy/core/api/resources/user.py +++ b/src/specklepy/core/api/resources/user.py @@ -4,7 +4,11 @@ from typing import List, Optional, Union from deprecated import deprecated from gql import gql -from specklepy.core.api.models import ActivityCollection, PendingStreamCollaborator, User +from specklepy.core.api.models import ( + ActivityCollection, + PendingStreamCollaborator, + User, +) from specklepy.core.api.resource import ResourceBase from specklepy.logging.exceptions import SpeckleException diff --git a/src/specklepy/logging/metrics.py b/src/specklepy/logging/metrics.py index 80fbc6b..3177ee7 100644 --- a/src/specklepy/logging/metrics.py +++ b/src/specklepy/logging/metrics.py @@ -28,7 +28,7 @@ CONNECTOR = "Connector Action" RECEIVE = "Receive" SEND = "Send" -# not in use since 2.15 +# not in use since 2.15 ACCOUNTS = "Get Local Accounts" BRANCH = "Branch Action" CLIENT = "Speckle Client" @@ -142,7 +142,7 @@ class MetricsTracker(metaclass=Singleton): def hash(self, value: str): inputList = value.lower().split("://") - input = inputList[len(inputList)-1].split("/")[0].split('?')[0] + input = inputList[len(inputList) - 1].split("/")[0].split("?")[0] return hashlib.md5(input.encode("utf-8")).hexdigest().upper() def _send_tracking_requests(self): diff --git a/src/specklepy/objects/GIS/CRS.py b/src/specklepy/objects/GIS/CRS.py index 746f442..4fc2d5c 100644 --- a/src/specklepy/objects/GIS/CRS.py +++ b/src/specklepy/objects/GIS/CRS.py @@ -8,9 +8,7 @@ class CRS(Base, speckle_type="Objects.GIS.CRS"): name: Optional[str] = None authority_id: Optional[str] = None wkt: Optional[str] = None - units_native: Optional[str] = None + units_native: Optional[str] = None offset_x: Optional[float] = None offset_y: Optional[float] = None rotation: Optional[float] = None - - diff --git a/src/specklepy/objects/GIS/__init__.py b/src/specklepy/objects/GIS/__init__.py index 566eab9..a2e3f85 100644 --- a/src/specklepy/objects/GIS/__init__.py +++ b/src/specklepy/objects/GIS/__init__.py @@ -17,6 +17,13 @@ from specklepy.objects.GIS.CRS import ( CRS, ) -__all__ = ["VectorLayer", "RasterLayer", - "GisPolygonGeometry", "GisPolygonElement", "GisLineElement", "GisPointElement", "GisRasterElement", - "CRS"] +__all__ = [ + "VectorLayer", + "RasterLayer", + "GisPolygonGeometry", + "GisPolygonElement", + "GisLineElement", + "GisPointElement", + "GisRasterElement", + "CRS", +] diff --git a/src/specklepy/objects/GIS/geometry.py b/src/specklepy/objects/GIS/geometry.py index b692fa5..6cccb45 100644 --- a/src/specklepy/objects/GIS/geometry.py +++ b/src/specklepy/objects/GIS/geometry.py @@ -1,35 +1,51 @@ - -from typing import Optional, Union, List -from specklepy.objects.geometry import Point, Line, Polyline, Circle, Arc, Polycurve, Mesh +from typing import Optional, Union, List +from specklepy.objects.geometry import ( + Point, + Line, + Polyline, + Circle, + Arc, + Polycurve, + Mesh, +) from specklepy.objects import Base from deprecated import deprecated -class GisPolygonGeometry(Base, speckle_type="Objects.GIS.PolygonGeometry", detachable={"displayValue"}): + +class GisPolygonGeometry( + Base, speckle_type="Objects.GIS.PolygonGeometry", detachable={"displayValue"} +): """GIS Polygon Geometry""" boundary: Optional[Union[Polyline, Arc, Line, Circle, Polycurve]] = None - voids: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]] ] = None + voids: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]]] = None displayValue: Optional[List[Mesh]] = None + class GisPolygonElement(Base, speckle_type="Objects.GIS.PolygonElement"): """GIS Polygon element""" geometry: Optional[List[GisPolygonGeometry]] = None attributes: Optional[Base] = None + class GisLineElement(Base, speckle_type="Objects.GIS.LineElement"): """GIS Polyline element""" - geometry: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]]] = None, - attributes: Optional[Base] = None, + geometry: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]]] = (None,) + attributes: Optional[Base] = (None,) + class GisPointElement(Base, speckle_type="Objects.GIS.PointElement"): """GIS Point element""" - geometry: Optional[List[Point]] = None, - attributes: Optional[Base] = None, + geometry: Optional[List[Point]] = (None,) + attributes: Optional[Base] = (None,) -class GisRasterElement(Base, speckle_type="Objects.GIS.RasterElement", detachable={"displayValue"}): + +class GisRasterElement( + Base, speckle_type="Objects.GIS.RasterElement", detachable={"displayValue"} +): """GIS Raster element""" band_count: Optional[int] = None @@ -43,11 +59,16 @@ class GisRasterElement(Base, speckle_type="Objects.GIS.RasterElement", detachabl noDataValue: Optional[List[float]] = None displayValue: Optional[List[Mesh]] = None -class GisTopography(GisRasterElement, speckle_type="Objects.GIS.GisTopography", detachable={"displayValue"}): + +class GisTopography( + GisRasterElement, + speckle_type="Objects.GIS.GisTopography", + detachable={"displayValue"}, +): """GIS Raster element with 3d Topography representation""" + class GisNonGeometryElement(Base, speckle_type="Objects.GIS.NonGeometryElement"): """GIS Table feature""" attributes: Optional[Base] = None - diff --git a/src/specklepy/objects/GIS/layers.py b/src/specklepy/objects/GIS/layers.py index c5411b2..ae39cfa 100644 --- a/src/specklepy/objects/GIS/layers.py +++ b/src/specklepy/objects/GIS/layers.py @@ -5,19 +5,21 @@ from specklepy.objects.other import Collection from specklepy.objects.GIS.CRS import CRS from deprecated import deprecated + @deprecated(version="2.15", reason="Use VectorLayer or RasterLayer instead") class Layer(Base, detachable={"features"}): """A GIS Layer""" + def __init__( self, - name:str=None, - crs:CRS=None, + name: str = None, + crs: CRS = None, units: str = "m", features: Optional[List[Base]] = None, layerType: str = "None", geomType: str = "None", renderer: Optional[dict[str, Any]] = None, - **kwargs + **kwargs, ) -> None: super().__init__(**kwargs) self.name = name @@ -26,25 +28,28 @@ class Layer(Base, detachable={"features"}): self.type = layerType self.features = features or [] self.geomType = geomType - self.renderer = renderer or {} + self.renderer = renderer or {} + @deprecated(version="2.16", reason="Use VectorLayer or RasterLayer instead") class VectorLayer( - Collection, - detachable={"elements"}, - speckle_type="VectorLayer", - serialize_ignore={"features"}): + Collection, + detachable={"elements"}, + speckle_type="VectorLayer", + serialize_ignore={"features"}, +): """GIS Vector Layer""" - name: Optional[str]=None - crs: Optional[Union[CRS, Base]]=None + + name: Optional[str] = None + crs: Optional[Union[CRS, Base]] = None units: Optional[str] = None elements: Optional[List[Base]] = None attributes: Optional[Base] = None geomType: Optional[str] = "None" renderer: Optional[Dict[str, Any]] = None collectionType = "VectorLayer" - + @property @deprecated(version="2.14", reason="Use elements") def features(self) -> Optional[List[Base]]: @@ -54,25 +59,26 @@ class VectorLayer( def features(self, value: Optional[List[Base]]) -> None: self.elements = value + @deprecated(version="2.16", reason="Use VectorLayer or RasterLayer instead") class RasterLayer( - Collection, - detachable={"elements"}, - speckle_type="RasterLayer", - serialize_ignore={"features"}): + Collection, + detachable={"elements"}, + speckle_type="RasterLayer", + serialize_ignore={"features"}, +): """GIS Raster Layer""" name: Optional[str] = None - crs: Optional[Union[CRS, Base]]=None + crs: Optional[Union[CRS, Base]] = None units: Optional[str] = None - rasterCrs: Optional[Union[CRS, Base]]=None + rasterCrs: Optional[Union[CRS, Base]] = None elements: Optional[List[Base]] = None geomType: Optional[str] = "None" renderer: Optional[Dict[str, Any]] = None collectionType = "RasterLayer" - @property @deprecated(version="2.14", reason="Use elements") def features(self) -> Optional[List[Base]]: @@ -84,22 +90,23 @@ class RasterLayer( class VectorLayer( - Collection, - detachable={"elements"}, - speckle_type="Objects.GIS.VectorLayer", - serialize_ignore={"features"}): + Collection, + detachable={"elements"}, + speckle_type="Objects.GIS.VectorLayer", + serialize_ignore={"features"}, +): """GIS Vector Layer""" - name: Optional[str]=None - crs: Optional[Union[CRS, Base]]=None + name: Optional[str] = None + crs: Optional[Union[CRS, Base]] = None units: Optional[str] = None elements: Optional[List[Base]] = None attributes: Optional[Base] = None geomType: Optional[str] = "None" renderer: Optional[Dict[str, Any]] = None collectionType = "VectorLayer" - + @property @deprecated(version="2.14", reason="Use elements") def features(self) -> Optional[List[Base]]: @@ -109,24 +116,25 @@ class VectorLayer( def features(self, value: Optional[List[Base]]) -> None: self.elements = value + class RasterLayer( - Collection, - detachable={"elements"}, - speckle_type="Objects.GIS.RasterLayer", - serialize_ignore={"features"}): + Collection, + detachable={"elements"}, + speckle_type="Objects.GIS.RasterLayer", + serialize_ignore={"features"}, +): """GIS Raster Layer""" name: Optional[str] = None - crs: Optional[Union[CRS, Base]]=None + crs: Optional[Union[CRS, Base]] = None units: Optional[str] = None - rasterCrs: Optional[Union[CRS, Base]]=None + rasterCrs: Optional[Union[CRS, Base]] = None elements: Optional[List[Base]] = None geomType: Optional[str] = "None" renderer: Optional[Dict[str, Any]] = None collectionType = "RasterLayer" - @property @deprecated(version="2.14", reason="Use elements") def features(self) -> Optional[List[Base]]: @@ -135,4 +143,3 @@ class RasterLayer( @features.setter def features(self, value: Optional[List[Base]]) -> None: self.elements = value - diff --git a/src/specklepy/objects/graph_traversal/commit_object_builder.py b/src/specklepy/objects/graph_traversal/commit_object_builder.py index 2b8d1b3..5157a45 100644 --- a/src/specklepy/objects/graph_traversal/commit_object_builder.py +++ b/src/specklepy/objects/graph_traversal/commit_object_builder.py @@ -1,14 +1,25 @@ from abc import ABC, abstractmethod from dataclasses import dataclass -from typing import Any, Collection, Dict, Generic, Iterable, List, Optional, Tuple, TypeVar +from typing import ( + Any, + Collection, + Dict, + Generic, + Iterable, + List, + Optional, + Tuple, + TypeVar, +) from attrs import define from specklepy.objects.base import Base ROOT: str = "__Root" -T = TypeVar('T') +T = TypeVar("T") PARENT_INFO = Tuple[Optional[str], str] + @define(slots=True) class CommitObjectBuilder(ABC, Generic[T]): @@ -18,7 +29,7 @@ class CommitObjectBuilder(ABC, Generic[T]): def __init__(self) -> None: self.converted = {} self._parent_infos = {} - + @abstractmethod def include_object(self, conversion_result: Base, native_object: T) -> None: pass @@ -26,14 +37,18 @@ class CommitObjectBuilder(ABC, Generic[T]): def build_commit_object(self, root_commit_object: Base) -> None: self.apply_relationships(self.converted.values(), root_commit_object) - def set_relationship(self, app_id: Optional[str], *parent_info : PARENT_INFO) -> None: + def set_relationship( + self, app_id: Optional[str], *parent_info: PARENT_INFO + ) -> None: if not app_id: return - + self._parent_infos[app_id] = parent_info - def apply_relationships(self, to_add: Iterable[Base], root_commit_object: Base) -> None: + def apply_relationships( + self, to_add: Iterable[Base], root_commit_object: Base + ) -> None: for c in to_add: try: self.apply_relationship(c, root_commit_object) @@ -41,20 +56,25 @@ class CommitObjectBuilder(ABC, Generic[T]): print(f"Failed to add object {type(c)} to commit object: {ex}") def apply_relationship(self, current: Base, root_commit_object: Base): - if not current.applicationId: raise Exception(f"Expected applicationId to have been set") - + if not current.applicationId: + raise Exception(f"Expected applicationId to have been set") + parents = self._parent_infos[current.applicationId] - + for (parent_id, prop_name) in parents: - if not parent_id: continue + if not parent_id: + continue parent: Optional[Base] if parent_id == ROOT: parent = root_commit_object else: - parent = self.converted[parent_id] if parent_id in self.converted else None - - if not parent: continue + parent = ( + self.converted[parent_id] if parent_id in self.converted else None + ) + + if not parent: + continue try: elements = get_detached_prop(parent, prop_name) @@ -66,18 +86,26 @@ class CommitObjectBuilder(ABC, Generic[T]): return except Exception as ex: # A parent was found, but it was invalid (Likely because of a type mismatch on a `elements` property) - print(f"Failed to add object {type(current)} to a converted parent; {ex}") - - raise Exception(f"Could not find a valid parent for object of type {type(current)}. Checked {len(parents)} potential parent, and non were converted!") + print( + f"Failed to add object {type(current)} to a converted parent; {ex}" + ) + + raise Exception( + f"Could not find a valid parent for object of type {type(current)}. Checked {len(parents)} potential parent, and non were converted!" + ) def get_detached_prop(speckle_object: Base, prop_name: str) -> Optional[Any]: detached_prop_name = get_detached_prop_name(speckle_object, prop_name) return getattr(speckle_object, detached_prop_name, None) -def set_detached_prop(speckle_object: Base, prop_name: str, value: Optional[Any]) -> None: + +def set_detached_prop( + speckle_object: Base, prop_name: str, value: Optional[Any] +) -> None: detached_prop_name = get_detached_prop_name(speckle_object, prop_name) setattr(speckle_object, detached_prop_name, value) + def get_detached_prop_name(speckle_object: Base, prop_name: str) -> str: - return prop_name if hasattr(speckle_object, prop_name) else f"@{prop_name}" \ No newline at end of file + return prop_name if hasattr(speckle_object, prop_name) else f"@{prop_name}" diff --git a/src/specklepy/objects/graph_traversal/traversal.py b/src/specklepy/objects/graph_traversal/traversal.py index 0e2b305..6187232 100644 --- a/src/specklepy/objects/graph_traversal/traversal.py +++ b/src/specklepy/objects/graph_traversal/traversal.py @@ -58,15 +58,15 @@ class GraphTraversal: members_to_traverse = active_rule.get_members_to_traverse(current) for child_prop in members_to_traverse: try: - if child_prop in {"speckle_type", "units", "applicationId"}: continue #debug: to avoid noisy exceptions, explicitly avoid checking ones we know will fail, this is not exhaustive + if child_prop in {"speckle_type", "units", "applicationId"}: + continue # debug: to avoid noisy exceptions, explicitly avoid checking ones we know will fail, this is not exhaustive if getattr(current, child_prop, None): value = current[child_prop] - self._traverse_member_to_stack( - stack, value, child_prop, head - ) + self._traverse_member_to_stack(stack, value, child_prop, head) except KeyError as ex: # Unset application ids, and class variables like SpeckleType will throw when __getitem__ is called pass + @staticmethod def _traverse_member_to_stack( stack: List[TraversalContext], @@ -78,10 +78,14 @@ class GraphTraversal: stack.append(TraversalContext(value, member_name, parent)) elif isinstance(value, list): for obj in value: - GraphTraversal._traverse_member_to_stack(stack, obj, member_name, parent) + GraphTraversal._traverse_member_to_stack( + stack, obj, member_name, parent + ) elif isinstance(value, dict): for obj in value.values(): - GraphTraversal._traverse_member_to_stack(stack, obj, member_name, parent) + GraphTraversal._traverse_member_to_stack( + stack, obj, member_name, parent + ) @staticmethod def traverse_member(value: Optional[Any]) -> Iterator[Base]: @@ -96,7 +100,6 @@ class GraphTraversal: for o in GraphTraversal.traverse_member(obj): yield o - def _get_active_rule_or_default_rule(self, o: Base) -> ITraversalRule: return self._get_active_rule(o) or _default_rule @@ -120,4 +123,4 @@ class TraversalRule: for condition in self._conditions: if condition(o): return True - return False \ No newline at end of file + return False diff --git a/src/specklepy/objects/other.py b/src/specklepy/objects/other.py index 4878520..b8d65a3 100644 --- a/src/specklepy/objects/other.py +++ b/src/specklepy/objects/other.py @@ -75,6 +75,7 @@ class Text(Base, speckle_type=OTHER + "Text"): """ Text object to render it on viewer. """ + plane: Plane value: str height: float @@ -259,9 +260,7 @@ class BlockDefinition( geometry: Optional[List[Base]] = None -class Instance( - Base, speckle_type=OTHER + "Instance", detachable={"definition"} -): +class Instance(Base, speckle_type=OTHER + "Instance", detachable={"definition"}): transform: Optional[Transform] = None definition: Optional[Base] = None @@ -280,17 +279,17 @@ class BlockInstance( def blockDefinition(self, value: Optional[BlockDefinition]) -> None: self.definition = value + class RevitInstance(Instance, speckle_type=OTHER_REVIT + "RevitInstance"): - level: Optional[Base] = None + level: Optional[Base] = None facingFlipped: bool handFlipped: bool - parameters: Optional[Base] = None + parameters: Optional[Base] = None elementId: Optional[str] + # TODO: prob move this into a built elements module, but just trialling this for now -class RevitParameter( - Base, speckle_type="Objects.BuiltElements.Revit.Parameter" -): +class RevitParameter(Base, speckle_type="Objects.BuiltElements.Revit.Parameter"): name: Optional[str] = None value: Any = None applicationUnitType: Optional[str] = None # eg UnitType UT_Length @@ -302,9 +301,10 @@ class RevitParameter( isReadOnly: bool = False isTypeParameter: bool = False + class Collection( Base, speckle_type="Speckle.Core.Models.Collection", detachable={"elements"} ): name: Optional[str] = None collectionType: Optional[str] = None - elements: Optional[List[Base]] = None \ No newline at end of file + elements: Optional[List[Base]] = None diff --git a/src/specklepy/objects/structural/__init__.py b/src/specklepy/objects/structural/__init__.py index 682505c..448aca3 100644 --- a/src/specklepy/objects/structural/__init__.py +++ b/src/specklepy/objects/structural/__init__.py @@ -6,10 +6,7 @@ from specklepy.objects.structural.analysis import ( ModelSettings, ModelUnits, ) -from specklepy.objects.structural.axis import ( - AxisType, - Axis -) +from specklepy.objects.structural.axis import AxisType, Axis from specklepy.objects.structural.geometry import ( Element1D, Element2D, diff --git a/src/specklepy/objects/units.py b/src/specklepy/objects/units.py index d795738..0afade7 100644 --- a/src/specklepy/objects/units.py +++ b/src/specklepy/objects/units.py @@ -106,7 +106,9 @@ def get_encoding_from_units(unit: Union[Units, str, None]): def get_scale_factor_from_string(fromUnits: str, toUnits: str) -> float: """Returns a scalar to convert distance values from one unit system to another""" - return get_scale_factor(get_units_from_string(fromUnits), get_units_from_string(toUnits)) + return get_scale_factor( + get_units_from_string(fromUnits), get_units_from_string(toUnits) + ) def get_scale_factor(fromUnits: Units, toUnits: Units) -> float: @@ -119,4 +121,4 @@ def get_scale_factor_to_meters(fromUnits: Units) -> float: if fromUnits not in UNIT_SCALE: raise ValueError(f"Invalid units provided: {fromUnits}") - return UNIT_SCALE[fromUnits] \ No newline at end of file + return UNIT_SCALE[fromUnits] diff --git a/src/specklepy/transports/server/batch_sender.py b/src/specklepy/transports/server/batch_sender.py index a9e9a37..bb35b95 100644 --- a/src/specklepy/transports/server/batch_sender.py +++ b/src/specklepy/transports/server/batch_sender.py @@ -137,7 +137,7 @@ class BatchSender(object): raise SpeckleException( message=( "Could not save the object to the server - status code" - f" {r.status_code} ({r.text[:1000]})" + f" {r.status_code} ({r.text[:1000]})" ) ) except json.JSONDecodeError as error: diff --git a/tests/unit/test_graph_traversal.py b/tests/unit/test_graph_traversal.py index df8cf1b..10e3508 100644 --- a/tests/unit/test_graph_traversal.py +++ b/tests/unit/test_graph_traversal.py @@ -102,4 +102,4 @@ class GraphTraversalTests(TestCase): self.assertCountEqual(ret, [test_case, expected_traverse, expected_traverse]) self.assertNotIn(expected_ignore, ret) - self.assertEqual(len(ret), 3) \ No newline at end of file + self.assertEqual(len(ret), 3) diff --git a/tests/unit/test_type_validation.py b/tests/unit/test_type_validation.py index 5ca9aec..7403dfb 100644 --- a/tests/unit/test_type_validation.py +++ b/tests/unit/test_type_validation.py @@ -107,7 +107,12 @@ fake_bases = [FakeBase("foo"), FakeBase("bar")] fake_bases, ), (List["int"], [2, 3, 4], True, [2, 3, 4]), - (Union[float, Dict[str, float]], {"foo": 1, "bar": 2}, True, {"foo": 1.0, "bar": 2.0}), + ( + Union[float, Dict[str, float]], + {"foo": 1, "bar": 2}, + True, + {"foo": 1.0, "bar": 2.0}, + ), (Union[float, Dict[str, float]], {"foo": "bar"}, False, {"foo": "bar"}), ], ) diff --git a/tests/unit/test_unit_scaling.py b/tests/unit/test_unit_scaling.py index 3462746..7ead259 100644 --- a/tests/unit/test_unit_scaling.py +++ b/tests/unit/test_unit_scaling.py @@ -1,5 +1,3 @@ - - import pytest from specklepy.objects.units import Units, get_scale_factor @@ -8,7 +6,7 @@ from specklepy.objects.units import Units, get_scale_factor @pytest.mark.parametrize( "fromUnits, toUnits, inValue, expectedOutValue", [ - #To self + # To self (Units.km, Units.km, 1.5, 1.5), (Units.km, Units.km, 0, 0), (Units.m, Units.m, 1.5, 1.5), @@ -23,24 +21,20 @@ from specklepy.objects.units import Units, get_scale_factor (Units.yards, Units.yards, 0, 0), (Units.feet, Units.feet, 1.5, 1.5), (Units.feet, Units.feet, 0, 0), - - #To Meters + # To Meters (Units.km, Units.m, 987654.321, 987654321), (Units.m, Units.m, 987654.321, 987654.321), (Units.mm, Units.m, 98765432.1, 98765.4321), (Units.cm, Units.m, 9876543.21, 98765.4321), - - #To negative meters + # To negative meters (Units.km, Units.m, -987654.321, -987654321), - (Units.m, Units.m,- 987654.321, -987654.321), + (Units.m, Units.m, -987654.321, -987654.321), (Units.mm, Units.m, -98765432.1, -98765.4321), (Units.cm, Units.m, -9876543.21, -98765.4321), - (Units.m, Units.km, 987654.321, 987.654321), (Units.m, Units.cm, 987654.321, 98765432.1), (Units.m, Units.mm, 987654.321, 987654321), - - #Imperial + # Imperial (Units.miles, Units.m, 123.45, 198673.517), (Units.miles, Units.inches, 123.45, 7821792), (Units.yards, Units.m, 123.45, 112.88268), @@ -50,7 +44,9 @@ from specklepy.objects.units import Units, get_scale_factor (Units.inches, Units.m, 123.45, 3.13563), ], ) -def test_get_scale_factor_between_units(fromUnits: Units, toUnits: Units, inValue: float, expectedOutValue: float): +def test_get_scale_factor_between_units( + fromUnits: Units, toUnits: Units, inValue: float, expectedOutValue: float +): Tolerance = 1e-10 actual = inValue * get_scale_factor(fromUnits, toUnits) - assert(actual - expectedOutValue < Tolerance) + assert actual - expectedOutValue < Tolerance diff --git a/utils/installer.py b/utils/installer.py index 9f22cc8..7637ba4 100644 --- a/utils/installer.py +++ b/utils/installer.py @@ -55,9 +55,7 @@ def user_application_data_path() -> Path: if sys.platform.startswith("win"): app_data_path = os.getenv("APPDATA") if not app_data_path: - raise Exception( - "Cannot get appdata path from environment." - ) + raise Exception("Cannot get appdata path from environment.") return Path(app_data_path) else: # try getting the standard XDG_DATA_HOME value @@ -68,9 +66,7 @@ def user_application_data_path() -> Path: else: return _ensure_folder_exists(Path.home(), ".config") except Exception as ex: - raise Exception( - "Failed to initialize user application data path.", ex - ) + raise Exception("Failed to initialize user application data path.", ex) def user_speckle_folder_path() -> Path: @@ -90,19 +86,16 @@ def user_speckle_connector_installation_path(host_application: str) -> Path: ) - - - - print("Starting module dependency installation") print(sys.executable) PYTHON_PATH = sys.executable - def connector_installation_path(host_application: str) -> Path: - connector_installation_path = user_speckle_connector_installation_path(host_application) + connector_installation_path = user_speckle_connector_installation_path( + host_application + ) connector_installation_path.mkdir(exist_ok=True, parents=True) # set user modules path at beginning of paths for earlier hit @@ -113,7 +106,6 @@ def connector_installation_path(host_application: str) -> Path: return connector_installation_path - def is_pip_available() -> bool: try: import_module("pip") # noqa F401 @@ -132,7 +124,9 @@ def ensure_pip() -> None: if completed_process.returncode == 0: print("Successfully installed pip") else: - raise Exception(f"Failed to install pip, got {completed_process.returncode} return code") + raise Exception( + f"Failed to install pip, got {completed_process.returncode} return code" + ) def get_requirements_path() -> Path: @@ -184,7 +178,7 @@ def _import_dependencies() -> None: # the code above doesn't work for now, it fails on importing graphql-core # despite that, the connector seams to be working as expected # But it would be nice to make this solution work - # it would ensure that all dependencies are fully loaded + # it would ensure that all dependencies are fully loaded # requirements = get_requirements_path().read_text() # reqs = [ # req.split(" ; ")[0].split("==")[0].split("[")[0].replace("-", "_") @@ -195,6 +189,7 @@ def _import_dependencies() -> None: # print(req) # import_module("specklepy") + def ensure_dependencies(host_application: str) -> None: try: install_dependencies(host_application) @@ -202,6 +197,6 @@ def ensure_dependencies(host_application: str) -> None: _import_dependencies() print("Successfully found dependencies") except ImportError: - raise Exception(f"Cannot automatically ensure Speckle dependencies. Please try restarting the host application {host_application}!") - - + raise Exception( + f"Cannot automatically ensure Speckle dependencies. Please try restarting the host application {host_application}!" + ) From bf3ab7da4cd5c4912662a717b4bdc014d48210ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Mon, 27 Nov 2023 12:22:33 +0100 Subject: [PATCH 41/54] chore: reorder imports --- src/speckle_automate/automation_context.py | 16 ++--- src/speckle_automate/helpers.py | 3 +- src/specklepy/api/client.py | 5 +- src/specklepy/api/credentials.py | 19 +++--- src/specklepy/api/host_applications.py | 62 +++++++++---------- src/specklepy/api/models.py | 14 ++--- src/specklepy/api/operations.py | 11 ++-- src/specklepy/api/resource.py | 8 +-- src/specklepy/api/resources/active_user.py | 3 +- src/specklepy/api/resources/branch.py | 3 +- src/specklepy/api/resources/commit.py | 3 +- src/specklepy/api/resources/object.py | 6 +- src/specklepy/api/resources/other_user.py | 3 +- src/specklepy/api/resources/server.py | 3 +- src/specklepy/api/resources/stream.py | 3 +- src/specklepy/api/resources/subscriptions.py | 5 +- src/specklepy/api/resources/user.py | 6 +- src/specklepy/api/wrapper.py | 5 +- src/specklepy/core/api/client.py | 2 +- src/specklepy/core/api/resources/user.py | 1 - src/specklepy/core/api/wrapper.py | 1 + src/specklepy/objects/GIS/CRS.py | 1 + src/specklepy/objects/GIS/__init__.py | 15 ++--- src/specklepy/objects/GIS/geometry.py | 24 +++---- src/specklepy/objects/GIS/layers.py | 9 +-- .../graph_traversal/commit_object_builder.py | 2 + src/specklepy/objects/other.py | 3 +- src/specklepy/objects/structural/__init__.py | 2 +- src/specklepy/objects/structural/axis.py | 2 +- .../test_automation_context.py | 12 ++-- utils/installer.py | 2 +- 31 files changed, 119 insertions(+), 135 deletions(-) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index e1038c9..9ce2eff 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -1,18 +1,11 @@ """This module provides an abstraction layer above the Speckle Automate runtime.""" +import time from dataclasses import dataclass, field from pathlib import Path -import time from typing import Any, Dict, List, Optional, Tuple, Union import httpx from gql import gql -from specklepy.api import operations -from specklepy.api.client import SpeckleClient -from specklepy.core.api.models import Branch -from specklepy.objects import Base -from specklepy.transports.memory import MemoryTransport -from specklepy.transports.server import ServerTransport -from specklepy.logging.exceptions import SpeckleException from speckle_automate.schema import ( AutomateBase, @@ -22,6 +15,13 @@ from speckle_automate.schema import ( ObjectResultLevel, ResultCase, ) +from specklepy.api import operations +from specklepy.api.client import SpeckleClient +from specklepy.core.api.models import Branch +from specklepy.logging.exceptions import SpeckleException +from specklepy.objects import Base +from specklepy.transports.memory import MemoryTransport +from specklepy.transports.server import ServerTransport @dataclass diff --git a/src/speckle_automate/helpers.py b/src/speckle_automate/helpers.py index 8fe7870..0f9cbb3 100644 --- a/src/speckle_automate/helpers.py +++ b/src/speckle_automate/helpers.py @@ -2,9 +2,10 @@ import secrets import string -from specklepy.api.client import SpeckleClient from gql import gql +from specklepy.api.client import SpeckleClient + def register_new_automation( speckle_client: SpeckleClient, diff --git a/src/specklepy/api/client.py b/src/specklepy/api/client.py index c21a566..2dd62ec 100644 --- a/src/specklepy/api/client.py +++ b/src/specklepy/api/client.py @@ -5,7 +5,6 @@ from gql.transport.websockets import WebsocketsTransport from specklepy.api.credentials import Account, get_account_from_token from specklepy.api.resources import ( - user, active_user, branch, commit, @@ -14,12 +13,12 @@ from specklepy.api.resources import ( server, stream, subscriptions, + user, ) +from specklepy.core.api.client import SpeckleClient as CoreSpeckleClient from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException, SpeckleWarning -from specklepy.core.api.client import SpeckleClient as CoreSpeckleClient - class SpeckleClient(CoreSpeckleClient): """ diff --git a/src/specklepy/api/credentials.py b/src/specklepy/api/credentials.py index 04ab00f..23744ad 100644 --- a/src/specklepy/api/credentials.py +++ b/src/specklepy/api/credentials.py @@ -4,21 +4,20 @@ from typing import List, Optional from pydantic import BaseModel, Field # pylint: disable=no-name-in-module from specklepy.api.models import ServerInfo + +# following imports seem to be unnecessary, but they need to stay +# to not break the scripts using these functions as non-core +from specklepy.core.api.credentials import StreamWrapper # deprecated +from specklepy.core.api.credentials import Account, UserInfo +from specklepy.core.api.credentials import ( + get_account_from_token as core_get_account_from_token, +) +from specklepy.core.api.credentials import get_local_accounts as core_get_local_accounts from specklepy.core.helpers import speckle_path_provider from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException from specklepy.transports.sqlite import SQLiteTransport -# following imports seem to be unnecessary, but they need to stay -# to not break the scripts using these functions as non-core -from specklepy.core.api.credentials import ( - Account, - UserInfo, - StreamWrapper, # deprecated - get_local_accounts as core_get_local_accounts, - get_account_from_token as core_get_account_from_token, -) - def get_local_accounts(base_path: Optional[str] = None) -> List[Account]: """Gets all the accounts present in this environment diff --git a/src/specklepy/api/host_applications.py b/src/specklepy/api/host_applications.py index c9e2a55..b52fcbe 100644 --- a/src/specklepy/api/host_applications.py +++ b/src/specklepy/api/host_applications.py @@ -5,40 +5,40 @@ from unicodedata import name # following imports seem to be unnecessary, but they need to stay # to not break the scripts using these functions as non-core from specklepy.core.api.host_applications import ( + ARCGIS, + ARCHICAD, + AUTOCAD, + BLENDER, + CIVIL, + CSIBRIDGE, + DXF, + DYNAMO, + ETABS, + EXCEL, + GRASSHOPPER, + GSA, + MICROSTATION, + NET, + OPENBUILDINGS, + OPENRAIL, + OPENROADS, + OTHER, + POWERBI, + PYTHON, + QGIS, + REVIT, + RHINO, + SAFE, + SAP2000, + SKETCHUP, + TEKLASTRUCTURES, + TOPSOLID, + UNITY, + UNREAL, HostApplication, HostAppVersion, - get_host_app_from_string, _app_name_host_app_mapping, - RHINO, - GRASSHOPPER, - REVIT, - DYNAMO, - UNITY, - GSA, - CIVIL, - AUTOCAD, - MICROSTATION, - OPENROADS, - OPENRAIL, - OPENBUILDINGS, - ETABS, - SAP2000, - CSIBRIDGE, - SAFE, - TEKLASTRUCTURES, - DXF, - EXCEL, - UNREAL, - POWERBI, - BLENDER, - QGIS, - ARCGIS, - SKETCHUP, - ARCHICAD, - TOPSOLID, - PYTHON, - NET, - OTHER, + get_host_app_from_string, ) if __name__ == "__main__": diff --git a/src/specklepy/api/models.py b/src/specklepy/api/models.py index 12346dd..3857d37 100644 --- a/src/specklepy/api/models.py +++ b/src/specklepy/api/models.py @@ -6,18 +6,18 @@ from pydantic import BaseModel, Field # following imports seem to be unnecessary, but they need to stay # to not break the scripts using these functions as non-core from specklepy.core.api.models import ( + Activity, + ActivityCollection, + Branch, + Branches, Collaborator, Commit, Commits, + LimitedUser, Object, - Branch, - Branches, + PendingStreamCollaborator, + ServerInfo, Stream, Streams, User, - LimitedUser, - PendingStreamCollaborator, - Activity, - ActivityCollection, - ServerInfo, ) diff --git a/src/specklepy/api/operations.py b/src/specklepy/api/operations.py index 489b65e..6ef7f5e 100644 --- a/src/specklepy/api/operations.py +++ b/src/specklepy/api/operations.py @@ -1,5 +1,9 @@ from typing import List, Optional +from specklepy.core.api.operations import deserialize as core_deserialize +from specklepy.core.api.operations import receive as _untracked_receive +from specklepy.core.api.operations import send as core_send +from specklepy.core.api.operations import serialize as core_serialize from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException from specklepy.objects.base import Base @@ -7,13 +11,6 @@ from specklepy.serialization.base_object_serializer import BaseObjectSerializer from specklepy.transports.abstract_transport import AbstractTransport from specklepy.transports.sqlite import SQLiteTransport -from specklepy.core.api.operations import ( - send as core_send, - receive as _untracked_receive, - serialize as core_serialize, - deserialize as core_deserialize, -) - def send( base: Base, diff --git a/src/specklepy/api/resource.py b/src/specklepy/api/resource.py index 028bceb..c2e25ea 100644 --- a/src/specklepy/api/resource.py +++ b/src/specklepy/api/resource.py @@ -6,6 +6,10 @@ from gql.transport.exceptions import TransportQueryError from graphql import DocumentNode from specklepy.api.credentials import Account + +# following imports seem to be unnecessary, but they need to stay +# to not break the scripts using these functions as non-core +from specklepy.core.api.resource import ResourceBase as CoreResourceBase from specklepy.logging.exceptions import ( GraphQLException, SpeckleException, @@ -14,10 +18,6 @@ from specklepy.logging.exceptions import ( from specklepy.serialization.base_object_serializer import BaseObjectSerializer from specklepy.transports.sqlite import SQLiteTransport -# following imports seem to be unnecessary, but they need to stay -# to not break the scripts using these functions as non-core -from specklepy.core.api.resource import ResourceBase as CoreResourceBase - class ResourceBase(CoreResourceBase): def __init__( diff --git a/src/specklepy/api/resources/active_user.py b/src/specklepy/api/resources/active_user.py index c33d16b..141a717 100644 --- a/src/specklepy/api/resources/active_user.py +++ b/src/specklepy/api/resources/active_user.py @@ -5,11 +5,10 @@ from gql import gql from specklepy.api.models import ActivityCollection, PendingStreamCollaborator, User from specklepy.api.resource import ResourceBase +from specklepy.core.api.resources.active_user import Resource as CoreResource from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException -from specklepy.core.api.resources.active_user import Resource as CoreResource - class Resource(CoreResource): """API Access class for users""" diff --git a/src/specklepy/api/resources/branch.py b/src/specklepy/api/resources/branch.py index e913390..590b979 100644 --- a/src/specklepy/api/resources/branch.py +++ b/src/specklepy/api/resources/branch.py @@ -4,9 +4,8 @@ from gql import gql from specklepy.api.models import Branch from specklepy.api.resource import ResourceBase -from specklepy.logging import metrics - from specklepy.core.api.resources.branch import Resource as CoreResource +from specklepy.logging import metrics class Resource(CoreResource): diff --git a/src/specklepy/api/resources/commit.py b/src/specklepy/api/resources/commit.py index 8a0bc6a..404de5c 100644 --- a/src/specklepy/api/resources/commit.py +++ b/src/specklepy/api/resources/commit.py @@ -4,9 +4,8 @@ from gql import gql from specklepy.api.models import Commit from specklepy.api.resource import ResourceBase -from specklepy.logging import metrics - from specklepy.core.api.resources.commit import Resource as CoreResource +from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException diff --git a/src/specklepy/api/resources/object.py b/src/specklepy/api/resources/object.py index b6683d3..a15caf9 100644 --- a/src/specklepy/api/resources/object.py +++ b/src/specklepy/api/resources/object.py @@ -3,11 +3,9 @@ from typing import Dict, List from gql import gql from specklepy.api.resource import ResourceBase -from specklepy.objects.base import Base - -from specklepy.logging import metrics - from specklepy.core.api.resources.object import Resource as CoreResource +from specklepy.logging import metrics +from specklepy.objects.base import Base class Resource(CoreResource): diff --git a/src/specklepy/api/resources/other_user.py b/src/specklepy/api/resources/other_user.py index 585afd4..a3c2656 100644 --- a/src/specklepy/api/resources/other_user.py +++ b/src/specklepy/api/resources/other_user.py @@ -5,11 +5,10 @@ from gql import gql from specklepy.api.models import ActivityCollection, LimitedUser from specklepy.api.resource import ResourceBase +from specklepy.core.api.resources.other_user import Resource as CoreResource from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException -from specklepy.core.api.resources.other_user import Resource as CoreResource - class Resource(CoreResource): """API Access class for other users, that are not the currently active user.""" diff --git a/src/specklepy/api/resources/server.py b/src/specklepy/api/resources/server.py index 74cc957..f851def 100644 --- a/src/specklepy/api/resources/server.py +++ b/src/specklepy/api/resources/server.py @@ -5,11 +5,10 @@ from gql import gql from specklepy.api.models import ServerInfo from specklepy.api.resource import ResourceBase +from specklepy.core.api.resources.server import Resource as CoreResource from specklepy.logging import metrics from specklepy.logging.exceptions import GraphQLException -from specklepy.core.api.resources.server import Resource as CoreResource - class Resource(CoreResource): """API Access class for the server""" diff --git a/src/specklepy/api/resources/stream.py b/src/specklepy/api/resources/stream.py index 3e5558a..24dc4ca 100644 --- a/src/specklepy/api/resources/stream.py +++ b/src/specklepy/api/resources/stream.py @@ -6,11 +6,10 @@ from gql import gql from specklepy.api.models import ActivityCollection, PendingStreamCollaborator, Stream from specklepy.api.resource import ResourceBase +from specklepy.core.api.resources.stream import Resource as CoreResource from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException, UnsupportedException -from specklepy.core.api.resources.stream import Resource as CoreResource - class Resource(CoreResource): """API Access class for streams""" diff --git a/src/specklepy/api/resources/subscriptions.py b/src/specklepy/api/resources/subscriptions.py index d8b11ee..ab28736 100644 --- a/src/specklepy/api/resources/subscriptions.py +++ b/src/specklepy/api/resources/subscriptions.py @@ -6,10 +6,9 @@ from graphql import DocumentNode from specklepy.api.resource import ResourceBase from specklepy.api.resources.stream import Stream -from specklepy.logging.exceptions import SpeckleException - -from specklepy.logging import metrics from specklepy.core.api.resources.subscriptions import Resource as CoreResource +from specklepy.logging import metrics +from specklepy.logging.exceptions import SpeckleException def check_wsclient(function): diff --git a/src/specklepy/api/resources/user.py b/src/specklepy/api/resources/user.py index f603f87..6742a50 100644 --- a/src/specklepy/api/resources/user.py +++ b/src/specklepy/api/resources/user.py @@ -6,11 +6,9 @@ from gql import gql from specklepy.api.models import ActivityCollection, PendingStreamCollaborator, User from specklepy.api.resource import ResourceBase - -from specklepy.logging.exceptions import SpeckleException - -from specklepy.logging import metrics from specklepy.core.api.resources.user import Resource as CoreResource +from specklepy.logging import metrics +from specklepy.logging.exceptions import SpeckleException DEPRECATION_VERSION = "2.9.0" DEPRECATION_TEXT = ( diff --git a/src/specklepy/api/wrapper.py b/src/specklepy/api/wrapper.py index 7a3ae31..22a3ea6 100644 --- a/src/specklepy/api/wrapper.py +++ b/src/specklepy/api/wrapper.py @@ -7,12 +7,11 @@ from specklepy.api.credentials import ( get_account_from_token, get_local_accounts, ) +from specklepy.core.api.wrapper import StreamWrapper as CoreStreamWrapper +from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException, SpeckleWarning from specklepy.transports.server.server import ServerTransport -from specklepy.logging import metrics -from specklepy.core.api.wrapper import StreamWrapper as CoreStreamWrapper - class StreamWrapper(CoreStreamWrapper): """ diff --git a/src/specklepy/core/api/client.py b/src/specklepy/core/api/client.py index 197fcc9..24adb87 100644 --- a/src/specklepy/core/api/client.py +++ b/src/specklepy/core/api/client.py @@ -11,7 +11,6 @@ from gql.transport.websockets import WebsocketsTransport from specklepy.core.api import resources from specklepy.core.api.credentials import Account, get_account_from_token from specklepy.core.api.resources import ( - user, active_user, branch, commit, @@ -20,6 +19,7 @@ from specklepy.core.api.resources import ( server, stream, subscriptions, + user, ) from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException, SpeckleWarning diff --git a/src/specklepy/core/api/resources/user.py b/src/specklepy/core/api/resources/user.py index d17e755..b9ecd1e 100644 --- a/src/specklepy/core/api/resources/user.py +++ b/src/specklepy/core/api/resources/user.py @@ -10,7 +10,6 @@ from specklepy.core.api.models import ( User, ) from specklepy.core.api.resource import ResourceBase - from specklepy.logging.exceptions import SpeckleException NAME = "user" diff --git a/src/specklepy/core/api/wrapper.py b/src/specklepy/core/api/wrapper.py index 9f9a11e..8a46608 100644 --- a/src/specklepy/core/api/wrapper.py +++ b/src/specklepy/core/api/wrapper.py @@ -1,5 +1,6 @@ from urllib.parse import unquote, urlparse from warnings import warn + from gql import gql from specklepy.core.api.client import SpeckleClient diff --git a/src/specklepy/objects/GIS/CRS.py b/src/specklepy/objects/GIS/CRS.py index 4fc2d5c..44b998d 100644 --- a/src/specklepy/objects/GIS/CRS.py +++ b/src/specklepy/objects/GIS/CRS.py @@ -1,4 +1,5 @@ from typing import Optional + from specklepy.objects import Base diff --git a/src/specklepy/objects/GIS/__init__.py b/src/specklepy/objects/GIS/__init__.py index a2e3f85..58d7b33 100644 --- a/src/specklepy/objects/GIS/__init__.py +++ b/src/specklepy/objects/GIS/__init__.py @@ -1,21 +1,14 @@ """Builtin Speckle object kit.""" -from specklepy.objects.GIS.layers import ( - VectorLayer, - RasterLayer, -) - +from specklepy.objects.GIS.CRS import CRS from specklepy.objects.GIS.geometry import ( - GisPolygonGeometry, - GisPolygonElement, GisLineElement, GisPointElement, + GisPolygonElement, + GisPolygonGeometry, GisRasterElement, ) - -from specklepy.objects.GIS.CRS import ( - CRS, -) +from specklepy.objects.GIS.layers import RasterLayer, VectorLayer __all__ = [ "VectorLayer", diff --git a/src/specklepy/objects/GIS/geometry.py b/src/specklepy/objects/GIS/geometry.py index 6cccb45..e2951c5 100644 --- a/src/specklepy/objects/GIS/geometry.py +++ b/src/specklepy/objects/GIS/geometry.py @@ -1,16 +1,18 @@ -from typing import Optional, Union, List -from specklepy.objects.geometry import ( - Point, - Line, - Polyline, - Circle, - Arc, - Polycurve, - Mesh, -) -from specklepy.objects import Base +from typing import List, Optional, Union + from deprecated import deprecated +from specklepy.objects import Base +from specklepy.objects.geometry import ( + Arc, + Circle, + Line, + Mesh, + Point, + Polycurve, + Polyline, +) + class GisPolygonGeometry( Base, speckle_type="Objects.GIS.PolygonGeometry", detachable={"displayValue"} diff --git a/src/specklepy/objects/GIS/layers.py b/src/specklepy/objects/GIS/layers.py index ae39cfa..ffa207a 100644 --- a/src/specklepy/objects/GIS/layers.py +++ b/src/specklepy/objects/GIS/layers.py @@ -1,10 +1,11 @@ -from typing import Any, Dict, List, Union, Optional -from specklepy.objects.base import Base -from specklepy.objects.other import Collection +from typing import Any, Dict, List, Optional, Union -from specklepy.objects.GIS.CRS import CRS from deprecated import deprecated +from specklepy.objects.base import Base +from specklepy.objects.GIS.CRS import CRS +from specklepy.objects.other import Collection + @deprecated(version="2.15", reason="Use VectorLayer or RasterLayer instead") class Layer(Base, detachable={"features"}): diff --git a/src/specklepy/objects/graph_traversal/commit_object_builder.py b/src/specklepy/objects/graph_traversal/commit_object_builder.py index 5157a45..71d76b5 100644 --- a/src/specklepy/objects/graph_traversal/commit_object_builder.py +++ b/src/specklepy/objects/graph_traversal/commit_object_builder.py @@ -11,7 +11,9 @@ from typing import ( Tuple, TypeVar, ) + from attrs import define + from specklepy.objects.base import Base ROOT: str = "__Root" diff --git a/src/specklepy/objects/other.py b/src/specklepy/objects/other.py index b8d65a3..5a2576e 100644 --- a/src/specklepy/objects/other.py +++ b/src/specklepy/objects/other.py @@ -1,7 +1,8 @@ from typing import Any, List, Optional + from deprecated import deprecated -from specklepy.objects.geometry import Point, Vector, Plane, Polyline +from specklepy.objects.geometry import Plane, Point, Polyline, Vector from .base import Base diff --git a/src/specklepy/objects/structural/__init__.py b/src/specklepy/objects/structural/__init__.py index 448aca3..dc91f3a 100644 --- a/src/specklepy/objects/structural/__init__.py +++ b/src/specklepy/objects/structural/__init__.py @@ -6,7 +6,7 @@ from specklepy.objects.structural.analysis import ( ModelSettings, ModelUnits, ) -from specklepy.objects.structural.axis import AxisType, Axis +from specklepy.objects.structural.axis import Axis, AxisType from specklepy.objects.structural.geometry import ( Element1D, Element2D, diff --git a/src/specklepy/objects/structural/axis.py b/src/specklepy/objects/structural/axis.py index 87773dc..aa4408d 100644 --- a/src/specklepy/objects/structural/axis.py +++ b/src/specklepy/objects/structural/axis.py @@ -1,5 +1,5 @@ -from typing import Optional from enum import Enum +from typing import Optional from specklepy.objects.base import Base from specklepy.objects.geometry import Plane diff --git a/tests/intergration/speckle_automate/test_automation_context.py b/tests/intergration/speckle_automate/test_automation_context.py index 2d6d2a0..01f2685 100644 --- a/tests/intergration/speckle_automate/test_automation_context.py +++ b/tests/intergration/speckle_automate/test_automation_context.py @@ -5,12 +5,6 @@ from typing import Dict import pytest from gql import gql -from speckle_automate.schema import AutomateBase -from speckle_automate.helpers import register_new_automation, crypto_random_string -from specklepy.api import operations -from specklepy.api.client import SpeckleClient -from specklepy.objects.base import Base -from specklepy.transports.server import ServerTransport from speckle_automate import ( AutomationContext, @@ -18,6 +12,12 @@ from speckle_automate import ( AutomationStatus, run_function, ) +from speckle_automate.helpers import crypto_random_string, register_new_automation +from speckle_automate.schema import AutomateBase +from specklepy.api import operations +from specklepy.api.client import SpeckleClient +from specklepy.objects.base import Base +from specklepy.transports.server import ServerTransport @pytest.fixture diff --git a/utils/installer.py b/utils/installer.py index 7637ba4..668ad64 100644 --- a/utils/installer.py +++ b/utils/installer.py @@ -3,9 +3,9 @@ Provides uniform and consistent path helpers for `specklepy` """ import os import sys +from importlib import import_module, invalidate_caches from pathlib import Path from typing import Optional -from importlib import import_module, invalidate_caches _user_data_env_var = "SPECKLE_USERDATA_PATH" From bddf9c0c1cba93c353a0c75a1f65796bbab4225c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Mon, 27 Nov 2023 14:24:45 +0100 Subject: [PATCH 42/54] chore: fix imports --- src/speckle_automate/automation_context.py | 5 +-- src/speckle_automate/helpers.py | 8 ++-- src/speckle_automate/runner.py | 2 +- src/specklepy/api/client.py | 6 +-- src/specklepy/api/credentials.py | 12 +---- src/specklepy/api/host_applications.py | 45 +++++++++++++++---- src/specklepy/api/models.py | 22 ++++++--- src/specklepy/api/operations.py | 3 -- src/specklepy/api/resource.py | 15 +------ src/specklepy/api/resources/active_user.py | 8 +--- src/specklepy/api/resources/branch.py | 3 -- src/specklepy/api/resources/commit.py | 3 -- src/specklepy/api/resources/object.py | 3 -- src/specklepy/api/resources/other_user.py | 5 +-- src/specklepy/api/resources/server.py | 5 --- src/specklepy/api/resources/stream.py | 9 +--- src/specklepy/api/resources/subscriptions.py | 3 -- src/specklepy/api/resources/user.py | 6 +-- src/specklepy/api/wrapper.py | 10 +---- src/specklepy/core/api/credentials.py | 1 - src/specklepy/objects/GIS/geometry.py | 10 ++--- src/specklepy/objects/GIS/layers.py | 4 +- src/specklepy/objects/base.py | 2 +- .../graph_traversal/commit_object_builder.py | 19 ++------ .../objects/graph_traversal/traversal.py | 3 +- src/specklepy/transports/memory.py | 2 +- src/specklepy/transports/server/server.py | 2 +- src/specklepy/transports/sqlite.py | 2 +- .../test_automation_context.py | 4 +- tests/intergration/test_stream.py | 6 +-- 30 files changed, 90 insertions(+), 138 deletions(-) diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index 9ce2eff..5968c74 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -17,7 +17,6 @@ from speckle_automate.schema import ( ) from specklepy.api import operations from specklepy.api.client import SpeckleClient -from specklepy.core.api.models import Branch from specklepy.logging.exceptions import SpeckleException from specklepy.objects import Base from specklepy.transports.memory import MemoryTransport @@ -196,8 +195,8 @@ class AutomationContext: query = gql( """ mutation ReportFunctionRunStatus( - $automationId: String!, - $automationRevisionId: String!, + $automationId: String!, + $automationRevisionId: String!, $automationRunId: String!, $versionId: String!, $functionId: String!, diff --git a/src/speckle_automate/helpers.py b/src/speckle_automate/helpers.py index 0f9cbb3..fdf3495 100644 --- a/src/speckle_automate/helpers.py +++ b/src/speckle_automate/helpers.py @@ -19,10 +19,10 @@ def register_new_automation( query = gql( """ mutation CreateAutomation( - $projectId: String! - $modelId: String! + $projectId: String! + $modelId: String! $automationName: String! - $automationId: String! + $automationId: String! $automationRevisionId: String! ) { automationMutations { @@ -30,7 +30,7 @@ def register_new_automation( input: { projectId: $projectId modelId: $modelId - automationName: $automationName + automationName: $automationName automationId: $automationId automationRevisionId: $automationRevisionId } diff --git a/src/speckle_automate/runner.py b/src/speckle_automate/runner.py index d60096a..e019655 100644 --- a/src/speckle_automate/runner.py +++ b/src/speckle_automate/runner.py @@ -11,7 +11,7 @@ from pathlib import Path from typing import Callable, Optional, TypeVar, Union, overload from speckle_automate.automation_context import AutomationContext -from speckle_automate.schema import AutomateBase, AutomationRunData, AutomationStatus +from speckle_automate.schema import AutomateBase, AutomationStatus T = TypeVar("T", bound=AutomateBase) diff --git a/src/specklepy/api/client.py b/src/specklepy/api/client.py index 2dd62ec..8abb0b6 100644 --- a/src/specklepy/api/client.py +++ b/src/specklepy/api/client.py @@ -1,9 +1,6 @@ from deprecated import deprecated -from gql.transport.exceptions import TransportServerError -from gql.transport.requests import RequestsHTTPTransport -from gql.transport.websockets import WebsocketsTransport -from specklepy.api.credentials import Account, get_account_from_token +from specklepy.api.credentials import Account from specklepy.api.resources import ( active_user, branch, @@ -17,7 +14,6 @@ from specklepy.api.resources import ( ) from specklepy.core.api.client import SpeckleClient as CoreSpeckleClient from specklepy.logging import metrics -from specklepy.logging.exceptions import SpeckleException, SpeckleWarning class SpeckleClient(CoreSpeckleClient): diff --git a/src/specklepy/api/credentials.py b/src/specklepy/api/credentials.py index 23744ad..fb7b56f 100644 --- a/src/specklepy/api/credentials.py +++ b/src/specklepy/api/credentials.py @@ -1,22 +1,14 @@ -import os from typing import List, Optional -from pydantic import BaseModel, Field # pylint: disable=no-name-in-module - -from specklepy.api.models import ServerInfo - # following imports seem to be unnecessary, but they need to stay # to not break the scripts using these functions as non-core -from specklepy.core.api.credentials import StreamWrapper # deprecated -from specklepy.core.api.credentials import Account, UserInfo +from specklepy.core.api.credentials import StreamWrapper # noqa: F401 +from specklepy.core.api.credentials import Account, UserInfo # noqa: F401 from specklepy.core.api.credentials import ( get_account_from_token as core_get_account_from_token, ) from specklepy.core.api.credentials import get_local_accounts as core_get_local_accounts -from specklepy.core.helpers import speckle_path_provider from specklepy.logging import metrics -from specklepy.logging.exceptions import SpeckleException -from specklepy.transports.sqlite import SQLiteTransport def get_local_accounts(base_path: Optional[str] = None) -> List[Account]: diff --git a/src/specklepy/api/host_applications.py b/src/specklepy/api/host_applications.py index b52fcbe..e777073 100644 --- a/src/specklepy/api/host_applications.py +++ b/src/specklepy/api/host_applications.py @@ -1,9 +1,3 @@ -from dataclasses import dataclass -from enum import Enum -from unicodedata import name - -# following imports seem to be unnecessary, but they need to stay -# to not break the scripts using these functions as non-core from specklepy.core.api.host_applications import ( ARCGIS, ARCHICAD, @@ -41,5 +35,40 @@ from specklepy.core.api.host_applications import ( get_host_app_from_string, ) -if __name__ == "__main__": - print(HostAppVersion.v) +# re-exporting stuff from the moved api module +__all__ = [ + "ARCGIS", + "ARCHICAD", + "AUTOCAD", + "BLENDER", + "CIVIL", + "CSIBRIDGE", + "DXF", + "DYNAMO", + "ETABS", + "EXCEL", + "GRASSHOPPER", + "GSA", + "MICROSTATION", + "NET", + "OPENBUILDINGS", + "OPENRAIL", + "OPENROADS", + "OTHER", + "POWERBI", + "PYTHON", + "QGIS", + "REVIT", + "RHINO", + "SAFE", + "SAP2000", + "SKETCHUP", + "TEKLASTRUCTURES", + "TOPSOLID", + "UNITY", + "UNREAL", + "HostApplication", + "HostAppVersion", + "_app_name_host_app_mapping", + "get_host_app_from_string", +] diff --git a/src/specklepy/api/models.py b/src/specklepy/api/models.py index 3857d37..5c2db83 100644 --- a/src/specklepy/api/models.py +++ b/src/specklepy/api/models.py @@ -1,8 +1,3 @@ -from datetime import datetime -from typing import List, Optional - -from pydantic import BaseModel, Field - # following imports seem to be unnecessary, but they need to stay # to not break the scripts using these functions as non-core from specklepy.core.api.models import ( @@ -21,3 +16,20 @@ from specklepy.core.api.models import ( Streams, User, ) + +__all__ = [ + "Activity", + "ActivityCollection", + "Branch", + "Branches", + "Collaborator", + "Commit", + "Commits", + "LimitedUser", + "Object", + "PendingStreamCollaborator", + "ServerInfo", + "Stream", + "Streams", + "User", +] diff --git a/src/specklepy/api/operations.py b/src/specklepy/api/operations.py index 6ef7f5e..4f7cb1e 100644 --- a/src/specklepy/api/operations.py +++ b/src/specklepy/api/operations.py @@ -5,11 +5,8 @@ from specklepy.core.api.operations import receive as _untracked_receive from specklepy.core.api.operations import send as core_send from specklepy.core.api.operations import serialize as core_serialize from specklepy.logging import metrics -from specklepy.logging.exceptions import SpeckleException from specklepy.objects.base import Base -from specklepy.serialization.base_object_serializer import BaseObjectSerializer from specklepy.transports.abstract_transport import AbstractTransport -from specklepy.transports.sqlite import SQLiteTransport def send( diff --git a/src/specklepy/api/resource.py b/src/specklepy/api/resource.py index c2e25ea..3fcc156 100644 --- a/src/specklepy/api/resource.py +++ b/src/specklepy/api/resource.py @@ -1,22 +1,9 @@ -from threading import Lock -from typing import Any, Dict, List, Optional, Tuple, Type, Union +from typing import Any, Optional, Tuple from gql.client import Client -from gql.transport.exceptions import TransportQueryError -from graphql import DocumentNode from specklepy.api.credentials import Account - -# following imports seem to be unnecessary, but they need to stay -# to not break the scripts using these functions as non-core from specklepy.core.api.resource import ResourceBase as CoreResourceBase -from specklepy.logging.exceptions import ( - GraphQLException, - SpeckleException, - UnsupportedException, -) -from specklepy.serialization.base_object_serializer import BaseObjectSerializer -from specklepy.transports.sqlite import SQLiteTransport class ResourceBase(CoreResourceBase): diff --git a/src/specklepy/api/resources/active_user.py b/src/specklepy/api/resources/active_user.py index 141a717..a59a5e6 100644 --- a/src/specklepy/api/resources/active_user.py +++ b/src/specklepy/api/resources/active_user.py @@ -1,13 +1,9 @@ -from datetime import datetime, timezone +from datetime import datetime from typing import List, Optional -from gql import gql - -from specklepy.api.models import ActivityCollection, PendingStreamCollaborator, User -from specklepy.api.resource import ResourceBase +from specklepy.api.models import PendingStreamCollaborator, User from specklepy.core.api.resources.active_user import Resource as CoreResource from specklepy.logging import metrics -from specklepy.logging.exceptions import SpeckleException class Resource(CoreResource): diff --git a/src/specklepy/api/resources/branch.py b/src/specklepy/api/resources/branch.py index 590b979..2336110 100644 --- a/src/specklepy/api/resources/branch.py +++ b/src/specklepy/api/resources/branch.py @@ -1,9 +1,6 @@ from typing import Optional -from gql import gql - from specklepy.api.models import Branch -from specklepy.api.resource import ResourceBase from specklepy.core.api.resources.branch import Resource as CoreResource from specklepy.logging import metrics diff --git a/src/specklepy/api/resources/commit.py b/src/specklepy/api/resources/commit.py index 404de5c..367e5ad 100644 --- a/src/specklepy/api/resources/commit.py +++ b/src/specklepy/api/resources/commit.py @@ -1,9 +1,6 @@ from typing import List, Optional, Union -from gql import gql - from specklepy.api.models import Commit -from specklepy.api.resource import ResourceBase from specklepy.core.api.resources.commit import Resource as CoreResource from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException diff --git a/src/specklepy/api/resources/object.py b/src/specklepy/api/resources/object.py index a15caf9..b7ea96c 100644 --- a/src/specklepy/api/resources/object.py +++ b/src/specklepy/api/resources/object.py @@ -1,8 +1,5 @@ from typing import Dict, List -from gql import gql - -from specklepy.api.resource import ResourceBase from specklepy.core.api.resources.object import Resource as CoreResource from specklepy.logging import metrics from specklepy.objects.base import Base diff --git a/src/specklepy/api/resources/other_user.py b/src/specklepy/api/resources/other_user.py index a3c2656..f9ff35f 100644 --- a/src/specklepy/api/resources/other_user.py +++ b/src/specklepy/api/resources/other_user.py @@ -1,10 +1,7 @@ -from datetime import datetime, timezone +from datetime import datetime from typing import List, Optional, Union -from gql import gql - from specklepy.api.models import ActivityCollection, LimitedUser -from specklepy.api.resource import ResourceBase from specklepy.core.api.resources.other_user import Resource as CoreResource from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException diff --git a/src/specklepy/api/resources/server.py b/src/specklepy/api/resources/server.py index f851def..1e3bb13 100644 --- a/src/specklepy/api/resources/server.py +++ b/src/specklepy/api/resources/server.py @@ -1,13 +1,8 @@ -import re from typing import Any, Dict, List, Tuple -from gql import gql - from specklepy.api.models import ServerInfo -from specklepy.api.resource import ResourceBase from specklepy.core.api.resources.server import Resource as CoreResource from specklepy.logging import metrics -from specklepy.logging.exceptions import GraphQLException class Resource(CoreResource): diff --git a/src/specklepy/api/resources/stream.py b/src/specklepy/api/resources/stream.py index 24dc4ca..330677d 100644 --- a/src/specklepy/api/resources/stream.py +++ b/src/specklepy/api/resources/stream.py @@ -1,14 +1,9 @@ -from datetime import datetime, timezone +from datetime import datetime from typing import List, Optional -from deprecated import deprecated -from gql import gql - -from specklepy.api.models import ActivityCollection, PendingStreamCollaborator, Stream -from specklepy.api.resource import ResourceBase +from specklepy.api.models import PendingStreamCollaborator, Stream from specklepy.core.api.resources.stream import Resource as CoreResource from specklepy.logging import metrics -from specklepy.logging.exceptions import SpeckleException, UnsupportedException class Resource(CoreResource): diff --git a/src/specklepy/api/resources/subscriptions.py b/src/specklepy/api/resources/subscriptions.py index ab28736..3e015fb 100644 --- a/src/specklepy/api/resources/subscriptions.py +++ b/src/specklepy/api/resources/subscriptions.py @@ -1,11 +1,8 @@ from functools import wraps from typing import Callable, Dict, List, Optional, Union -from gql import gql from graphql import DocumentNode -from specklepy.api.resource import ResourceBase -from specklepy.api.resources.stream import Stream from specklepy.core.api.resources.subscriptions import Resource as CoreResource from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException diff --git a/src/specklepy/api/resources/user.py b/src/specklepy/api/resources/user.py index 6742a50..3f45768 100644 --- a/src/specklepy/api/resources/user.py +++ b/src/specklepy/api/resources/user.py @@ -1,11 +1,9 @@ -from datetime import datetime, timezone +from datetime import datetime from typing import List, Optional, Union from deprecated import deprecated -from gql import gql -from specklepy.api.models import ActivityCollection, PendingStreamCollaborator, User -from specklepy.api.resource import ResourceBase +from specklepy.api.models import PendingStreamCollaborator, User from specklepy.core.api.resources.user import Resource as CoreResource from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException diff --git a/src/specklepy/api/wrapper.py b/src/specklepy/api/wrapper.py index 22a3ea6..ad23f12 100644 --- a/src/specklepy/api/wrapper.py +++ b/src/specklepy/api/wrapper.py @@ -1,15 +1,7 @@ -from urllib.parse import unquote, urlparse -from warnings import warn - from specklepy.api.client import SpeckleClient -from specklepy.api.credentials import ( - Account, - get_account_from_token, - get_local_accounts, -) +from specklepy.api.credentials import Account from specklepy.core.api.wrapper import StreamWrapper as CoreStreamWrapper from specklepy.logging import metrics -from specklepy.logging.exceptions import SpeckleException, SpeckleWarning from specklepy.transports.server.server import ServerTransport diff --git a/src/specklepy/core/api/credentials.py b/src/specklepy/core/api/credentials.py index eae4f1c..ba11401 100644 --- a/src/specklepy/core/api/credentials.py +++ b/src/specklepy/core/api/credentials.py @@ -6,7 +6,6 @@ from pydantic import BaseModel, Field # pylint: disable=no-name-in-module from specklepy.core.api.models import ServerInfo from specklepy.core.helpers import speckle_path_provider -from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException from specklepy.transports.sqlite import SQLiteTransport diff --git a/src/specklepy/objects/GIS/geometry.py b/src/specklepy/objects/GIS/geometry.py index e2951c5..d08ba4f 100644 --- a/src/specklepy/objects/GIS/geometry.py +++ b/src/specklepy/objects/GIS/geometry.py @@ -1,7 +1,5 @@ from typing import List, Optional, Union -from deprecated import deprecated - from specklepy.objects import Base from specklepy.objects.geometry import ( Arc, @@ -34,15 +32,15 @@ class GisPolygonElement(Base, speckle_type="Objects.GIS.PolygonElement"): class GisLineElement(Base, speckle_type="Objects.GIS.LineElement"): """GIS Polyline element""" - geometry: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]]] = (None,) - attributes: Optional[Base] = (None,) + geometry: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]]] = None + attributes: Optional[Base] = None class GisPointElement(Base, speckle_type="Objects.GIS.PointElement"): """GIS Point element""" - geometry: Optional[List[Point]] = (None,) - attributes: Optional[Base] = (None,) + geometry: Optional[List[Point]] = None + attributes: Optional[Base] = None class GisRasterElement( diff --git a/src/specklepy/objects/GIS/layers.py b/src/specklepy/objects/GIS/layers.py index ffa207a..e9ab2bc 100644 --- a/src/specklepy/objects/GIS/layers.py +++ b/src/specklepy/objects/GIS/layers.py @@ -90,7 +90,7 @@ class RasterLayer( self.elements = value -class VectorLayer( +class VectorLayer( # noqa: F811 Collection, detachable={"elements"}, speckle_type="Objects.GIS.VectorLayer", @@ -118,7 +118,7 @@ class VectorLayer( self.elements = value -class RasterLayer( +class RasterLayer( # noqa: F811 Collection, detachable={"elements"}, speckle_type="Objects.GIS.RasterLayer", diff --git a/src/specklepy/objects/base.py b/src/specklepy/objects/base.py index d198c2a..e03e32d 100644 --- a/src/specklepy/objects/base.py +++ b/src/specklepy/objects/base.py @@ -19,7 +19,7 @@ from warnings import warn from stringcase import pascalcase from specklepy.logging.exceptions import SpeckleException, SpeckleInvalidUnitException -from specklepy.objects.units import Units, get_units_from_string +from specklepy.objects.units import Units from specklepy.transports.memory import MemoryTransport PRIMITIVES = (int, float, str, bool) diff --git a/src/specklepy/objects/graph_traversal/commit_object_builder.py b/src/specklepy/objects/graph_traversal/commit_object_builder.py index 71d76b5..4b381e9 100644 --- a/src/specklepy/objects/graph_traversal/commit_object_builder.py +++ b/src/specklepy/objects/graph_traversal/commit_object_builder.py @@ -1,16 +1,5 @@ from abc import ABC, abstractmethod -from dataclasses import dataclass -from typing import ( - Any, - Collection, - Dict, - Generic, - Iterable, - List, - Optional, - Tuple, - TypeVar, -) +from typing import Any, Collection, Dict, Generic, Iterable, Optional, Tuple, TypeVar from attrs import define @@ -24,7 +13,6 @@ PARENT_INFO = Tuple[Optional[str], str] @define(slots=True) class CommitObjectBuilder(ABC, Generic[T]): - converted: Dict[str, Base] _parent_infos: Dict[str, Collection[PARENT_INFO]] @@ -42,7 +30,6 @@ class CommitObjectBuilder(ABC, Generic[T]): def set_relationship( self, app_id: Optional[str], *parent_info: PARENT_INFO ) -> None: - if not app_id: return @@ -59,11 +46,11 @@ class CommitObjectBuilder(ABC, Generic[T]): def apply_relationship(self, current: Base, root_commit_object: Base): if not current.applicationId: - raise Exception(f"Expected applicationId to have been set") + raise Exception("Expected applicationId to have been set") parents = self._parent_infos[current.applicationId] - for (parent_id, prop_name) in parents: + for parent_id, prop_name in parents: if not parent_id: continue diff --git a/src/specklepy/objects/graph_traversal/traversal.py b/src/specklepy/objects/graph_traversal/traversal.py index 6187232..22f3ff1 100644 --- a/src/specklepy/objects/graph_traversal/traversal.py +++ b/src/specklepy/objects/graph_traversal/traversal.py @@ -41,7 +41,6 @@ class TraversalContext: @final @define(slots=True, frozen=True) class GraphTraversal: - _rules: List[ITraversalRule] def traverse(self, root: Base) -> Iterator[TraversalContext]: @@ -63,7 +62,7 @@ class GraphTraversal: if getattr(current, child_prop, None): value = current[child_prop] self._traverse_member_to_stack(stack, value, child_prop, head) - except KeyError as ex: + except KeyError: # Unset application ids, and class variables like SpeckleType will throw when __getitem__ is called pass diff --git a/src/specklepy/transports/memory.py b/src/specklepy/transports/memory.py index 43cdff6..3be9e98 100644 --- a/src/specklepy/transports/memory.py +++ b/src/specklepy/transports/memory.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List +from typing import Dict, List from specklepy.transports.abstract_transport import AbstractTransport diff --git a/src/specklepy/transports/server/server.py b/src/specklepy/transports/server/server.py index 019564f..2569323 100644 --- a/src/specklepy/transports/server/server.py +++ b/src/specklepy/transports/server/server.py @@ -1,5 +1,5 @@ import json -from typing import Any, Dict, List, Optional +from typing import Dict, List, Optional from warnings import warn import requests diff --git a/src/specklepy/transports/sqlite.py b/src/specklepy/transports/sqlite.py index bcdd475..085bedd 100644 --- a/src/specklepy/transports/sqlite.py +++ b/src/specklepy/transports/sqlite.py @@ -1,7 +1,7 @@ import os import sqlite3 from contextlib import closing -from typing import Any, Dict, List, Optional, Tuple +from typing import Dict, List, Optional, Tuple from specklepy.core.helpers import speckle_path_provider from specklepy.logging.exceptions import SpeckleException diff --git a/tests/intergration/speckle_automate/test_automation_context.py b/tests/intergration/speckle_automate/test_automation_context.py index 01f2685..af5aafe 100644 --- a/tests/intergration/speckle_automate/test_automation_context.py +++ b/tests/intergration/speckle_automate/test_automation_context.py @@ -111,8 +111,8 @@ def get_automation_status( query = gql( """ query AutomationRuns( - $projectId: String! - $modelId: String! + $projectId: String! + $modelId: String! ) { project(id: $projectId) { diff --git a/tests/intergration/test_stream.py b/tests/intergration/test_stream.py index 4c8e4c2..7e6455d 100644 --- a/tests/intergration/test_stream.py +++ b/tests/intergration/test_stream.py @@ -8,11 +8,7 @@ from specklepy.api.models import ( Stream, User, ) -from specklepy.logging.exceptions import ( - GraphQLException, - SpeckleException, - UnsupportedException, -) +from specklepy.logging.exceptions import GraphQLException, SpeckleException @pytest.mark.run(order=3) From 7ca00b7b7723ff58d0edd5e0c841599c101d3326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Mon, 27 Nov 2023 14:27:09 +0100 Subject: [PATCH 43/54] chore: fix unused import --- src/specklepy/core/api/resources/stream.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/specklepy/core/api/resources/stream.py b/src/specklepy/core/api/resources/stream.py index 712851d..5c105cd 100644 --- a/src/specklepy/core/api/resources/stream.py +++ b/src/specklepy/core/api/resources/stream.py @@ -1,7 +1,6 @@ from datetime import datetime, timezone from typing import List, Optional -from deprecated import deprecated from gql import gql from specklepy.core.api.models import ( From 7ad0785c6267905d5ede14ef060febae278ce417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Mon, 27 Nov 2023 14:33:31 +0100 Subject: [PATCH 44/54] chore: reformat --- src/specklepy/core/api/client.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/specklepy/core/api/client.py b/src/specklepy/core/api/client.py index 4386dea..b7c70d0 100644 --- a/src/specklepy/core/api/client.py +++ b/src/specklepy/core/api/client.py @@ -60,7 +60,12 @@ class SpeckleClient: USE_SSL = True VERIFY_CERTIFICATE = True - def __init__(self, host: str = DEFAULT_HOST, use_ssl: bool = USE_SSL, verify_certificate: bool = VERIFY_CERTIFICATE) -> None: + def __init__( + self, + host: str = DEFAULT_HOST, + use_ssl: bool = USE_SSL, + verify_certificate: bool = VERIFY_CERTIFICATE, + ) -> None: ws_protocol = "ws" http_protocol = "http" @@ -78,7 +83,9 @@ class SpeckleClient: self.verify_certificate = verify_certificate self.httpclient = Client( - transport=RequestsHTTPTransport(url=self.graphql, verify=self.verify_certificate, retries=3) + transport=RequestsHTTPTransport( + url=self.graphql, verify=self.verify_certificate, retries=3 + ) ) self.wsclient = None From 223c776c633140254ca6ae0f2f43fee604a10efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Tue, 5 Dec 2023 15:03:25 +0100 Subject: [PATCH 45/54] fix: remove unnecessary kwargs from init subclass call chain --- poetry.lock | 820 +++++++++++++++++----------------- pyproject.toml | 4 +- src/specklepy/objects/base.py | 3 +- 3 files changed, 420 insertions(+), 407 deletions(-) diff --git a/poetry.lock b/poetry.lock index f6a6c9f..8beb5cd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,13 +2,13 @@ [[package]] name = "annotated-types" -version = "0.5.0" +version = "0.6.0" description = "Reusable constraint types to use with typing.Annotated" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, - {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, ] [package.dependencies] @@ -16,13 +16,13 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} [[package]] name = "anyio" -version = "4.0.0" +version = "4.1.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.0.0-py3-none-any.whl", hash = "sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f"}, - {file = "anyio-4.0.0.tar.gz", hash = "sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a"}, + {file = "anyio-4.1.0-py3-none-any.whl", hash = "sha256:56a415fbc462291813a94528a779597226619c8e78af7de0507333f700011e5f"}, + {file = "anyio-4.1.0.tar.gz", hash = "sha256:5a0bec7085176715be77df87fc66d6c9d70626bd752fcc85f57cdbee5b3760da"}, ] [package.dependencies] @@ -31,9 +31,9 @@ idna = ">=2.8" sniffio = ">=1.1" [package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.22)"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] [[package]] name = "appdirs" @@ -63,13 +63,13 @@ test = ["coverage", "flake8", "mypy", "pexpect", "wheel"] [[package]] name = "astroid" -version = "2.15.6" +version = "2.15.8" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.7.2" files = [ - {file = "astroid-2.15.6-py3-none-any.whl", hash = "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c"}, - {file = "astroid-2.15.6.tar.gz", hash = "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd"}, + {file = "astroid-2.15.8-py3-none-any.whl", hash = "sha256:1aa149fc5c6589e3d0ece885b4491acd80af4f087baafa3fb5203b113e68cd3c"}, + {file = "astroid-2.15.8.tar.gz", hash = "sha256:6c107453dffee9055899705de3c9ead36e74119cee151e5a9aaf7f0b0e020a6a"}, ] [package.dependencies] @@ -82,20 +82,21 @@ wrapt = [ [[package]] name = "asttokens" -version = "2.4.0" +version = "2.4.1" description = "Annotate AST trees with source code positions" optional = false python-versions = "*" files = [ - {file = "asttokens-2.4.0-py2.py3-none-any.whl", hash = "sha256:cf8fc9e61a86461aa9fb161a14a0841a03c405fa829ac6b202670b3495d2ce69"}, - {file = "asttokens-2.4.0.tar.gz", hash = "sha256:2e0171b991b2c959acc6c49318049236844a5da1d65ba2672c4880c1c894834e"}, + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, ] [package.dependencies] six = ">=1.12.0" [package.extras] -test = ["astroid", "pytest"] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] [[package]] name = "attrs" @@ -163,13 +164,13 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" -version = "2023.7.22" +version = "2023.11.17" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, ] [[package]] @@ -248,63 +249,63 @@ typing-extensions = ">=4.0.1,<5.0.0" [[package]] name = "coverage" -version = "7.3.1" +version = "7.3.2" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cd0f7429ecfd1ff597389907045ff209c8fdb5b013d38cfa7c60728cb484b6e3"}, - {file = "coverage-7.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:966f10df9b2b2115da87f50f6a248e313c72a668248be1b9060ce935c871f276"}, - {file = "coverage-7.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0575c37e207bb9b98b6cf72fdaaa18ac909fb3d153083400c2d48e2e6d28bd8e"}, - {file = "coverage-7.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:245c5a99254e83875c7fed8b8b2536f040997a9b76ac4c1da5bff398c06e860f"}, - {file = "coverage-7.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c96dd7798d83b960afc6c1feb9e5af537fc4908852ef025600374ff1a017392"}, - {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:de30c1aa80f30af0f6b2058a91505ea6e36d6535d437520067f525f7df123887"}, - {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:50dd1e2dd13dbbd856ffef69196781edff26c800a74f070d3b3e3389cab2600d"}, - {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9c0c19f70d30219113b18fe07e372b244fb2a773d4afde29d5a2f7930765136"}, - {file = "coverage-7.3.1-cp310-cp310-win32.whl", hash = "sha256:770f143980cc16eb601ccfd571846e89a5fe4c03b4193f2e485268f224ab602f"}, - {file = "coverage-7.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:cdd088c00c39a27cfa5329349cc763a48761fdc785879220d54eb785c8a38520"}, - {file = "coverage-7.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74bb470399dc1989b535cb41f5ca7ab2af561e40def22d7e188e0a445e7639e3"}, - {file = "coverage-7.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:025ded371f1ca280c035d91b43252adbb04d2aea4c7105252d3cbc227f03b375"}, - {file = "coverage-7.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6191b3a6ad3e09b6cfd75b45c6aeeffe7e3b0ad46b268345d159b8df8d835f9"}, - {file = "coverage-7.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7eb0b188f30e41ddd659a529e385470aa6782f3b412f860ce22b2491c89b8593"}, - {file = "coverage-7.3.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75c8f0df9dfd8ff745bccff75867d63ef336e57cc22b2908ee725cc552689ec8"}, - {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7eb3cd48d54b9bd0e73026dedce44773214064be93611deab0b6a43158c3d5a0"}, - {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ac3c5b7e75acac31e490b7851595212ed951889918d398b7afa12736c85e13ce"}, - {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b4ee7080878077af0afa7238df1b967f00dc10763f6e1b66f5cced4abebb0a3"}, - {file = "coverage-7.3.1-cp311-cp311-win32.whl", hash = "sha256:229c0dd2ccf956bf5aeede7e3131ca48b65beacde2029f0361b54bf93d36f45a"}, - {file = "coverage-7.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c6f55d38818ca9596dc9019eae19a47410d5322408140d9a0076001a3dcb938c"}, - {file = "coverage-7.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5289490dd1c3bb86de4730a92261ae66ea8d44b79ed3cc26464f4c2cde581fbc"}, - {file = "coverage-7.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ca833941ec701fda15414be400c3259479bfde7ae6d806b69e63b3dc423b1832"}, - {file = "coverage-7.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd694e19c031733e446c8024dedd12a00cda87e1c10bd7b8539a87963685e969"}, - {file = "coverage-7.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aab8e9464c00da5cb9c536150b7fbcd8850d376d1151741dd0d16dfe1ba4fd26"}, - {file = "coverage-7.3.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87d38444efffd5b056fcc026c1e8d862191881143c3aa80bb11fcf9dca9ae204"}, - {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8a07b692129b8a14ad7a37941a3029c291254feb7a4237f245cfae2de78de037"}, - {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2829c65c8faaf55b868ed7af3c7477b76b1c6ebeee99a28f59a2cb5907a45760"}, - {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f111a7d85658ea52ffad7084088277135ec5f368457275fc57f11cebb15607f"}, - {file = "coverage-7.3.1-cp312-cp312-win32.whl", hash = "sha256:c397c70cd20f6df7d2a52283857af622d5f23300c4ca8e5bd8c7a543825baa5a"}, - {file = "coverage-7.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:5ae4c6da8b3d123500f9525b50bf0168023313963e0e2e814badf9000dd6ef92"}, - {file = "coverage-7.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca70466ca3a17460e8fc9cea7123c8cbef5ada4be3140a1ef8f7b63f2f37108f"}, - {file = "coverage-7.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f2781fd3cabc28278dc982a352f50c81c09a1a500cc2086dc4249853ea96b981"}, - {file = "coverage-7.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6407424621f40205bbe6325686417e5e552f6b2dba3535dd1f90afc88a61d465"}, - {file = "coverage-7.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:04312b036580ec505f2b77cbbdfb15137d5efdfade09156961f5277149f5e344"}, - {file = "coverage-7.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9ad38204887349853d7c313f53a7b1c210ce138c73859e925bc4e5d8fc18e7"}, - {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:53669b79f3d599da95a0afbef039ac0fadbb236532feb042c534fbb81b1a4e40"}, - {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:614f1f98b84eb256e4f35e726bfe5ca82349f8dfa576faabf8a49ca09e630086"}, - {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1a317fdf5c122ad642db8a97964733ab7c3cf6009e1a8ae8821089993f175ff"}, - {file = "coverage-7.3.1-cp38-cp38-win32.whl", hash = "sha256:defbbb51121189722420a208957e26e49809feafca6afeef325df66c39c4fdb3"}, - {file = "coverage-7.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:f4f456590eefb6e1b3c9ea6328c1e9fa0f1006e7481179d749b3376fc793478e"}, - {file = "coverage-7.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f12d8b11a54f32688b165fd1a788c408f927b0960984b899be7e4c190ae758f1"}, - {file = "coverage-7.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f09195dda68d94a53123883de75bb97b0e35f5f6f9f3aa5bf6e496da718f0cb6"}, - {file = "coverage-7.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6601a60318f9c3945be6ea0f2a80571f4299b6801716f8a6e4846892737ebe4"}, - {file = "coverage-7.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d156269718670d00a3b06db2288b48527fc5f36859425ff7cec07c6b367745"}, - {file = "coverage-7.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:636a8ac0b044cfeccae76a36f3b18264edcc810a76a49884b96dd744613ec0b7"}, - {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5d991e13ad2ed3aced177f524e4d670f304c8233edad3210e02c465351f785a0"}, - {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:586649ada7cf139445da386ab6f8ef00e6172f11a939fc3b2b7e7c9082052fa0"}, - {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4aba512a15a3e1e4fdbfed2f5392ec221434a614cc68100ca99dcad7af29f3f8"}, - {file = "coverage-7.3.1-cp39-cp39-win32.whl", hash = "sha256:6bc6f3f4692d806831c136c5acad5ccedd0262aa44c087c46b7101c77e139140"}, - {file = "coverage-7.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:553d7094cb27db58ea91332e8b5681bac107e7242c23f7629ab1316ee73c4981"}, - {file = "coverage-7.3.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:220eb51f5fb38dfdb7e5d54284ca4d0cd70ddac047d750111a68ab1798945194"}, - {file = "coverage-7.3.1.tar.gz", hash = "sha256:6cb7fe1581deb67b782c153136541e20901aa312ceedaf1467dcb35255787952"}, + {file = "coverage-7.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d872145f3a3231a5f20fd48500274d7df222e291d90baa2026cc5152b7ce86bf"}, + {file = "coverage-7.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:310b3bb9c91ea66d59c53fa4989f57d2436e08f18fb2f421a1b0b6b8cc7fffda"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f47d39359e2c3779c5331fc740cf4bce6d9d680a7b4b4ead97056a0ae07cb49a"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa72dbaf2c2068404b9870d93436e6d23addd8bbe9295f49cbca83f6e278179c"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:beaa5c1b4777f03fc63dfd2a6bd820f73f036bfb10e925fce067b00a340d0f3f"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dbc1b46b92186cc8074fee9d9fbb97a9dd06c6cbbef391c2f59d80eabdf0faa6"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:315a989e861031334d7bee1f9113c8770472db2ac484e5b8c3173428360a9148"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d1bc430677773397f64a5c88cb522ea43175ff16f8bfcc89d467d974cb2274f9"}, + {file = "coverage-7.3.2-cp310-cp310-win32.whl", hash = "sha256:a889ae02f43aa45032afe364c8ae84ad3c54828c2faa44f3bfcafecb5c96b02f"}, + {file = "coverage-7.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c0ba320de3fb8c6ec16e0be17ee1d3d69adcda99406c43c0409cb5c41788a611"}, + {file = "coverage-7.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ac8c802fa29843a72d32ec56d0ca792ad15a302b28ca6203389afe21f8fa062c"}, + {file = "coverage-7.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:89a937174104339e3a3ffcf9f446c00e3a806c28b1841c63edb2b369310fd074"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e267e9e2b574a176ddb983399dec325a80dbe161f1a32715c780b5d14b5f583a"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2443cbda35df0d35dcfb9bf8f3c02c57c1d6111169e3c85fc1fcc05e0c9f39a3"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4175e10cc8dda0265653e8714b3174430b07c1dca8957f4966cbd6c2b1b8065a"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf38419fb1a347aaf63481c00f0bdc86889d9fbf3f25109cf96c26b403fda1"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5c913b556a116b8d5f6ef834038ba983834d887d82187c8f73dec21049abd65c"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1981f785239e4e39e6444c63a98da3a1db8e971cb9ceb50a945ba6296b43f312"}, + {file = "coverage-7.3.2-cp311-cp311-win32.whl", hash = "sha256:43668cabd5ca8258f5954f27a3aaf78757e6acf13c17604d89648ecc0cc66640"}, + {file = "coverage-7.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10c39c0452bf6e694511c901426d6b5ac005acc0f78ff265dbe36bf81f808a2"}, + {file = "coverage-7.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4cbae1051ab791debecc4a5dcc4a1ff45fc27b91b9aee165c8a27514dd160836"}, + {file = "coverage-7.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12d15ab5833a997716d76f2ac1e4b4d536814fc213c85ca72756c19e5a6b3d63"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c7bba973ebee5e56fe9251300c00f1579652587a9f4a5ed8404b15a0471f216"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe494faa90ce6381770746077243231e0b83ff3f17069d748f645617cefe19d4"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6e9589bd04d0461a417562649522575d8752904d35c12907d8c9dfeba588faf"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d51ac2a26f71da1b57f2dc81d0e108b6ab177e7d30e774db90675467c847bbdf"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:99b89d9f76070237975b315b3d5f4d6956ae354a4c92ac2388a5695516e47c84"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fa28e909776dc69efb6ed975a63691bc8172b64ff357e663a1bb06ff3c9b589a"}, + {file = "coverage-7.3.2-cp312-cp312-win32.whl", hash = "sha256:289fe43bf45a575e3ab10b26d7b6f2ddb9ee2dba447499f5401cfb5ecb8196bb"}, + {file = "coverage-7.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7dbc3ed60e8659bc59b6b304b43ff9c3ed858da2839c78b804973f613d3e92ed"}, + {file = "coverage-7.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f94b734214ea6a36fe16e96a70d941af80ff3bfd716c141300d95ebc85339738"}, + {file = "coverage-7.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af3d828d2c1cbae52d34bdbb22fcd94d1ce715d95f1a012354a75e5913f1bda2"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630b13e3036e13c7adc480ca42fa7afc2a5d938081d28e20903cf7fd687872e2"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9eacf273e885b02a0273bb3a2170f30e2d53a6d53b72dbe02d6701b5296101c"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f17966e861ff97305e0801134e69db33b143bbfb36436efb9cfff6ec7b2fd9"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4275802d16882cf9c8b3d057a0839acb07ee9379fa2749eca54efbce1535b82"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:72c0cfa5250f483181e677ebc97133ea1ab3eb68645e494775deb6a7f6f83901"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cb536f0dcd14149425996821a168f6e269d7dcd2c273a8bff8201e79f5104e76"}, + {file = "coverage-7.3.2-cp38-cp38-win32.whl", hash = "sha256:307adb8bd3abe389a471e649038a71b4eb13bfd6b7dd9a129fa856f5c695cf92"}, + {file = "coverage-7.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:88ed2c30a49ea81ea3b7f172e0269c182a44c236eb394718f976239892c0a27a"}, + {file = "coverage-7.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b631c92dfe601adf8f5ebc7fc13ced6bb6e9609b19d9a8cd59fa47c4186ad1ce"}, + {file = "coverage-7.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d3d9df4051c4a7d13036524b66ecf7a7537d14c18a384043f30a303b146164e9"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7363d3b6a1119ef05015959ca24a9afc0ea8a02c687fe7e2d557705375c01f"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f11cc3c967a09d3695d2a6f03fb3e6236622b93be7a4b5dc09166a861be6d25"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:149de1d2401ae4655c436a3dced6dd153f4c3309f599c3d4bd97ab172eaf02d9"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3a4006916aa6fee7cd38db3bfc95aa9c54ebb4ffbfc47c677c8bba949ceba0a6"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9028a3871280110d6e1aa2df1afd5ef003bab5fb1ef421d6dc748ae1c8ef2ebc"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9f805d62aec8eb92bab5b61c0f07329275b6f41c97d80e847b03eb894f38d083"}, + {file = "coverage-7.3.2-cp39-cp39-win32.whl", hash = "sha256:d1c88ec1a7ff4ebca0219f5b1ef863451d828cccf889c173e1253aa84b1e07ce"}, + {file = "coverage-7.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4767da59464bb593c07afceaddea61b154136300881844768037fd5e859353f"}, + {file = "coverage-7.3.2-pp38.pp39.pp310-none-any.whl", hash = "sha256:ae97af89f0fbf373400970c0a21eef5aa941ffeed90aee43650b81f7d7f47637"}, + {file = "coverage-7.3.2.tar.gz", hash = "sha256:be32ad29341b0170e795ca590e1c07e81fc061cb5b10c74ce7203491484404ef"}, ] [package.dependencies] @@ -386,13 +387,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -411,19 +412,19 @@ files = [ [[package]] name = "filelock" -version = "3.12.4" +version = "3.13.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, - {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] -typing = ["typing-extensions (>=4.7.1)"] +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)"] +typing = ["typing-extensions (>=4.8)"] [[package]] name = "gql" @@ -479,39 +480,40 @@ files = [ [[package]] name = "httpcore" -version = "0.18.0" +version = "1.0.2" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-0.18.0-py3-none-any.whl", hash = "sha256:adc5398ee0a476567bf87467063ee63584a8bce86078bf748e48754f60202ced"}, - {file = "httpcore-0.18.0.tar.gz", hash = "sha256:13b5e5cd1dca1a6636a6aaea212b19f4f85cd88c366a2b82304181b769aab3c9"}, + {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, + {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, ] [package.dependencies] -anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = "==1.*" [package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.23.0)"] [[package]] name = "httpx" -version = "0.25.0" +version = "0.25.2" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpx-0.25.0-py3-none-any.whl", hash = "sha256:181ea7f8ba3a82578be86ef4171554dd45fec26a02556a744db029a0a27b7100"}, - {file = "httpx-0.25.0.tar.gz", hash = "sha256:47ecda285389cb32bb2691cc6e069e3ab0205956f681c5b2ad2325719751d875"}, + {file = "httpx-0.25.2-py3-none-any.whl", hash = "sha256:a05d3d052d9b2dfce0e3896636467f8a5342fb2b902c819428e1ac65413ca118"}, + {file = "httpx-0.25.2.tar.gz", hash = "sha256:8b8fcaa0c8ea7b05edd69a094e63a2094c4efcb48129fb757361bc423c0ad9e8"}, ] [package.dependencies] +anyio = "*" certifi = "*" -httpcore = ">=0.18.0,<0.19.0" +httpcore = "==1.*" idna = "*" sniffio = "*" @@ -523,13 +525,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "identify" -version = "2.5.29" +version = "2.5.32" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.29-py2.py3-none-any.whl", hash = "sha256:24437fbf6f4d3fe6efd0eb9d67e24dd9106db99af5ceb27996a5f7895f24bf1b"}, - {file = "identify-2.5.29.tar.gz", hash = "sha256:d43d52b86b15918c137e3a74fff5224f60385cd0e9c38e99d07c257f02f151a5"}, + {file = "identify-2.5.32-py2.py3-none-any.whl", hash = "sha256:0b7656ef6cba81664b783352c73f8c24b39cf82f926f78f4550eda928e5e0545"}, + {file = "identify-2.5.32.tar.gz", hash = "sha256:5d9979348ec1a21c768ae07e0a652924538e8bce67313a73cb0f681cf08ba407"}, ] [package.extras] @@ -537,13 +539,13 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] @@ -859,13 +861,13 @@ setuptools = "*" [[package]] name = "packaging" -version = "23.1" +version = "23.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] [[package]] @@ -881,13 +883,13 @@ files = [ [[package]] name = "platformdirs" -version = "3.10.0" +version = "4.1.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, - {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, + {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, + {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, ] [package.extras] @@ -929,13 +931,13 @@ virtualenv = ">=20.10.0" [[package]] name = "prompt-toolkit" -version = "3.0.39" +version = "3.0.41" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, - {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, + {file = "prompt_toolkit-3.0.41-py3-none-any.whl", hash = "sha256:f36fe301fafb7470e86aaf90f036eef600a3210be4decf461a5b1ca8403d3cb2"}, + {file = "prompt_toolkit-3.0.41.tar.gz", hash = "sha256:941367d97fc815548822aa26c2a269fdc4eb21e9ec05fc5d447cf09bad5d75f0"}, ] [package.dependencies] @@ -943,18 +945,18 @@ wcwidth = "*" [[package]] name = "pydantic" -version = "2.3.0" +version = "2.5.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-2.3.0-py3-none-any.whl", hash = "sha256:45b5e446c6dfaad9444819a293b921a40e1db1aa61ea08aede0522529ce90e81"}, - {file = "pydantic-2.3.0.tar.gz", hash = "sha256:1607cc106602284cd4a00882986570472f193fde9cb1259bceeaedb26aa79a6d"}, + {file = "pydantic-2.5.2-py3-none-any.whl", hash = "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0"}, + {file = "pydantic-2.5.2.tar.gz", hash = "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.6.3" +pydantic-core = "2.14.5" typing-extensions = ">=4.6.1" [package.extras] @@ -962,117 +964,116 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.6.3" +version = "2.14.5" description = "" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic_core-2.6.3-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:1a0ddaa723c48af27d19f27f1c73bdc615c73686d763388c8683fe34ae777bad"}, - {file = "pydantic_core-2.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5cfde4fab34dd1e3a3f7f3db38182ab6c95e4ea91cf322242ee0be5c2f7e3d2f"}, - {file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5493a7027bfc6b108e17c3383959485087d5942e87eb62bbac69829eae9bc1f7"}, - {file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:84e87c16f582f5c753b7f39a71bd6647255512191be2d2dbf49458c4ef024588"}, - {file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:522a9c4a4d1924facce7270c84b5134c5cabcb01513213662a2e89cf28c1d309"}, - {file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaafc776e5edc72b3cad1ccedb5fd869cc5c9a591f1213aa9eba31a781be9ac1"}, - {file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a750a83b2728299ca12e003d73d1264ad0440f60f4fc9cee54acc489249b728"}, - {file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e8b374ef41ad5c461efb7a140ce4730661aadf85958b5c6a3e9cf4e040ff4bb"}, - {file = "pydantic_core-2.6.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b594b64e8568cf09ee5c9501ede37066b9fc41d83d58f55b9952e32141256acd"}, - {file = "pydantic_core-2.6.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2a20c533cb80466c1d42a43a4521669ccad7cf2967830ac62c2c2f9cece63e7e"}, - {file = "pydantic_core-2.6.3-cp310-none-win32.whl", hash = "sha256:04fe5c0a43dec39aedba0ec9579001061d4653a9b53a1366b113aca4a3c05ca7"}, - {file = "pydantic_core-2.6.3-cp310-none-win_amd64.whl", hash = "sha256:6bf7d610ac8f0065a286002a23bcce241ea8248c71988bda538edcc90e0c39ad"}, - {file = "pydantic_core-2.6.3-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:6bcc1ad776fffe25ea5c187a028991c031a00ff92d012ca1cc4714087e575973"}, - {file = "pydantic_core-2.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:df14f6332834444b4a37685810216cc8fe1fe91f447332cd56294c984ecbff1c"}, - {file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b7486d85293f7f0bbc39b34e1d8aa26210b450bbd3d245ec3d732864009819"}, - {file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a892b5b1871b301ce20d40b037ffbe33d1407a39639c2b05356acfef5536d26a"}, - {file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:883daa467865e5766931e07eb20f3e8152324f0adf52658f4d302242c12e2c32"}, - {file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4eb77df2964b64ba190eee00b2312a1fd7a862af8918ec70fc2d6308f76ac64"}, - {file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce8c84051fa292a5dc54018a40e2a1926fd17980a9422c973e3ebea017aa8da"}, - {file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22134a4453bd59b7d1e895c455fe277af9d9d9fbbcb9dc3f4a97b8693e7e2c9b"}, - {file = "pydantic_core-2.6.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:02e1c385095efbd997311d85c6021d32369675c09bcbfff3b69d84e59dc103f6"}, - {file = "pydantic_core-2.6.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d79f1f2f7ebdb9b741296b69049ff44aedd95976bfee38eb4848820628a99b50"}, - {file = "pydantic_core-2.6.3-cp311-none-win32.whl", hash = "sha256:430ddd965ffd068dd70ef4e4d74f2c489c3a313adc28e829dd7262cc0d2dd1e8"}, - {file = "pydantic_core-2.6.3-cp311-none-win_amd64.whl", hash = "sha256:84f8bb34fe76c68c9d96b77c60cef093f5e660ef8e43a6cbfcd991017d375950"}, - {file = "pydantic_core-2.6.3-cp311-none-win_arm64.whl", hash = "sha256:5a2a3c9ef904dcdadb550eedf3291ec3f229431b0084666e2c2aa8ff99a103a2"}, - {file = "pydantic_core-2.6.3-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:8421cf496e746cf8d6b677502ed9a0d1e4e956586cd8b221e1312e0841c002d5"}, - {file = "pydantic_core-2.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bb128c30cf1df0ab78166ded1ecf876620fb9aac84d2413e8ea1594b588c735d"}, - {file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37a822f630712817b6ecc09ccc378192ef5ff12e2c9bae97eb5968a6cdf3b862"}, - {file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:240a015102a0c0cc8114f1cba6444499a8a4d0333e178bc504a5c2196defd456"}, - {file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f90e5e3afb11268628c89f378f7a1ea3f2fe502a28af4192e30a6cdea1e7d5e"}, - {file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:340e96c08de1069f3d022a85c2a8c63529fd88709468373b418f4cf2c949fb0e"}, - {file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1480fa4682e8202b560dcdc9eeec1005f62a15742b813c88cdc01d44e85308e5"}, - {file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f14546403c2a1d11a130b537dda28f07eb6c1805a43dae4617448074fd49c282"}, - {file = "pydantic_core-2.6.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a87c54e72aa2ef30189dc74427421e074ab4561cf2bf314589f6af5b37f45e6d"}, - {file = "pydantic_core-2.6.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f93255b3e4d64785554e544c1c76cd32f4a354fa79e2eeca5d16ac2e7fdd57aa"}, - {file = "pydantic_core-2.6.3-cp312-none-win32.whl", hash = "sha256:f70dc00a91311a1aea124e5f64569ea44c011b58433981313202c46bccbec0e1"}, - {file = "pydantic_core-2.6.3-cp312-none-win_amd64.whl", hash = "sha256:23470a23614c701b37252618e7851e595060a96a23016f9a084f3f92f5ed5881"}, - {file = "pydantic_core-2.6.3-cp312-none-win_arm64.whl", hash = "sha256:1ac1750df1b4339b543531ce793b8fd5c16660a95d13aecaab26b44ce11775e9"}, - {file = "pydantic_core-2.6.3-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:a53e3195f134bde03620d87a7e2b2f2046e0e5a8195e66d0f244d6d5b2f6d31b"}, - {file = "pydantic_core-2.6.3-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:f2969e8f72c6236c51f91fbb79c33821d12a811e2a94b7aa59c65f8dbdfad34a"}, - {file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:672174480a85386dd2e681cadd7d951471ad0bb028ed744c895f11f9d51b9ebe"}, - {file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:002d0ea50e17ed982c2d65b480bd975fc41086a5a2f9c924ef8fc54419d1dea3"}, - {file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ccc13afee44b9006a73d2046068d4df96dc5b333bf3509d9a06d1b42db6d8bf"}, - {file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:439a0de139556745ae53f9cc9668c6c2053444af940d3ef3ecad95b079bc9987"}, - {file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d63b7545d489422d417a0cae6f9898618669608750fc5e62156957e609e728a5"}, - {file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b44c42edc07a50a081672e25dfe6022554b47f91e793066a7b601ca290f71e42"}, - {file = "pydantic_core-2.6.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1c721bfc575d57305dd922e6a40a8fe3f762905851d694245807a351ad255c58"}, - {file = "pydantic_core-2.6.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5e4a2cf8c4543f37f5dc881de6c190de08096c53986381daebb56a355be5dfe6"}, - {file = "pydantic_core-2.6.3-cp37-none-win32.whl", hash = "sha256:d9b4916b21931b08096efed090327f8fe78e09ae8f5ad44e07f5c72a7eedb51b"}, - {file = "pydantic_core-2.6.3-cp37-none-win_amd64.whl", hash = "sha256:a8acc9dedd304da161eb071cc7ff1326aa5b66aadec9622b2574ad3ffe225525"}, - {file = "pydantic_core-2.6.3-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:5e9c068f36b9f396399d43bfb6defd4cc99c36215f6ff33ac8b9c14ba15bdf6b"}, - {file = "pydantic_core-2.6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e61eae9b31799c32c5f9b7be906be3380e699e74b2db26c227c50a5fc7988698"}, - {file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85463560c67fc65cd86153a4975d0b720b6d7725cf7ee0b2d291288433fc21b"}, - {file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9616567800bdc83ce136e5847d41008a1d602213d024207b0ff6cab6753fe645"}, - {file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e9b65a55bbabda7fccd3500192a79f6e474d8d36e78d1685496aad5f9dbd92c"}, - {file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f468d520f47807d1eb5d27648393519655eadc578d5dd862d06873cce04c4d1b"}, - {file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9680dd23055dd874173a3a63a44e7f5a13885a4cfd7e84814be71be24fba83db"}, - {file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a718d56c4d55efcfc63f680f207c9f19c8376e5a8a67773535e6f7e80e93170"}, - {file = "pydantic_core-2.6.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8ecbac050856eb6c3046dea655b39216597e373aa8e50e134c0e202f9c47efec"}, - {file = "pydantic_core-2.6.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:788be9844a6e5c4612b74512a76b2153f1877cd845410d756841f6c3420230eb"}, - {file = "pydantic_core-2.6.3-cp38-none-win32.whl", hash = "sha256:07a1aec07333bf5adebd8264047d3dc518563d92aca6f2f5b36f505132399efc"}, - {file = "pydantic_core-2.6.3-cp38-none-win_amd64.whl", hash = "sha256:621afe25cc2b3c4ba05fff53525156d5100eb35c6e5a7cf31d66cc9e1963e378"}, - {file = "pydantic_core-2.6.3-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:813aab5bfb19c98ae370952b6f7190f1e28e565909bfc219a0909db168783465"}, - {file = "pydantic_core-2.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:50555ba3cb58f9861b7a48c493636b996a617db1a72c18da4d7f16d7b1b9952b"}, - {file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19e20f8baedd7d987bd3f8005c146e6bcbda7cdeefc36fad50c66adb2dd2da48"}, - {file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b0a5d7edb76c1c57b95df719af703e796fc8e796447a1da939f97bfa8a918d60"}, - {file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f06e21ad0b504658a3a9edd3d8530e8cea5723f6ea5d280e8db8efc625b47e49"}, - {file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea053cefa008fda40f92aab937fb9f183cf8752e41dbc7bc68917884454c6362"}, - {file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:171a4718860790f66d6c2eda1d95dd1edf64f864d2e9f9115840840cf5b5713f"}, - {file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ed7ceca6aba5331ece96c0e328cd52f0dcf942b8895a1ed2642de50800b79d3"}, - {file = "pydantic_core-2.6.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:acafc4368b289a9f291e204d2c4c75908557d4f36bd3ae937914d4529bf62a76"}, - {file = "pydantic_core-2.6.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1aa712ba150d5105814e53cb141412217146fedc22621e9acff9236d77d2a5ef"}, - {file = "pydantic_core-2.6.3-cp39-none-win32.whl", hash = "sha256:44b4f937b992394a2e81a5c5ce716f3dcc1237281e81b80c748b2da6dd5cf29a"}, - {file = "pydantic_core-2.6.3-cp39-none-win_amd64.whl", hash = "sha256:9b33bf9658cb29ac1a517c11e865112316d09687d767d7a0e4a63d5c640d1b17"}, - {file = "pydantic_core-2.6.3-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d7050899026e708fb185e174c63ebc2c4ee7a0c17b0a96ebc50e1f76a231c057"}, - {file = "pydantic_core-2.6.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:99faba727727b2e59129c59542284efebbddade4f0ae6a29c8b8d3e1f437beb7"}, - {file = "pydantic_core-2.6.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fa159b902d22b283b680ef52b532b29554ea2a7fc39bf354064751369e9dbd7"}, - {file = "pydantic_core-2.6.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:046af9cfb5384f3684eeb3f58a48698ddab8dd870b4b3f67f825353a14441418"}, - {file = "pydantic_core-2.6.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:930bfe73e665ebce3f0da2c6d64455098aaa67e1a00323c74dc752627879fc67"}, - {file = "pydantic_core-2.6.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:85cc4d105747d2aa3c5cf3e37dac50141bff779545ba59a095f4a96b0a460e70"}, - {file = "pydantic_core-2.6.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b25afe9d5c4f60dcbbe2b277a79be114e2e65a16598db8abee2a2dcde24f162b"}, - {file = "pydantic_core-2.6.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e49ce7dc9f925e1fb010fc3d555250139df61fa6e5a0a95ce356329602c11ea9"}, - {file = "pydantic_core-2.6.3-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:2dd50d6a1aef0426a1d0199190c6c43ec89812b1f409e7fe44cb0fbf6dfa733c"}, - {file = "pydantic_core-2.6.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6595b0d8c8711e8e1dc389d52648b923b809f68ac1c6f0baa525c6440aa0daa"}, - {file = "pydantic_core-2.6.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ef724a059396751aef71e847178d66ad7fc3fc969a1a40c29f5aac1aa5f8784"}, - {file = "pydantic_core-2.6.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3c8945a105f1589ce8a693753b908815e0748f6279959a4530f6742e1994dcb6"}, - {file = "pydantic_core-2.6.3-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c8c6660089a25d45333cb9db56bb9e347241a6d7509838dbbd1931d0e19dbc7f"}, - {file = "pydantic_core-2.6.3-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:692b4ff5c4e828a38716cfa92667661a39886e71136c97b7dac26edef18767f7"}, - {file = "pydantic_core-2.6.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:f1a5d8f18877474c80b7711d870db0eeef9442691fcdb00adabfc97e183ee0b0"}, - {file = "pydantic_core-2.6.3-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:3796a6152c545339d3b1652183e786df648ecdf7c4f9347e1d30e6750907f5bb"}, - {file = "pydantic_core-2.6.3-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b962700962f6e7a6bd77e5f37320cabac24b4c0f76afeac05e9f93cf0c620014"}, - {file = "pydantic_core-2.6.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56ea80269077003eaa59723bac1d8bacd2cd15ae30456f2890811efc1e3d4413"}, - {file = "pydantic_core-2.6.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75c0ebbebae71ed1e385f7dfd9b74c1cff09fed24a6df43d326dd7f12339ec34"}, - {file = "pydantic_core-2.6.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:252851b38bad3bfda47b104ffd077d4f9604a10cb06fe09d020016a25107bf98"}, - {file = "pydantic_core-2.6.3-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:6656a0ae383d8cd7cc94e91de4e526407b3726049ce8d7939049cbfa426518c8"}, - {file = "pydantic_core-2.6.3-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d9140ded382a5b04a1c030b593ed9bf3088243a0a8b7fa9f071a5736498c5483"}, - {file = "pydantic_core-2.6.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d38bbcef58220f9c81e42c255ef0bf99735d8f11edef69ab0b499da77105158a"}, - {file = "pydantic_core-2.6.3-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:c9d469204abcca28926cbc28ce98f28e50e488767b084fb3fbdf21af11d3de26"}, - {file = "pydantic_core-2.6.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:48c1ed8b02ffea4d5c9c220eda27af02b8149fe58526359b3c07eb391cb353a2"}, - {file = "pydantic_core-2.6.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b2b1bfed698fa410ab81982f681f5b1996d3d994ae8073286515ac4d165c2e7"}, - {file = "pydantic_core-2.6.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf9d42a71a4d7a7c1f14f629e5c30eac451a6fc81827d2beefd57d014c006c4a"}, - {file = "pydantic_core-2.6.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4292ca56751aebbe63a84bbfc3b5717abb09b14d4b4442cc43fd7c49a1529efd"}, - {file = "pydantic_core-2.6.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7dc2ce039c7290b4ef64334ec7e6ca6494de6eecc81e21cb4f73b9b39991408c"}, - {file = "pydantic_core-2.6.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:615a31b1629e12445c0e9fc8339b41aaa6cc60bd53bf802d5fe3d2c0cda2ae8d"}, - {file = "pydantic_core-2.6.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1fa1f6312fb84e8c281f32b39affe81984ccd484da6e9d65b3d18c202c666149"}, - {file = "pydantic_core-2.6.3.tar.gz", hash = "sha256:1508f37ba9e3ddc0189e6ff4e2228bd2d3c3a4641cbe8c07177162f76ed696c7"}, + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd"}, + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093"}, + {file = "pydantic_core-2.14.5-cp310-none-win32.whl", hash = "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720"}, + {file = "pydantic_core-2.14.5-cp310-none-win_amd64.whl", hash = "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda"}, + {file = "pydantic_core-2.14.5-cp311-none-win32.whl", hash = "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651"}, + {file = "pydantic_core-2.14.5-cp311-none-win_amd64.whl", hash = "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077"}, + {file = "pydantic_core-2.14.5-cp311-none-win_arm64.whl", hash = "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d"}, + {file = "pydantic_core-2.14.5-cp312-none-win32.whl", hash = "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260"}, + {file = "pydantic_core-2.14.5-cp312-none-win_amd64.whl", hash = "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36"}, + {file = "pydantic_core-2.14.5-cp312-none-win_arm64.whl", hash = "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325"}, + {file = "pydantic_core-2.14.5-cp37-none-win32.whl", hash = "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405"}, + {file = "pydantic_core-2.14.5-cp37-none-win_amd64.whl", hash = "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124"}, + {file = "pydantic_core-2.14.5-cp38-none-win32.whl", hash = "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867"}, + {file = "pydantic_core-2.14.5-cp38-none-win_amd64.whl", hash = "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209"}, + {file = "pydantic_core-2.14.5-cp39-none-win32.whl", hash = "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6"}, + {file = "pydantic_core-2.14.5-cp39-none-win_amd64.whl", hash = "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3"}, + {file = "pydantic_core-2.14.5.tar.gz", hash = "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71"}, ] [package.dependencies] @@ -1080,17 +1081,17 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pylint" -version = "2.17.5" +version = "2.17.7" description = "python code static checker" optional = false python-versions = ">=3.7.2" files = [ - {file = "pylint-2.17.5-py3-none-any.whl", hash = "sha256:73995fb8216d3bed149c8d51bba25b2c52a8251a2c8ac846ec668ce38fab5413"}, - {file = "pylint-2.17.5.tar.gz", hash = "sha256:f7b601cbc06fef7e62a754e2b41294c2aa31f1cb659624b9a85bcba29eaf8252"}, + {file = "pylint-2.17.7-py3-none-any.whl", hash = "sha256:27a8d4c7ddc8c2f8c18aa0050148f89ffc09838142193fdbe98f172781a3ff87"}, + {file = "pylint-2.17.7.tar.gz", hash = "sha256:f4fcac7ae74cfe36bc8451e931d8438e4a476c20314b1101c458ad0f05191fad"}, ] [package.dependencies] -astroid = ">=2.15.6,<=2.17.0-dev0" +astroid = ">=2.15.8,<=2.17.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, @@ -1109,13 +1110,13 @@ testutils = ["gitpython (>3)"] [[package]] name = "pytest" -version = "7.4.2" +version = "7.4.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, - {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, ] [package.dependencies] @@ -1290,17 +1291,17 @@ files = [ [[package]] name = "setuptools" -version = "68.2.2" +version = "69.0.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, - {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, + {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, + {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, ] [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-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +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-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "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"] @@ -1338,13 +1339,13 @@ files = [ [[package]] name = "termcolor" -version = "2.3.0" +version = "2.4.0" description = "ANSI color formatting for output in terminal" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "termcolor-2.3.0-py3-none-any.whl", hash = "sha256:3afb05607b89aed0ffe25202399ee0867ad4d3cb4180d98aaf8eefa6a5f7d475"}, - {file = "termcolor-2.3.0.tar.gz", hash = "sha256:b5b08f68937f138fe92f6c089b99f1e2da0ae56c52b78bf7075fd95420fd9a5a"}, + {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, + {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, ] [package.extras] @@ -1363,13 +1364,13 @@ files = [ [[package]] name = "tomlkit" -version = "0.12.1" +version = "0.12.3" description = "Style preserving TOML library" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"}, - {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, + {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, + {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, ] [[package]] @@ -1385,13 +1386,13 @@ files = [ [[package]] name = "types-requests" -version = "2.31.0.2" +version = "2.31.0.6" description = "Typing stubs for requests" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "types-requests-2.31.0.2.tar.gz", hash = "sha256:6aa3f7faf0ea52d728bb18c0a0d1522d9bfd8c72d26ff6f61bfc3d06a411cf40"}, - {file = "types_requests-2.31.0.2-py3-none-any.whl", hash = "sha256:56d181c85b5925cbc59f4489a57e72a8b2166f18273fd8ba7b6fe0c0b986f12a"}, + {file = "types-requests-2.31.0.6.tar.gz", hash = "sha256:cd74ce3b53c461f1228a9b783929ac73a666658f223e28ed29753771477b3bd0"}, + {file = "types_requests-2.31.0.6-py3-none-any.whl", hash = "sha256:a2db9cb228a81da8348b49ad6db3f5519452dd20a9c1e1a868c83c5fe88fd1a9"}, ] [package.dependencies] @@ -1502,35 +1503,35 @@ files = [ [[package]] name = "urllib3" -version = "1.26.16" +version = "1.26.18" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-1.26.16-py2.py3-none-any.whl", hash = "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f"}, - {file = "urllib3-1.26.16.tar.gz", hash = "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"}, + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "virtualenv" -version = "20.24.5" +version = "20.25.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"}, - {file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"}, + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<4" +platformdirs = ">=3.9.1,<5" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] @@ -1538,13 +1539,13 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "wcwidth" -version = "0.2.6" +version = "0.2.12" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, - {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, + {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, + {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, ] [[package]] @@ -1627,169 +1628,180 @@ files = [ [[package]] name = "wrapt" -version = "1.15.0" +version = "1.16.0" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.6" files = [ - {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"}, - {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"}, - {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"}, - {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"}, - {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"}, - {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"}, - {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"}, - {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"}, - {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"}, - {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"}, - {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"}, - {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"}, - {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"}, - {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"}, - {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"}, - {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"}, - {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"}, - {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"}, - {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] [[package]] name = "yarl" -version = "1.9.2" +version = "1.9.3" description = "Yet another URL library" optional = false python-versions = ">=3.7" files = [ - {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82"}, - {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8"}, - {file = "yarl-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9"}, - {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560"}, - {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac"}, - {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea"}, - {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608"}, - {file = "yarl-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5"}, - {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0"}, - {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4"}, - {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095"}, - {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3"}, - {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528"}, - {file = "yarl-1.9.2-cp310-cp310-win32.whl", hash = "sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3"}, - {file = "yarl-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde"}, - {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6"}, - {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb"}, - {file = "yarl-1.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0"}, - {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2"}, - {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191"}, - {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d"}, - {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7"}, - {file = "yarl-1.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6"}, - {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8"}, - {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9"}, - {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be"}, - {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7"}, - {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a"}, - {file = "yarl-1.9.2-cp311-cp311-win32.whl", hash = "sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8"}, - {file = "yarl-1.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051"}, - {file = "yarl-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74"}, - {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367"}, - {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef"}, - {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3"}, - {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938"}, - {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc"}, - {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33"}, - {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45"}, - {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185"}, - {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04"}, - {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582"}, - {file = "yarl-1.9.2-cp37-cp37m-win32.whl", hash = "sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b"}, - {file = "yarl-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368"}, - {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac"}, - {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4"}, - {file = "yarl-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574"}, - {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb"}, - {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59"}, - {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e"}, - {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417"}, - {file = "yarl-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78"}, - {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333"}, - {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c"}, - {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5"}, - {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc"}, - {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b"}, - {file = "yarl-1.9.2-cp38-cp38-win32.whl", hash = "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7"}, - {file = "yarl-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72"}, - {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9"}, - {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8"}, - {file = "yarl-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7"}, - {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716"}, - {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a"}, - {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3"}, - {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955"}, - {file = "yarl-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1"}, - {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4"}, - {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6"}, - {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf"}, - {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3"}, - {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80"}, - {file = "yarl-1.9.2-cp39-cp39-win32.whl", hash = "sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623"}, - {file = "yarl-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18"}, - {file = "yarl-1.9.2.tar.gz", hash = "sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571"}, + {file = "yarl-1.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32435d134414e01d937cd9d6cc56e8413a8d4741dea36af5840c7750f04d16ab"}, + {file = "yarl-1.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9a5211de242754b5e612557bca701f39f8b1a9408dff73c6db623f22d20f470e"}, + {file = "yarl-1.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:525cd69eff44833b01f8ef39aa33a9cc53a99ff7f9d76a6ef6a9fb758f54d0ff"}, + {file = "yarl-1.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc94441bcf9cb8c59f51f23193316afefbf3ff858460cb47b5758bf66a14d130"}, + {file = "yarl-1.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e36021db54b8a0475805acc1d6c4bca5d9f52c3825ad29ae2d398a9d530ddb88"}, + {file = "yarl-1.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0f17d1df951336a02afc8270c03c0c6e60d1f9996fcbd43a4ce6be81de0bd9d"}, + {file = "yarl-1.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5f3faeb8100a43adf3e7925d556801d14b5816a0ac9e75e22948e787feec642"}, + {file = "yarl-1.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aed37db837ecb5962469fad448aaae0f0ee94ffce2062cf2eb9aed13328b5196"}, + {file = "yarl-1.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:721ee3fc292f0d069a04016ef2c3a25595d48c5b8ddc6029be46f6158d129c92"}, + {file = "yarl-1.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b8bc5b87a65a4e64bc83385c05145ea901b613d0d3a434d434b55511b6ab0067"}, + {file = "yarl-1.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:dd952b9c64f3b21aedd09b8fe958e4931864dba69926d8a90c90d36ac4e28c9a"}, + {file = "yarl-1.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:c405d482c320a88ab53dcbd98d6d6f32ada074f2d965d6e9bf2d823158fa97de"}, + {file = "yarl-1.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9df9a0d4c5624790a0dea2e02e3b1b3c69aed14bcb8650e19606d9df3719e87d"}, + {file = "yarl-1.9.3-cp310-cp310-win32.whl", hash = "sha256:d34c4f80956227f2686ddea5b3585e109c2733e2d4ef12eb1b8b4e84f09a2ab6"}, + {file = "yarl-1.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:cf7a4e8de7f1092829caef66fd90eaf3710bc5efd322a816d5677b7664893c93"}, + {file = "yarl-1.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d61a0ca95503867d4d627517bcfdc28a8468c3f1b0b06c626f30dd759d3999fd"}, + {file = "yarl-1.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73cc83f918b69110813a7d95024266072d987b903a623ecae673d1e71579d566"}, + {file = "yarl-1.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d81657b23e0edb84b37167e98aefb04ae16cbc5352770057893bd222cdc6e45f"}, + {file = "yarl-1.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26a1a8443091c7fbc17b84a0d9f38de34b8423b459fb853e6c8cdfab0eacf613"}, + {file = "yarl-1.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe34befb8c765b8ce562f0200afda3578f8abb159c76de3ab354c80b72244c41"}, + {file = "yarl-1.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c757f64afe53a422e45e3e399e1e3cf82b7a2f244796ce80d8ca53e16a49b9f"}, + {file = "yarl-1.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72a57b41a0920b9a220125081c1e191b88a4cdec13bf9d0649e382a822705c65"}, + {file = "yarl-1.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:632c7aeb99df718765adf58eacb9acb9cbc555e075da849c1378ef4d18bf536a"}, + {file = "yarl-1.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b0b8c06afcf2bac5a50b37f64efbde978b7f9dc88842ce9729c020dc71fae4ce"}, + {file = "yarl-1.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1d93461e2cf76c4796355494f15ffcb50a3c198cc2d601ad8d6a96219a10c363"}, + {file = "yarl-1.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:4003f380dac50328c85e85416aca6985536812c082387255c35292cb4b41707e"}, + {file = "yarl-1.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4d6d74a97e898c1c2df80339aa423234ad9ea2052f66366cef1e80448798c13d"}, + {file = "yarl-1.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b61e64b06c3640feab73fa4ff9cb64bd8182de52e5dc13038e01cfe674ebc321"}, + {file = "yarl-1.9.3-cp311-cp311-win32.whl", hash = "sha256:29beac86f33d6c7ab1d79bd0213aa7aed2d2f555386856bb3056d5fdd9dab279"}, + {file = "yarl-1.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:f7271d6bd8838c49ba8ae647fc06469137e1c161a7ef97d778b72904d9b68696"}, + {file = "yarl-1.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:dd318e6b75ca80bff0b22b302f83a8ee41c62b8ac662ddb49f67ec97e799885d"}, + {file = "yarl-1.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c4b1efb11a8acd13246ffb0bee888dd0e8eb057f8bf30112e3e21e421eb82d4a"}, + {file = "yarl-1.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c6f034386e5550b5dc8ded90b5e2ff7db21f0f5c7de37b6efc5dac046eb19c10"}, + {file = "yarl-1.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd49a908cb6d387fc26acee8b7d9fcc9bbf8e1aca890c0b2fdfd706057546080"}, + {file = "yarl-1.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa4643635f26052401750bd54db911b6342eb1a9ac3e74f0f8b58a25d61dfe41"}, + {file = "yarl-1.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e741bd48e6a417bdfbae02e088f60018286d6c141639359fb8df017a3b69415a"}, + {file = "yarl-1.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c86d0d0919952d05df880a1889a4f0aeb6868e98961c090e335671dea5c0361"}, + {file = "yarl-1.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d5434b34100b504aabae75f0622ebb85defffe7b64ad8f52b8b30ec6ef6e4b9"}, + {file = "yarl-1.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79e1df60f7c2b148722fb6cafebffe1acd95fd8b5fd77795f56247edaf326752"}, + {file = "yarl-1.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:44e91a669c43f03964f672c5a234ae0d7a4d49c9b85d1baa93dec28afa28ffbd"}, + {file = "yarl-1.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:3cfa4dbe17b2e6fca1414e9c3bcc216f6930cb18ea7646e7d0d52792ac196808"}, + {file = "yarl-1.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:88d2c3cc4b2f46d1ba73d81c51ec0e486f59cc51165ea4f789677f91a303a9a7"}, + {file = "yarl-1.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cccdc02e46d2bd7cb5f38f8cc3d9db0d24951abd082b2f242c9e9f59c0ab2af3"}, + {file = "yarl-1.9.3-cp312-cp312-win32.whl", hash = "sha256:96758e56dceb8a70f8a5cff1e452daaeff07d1cc9f11e9b0c951330f0a2396a7"}, + {file = "yarl-1.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:c4472fe53ebf541113e533971bd8c32728debc4c6d8cc177f2bff31d011ec17e"}, + {file = "yarl-1.9.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:126638ab961633f0940a06e1c9d59919003ef212a15869708dcb7305f91a6732"}, + {file = "yarl-1.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c99ddaddb2fbe04953b84d1651149a0d85214780e4d0ee824e610ab549d98d92"}, + {file = "yarl-1.9.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dab30b21bd6fb17c3f4684868c7e6a9e8468078db00f599fb1c14e324b10fca"}, + {file = "yarl-1.9.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:828235a2a169160ee73a2fcfb8a000709edf09d7511fccf203465c3d5acc59e4"}, + {file = "yarl-1.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc391e3941045fd0987c77484b2799adffd08e4b6735c4ee5f054366a2e1551d"}, + {file = "yarl-1.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51382c72dd5377861b573bd55dcf680df54cea84147c8648b15ac507fbef984d"}, + {file = "yarl-1.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:28a108cb92ce6cf867690a962372996ca332d8cda0210c5ad487fe996e76b8bb"}, + {file = "yarl-1.9.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8f18a7832ff85dfcd77871fe677b169b1bc60c021978c90c3bb14f727596e0ae"}, + {file = "yarl-1.9.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:7eaf13af79950142ab2bbb8362f8d8d935be9aaf8df1df89c86c3231e4ff238a"}, + {file = "yarl-1.9.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:66a6dbf6ca7d2db03cc61cafe1ee6be838ce0fbc97781881a22a58a7c5efef42"}, + {file = "yarl-1.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1a0a4f3aaa18580038cfa52a7183c8ffbbe7d727fe581300817efc1e96d1b0e9"}, + {file = "yarl-1.9.3-cp37-cp37m-win32.whl", hash = "sha256:946db4511b2d815979d733ac6a961f47e20a29c297be0d55b6d4b77ee4b298f6"}, + {file = "yarl-1.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:2dad8166d41ebd1f76ce107cf6a31e39801aee3844a54a90af23278b072f1ccf"}, + {file = "yarl-1.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bb72d2a94481e7dc7a0c522673db288f31849800d6ce2435317376a345728225"}, + {file = "yarl-1.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9a172c3d5447b7da1680a1a2d6ecdf6f87a319d21d52729f45ec938a7006d5d8"}, + {file = "yarl-1.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2dc72e891672343b99db6d497024bf8b985537ad6c393359dc5227ef653b2f17"}, + {file = "yarl-1.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8d51817cf4b8d545963ec65ff06c1b92e5765aa98831678d0e2240b6e9fd281"}, + {file = "yarl-1.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53ec65f7eee8655bebb1f6f1607760d123c3c115a324b443df4f916383482a67"}, + {file = "yarl-1.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cfd77e8e5cafba3fb584e0f4b935a59216f352b73d4987be3af51f43a862c403"}, + {file = "yarl-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e73db54c967eb75037c178a54445c5a4e7461b5203b27c45ef656a81787c0c1b"}, + {file = "yarl-1.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09c19e5f4404574fcfb736efecf75844ffe8610606f3fccc35a1515b8b6712c4"}, + {file = "yarl-1.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6280353940f7e5e2efaaabd686193e61351e966cc02f401761c4d87f48c89ea4"}, + {file = "yarl-1.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c25ec06e4241e162f5d1f57c370f4078797ade95c9208bd0c60f484834f09c96"}, + {file = "yarl-1.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:7217234b10c64b52cc39a8d82550342ae2e45be34f5bff02b890b8c452eb48d7"}, + {file = "yarl-1.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4ce77d289f8d40905c054b63f29851ecbfd026ef4ba5c371a158cfe6f623663e"}, + {file = "yarl-1.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5f74b015c99a5eac5ae589de27a1201418a5d9d460e89ccb3366015c6153e60a"}, + {file = "yarl-1.9.3-cp38-cp38-win32.whl", hash = "sha256:8a2538806be846ea25e90c28786136932ec385c7ff3bc1148e45125984783dc6"}, + {file = "yarl-1.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:6465d36381af057d0fab4e0f24ef0e80ba61f03fe43e6eeccbe0056e74aadc70"}, + {file = "yarl-1.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2f3c8822bc8fb4a347a192dd6a28a25d7f0ea3262e826d7d4ef9cc99cd06d07e"}, + {file = "yarl-1.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7831566595fe88ba17ea80e4b61c0eb599f84c85acaa14bf04dd90319a45b90"}, + {file = "yarl-1.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ff34cb09a332832d1cf38acd0f604c068665192c6107a439a92abfd8acf90fe2"}, + {file = "yarl-1.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe8080b4f25dfc44a86bedd14bc4f9d469dfc6456e6f3c5d9077e81a5fedfba7"}, + {file = "yarl-1.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8535e111a064f3bdd94c0ed443105934d6f005adad68dd13ce50a488a0ad1bf3"}, + {file = "yarl-1.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d155a092bf0ebf4a9f6f3b7a650dc5d9a5bbb585ef83a52ed36ba46f55cc39d"}, + {file = "yarl-1.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:778df71c8d0c8c9f1b378624b26431ca80041660d7be7c3f724b2c7a6e65d0d6"}, + {file = "yarl-1.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9f9cafaf031c34d95c1528c16b2fa07b710e6056b3c4e2e34e9317072da5d1a"}, + {file = "yarl-1.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ca6b66f69e30f6e180d52f14d91ac854b8119553b524e0e28d5291a724f0f423"}, + {file = "yarl-1.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0e7e83f31e23c5d00ff618045ddc5e916f9e613d33c5a5823bc0b0a0feb522f"}, + {file = "yarl-1.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:af52725c7c39b0ee655befbbab5b9a1b209e01bb39128dce0db226a10014aacc"}, + {file = "yarl-1.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0ab5baaea8450f4a3e241ef17e3d129b2143e38a685036b075976b9c415ea3eb"}, + {file = "yarl-1.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d350388ba1129bc867c6af1cd17da2b197dff0d2801036d2d7d83c2d771a682"}, + {file = "yarl-1.9.3-cp39-cp39-win32.whl", hash = "sha256:e2a16ef5fa2382af83bef4a18c1b3bcb4284c4732906aa69422cf09df9c59f1f"}, + {file = "yarl-1.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:d92d897cb4b4bf915fbeb5e604c7911021a8456f0964f3b8ebbe7f9188b9eabb"}, + {file = "yarl-1.9.3-py3-none-any.whl", hash = "sha256:271d63396460b6607b588555ea27a1a02b717ca2e3f2cf53bdde4013d7790929"}, + {file = "yarl-1.9.3.tar.gz", hash = "sha256:4a14907b597ec55740f63e52d7fee0e9ee09d5b9d57a4f399a7423268e457b57"}, ] [package.dependencies] @@ -1799,4 +1811,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.8.0, <4.0" -content-hash = "f4b42bf68f4d232c8a6e551da3f9f3432627b8b65252e6ee0b04dd803af0179b" +content-hash = "fe7537892ee25f88f03501e2101202a3e99dc435ad83d1729409c2d9c9f801f3" diff --git a/pyproject.toml b/pyproject.toml index 9bc2528..9b9fe63 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,9 +16,9 @@ packages = [ [tool.poetry.dependencies] python = ">=3.8.0, <4.0" -pydantic = "^2.0" +pydantic = "^2.5" appdirs = "^1.4.4" -gql = {extras = ["requests", "websockets"], version = "^3.3.0"} +gql = { extras = ["requests", "websockets"], version = "^3.3.0" } ujson = "^5.3.0" Deprecated = "^1.2.13" stringcase = "^1.2.0" diff --git a/src/specklepy/objects/base.py b/src/specklepy/objects/base.py index e03e32d..19f95ed 100644 --- a/src/specklepy/objects/base.py +++ b/src/specklepy/objects/base.py @@ -168,6 +168,7 @@ class _RegisteringBase: initialization. This is reused to register each subclassing type into a class level dictionary. """ + print(cls, super()) cls._speckle_type_override = speckle_type cls.speckle_type = cls._determine_speckle_type() if cls._full_name() in cls._type_registry: @@ -188,7 +189,7 @@ class _RegisteringBase: cls._detachable = cls._detachable.union(detachable) if serialize_ignore: cls._serialize_ignore = cls._serialize_ignore.union(serialize_ignore) - super().__init_subclass__(**kwargs) + return super().__init_subclass__() # T = TypeVar("T") From f65173581a056f50b5423ac4d6d11b1abd619bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Tue, 5 Dec 2023 16:07:23 +0100 Subject: [PATCH 46/54] fix: pre-commit config --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 83f4105..8f92e8f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,11 +6,11 @@ repos: - repo: https://github.com/commitizen-tools/commitizen hooks: - - id: commitizen - - id: commitizen-branch - stages: - - push - rev: 3.12.0 + - id: commitizen + - id: commitizen-branch + stages: + - push + rev: v3.13.0 - repo: https://github.com/pycqa/isort rev: 5.12.0 From 1eca211c963e6e7976db89d2db5fc15988b92cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Wed, 6 Dec 2023 11:50:07 +0100 Subject: [PATCH 47/54] fix: remove debug print statement --- src/specklepy/objects/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/specklepy/objects/base.py b/src/specklepy/objects/base.py index 19f95ed..52c4c1f 100644 --- a/src/specklepy/objects/base.py +++ b/src/specklepy/objects/base.py @@ -168,7 +168,6 @@ class _RegisteringBase: initialization. This is reused to register each subclassing type into a class level dictionary. """ - print(cls, super()) cls._speckle_type_override = speckle_type cls.speckle_type = cls._determine_speckle_type() if cls._full_name() in cls._type_registry: @@ -189,6 +188,7 @@ class _RegisteringBase: cls._detachable = cls._detachable.union(detachable) if serialize_ignore: cls._serialize_ignore = cls._serialize_ignore.union(serialize_ignore) + # we know, that the super here is object, that takes no args on init subclass return super().__init_subclass__() From 4db0fa69fafe98b86a96f5bbf33544efa43f285c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= <57442769+gjedlicska@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:15:07 +0100 Subject: [PATCH 48/54] Update client.py --- src/specklepy/api/client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/specklepy/api/client.py b/src/specklepy/api/client.py index 8abb0b6..ef4a4c7 100644 --- a/src/specklepy/api/client.py +++ b/src/specklepy/api/client.py @@ -50,10 +50,11 @@ class SpeckleClient(CoreSpeckleClient): DEFAULT_HOST = "speckle.xyz" USE_SSL = True - def __init__(self, host: str = DEFAULT_HOST, use_ssl: bool = USE_SSL) -> None: + def __init__(self, host: str = DEFAULT_HOST, use_ssl: bool = USE_SSL, verify_certificate: bool = True) -> None: super().__init__( host=host, use_ssl=use_ssl, + verify_certificate: bool = VERIFY_CERTIFICATE, ) self.account = Account() From 558b25b1d1d88bbb0706dba37ed2565a5fff238f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Mon, 11 Dec 2023 17:30:08 +0100 Subject: [PATCH 49/54] feat: read automation function inputs from file --- .pre-commit-config.yaml | 10 ++-- pyproject.toml | 4 +- src/speckle_automate/runner.py | 91 ++++++++++++++++++++++++---------- 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 83f4105..8f92e8f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,11 +6,11 @@ repos: - repo: https://github.com/commitizen-tools/commitizen hooks: - - id: commitizen - - id: commitizen-branch - stages: - - push - rev: 3.12.0 + - id: commitizen + - id: commitizen-branch + stages: + - push + rev: v3.13.0 - repo: https://github.com/pycqa/isort rev: 5.12.0 diff --git a/pyproject.toml b/pyproject.toml index 9bc2528..2633da6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "specklepy" -version = "2.17.8" +version = "2.17.14" description = "The Python SDK for Speckle 2.0" readme = "README.md" authors = ["Speckle Systems "] @@ -18,7 +18,7 @@ packages = [ python = ">=3.8.0, <4.0" pydantic = "^2.0" appdirs = "^1.4.4" -gql = {extras = ["requests", "websockets"], version = "^3.3.0"} +gql = { extras = ["requests", "websockets"], version = "^3.3.0" } ujson = "^5.3.0" Deprecated = "^1.2.13" stringcase = "^1.2.0" diff --git a/src/speckle_automate/runner.py b/src/speckle_automate/runner.py index e019655..d85b216 100644 --- a/src/speckle_automate/runner.py +++ b/src/speckle_automate/runner.py @@ -4,14 +4,16 @@ Provides mechanisms to execute any function, that conforms to the AutomateFunction "interface" """ import json -import os import sys import traceback from pathlib import Path -from typing import Callable, Optional, TypeVar, Union, overload +from typing import Callable, Optional, Tuple, TypeVar, Union, overload + +from pydantic import create_model +from pydantic.json_schema import GenerateJsonSchema from speckle_automate.automation_context import AutomationContext -from speckle_automate.schema import AutomateBase, AutomationStatus +from speckle_automate.schema import AutomateBase, AutomationRunData, AutomationStatus T = TypeVar("T", bound=AutomateBase) @@ -19,6 +21,41 @@ AutomateFunction = Callable[[AutomationContext, T], None] AutomateFunctionWithoutInputs = Callable[[AutomationContext], None] +def _read_input_data(inputs_location: str) -> str: + input_path = Path(inputs_location) + if not input_path.exists(): + raise ValueError(f"Cannot find the function inputs file at {input_path}") + + return input_path.read_text() + + +def _parse_input_data( + input_location: str, input_schema: Optional[type[T]] +) -> Tuple[AutomationRunData, Optional[T], str]: + input_json_string = _read_input_data(input_location) + + class FunctionRunData(AutomateBase): + speckle_token: str + automation_run_data: AutomationRunData + function_inputs: None = None + + parser_model = FunctionRunData + + if input_schema: + parser_model = create_model( + "FunctionRunDataWithInputs", + function_inputs=(input_schema, ...), + __base__=FunctionRunData, + ) + + input_data = parser_model.model_validate_json(input_json_string) + return ( + input_data.automation_run_data, + input_data.function_inputs, + input_data.speckle_token, + ) + + @overload def execute_automate_function( automate_function: AutomateFunction[T], @@ -32,6 +69,13 @@ def execute_automate_function(automate_function: AutomateFunctionWithoutInputs) ... +class AutomateGenerateJsonSchema(GenerateJsonSchema): + def generate(self, schema, mode="validation"): + json_schema = super().generate(schema, mode=mode) + json_schema["$schema"] = self.schema_dialect + return json_schema + + def execute_automate_function( automate_function: Union[AutomateFunction[T], AutomateFunctionWithoutInputs], input_schema: Optional[type[T]] = None, @@ -40,49 +84,44 @@ def execute_automate_function( # first arg is the python file name, we do not need that args = sys.argv[1:] - if len(args) < 2: - raise ValueError("too few arguments specified need minimum 2") - - if len(args) > 4: - raise ValueError("too many arguments specified, max supported is 4") + if len(args) != 2: + raise ValueError("Incorrect number of arguments specified need 2") # we rely on a command name convention to decide what to do. # this is here, so that the function authors do not see any of this - command = args[0] + command, argument = args if command == "generate_schema": - path = Path(args[1]) + path = Path(argument) schema = json.dumps( - input_schema.model_json_schema(by_alias=True) if input_schema else {} + input_schema.model_json_schema( + by_alias=True, schema_generator=AutomateGenerateJsonSchema + ) + if input_schema + else {} ) path.write_text(schema) elif command == "run": - automation_run_data = args[1] - function_inputs = args[2] + automation_run_data, function_inputs, speckle_token = _parse_input_data( + argument, input_schema + ) - speckle_token = os.environ.get("SPECKLE_TOKEN", None) - if not speckle_token and len(args) != 4: - raise ValueError("Cannot get speckle token from arguments or environment") - - speckle_token = speckle_token if speckle_token else args[3] automation_context = AutomationContext.initialize( automation_run_data, speckle_token ) - inputs = ( - input_schema.model_validate_json(function_inputs) - if input_schema - else input_schema - ) - - if inputs: + if function_inputs: automation_context = run_function( automation_context, automate_function, # type: ignore - inputs, + function_inputs, # type: ignore ) + else: + automation_context = AutomationContext.initialize( + automation_run_data, speckle_token + ) automation_context = run_function( automation_context, automate_function, # type: ignore From deb8ad50c56351897d75acd9329378425049c854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Mon, 11 Dec 2023 17:34:26 +0100 Subject: [PATCH 50/54] fix: client certificate verification --- .pre-commit-config.yaml | 10 +++++----- src/specklepy/api/client.py | 9 +++++++-- src/specklepy/core/api/client.py | 3 +-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 83f4105..8f92e8f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,11 +6,11 @@ repos: - repo: https://github.com/commitizen-tools/commitizen hooks: - - id: commitizen - - id: commitizen-branch - stages: - - push - rev: 3.12.0 + - id: commitizen + - id: commitizen-branch + stages: + - push + rev: v3.13.0 - repo: https://github.com/pycqa/isort rev: 5.12.0 diff --git a/src/specklepy/api/client.py b/src/specklepy/api/client.py index ef4a4c7..51c7b79 100644 --- a/src/specklepy/api/client.py +++ b/src/specklepy/api/client.py @@ -50,11 +50,16 @@ class SpeckleClient(CoreSpeckleClient): DEFAULT_HOST = "speckle.xyz" USE_SSL = True - def __init__(self, host: str = DEFAULT_HOST, use_ssl: bool = USE_SSL, verify_certificate: bool = True) -> None: + def __init__( + self, + host: str = DEFAULT_HOST, + use_ssl: bool = USE_SSL, + verify_certificate: bool = True, + ) -> None: super().__init__( host=host, use_ssl=use_ssl, - verify_certificate: bool = VERIFY_CERTIFICATE, + verify_certificate=verify_certificate, ) self.account = Account() diff --git a/src/specklepy/core/api/client.py b/src/specklepy/core/api/client.py index b7c70d0..4e4d9d7 100644 --- a/src/specklepy/core/api/client.py +++ b/src/specklepy/core/api/client.py @@ -58,13 +58,12 @@ class SpeckleClient: DEFAULT_HOST = "speckle.xyz" USE_SSL = True - VERIFY_CERTIFICATE = True def __init__( self, host: str = DEFAULT_HOST, use_ssl: bool = USE_SSL, - verify_certificate: bool = VERIFY_CERTIFICATE, + verify_certificate: bool = True, ) -> None: ws_protocol = "ws" http_protocol = "http" From d716db251fd93e3161b92330e7355b921460c1e1 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Mon, 5 Feb 2024 10:40:13 +0000 Subject: [PATCH 51/54] add frontend2 property to ServerInfo --- src/specklepy/core/api/models.py | 1 + src/specklepy/core/api/resources/server.py | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/specklepy/core/api/models.py b/src/specklepy/core/api/models.py index 273e55a..9559d4f 100644 --- a/src/specklepy/core/api/models.py +++ b/src/specklepy/core/api/models.py @@ -196,3 +196,4 @@ class ServerInfo(BaseModel): scopes: Optional[List[dict]] = None authStrategies: Optional[List[dict]] = None version: Optional[str] = None + frontend2: Optional[bool] = None diff --git a/src/specklepy/core/api/resources/server.py b/src/specklepy/core/api/resources/server.py index 92e57ed..c57c588 100644 --- a/src/specklepy/core/api/resources/server.py +++ b/src/specklepy/core/api/resources/server.py @@ -1,4 +1,6 @@ import re +import requests + from typing import Any, Dict, List, Tuple from gql import gql @@ -56,9 +58,21 @@ class Resource(ResourceBase): """ ) - return self.make_request( + server_info = self.make_request( query=query, return_type="serverInfo", schema=ServerInfo ) + if isinstance(server_info, ServerInfo) and isinstance( + server_info.canonicalUrl, str + ): + r = requests.get( + server_info.canonicalUrl, headers={"User-Agent": "specklepy SDK"} + ) + if "x-speckle-frontend-2" in r.headers: + server_info.frontend2 = True + else: + server_info.frontend2 = False + + return server_info def version(self) -> Tuple[Any, ...]: """Get the server version From b374bfefd0a3e8e32924c83257160569d726696a Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Mon, 5 Feb 2024 11:17:51 +0000 Subject: [PATCH 52/54] reorder import --- src/specklepy/core/api/resources/server.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/specklepy/core/api/resources/server.py b/src/specklepy/core/api/resources/server.py index c57c588..4f869ce 100644 --- a/src/specklepy/core/api/resources/server.py +++ b/src/specklepy/core/api/resources/server.py @@ -1,8 +1,7 @@ import re -import requests - from typing import Any, Dict, List, Tuple +import requests from gql import gql from specklepy.core.api.models import ServerInfo From c7cd2f3e91369f766f939988ecc3638cc0b134a7 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Mon, 5 Feb 2024 11:23:22 +0000 Subject: [PATCH 53/54] test --- tests/intergration/test_server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/intergration/test_server.py b/tests/intergration/test_server.py index 884ef33..37ac1ab 100644 --- a/tests/intergration/test_server.py +++ b/tests/intergration/test_server.py @@ -18,6 +18,7 @@ class TestServer: server = client.server.get() assert isinstance(server, ServerInfo) + assert isinstance(server.frontend2, bool) def test_server_version(self, client: SpeckleClient): version = client.server.version() From a0ca10ad20e7ef2908730c900eb531fa64c6f179 Mon Sep 17 00:00:00 2001 From: KatKatKateryna <89912278+KatKatKateryna@users.noreply.github.com> Date: Sat, 10 Feb 2024 01:35:20 +0800 Subject: [PATCH 54/54] add to_string; add cases for object url in fe2 (#327) * add to_string; add cases for object url in fe2 * cover exceptions * add federated model exception, reorder conditions * formatting * reformatting * update black formatter * resolving dependencies --- poetry.lock | 63 ++++++++++----- pyproject.toml | 2 +- src/specklepy/core/api/wrapper.py | 125 +++++++++++++++++++++-------- tests/intergration/test_wrapper.py | 66 +++++++++++++++ 4 files changed, 203 insertions(+), 53 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8beb5cd..1f383ff 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "annotated-types" @@ -129,32 +129,39 @@ files = [ [[package]] name = "black" -version = "22.12.0" +version = "23.11.0" description = "The uncompromising code formatter." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, - {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, - {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, - {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, - {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, - {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, - {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, - {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, - {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, - {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, - {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, - {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, + {file = "black-23.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911"}, + {file = "black-23.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f"}, + {file = "black-23.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394"}, + {file = "black-23.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f"}, + {file = "black-23.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479"}, + {file = "black-23.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244"}, + {file = "black-23.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221"}, + {file = "black-23.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5"}, + {file = "black-23.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187"}, + {file = "black-23.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6"}, + {file = "black-23.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b"}, + {file = "black-23.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142"}, + {file = "black-23.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055"}, + {file = "black-23.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4"}, + {file = "black-23.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06"}, + {file = "black-23.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07"}, + {file = "black-23.11.0-py3-none-any.whl", hash = "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e"}, + {file = "black-23.11.0.tar.gz", hash = "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05"}, ] [package.dependencies] click = ">=8.0.0" mypy-extensions = ">=0.4.3" +packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -665,6 +672,16 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -1175,6 +1192,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1182,8 +1200,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {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_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"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1200,6 +1225,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1207,6 +1233,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1811,4 +1838,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.8.0, <4.0" -content-hash = "fe7537892ee25f88f03501e2101202a3e99dc435ad83d1729409c2d9c9f801f3" +content-hash = "71048c951f0fa82db1c725f10c863fcc60bb7e85d0f26bc4fae3a63577729c13" diff --git a/pyproject.toml b/pyproject.toml index 24b48f6..2d8dc90 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ attrs = "^23.1.0" httpx = "^0.25.0" [tool.poetry.group.dev.dependencies] -black = "^22.8.0" +black = "23.11.0" isort = "^5.7.0" pytest = "^7.1.3" pytest-ordering = "^0.6" diff --git a/src/specklepy/core/api/wrapper.py b/src/specklepy/core/api/wrapper.py index 8a46608..21681f2 100644 --- a/src/specklepy/core/api/wrapper.py +++ b/src/specklepy/core/api/wrapper.py @@ -1,4 +1,4 @@ -from urllib.parse import unquote, urlparse +from urllib.parse import quote, unquote, urlparse from warnings import warn from gql import gql @@ -47,6 +47,7 @@ class StreamWrapper: commit_id: str = None object_id: str = None branch_name: str = None + model_id: str = None _client: SpeckleClient = None _account: Account = None @@ -86,45 +87,58 @@ class StreamWrapper: # check for fe2 URL if "/projects/" in parsed.path: use_fe2 = True + key_stream = "project" else: use_fe2 = False + key_stream = "stream" while segments: segment = segments.pop(0) - if segments and ( - (use_fe2 is False and segment.lower() == "streams") - or (use_fe2 is True and segment.lower() == "projects") - ): - self.stream_id = segments.pop(0) - elif segments and segment.lower() == "commits": - self.commit_id = segments.pop(0) - elif segments and ( - (use_fe2 is False and segment.lower() == "branches") - or (use_fe2 is True and segment.lower() == "models") - ): - self.branch_name = unquote(segments.pop(0)) - elif segments and segment.lower() == "objects": - self.object_id = segments.pop(0) - elif segment.lower() == "globals": - self.branch_name = "globals" - if segments: + + if use_fe2 is False: + if segments and segment.lower() == "streams": + self.stream_id = segments.pop(0) + elif segments and segment.lower() == "commits": self.commit_id = segments.pop(0) - else: - raise SpeckleException( - f"Cannot parse {url} into a stream wrapper class - invalid URL" - " provided." - ) + elif segments and segment.lower() == "branches": + self.branch_name = unquote(segments.pop(0)) + elif segments and segment.lower() == "objects": + self.object_id = segments.pop(0) + elif segment.lower() == "globals": + self.branch_name = "globals" + if segments: + self.commit_id = segments.pop(0) + else: + raise SpeckleException( + f"Cannot parse {url} into a stream wrapper class - invalid URL" + " provided." + ) + elif segments and use_fe2 is True: + if segment.lower() == "projects": + self.stream_id = segments.pop(0) + elif segment.lower() == "models": + next_segment = segments.pop(0) + if "," in next_segment: + raise SpeckleException("Multi-model urls are not supported yet") + elif unquote(next_segment).startswith("$"): + raise SpeckleException( + "Federation model urls are not supported" + ) + elif len(next_segment) == 32: + self.object_id = next_segment + else: + self.branch_name = unquote(next_segment).split("@")[0] + if "@" in unquote(next_segment): + self.commit_id = unquote(next_segment).split("@")[1] + + else: + raise SpeckleException( + f"Cannot parse {url} into a stream wrapper class - invalid URL" + " provided." + ) if use_fe2 is True and self.branch_name is not None: - if "," in self.branch_name: - raise SpeckleException("Multi-model urls are not supported yet") - - if "@" in self.branch_name: - model_id = self.branch_name.split("@")[0] - self.commit_id = self.branch_name.split("@")[1] - else: - model_id = self.branch_name - + self.model_id = self.branch_name # get branch name query = gql( """ @@ -139,7 +153,7 @@ class StreamWrapper: """ ) self._client = self.get_client() - params = {"project_id": self.stream_id, "model_id": model_id} + params = {"project_id": self.stream_id, "model_id": self.model_id} project = self._client.httpclient.execute(query, params) try: @@ -149,7 +163,7 @@ class StreamWrapper: if not self.stream_id: raise SpeckleException( - f"Cannot parse {url} into a stream wrapper class - no stream id found." + f"Cannot parse {url} into a stream wrapper class - no {key_stream} id found." ) @property @@ -230,3 +244,46 @@ class StreamWrapper: if not self._account or not self._account.token: self.get_account(token) return ServerTransport(self.stream_id, account=self._account) + + def to_string(self) -> str: + """ + Constructs a URL depending on the StreamWrapper type and FE version. + """ + use_fe2 = False + key_streams = "/streams/" + key_branches = "/branches/" + if isinstance(self.branch_name, str): + value_branch = quote(self.branch_name) + if self.branch_name == "globals": + key_branches = "/" + key_commits = "/commits/" + if isinstance(self.commit_id, str) and self.branch_name == "globals": + key_commits = "/globals/" + key_objects = "/objects/" + + if "/projects/" in self.stream_url: + use_fe2 = True + key_streams = "/projects/" + key_branches = "/models/" + value_branch = self.model_id + key_commits = "@" + key_objects = "/models/" + + wrapper_type = self.type + if use_fe2 is False or (use_fe2 is True and not self.model_id): + base_url = f"{self.server_url}{key_streams}{self.stream_id}" + else: # fe2 is True and model_id available + base_url = f"{self.server_url}{key_streams}{self.stream_id}{key_branches}{value_branch}" + + if wrapper_type == "object": + return f"{base_url}{key_objects}{self.object_id}" + elif wrapper_type == "commit": + return f"{base_url}{key_commits}{self.commit_id}" + elif wrapper_type == "branch": + return f"{self.server_url}{key_streams}{self.stream_id}{key_branches}{value_branch}" + elif wrapper_type == "stream": + return f"{self.server_url}{key_streams}{self.stream_id}" + else: + raise SpeckleException( + f"Cannot parse StreamWrapper of type '{wrapper_type}'" + ) diff --git a/tests/intergration/test_wrapper.py b/tests/intergration/test_wrapper.py index 5ab0bb7..f53ba02 100644 --- a/tests/intergration/test_wrapper.py +++ b/tests/intergration/test_wrapper.py @@ -2,11 +2,13 @@ import json import tempfile from pathlib import Path from typing import Iterable +from urllib.parse import unquote import pytest from specklepy.api.wrapper import StreamWrapper from specklepy.core.helpers import speckle_path_provider +from specklepy.logging.exceptions import SpeckleException @pytest.fixture(scope="module", autouse=True) @@ -29,6 +31,22 @@ def user_path() -> Iterable[Path]: speckle_path_provider.override_application_data_path(None) +def test_parse_empty(): + try: + StreamWrapper("https://testing.speckle.dev/streams") + assert False + except SpeckleException: + assert True + + +def test_parse_empty_fe2(): + try: + StreamWrapper("https://latest.speckle.systems/projects") + assert False + except SpeckleException: + assert True + + def test_parse_stream(): wrap = StreamWrapper("https://testing.speckle.dev/streams/a75ab4f10f") assert wrap.type == "stream" @@ -142,8 +160,56 @@ def test_parse_model(): assert wrap.type == "branch" +def test_parse_federated_model(): + try: + StreamWrapper("https://latest.speckle.systems/projects/843d07eb10/models/$main") + assert False + except SpeckleException: + assert True + + +def test_parse_multi_model(): + try: + StreamWrapper( + "https://latest.speckle.systems/projects/2099ac4b5f/models/1870f279e3,a9cfdddc79" + ) + assert False + except SpeckleException: + assert True + + +def test_parse_object_fe2(): + wrap = StreamWrapper( + "https://latest.speckle.systems/projects/24c3741255/models/b48d1b10f5a732f4ca4144286391282c" + ) + assert wrap.type == "object" + + def test_parse_version(): wrap = StreamWrapper( "https://latest.speckle.systems/projects/843d07eb10/models/4e7345c838@c42d5cbac1" ) + wrap_quoted = StreamWrapper( + "https://latest.speckle.systems/projects/843d07eb10/models/4e7345c838%40c42d5cbac1" + ) assert wrap.type == "commit" + assert wrap_quoted.type == "commit" + + +def test_to_string(): + urls = [ + "https://testing.speckle.dev/streams/a75ab4f10f", + "https://testing.speckle.dev/streams/4c3ce1459c/branches/%F0%9F%8D%95%E2%AC%85%F0%9F%8C%9F%20you%20wat%3F", + "https://testing.speckle.dev/streams/0c6ad366c4/globals", + "https://testing.speckle.dev/streams/0c6ad366c4/globals/abd3787893", + "https://testing.speckle.dev/streams/4c3ce1459c/commits/8b9b831792", + "https://testing.speckle.dev/streams/a75ab4f10f/objects/5530363e6d51c904903dafc3ea1d2ec6", + "https://latest.speckle.systems/projects/843d07eb10", + "https://latest.speckle.systems/projects/843d07eb10/models/4e7345c838", + "https://latest.speckle.systems/projects/843d07eb10/models/4e7345c838@c42d5cbac1", + "https://latest.speckle.systems/projects/843d07eb10/models/4e7345c838%40c42d5cbac1", + "https://latest.speckle.systems/projects/24c3741255/models/b48d1b10f5a732f4ca4144286391282c", + ] + for url in urls: + wrap = StreamWrapper(url) + assert unquote(wrap.to_string()) == unquote(url)