Addition of logic from Beam vs Duct WIP function
build and deploy Speckle functions / publish-automate-function-version (push) Has been cancelled

This commit is contained in:
Jonathon Broughton
2023-11-12 14:28:24 +00:00
parent 78ceb3b49a
commit e2e6711896
17 changed files with 1298 additions and 131 deletions
+11
View File
@@ -0,0 +1,11 @@
*.pyc
build/
dist/
*.egg-info/
.cache/
*.log
.ruff_cache/
.venv/
.env/
.git/
Dockerfile copy*
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v3.4.0
- uses: actions/setup-python@v4
with:
python-version: '3.11'
python-version: '3.10'
- name: Install and configure Poetry
uses: snok/install-poetry@v1
with:
+4 -47
View File
@@ -175,7 +175,7 @@ ARG BRANCH=main
ARG NUM_CORES=10
# Clone a git repository
RUN /bin/sh -c "git clone --single-branch -b $BRANCH https://github.com/nuvolos-cloud/PyMesh.git"
RUN /bin/sh -c "git clone --single-branch --depth 1 -b $BRANCH https://github.com/nuvolos-cloud/PyMesh.git"
# Set environment variables
ENV PYMESH_PATH=/root/PyMesh
@@ -199,69 +199,28 @@ RUN echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" >>
# Build and install PyMesh
WORKDIR /root/PyMesh
# RUN git submodule update --init
RUN git clone --depth 1 https://github.com/PyMesh/cgal.git $PYMESH_PATH/third_party/cgal
# RUN git submodule update --init third_party/libigl
RUN git clone --depth 1 https://github.com/PyMesh/libigl.git $PYMESH_PATH/third_party/libigl
# RUN git submodule update --init third_party/carve
RUN git clone --depth 1 https://github.com/PyMesh/carve.git $PYMESH_PATH/third_party/carve
# RUN git submodule update --init third_party/cork
RUN git clone --depth 1 https://github.com/PyMesh/cork.git $PYMESH_PATH/third_party/cork
# RUN git submodule update --init third_party/tetgen
RUN git clone --depth 1 https://github.com/PyMesh/tetgen.git $PYMESH_PATH/third_party/tetgen
RUN git submodule update --init third_party/triangle
# RUN git clone --depth 1 https://github.com/PyMesh/triangle.git $PYMESH_PATH/third_party/triangle
# RUN git submodule update --init third_party/qhull
RUN git clone --depth 1 https://github.com/PyMesh/qhull.git $PYMESH_PATH/third_party/qhull
# RUN git submodule update --init third_party/Clipper
RUN git clone --depth 1 https://github.com/PyMesh/Clipper.git $PYMESH_PATH/third_party/Clipper
# RUN git submodule update --init third_party/eigen
RUN git clone --depth 1 https://github.com/PyMesh/eigen.git $PYMESH_PATH/third_party/eigen
RUN git submodule update --init third_party/quartet
# RUN git clone --depth 1 https://github.com/PyMesh/quartet.git $PYMESH_PATH/third_party/quartet
# RUN git submodule update --init third_party/pybind11
RUN git clone --depth 1 https://github.com/PyMesh/pybind11.git $PYMESH_PATH/third_party/pybind11
# RUN git submodule update --init third_party/geogram
RUN git clone --depth 1 https://github.com/PyMesh/geogram.git $PYMESH_PATH/third_party/geogram
# RUN git submodule update --init third_party/draco
RUN git clone --depth 1 https://github.com/PyMesh/draco.git $PYMESH_PATH/third_party/draco
# RUN git submodule update --init third_party/TetWild
RUN git clone --depth 1 https://github.com/PyMesh/TetWild.git $PYMESH_PATH/third_party/TetWild
# RUN git submodule update --init third_party/WindingNumber
RUN git clone --depth 1 https://github.com/PyMesh/WindingNumber.git $PYMESH_PATH/third_party/WindingNumber
# RUN git submodule update --init third_party/tbb
RUN git clone --depth 1 https://github.com/PyMesh/tbb.git $PYMESH_PATH/third_party/tbb
# RUN git submodule update --init third_party/jigsaw
RUN git clone --depth 1 https://github.com/PyMesh/jigsaw.git $PYMESH_PATH/third_party/jigsaw
RUN git submodule update --init third_party/mmg
# RUN git clone --depth 1 https://github.com/PyMesh/mmg.git $PYMESH_PATH/third_party/mmg
# RUN git submodule update --init third_party/fmt
RUN git clone --depth 1 https://github.com/fmtlib/fmt.git $PYMESH_PATH/third_party/fmt
# RUN git submodule update --init third_party/spdlog
RUN git clone --depth 1 https://github.com/gabime/spdlog.git $PYMESH_PATH/third_party/spdlog
RUN git submodule update --init third_party/triangle
RUN git submodule update --init third_party/quartet
RUN git submodule update --init third_party/mmg
RUN git submodule update --init third_party/json
# RUN git clone --depth 1 https://github.com/nlohmann/json.git $PYMESH_PATH/third_party/json
RUN pip install -r $PYMESH_PATH/python/requirements.txt
RUN ./setup.py bdist_wheel
@@ -274,8 +233,6 @@ RUN pip install dist/pymesh2*.whl
WORKDIR /root/PyMesh/third_party
RUN /bin/sh -c "python ./build.py mmg && python ./build.py tetgen"
# We install poetry to generate a list of dependencies which will be required by our application
RUN pip install poetry
View File
+107
View File
@@ -0,0 +1,107 @@
from typing import Tuple, Optional
import numpy as np
import trimesh
from specklepy.objects import Base
from specklepy.objects.geometry import Mesh as SpeckleMesh
from specklepy.objects.other import Transform
from trimesh import Trimesh
class Element:
def __init__(self, id, meshes):
"""
Initialize an Element object with an ID and a list of meshes.
Args:
id (str): The ID of the Element.
meshes (List[Trimesh]): List of trimesh Mesh objects.
"""
self.id = id
self.meshes = meshes
def speckle_transform_to_trimesh_matrix(transform: Transform) -> np.ndarray:
"""
Convert the Speckle Transform matrix to a NumPy array format suitable for trimesh.
Returns:
np.ndarray: 4x4 transformation matrix in NumPy array format.
"""
return np.array(transform.value).reshape(4, 4)
def speckle_to_element(
base_with_transforms: Tuple[Base, str, Optional[Transform]]
) -> Element:
"""
Convert a SpecklePy Base object and its associated Transform to an Element object.
Args:
base_with_transforms (tuple): Contains a SpecklePy Base object and its
associated Transform object.
Returns:
Element: The resulting Element object.
"""
# Unpack the tuple to get the base, speckle ID, and transform.
base, speckle_id, transform = base_with_transforms
# To convert the Base object to a trimesh Mesh, use the displayValue property.
# This property provides the display mesh, expected to be an iterable of
# SpecklePy Mesh objects. However, legacy objects might be a single mesh.
display_value = base.displayValue
if isinstance(display_value, SpeckleMesh):
display_value = [display_value]
if isinstance(display_value, list):
# Initialize an Element with an empty list of meshes.
element = Element(speckle_id, meshes=[])
for mesh in display_value:
if mesh:
# Convert the SpecklePy Mesh to a trimesh Mesh.
t_mesh = speckle_to_trimesh(mesh)
if not isinstance(t_mesh, Trimesh):
continue
# If there's a transform, apply it to the trimesh Mesh.
if transform is not None:
trimesh_matrix = speckle_transform_to_trimesh_matrix(transform)
t_mesh.apply_transform(trimesh_matrix)
# Append the trimesh Mesh to the Element's list of meshes.
element.meshes.append(t_mesh)
return element
def speckle_to_trimesh(speckle_mesh: SpeckleMesh) -> Trimesh:
"""
Convert a SpecklePy Mesh to a trimesh Mesh object.
Args:
speckle_mesh: The SpecklePy Mesh to convert.
Returns:
trimesh.Trimesh: The resulting trimesh Mesh object.
"""
# Convert the list of vertices to a numpy array. Reshape it to
# (num_vertices, 3) to fit the trimesh format.
vertices_array = np.array(speckle_mesh.vertices).reshape((-1, 3))
# Faces are expected to be triangular. Reshape the faces list accordingly.
# Convert the faces list to a numpy array
faces_array_raw = np.array(speckle_mesh.faces)
# Remove the leading 3s by skipping every 4th value
faces_cleaned = np.delete(faces_array_raw, np.arange(0, faces_array_raw.size, 4))
# Reshape the array into (-1, 3) shape
faces_array = faces_cleaned.reshape((-1, 3))
# Return a new trimesh object using the reshaped vertices and faces.
return trimesh.Trimesh(vertices=vertices_array, faces=faces_array)
+16
View File
@@ -0,0 +1,16 @@
import pymesh
vertices = [
[0, 0, 0],
[1, 0, 0],
[1, 1, 0],
[0, 1, 0]
]
faces = [
[0, 1, 2],
[0, 2, 3]
]
mesh = pymesh.form_mesh(vertices, faces)
+27 -23
View File
@@ -1,39 +1,43 @@
# Speckle Automate function template - Python
[![build and deploy Speckle functions](https://github.com/specklesystems/speckle_automate-basic_clash_demo/actions/workflows/main.yml/badge.svg)](https://github.com/specklesystems/speckle_automate-basic_clash_demo/actions/workflows/main.yml)
This is a template repository for a Speckle Automate functions written in python
using the [specklepy](https://pypi.org/project/specklepy/) SDK to interact with Speckle data.
# Speckle Automate Function: Basic Clash Analysis Demo
This template contains the full scaffolding required to publish a function to the automate environment.
Also has some sane defaults for a development environment setups.
## Overview
This repository hosts the Basic Clash Analysis Demo for Speckle Automate, tailored for the AEC industry. It demonstrates automated clash detection using complex third-party libraries to analyze elements from both a static reference model and a dynamic model.
## Getting started
## ⚠️ Disclaimer: Conceptual Demonstration Only
**IMPORTANT: This function is a conceptual model and is not intended for actual use in production environments. It serves as a demonstration to illustrate automated clash detection principles in Speckle Automate and the use of third-party libraries for advanced analysis.**
1. Use this template repository to create a new repository in your own / organization's profile.
## Functionality
- **Element Type Selection:** Users specify element categories for clash tests.
- **Automated Detection:** Demonstrates real-time clash detection as the dynamic model evolves.
- **Clash Reporting:** Generates reports on detected clashes.
- **Integration Example:** Illustrates potential integration with Speckle's platform and AEC software tools.
- **Notification Simulation:** Simulates automated notifications about clashes.
Register the function
### How It Works
The function analyzes elements from a static reference model and a dynamic model, identifying potential geometric conflicts when the dynamic model is updated.
### Add new dependencies
### Utilization of Third-Party Libraries
This demo showcases the ability to incorporate complex third-party libraries for detailed analysis, extending the functionality of Speckle Automate beyond its core features. In this case a custom build of PyMesh and its c++ library dependencies are included in the Dockerfile.
To add new python package dependencies to the project, use:
`$ poetry add pandas`
### Containerization and Deployment
- **Dockerization:** The included Dockerfile demonstrates how the project can be containerized, emphasizing the ease of deployment in Speckle Automate.
- **Automate Deployment:** Highlights the potential for easy deployment of containerized projects within the Speckle ecosystem.
### Change launch variables
## Note
This function is designed for educational purposes and is not equipped for real-world AEC projects.
describe how the launch.json should be edited
---
### Github Codespaces
**Reminder:** This repository is a conceptual demonstration for automated clash detection and the use of third-party libraries in Speckle Automate.
Create a new repo from this template, and use the create new code.
## Using this Speckle Function
1. **Create a New Speckle Automation**: Set up in the Speckle dashboard.
2. **Configure the Function**: Choose the "Basic Clash Analysis" function.
3. **Run and Review**: Execute the function and review the clash reports.
### Using this Speckle Function
1. [Create](https://automate.speckle.dev/) a new Speckle Automation.
1. Select your Speckle Project and Speckle Model.
1. Select the existing Speckle Function named [`Random comment on IFC beam`](https://automate.speckle.dev/functions/e110be8fad).
1. Enter a phrase to use in the comment.
1. Click `Create Automation`.
## Getting Started with creating your own Speckle Function
1. [Register](https://automate.speckle.dev/) your Function with [Speckle Automate](https://automate.speckle.dev/) and select the Python template.
1. A new repository will be created in your GitHub account.
View File
View File
+51
View File
@@ -0,0 +1,51 @@
# Required imports
from typing import Callable, List, Union
from specklepy.objects import Base
# We're going to define a set of rules that will allow us to filter and
# process parameters in our Speckle objects. These rules will be encapsulated
# in a class called `ParameterRules`.
class ElementCheckRules:
"""A collection of rules for processing parameters in Speckle objects.
This class provides static methods that return lambda functions. These
lambda functions serve as filters or conditions we can use in our main
processing logic. By encapsulating these rules, we can easily extend
or modify them in the future.
"""
@staticmethod
def rule_combiner(*rules: Callable[[Base], bool]) -> Callable[[Base], bool]:
def combined(obj: Base) -> bool:
return all(rule(obj) for rule in rules)
return combined
@staticmethod
def is_displayable_rule() -> Callable[[Base], bool]:
"""Rule: Check if a parameter is displayable."""
return (
lambda parameter: parameter.displayValue
and parameter.displayValue is not None
)
@staticmethod
def speckle_type_rule(
desired_type: Union[str, List[str]]
) -> Callable[[Base], bool]:
"""Rule: Check if a parameter's speckle_type matches the desired type."""
# Convert single string to list for consistent handling
if isinstance(desired_type, str):
desired_type = [desired_type]
print(desired_type)
return (
lambda speckle_object: getattr(speckle_object, "speckle_type", None)
in desired_type
)
View File
+66 -8
View File
@@ -1,13 +1,71 @@
"""Helper module for a simple speckle object tree flattening."""
from collections.abc import Iterable
from typing import Tuple, Optional
from specklepy.objects import Base
from specklepy.objects.other import Instance, Transform
def flatten_base(base: Base) -> Iterable[Base]:
"""Take a base and flatten it to an iterable of bases."""
if hasattr(base, "elements"):
for element in base["elements"]:
yield from flatten_base(element)
yield base
# def flatten_base(base: Base) -> Iterable[Base]:
# """Take a base and flatten it to an iterable of bases."""
# if hasattr(base, "elements") and base["elements"] is not None:
# for element in base["elements"]:
# yield from flatten_base(element)
# yield base
def extract_base_and_transform(
base: Base,
inherited_instance_id: Optional[str] = None,
transform_list: Optional[List[Transform]] = None,
) -> Tuple[Base, str, Optional[List[Transform]]]:
"""
Traverses Speckle object hierarchies to yield `Base` objects and their transformations.
Tailored to Speckle's AEC data structures, it covers the newer hierarchical structures
with Collections and also with patterns found in older Revit specific data.
Parameters:
- base (Base): The starting point `Base` object for traversal.
- inherited_instance_id (str, optional): The inherited identifier for `Base` objects without a unique ID.
- transform_list (List[Transform], optional): Accumulated list of transformations from parent to child objects.
Yields:
- tuple: A `Base` object, its identifier, and a list of applicable `Transform` objects or None.
The id of the `Base` object is either the inherited identifier for a definition from an instance
or the one defined in the object.
"""
# Derive the identifier for the current `Base` object, defaulting to an inherited one if needed.
current_id = getattr(base, "id", inherited_instance_id)
transform_list = transform_list or []
if isinstance(base, Instance):
# Append transformation data and dive into the definition of `Instance` objects.
if base.transform:
transform_list.append(base.transform)
if base.definition:
yield from extract_base_and_transform(
base.definition, current_id, transform_list.copy()
)
else:
# Initial yield for the current `Base` object.
yield base, current_id, transform_list
# Process 'elements' and '@elements', typical containers for `Base` objects in AEC models.
elements_attr = getattr(base, "elements", []) or getattr(base, "@elements", [])
for element in elements_attr:
if isinstance(element, Base):
# Recurse into each `Base` object within 'elements' or '@elements'.
yield from extract_base_and_transform(
element, current_id, transform_list.copy()
)
# Recursively process '@'-prefixed properties that are Base objects with 'elements'.
# This is a common pattern in older Speckle data models, such as those used for Revit commits.
for attr_name in dir(base):
if attr_name.startswith("@"):
attr_value = getattr(base, attr_name)
# If the attribute is a Base object containing 'elements', recurse into it.
if isinstance(attr_value, Base) and hasattr(attr_value, "elements"):
yield from extract_base_and_transform(
attr_value, current_id, transform_list.copy()
)
+194 -52
View File
@@ -1,9 +1,8 @@
"""This module contains the business logic of the function.
use the automation_context module to wrap your function in an Autamate context helper
use the automation_context module to wrap your function in an Automate context helper
"""
import time
from typing import List, Optional, Tuple
from pydantic import Field
from speckle_automate import (
@@ -11,8 +10,17 @@ from speckle_automate import (
AutomationContext,
execute_automate_function,
)
from specklepy.api import operations
from specklepy.api.models import Branch
from specklepy.objects import Base
from specklepy.objects.other import Transform
from specklepy.objects.units import Units
from specklepy.transports.server import ServerTransport
from trimesh import Trimesh
from flatten import flatten_base
from Geometry.mesh import speckle_to_element, Element
from Rules.checks import ElementCheckRules
from flatten import extract_base_and_transform
class FunctionInputs(AutomateBase):
@@ -23,12 +31,22 @@ class FunctionInputs(AutomateBase):
https://docs.pydantic.dev/latest/usage/models/
"""
forbidden_speckle_type: str = Field(
title="Forbidden speckle type",
description=(
"If a object has the following speckle_type,"
" it will be marked with an error."
),
tolerance: float = Field(
default=25.0,
title="Tolerance",
description="Specify the tolerance value for the analysis. \
Negative values relaxes the test, positive values make it more strict.",
)
tolerance_unit: str = Field( # Using the SpecklePy Units enum here
default=Units.mm,
json_schema_extra={"examples": ["mm", "cm", "m"]},
title="Tolerance Unit",
description="Unit of the tolerance value.",
)
static_model_name: str = Field(
...,
title="Static Model Name",
description="Name of the static structural model.",
)
@@ -42,59 +60,183 @@ def automate_function(
automate_context: A context helper object, that carries relevant information
about the runtime context of this function.
It gives access to the Speckle project data, that triggered this run.
It also has conveniece methods attach result data to the Speckle model.
It also has convenience methods attach result data to the Speckle model.
function_inputs: An instance object matching the defined schema.
"""
# the context provides a conveniet way, to receive the triggering version
version_root_object = automate_context.receive_version()
# the context provides a convenient way, to receive the triggering version
changed_model_version = automate_context.receive_version()
sleep_cycles = 10
for i in range(sleep_cycles):
print(f"sleeping {i}/{sleep_cycles}")
time.sleep(5)
count = 0
for b in flatten_base(version_root_object):
if b.speckle_type == function_inputs.forbidden_speckle_type:
if not b.id:
raise ValueError("Cannot operate on objects without their id's.")
automate_context.attach_error_to_objects(
category="Forbidden speckle_type",
object_ids=b.id,
message="This project should not contain the type: "
f"{b.speckle_type}",
)
count += 1
if count > 0:
# this is how a run is marked with a failure cause
automate_context.mark_run_failed(
"Automation failed: "
f"Found {count} object that have one of the forbidden speckle types: "
f"{function_inputs.forbidden_speckle_type}"
try:
reference_model_version = get_reference_model(
automate_context, function_inputs.static_model_name
)
# set the automation context view, to the original model / version view
# to show the offending objects
automate_context.set_context_view()
except Exception as ex:
automate_context.mark_run_failed(status_message=str(ex))
return
else:
automate_context.mark_run_success("No forbidden types found.")
reference_objects: tuple[
Base,
str,
Optional[Transform],
] = extract_base_and_transform(reference_model_version)
latest_objects: tuple[
Base,
str,
Optional[Transform],
] = extract_base_and_transform(changed_model_version)
# if the function generates file results, this is how it can be
# attached to the Speckle project / model
# automate_context.store_file_result("./report.pdf")
element_rules = ElementCheckRules()
beam_types = [
"Objects.BuiltElements.Beam:Objects.BuiltElements.Revit.RevitBeam",
]
duct_types = [
"Objects.BuiltElements.Duct",
"Objects.BuiltElements.Duct:Objects.BuiltElements.Revit.RevitDuct",
"Objects.BuiltElements.Duct:Objects.BuiltElements.Revit.RevitDuct:Objects.BuiltElements.Revit.RevitFlexDuct",
]
visible_beams_rule = element_rules.rule_combiner(
element_rules.speckle_type_rule(beam_types),
element_rules.is_displayable_rule(),
)
visible_ducts_rule = element_rules.rule_combiner(
element_rules.speckle_type_rule(duct_types),
element_rules.is_displayable_rule(),
)
reference_displayable_objects = [
(base_obj, id, transform)
for base_obj, id, transform in reference_objects
if visible_beams_rule(base_obj)
]
latest_displayable_objects = [
(base_obj, id, transform)
for base_obj, id, transform in latest_objects
if visible_ducts_rule(base_obj)
]
reference_mesh_elements = [
speckle_to_element(obj) for obj in reference_displayable_objects
]
latest_mesh_elements = [
speckle_to_element(obj) for obj in latest_displayable_objects
]
# using trimesh library process all these meshes in the form of A vs B
# and get the clashes
clashes = detect_clashes(
reference_mesh_elements, latest_mesh_elements, function_inputs.tolerance
)
print(len(clashes))
automate_context.mark_run_success(status_message="Clash detection completed.")
def automate_function_without_inputs(automate_context: AutomationContext) -> None:
"""A function example without inputs.
If your function does not need any input variables,
besides what the automation context provides,
the inputs argument can be omitted.
def detect_clashes(
elements_a: List[Element], elements_b: List[Element], length_tolerance: float
) -> List[Tuple[Element, Element]]:
"""
pass
Detects clashes between two sets of elements with a specified tolerance.
This function checks each combination of elements from `elements_a` and `elements_b`
to see if any of their respective meshes intersect within the specified tolerance.
If a clash is detected between any mesh from an element in `elements_a` and any mesh
from an element in `elements_b`, the pair of elements is added to the results.
Args:
- elements_a (List[Element]): A list of `Element` objects to be checked for clashes.
- elements_b (List[Element]): A second list of `Element` objects to be checked for clashes against `elements_a`.
- length_tolerance (float): The distance to offset mesh vertices for intersection check.
Returns:
- List[Tuple[Element, Element]]: A list of tuples where each tuple contains a pair of `Element` objects that clash.
"""
# Use list comprehension to get pairs of elements that have clashing meshes
clashes = [
(element_a, element_b)
for element_a in elements_a
for element_b in elements_b
if any(
check_intersection_with_tolerance(mesh_a, mesh_b, length_tolerance)
for mesh_a in element_a.meshes
for mesh_b in element_b.meshes
)
]
return clashes
def check_intersection_with_tolerance(
mesh_a: Trimesh, mesh_b: Trimesh, tolerance: float
) -> bool:
"""
Checks for intersections between two meshes within a specified tolerance.
Args:
- mesh_a: The first mesh to check.
- mesh_b: The second mesh to check.
- tolerance (float): The distance to offset mesh vertices for intersection check.
Positive values expand the mesh, negative values contract it.
Returns:
- bool: True if the meshes intersect within the specified tolerance, otherwise False.
"""
half_tolerance = tolerance / 2.0 # TODO: how to shrink bloat mesh?
offset_mesh_a: Trimesh = mesh_a # mesh_a.offset_mesh(half_tolerance)
offset_mesh_b: Trimesh = mesh_b # mesh_b.offset_mesh(half_tolerance)
# return offset_mesh_a.intersection(offset_mesh_b).volume > 0 TODO: Install Blender as the engine
# return a random boolean for testing - significantly favouring false
import random
return random.random() < 0.05
def get_reference_model(
automate_context: AutomationContext, static_model_name: str
) -> Base:
# the static reference model will be retrieved from the project using model name stored in the inputs
speckle_client = automate_context.speckle_client
project_id = automate_context.automation_run_data.project_id
remote_transport = ServerTransport(
automate_context.automation_run_data.project_id, speckle_client
)
model: Branch = speckle_client.branch.get(
project_id, static_model_name, commits_limit=1
) # get the latest commit of the static model
if not model:
raise Exception("The static model named does not exist, skipping the function.")
reference_model_commits = model.commits.items
if not reference_model_commits:
raise Exception("The static model has no versions, skipping the function.")
latest_reference_model_id = model.id
latest_reference_model_version_object = reference_model_commits[0].referencedObject
if latest_reference_model_id == automate_context.automation_run_data.model_id:
raise Exception(
"The static model is the same as the changed model, skipping the function."
)
latest_reference_model_version = operations.receive(
latest_reference_model_version_object,
remote_transport,
) # receive the static model
return latest_reference_model_version
# make sure to call the function with the executor
+616
View File
@@ -0,0 +1,616 @@
annotated-types==0.6.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43 \
--hash=sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d
anyio==4.0.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f \
--hash=sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a
appdirs==1.4.4 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41 \
--hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128
attrs==23.1.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04 \
--hash=sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015
backoff==2.2.1 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba \
--hash=sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8
certifi==2023.7.22 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
--hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
--hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
--hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
--hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
--hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
--hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
--hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
--hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
--hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
--hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
--hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
--hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
--hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
--hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
--hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
--hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
--hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
--hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
--hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
--hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
--hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
--hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
--hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
--hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
--hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
--hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
--hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
--hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
--hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
--hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
--hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
--hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
--hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
--hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
--hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
--hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
--hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
--hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
--hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
--hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
--hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
--hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
--hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
--hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
--hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
--hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
--hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
--hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
--hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
--hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
--hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
--hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
--hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
--hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
--hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
--hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
--hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
--hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
--hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
--hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
--hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
--hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
--hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
--hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
--hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
--hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
--hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
--hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
--hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
--hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
--hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
--hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
--hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
--hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
--hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
--hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
--hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
--hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
--hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
--hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
--hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \
--hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3
exceptiongroup==1.1.3 ; python_version >= "3.10" and python_version < "3.11" \
--hash=sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9 \
--hash=sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3
gql[requests,websockets]==3.4.1 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:11dc5d8715a827f2c2899593439a4f36449db4f0eafa5b1ea63948f8a2f8c545 \
--hash=sha256:315624ca0f4d571ef149d455033ebd35e45c1a13f18a059596aeddcea99135cf
graphql-core==3.2.3 ; python_version >= "3.10" and python_version < "4" \
--hash=sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676 \
--hash=sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3
h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \
--hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761
httpcore==1.0.2 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7 \
--hash=sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535
httpx==0.25.1 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:fec7d6cc5c27c578a391f7e87b9aa7d3d8fbcd034f6399f9f79b45bcc12a866a \
--hash=sha256:ffd96d5cf901e63863d9f1b4b6807861dbea4d301613415d9e6e57ead15fc5d0
idna==3.4 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
--hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
multidict==6.0.4 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9 \
--hash=sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8 \
--hash=sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03 \
--hash=sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710 \
--hash=sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161 \
--hash=sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664 \
--hash=sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569 \
--hash=sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067 \
--hash=sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313 \
--hash=sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706 \
--hash=sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2 \
--hash=sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636 \
--hash=sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49 \
--hash=sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93 \
--hash=sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603 \
--hash=sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0 \
--hash=sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60 \
--hash=sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4 \
--hash=sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e \
--hash=sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1 \
--hash=sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60 \
--hash=sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951 \
--hash=sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc \
--hash=sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe \
--hash=sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95 \
--hash=sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d \
--hash=sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8 \
--hash=sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed \
--hash=sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2 \
--hash=sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775 \
--hash=sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87 \
--hash=sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c \
--hash=sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2 \
--hash=sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98 \
--hash=sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3 \
--hash=sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe \
--hash=sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78 \
--hash=sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660 \
--hash=sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176 \
--hash=sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e \
--hash=sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988 \
--hash=sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c \
--hash=sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c \
--hash=sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0 \
--hash=sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449 \
--hash=sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f \
--hash=sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde \
--hash=sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5 \
--hash=sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d \
--hash=sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac \
--hash=sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a \
--hash=sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9 \
--hash=sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca \
--hash=sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11 \
--hash=sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35 \
--hash=sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063 \
--hash=sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b \
--hash=sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982 \
--hash=sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258 \
--hash=sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1 \
--hash=sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52 \
--hash=sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480 \
--hash=sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7 \
--hash=sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461 \
--hash=sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d \
--hash=sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc \
--hash=sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779 \
--hash=sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a \
--hash=sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547 \
--hash=sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0 \
--hash=sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171 \
--hash=sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf \
--hash=sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d \
--hash=sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba
pydantic-core==2.10.1 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:042462d8d6ba707fd3ce9649e7bf268633a41018d6a998fb5fbacb7e928a183e \
--hash=sha256:0523aeb76e03f753b58be33b26540880bac5aa54422e4462404c432230543f33 \
--hash=sha256:05560ab976012bf40f25d5225a58bfa649bb897b87192a36c6fef1ab132540d7 \
--hash=sha256:0675ba5d22de54d07bccde38997e780044dcfa9a71aac9fd7d4d7a1d2e3e65f7 \
--hash=sha256:073d4a470b195d2b2245d0343569aac7e979d3a0dcce6c7d2af6d8a920ad0bea \
--hash=sha256:07ec6d7d929ae9c68f716195ce15e745b3e8fa122fc67698ac6498d802ed0fa4 \
--hash=sha256:0880e239827b4b5b3e2ce05e6b766a7414e5f5aedc4523be6b68cfbc7f61c5d0 \
--hash=sha256:0c27f38dc4fbf07b358b2bc90edf35e82d1703e22ff2efa4af4ad5de1b3833e7 \
--hash=sha256:0d8a8adef23d86d8eceed3e32e9cca8879c7481c183f84ed1a8edc7df073af94 \
--hash=sha256:0e2a35baa428181cb2270a15864ec6286822d3576f2ed0f4cd7f0c1708472aff \
--hash=sha256:0f8682dbdd2f67f8e1edddcbffcc29f60a6182b4901c367fc8c1c40d30bb0a82 \
--hash=sha256:0fa467fd300a6f046bdb248d40cd015b21b7576c168a6bb20aa22e595c8ffcdd \
--hash=sha256:128552af70a64660f21cb0eb4876cbdadf1a1f9d5de820fed6421fa8de07c893 \
--hash=sha256:1396e81b83516b9d5c9e26a924fa69164156c148c717131f54f586485ac3c15e \
--hash=sha256:149b8a07712f45b332faee1a2258d8ef1fb4a36f88c0c17cb687f205c5dc6e7d \
--hash=sha256:14ac492c686defc8e6133e3a2d9eaf5261b3df26b8ae97450c1647286750b901 \
--hash=sha256:14cfbb00959259e15d684505263d5a21732b31248a5dd4941f73a3be233865b9 \
--hash=sha256:14e09ff0b8fe6e46b93d36a878f6e4a3a98ba5303c76bb8e716f4878a3bee92c \
--hash=sha256:154ea7c52e32dce13065dbb20a4a6f0cc012b4f667ac90d648d36b12007fa9f7 \
--hash=sha256:15d6bca84ffc966cc9976b09a18cf9543ed4d4ecbd97e7086f9ce9327ea48891 \
--hash=sha256:1d40f55222b233e98e3921df7811c27567f0e1a4411b93d4c5c0f4ce131bc42f \
--hash=sha256:25bd966103890ccfa028841a8f30cebcf5875eeac8c4bde4fe221364c92f0c9a \
--hash=sha256:2cf5bb4dd67f20f3bbc1209ef572a259027c49e5ff694fa56bed62959b41e1f9 \
--hash=sha256:2e0e2959ef5d5b8dc9ef21e1a305a21a36e254e6a34432d00c72a92fdc5ecda5 \
--hash=sha256:320f14bd4542a04ab23747ff2c8a778bde727158b606e2661349557f0770711e \
--hash=sha256:3625578b6010c65964d177626fde80cf60d7f2e297d56b925cb5cdeda6e9925a \
--hash=sha256:39215d809470f4c8d1881758575b2abfb80174a9e8daf8f33b1d4379357e417c \
--hash=sha256:3f0ac9fb8608dbc6eaf17956bf623c9119b4db7dbb511650910a82e261e6600f \
--hash=sha256:417243bf599ba1f1fef2bb8c543ceb918676954734e2dcb82bf162ae9d7bd514 \
--hash=sha256:420a692b547736a8d8703c39ea935ab5d8f0d2573f8f123b0a294e49a73f214b \
--hash=sha256:443fed67d33aa85357464f297e3d26e570267d1af6fef1c21ca50921d2976302 \
--hash=sha256:48525933fea744a3e7464c19bfede85df4aba79ce90c60b94d8b6e1eddd67096 \
--hash=sha256:485a91abe3a07c3a8d1e082ba29254eea3e2bb13cbbd4351ea4e5a21912cc9b0 \
--hash=sha256:4a5be350f922430997f240d25f8219f93b0c81e15f7b30b868b2fddfc2d05f27 \
--hash=sha256:4d966c47f9dd73c2d32a809d2be529112d509321c5310ebf54076812e6ecd884 \
--hash=sha256:524ff0ca3baea164d6d93a32c58ac79eca9f6cf713586fdc0adb66a8cdeab96a \
--hash=sha256:53df009d1e1ba40f696f8995683e067e3967101d4bb4ea6f667931b7d4a01357 \
--hash=sha256:5994985da903d0b8a08e4935c46ed8daf5be1cf217489e673910951dc533d430 \
--hash=sha256:5cabb9710f09d5d2e9e2748c3e3e20d991a4c5f96ed8f1132518f54ab2967221 \
--hash=sha256:5fdb39f67c779b183b0c853cd6b45f7db84b84e0571b3ef1c89cdb1dfc367325 \
--hash=sha256:600d04a7b342363058b9190d4e929a8e2e715c5682a70cc37d5ded1e0dd370b4 \
--hash=sha256:631cb7415225954fdcc2a024119101946793e5923f6c4d73a5914d27eb3d3a05 \
--hash=sha256:63974d168b6233b4ed6a0046296803cb13c56637a7b8106564ab575926572a55 \
--hash=sha256:64322bfa13e44c6c30c518729ef08fda6026b96d5c0be724b3c4ae4da939f875 \
--hash=sha256:655f8f4c8d6a5963c9a0687793da37b9b681d9ad06f29438a3b2326d4e6b7970 \
--hash=sha256:6835451b57c1b467b95ffb03a38bb75b52fb4dc2762bb1d9dbed8de31ea7d0fc \
--hash=sha256:6db2eb9654a85ada248afa5a6db5ff1cf0f7b16043a6b070adc4a5be68c716d6 \
--hash=sha256:7c4d1894fe112b0864c1fa75dffa045720a194b227bed12f4be7f6045b25209f \
--hash=sha256:7eb037106f5c6b3b0b864ad226b0b7ab58157124161d48e4b30c4a43fef8bc4b \
--hash=sha256:8282bab177a9a3081fd3d0a0175a07a1e2bfb7fcbbd949519ea0980f8a07144d \
--hash=sha256:82f55187a5bebae7d81d35b1e9aaea5e169d44819789837cdd4720d768c55d15 \
--hash=sha256:8572cadbf4cfa95fb4187775b5ade2eaa93511f07947b38f4cd67cf10783b118 \
--hash=sha256:8cdbbd92154db2fec4ec973d45c565e767ddc20aa6dbaf50142676484cbff8ee \
--hash=sha256:8f6e6aed5818c264412ac0598b581a002a9f050cb2637a84979859e70197aa9e \
--hash=sha256:92f675fefa977625105708492850bcbc1182bfc3e997f8eecb866d1927c98ae6 \
--hash=sha256:962ed72424bf1f72334e2f1e61b68f16c0e596f024ca7ac5daf229f7c26e4208 \
--hash=sha256:9badf8d45171d92387410b04639d73811b785b5161ecadabf056ea14d62d4ede \
--hash=sha256:9c120c9ce3b163b985a3b966bb701114beb1da4b0468b9b236fc754783d85aa3 \
--hash=sha256:9f6f3e2598604956480f6c8aa24a3384dbf6509fe995d97f6ca6103bb8c2534e \
--hash=sha256:a1254357f7e4c82e77c348dabf2d55f1d14d19d91ff025004775e70a6ef40ada \
--hash=sha256:a1392e0638af203cee360495fd2cfdd6054711f2db5175b6e9c3c461b76f5175 \
--hash=sha256:a1c311fd06ab3b10805abb72109f01a134019739bd3286b8ae1bc2fc4e50c07a \
--hash=sha256:a5cb87bdc2e5f620693148b5f8f842d293cae46c5f15a1b1bf7ceeed324a740c \
--hash=sha256:a7a7902bf75779bc12ccfc508bfb7a4c47063f748ea3de87135d433a4cca7a2f \
--hash=sha256:aad7bd686363d1ce4ee930ad39f14e1673248373f4a9d74d2b9554f06199fb58 \
--hash=sha256:aafdb89fdeb5fe165043896817eccd6434aee124d5ee9b354f92cd574ba5e78f \
--hash=sha256:ae8a8843b11dc0b03b57b52793e391f0122e740de3df1474814c700d2622950a \
--hash=sha256:b00bc4619f60c853556b35f83731bd817f989cba3e97dc792bb8c97941b8053a \
--hash=sha256:b1f22a9ab44de5f082216270552aa54259db20189e68fc12484873d926426921 \
--hash=sha256:b3c01c2fb081fced3bbb3da78510693dc7121bb893a1f0f5f4b48013201f362e \
--hash=sha256:b3dcd587b69bbf54fc04ca157c2323b8911033e827fffaecf0cafa5a892a0904 \
--hash=sha256:b4a6db486ac8e99ae696e09efc8b2b9fea67b63c8f88ba7a1a16c24a057a0776 \
--hash=sha256:bec7dd208a4182e99c5b6c501ce0b1f49de2802448d4056091f8e630b28e9a52 \
--hash=sha256:c0877239307b7e69d025b73774e88e86ce82f6ba6adf98f41069d5b0b78bd1bf \
--hash=sha256:caa48fc31fc7243e50188197b5f0c4228956f97b954f76da157aae7f67269ae8 \
--hash=sha256:cfe1090245c078720d250d19cb05d67e21a9cd7c257698ef139bc41cf6c27b4f \
--hash=sha256:d43002441932f9a9ea5d6f9efaa2e21458221a3a4b417a14027a1d530201ef1b \
--hash=sha256:d64728ee14e667ba27c66314b7d880b8eeb050e58ffc5fec3b7a109f8cddbd63 \
--hash=sha256:d6495008733c7521a89422d7a68efa0a0122c99a5861f06020ef5b1f51f9ba7c \
--hash=sha256:d8f1ebca515a03e5654f88411420fea6380fc841d1bea08effb28184e3d4899f \
--hash=sha256:d99277877daf2efe074eae6338453a4ed54a2d93fb4678ddfe1209a0c93a2468 \
--hash=sha256:da01bec0a26befab4898ed83b362993c844b9a607a86add78604186297eb047e \
--hash=sha256:db9a28c063c7c00844ae42a80203eb6d2d6bbb97070cfa00194dff40e6f545ab \
--hash=sha256:dda81e5ec82485155a19d9624cfcca9be88a405e2857354e5b089c2a982144b2 \
--hash=sha256:e357571bb0efd65fd55f18db0a2fb0ed89d0bb1d41d906b138f088933ae618bb \
--hash=sha256:e544246b859f17373bed915182ab841b80849ed9cf23f1f07b73b7c58baee5fb \
--hash=sha256:e562617a45b5a9da5be4abe72b971d4f00bf8555eb29bb91ec2ef2be348cd132 \
--hash=sha256:e570ffeb2170e116a5b17e83f19911020ac79d19c96f320cbfa1fa96b470185b \
--hash=sha256:e6f31a17acede6a8cd1ae2d123ce04d8cca74056c9d456075f4f6f85de055607 \
--hash=sha256:e9121b4009339b0f751955baf4543a0bfd6bc3f8188f8056b1a25a2d45099934 \
--hash=sha256:ebedb45b9feb7258fac0a268a3f6bec0a2ea4d9558f3d6f813f02ff3a6dc6698 \
--hash=sha256:ecaac27da855b8d73f92123e5f03612b04c5632fd0a476e469dfc47cd37d6b2e \
--hash=sha256:ecdbde46235f3d560b18be0cb706c8e8ad1b965e5c13bbba7450c86064e96561 \
--hash=sha256:ed550ed05540c03f0e69e6d74ad58d026de61b9eaebebbaaf8873e585cbb18de \
--hash=sha256:eeb3d3d6b399ffe55f9a04e09e635554012f1980696d6b0aca3e6cf42a17a03b \
--hash=sha256:ef337945bbd76cce390d1b2496ccf9f90b1c1242a3a7bc242ca4a9fc5993427a \
--hash=sha256:f1365e032a477c1430cfe0cf2856679529a2331426f8081172c4a74186f1d595 \
--hash=sha256:f23b55eb5464468f9e0e9a9935ce3ed2a870608d5f534025cd5536bca25b1402 \
--hash=sha256:f2e9072d71c1f6cfc79a36d4484c82823c560e6f5599c43c1ca6b5cdbd54f881 \
--hash=sha256:f323306d0556351735b54acbf82904fe30a27b6a7147153cbe6e19aaaa2aa429 \
--hash=sha256:f36a3489d9e28fe4b67be9992a23029c3cec0babc3bd9afb39f49844a8c721c5 \
--hash=sha256:f64f82cc3443149292b32387086d02a6c7fb39b8781563e0ca7b8d7d9cf72bd7 \
--hash=sha256:f6defd966ca3b187ec6c366604e9296f585021d922e666b99c47e78738b5666c \
--hash=sha256:f7c2b8eb9fc872e68b46eeaf835e86bccc3a58ba57d0eedc109cbb14177be531 \
--hash=sha256:fa7db7558607afeccb33c0e4bf1c9a9a835e26599e76af6fe2fcea45904083a6 \
--hash=sha256:fcb83175cc4936a5425dde3356f079ae03c0802bbdf8ff82c035f8a54b333521
pydantic==2.4.2 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:94f336138093a5d7f426aac732dcfe7ab4eb4da243c88f891d65deb4a2556ee7 \
--hash=sha256:bc3ddf669d234f4220e6e1c4d96b061abe0998185a8d7855c0126782b7abc8c1
requests-toolbelt==0.10.1 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7 \
--hash=sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d
requests==2.31.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
sniffio==1.3.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \
--hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384
specklepy==2.17.11 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:b903ba6848959b95e60f5e1e80bacfa9c542359f85b360afd0d84bdd66615b15 \
--hash=sha256:e915ec4c3862a517f417f0b764e252a6582e7ace3696938a8e5043891308a5ab
stringcase==1.2.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:48a06980661908efe8d9d34eab2b6c13aefa2163b3ced26972902e3bdfd87008
typing-extensions==4.8.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \
--hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef
ujson==5.8.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:07d459aca895eb17eb463b00441986b021b9312c6c8cc1d06880925c7f51009c \
--hash=sha256:0be81bae295f65a6896b0c9030b55a106fb2dec69ef877253a87bc7c9c5308f7 \
--hash=sha256:0fe1b7edaf560ca6ab023f81cbeaf9946a240876a993b8c5a21a1c539171d903 \
--hash=sha256:102bf31c56f59538cccdfec45649780ae00657e86247c07edac434cb14d5388c \
--hash=sha256:11da6bed916f9bfacf13f4fc6a9594abd62b2bb115acfb17a77b0f03bee4cfd5 \
--hash=sha256:16fde596d5e45bdf0d7de615346a102510ac8c405098e5595625015b0d4b5296 \
--hash=sha256:193349a998cd821483a25f5df30b44e8f495423840ee11b3b28df092ddfd0f7f \
--hash=sha256:20768961a6a706170497129960762ded9c89fb1c10db2989c56956b162e2a8a3 \
--hash=sha256:27a2a3c7620ebe43641e926a1062bc04e92dbe90d3501687957d71b4bdddaec4 \
--hash=sha256:2873d196725a8193f56dde527b322c4bc79ed97cd60f1d087826ac3290cf9207 \
--hash=sha256:299a312c3e85edee1178cb6453645217ba23b4e3186412677fa48e9a7f986de6 \
--hash=sha256:2a64cc32bb4a436e5813b83f5aab0889927e5ea1788bf99b930fad853c5625cb \
--hash=sha256:2b852bdf920fe9f84e2a2c210cc45f1b64f763b4f7d01468b33f7791698e455e \
--hash=sha256:2e72ba76313d48a1a3a42e7dc9d1db32ea93fac782ad8dde6f8b13e35c229130 \
--hash=sha256:3659deec9ab9eb19e8646932bfe6fe22730757c4addbe9d7d5544e879dc1b721 \
--hash=sha256:3b27a8da7a080add559a3b73ec9ebd52e82cc4419f7c6fb7266e62439a055ed0 \
--hash=sha256:3f9b63530a5392eb687baff3989d0fb5f45194ae5b1ca8276282fb647f8dcdb3 \
--hash=sha256:407d60eb942c318482bbfb1e66be093308bb11617d41c613e33b4ce5be789adc \
--hash=sha256:40931d7c08c4ce99adc4b409ddb1bbb01635a950e81239c2382cfe24251b127a \
--hash=sha256:48c7d373ff22366eecfa36a52b9b55b0ee5bd44c2b50e16084aa88b9de038916 \
--hash=sha256:4ddeabbc78b2aed531f167d1e70387b151900bc856d61e9325fcdfefb2a51ad8 \
--hash=sha256:5ac97b1e182d81cf395ded620528c59f4177eee024b4b39a50cdd7b720fdeec6 \
--hash=sha256:5ce24909a9c25062e60653073dd6d5e6ec9d6ad7ed6e0069450d5b673c854405 \
--hash=sha256:69b3104a2603bab510497ceabc186ba40fef38ec731c0ccaa662e01ff94a985c \
--hash=sha256:6a4dafa9010c366589f55afb0fd67084acd8added1a51251008f9ff2c3e44042 \
--hash=sha256:6d230d870d1ce03df915e694dcfa3f4e8714369cce2346686dbe0bc8e3f135e7 \
--hash=sha256:78e318def4ade898a461b3d92a79f9441e7e0e4d2ad5419abed4336d702c7425 \
--hash=sha256:7a42baa647a50fa8bed53d4e242be61023bd37b93577f27f90ffe521ac9dc7a3 \
--hash=sha256:7cba16b26efe774c096a5e822e4f27097b7c81ed6fb5264a2b3f5fd8784bab30 \
--hash=sha256:7d8283ac5d03e65f488530c43d6610134309085b71db4f675e9cf5dff96a8282 \
--hash=sha256:7ecc33b107ae88405aebdb8d82c13d6944be2331ebb04399134c03171509371a \
--hash=sha256:9249fdefeb021e00b46025e77feed89cd91ffe9b3a49415239103fc1d5d9c29a \
--hash=sha256:9399eaa5d1931a0ead49dce3ffacbea63f3177978588b956036bfe53cdf6af75 \
--hash=sha256:94c7bd9880fa33fcf7f6d7f4cc032e2371adee3c5dba2922b918987141d1bf07 \
--hash=sha256:9571de0c53db5cbc265945e08f093f093af2c5a11e14772c72d8e37fceeedd08 \
--hash=sha256:9721cd112b5e4687cb4ade12a7b8af8b048d4991227ae8066d9c4b3a6642a582 \
--hash=sha256:9ab282d67ef3097105552bf151438b551cc4bedb3f24d80fada830f2e132aeb9 \
--hash=sha256:9d9707e5aacf63fb919f6237d6490c4e0244c7f8d3dc2a0f84d7dec5db7cb54c \
--hash=sha256:a70f776bda2e5072a086c02792c7863ba5833d565189e09fabbd04c8b4c3abba \
--hash=sha256:a89cf3cd8bf33a37600431b7024a7ccf499db25f9f0b332947fbc79043aad879 \
--hash=sha256:a8c91b6f4bf23f274af9002b128d133b735141e867109487d17e344d38b87d94 \
--hash=sha256:ad24ec130855d4430a682c7a60ca0bc158f8253ec81feed4073801f6b6cb681b \
--hash=sha256:ae7f4725c344bf437e9b881019c558416fe84ad9c6b67426416c131ad577df67 \
--hash=sha256:b748797131ac7b29826d1524db1cc366d2722ab7afacc2ce1287cdafccddbf1f \
--hash=sha256:bdf04c6af3852161be9613e458a1fb67327910391de8ffedb8332e60800147a2 \
--hash=sha256:bf5737dbcfe0fa0ac8fa599eceafae86b376492c8f1e4b84e3adf765f03fb564 \
--hash=sha256:c4e7bb7eba0e1963f8b768f9c458ecb193e5bf6977090182e2b4f4408f35ac76 \
--hash=sha256:d524a8c15cfc863705991d70bbec998456a42c405c291d0f84a74ad7f35c5109 \
--hash=sha256:d53039d39de65360e924b511c7ca1a67b0975c34c015dd468fca492b11caa8f7 \
--hash=sha256:d6f84a7a175c75beecde53a624881ff618e9433045a69fcfb5e154b73cdaa377 \
--hash=sha256:e0147d41e9fb5cd174207c4a2895c5e24813204499fd0839951d4c8784a23bf5 \
--hash=sha256:e3673053b036fd161ae7a5a33358ccae6793ee89fd499000204676baafd7b3aa \
--hash=sha256:e54578fa8838ddc722539a752adfce9372474114f8c127bb316db5392d942f8b \
--hash=sha256:eb0142f6f10f57598655340a3b2c70ed4646cbe674191da195eb0985a9813b83 \
--hash=sha256:efeddf950fb15a832376c0c01d8d7713479fbeceaed1eaecb2665aa62c305aec \
--hash=sha256:f26629ac531d712f93192c233a74888bc8b8212558bd7d04c349125f10199fcf \
--hash=sha256:f2e385a7679b9088d7bc43a64811a7713cc7c33d032d020f757c54e7d41931ae \
--hash=sha256:f3554eaadffe416c6f543af442066afa6549edbc34fe6a7719818c3e72ebfe95 \
--hash=sha256:f4511560d75b15ecb367eef561554959b9d49b6ec3b8d5634212f9fed74a6df1 \
--hash=sha256:f504117a39cb98abba4153bf0b46b4954cc5d62f6351a14660201500ba31fe7f \
--hash=sha256:fb87decf38cc82bcdea1d7511e73629e651bdec3a43ab40985167ab8449b769c
urllib3==1.26.18 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
--hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
websockets==10.4 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:00213676a2e46b6ebf6045bc11d0f529d9120baa6f58d122b4021ad92adabd41 \
--hash=sha256:00c870522cdb69cd625b93f002961ffb0c095394f06ba8c48f17eef7c1541f96 \
--hash=sha256:0154f7691e4fe6c2b2bc275b5701e8b158dae92a1ab229e2b940efe11905dff4 \
--hash=sha256:05a7233089f8bd355e8cbe127c2e8ca0b4ea55467861906b80d2ebc7db4d6b72 \
--hash=sha256:09a1814bb15eff7069e51fed0826df0bc0702652b5cb8f87697d469d79c23576 \
--hash=sha256:0cff816f51fb33c26d6e2b16b5c7d48eaa31dae5488ace6aae468b361f422b63 \
--hash=sha256:185929b4808b36a79c65b7865783b87b6841e852ef5407a2fb0c03381092fa3b \
--hash=sha256:2fc8709c00704194213d45e455adc106ff9e87658297f72d544220e32029cd3d \
--hash=sha256:33d69ca7612f0ddff3316b0c7b33ca180d464ecac2d115805c044bf0a3b0d032 \
--hash=sha256:389f8dbb5c489e305fb113ca1b6bdcdaa130923f77485db5b189de343a179393 \
--hash=sha256:38ea7b82bfcae927eeffc55d2ffa31665dc7fec7b8dc654506b8e5a518eb4d50 \
--hash=sha256:3d3cac3e32b2c8414f4f87c1b2ab686fa6284a980ba283617404377cd448f631 \
--hash=sha256:40e826de3085721dabc7cf9bfd41682dadc02286d8cf149b3ad05bff89311e4f \
--hash=sha256:4239b6027e3d66a89446908ff3027d2737afc1a375f8fd3eea630a4842ec9a0c \
--hash=sha256:45ec8e75b7dbc9539cbfafa570742fe4f676eb8b0d3694b67dabe2f2ceed8aa6 \
--hash=sha256:47a2964021f2110116cc1125b3e6d87ab5ad16dea161949e7244ec583b905bb4 \
--hash=sha256:48c08473563323f9c9debac781ecf66f94ad5a3680a38fe84dee5388cf5acaf6 \
--hash=sha256:4c6d2264f485f0b53adf22697ac11e261ce84805c232ed5dbe6b1bcb84b00ff0 \
--hash=sha256:4f72e5cd0f18f262f5da20efa9e241699e0cf3a766317a17392550c9ad7b37d8 \
--hash=sha256:56029457f219ade1f2fc12a6504ea61e14ee227a815531f9738e41203a429112 \
--hash=sha256:5c1289596042fad2cdceb05e1ebf7aadf9995c928e0da2b7a4e99494953b1b94 \
--hash=sha256:62e627f6b6d4aed919a2052efc408da7a545c606268d5ab5bfab4432734b82b4 \
--hash=sha256:74de2b894b47f1d21cbd0b37a5e2b2392ad95d17ae983e64727e18eb281fe7cb \
--hash=sha256:7c584f366f46ba667cfa66020344886cf47088e79c9b9d39c84ce9ea98aaa331 \
--hash=sha256:7d27a7e34c313b3a7f91adcd05134315002aaf8540d7b4f90336beafaea6217c \
--hash=sha256:7d3f0b61c45c3fa9a349cf484962c559a8a1d80dae6977276df8fd1fa5e3cb8c \
--hash=sha256:82ff5e1cae4e855147fd57a2863376ed7454134c2bf49ec604dfe71e446e2193 \
--hash=sha256:84bc2a7d075f32f6ed98652db3a680a17a4edb21ca7f80fe42e38753a58ee02b \
--hash=sha256:884be66c76a444c59f801ac13f40c76f176f1bfa815ef5b8ed44321e74f1600b \
--hash=sha256:8a5cc00546e0a701da4639aa0bbcb0ae2bb678c87f46da01ac2d789e1f2d2038 \
--hash=sha256:8dc96f64ae43dde92530775e9cb169979f414dcf5cff670455d81a6823b42089 \
--hash=sha256:8f38706e0b15d3c20ef6259fd4bc1700cd133b06c3c1bb108ffe3f8947be15fa \
--hash=sha256:90fcf8929836d4a0e964d799a58823547df5a5e9afa83081761630553be731f9 \
--hash=sha256:931c039af54fc195fe6ad536fde4b0de04da9d5916e78e55405436348cfb0e56 \
--hash=sha256:932af322458da7e4e35df32f050389e13d3d96b09d274b22a7aa1808f292fee4 \
--hash=sha256:942de28af58f352a6f588bc72490ae0f4ccd6dfc2bd3de5945b882a078e4e179 \
--hash=sha256:9bc42e8402dc5e9905fb8b9649f57efcb2056693b7e88faa8fb029256ba9c68c \
--hash=sha256:a7a240d7a74bf8d5cb3bfe6be7f21697a28ec4b1a437607bae08ac7acf5b4882 \
--hash=sha256:a9f9a735deaf9a0cadc2d8c50d1a5bcdbae8b6e539c6e08237bc4082d7c13f28 \
--hash=sha256:ae5e95cfb53ab1da62185e23b3130e11d64431179debac6dc3c6acf08760e9b1 \
--hash=sha256:b029fb2032ae4724d8ae8d4f6b363f2cc39e4c7b12454df8df7f0f563ed3e61a \
--hash=sha256:b0d15c968ea7a65211e084f523151dbf8ae44634de03c801b8bd070b74e85033 \
--hash=sha256:b343f521b047493dc4022dd338fc6db9d9282658862756b4f6fd0e996c1380e1 \
--hash=sha256:b627c266f295de9dea86bd1112ed3d5fafb69a348af30a2422e16590a8ecba13 \
--hash=sha256:b9968694c5f467bf67ef97ae7ad4d56d14be2751000c1207d31bf3bb8860bae8 \
--hash=sha256:ba089c499e1f4155d2a3c2a05d2878a3428cf321c848f2b5a45ce55f0d7d310c \
--hash=sha256:bbccd847aa0c3a69b5f691a84d2341a4f8a629c6922558f2a70611305f902d74 \
--hash=sha256:bc0b82d728fe21a0d03e65f81980abbbcb13b5387f733a1a870672c5be26edab \
--hash=sha256:c57e4c1349fbe0e446c9fa7b19ed2f8a4417233b6984277cce392819123142d3 \
--hash=sha256:c94ae4faf2d09f7c81847c63843f84fe47bf6253c9d60b20f25edfd30fb12588 \
--hash=sha256:c9b27d6c1c6cd53dc93614967e9ce00ae7f864a2d9f99fe5ed86706e1ecbf485 \
--hash=sha256:d210abe51b5da0ffdbf7b43eed0cfdff8a55a1ab17abbec4301c9ff077dd0342 \
--hash=sha256:d58804e996d7d2307173d56c297cf7bc132c52df27a3efaac5e8d43e36c21c48 \
--hash=sha256:d6a4162139374a49eb18ef5b2f4da1dd95c994588f5033d64e0bbfda4b6b6fcf \
--hash=sha256:da39dd03d130162deb63da51f6e66ed73032ae62e74aaccc4236e30edccddbb0 \
--hash=sha256:db3c336f9eda2532ec0fd8ea49fef7a8df8f6c804cdf4f39e5c5c0d4a4ad9a7a \
--hash=sha256:dd500e0a5e11969cdd3320935ca2ff1e936f2358f9c2e61f100a1660933320ea \
--hash=sha256:dd9becd5fe29773d140d68d607d66a38f60e31b86df75332703757ee645b6faf \
--hash=sha256:e0cb5cc6ece6ffa75baccfd5c02cffe776f3f5c8bf486811f9d3ea3453676ce8 \
--hash=sha256:e23173580d740bf8822fd0379e4bf30aa1d5a92a4f252d34e893070c081050df \
--hash=sha256:e3a686ecb4aa0d64ae60c9c9f1a7d5d46cab9bfb5d91a2d303d00e2cd4c4c5cc \
--hash=sha256:e789376b52c295c4946403bd0efecf27ab98f05319df4583d3c48e43c7342c2f \
--hash=sha256:edc344de4dac1d89300a053ac973299e82d3db56330f3494905643bb68801269 \
--hash=sha256:eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3 \
--hash=sha256:f2c38d588887a609191d30e902df2a32711f708abfd85d318ca9b367258cfd0c \
--hash=sha256:f55b5905705725af31ccef50e55391621532cd64fbf0bc6f4bac935f0fccec46 \
--hash=sha256:f5fc088b7a32f244c519a048c170f14cf2251b849ef0e20cbbb0fdf0fdaf556f \
--hash=sha256:fe10ddc59b304cb19a1bdf5bd0a7719cbbc9fbdd57ac80ed436b709fcf889106 \
--hash=sha256:ff64a1d38d156d429404aaa84b27305e957fd10c30e5880d1765c9480bea490f
wrapt==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \
--hash=sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81 \
--hash=sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09 \
--hash=sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e \
--hash=sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca \
--hash=sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0 \
--hash=sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb \
--hash=sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487 \
--hash=sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40 \
--hash=sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c \
--hash=sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060 \
--hash=sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202 \
--hash=sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41 \
--hash=sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9 \
--hash=sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b \
--hash=sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664 \
--hash=sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d \
--hash=sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362 \
--hash=sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00 \
--hash=sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc \
--hash=sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1 \
--hash=sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267 \
--hash=sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956 \
--hash=sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966 \
--hash=sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1 \
--hash=sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228 \
--hash=sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72 \
--hash=sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d \
--hash=sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292 \
--hash=sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0 \
--hash=sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0 \
--hash=sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36 \
--hash=sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c \
--hash=sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5 \
--hash=sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f \
--hash=sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73 \
--hash=sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b \
--hash=sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2 \
--hash=sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593 \
--hash=sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39 \
--hash=sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389 \
--hash=sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf \
--hash=sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf \
--hash=sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89 \
--hash=sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c \
--hash=sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c \
--hash=sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f \
--hash=sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440 \
--hash=sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465 \
--hash=sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136 \
--hash=sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b \
--hash=sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8 \
--hash=sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3 \
--hash=sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8 \
--hash=sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6 \
--hash=sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e \
--hash=sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f \
--hash=sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c \
--hash=sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e \
--hash=sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8 \
--hash=sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2 \
--hash=sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020 \
--hash=sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35 \
--hash=sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d \
--hash=sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3 \
--hash=sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537 \
--hash=sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809 \
--hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \
--hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \
--hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4
yarl==1.9.2 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571 \
--hash=sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3 \
--hash=sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3 \
--hash=sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c \
--hash=sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7 \
--hash=sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04 \
--hash=sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191 \
--hash=sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea \
--hash=sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4 \
--hash=sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4 \
--hash=sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095 \
--hash=sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e \
--hash=sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74 \
--hash=sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef \
--hash=sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33 \
--hash=sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde \
--hash=sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45 \
--hash=sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf \
--hash=sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b \
--hash=sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac \
--hash=sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0 \
--hash=sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528 \
--hash=sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716 \
--hash=sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb \
--hash=sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18 \
--hash=sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72 \
--hash=sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6 \
--hash=sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582 \
--hash=sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5 \
--hash=sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368 \
--hash=sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc \
--hash=sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9 \
--hash=sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be \
--hash=sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a \
--hash=sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80 \
--hash=sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8 \
--hash=sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6 \
--hash=sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417 \
--hash=sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574 \
--hash=sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59 \
--hash=sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608 \
--hash=sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82 \
--hash=sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1 \
--hash=sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3 \
--hash=sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d \
--hash=sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8 \
--hash=sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc \
--hash=sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac \
--hash=sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8 \
--hash=sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955 \
--hash=sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0 \
--hash=sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367 \
--hash=sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb \
--hash=sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a \
--hash=sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623 \
--hash=sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2 \
--hash=sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6 \
--hash=sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7 \
--hash=sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4 \
--hash=sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051 \
--hash=sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938 \
--hash=sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8 \
--hash=sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9 \
--hash=sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3 \
--hash=sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5 \
--hash=sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9 \
--hash=sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333 \
--hash=sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185 \
--hash=sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3 \
--hash=sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560 \
--hash=sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b \
--hash=sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7 \
--hash=sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78 \
--hash=sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7
View File
+24
View File
@@ -0,0 +1,24 @@
import os
from dotenv import load_dotenv
def pytest_configure(config):
load_dotenv(dotenv_path=".env")
token_var = "SPECKLE_TOKEN"
server_var = "SPECKLE_SERVER_URL"
token = os.getenv(token_var)
server = os.getenv(server_var)
if not token:
raise ValueError(f"Cannot run tests without a {token_var} environment variable")
if not server:
raise ValueError(
f"Cannot run tests without a {server_var} environment variable"
)
# Set the token as an attribute on the config object
config.SPECKLE_TOKEN = token
config.SPECKLE_SERVER_URL = server
+181
View File
@@ -0,0 +1,181 @@
"""Run integration tests with a speckle server."""
import secrets
import string
import pytest
from gql import gql
from speckle_automate import (
AutomationRunData,
AutomationStatus,
run_function,
AutomationContext,
)
from specklepy.api.client import SpeckleClient
from specklepy.objects.base import Base
from main import FunctionInputs, automate_function, get_reference_model
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(request) -> str:
return request.config.SPECKLE_TOKEN
@pytest.fixture()
def speckle_server_url(request) -> str:
"""Provide a speckle server url for the test suite, default to localhost."""
return request.config.SPECKLE_SERVER_URL
@pytest.fixture()
def test_client(speckle_server_url: str, speckle_token: str) -> SpeckleClient:
"""Initialize a SpeckleClient for testing."""
test_client = SpeckleClient(
speckle_server_url, speckle_server_url.startswith("https")
)
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()
# fixture to mock the AutomationRunData that would be generated by a full Automation Run
def fake_automation_run_data(request, test_client: SpeckleClient) -> AutomationRunData:
server_url = request.config.SPECKLE_SERVER_URL
project_id = "4f064f09e6"
model_id = "5a16cf52af"
function_name = "Clash Test"
automation_id = crypto_random_string(10)
automation_name = "Local Test Automation"
automation_revision_id = crypto_random_string(10)
register_new_automation(
project_id,
model_id,
test_client,
automation_id,
automation_name,
automation_revision_id,
)
fake_run_data = AutomationRunData(
project_id=project_id,
model_id=model_id,
branch_name="main",
version_id="2b16327448",
speckle_server_url=server_url,
# These ids would be available with a valid registered Automation definition.
automation_id=automation_id,
automation_revision_id=automation_revision_id,
automation_run_id=crypto_random_string(12),
# These ids would be available with a valid registered Function definition. Can also be faked.
function_id="12345",
function_name=function_name,
function_logo=None,
)
return fake_run_data
def test_function_run(fake_automation_run_data: AutomationRunData, speckle_token: str):
"""Run an integration test for the automate function."""
context = AutomationContext.initialize(fake_automation_run_data, speckle_token)
automate_sdk = run_function(
context,
automate_function,
FunctionInputs(
tolerance=0.1, tolerance_unit="mm", static_model_name="structural"
),
)
assert automate_sdk.run_status == AutomationStatus.SUCCEEDED
@pytest.fixture
def context(fake_automation_run_data: AutomationRunData, speckle_token: str):
return AutomationContext.initialize(fake_automation_run_data, speckle_token)
def test_non_existent_model(context, test_client: SpeckleClient):
with pytest.raises(
Exception, match="The static model named does not exist, skipping the function."
):
get_reference_model(context, "Fake Name")
def test_model_with_no_versions(context, test_client: SpeckleClient):
with pytest.raises(
Exception, match="The static model has no versions, skipping the function."
):
get_reference_model(context, "blank")
def test_same_as_changed_model(context, test_client: SpeckleClient):
with pytest.raises(
Exception,
match="The static model is the same as the changed model, skipping the function.",
):
get_reference_model(context, "hvac")
def test_valid_reference_model(context, test_client: SpeckleClient):
reference_model = get_reference_model(context, "structural")
assert reference_model is not None