Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a26618a4f7 | |||
| eaf370407d | |||
| a2b50fe5a1 | |||
| 7e62f76841 | |||
| fc804f16d3 | |||
| 6c7da24595 | |||
| b284d39328 | |||
| 907185c9bb | |||
| a189a2e1c0 | |||
| 1fad926275 | |||
| 99c147fe2f | |||
| e2adf710b3 | |||
| 9509344533 | |||
| 6fabc6cae6 |
@@ -0,0 +1,150 @@
|
||||
from typing import Deque, Dict, List, Optional, Set, Tuple, Union
|
||||
import bpy
|
||||
from bpy.types import Object, Collection, ID
|
||||
from specklepy.objects.base import Base
|
||||
from bpy_speckle.functions import _report
|
||||
from bpy_speckle.specklepy_extras.commit_object_builder import CommitObjectBuilder, ROOT
|
||||
from specklepy.objects import Base
|
||||
from specklepy.objects.other import Collection as SCollection
|
||||
from attrs import define
|
||||
|
||||
ELEMENTS = "elements"
|
||||
|
||||
def _id(natvive_object: ID) -> str:
|
||||
#NOTE: to avoid naming collisions, we prefix collections and objects differently
|
||||
return f"{type(natvive_object).__name__}:{natvive_object.name_full}"
|
||||
|
||||
def _try_id(natvive_object: Optional[Union[Collection, Object]]) -> Optional[str]:
|
||||
return _id(natvive_object) if natvive_object else None
|
||||
|
||||
def convert_collection_to_speckle(col: Collection) -> SCollection:
|
||||
convered_collection = SCollection(name = col.name_full, collectionType = "Blender Collection", elements = [])
|
||||
convered_collection.applicationId = _id(col)
|
||||
return convered_collection
|
||||
|
||||
@define(slots=True)
|
||||
class BlenderCommitObjectBuilder(CommitObjectBuilder[Object]):
|
||||
|
||||
_collections: Dict[str, SCollection]
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._collections = {}
|
||||
|
||||
def include_object(self, conversion_result: Base, native_object: Object) -> None:
|
||||
|
||||
# Set the Child -> Parent relationships
|
||||
parent = native_object.parent
|
||||
|
||||
parent_collections: Tuple[Collection] = native_object.users_collection # type: ignore
|
||||
parent_collection = parent_collections[0] if len(parent_collections) > 0 else None #NOTE: we don't support objects appearing in more than one collection, for now, we will just take the zeroth one
|
||||
|
||||
app_id = _id(native_object)
|
||||
conversion_result.applicationId = app_id
|
||||
self.converted[app_id] = conversion_result
|
||||
|
||||
# in order or priority, direct parent, direct parent collection, root
|
||||
self.set_relationship(app_id, (_try_id(parent), ELEMENTS), (_try_id(parent_collection), ELEMENTS), (ROOT, ELEMENTS))
|
||||
# if parent_collection:
|
||||
# self._include_collection(parent_collection)
|
||||
|
||||
def ensure_collection(self, col: Collection) -> SCollection:
|
||||
id = _id(col)
|
||||
if id in self._collections:
|
||||
return self._collections[id] # collection already converted!
|
||||
|
||||
# Set the Parent -> Children relationships
|
||||
for c in col.children:
|
||||
#NOTE: There's no falling back to the grandparent, if the direct parent collection wasn't converted, then we we fallback to the root
|
||||
self.set_relationship(_id(c), (id, ELEMENTS), (ROOT, ELEMENTS))
|
||||
|
||||
# Set Child -> Parent relationship
|
||||
# parent = self.find_collection_parent(col)
|
||||
# self.set_relationship(id, (_try_builder_id(parent), ELEMENTS), (ROOT, ELEMENTS))
|
||||
|
||||
convered_collection = convert_collection_to_speckle(col)
|
||||
self.converted[id] = convered_collection
|
||||
self._collections[id] = convered_collection
|
||||
|
||||
return convered_collection
|
||||
|
||||
# def find_collection_parent(self, col: Collection) -> Optional[Collection]:
|
||||
# for p in bpy.data.collections:
|
||||
# if col.name in p.children.keys():
|
||||
# return p
|
||||
# return None
|
||||
|
||||
#TODO: I've started an approach that will not work
|
||||
# Goal #1 get all collections sending
|
||||
# Sync with Claire, ask how we handle this in Rhino with partial selection of layers (proably how I'm expecting it works, but good to double check)
|
||||
# Goal #2 Figure out how to send collections
|
||||
# - all collections
|
||||
# - all collections that contain a child collection that has geometry...
|
||||
# - only collections explicitly selected
|
||||
|
||||
def build_commit_object(self, root_commit_object: Base) -> None:
|
||||
assert(root_commit_object.applicationId in self.converted)
|
||||
|
||||
# Create all collections
|
||||
root_col = self.ensure_collection(bpy.context.scene.collection)
|
||||
root_col.collectionType = "Scene Collection"
|
||||
for col in bpy.context.scene.collection.children_recursive:
|
||||
self.ensure_collection(col)
|
||||
|
||||
objects_to_build = set(self.converted.values())
|
||||
objects_to_build.remove(root_commit_object)
|
||||
|
||||
self.apply_relationships(objects_to_build, root_commit_object)
|
||||
|
||||
assert(isinstance(root_commit_object, SCollection))
|
||||
# Kill unused collections
|
||||
|
||||
def should_remove_unuseful_collection(col: SCollection) -> bool: #TODO: this maybe could be optimised
|
||||
elements = col.elements
|
||||
if not elements: return True
|
||||
|
||||
should_remove_this_col = True
|
||||
|
||||
i = 0
|
||||
while i < len(elements):
|
||||
c = elements[i]
|
||||
if not isinstance(c, SCollection):
|
||||
# col has objects (c)
|
||||
should_remove_this_col = False
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if should_remove_unuseful_collection(c):
|
||||
# c is not useful, kill it
|
||||
del elements[i]
|
||||
else:
|
||||
# col has a child (c) with objects
|
||||
should_remove_this_col = False
|
||||
i += 1
|
||||
continue
|
||||
|
||||
return should_remove_this_col
|
||||
|
||||
if should_remove_unuseful_collection(root_commit_object):
|
||||
_report("WARNING: Only empty collections have been converted!") #TODO: consider raising exception here, to halt the send operation
|
||||
|
||||
|
||||
|
||||
|
||||
# def build_commit_object(self, root_commit_object: Base) -> None:
|
||||
|
||||
# convertedObjects = [x for x in self.converted.values()] # Converted objects, but no collections!
|
||||
# for (id, col) in self._collections.items():
|
||||
# self.converted[id] = col
|
||||
|
||||
# # Apply relationships for all non-collection objects
|
||||
# self.apply_relationships(convertedObjects, root_commit_object)
|
||||
|
||||
# # Remove empty collections
|
||||
# for (id, col) in self._collections.items(): #TODO: XXX: How to ensure empty collections are avoided! Potentially need to traverse from root object down...
|
||||
# if not col.elements:
|
||||
# self.converted.pop(id)
|
||||
|
||||
# self.apply_relationships(convertedObjects, root_commit_object)
|
||||
|
||||
# return
|
||||
@@ -26,8 +26,8 @@ from .util import (
|
||||
)
|
||||
|
||||
SUPPORTED_CURVES = (Line, Polyline, Curve, Arc, Polycurve, Ellipse, Circle)
|
||||
|
||||
CAN_CONVERT_TO_NATIVE = (
|
||||
|
||||
Mesh,
|
||||
*SUPPORTED_CURVES,
|
||||
Instance,
|
||||
@@ -35,7 +35,7 @@ CAN_CONVERT_TO_NATIVE = (
|
||||
|
||||
|
||||
def _has_native_convesion(speckle_object: Base) -> bool:
|
||||
return any(isinstance(speckle_object, t) for t in CAN_CONVERT_TO_NATIVE)
|
||||
return any(isinstance(speckle_object, t) for t in CAN_CONVERT_TO_NATIVE) #or "View" in speckle_object.speckle_type #hack
|
||||
|
||||
def _has_fallback_conversion(speckle_object: Base) -> bool:
|
||||
return any(getattr(speckle_object, alias, None) for alias in DISPLAY_VALUE_PROPERTY_ALIASES)
|
||||
@@ -44,8 +44,6 @@ def can_convert_to_native(speckle_object: Base) -> bool:
|
||||
|
||||
if(_has_native_convesion(speckle_object) or _has_fallback_conversion(speckle_object)):
|
||||
return True
|
||||
|
||||
_report(f"Could not convert unsupported Speckle object: {speckle_object}")
|
||||
return False
|
||||
|
||||
def create_new_object(obj_data: Optional[bpy.types.ID], desired_name: str, counter: int = 0) -> bpy.types.Object:
|
||||
@@ -58,7 +56,7 @@ def create_new_object(obj_data: Optional[bpy.types.ID], desired_name: str, count
|
||||
|
||||
#TODO: This is very slow, and gets slower the more objects you receive with the same name...
|
||||
# We could use a binary/galloping search, and/or cache the name -> index within a receive.
|
||||
if name in bpy.data.objects.keys():
|
||||
if name in bpy.data.objects.keys():
|
||||
#Object already exists, increment counter and try again!
|
||||
return create_new_object(obj_data, desired_name, counter + 1)
|
||||
|
||||
@@ -70,86 +68,93 @@ def set_convert_instances_as(value: str):
|
||||
global convert_instances_as
|
||||
convert_instances_as = value
|
||||
|
||||
def convert_to_native(speckle_object: Base) -> list[Object]:
|
||||
#TODO: Check usages handle exceptions
|
||||
|
||||
def convert_to_native(speckle_object: Base) -> Object:
|
||||
|
||||
speckle_type = type(speckle_object)
|
||||
try:
|
||||
object_name = _generate_object_name(speckle_object)
|
||||
scale = get_scale_factor(speckle_object)
|
||||
|
||||
obj_data: Optional[Union[bpy.types.ID, bpy.types.Object]] = None
|
||||
converted: list[Object] = []
|
||||
object_name = _generate_object_name(speckle_object)
|
||||
scale = get_scale_factor(speckle_object)
|
||||
|
||||
# convert elements/breps
|
||||
if not _has_native_convesion(speckle_object):
|
||||
(obj_data, converted) = element_to_native(speckle_object, object_name, scale)
|
||||
if not obj_data and not converted:
|
||||
_report(f"Unsupported type {speckle_object.speckle_type}")
|
||||
converted: Union[bpy.types.ID, bpy.types.Object, None] = None
|
||||
children: list[Object] = []
|
||||
|
||||
# convert supported geometry
|
||||
elif isinstance(speckle_object, Mesh):
|
||||
obj_data = mesh_to_native(speckle_object, object_name, scale)
|
||||
elif speckle_type in SUPPORTED_CURVES:
|
||||
obj_data = icurve_to_native(speckle_object, object_name, scale)
|
||||
elif isinstance(speckle_object, Instance):
|
||||
if convert_instances_as == "linked_duplicates":
|
||||
(obj_data, converted) = instance_to_native_object(speckle_object, scale)
|
||||
elif convert_instances_as != "collection_instance":
|
||||
obj_data = instance_to_native_collection_instance(speckle_object, scale)
|
||||
else:
|
||||
_report(f"convert_instances_as = '{convert_instances_as}' is not implemented, Instances will be converted as collection instances!")
|
||||
obj_data = instance_to_native_collection_instance(speckle_object, scale)
|
||||
# convert elements/breps
|
||||
if not _has_native_convesion(speckle_object):
|
||||
(converted, children) = display_value_to_native(speckle_object, object_name, scale)
|
||||
if not converted and not children:
|
||||
raise Exception(f"Zero geometry converted from displayValues for {speckle_object}")
|
||||
|
||||
# convert supported geometry
|
||||
elif isinstance(speckle_object, Mesh):
|
||||
converted = mesh_to_native(speckle_object, object_name, scale)
|
||||
elif speckle_type in SUPPORTED_CURVES:
|
||||
converted = icurve_to_native(speckle_object, object_name, scale)
|
||||
# elif "View" in speckle_object.speckle_type:
|
||||
# return view_to_native(speckle_object, object_name, scale)
|
||||
elif isinstance(speckle_object, Instance):
|
||||
if convert_instances_as == "linked_duplicates":
|
||||
(converted, children) = instance_to_native_object(speckle_object, scale)
|
||||
elif convert_instances_as == "collection_instance":
|
||||
converted = instance_to_native_collection_instance(speckle_object, scale)
|
||||
else:
|
||||
_report(f"Unsupported type {speckle_type}")
|
||||
return []
|
||||
except Exception as ex: # conversion error
|
||||
_report(f"Error converting {speckle_object} \n{ex}")
|
||||
return []
|
||||
_report(f"convert_instances_as = '{convert_instances_as}' is not implemented, Instances will be converted as collection instances!")
|
||||
converted = instance_to_native_collection_instance(speckle_object, scale)
|
||||
else:
|
||||
raise Exception(f"Unsupported type {speckle_type}")
|
||||
|
||||
|
||||
blender_object = obj_data if isinstance(obj_data, Object) else create_new_object(obj_data, object_name)
|
||||
if not isinstance(converted, Object):
|
||||
converted = create_new_object(converted, object_name)
|
||||
|
||||
blender_object.speckle.object_id = str(speckle_object.id)
|
||||
blender_object.speckle.enabled = True
|
||||
add_custom_properties(speckle_object, blender_object)
|
||||
converted.speckle.object_id = str(speckle_object.id)
|
||||
converted.speckle.enabled = True
|
||||
add_custom_properties(speckle_object, converted)
|
||||
|
||||
for child in converted:
|
||||
child.parent = blender_object
|
||||
for child in children:
|
||||
child.parent = converted
|
||||
|
||||
converted.append(blender_object)
|
||||
_report(f"Successfully converted {object_name} as {blender_object.type}")
|
||||
return converted
|
||||
|
||||
|
||||
DISPLAY_VALUE_PROPERTY_ALIASES = ["displayValue", "@displayValue", "displayMesh", "@displayMesh", "elements", "@elements"]
|
||||
DISPLAY_VALUE_PROPERTY_ALIASES = ["displayValue", "@displayValue"]
|
||||
ELEMENTS_PROPERTY_ALIASES = ["elements", "@elements"]
|
||||
|
||||
def element_to_native(speckle_object: Base, name: str, scale: float, combineMeshes: bool = True) -> tuple[Optional[bpy.types.Mesh], list[bpy.types.Object]]:
|
||||
|
||||
def display_value_to_native(speckle_object: Base, name: str, scale: float) -> tuple[Optional[bpy.types.Mesh], list[bpy.types.Object]]:
|
||||
return _members_to_native(speckle_object, name, scale, DISPLAY_VALUE_PROPERTY_ALIASES, True)
|
||||
|
||||
def elements_to_native(speckle_object: Base, name: str, scale: float) -> list[bpy.types.Object]:
|
||||
(_, elements) = _members_to_native(speckle_object, name, scale, ELEMENTS_PROPERTY_ALIASES, False)
|
||||
return elements
|
||||
|
||||
def _members_to_native(speckle_object: Base, name: str, scale: float, members: List[str], combineMeshes: bool) -> tuple[Optional[bpy.types.Mesh], list[bpy.types.Object]]:
|
||||
"""
|
||||
Converts a given speckle_object by converting displayValue properties (elements treated the same as displayValues)
|
||||
Converts a given speckle_object by converting specified members
|
||||
|
||||
if combineMeshes == True
|
||||
Converts mesh displayValues as one mesh
|
||||
Converts non-mesh displayValues as child Objects
|
||||
Converts mesh members as one mesh
|
||||
Converts non-mesh members as child Objects
|
||||
if combineMeshes == False
|
||||
Converts all displayValues as child objects (first item of the returned tuple will be None)
|
||||
Converts all members as child objects (first item of the returned tuple will be None)
|
||||
:returns: converted mesh, and any other converted child objects (may happen if members contained non-meshes)
|
||||
"""
|
||||
meshes: list[Mesh] = []
|
||||
elements: list[Base] = []
|
||||
others: list[Base] = []
|
||||
|
||||
#NOTE: raw Mesh elements will be treated like displayValues, which is not ideal, but no connector sends raw Mesh elements so it's fine
|
||||
for alias in DISPLAY_VALUE_PROPERTY_ALIASES:
|
||||
for alias in members:
|
||||
display = getattr(speckle_object, alias, None)
|
||||
|
||||
count = 0
|
||||
MAX_DEPTH = 255 # some large value, to prevent infinite reccursion
|
||||
def seperate(value: Any) -> bool:
|
||||
nonlocal meshes, elements, count, MAX_DEPTH
|
||||
nonlocal meshes, others, count, MAX_DEPTH
|
||||
|
||||
if combineMeshes and isinstance(value, Mesh):
|
||||
meshes.append(value)
|
||||
elif isinstance(value, Base):
|
||||
elements.append(value)
|
||||
others.append(value)
|
||||
elif isinstance(value, list):
|
||||
count += 1
|
||||
if(count > MAX_DEPTH):
|
||||
@@ -165,26 +170,50 @@ def element_to_native(speckle_object: Base, name: str, scale: float, combineMesh
|
||||
_report(f"Traversal of {speckle_object.speckle_type} {speckle_object.id} halted after traversal depth exceeds MAX_DEPTH={MAX_DEPTH}. Are there circular references object structure?")
|
||||
|
||||
|
||||
converted: list[Object] = []
|
||||
children: list[Object] = []
|
||||
mesh = None
|
||||
|
||||
if meshes:
|
||||
mesh = meshes_to_native(speckle_object, meshes, name, scale)
|
||||
mesh = meshes_to_native(speckle_object, meshes, name, scale) #TODO: reconsider passing scale around...
|
||||
|
||||
for item in elements:
|
||||
# add parent type here so we can use it as a blender custom prop
|
||||
# not making it hidden, so it will get added on send as i think it might be helpful? can reconsider
|
||||
item.parent_speckle_type = speckle_object.speckle_type #TODO: consider if this is still useful, as we now properly structure object parenting
|
||||
blender_object = convert_to_native(item)
|
||||
if isinstance(blender_object, list):
|
||||
converted.extend(blender_object)
|
||||
else:
|
||||
add_custom_properties(speckle_object, blender_object)
|
||||
converted.append(blender_object)
|
||||
for item in others:
|
||||
try:
|
||||
blender_object = convert_to_native(item)
|
||||
children.append(blender_object)
|
||||
except Exception as ex:
|
||||
_report(f"Failed to convert display value {item}: {ex}")
|
||||
|
||||
return (mesh, converted)
|
||||
return (mesh, children)
|
||||
|
||||
|
||||
|
||||
def view_to_native(speckle_view, name: str, scale: float) -> bpy.types.Object:
|
||||
native_cam: bpy.types.Camera
|
||||
if name in bpy.data.cameras.keys():
|
||||
native_cam = bpy.data.cameras[name]
|
||||
else:
|
||||
native_cam = bpy.data.cameras.new(name=name)
|
||||
native_cam.lens = 18 # 90° horizontal fov
|
||||
|
||||
cam_obj = create_new_object(native_cam, name)
|
||||
|
||||
scale_factor = get_scale_factor(speckle_view, scale)
|
||||
tx = (speckle_view.origin.x * scale_factor)
|
||||
ty = (speckle_view.origin.y * scale_factor)
|
||||
tz = (speckle_view.origin.z * scale_factor)
|
||||
|
||||
forward = MVector((speckle_view.forwardDirection.x, speckle_view.forwardDirection.y, speckle_view.forwardDirection.z))
|
||||
up = MVector((speckle_view.upDirection.x, speckle_view.upDirection.y, speckle_view.upDirection.z))
|
||||
right = forward.cross(up).normalized()
|
||||
|
||||
cam_obj.matrix_world = MMatrix((
|
||||
(right.x, up.x, -forward.x, tx),
|
||||
(right.y, up.y, -forward.y, ty),
|
||||
(right.z, up.z, -forward.z, tz),
|
||||
(0, 0, 0, 1 )
|
||||
))
|
||||
return cam_obj
|
||||
|
||||
def mesh_to_native(speckle_mesh: Mesh, name: str, scale: float) -> bpy.types.Mesh:
|
||||
return meshes_to_native(speckle_mesh, [speckle_mesh], name, scale)
|
||||
|
||||
@@ -225,8 +254,6 @@ def meshes_to_native(element: Base, meshes: Collection[Mesh], name: str, scale:
|
||||
add_colors(mesh, bm)
|
||||
add_uv_coords(mesh, bm)
|
||||
|
||||
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
|
||||
|
||||
bm.to_mesh(blender_mesh)
|
||||
bm.free()
|
||||
|
||||
@@ -389,18 +416,18 @@ def polycurve_to_native(scurve: Polycurve, bcurve: bpy.types.Curve, scale: float
|
||||
_report(f"Unsupported curve type: {speckle_type}")
|
||||
|
||||
return curves
|
||||
|
||||
def circle_to_native(circle: Circle, bcurve: bpy.types.Curve, units_scale: float) -> list[bpy.types.Spline]:
|
||||
#HACK: violates typing, but it works...
|
||||
circle["firstRadius"] = circle.radius
|
||||
circle["secondRadius"] = circle.radius
|
||||
return ellipse_to_native(circle, bcurve, units_scale)
|
||||
|
||||
def ellipse_to_native(ellipse: Ellipse, bcurve: bpy.types.Curve, units_scale: float) -> list[bpy.types.Spline]:
|
||||
plane = ellipse.plane
|
||||
def ellipse_to_native(ellipse: Union[Ellipse, Circle], bcurve: bpy.types.Curve, units_scale: float) -> list[bpy.types.Spline]:
|
||||
|
||||
radX: float
|
||||
radY: float
|
||||
if isinstance(ellipse, Ellipse):
|
||||
radX = ellipse.firstRadius * units_scale
|
||||
radY = ellipse.secondRadius * units_scale
|
||||
else:
|
||||
radX = ellipse.radius * units_scale
|
||||
radY = ellipse.radius * units_scale
|
||||
|
||||
radX = ellipse.firstRadius * units_scale
|
||||
radY = ellipse.secondRadius * units_scale
|
||||
|
||||
D = 0.5522847498307936 # (4/3)*tan(pi/8)
|
||||
|
||||
@@ -424,7 +451,7 @@ def ellipse_to_native(ellipse: Ellipse, bcurve: bpy.types.Curve, units_scale: fl
|
||||
(-radX, 0.0, 0.0),
|
||||
(0.0, -radY, 0.0),
|
||||
]
|
||||
transform = plane_to_native_transform(plane, units_scale)
|
||||
transform = plane_to_native_transform(ellipse.plane, units_scale)
|
||||
|
||||
spline = bcurve.splines.new("BEZIER")
|
||||
spline.bezier_points.add(len(points) - 1)
|
||||
@@ -453,22 +480,20 @@ def icurve_to_native_spline(speckle_curve: Base, blender_curve: bpy.types.Curve,
|
||||
elif isinstance(speckle_curve, Polyline):
|
||||
spline = polyline_to_native(speckle_curve, blender_curve, scale)
|
||||
elif isinstance(speckle_curve, Arc):
|
||||
spline = arc_to_native(speckle_curve, blender_curve, scale)
|
||||
elif isinstance(speckle_curve, Ellipse):
|
||||
spline = ellipse_to_native(speckle_curve, blender_curve, scale)
|
||||
elif isinstance(speckle_curve, Circle):
|
||||
spline = circle_to_native(speckle_curve, blender_curve, scale)
|
||||
spline = arc_to_native(speckle_curve, blender_curve, scale)
|
||||
elif isinstance(speckle_curve, Ellipse) or isinstance(speckle_curve, Circle):
|
||||
spline = ellipse_to_native(speckle_curve, blender_curve, scale)
|
||||
else:
|
||||
raise TypeError(f"{speckle_curve} is not a supported curve type. Supported types: {SUPPORTED_CURVES}")
|
||||
|
||||
return [spline] if spline is not None else []
|
||||
|
||||
|
||||
def icurve_to_native(speckle_curve: Base, name: str, scale: float) -> Optional[bpy.types.Curve]:
|
||||
def icurve_to_native(speckle_curve: Base, name: str, scale: float) -> bpy.types.Curve:
|
||||
curve_type = type(speckle_curve)
|
||||
if curve_type not in SUPPORTED_CURVES:
|
||||
_report(f"Unsupported curve type: {curve_type}")
|
||||
return None
|
||||
raise Exception(f"Unsupported curve type: {curve_type}")
|
||||
|
||||
blender_curve = (
|
||||
bpy.data.curves[name]
|
||||
if name in bpy.data.curves.keys()
|
||||
@@ -542,20 +567,20 @@ def instance_to_native_object(instance: Instance, scale: float) -> Tuple[bpy.typ
|
||||
native_instance = create_new_object(None, name) #Instance will be empty
|
||||
native_instance.empty_display_size = 0
|
||||
for geo in definition.geometry:
|
||||
native_elements.append(convert_to_native(geo)[-1])
|
||||
native_elements.append(convert_to_native(geo))
|
||||
else:
|
||||
native_instance = convert_to_native(instance.definition)[-1] # Convert assuming that definition is convertable
|
||||
native_instance = convert_to_native(instance.definition)
|
||||
|
||||
instance_transform = transform_to_native(instance.transform, scale)
|
||||
instance_transform_inverted = instance_transform.inverted()
|
||||
native_instance.matrix_world = instance_transform
|
||||
|
||||
(_, elements_on_instance) = element_to_native(instance, name, scale)
|
||||
elements_on_instance = elements_to_native(instance, name, scale)
|
||||
for c in elements_on_instance:
|
||||
c.matrix_world = instance_transform_inverted @ c.matrix_world #Undo the instance transform on elements
|
||||
|
||||
native_elements.extend(elements_on_instance)
|
||||
|
||||
|
||||
return (native_instance, native_elements) #TODO: need to double check that all child objects have custom props attached correctly
|
||||
|
||||
def instance_to_native_collection_instance(instance: Instance, scale: float) -> bpy.types.Object:
|
||||
@@ -575,7 +600,7 @@ def instance_to_native_collection_instance(instance: Instance, scale: float) ->
|
||||
collection_def = _instance_definition_to_native(instance.definition)
|
||||
|
||||
# Convert elements as children of collection instance object
|
||||
(_, elements) = element_to_native(instance, name, scale, False)
|
||||
elements = elements_to_native(instance, name, scale)
|
||||
|
||||
instance_transform = transform_to_native(instance.transform, scale)
|
||||
instance_transform_inverted = instance_transform.inverted()
|
||||
@@ -612,7 +637,7 @@ def _instance_definition_to_native(definition: Union[Base, BlockDefinition]) ->
|
||||
|
||||
for geo in geometry:
|
||||
if not geo: continue
|
||||
converted = convert_to_native(geo)[-1] #NOTE: we assume the last item is the root converted item
|
||||
converted = convert_to_native(geo) #NOTE: we assume the last item is the root converted item
|
||||
link_object_to_collection_nested(converted, native_def)
|
||||
|
||||
|
||||
|
||||
+176
-119
@@ -1,75 +1,92 @@
|
||||
from typing import Dict, Iterable, Optional, Tuple
|
||||
from typing import Dict, Iterable, List, Optional, Tuple, Union, cast
|
||||
import bpy
|
||||
from bpy.types import Depsgraph, MeshPolygon, Object
|
||||
from bpy.types import (
|
||||
Depsgraph,
|
||||
MeshPolygon,
|
||||
Object,
|
||||
Curve as NCurve,
|
||||
Mesh as NMesh,
|
||||
)
|
||||
from deprecated import deprecated
|
||||
from mathutils.geometry import interpolate_bezier
|
||||
from mathutils import (
|
||||
Matrix as MMatrix,
|
||||
Vector as MVector,
|
||||
)
|
||||
from specklepy.objects import Base
|
||||
from specklepy.objects.other import BlockInstance, BlockDefinition, RenderMaterial, Transform
|
||||
from specklepy.objects.geometry import (
|
||||
Mesh, Curve, Interval, Box, Point, Polyline
|
||||
)
|
||||
from specklepy.objects.other import *
|
||||
from bpy_speckle.functions import _report
|
||||
from bpy_speckle.convert.to_native import OBJECT_NAME_SEPERATOR, SPECKLE_ID_LENGTH
|
||||
from bpy_speckle.convert.util import (
|
||||
get_blender_custom_properties,
|
||||
make_knots,
|
||||
nurb_make_curve,
|
||||
to_argb_int,
|
||||
)
|
||||
from bpy_speckle.functions import _report
|
||||
|
||||
UNITS = "m"
|
||||
class ConversionSkippedException(Exception):
|
||||
pass
|
||||
|
||||
Units: str = "m" # The desired final units to send
|
||||
UnitsScale: float = 1 # The scale factor conversions need to apply to position data to get to the desired units
|
||||
|
||||
CAN_CONVERT_TO_SPECKLE = ("MESH", "CURVE", "EMPTY")
|
||||
|
||||
|
||||
def convert_to_speckle(raw_blender_object: Object, scale: float, units: str, depsgraph: Optional[Depsgraph]) -> Optional[list]:
|
||||
global UNITS
|
||||
UNITS = units
|
||||
def convert_to_speckle(raw_blender_object: Object, units_scale: float, units: str, depsgraph: Optional[Depsgraph]) -> Base:
|
||||
"""
|
||||
Converts supported 1 blender objects to 1 speckle object (potentially with children)
|
||||
:param raw_blender_object: the blender object (unevaluated by a Depsgraph) to convert
|
||||
:param units_scale: The scale factor conversions need to apply to position data to get to the desired units
|
||||
:param units: The desired final units to send
|
||||
:param depsgraph: Optional depsgraph if provided will evaluate modifiers on geometry data
|
||||
:return: The Converted blender object
|
||||
"""
|
||||
global Units, UnitsScale
|
||||
Units = units
|
||||
UnitsScale = units_scale
|
||||
|
||||
blender_type = raw_blender_object.type
|
||||
if blender_type not in CAN_CONVERT_TO_SPECKLE:
|
||||
return None
|
||||
raise ConversionSkippedException(f"Objects of type {blender_type} are not supported")
|
||||
|
||||
blender_object: Object = (
|
||||
blender_object = cast(Object, (
|
||||
raw_blender_object.evaluated_get(depsgraph)
|
||||
if depsgraph
|
||||
else raw_blender_object
|
||||
))
|
||||
|
||||
converted: Optional[Base] = None
|
||||
if blender_type == "MESH":
|
||||
converted = mesh_to_speckle(blender_object, cast(NMesh, blender_object.data))
|
||||
elif blender_type == "CURVE":
|
||||
converted = curve_to_speckle(blender_object, cast(NCurve, blender_object.data))
|
||||
elif blender_type == "EMPTY":
|
||||
converted = empty_to_speckle(blender_object)
|
||||
|
||||
if not converted:
|
||||
raise Exception("Conversion returned None")
|
||||
|
||||
converted["properties"] = get_blender_custom_properties(raw_blender_object) #NOTE: Depsgraph copies don't have custom properties so we use the raw version
|
||||
|
||||
# Set object transform #TODO: this could be deprecated once we add proper geometry instancing support
|
||||
if blender_type != "EMPTY":
|
||||
converted["properties"]["transform"] = transform_to_speckle(
|
||||
blender_object.matrix_world
|
||||
)
|
||||
|
||||
converted = None
|
||||
if blender_type == "MESH":
|
||||
converted = mesh_to_speckle(blender_object, blender_object.data, scale)
|
||||
elif blender_type == "CURVE":
|
||||
converted = icurve_to_speckle(blender_object, blender_object.data, scale)
|
||||
elif blender_type == "EMPTY":
|
||||
converted = empty_to_speckle(blender_object, scale)
|
||||
if not converted:
|
||||
return None
|
||||
return converted
|
||||
|
||||
speckle_objects = []
|
||||
if isinstance(converted, list):
|
||||
speckle_objects.extend([c for c in converted if c != None])
|
||||
else:
|
||||
speckle_objects.append(converted)
|
||||
def mesh_to_speckle(blender_object: Object, data: bpy.types.Mesh) -> Base:
|
||||
b = Base()
|
||||
b["name"] = to_speckle_name(blender_object)
|
||||
b["@displayValue"] = mesh_to_speckle_meshes(blender_object, data)
|
||||
return b
|
||||
|
||||
for so in speckle_objects:
|
||||
so["properties"] = get_blender_custom_properties(raw_blender_object) #NOTE: Depsgraph copies don't have custom properties so we use the raw version
|
||||
so["applicationId"] = so.properties.pop("applicationId", None)
|
||||
|
||||
|
||||
# Set object transform
|
||||
if blender_type != "EMPTY": #TODO: this could be deprecated once we add proper instancing support
|
||||
so["properties"]["transform"] = transform_to_speckle(
|
||||
blender_object.matrix_world
|
||||
)
|
||||
|
||||
return speckle_objects
|
||||
|
||||
def mesh_to_speckle(blender_object: Object, data: bpy.types.Mesh, scale: float = 1.0) -> List[Mesh]:
|
||||
#if data.loop_triangles is None or len(data.loop_triangles) < 1:
|
||||
# data.calc_loop_triangles()
|
||||
def mesh_to_speckle_meshes(blender_object: Object, data: bpy.types.Mesh) -> List[Mesh]:
|
||||
|
||||
# Categorise polygons by material index
|
||||
submesh_data: Dict[int, List[MeshPolygon]] = {}
|
||||
@@ -79,8 +96,8 @@ def mesh_to_speckle(blender_object: Object, data: bpy.types.Mesh, scale: float =
|
||||
submesh_data[p.material_index] = []
|
||||
submesh_data[p.material_index].append(p)
|
||||
|
||||
transform = blender_object.matrix_world
|
||||
scaled_vertices = [tuple(transform @ x.co * scale) for x in data.vertices]
|
||||
transform = cast(MMatrix, blender_object.matrix_world)
|
||||
scaled_vertices = [tuple(transform @ x.co * UnitsScale) for x in data.vertices]
|
||||
|
||||
# Create Speckle meshes for each material
|
||||
submeshes = []
|
||||
@@ -110,7 +127,8 @@ def mesh_to_speckle(blender_object: Object, data: bpy.types.Mesh, scale: float =
|
||||
|
||||
if data.uv_layers.active:
|
||||
vt = data.uv_layers.active.data[index_counter]
|
||||
m_texcoords.extend([vt.uv.x, vt.uv.y])
|
||||
uv = cast(MVector, vt.uv)
|
||||
m_texcoords.extend([uv.x, uv.y])
|
||||
|
||||
m_faces.append(index_mapping[u_index])
|
||||
index_counter += 1
|
||||
@@ -120,7 +138,7 @@ def mesh_to_speckle(blender_object: Object, data: bpy.types.Mesh, scale: float =
|
||||
faces=m_faces,
|
||||
colors=[],
|
||||
textureCoordinates=m_texcoords,
|
||||
units=UNITS,
|
||||
units=Units,
|
||||
area = mesh_area,
|
||||
bbox=Box(area=0.0, volume=0.0),
|
||||
)
|
||||
@@ -134,24 +152,23 @@ def mesh_to_speckle(blender_object: Object, data: bpy.types.Mesh, scale: float =
|
||||
return submeshes
|
||||
|
||||
|
||||
def bezier_to_speckle(matrix: MMatrix, spline: bpy.types.Spline, scale: float, name: Optional[str] = None) -> Curve:
|
||||
def bezier_to_speckle(matrix: MMatrix, spline: bpy.types.Spline, name: Optional[str] = None) -> Curve:
|
||||
degree = 3
|
||||
closed = spline.use_cyclic_u
|
||||
|
||||
points = []
|
||||
points: List[Tuple[MVector]] = []
|
||||
for i, bp in enumerate(spline.bezier_points):
|
||||
if i > 0:
|
||||
points.append(tuple(matrix @ bp.handle_left * scale))
|
||||
points.append(tuple(matrix @ bp.co * scale))
|
||||
points.append(tuple(matrix @ bp.handle_left * UnitsScale))
|
||||
points.append(tuple(matrix @ bp.co * UnitsScale))
|
||||
if i < len(spline.bezier_points) - 1:
|
||||
points.append(tuple(matrix @ bp.handle_right * scale))
|
||||
points.append(tuple(matrix @ bp.handle_right * UnitsScale))
|
||||
|
||||
if closed:
|
||||
points.extend(
|
||||
(
|
||||
tuple(matrix @ spline.bezier_points[-1].handle_right * scale),
|
||||
tuple(matrix @ spline.bezier_points[0].handle_left * scale),
|
||||
tuple(matrix @ spline.bezier_points[0].co * scale),
|
||||
tuple(matrix @ spline.bezier_points[-1].handle_right * UnitsScale),
|
||||
tuple(matrix @ spline.bezier_points[0].handle_left * UnitsScale),
|
||||
tuple(matrix @ spline.bezier_points[0].co * UnitsScale),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -181,13 +198,13 @@ def bezier_to_speckle(matrix: MMatrix, spline: bpy.types.Spline, scale: float, n
|
||||
volume=0,
|
||||
length=length,
|
||||
domain=domain,
|
||||
units=UNITS,
|
||||
units=Units,
|
||||
bbox=Box(area=0.0, volume=0.0),
|
||||
displayValue = bezier_to_speckle_polyline(matrix, spline, scale, length),
|
||||
displayValue = bezier_to_speckle_polyline(matrix, spline, length),
|
||||
)
|
||||
|
||||
|
||||
def nurbs_to_speckle(matrix: MMatrix, spline: bpy.types.Spline, scale: float, name: Optional[str] = None) -> Curve:
|
||||
def nurbs_to_speckle(matrix: MMatrix, spline: bpy.types.Spline, name: Optional[str] = None) -> Curve:
|
||||
|
||||
degree = spline.order_u - 1
|
||||
knots = make_knots(spline)
|
||||
@@ -198,7 +215,7 @@ def nurbs_to_speckle(matrix: MMatrix, spline: bpy.types.Spline, scale: float, na
|
||||
weights = [pt.weight for pt in spline.points]
|
||||
is_rational = all(w == weights[0] for w in weights)
|
||||
|
||||
points = [tuple(matrix @ pt.co.xyz * scale) for pt in spline.points]
|
||||
points = [tuple(matrix @ pt.co.xyz * UnitsScale) for pt in spline.points]
|
||||
|
||||
flattend_points = []
|
||||
for row in points: flattend_points.extend(row)
|
||||
@@ -226,12 +243,12 @@ def nurbs_to_speckle(matrix: MMatrix, spline: bpy.types.Spline, scale: float, na
|
||||
volume=0,
|
||||
length=length,
|
||||
domain=domain,
|
||||
units=UNITS,
|
||||
units=Units,
|
||||
bbox=Box(area=0.0, volume=0.0),
|
||||
displayValue=nurbs_to_speckle_polyline(matrix, spline, scale, length),
|
||||
displayValue=nurbs_to_speckle_polyline(matrix, spline, length),
|
||||
)
|
||||
|
||||
def nurbs_to_speckle_polyline(matrix: MMatrix, spline: bpy.types.Spline, scale: float, length: Optional[float] = None) -> Polyline:
|
||||
def nurbs_to_speckle_polyline(matrix: MMatrix, spline: bpy.types.Spline, length: Optional[float] = None) -> Polyline:
|
||||
"""
|
||||
Samples a nurbs curve with resolution_u creating a polyline
|
||||
"""
|
||||
@@ -241,7 +258,7 @@ def nurbs_to_speckle_polyline(matrix: MMatrix, spline: bpy.types.Spline, scale:
|
||||
scaled_point = matrix @ MVector((
|
||||
sampled_points[i + 0],
|
||||
sampled_points[i + 1],
|
||||
sampled_points[i + 2])) * scale
|
||||
sampled_points[i + 2])) * UnitsScale
|
||||
|
||||
points.append(scaled_point.x)
|
||||
points.append(scaled_point.y)
|
||||
@@ -253,7 +270,7 @@ def nurbs_to_speckle_polyline(matrix: MMatrix, spline: bpy.types.Spline, scale:
|
||||
|
||||
|
||||
#Inspired by https://blender.stackexchange.com/a/689 (CC BY-SA 3.0)
|
||||
def bezier_to_speckle_polyline(matrix: MMatrix, spline: bpy.types.Spline, scale: float, length: Optional[float] = None) -> Optional[Polyline]:
|
||||
def bezier_to_speckle_polyline(matrix: MMatrix, spline: bpy.types.Spline, length: Optional[float] = None) -> Optional[Polyline]:
|
||||
"""
|
||||
Samples a Bézier curve with resolution_u creating a polyline
|
||||
"""
|
||||
@@ -277,7 +294,7 @@ def bezier_to_speckle_polyline(matrix: MMatrix, spline: bpy.types.Spline, scale:
|
||||
|
||||
_points = interpolate_bezier(knot1, handle1, handle2, knot2, R)
|
||||
for p in _points:
|
||||
scaled_point = matrix @ p * scale
|
||||
scaled_point = matrix @ p * UnitsScale
|
||||
points.append(scaled_point.x)
|
||||
points.append(scaled_point.y)
|
||||
points.append(scaled_point.z)
|
||||
@@ -286,8 +303,17 @@ def bezier_to_speckle_polyline(matrix: MMatrix, spline: bpy.types.Spline, scale:
|
||||
domain = Interval(start=0, end=length, totalChildrenCount=0)
|
||||
return Polyline(value=points, closed = spline.use_cyclic_u, domain=domain, area=0, len=length)
|
||||
|
||||
def poly_to_speckle(matrix: MMatrix, spline: bpy.types.Spline, scale: float, name: Optional[str] = None) -> Polyline:
|
||||
points = [tuple(matrix @ pt.co.xyz * scale) for pt in spline.points]
|
||||
_QUICK_TEST_NAME_LENGTH = SPECKLE_ID_LENGTH + len(OBJECT_NAME_SEPERATOR)
|
||||
|
||||
def to_speckle_name(blender_object: bpy.types.ID) -> str:
|
||||
does_name_contain_id = len(blender_object.name) > _QUICK_TEST_NAME_LENGTH and OBJECT_NAME_SEPERATOR in blender_object.name
|
||||
if does_name_contain_id:
|
||||
return blender_object.name.rsplit(OBJECT_NAME_SEPERATOR, 1)[0]
|
||||
else:
|
||||
return blender_object.name
|
||||
|
||||
def poly_to_speckle(matrix: MMatrix, spline: bpy.types.Spline, name: Optional[str] = None) -> Polyline:
|
||||
points = [tuple(matrix @ pt.co.xyz * UnitsScale) for pt in spline.points]
|
||||
|
||||
flattend_points = []
|
||||
for row in points: flattend_points.extend(row)
|
||||
@@ -302,40 +328,48 @@ def poly_to_speckle(matrix: MMatrix, spline: bpy.types.Spline, scale: float, nam
|
||||
domain=domain,
|
||||
bbox=Box(area=0.0, volume=0.0),
|
||||
area=0,
|
||||
units=UNITS,
|
||||
units=Units,
|
||||
)
|
||||
|
||||
|
||||
def icurve_to_speckle(blender_object: Object, data: bpy.types.Curve, scale=1.0) -> Optional[List[Base]]:
|
||||
UNITS = "m" if bpy.context.scene.unit_settings.system == "METRIC" else "ft"
|
||||
def curve_to_speckle(blender_object: Object, data: bpy.types.Curve) -> Base:
|
||||
b = Base()
|
||||
(meshes, curves) = curve_to_speckle_geometry(blender_object, data)
|
||||
if meshes:
|
||||
b["@displayValue"] = meshes
|
||||
|
||||
if blender_object.type != "CURVE":
|
||||
return None
|
||||
b["name"] = to_speckle_name(blender_object)
|
||||
b["@elements"] = curves
|
||||
return b
|
||||
|
||||
blender_object = blender_object.evaluated_get(bpy.context.view_layer.depsgraph)
|
||||
def curve_to_speckle_geometry(blender_object: Object, data: bpy.types.Curve) -> Tuple[List[Mesh], List[Base]]:
|
||||
assert(blender_object.type == "CURVE")
|
||||
|
||||
mat = blender_object.matrix_world
|
||||
blender_object = cast(Object, blender_object.evaluated_get(bpy.context.view_layer.depsgraph))
|
||||
|
||||
curves = []
|
||||
matrix = cast(MMatrix, blender_object.matrix_world)
|
||||
|
||||
meshes: List[Mesh] = []
|
||||
curves: List[Base] = []
|
||||
|
||||
#TODO: Could we support this better?
|
||||
if data.bevel_mode == "OBJECT" and data.bevel_object != None:
|
||||
mesh = mesh_to_speckle(blender_object, blender_object.to_mesh(), scale)
|
||||
curves.extend(mesh)
|
||||
meshes = mesh_to_speckle_meshes(blender_object, blender_object.to_mesh())
|
||||
|
||||
for spline in data.splines:
|
||||
if spline.type == "BEZIER":
|
||||
curves.append(bezier_to_speckle(mat, spline, scale, blender_object.name))
|
||||
curves.append(bezier_to_speckle(matrix, spline, to_speckle_name(blender_object)))
|
||||
|
||||
elif spline.type == "NURBS":
|
||||
curves.append(nurbs_to_speckle(mat, spline, scale, blender_object.name))
|
||||
curves.append(nurbs_to_speckle(matrix, spline, to_speckle_name(blender_object)))
|
||||
|
||||
elif spline.type == "POLY":
|
||||
curves.append(poly_to_speckle(mat, spline, scale, blender_object.name))
|
||||
curves.append(poly_to_speckle(matrix, spline, to_speckle_name(blender_object)))
|
||||
|
||||
return curves
|
||||
return (meshes, curves)
|
||||
|
||||
@deprecated
|
||||
def ngons_to_speckle_polylines(blender_object: Object, data: bpy.types.Mesh, scale=1.0) -> Optional[List[Polyline]]:
|
||||
def ngons_to_speckle_polylines(blender_object: Object, data: bpy.types.Mesh) -> Optional[List[Polyline]]:
|
||||
UNITS = "m" if bpy.context.scene.unit_settings.system == "METRIC" else "ft"
|
||||
|
||||
if blender_object.type != "MESH":
|
||||
@@ -348,7 +382,7 @@ def ngons_to_speckle_polylines(blender_object: Object, data: bpy.types.Mesh, sca
|
||||
for i, poly in enumerate(data.polygons):
|
||||
value = []
|
||||
for v in poly.vertices:
|
||||
value.extend(mat @ verts[v].co * scale)
|
||||
value.extend(mat @ verts[v].co * UnitsScale)
|
||||
|
||||
domain = Interval(start=0, end=1)
|
||||
poly = Polyline(
|
||||
@@ -371,24 +405,30 @@ def material_to_speckle(blender_mat: bpy.types.Material) -> RenderMaterial:
|
||||
speckle_mat = RenderMaterial()
|
||||
speckle_mat.name = blender_mat.name
|
||||
|
||||
if blender_mat.use_nodes is True and blender_mat.node_tree.nodes.get(
|
||||
"Principled BSDF"
|
||||
):
|
||||
inputs = blender_mat.node_tree.nodes["Principled BSDF"].inputs
|
||||
speckle_mat.diffuse = to_argb_int(inputs["Base Color"].default_value)
|
||||
speckle_mat.emissive = to_argb_int(inputs["Emission"].default_value)
|
||||
speckle_mat.roughness = inputs["Roughness"].default_value
|
||||
speckle_mat.metalness = inputs["Metallic"].default_value
|
||||
speckle_mat.opacity = inputs["Alpha"].default_value
|
||||
if blender_mat.use_nodes:
|
||||
if blender_mat.node_tree.nodes.get("Principled BSDF"):
|
||||
inputs = blender_mat.node_tree.nodes["Principled BSDF"].inputs
|
||||
speckle_mat.diffuse = to_argb_int(inputs["Base Color"].default_value)
|
||||
speckle_mat.emissive = to_argb_int(inputs["Emission"].default_value)
|
||||
speckle_mat.roughness = inputs["Roughness"].default_value
|
||||
speckle_mat.metalness = inputs["Metallic"].default_value
|
||||
speckle_mat.opacity = inputs["Alpha"].default_value
|
||||
return speckle_mat
|
||||
elif blender_mat.node_tree.nodes.get("Diffuse BSDF"):
|
||||
inputs = blender_mat.node_tree.nodes["Diffuse BSDF"].inputs
|
||||
speckle_mat.diffuse = to_argb_int(inputs["Color"].default_value)
|
||||
speckle_mat.roughness = inputs["Roughness"].default_value
|
||||
return speckle_mat
|
||||
#TODO: Support more shaders
|
||||
|
||||
else:
|
||||
speckle_mat.diffuse = to_argb_int(blender_mat.diffuse_color)
|
||||
speckle_mat.metalness = blender_mat.metallic
|
||||
speckle_mat.roughness = blender_mat.roughness
|
||||
# fallback to standard material props
|
||||
speckle_mat.diffuse = to_argb_int(blender_mat.diffuse_color)
|
||||
speckle_mat.metalness = blender_mat.metallic
|
||||
speckle_mat.roughness = blender_mat.roughness
|
||||
|
||||
return speckle_mat
|
||||
|
||||
|
||||
@deprecated
|
||||
def material_to_speckle_old(blender_object: Object) -> Optional[RenderMaterial]:
|
||||
"""Create and return a render material from a blender object"""
|
||||
if not getattr(blender_object.data, "materials", None):
|
||||
@@ -401,48 +441,65 @@ def material_to_speckle_old(blender_object: Object) -> Optional[RenderMaterial]:
|
||||
return material_to_speckle(blender_mat)
|
||||
|
||||
|
||||
def transform_to_speckle(blender_transform: Iterable[Iterable[float]], scale=1.0) -> Transform:
|
||||
value = [y for x in blender_transform for y in x]
|
||||
def transform_to_speckle(blender_transform: Union[Iterable[Iterable[float]], MMatrix]) -> Transform:
|
||||
iterable_transform = cast(Iterable[Iterable[float]], blender_transform) #NOTE: Matrix are itterable, even if type hinting says they are not
|
||||
value = [y for x in iterable_transform for y in x]
|
||||
# scale the translation
|
||||
for i in (3, 7, 11):
|
||||
value[i] *= scale
|
||||
value[i] *= UnitsScale
|
||||
|
||||
return Transform(value=value, units=UNITS)
|
||||
return Transform(value=value, units=Units)
|
||||
|
||||
|
||||
def block_def_to_speckle(blender_definition: bpy.types.Collection, scale=1.0) -> BlockDefinition:
|
||||
def block_def_to_speckle(blender_definition: bpy.types.Collection) -> BlockDefinition:
|
||||
geometry = []
|
||||
for geo in blender_definition.objects:
|
||||
geometry.extend(convert_to_speckle(geo, scale, UNITS, None))
|
||||
try:
|
||||
#TODO: right now, geometry will be a flat list of objects. Eventually we will want to preseve the parent relationship
|
||||
geometry.append(convert_to_speckle(geo, UnitsScale, Units, None))
|
||||
except ConversionSkippedException as ex:
|
||||
_report(f"Skipped converting '{geo.name_full}' inside collection instance: '{ex}")
|
||||
except Exception as ex:
|
||||
_report(f"Failed to converted '{geo.name_full}' inside collection instance: '{ex}'")
|
||||
|
||||
block_def = BlockDefinition(
|
||||
units=UNITS,
|
||||
name=blender_definition.name,
|
||||
units=Units,
|
||||
name=to_speckle_name(blender_definition),
|
||||
geometry=geometry,
|
||||
basePoint=Point(units=UNITS),
|
||||
basePoint=Point(units=Units),
|
||||
)
|
||||
blender_props = get_blender_custom_properties(blender_definition)
|
||||
block_def.applicationId = blender_props.pop("applicationId", None)
|
||||
# blender_props = get_blender_custom_properties(blender_definition)
|
||||
# block_def.applicationId = blender_props.pop("applicationId", None) #TODO: remove?
|
||||
return block_def
|
||||
|
||||
|
||||
def block_instance_to_speckle(blender_instance: Object, scale=1.0) -> BlockInstance:
|
||||
def block_instance_to_speckle(blender_instance: Object) -> BlockInstance:
|
||||
return BlockInstance(
|
||||
blockDefinition=block_def_to_speckle(
|
||||
blender_instance.instance_collection, scale
|
||||
blender_instance.instance_collection
|
||||
),
|
||||
transform=transform_to_speckle(blender_instance.matrix_world),
|
||||
name=blender_instance.name,
|
||||
units=UNITS,
|
||||
name=to_speckle_name(blender_instance),
|
||||
units=Units,
|
||||
)
|
||||
|
||||
|
||||
def empty_to_speckle(blender_object: Object, scale=1.0) -> Optional[BlockInstance]:
|
||||
def empty_to_speckle(blender_object: Object) -> Union[BlockInstance, Base]:
|
||||
# probably an instance collection (block) so let's try it
|
||||
try:
|
||||
geo = blender_object.instance_collection.objects.items()
|
||||
return block_instance_to_speckle(blender_object, scale)
|
||||
except AttributeError as err:
|
||||
_report(
|
||||
f"No instance collection found in empty. Skipping object {blender_object.name}"
|
||||
)
|
||||
return None
|
||||
|
||||
if blender_object.instance_collection and blender_object.instance_type == "COLLECTION":
|
||||
return block_instance_to_speckle(blender_object)
|
||||
else:
|
||||
#raise ConversionSkippedException("Sending non-collection instance empties are not currently supported")
|
||||
wrapper = Base()
|
||||
wrapper["@displayValue"] = matrix_to_speckle_point(cast(MMatrix, blender_object.matrix_world))
|
||||
return wrapper
|
||||
#TODO: we could do a Empty -> Point conversion here. However, the viewer (and likly other apps) don't support a pont with "elements"
|
||||
#return matrix_to_speckle_point(cast(MMatrix, blender_object.matrix_world))
|
||||
|
||||
|
||||
def matrix_to_speckle_point(matrix: MMatrix, units_scale: float = 1.0) -> Point:
|
||||
transformed_pos = cast(MVector, matrix @ MVector((0,0,0)) * units_scale)
|
||||
return Point(x = transformed_pos.x,
|
||||
y = transformed_pos.y,
|
||||
z = transformed_pos.z)
|
||||
@@ -235,7 +235,7 @@ ignored_keys = {
|
||||
"_chunkable",
|
||||
}
|
||||
|
||||
def get_blender_custom_properties(obj, max_depth: int = 1000):
|
||||
def get_blender_custom_properties(obj, max_depth: int = 200):
|
||||
if max_depth < 0:
|
||||
return obj
|
||||
|
||||
|
||||
+27
-18
@@ -1,4 +1,10 @@
|
||||
from bpy_speckle.clients import speckle_clients
|
||||
from typing import Callable, Set
|
||||
|
||||
import bpy
|
||||
from specklepy.objects.base import Base
|
||||
from bpy_speckle.properties.scene import SpeckleSceneSettings
|
||||
|
||||
from bpy_speckle.specklepy_extras.traversal import GraphTraversal, TraversalRule
|
||||
|
||||
"""
|
||||
Speckle functions
|
||||
@@ -44,29 +50,32 @@ def get_scale_length(units: str) -> float:
|
||||
Client, user, and stream functions
|
||||
"""
|
||||
|
||||
elements_aliases: Set[str] = {"elements", "@elements"}
|
||||
ignore_props: Set[str] = {"@blockDefinition", "displayValue", "@displayValue", "units", "id", "applicationId"}
|
||||
|
||||
def _check_speckle_client_user_stream(scene):
|
||||
def get_default_traversal_func(can_convert_to_native: Callable[[Base], bool]) -> GraphTraversal:
|
||||
"""
|
||||
Verify that there is a valid user and stream
|
||||
Traversal func for traversing a speckle commit object
|
||||
"""
|
||||
speckle = scene.speckle
|
||||
|
||||
user = (
|
||||
speckle.users[int(speckle.active_user)]
|
||||
if len(speckle.users) > int(speckle.active_user)
|
||||
else None
|
||||
convertable_rule = TraversalRule(
|
||||
[can_convert_to_native],
|
||||
lambda _: [i for i in elements_aliases if i not in ignore_props],
|
||||
)
|
||||
|
||||
if user is None:
|
||||
print("No users loaded.")
|
||||
|
||||
stream = (
|
||||
user.streams[user.active_stream]
|
||||
if len(user.streams) > user.active_stream
|
||||
else None
|
||||
ignore_result_rule = TraversalRule(
|
||||
[lambda o: "Objects.Structural.Results" in o.speckle_type, #Sadly, this one is nessasary to avoid double conversion...
|
||||
lambda o: "Objects.BuiltElements.Revit.Parameter" in o.speckle_type], #This one is just for traversal performance of revit commits
|
||||
lambda _: [],
|
||||
)
|
||||
|
||||
if stream is None:
|
||||
print("Account contains no streams.")
|
||||
default_rule = TraversalRule(
|
||||
[lambda _: True],
|
||||
lambda o: o.get_member_names(), #TODO: avoid deprecated members
|
||||
)
|
||||
|
||||
return (user, stream)
|
||||
return GraphTraversal([convertable_rule, ignore_result_rule, default_rule])
|
||||
|
||||
|
||||
def get_speckle(context: bpy.types.Context) -> 'SpeckleSceneSettings':
|
||||
return context.scene.speckle #type: ignore
|
||||
@@ -1,9 +1,10 @@
|
||||
"""
|
||||
Commit operators
|
||||
"""
|
||||
from typing import cast
|
||||
import bpy
|
||||
from bpy.props import BoolProperty
|
||||
from bpy_speckle.functions import _check_speckle_client_user_stream, _report
|
||||
from bpy_speckle.functions import _report, get_speckle
|
||||
from bpy_speckle.clients import speckle_clients
|
||||
from bpy_speckle.properties.scene import SpeckleSceneSettings
|
||||
|
||||
@@ -30,48 +31,37 @@ class DeleteCommit(bpy.types.Operator):
|
||||
col.prop(self, "are_you_sure")
|
||||
|
||||
def invoke(self, context, event):
|
||||
speckle = get_speckle(context)
|
||||
wm = context.window_manager
|
||||
if len(context.scene.speckle.users) > 0:
|
||||
if len(speckle.users) > 0:
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
return {"CANCELLED"}
|
||||
|
||||
def execute(self, context):
|
||||
try:
|
||||
self.delete_commit(context)
|
||||
return {"FINISHED"}
|
||||
except Exception as ex:
|
||||
print(f"{self.bl_idname}: failed: {ex}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
def delete_commit(self, context: bpy.types.Context) -> None:
|
||||
|
||||
if not self.are_you_sure:
|
||||
_report(f"{self.bl_idname}: cancelled by user")
|
||||
return {"CANCELLED"}
|
||||
raise Exception("Cancelled by user")
|
||||
|
||||
self.are_you_sure = False
|
||||
|
||||
speckle: SpeckleSceneSettings = context.scene.speckle
|
||||
speckle = get_speckle(context)
|
||||
|
||||
user = speckle.get_active_user()
|
||||
if user is None:
|
||||
print(f"{self.bl_idname}: failed - No user selected/found")
|
||||
return {"CANCELLED"}
|
||||
|
||||
stream = user.get_active_stream()
|
||||
if stream is None:
|
||||
print(f"{self.bl_idname}: failed - No stream selected/found")
|
||||
return {"CANCELLED"}
|
||||
|
||||
branch = stream.get_active_branch()
|
||||
if branch is None:
|
||||
print(f"{self.bl_idname}: failed - No branch selected/found")
|
||||
return {"CANCELLED"}
|
||||
|
||||
commit = branch.get_active_commit()
|
||||
if commit is None:
|
||||
print(f"{self.bl_idname}: failed - No commit selected/found")
|
||||
return {"CANCELLED"}
|
||||
(_, stream, _, commit) = speckle.validate_commit_selection()
|
||||
|
||||
client = speckle_clients[int(speckle.active_user)]
|
||||
|
||||
deleted = client.commit.delete(stream_id=stream.id, commit_id=commit.id)
|
||||
if not deleted:
|
||||
print(f"{self.bl_idname}: failed - Delete operation failed")
|
||||
return {"CANCELLED"}
|
||||
raise Exception("Delete operation failed")
|
||||
|
||||
print(f"{self.bl_idname}: succeeded - commit {commit.id} ({commit.message}) has been deleted from stream {stream.id}")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
+316
-274
@@ -3,58 +3,69 @@ Stream operators
|
||||
"""
|
||||
from itertools import chain
|
||||
from math import radians
|
||||
from typing import Callable, Dict, Iterable, Optional
|
||||
import bpy
|
||||
from bpy_speckle.convert.util import link_object_to_collection_nested
|
||||
from bpy_speckle.properties.scene import SpeckleSceneSettings
|
||||
from specklepy.api.models import Commit
|
||||
from deprecated import deprecated
|
||||
from typing import Any, Callable, Dict, Iterable, List, Optional, Union, cast
|
||||
import webbrowser
|
||||
import bpy
|
||||
from bpy.props import (
|
||||
StringProperty,
|
||||
BoolProperty,
|
||||
EnumProperty,
|
||||
)
|
||||
from bpy.types import Context, Object
|
||||
from bpy.types import (
|
||||
Context,
|
||||
Object,
|
||||
Collection
|
||||
)
|
||||
from bpy_speckle.blender_commit_object_builder import BlenderCommitObjectBuilder
|
||||
from bpy_speckle.convert.to_native import (
|
||||
can_convert_to_native,
|
||||
convert_to_native,
|
||||
set_convert_instances_as,
|
||||
)
|
||||
from bpy_speckle.convert.to_speckle import (
|
||||
ConversionSkippedException,
|
||||
convert_to_speckle,
|
||||
)
|
||||
from bpy_speckle.functions import (
|
||||
_check_speckle_client_user_stream,
|
||||
get_scale_length,
|
||||
get_default_traversal_func,
|
||||
_report,
|
||||
get_scale_length,
|
||||
get_speckle,
|
||||
)
|
||||
from bpy_speckle.clients import speckle_clients
|
||||
from bpy_speckle.operators.users import add_user_stream
|
||||
from bpy_speckle.properties.scene import SpeckleSceneSettings, SpeckleUserObject
|
||||
from bpy_speckle.convert.util import link_object_to_collection_nested
|
||||
|
||||
from specklepy.api.models import Commit
|
||||
from specklepy.api import operations, host_applications
|
||||
from specklepy.api.wrapper import StreamWrapper
|
||||
from specklepy.api.resources.stream import Stream
|
||||
from specklepy.transports.server import ServerTransport
|
||||
from specklepy.objects.geometry import *
|
||||
from specklepy.objects import Base
|
||||
from specklepy.objects.other import Collection as SCollection
|
||||
from specklepy.logging.exceptions import SpeckleException
|
||||
from specklepy.logging import metrics
|
||||
|
||||
from bpy_speckle.specklepy_extras.traversal import TraversalContext
|
||||
|
||||
@deprecated
|
||||
def get_objects_collections(base: Base) -> Dict[str, list]:
|
||||
"""Create collections based on the dynamic members on a root commit object"""
|
||||
collections = {}
|
||||
for name in base.get_dynamic_member_names():
|
||||
value = base[name]
|
||||
if isinstance(value, list):
|
||||
col = create_collection(name)
|
||||
col = get_or_create_collection(name)
|
||||
collections[name] = get_objects_nested_lists(value, col)
|
||||
if isinstance(value, Base):
|
||||
col = create_collection(name)
|
||||
col = get_or_create_collection(name)
|
||||
collections[name] = get_objects_collections_recursive(value, col)
|
||||
|
||||
return collections
|
||||
|
||||
|
||||
@deprecated
|
||||
def get_objects_nested_lists(items: list, parent_col: Optional[bpy.types.Collection] = None) -> List:
|
||||
"""For handling the weird nested lists that come from Grasshopper"""
|
||||
objects = []
|
||||
@@ -73,7 +84,7 @@ def get_objects_nested_lists(items: list, parent_col: Optional[bpy.types.Collect
|
||||
|
||||
return objects
|
||||
|
||||
|
||||
@deprecated
|
||||
def get_objects_collections_recursive(base: Base, parent_col: Optional[bpy.types.Collection] = None) -> List:
|
||||
"""Recursively create collections based on the dynamic members on nested `Base` objects within the root commit object"""
|
||||
# if it's a convertable (registered) class and not just a plain `Base`, return the object itself
|
||||
@@ -90,7 +101,7 @@ def get_objects_collections_recursive(base: Base, parent_col: Optional[bpy.types
|
||||
if isinstance(value, Base):
|
||||
col = parent_col.children.get(name)
|
||||
if not col:
|
||||
col = create_collection(name)
|
||||
col = get_or_create_collection(name)
|
||||
try:
|
||||
parent_col.children.link(col)
|
||||
except:
|
||||
@@ -103,45 +114,29 @@ def get_objects_collections_recursive(base: Base, parent_col: Optional[bpy.types
|
||||
|
||||
|
||||
ObjectCallback = Optional[Callable[[bpy.types.Context, Object, Base], Object]]
|
||||
ReceiveCompleteCallback = Optional[Callable[[bpy.types.Context, Dict[str, Object]], None]]
|
||||
ReceiveCompleteCallback = Optional[Callable[[bpy.types.Context, Dict[str, Union[Object, Collection]]], None]]
|
||||
|
||||
def get_receive_funcs(context: Context, created_objects: Dict[str, Object]) -> tuple[ObjectCallback, ReceiveCompleteCallback]:
|
||||
"""
|
||||
Fetches the injected callback functions from user specified "Receive Script"
|
||||
"""
|
||||
def get_receive_funcs(speckle: SpeckleSceneSettings) -> tuple[ObjectCallback, ReceiveCompleteCallback]:
|
||||
"""
|
||||
Fetches the injected callback functions from user specified "Receive Script"
|
||||
"""
|
||||
|
||||
objectCallback: ObjectCallback = None
|
||||
receiveCompleteCallback: ReceiveCompleteCallback = None
|
||||
|
||||
if context.scene.speckle.receive_script in bpy.data.texts:
|
||||
mod = bpy.data.texts[context.scene.speckle.receive_script].as_module()
|
||||
if hasattr(mod, "execute_for_each"):
|
||||
objectCallback = mod.execute_for_each
|
||||
elif hasattr(mod, "execute"):
|
||||
objectCallback = lambda c, o, _ : mod.execute(c.scene, o)
|
||||
objectCallback: ObjectCallback = None
|
||||
receiveCompleteCallback: ReceiveCompleteCallback = None
|
||||
|
||||
if speckle.receive_script in bpy.data.texts:
|
||||
mod = bpy.data.texts[speckle.receive_script].as_module()
|
||||
if hasattr(mod, "execute_for_each"):
|
||||
objectCallback = mod.execute_for_each #type: ignore
|
||||
elif hasattr(mod, "execute"):
|
||||
objectCallback = lambda c, o, _ : mod.execute(c.scene, o) #type: ignore
|
||||
|
||||
if hasattr(mod, "execute_for_all"):
|
||||
receiveCompleteCallback = mod.execute_for_all
|
||||
if hasattr(mod, "execute_for_all"):
|
||||
receiveCompleteCallback = mod.execute_for_all #type: ignore
|
||||
|
||||
return (objectCallback, receiveCompleteCallback)
|
||||
|
||||
progress = 0
|
||||
|
||||
def for_each_object(context: bpy.types.Context, obj: Object, base: Base) -> Object:
|
||||
nonlocal progress
|
||||
nonlocal created_objects
|
||||
nonlocal objectCallback
|
||||
|
||||
progress += 1 #NOTE:XXX Progress bar never reaches 100 because func is only called for convertible objects
|
||||
context.window_manager.progress_update(progress)
|
||||
created_objects[obj.name] = obj
|
||||
|
||||
if objectCallback:
|
||||
return objectCallback(context, obj, base)
|
||||
else:
|
||||
return obj
|
||||
|
||||
return (for_each_object, receiveCompleteCallback)
|
||||
|
||||
@deprecated
|
||||
def bases_to_native(context: bpy.types.Context, collections: Dict[str, list], scale: float, stream_id: str, func: ObjectCallback = None):
|
||||
for col_name, objects in collections.items():
|
||||
col = bpy.data.collections[col_name]
|
||||
@@ -174,7 +169,7 @@ def bases_to_native(context: bpy.types.Context, collections: Dict[str, list], sc
|
||||
context.area.tag_redraw()
|
||||
|
||||
|
||||
|
||||
@deprecated
|
||||
def base_to_native(context: bpy.types.Context,
|
||||
base: Base,
|
||||
scale: float,
|
||||
@@ -227,24 +222,66 @@ def base_to_native(context: bpy.types.Context,
|
||||
#col.objects.link(new_object)
|
||||
|
||||
|
||||
def create_collection(name: str, clear_collection=True) -> bpy.types.Collection:
|
||||
if name in bpy.data.collections:
|
||||
col = bpy.data.collections[name]
|
||||
def _add_to_heirarchy(converted: Union[Object, Collection], traversalContext : TraversalContext, converted_objects: Dict[str, Union[Object, Collection]]) -> None:
|
||||
nextParent = traversalContext.parent
|
||||
|
||||
# Traverse up the tree to find a direct parent object, and a containing collection
|
||||
parent_collection: Optional[Collection] = None
|
||||
parent_object: Optional[Object] = None
|
||||
|
||||
while nextParent:
|
||||
if nextParent.current.id in converted_objects:
|
||||
c = converted_objects[nextParent.current.id]
|
||||
|
||||
if isinstance(c, Collection):
|
||||
parent_collection = c
|
||||
break
|
||||
else: #isinstance(c, Object):
|
||||
parent_object = parent_object or c
|
||||
|
||||
nextParent = nextParent.parent
|
||||
|
||||
# If no containing collection is found, fall back to the scene collection
|
||||
if not parent_collection:
|
||||
parent_collection = bpy.context.scene.collection
|
||||
|
||||
if isinstance(converted, Object):
|
||||
if parent_object:
|
||||
converted.parent = parent_object
|
||||
link_object_to_collection_nested(converted, parent_collection)
|
||||
elif converted.name not in parent_collection.children.keys():
|
||||
parent_collection.children.link(converted)
|
||||
|
||||
|
||||
def collection_to_native(collection: SCollection) -> Collection:
|
||||
name = collection.name or f"{collection.collectionType} -- {collection.applicationId or collection.id}" #TODO: consider consolidating name formatting with Rhino
|
||||
return get_or_create_collection(name)
|
||||
|
||||
def get_or_create_collection(name: str, clear_collection: bool = True) -> Collection:
|
||||
existing = cast(Collection, bpy.data.collections.get(name))
|
||||
if existing:
|
||||
if clear_collection:
|
||||
for obj in col.objects:
|
||||
col.objects.unlink(obj)
|
||||
for obj in existing.objects:
|
||||
existing.objects.unlink(obj)
|
||||
return existing
|
||||
else:
|
||||
col = bpy.data.collections.new(name)
|
||||
new_collection = bpy.data.collections.new(name)
|
||||
|
||||
return col
|
||||
#NOTE: We want to not render revit "Rooms" collections by default.
|
||||
if name == "Rooms":
|
||||
new_collection.hide_viewport = True
|
||||
new_collection.hide_render = True
|
||||
|
||||
return new_collection
|
||||
|
||||
|
||||
def create_child_collections(parent_col: bpy.types.Collection, children_names: Iterable[str]):
|
||||
|
||||
def create_child_collections(parent_col: bpy.types.Collection, children_names: Iterable[str]) -> None:
|
||||
for name in children_names:
|
||||
col = create_collection(name)
|
||||
col = get_or_create_collection(name)
|
||||
parent_col.children.link(col)
|
||||
|
||||
|
||||
@deprecated
|
||||
def get_existing_collection_objs(col: bpy.types.Collection) -> Dict[str, bpy.types.Object]:
|
||||
return {
|
||||
obj.speckle.object_id: obj for obj in col.objects if obj.speckle.object_id != ""
|
||||
@@ -351,32 +388,20 @@ class ReceiveStreamObjects(bpy.types.Operator):
|
||||
bpy.context.view_layer.objects.active = None
|
||||
|
||||
def execute(self, context):
|
||||
try:
|
||||
self.receive(context)
|
||||
return {"FINISHED"}
|
||||
except Exception as ex:
|
||||
_report(f"Failed to receive objects: {type(ex)} {ex}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
def receive(self, context: Context) -> None:
|
||||
bpy.context.view_layer.objects.active = None
|
||||
|
||||
speckle: SpeckleSceneSettings = context.scene.speckle
|
||||
speckle = get_speckle(context)
|
||||
|
||||
#Get UI Selection
|
||||
user = speckle.get_active_user()
|
||||
if not user:
|
||||
print("No user selected/found")
|
||||
return {"CANCELLED"}
|
||||
(user, stream, branch, commit) = speckle.validate_commit_selection()
|
||||
|
||||
stream = user.get_active_stream()
|
||||
if not stream:
|
||||
print("No stream selected/found")
|
||||
return {"CANCELLED"}
|
||||
|
||||
branch = stream.get_active_branch()
|
||||
if not branch:
|
||||
print("No branch selected/found")
|
||||
return {"CANCELLED"}
|
||||
|
||||
commit = branch.get_active_commit()
|
||||
if commit is None:
|
||||
print("No commit selected/found")
|
||||
return {"CANCELLED"}
|
||||
|
||||
#Get actual stream data
|
||||
client = speckle_clients[int(speckle.active_user)]
|
||||
|
||||
transport = ServerTransport(stream.id, client)
|
||||
@@ -390,6 +415,8 @@ class ReceiveStreamObjects(bpy.types.Operator):
|
||||
"isMultiplayer": commit.author_id != user.id,
|
||||
},
|
||||
)
|
||||
|
||||
# Fetch commit data
|
||||
commit_object = operations._untracked_receive(commit.referenced_object, transport)
|
||||
client.commit.received(
|
||||
stream.id,
|
||||
@@ -398,69 +425,76 @@ class ReceiveStreamObjects(bpy.types.Operator):
|
||||
message="received commit from Speckle Blender",
|
||||
)
|
||||
|
||||
# Convert received data
|
||||
context.window_manager.progress_begin(0, commit_object.totalChildrenCount or 1)
|
||||
|
||||
set_convert_instances_as(self.receive_instances_as) #HACK: we need a better way to pass settings down to the converter
|
||||
|
||||
"""
|
||||
Create or get Collection for stream objects
|
||||
"""
|
||||
collections = get_objects_collections(commit_object)
|
||||
traversalFunc = get_default_traversal_func(can_convert_to_native)
|
||||
converted_objects: Dict[str, Union[Object, Collection]] = {}
|
||||
converted_count: int = 0
|
||||
(object_converted_callback, on_complete_callback) = get_receive_funcs(speckle)
|
||||
|
||||
if not collections:
|
||||
print("Unusual commit structure - did not correctly create collections")
|
||||
return {"CANCELLED"}
|
||||
# older commits won't will have a non-collection root object
|
||||
# for the sake of consistant behaviour, we will wrap anynon-collection commit objects in a collection
|
||||
if not isinstance(commit_object, SCollection):
|
||||
dummy_commit_object = SCollection()
|
||||
dummy_commit_object.elements = [commit_object]
|
||||
dummy_commit_object.name = getattr(commit_object, "name", None)
|
||||
dummy_commit_object.id = dummy_commit_object.get_id()
|
||||
commit_object = dummy_commit_object
|
||||
|
||||
# name = ""
|
||||
# if self.receive_mode == "create":
|
||||
name = "{} [ {} @ {} ]".format(stream.name, branch.name, commit.id) # Matches Rhino "Create" naming
|
||||
# else:
|
||||
# name = stream.name # Doesn't quite match rhino's Update layer naming, but is close enough no?
|
||||
# ensure commit object has a name if not already
|
||||
if not commit_object.name:
|
||||
commit_object.name = "{} [ {} @ {} ]".format(stream.name, branch.name, commit.id) # Matches Rhino "Create" naming
|
||||
|
||||
col = create_collection(name)
|
||||
col.speckle.stream_id = stream.id
|
||||
col.speckle.units = commit_object.units or "m"
|
||||
for item in traversalFunc.traverse(commit_object):
|
||||
|
||||
if col.name not in bpy.context.scene.collection.children:
|
||||
bpy.context.scene.collection.children.link(col)
|
||||
current: Base = item.current
|
||||
if can_convert_to_native(current) or isinstance(current, SCollection):
|
||||
try:
|
||||
if not current or not current.id: raise Exception("{current} was an invalid speckle object")
|
||||
|
||||
for child_col in collections.keys():
|
||||
try:
|
||||
col.children.link(bpy.data.collections[child_col])
|
||||
except:
|
||||
pass
|
||||
"""
|
||||
Set conversion scale from stream units
|
||||
"""
|
||||
scale = (
|
||||
get_scale_length(col.speckle.units)
|
||||
/ context.scene.unit_settings.scale_length
|
||||
)
|
||||
#Convert the object!
|
||||
converted_data_type: str
|
||||
converted: Union[Object, Collection, None]
|
||||
if isinstance(current, SCollection):
|
||||
if(current.collectionType == "Scene Collection"): raise ConversionSkippedException()
|
||||
converted = collection_to_native(current)
|
||||
converted_data_type = "COLLECTION"
|
||||
else:
|
||||
converted = convert_to_native(current)
|
||||
converted_data_type = "COLLECTION_INSTANCE" if converted.instance_collection else str(converted.type)
|
||||
|
||||
#Run the user specified callback function (AKA receive script)
|
||||
if object_converted_callback:
|
||||
converted = object_converted_callback(context, converted, current)
|
||||
|
||||
if converted is None:
|
||||
raise Exception("Conversion returned None")
|
||||
|
||||
converted_objects[current.id] = converted
|
||||
|
||||
"""
|
||||
Get script from text editor for injection
|
||||
"""
|
||||
created_objects = {}
|
||||
(func, on_complete) = get_receive_funcs(context, created_objects)
|
||||
|
||||
_add_to_heirarchy(converted, item, converted_objects)
|
||||
|
||||
_report(f"Successfully converted {type(current).__name__} {current.id} as '{converted_data_type}'")
|
||||
except ConversionSkippedException as ex:
|
||||
_report(f"Skipped converting {type(current).__name__} {current.id}: {ex}")
|
||||
except Exception as ex:
|
||||
_report(f"Failed to converted {type(current).__name__} {current.id}: {ex}")
|
||||
|
||||
converted_count += 1
|
||||
context.window_manager.progress_update(converted_count) #NOTE: We don't expect to ever reach 100% since not every object will be traversed
|
||||
|
||||
"""
|
||||
Iterate through retrieved resources
|
||||
"""
|
||||
|
||||
bases_to_native(context, collections, scale, stream.id, func)
|
||||
context.window_manager.progress_end()
|
||||
|
||||
|
||||
if self.clean_meshes:
|
||||
self.clean_converted_meshes(context, created_objects)
|
||||
objects = {k: v for k, v in converted_objects.items() if isinstance(v, Object)}
|
||||
self.clean_converted_meshes(context, objects)
|
||||
|
||||
if on_complete:
|
||||
on_complete(context, created_objects)
|
||||
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
if on_complete_callback:
|
||||
on_complete_callback(context, converted_objects)
|
||||
|
||||
|
||||
|
||||
@@ -488,124 +522,110 @@ class SendStreamObjects(bpy.types.Operator):
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
if len(context.scene.speckle.users) > 0:
|
||||
N = len(context.selected_objects)
|
||||
if N == 1:
|
||||
self.commit_message = "Pushed {} element from Blender.".format(N)
|
||||
else:
|
||||
self.commit_message = "Pushed {} elements from Blender.".format(N)
|
||||
return wm.invoke_props_dialog(self)
|
||||
if len(context.scene.speckle.users) <= 0: return {"CANCELLED"}
|
||||
|
||||
N = len(context.selected_objects)
|
||||
if N == 1:
|
||||
self.commit_message = f"Pushed {N} element from Blender."
|
||||
else:
|
||||
self.commit_message = f"Pushed {N} elements from Blender."
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
return {"CANCELLED"}
|
||||
|
||||
def execute(self, context):
|
||||
try:
|
||||
self.send(context)
|
||||
return {"FINISHED"}
|
||||
except Exception as ex:
|
||||
_report(f"Send failed: {ex}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
def send(self, context: Context) -> None:
|
||||
|
||||
selected = context.selected_objects
|
||||
|
||||
if len(selected) < 1:
|
||||
return {"CANCELLED"}
|
||||
raise Exception("No objects are selected, sending canceled")
|
||||
|
||||
check = _check_speckle_client_user_stream(context.scene)
|
||||
user, bstream = check
|
||||
speckle = get_speckle(context)
|
||||
(user, stream, branch) = speckle.validate_branch_selection()
|
||||
|
||||
if user is None:
|
||||
return {"CANCELLED"}
|
||||
|
||||
stream = user.streams[user.active_stream]
|
||||
branch = stream.branches[int(stream.branch)]
|
||||
|
||||
client = speckle_clients[int(context.scene.speckle.active_user)]
|
||||
|
||||
# scale = context.scene.unit_settings.scale_length / get_scale_length(
|
||||
# stream.units.lower()
|
||||
# )
|
||||
|
||||
|
||||
scale = 1.0
|
||||
client = speckle_clients[int(speckle.active_user)]
|
||||
|
||||
units = "m" if bpy.context.scene.unit_settings.system == "METRIC" else "ft"
|
||||
|
||||
"""
|
||||
Get script from text editor for injection
|
||||
"""
|
||||
units_scale = context.scene.unit_settings.scale_length / get_scale_length(units)
|
||||
|
||||
# Get script from text editor for injection
|
||||
func = None
|
||||
if context.scene.speckle.send_script in bpy.data.texts:
|
||||
mod = bpy.data.texts[context.scene.speckle.send_script].as_module()
|
||||
if speckle.send_script in bpy.data.texts:
|
||||
mod = bpy.data.texts[speckle.send_script].as_module()
|
||||
if hasattr(mod, "execute"):
|
||||
func = mod.execute
|
||||
func = mod.execute #type: ignore
|
||||
|
||||
export = {}
|
||||
num_converted = 0
|
||||
context.window_manager.progress_begin(0, max(len(selected), 1))
|
||||
|
||||
depsgraph = bpy.context.evaluated_depsgraph_get() if self.apply_modifiers else None
|
||||
|
||||
commit_builder = BlenderCommitObjectBuilder()
|
||||
for obj in selected:
|
||||
try:
|
||||
# Run injected function
|
||||
new_object = obj
|
||||
if func:
|
||||
new_object = func(context.scene, obj)
|
||||
|
||||
# if obj.type != 'MESH':
|
||||
# continue
|
||||
if (new_object is None):
|
||||
raise ConversionSkippedException(f"Script '{func.__module__}' returned None.")
|
||||
|
||||
new_object = obj
|
||||
converted = convert_to_speckle(
|
||||
obj,
|
||||
units_scale,
|
||||
units,
|
||||
depsgraph
|
||||
)
|
||||
|
||||
"""
|
||||
Run injected function
|
||||
"""
|
||||
if func:
|
||||
new_object = func(context.scene, obj)
|
||||
if not converted:
|
||||
raise Exception("Converter returned None")
|
||||
|
||||
if (
|
||||
new_object is None
|
||||
): # Make sure that the injected function returned an object
|
||||
new_obj = obj
|
||||
_report("Script '{}' returned None.".format(func.__module__))
|
||||
continue
|
||||
commit_builder.include_object(converted, obj)
|
||||
|
||||
_report("Converting {}".format(obj.name))
|
||||
_report(f"Successfully converted '{obj.name_full}' as '{converted.speckle_type}'")
|
||||
except ConversionSkippedException as ex:
|
||||
_report(f"Skipped converting '{obj.name_full}': '{ex}'")
|
||||
except Exception as ex:
|
||||
_report(f"Failed to converted '{obj.name_full}': '{ex}'")
|
||||
|
||||
num_converted += 1
|
||||
context.window_manager.progress_update(num_converted)
|
||||
|
||||
converted = convert_to_speckle(
|
||||
obj,
|
||||
scale,
|
||||
units,
|
||||
bpy.context.evaluated_depsgraph_get()
|
||||
if self.apply_modifiers
|
||||
else None,
|
||||
)
|
||||
context.window_manager.progress_end()
|
||||
|
||||
if not converted:
|
||||
continue
|
||||
|
||||
collection_name = obj.users_collection[0].name
|
||||
if not export.get(collection_name):
|
||||
export[collection_name] = []
|
||||
|
||||
export[collection_name].extend(converted)
|
||||
|
||||
base = Base()
|
||||
for name, objects in export.items():
|
||||
collection = bpy.data.collections.get(name)
|
||||
hierarchy = get_collection_hierarchy(collection)
|
||||
create_nested_hierarchy(base, hierarchy, objects)
|
||||
commit_object = commit_builder.ensure_collection(context.scene.collection)
|
||||
commit_builder.build_commit_object(commit_object)
|
||||
|
||||
_report(f"Sending data to {stream.name}")
|
||||
transport = ServerTransport(stream.id, client)
|
||||
|
||||
_report(f"Sending to {stream}")
|
||||
obj_id = operations.send(
|
||||
base,
|
||||
OBJECT_ID = operations.send(
|
||||
commit_object,
|
||||
[transport],
|
||||
)
|
||||
|
||||
commitId = client.commit.create(
|
||||
COMMIT_ID = client.commit.create(
|
||||
stream.id,
|
||||
obj_id,
|
||||
OBJECT_ID,
|
||||
branch.name,
|
||||
message=self.commit_message,
|
||||
source_application="blender",
|
||||
)
|
||||
_report(f"Commit Created {user.server_url}/streams/{stream.id}/commits/{commitId}")
|
||||
|
||||
bpy.ops.speckle.load_user_streams()
|
||||
_report(f"Commit Created {user.server_url}/streams/{stream.id}/commits/{COMMIT_ID}")
|
||||
|
||||
bpy.ops.speckle.load_user_streams() # refresh loaded commits
|
||||
context.view_layer.update()
|
||||
|
||||
if context.area:
|
||||
context.area.tag_redraw()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
class ViewStreamDataApi(bpy.types.Operator):
|
||||
@@ -615,15 +635,20 @@ class ViewStreamDataApi(bpy.types.Operator):
|
||||
bl_description = "View the stream in the web browser"
|
||||
|
||||
def execute(self, context):
|
||||
try:
|
||||
self.view_stream_data_api(context)
|
||||
return {"FINISHED"}
|
||||
except Exception as ex:
|
||||
_report(f"{self.bl_idname} failed: {ex}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
if len(context.scene.speckle.users) > 0:
|
||||
user = context.scene.speckle.users[int(context.scene.speckle.active_user)]
|
||||
if len(user.streams) > 0:
|
||||
stream = user.streams[user.active_stream]
|
||||
def view_stream_data_api(self, context: Context) -> None:
|
||||
speckle = get_speckle(context)
|
||||
|
||||
webbrowser.open("%s/streams/%s" % (user.server_url, stream.id), new=2)
|
||||
return {"FINISHED"}
|
||||
return {"CANCELLED"}
|
||||
(user, stream) = speckle.validate_stream_selection()
|
||||
|
||||
if not webbrowser.open("%s/streams/%s" % (user.server_url, stream.id), new=2):
|
||||
raise Exception("Failed to open stream in browser")
|
||||
|
||||
|
||||
class AddStreamFromURL(bpy.types.Operator):
|
||||
@@ -646,13 +671,22 @@ class AddStreamFromURL(bpy.types.Operator):
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
if len(context.scene.speckle.users) > 0:
|
||||
speckle = get_speckle(context)
|
||||
if len(speckle.users) > 0:
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
return {"CANCELLED"}
|
||||
|
||||
def execute(self, context):
|
||||
speckle = context.scene.speckle
|
||||
try:
|
||||
self.add_stream_from_url(context)
|
||||
return {"FINISHED"}
|
||||
except Exception as ex:
|
||||
_report(f"{self.bl_idname} failed: {ex}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
def add_stream_from_url(self, context: Context) -> None:
|
||||
speckle = get_speckle(context)
|
||||
|
||||
wrapper = StreamWrapper(self.stream_url)
|
||||
user_index = next(
|
||||
@@ -660,9 +694,10 @@ class AddStreamFromURL(bpy.types.Operator):
|
||||
None,
|
||||
)
|
||||
if user_index is None:
|
||||
return {"CANCELLED"}
|
||||
raise Exception("Unable to find user stream server")
|
||||
|
||||
speckle.active_user = str(user_index)
|
||||
user = speckle.users[user_index]
|
||||
user = cast(SpeckleUserObject, speckle.users[user_index])
|
||||
|
||||
client = speckle_clients[user_index]
|
||||
stream = client.stream.get(wrapper.stream_id, branch_limit=20)
|
||||
@@ -701,8 +736,6 @@ class AddStreamFromURL(bpy.types.Operator):
|
||||
if context.area:
|
||||
context.area.tag_redraw()
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CreateStream(bpy.types.Operator):
|
||||
"""
|
||||
@@ -727,23 +760,31 @@ class CreateStream(bpy.types.Operator):
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
if len(context.scene.speckle.users) > 0:
|
||||
speckle = get_speckle(context)
|
||||
if len(speckle.users) > 0:
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
return {"CANCELLED"}
|
||||
|
||||
def execute(self, context):
|
||||
try:
|
||||
self.create_stream(context)
|
||||
return {"FINISHED"}
|
||||
except Exception as ex:
|
||||
_report(f"{self.bl_idname} failed: {ex}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
def create_stream(self, context: Context) -> None:
|
||||
speckle = get_speckle(context)
|
||||
|
||||
check = _check_speckle_client_user_stream(context.scene)
|
||||
if check is None:
|
||||
return {"CANCELLED"}
|
||||
user = speckle.validate_user_selection()
|
||||
|
||||
user, bstream = check
|
||||
|
||||
client = speckle_clients[int(context.scene.speckle.active_user)]
|
||||
client = speckle_clients[int(speckle.active_user)]
|
||||
|
||||
client.stream.create(
|
||||
name=self.stream_name, description=self.stream_description, is_public=True
|
||||
name=self.stream_name,
|
||||
description=self.stream_description,
|
||||
is_public=True
|
||||
)
|
||||
|
||||
bpy.ops.speckle.load_user_streams()
|
||||
@@ -755,8 +796,6 @@ class CreateStream(bpy.types.Operator):
|
||||
if context.area:
|
||||
context.area.tag_redraw()
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DeleteStream(bpy.types.Operator):
|
||||
"""
|
||||
@@ -783,24 +822,30 @@ class DeleteStream(bpy.types.Operator):
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
if len(context.scene.speckle.users) > 0:
|
||||
speckle = get_speckle(context)
|
||||
if len(speckle.users) > 0:
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
return {"CANCELLED"}
|
||||
|
||||
def execute(self, context):
|
||||
try:
|
||||
self.delete_stream(context)
|
||||
return {"FINISHED"}
|
||||
except Exception as ex:
|
||||
_report(f"{self.bl_idname} failed: {ex}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
def delete_stream(self, context: Context) -> None:
|
||||
if not self.are_you_sure:
|
||||
return {"CANCELLED"}
|
||||
raise Exception("Cancled by user")
|
||||
|
||||
self.are_you_sure = False
|
||||
|
||||
check = _check_speckle_client_user_stream(context.scene)
|
||||
if check is None:
|
||||
return {"CANCELLED"}
|
||||
speckle = get_speckle(context)
|
||||
(_, stream) = speckle.validate_stream_selection()
|
||||
|
||||
user, stream = check
|
||||
client = speckle_clients[int(context.scene.speckle.active_user)]
|
||||
client = speckle_clients[int(speckle.active_user)]
|
||||
|
||||
client.stream.delete(id=stream.id)
|
||||
|
||||
@@ -815,7 +860,6 @@ class DeleteStream(bpy.types.Operator):
|
||||
|
||||
if context.area:
|
||||
context.area.tag_redraw()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SelectOrphanObjects(bpy.types.Operator):
|
||||
@@ -844,7 +888,7 @@ class SelectOrphanObjects(bpy.types.Operator):
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@deprecated
|
||||
class UpdateGlobal(bpy.types.Operator):
|
||||
"""
|
||||
DEPRECATED
|
||||
@@ -864,7 +908,7 @@ class UpdateGlobal(bpy.types.Operator):
|
||||
label = row.label(text="Update everything.")
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
|
||||
client = context.scene.speckle.client
|
||||
|
||||
profiles = client.load_local_profiles()
|
||||
@@ -892,16 +936,18 @@ class CopyStreamId(bpy.types.Operator):
|
||||
bl_description = "Copy stream ID to clipboard"
|
||||
|
||||
def execute(self, context):
|
||||
speckle = context.scene.speckle
|
||||
try:
|
||||
self.copy_stream_id(context)
|
||||
return {"FINISHED"}
|
||||
except Exception as ex:
|
||||
_report(f"{self.bl_idname} failed: {ex}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
def copy_stream_id(self, context) -> None:
|
||||
speckle = get_speckle(context)
|
||||
|
||||
if len(speckle.users) < 1:
|
||||
return {"CANCELLED"}
|
||||
user = speckle.users[int(speckle.active_user)]
|
||||
if len(user.streams) < 1:
|
||||
return {"CANCELLED"}
|
||||
stream = user.streams[user.active_stream]
|
||||
(_, stream) = speckle.validate_stream_selection()
|
||||
bpy.context.window_manager.clipboard = stream.id
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CopyCommitId(bpy.types.Operator):
|
||||
@@ -915,22 +961,18 @@ class CopyCommitId(bpy.types.Operator):
|
||||
bl_description = "Copy commit ID to clipboard"
|
||||
|
||||
def execute(self, context):
|
||||
speckle = context.scene.speckle
|
||||
try:
|
||||
self.copy_commit_id(context)
|
||||
return {"FINISHED"}
|
||||
except Exception as ex:
|
||||
_report(f"{self.bl_idname} failed: {ex}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
def copy_commit_id(self, context) -> None:
|
||||
speckle = get_speckle(context)
|
||||
|
||||
if len(speckle.users) < 1:
|
||||
return {"CANCELLED"}
|
||||
user = speckle.users[int(speckle.active_user)]
|
||||
if len(user.streams) < 1:
|
||||
return {"CANCELLED"}
|
||||
stream = user.streams[user.active_stream]
|
||||
if len(stream.branches) < 1:
|
||||
return {"CANCELLED"}
|
||||
branch = stream.branches[int(stream.branch)]
|
||||
if len(branch.commits) < 1:
|
||||
return {"CANCELLED"}
|
||||
commit = branch.commits[int(branch.commit)]
|
||||
(_, _, _, commit) = speckle.validate_commit_selection()
|
||||
bpy.context.window_manager.clipboard = commit.id
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CopyBranchName(bpy.types.Operator):
|
||||
@@ -944,16 +986,16 @@ class CopyBranchName(bpy.types.Operator):
|
||||
bl_description = "Copy branch name to clipboard"
|
||||
|
||||
def execute(self, context):
|
||||
speckle = context.scene.speckle
|
||||
try:
|
||||
self.copy_branch_id(context)
|
||||
return {"FINISHED"}
|
||||
except Exception as ex:
|
||||
_report(f"{self.bl_idname} failed: {ex}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
def copy_branch_id(self, context) -> None:
|
||||
speckle = get_speckle(context)
|
||||
|
||||
(_, _, branch) = speckle.validate_branch_selection()
|
||||
|
||||
if len(speckle.users) < 1:
|
||||
return {"CANCELLED"}
|
||||
user = speckle.users[int(speckle.active_user)]
|
||||
if len(user.streams) < 1:
|
||||
return {"CANCELLED"}
|
||||
stream = user.streams[user.active_stream]
|
||||
if len(stream.branches) < 1:
|
||||
return {"CANCELLED"}
|
||||
branch = stream.branches[int(stream.branch)]
|
||||
bpy.context.window_manager.clipboard = branch.name
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
"""
|
||||
User account operators
|
||||
"""
|
||||
from typing import cast
|
||||
import bpy
|
||||
from bpy_speckle.functions import _report
|
||||
from bpy.types import Context
|
||||
from bpy_speckle.functions import _report, get_speckle
|
||||
from bpy_speckle.clients import speckle_clients
|
||||
from bpy_speckle.properties.scene import SpeckleCommitObject, SpeckleSceneSettings
|
||||
from bpy_speckle.properties.scene import SpeckleCommitObject, SpeckleSceneSettings, SpeckleUserObject
|
||||
from specklepy.api.client import SpeckleClient
|
||||
from specklepy.api.models import Stream, User
|
||||
from specklepy.api.models import Stream
|
||||
from specklepy.api.credentials import get_local_accounts
|
||||
from datetime import datetime
|
||||
|
||||
class ResetUsers(bpy.types.Operator):
|
||||
"""
|
||||
@@ -28,8 +29,8 @@ class ResetUsers(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
@staticmethod
|
||||
def reset_ui(context: bpy.types.Context):
|
||||
speckle: SpeckleSceneSettings = context.scene.speckle
|
||||
def reset_ui(context: Context):
|
||||
speckle = get_speckle(context)
|
||||
|
||||
speckle.users.clear()
|
||||
speckle_clients.clear()
|
||||
@@ -47,7 +48,7 @@ class LoadUsers(bpy.types.Operator):
|
||||
|
||||
_report("Loading users...")
|
||||
|
||||
speckle: SpeckleSceneSettings = context.scene.speckle
|
||||
speckle = cast(SpeckleSceneSettings, context.scene.speckle) #type: ignore
|
||||
users = speckle.users
|
||||
|
||||
ResetUsers.reset_ui(context)
|
||||
@@ -64,9 +65,11 @@ class LoadUsers(bpy.types.Operator):
|
||||
user.email = profile.userInfo.email
|
||||
user.company = profile.userInfo.company or ""
|
||||
try:
|
||||
url = profile.serverInfo.url
|
||||
assert(url)
|
||||
client = SpeckleClient(
|
||||
host=profile.serverInfo.url,
|
||||
use_ssl="https" in profile.serverInfo.url,
|
||||
host=url,
|
||||
use_ssl="https" in url,
|
||||
)
|
||||
client.authenticate_with_account(profile)
|
||||
speckle_clients.append(client)
|
||||
@@ -76,7 +79,6 @@ class LoadUsers(bpy.types.Operator):
|
||||
if profile.isDefault:
|
||||
active_user_index = len(users) - 1
|
||||
|
||||
#speckle.active_user_index = int(speckle.active_user) #TODO Wtf is this?
|
||||
speckle.active_user = str(active_user_index)
|
||||
bpy.context.view_layer.update()
|
||||
|
||||
@@ -85,7 +87,7 @@ class LoadUsers(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
def add_user_stream(user: User, stream: Stream):
|
||||
def add_user_stream(user: SpeckleUserObject, stream: Stream):
|
||||
s = user.streams.add()
|
||||
s.name = stream.name
|
||||
s.id = stream.id
|
||||
@@ -108,12 +110,12 @@ def add_user_stream(user: User, stream: Stream):
|
||||
commit.message = c.message or ""
|
||||
commit.author_name = c.authorName
|
||||
commit.author_id = c.authorId
|
||||
commit.created_at = datetime.strftime(c.createdAt, "%Y-%m-%d %H:%M:%S.%f%Z")
|
||||
commit.created_at = c.createdAt.strftime("%Y-%m-%d %H:%M:%S.%f%Z") if c.createdAt else ""
|
||||
commit.source_application = str(c.sourceApplication)
|
||||
commit.referenced_object = c.referencedObject
|
||||
|
||||
if hasattr(s, "baseProperties"):
|
||||
s.units = stream.baseProperties.units
|
||||
s.units = stream.baseProperties.units # type: ignore
|
||||
else:
|
||||
s.units = "Meters"
|
||||
|
||||
@@ -129,33 +131,40 @@ class LoadUserStreams(bpy.types.Operator):
|
||||
bl_description = "(Re)load all available user streams"
|
||||
|
||||
def execute(self, context):
|
||||
speckle = context.scene.speckle
|
||||
|
||||
if len(speckle.users) > 0:
|
||||
user = speckle.users[int(context.scene.speckle.active_user)]
|
||||
client = speckle_clients[int(context.scene.speckle.active_user)]
|
||||
|
||||
try:
|
||||
streams = client.stream.list(stream_limit=20)
|
||||
except Exception as e:
|
||||
_report(f"Failed to retrieve streams: {e}")
|
||||
return
|
||||
if not streams:
|
||||
_report("Failed to retrieve streams.")
|
||||
return
|
||||
|
||||
user.streams.clear()
|
||||
|
||||
default_units = "Meters"
|
||||
|
||||
for s in streams:
|
||||
sstream = client.stream.get(id=s.id, branch_limit=20)
|
||||
add_user_stream(user, sstream)
|
||||
|
||||
bpy.context.view_layer.update()
|
||||
|
||||
try:
|
||||
self.add_stream_from_url(context)
|
||||
return {"FINISHED"}
|
||||
except Exception as ex:
|
||||
_report(f"{self.bl_idname} failed: {ex}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
def add_stream_from_url(self, context: Context) -> None:
|
||||
speckle = get_speckle(context)
|
||||
|
||||
user = speckle.validate_user_selection()
|
||||
|
||||
client = speckle_clients[int(speckle.active_user)]
|
||||
|
||||
try:
|
||||
streams = client.stream.list(stream_limit=20)
|
||||
except Exception as e:
|
||||
_report(f"Failed to retrieve streams: {e}")
|
||||
return
|
||||
if not streams:
|
||||
_report("Failed to retrieve streams.")
|
||||
return
|
||||
|
||||
user.streams.clear()
|
||||
|
||||
default_units = "Meters"
|
||||
|
||||
for s in streams:
|
||||
assert(s.id)
|
||||
sstream = client.stream.get(id=s.id, branch_limit=20)
|
||||
add_user_stream(user, sstream)
|
||||
|
||||
bpy.context.view_layer.update()
|
||||
|
||||
if context.area:
|
||||
context.area.tag_redraw()
|
||||
return {"CANCELLED"}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Scene properties
|
||||
"""
|
||||
from typing import Optional
|
||||
from typing import Optional, Tuple
|
||||
import bpy
|
||||
from bpy.props import (
|
||||
StringProperty,
|
||||
@@ -157,3 +157,38 @@ class SpeckleSceneSettings(bpy.types.PropertyGroup):
|
||||
if 0 <= selected_index < len(self.users):
|
||||
return self.users[selected_index]
|
||||
return None
|
||||
|
||||
|
||||
def validate_user_selection(self) -> SpeckleUserObject:
|
||||
user = self.get_active_user()
|
||||
if not user:
|
||||
raise SelectionException("No user selected/found")
|
||||
return user
|
||||
|
||||
def validate_stream_selection(self) -> Tuple[SpeckleUserObject, SpeckleStreamObject]:
|
||||
user = self.validate_user_selection()
|
||||
|
||||
stream = user.get_active_stream()
|
||||
if not stream:
|
||||
raise SelectionException("No stream selected/found")
|
||||
|
||||
return (user, stream)
|
||||
|
||||
def validate_branch_selection(self) -> Tuple[SpeckleUserObject, SpeckleStreamObject, SpeckleBranchObject]:
|
||||
(user, stream) = self.validate_stream_selection()
|
||||
|
||||
branch = stream.get_active_branch()
|
||||
if not branch:
|
||||
raise SelectionException("No branch selected/found")
|
||||
return (user, stream, branch)
|
||||
|
||||
def validate_commit_selection(self) ->Tuple[SpeckleUserObject, SpeckleStreamObject, SpeckleBranchObject, SpeckleCommitObject]:
|
||||
(user, stream, branch) = self.validate_branch_selection()
|
||||
commit = branch.get_active_commit()
|
||||
if commit is None:
|
||||
raise SelectionException("No commit selected/found")
|
||||
|
||||
return (user, stream, branch, commit)
|
||||
|
||||
class SelectionException(Exception):
|
||||
pass
|
||||
@@ -0,0 +1,83 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
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')
|
||||
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]]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.converted = {}
|
||||
self._parent_infos = {}
|
||||
|
||||
@abstractmethod
|
||||
def include_object(self, conversion_result: Base, native_object: T) -> None:
|
||||
pass
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
for c in to_add:
|
||||
try:
|
||||
self.apply_relationship(c, root_commit_object)
|
||||
except Exception as ex:
|
||||
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")
|
||||
|
||||
parents = self._parent_infos[current.applicationId]
|
||||
|
||||
for (parent_id, prop_name) in parents:
|
||||
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
|
||||
|
||||
try:
|
||||
elements = get_detached_prop(parent, prop_name)
|
||||
if not isinstance(elements, list):
|
||||
elements = []
|
||||
set_detached_prop(parent, prop_name, elements)
|
||||
|
||||
elements.append(current)
|
||||
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!")
|
||||
|
||||
|
||||
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:
|
||||
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}"
|
||||
@@ -0,0 +1,121 @@
|
||||
from typing import Any, Callable, Collection, Iterable, Iterator, List, Optional, Set
|
||||
|
||||
from attrs import define
|
||||
from typing_extensions import Protocol, final
|
||||
|
||||
from specklepy.objects import Base
|
||||
|
||||
|
||||
class ITraversalRule(Protocol):
|
||||
def get_members_to_traverse(self, o: Base) -> Set[str]:
|
||||
"""Get the members to traverse."""
|
||||
pass
|
||||
|
||||
def does_rule_hold(self, o: Base) -> bool:
|
||||
"""Make sure the rule still holds."""
|
||||
pass
|
||||
|
||||
|
||||
@final
|
||||
class DefaultRule:
|
||||
def get_members_to_traverse(self, _) -> Set[str]:
|
||||
return set()
|
||||
|
||||
def does_rule_hold(self, _) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
# we're creating a local protected "singleton"
|
||||
_default_rule = DefaultRule()
|
||||
|
||||
|
||||
@final
|
||||
@define(slots=True, frozen=True)
|
||||
class TraversalContext:
|
||||
current: Base
|
||||
member_name: Optional[str] = None
|
||||
parent: Optional["TraversalContext"] = None
|
||||
|
||||
|
||||
@final
|
||||
@define(slots=True, frozen=True)
|
||||
class GraphTraversal:
|
||||
|
||||
_rules: List[ITraversalRule]
|
||||
|
||||
def traverse(self, root: Base) -> Iterator[TraversalContext]:
|
||||
stack: List[TraversalContext] = []
|
||||
|
||||
stack.append(TraversalContext(root))
|
||||
|
||||
while len(stack) > 0:
|
||||
head = stack.pop()
|
||||
yield head
|
||||
|
||||
current = head.current
|
||||
active_rule = self._get_active_rule_or_default_rule(current)
|
||||
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
|
||||
value = current[child_prop]
|
||||
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],
|
||||
value: Any,
|
||||
member_name: Optional[str] = None,
|
||||
parent: Optional[TraversalContext] = None,
|
||||
):
|
||||
if isinstance(value, Base):
|
||||
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)
|
||||
elif isinstance(value, dict):
|
||||
for obj in value.values():
|
||||
GraphTraversal._traverse_member_to_stack(stack, obj, member_name, parent)
|
||||
|
||||
@staticmethod
|
||||
def traverse_member(value: Optional[Any]) -> Iterator[Base]:
|
||||
if isinstance(value, Base):
|
||||
yield value
|
||||
elif isinstance(value, list):
|
||||
for obj in value:
|
||||
for o in GraphTraversal.traverse_member(obj):
|
||||
yield o
|
||||
elif isinstance(value, dict):
|
||||
for obj in value.values():
|
||||
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
|
||||
|
||||
def _get_active_rule(self, o: Base) -> Optional[ITraversalRule]:
|
||||
for rule in self._rules:
|
||||
if rule.does_rule_hold(o):
|
||||
return rule
|
||||
return None
|
||||
|
||||
|
||||
@final
|
||||
@define(slots=True, frozen=True)
|
||||
class TraversalRule:
|
||||
_conditions: Collection[Callable[[Base], bool]]
|
||||
_members_to_traverse: Callable[[Base], Iterable[str]]
|
||||
|
||||
def get_members_to_traverse(self, o: Base) -> Set[str]:
|
||||
return set(self._members_to_traverse(o))
|
||||
|
||||
def does_rule_hold(self, o: Base) -> bool:
|
||||
for condition in self._conditions:
|
||||
if condition(o):
|
||||
return True
|
||||
return False
|
||||
Generated
+206
-187
@@ -8,7 +8,7 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "astroid"
|
||||
version = "2.15.0"
|
||||
version = "2.15.5"
|
||||
description = "An abstract syntax tree for Python with inference support."
|
||||
category = "dev"
|
||||
optional = false
|
||||
@@ -22,6 +22,21 @@ wrapt = [
|
||||
{version = ">=1.14,<2", markers = "python_version >= \"3.11\""},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "23.1.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.extras]
|
||||
cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
|
||||
dev = ["attrs[docs,tests]", "pre-commit"]
|
||||
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
|
||||
tests = ["attrs[tests-no-zope]", "zope-interface"]
|
||||
tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
|
||||
[[package]]
|
||||
name = "backoff"
|
||||
version = "2.2.1"
|
||||
@@ -54,7 +69,7 @@ uvloop = ["uvloop (>=0.15.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2022.12.7"
|
||||
version = "2023.5.7"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -89,7 +104,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7
|
||||
|
||||
[[package]]
|
||||
name = "deprecated"
|
||||
version = "1.2.13"
|
||||
version = "1.2.14"
|
||||
description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -99,7 +114,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
wrapt = ">=1.10,<2"
|
||||
|
||||
[package.extras]
|
||||
dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"]
|
||||
dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"]
|
||||
|
||||
[[package]]
|
||||
name = "dill"
|
||||
@@ -122,7 +137,7 @@ python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "gql"
|
||||
version = "3.4.0"
|
||||
version = "3.4.1"
|
||||
description = "GraphQL client for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -133,17 +148,17 @@ backoff = ">=1.11.1,<3.0"
|
||||
graphql-core = ">=3.2,<3.3"
|
||||
requests = {version = ">=2.26,<3", optional = true, markers = "extra == \"requests\""}
|
||||
requests-toolbelt = {version = ">=0.9.1,<1", optional = true, markers = "extra == \"requests\""}
|
||||
urllib3 = {version = ">=1.26", optional = true, markers = "extra == \"requests\""}
|
||||
urllib3 = {version = ">=1.26,<2", optional = true, markers = "extra == \"requests\""}
|
||||
websockets = {version = ">=10,<11", optional = true, markers = "python_version > \"3.6\" and extra == \"websockets\""}
|
||||
yarl = ">=1.6,<2.0"
|
||||
|
||||
[package.extras]
|
||||
aiohttp = ["aiohttp (>=3.7.1,<3.9.0)"]
|
||||
all = ["aiohttp (>=3.7.1,<3.9.0)", "botocore (>=1.21,<2)", "requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "websockets (>=10,<11)", "websockets (>=9,<10)"]
|
||||
all = ["aiohttp (>=3.7.1,<3.9.0)", "botocore (>=1.21,<2)", "requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26,<2)", "websockets (>=10,<11)", "websockets (>=9,<10)"]
|
||||
botocore = ["botocore (>=1.21,<2)"]
|
||||
dev = ["aiofiles", "aiohttp (>=3.7.1,<3.9.0)", "black (==22.3.0)", "botocore (>=1.21,<2)", "check-manifest (>=0.42,<1)", "flake8 (==3.8.1)", "isort (==4.3.21)", "mock (==4.0.2)", "mypy (==0.910)", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-console-scripts (==1.3.1)", "pytest-cov (==3.0.0)", "requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "sphinx (>=3.0.0,<4)", "sphinx-argparse (==0.2.5)", "sphinx-rtd-theme (>=0.4,<1)", "types-aiofiles", "types-mock", "types-requests", "urllib3 (>=1.26)", "vcrpy (==4.0.2)", "websockets (>=10,<11)", "websockets (>=9,<10)"]
|
||||
requests = ["requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)"]
|
||||
test = ["aiofiles", "aiohttp (>=3.7.1,<3.9.0)", "botocore (>=1.21,<2)", "mock (==4.0.2)", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-console-scripts (==1.3.1)", "pytest-cov (==3.0.0)", "requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "vcrpy (==4.0.2)", "websockets (>=10,<11)", "websockets (>=9,<10)"]
|
||||
dev = ["aiofiles", "aiohttp (>=3.7.1,<3.9.0)", "black (==22.3.0)", "botocore (>=1.21,<2)", "check-manifest (>=0.42,<1)", "flake8 (==3.8.1)", "isort (==4.3.21)", "mock (==4.0.2)", "mypy (==0.910)", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-console-scripts (==1.3.1)", "pytest-cov (==3.0.0)", "requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "sphinx (>=3.0.0,<4)", "sphinx-argparse (==0.2.5)", "sphinx-rtd-theme (>=0.4,<1)", "types-aiofiles", "types-mock", "types-requests", "urllib3 (>=1.26,<2)", "vcrpy (==4.0.2)", "websockets (>=10,<11)", "websockets (>=9,<10)"]
|
||||
requests = ["requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26,<2)"]
|
||||
test = ["aiofiles", "aiohttp (>=3.7.1,<3.9.0)", "botocore (>=1.21,<2)", "mock (==4.0.2)", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-console-scripts (==1.3.1)", "pytest-cov (==3.0.0)", "requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26,<2)", "vcrpy (==4.0.2)", "websockets (>=10,<11)", "websockets (>=9,<10)"]
|
||||
test-no-transport = ["aiofiles", "mock (==4.0.2)", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-console-scripts (==1.3.1)", "pytest-cov (==3.0.0)", "vcrpy (==4.0.2)"]
|
||||
websockets = ["websockets (>=10,<11)", "websockets (>=9,<10)"]
|
||||
|
||||
@@ -211,7 +226,7 @@ python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "1.24.2"
|
||||
version = "1.24.3"
|
||||
description = "Fundamental package for array computing in Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@@ -227,19 +242,19 @@ python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "3.1.1"
|
||||
version = "3.5.1"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
|
||||
docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "1.10.6"
|
||||
version = "1.10.8"
|
||||
description = "Data validation and settings management using python type hints"
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -254,14 +269,14 @@ email = ["email-validator (>=1.0.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pylint"
|
||||
version = "2.17.0"
|
||||
version = "2.17.4"
|
||||
description = "python code static checker"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7.2"
|
||||
|
||||
[package.dependencies]
|
||||
astroid = ">=2.15.0,<=2.17.0-dev0"
|
||||
astroid = ">=2.15.4,<=2.17.0-dev0"
|
||||
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
|
||||
dill = [
|
||||
{version = ">=0.2", markers = "python_version < \"3.11\""},
|
||||
@@ -280,17 +295,17 @@ testutils = ["gitpython (>3)"]
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.28.2"
|
||||
version = "2.31.0"
|
||||
description = "Python HTTP for Humans."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7, <4"
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
charset-normalizer = ">=2,<4"
|
||||
idna = ">=2.5,<4"
|
||||
urllib3 = ">=1.21.1,<1.27"
|
||||
urllib3 = ">=1.21.1,<3"
|
||||
|
||||
[package.extras]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
@@ -317,7 +332,7 @@ python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "specklepy"
|
||||
version = "2.13.0"
|
||||
version = "2.14.0"
|
||||
description = "The Python SDK for Speckle 2.0"
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -349,15 +364,15 @@ python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "tomlkit"
|
||||
version = "0.11.6"
|
||||
version = "0.11.8"
|
||||
description = "Style preserving TOML library"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.5.0"
|
||||
version = "4.6.2"
|
||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -373,7 +388,7 @@ python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.15"
|
||||
version = "1.26.16"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -402,7 +417,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
|
||||
[[package]]
|
||||
name = "yarl"
|
||||
version = "1.8.2"
|
||||
version = "1.9.2"
|
||||
description = "Yet another URL library"
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -415,7 +430,7 @@ multidict = ">=4.0"
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = ">=3.8, <4.0.0"
|
||||
content-hash = "1c637a755112bbd1507a8bb66b1ba006ec6ff797000dc41329d9e80514d52474"
|
||||
content-hash = "22d03350287bdc78108c523e3cedf45c8b6345e0a12b99b8d027e4f0f27bab1b"
|
||||
|
||||
[metadata.files]
|
||||
appdirs = [
|
||||
@@ -423,8 +438,12 @@ appdirs = [
|
||||
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
|
||||
]
|
||||
astroid = [
|
||||
{file = "astroid-2.15.0-py3-none-any.whl", hash = "sha256:e3e4d0ffc2d15d954065579689c36aac57a339a4679a679579af6401db4d3fdb"},
|
||||
{file = "astroid-2.15.0.tar.gz", hash = "sha256:525f126d5dc1b8b0b6ee398b33159105615d92dc4a17f2cd064125d57f6186fa"},
|
||||
{file = "astroid-2.15.5-py3-none-any.whl", hash = "sha256:078e5212f9885fa85fbb0cf0101978a336190aadea6e13305409d099f71b2324"},
|
||||
{file = "astroid-2.15.5.tar.gz", hash = "sha256:1039262575027b441137ab4a62a793a9b43defb42c32d5670f38686207cd780f"},
|
||||
]
|
||||
attrs = [
|
||||
{file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"},
|
||||
{file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
|
||||
]
|
||||
backoff = [
|
||||
{file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"},
|
||||
@@ -445,8 +464,8 @@ black = [
|
||||
{file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"},
|
||||
]
|
||||
certifi = [
|
||||
{file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
|
||||
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
|
||||
{file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"},
|
||||
{file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"},
|
||||
]
|
||||
charset-normalizer = [
|
||||
{file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"},
|
||||
@@ -534,8 +553,8 @@ colorama = [
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
deprecated = [
|
||||
{file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"},
|
||||
{file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"},
|
||||
{file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"},
|
||||
{file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"},
|
||||
]
|
||||
dill = [
|
||||
{file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"},
|
||||
@@ -546,8 +565,8 @@ fake-bpy-module-latest = [
|
||||
{file = "fake_bpy_module_latest-20230117-py3-none-any.whl", hash = "sha256:73613c27418446bc2942baed6220f8ac4ddde694a3712dd595aa97f902a79242"},
|
||||
]
|
||||
gql = [
|
||||
{file = "gql-3.4.0-py2.py3-none-any.whl", hash = "sha256:59c8a0b8f0a2f3b0b2ff970c94de86f82f65cb1da3340bfe57143e5f7ea82f71"},
|
||||
{file = "gql-3.4.0.tar.gz", hash = "sha256:ca81aa8314fa88a8c57dd1ce34941278e0c352d762eb721edcba0387829ea7c0"},
|
||||
{file = "gql-3.4.1-py2.py3-none-any.whl", hash = "sha256:315624ca0f4d571ef149d455033ebd35e45c1a13f18a059596aeddcea99135cf"},
|
||||
{file = "gql-3.4.1.tar.gz", hash = "sha256:11dc5d8715a827f2c2899593439a4f36449db4f0eafa5b1ea63948f8a2f8c545"},
|
||||
]
|
||||
graphql-core = [
|
||||
{file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"},
|
||||
@@ -684,88 +703,88 @@ mypy-extensions = [
|
||||
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
||||
]
|
||||
numpy = [
|
||||
{file = "numpy-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d"},
|
||||
{file = "numpy-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5"},
|
||||
{file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253"},
|
||||
{file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978"},
|
||||
{file = "numpy-1.24.2-cp310-cp310-win32.whl", hash = "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9"},
|
||||
{file = "numpy-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0"},
|
||||
{file = "numpy-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a"},
|
||||
{file = "numpy-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0"},
|
||||
{file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281"},
|
||||
{file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910"},
|
||||
{file = "numpy-1.24.2-cp311-cp311-win32.whl", hash = "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95"},
|
||||
{file = "numpy-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04"},
|
||||
{file = "numpy-1.24.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2"},
|
||||
{file = "numpy-1.24.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5"},
|
||||
{file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a"},
|
||||
{file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96"},
|
||||
{file = "numpy-1.24.2-cp38-cp38-win32.whl", hash = "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d"},
|
||||
{file = "numpy-1.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756"},
|
||||
{file = "numpy-1.24.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a"},
|
||||
{file = "numpy-1.24.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f"},
|
||||
{file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb"},
|
||||
{file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780"},
|
||||
{file = "numpy-1.24.2-cp39-cp39-win32.whl", hash = "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468"},
|
||||
{file = "numpy-1.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5"},
|
||||
{file = "numpy-1.24.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d"},
|
||||
{file = "numpy-1.24.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa"},
|
||||
{file = "numpy-1.24.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f"},
|
||||
{file = "numpy-1.24.2.tar.gz", hash = "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22"},
|
||||
{file = "numpy-1.24.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570"},
|
||||
{file = "numpy-1.24.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7"},
|
||||
{file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463"},
|
||||
{file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6"},
|
||||
{file = "numpy-1.24.3-cp310-cp310-win32.whl", hash = "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b"},
|
||||
{file = "numpy-1.24.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7"},
|
||||
{file = "numpy-1.24.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3"},
|
||||
{file = "numpy-1.24.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf"},
|
||||
{file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385"},
|
||||
{file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950"},
|
||||
{file = "numpy-1.24.3-cp311-cp311-win32.whl", hash = "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096"},
|
||||
{file = "numpy-1.24.3-cp311-cp311-win_amd64.whl", hash = "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80"},
|
||||
{file = "numpy-1.24.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078"},
|
||||
{file = "numpy-1.24.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c"},
|
||||
{file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c"},
|
||||
{file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f"},
|
||||
{file = "numpy-1.24.3-cp38-cp38-win32.whl", hash = "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4"},
|
||||
{file = "numpy-1.24.3-cp38-cp38-win_amd64.whl", hash = "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289"},
|
||||
{file = "numpy-1.24.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4"},
|
||||
{file = "numpy-1.24.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187"},
|
||||
{file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02"},
|
||||
{file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4"},
|
||||
{file = "numpy-1.24.3-cp39-cp39-win32.whl", hash = "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c"},
|
||||
{file = "numpy-1.24.3-cp39-cp39-win_amd64.whl", hash = "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17"},
|
||||
{file = "numpy-1.24.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0"},
|
||||
{file = "numpy-1.24.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812"},
|
||||
{file = "numpy-1.24.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4"},
|
||||
{file = "numpy-1.24.3.tar.gz", hash = "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155"},
|
||||
]
|
||||
pathspec = [
|
||||
{file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"},
|
||||
{file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"},
|
||||
]
|
||||
platformdirs = [
|
||||
{file = "platformdirs-3.1.1-py3-none-any.whl", hash = "sha256:e5986afb596e4bb5bde29a79ac9061aa955b94fca2399b7aaac4090860920dd8"},
|
||||
{file = "platformdirs-3.1.1.tar.gz", hash = "sha256:024996549ee88ec1a9aa99ff7f8fc819bb59e2c3477b410d90a16d32d6e707aa"},
|
||||
{file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"},
|
||||
{file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"},
|
||||
]
|
||||
pydantic = [
|
||||
{file = "pydantic-1.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9289065611c48147c1dd1fd344e9d57ab45f1d99b0fb26c51f1cf72cd9bcd31"},
|
||||
{file = "pydantic-1.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c32b6bba301490d9bb2bf5f631907803135e8085b6aa3e5fe5a770d46dd0160"},
|
||||
{file = "pydantic-1.10.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd9b9e98068fa1068edfc9eabde70a7132017bdd4f362f8b4fd0abed79c33083"},
|
||||
{file = "pydantic-1.10.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c84583b9df62522829cbc46e2b22e0ec11445625b5acd70c5681ce09c9b11c4"},
|
||||
{file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b41822064585fea56d0116aa431fbd5137ce69dfe837b599e310034171996084"},
|
||||
{file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61f1f08adfaa9cc02e0cbc94f478140385cbd52d5b3c5a657c2fceb15de8d1fb"},
|
||||
{file = "pydantic-1.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:32937835e525d92c98a1512218db4eed9ddc8f4ee2a78382d77f54341972c0e7"},
|
||||
{file = "pydantic-1.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bbd5c531b22928e63d0cb1868dee76123456e1de2f1cb45879e9e7a3f3f1779b"},
|
||||
{file = "pydantic-1.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e277bd18339177daa62a294256869bbe84df1fb592be2716ec62627bb8d7c81d"},
|
||||
{file = "pydantic-1.10.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f15277d720aa57e173954d237628a8d304896364b9de745dcb722f584812c7"},
|
||||
{file = "pydantic-1.10.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b243b564cea2576725e77aeeda54e3e0229a168bc587d536cd69941e6797543d"},
|
||||
{file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3ce13a558b484c9ae48a6a7c184b1ba0e5588c5525482681db418268e5f86186"},
|
||||
{file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3ac1cd4deed871dfe0c5f63721e29debf03e2deefa41b3ed5eb5f5df287c7b70"},
|
||||
{file = "pydantic-1.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:b1eb6610330a1dfba9ce142ada792f26bbef1255b75f538196a39e9e90388bf4"},
|
||||
{file = "pydantic-1.10.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4ca83739c1263a044ec8b79df4eefc34bbac87191f0a513d00dd47d46e307a65"},
|
||||
{file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea4e2a7cb409951988e79a469f609bba998a576e6d7b9791ae5d1e0619e1c0f2"},
|
||||
{file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53de12b4608290992a943801d7756f18a37b7aee284b9ffa794ee8ea8153f8e2"},
|
||||
{file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:60184e80aac3b56933c71c48d6181e630b0fbc61ae455a63322a66a23c14731a"},
|
||||
{file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:415a3f719ce518e95a92effc7ee30118a25c3d032455d13e121e3840985f2efd"},
|
||||
{file = "pydantic-1.10.6-cp37-cp37m-win_amd64.whl", hash = "sha256:72cb30894a34d3a7ab6d959b45a70abac8a2a93b6480fc5a7bfbd9c935bdc4fb"},
|
||||
{file = "pydantic-1.10.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3091d2eaeda25391405e36c2fc2ed102b48bac4b384d42b2267310abae350ca6"},
|
||||
{file = "pydantic-1.10.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:751f008cd2afe812a781fd6aa2fb66c620ca2e1a13b6a2152b1ad51553cb4b77"},
|
||||
{file = "pydantic-1.10.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12e837fd320dd30bd625be1b101e3b62edc096a49835392dcf418f1a5ac2b832"},
|
||||
{file = "pydantic-1.10.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d92831d0115874d766b1f5fddcdde0c5b6c60f8c6111a394078ec227fca6d"},
|
||||
{file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:476f6674303ae7965730a382a8e8d7fae18b8004b7b69a56c3d8fa93968aa21c"},
|
||||
{file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3a2be0a0f32c83265fd71a45027201e1278beaa82ea88ea5b345eea6afa9ac7f"},
|
||||
{file = "pydantic-1.10.6-cp38-cp38-win_amd64.whl", hash = "sha256:0abd9c60eee6201b853b6c4be104edfba4f8f6c5f3623f8e1dba90634d63eb35"},
|
||||
{file = "pydantic-1.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6195ca908045054dd2d57eb9c39a5fe86409968b8040de8c2240186da0769da7"},
|
||||
{file = "pydantic-1.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43cdeca8d30de9a897440e3fb8866f827c4c31f6c73838e3a01a14b03b067b1d"},
|
||||
{file = "pydantic-1.10.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c19eb5163167489cb1e0161ae9220dadd4fc609a42649e7e84a8fa8fff7a80f"},
|
||||
{file = "pydantic-1.10.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:012c99a9c0d18cfde7469aa1ebff922e24b0c706d03ead96940f5465f2c9cf62"},
|
||||
{file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:528dcf7ec49fb5a84bf6fe346c1cc3c55b0e7603c2123881996ca3ad79db5bfc"},
|
||||
{file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:163e79386c3547c49366e959d01e37fc30252285a70619ffc1b10ede4758250a"},
|
||||
{file = "pydantic-1.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:189318051c3d57821f7233ecc94708767dd67687a614a4e8f92b4a020d4ffd06"},
|
||||
{file = "pydantic-1.10.6-py3-none-any.whl", hash = "sha256:acc6783751ac9c9bc4680379edd6d286468a1dc8d7d9906cd6f1186ed682b2b0"},
|
||||
{file = "pydantic-1.10.6.tar.gz", hash = "sha256:cf95adb0d1671fc38d8c43dd921ad5814a735e7d9b4d9e437c088002863854fd"},
|
||||
{file = "pydantic-1.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1243d28e9b05003a89d72e7915fdb26ffd1d39bdd39b00b7dbe4afae4b557f9d"},
|
||||
{file = "pydantic-1.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0ab53b609c11dfc0c060d94335993cc2b95b2150e25583bec37a49b2d6c6c3f"},
|
||||
{file = "pydantic-1.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9613fadad06b4f3bc5db2653ce2f22e0de84a7c6c293909b48f6ed37b83c61f"},
|
||||
{file = "pydantic-1.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df7800cb1984d8f6e249351139667a8c50a379009271ee6236138a22a0c0f319"},
|
||||
{file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0c6fafa0965b539d7aab0a673a046466d23b86e4b0e8019d25fd53f4df62c277"},
|
||||
{file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e82d4566fcd527eae8b244fa952d99f2ca3172b7e97add0b43e2d97ee77f81ab"},
|
||||
{file = "pydantic-1.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:ab523c31e22943713d80d8d342d23b6f6ac4b792a1e54064a8d0cf78fd64e800"},
|
||||
{file = "pydantic-1.10.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:666bdf6066bf6dbc107b30d034615d2627e2121506c555f73f90b54a463d1f33"},
|
||||
{file = "pydantic-1.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:35db5301b82e8661fa9c505c800d0990bc14e9f36f98932bb1d248c0ac5cada5"},
|
||||
{file = "pydantic-1.10.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90c1e29f447557e9e26afb1c4dbf8768a10cc676e3781b6a577841ade126b85"},
|
||||
{file = "pydantic-1.10.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93e766b4a8226e0708ef243e843105bf124e21331694367f95f4e3b4a92bbb3f"},
|
||||
{file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88f195f582851e8db960b4a94c3e3ad25692c1c1539e2552f3df7a9e972ef60e"},
|
||||
{file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:34d327c81e68a1ecb52fe9c8d50c8a9b3e90d3c8ad991bfc8f953fb477d42fb4"},
|
||||
{file = "pydantic-1.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:d532bf00f381bd6bc62cabc7d1372096b75a33bc197a312b03f5838b4fb84edd"},
|
||||
{file = "pydantic-1.10.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d5b8641c24886d764a74ec541d2fc2c7fb19f6da2a4001e6d580ba4a38f7878"},
|
||||
{file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b1f6cb446470b7ddf86c2e57cd119a24959af2b01e552f60705910663af09a4"},
|
||||
{file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c33b60054b2136aef8cf190cd4c52a3daa20b2263917c49adad20eaf381e823b"},
|
||||
{file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1952526ba40b220b912cdc43c1c32bcf4a58e3f192fa313ee665916b26befb68"},
|
||||
{file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bb14388ec45a7a0dc429e87def6396f9e73c8c77818c927b6a60706603d5f2ea"},
|
||||
{file = "pydantic-1.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:16f8c3e33af1e9bb16c7a91fc7d5fa9fe27298e9f299cff6cb744d89d573d62c"},
|
||||
{file = "pydantic-1.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ced8375969673929809d7f36ad322934c35de4af3b5e5b09ec967c21f9f7887"},
|
||||
{file = "pydantic-1.10.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93e6bcfccbd831894a6a434b0aeb1947f9e70b7468f274154d03d71fabb1d7c6"},
|
||||
{file = "pydantic-1.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:191ba419b605f897ede9892f6c56fb182f40a15d309ef0142212200a10af4c18"},
|
||||
{file = "pydantic-1.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:052d8654cb65174d6f9490cc9b9a200083a82cf5c3c5d3985db765757eb3b375"},
|
||||
{file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ceb6a23bf1ba4b837d0cfe378329ad3f351b5897c8d4914ce95b85fba96da5a1"},
|
||||
{file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f2e754d5566f050954727c77f094e01793bcb5725b663bf628fa6743a5a9108"},
|
||||
{file = "pydantic-1.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:6a82d6cda82258efca32b40040228ecf43a548671cb174a1e81477195ed3ed56"},
|
||||
{file = "pydantic-1.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e59417ba8a17265e632af99cc5f35ec309de5980c440c255ab1ca3ae96a3e0e"},
|
||||
{file = "pydantic-1.10.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84d80219c3f8d4cad44575e18404099c76851bc924ce5ab1c4c8bb5e2a2227d0"},
|
||||
{file = "pydantic-1.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e4148e635994d57d834be1182a44bdb07dd867fa3c2d1b37002000646cc5459"},
|
||||
{file = "pydantic-1.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12f7b0bf8553e310e530e9f3a2f5734c68699f42218bf3568ef49cd9b0e44df4"},
|
||||
{file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42aa0c4b5c3025483240a25b09f3c09a189481ddda2ea3a831a9d25f444e03c1"},
|
||||
{file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17aef11cc1b997f9d574b91909fed40761e13fac438d72b81f902226a69dac01"},
|
||||
{file = "pydantic-1.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:66a703d1983c675a6e0fed8953b0971c44dba48a929a2000a493c3772eb61a5a"},
|
||||
{file = "pydantic-1.10.8-py3-none-any.whl", hash = "sha256:7456eb22ed9aaa24ff3e7b4757da20d9e5ce2a81018c1b3ebd81a0b88a18f3b2"},
|
||||
{file = "pydantic-1.10.8.tar.gz", hash = "sha256:1410275520dfa70effadf4c21811d755e7ef9bb1f1d077a21958153a92c8d9ca"},
|
||||
]
|
||||
pylint = [
|
||||
{file = "pylint-2.17.0-py3-none-any.whl", hash = "sha256:e097d8325f8c88e14ad12844e3fe2d963d3de871ea9a8f8ad25ab1c109889ddc"},
|
||||
{file = "pylint-2.17.0.tar.gz", hash = "sha256:1460829b6397cb5eb0cdb0b4fc4b556348e515cdca32115f74a1eb7c20b896b4"},
|
||||
{file = "pylint-2.17.4-py3-none-any.whl", hash = "sha256:7a1145fb08c251bdb5cca11739722ce64a63db479283d10ce718b2460e54123c"},
|
||||
{file = "pylint-2.17.4.tar.gz", hash = "sha256:5dcf1d9e19f41f38e4e85d10f511e5b9c35e1aa74251bf95cdd8cb23584e2db1"},
|
||||
]
|
||||
requests = [
|
||||
{file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"},
|
||||
{file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"},
|
||||
{file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
|
||||
{file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
|
||||
]
|
||||
requests-toolbelt = [
|
||||
{file = "requests-toolbelt-0.10.1.tar.gz", hash = "sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d"},
|
||||
@@ -790,8 +809,8 @@ ruff = [
|
||||
{file = "ruff-0.0.166.tar.gz", hash = "sha256:804fa54aa04e0253b2f39a0ce7089359ea6ba2f037f299f5d8606605e5e37bfa"},
|
||||
]
|
||||
specklepy = [
|
||||
{file = "specklepy-2.13.0-py3-none-any.whl", hash = "sha256:7111a30c641f0dd929985c20d4e0bb6c8205c6fb5f591b0acb7e6d7745de6abe"},
|
||||
{file = "specklepy-2.13.0.tar.gz", hash = "sha256:5f3d9b120191b032fdb1c856c5d1b3a7fadb14561fbc46a237dcbf02aad08fea"},
|
||||
{file = "specklepy-2.14.0-py3-none-any.whl", hash = "sha256:c5b912155346ace934b26f745e80d2b23d5bf73ce914c625dccaa1a310e18ad0"},
|
||||
{file = "specklepy-2.14.0.tar.gz", hash = "sha256:7c7fbdd1809cfa722066be5e2fd45562b9d97a9d5a06308c1dc993ac1860931e"},
|
||||
]
|
||||
stringcase = [
|
||||
{file = "stringcase-1.2.0.tar.gz", hash = "sha256:48a06980661908efe8d9d34eab2b6c13aefa2163b3ced26972902e3bdfd87008"},
|
||||
@@ -801,12 +820,12 @@ tomli = [
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
tomlkit = [
|
||||
{file = "tomlkit-0.11.6-py3-none-any.whl", hash = "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b"},
|
||||
{file = "tomlkit-0.11.6.tar.gz", hash = "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73"},
|
||||
{file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"},
|
||||
{file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"},
|
||||
]
|
||||
typing-extensions = [
|
||||
{file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"},
|
||||
{file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"},
|
||||
{file = "typing_extensions-4.6.2-py3-none-any.whl", hash = "sha256:3a8b36f13dd5fdc5d1b16fe317f5668545de77fa0b8e02006381fd49d731ab98"},
|
||||
{file = "typing_extensions-4.6.2.tar.gz", hash = "sha256:06006244c70ac8ee83fa8282cb188f697b8db25bc8b4df07be1873c43897060c"},
|
||||
]
|
||||
ujson = [
|
||||
{file = "ujson-5.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5eba5e69e4361ac3a311cf44fa71bc619361b6e0626768a494771aacd1c2f09b"},
|
||||
@@ -876,8 +895,8 @@ ujson = [
|
||||
{file = "ujson-5.7.0.tar.gz", hash = "sha256:e788e5d5dcae8f6118ac9b45d0b891a0d55f7ac480eddcb7f07263f2bcf37b23"},
|
||||
]
|
||||
urllib3 = [
|
||||
{file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"},
|
||||
{file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"},
|
||||
{file = "urllib3-1.26.16-py2.py3-none-any.whl", hash = "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f"},
|
||||
{file = "urllib3-1.26.16.tar.gz", hash = "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"},
|
||||
]
|
||||
websockets = [
|
||||
{file = "websockets-10.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d58804e996d7d2307173d56c297cf7bc132c52df27a3efaac5e8d43e36c21c48"},
|
||||
@@ -1028,78 +1047,78 @@ wrapt = [
|
||||
{file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"},
|
||||
]
|
||||
yarl = [
|
||||
{file = "yarl-1.8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bb81f753c815f6b8e2ddd2eef3c855cf7da193b82396ac013c661aaa6cc6b0a5"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:47d49ac96156f0928f002e2424299b2c91d9db73e08c4cd6742923a086f1c863"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3fc056e35fa6fba63248d93ff6e672c096f95f7836938241ebc8260e062832fe"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58a3c13d1c3005dbbac5c9f0d3210b60220a65a999b1833aa46bd6677c69b08e"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10b08293cda921157f1e7c2790999d903b3fd28cd5c208cf8826b3b508026996"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de986979bbd87272fe557e0a8fcb66fd40ae2ddfe28a8b1ce4eae22681728fef"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c4fcfa71e2c6a3cb568cf81aadc12768b9995323186a10827beccf5fa23d4f8"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae4d7ff1049f36accde9e1ef7301912a751e5bae0a9d142459646114c70ecba6"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bf071f797aec5b96abfc735ab97da9fd8f8768b43ce2abd85356a3127909d146"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:74dece2bfc60f0f70907c34b857ee98f2c6dd0f75185db133770cd67300d505f"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:df60a94d332158b444301c7f569659c926168e4d4aad2cfbf4bce0e8fb8be826"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:63243b21c6e28ec2375f932a10ce7eda65139b5b854c0f6b82ed945ba526bff3"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cfa2bbca929aa742b5084fd4663dd4b87c191c844326fcb21c3afd2d11497f80"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-win32.whl", hash = "sha256:b05df9ea7496df11b710081bd90ecc3a3db6adb4fee36f6a411e7bc91a18aa42"},
|
||||
{file = "yarl-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:24ad1d10c9db1953291f56b5fe76203977f1ed05f82d09ec97acb623a7976574"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a1fca9588f360036242f379bfea2b8b44cae2721859b1c56d033adfd5893634"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f37db05c6051eff17bc832914fe46869f8849de5b92dc4a3466cd63095d23dfd"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77e913b846a6b9c5f767b14dc1e759e5aff05502fe73079f6f4176359d832581"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0978f29222e649c351b173da2b9b4665ad1feb8d1daa9d971eb90df08702668a"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388a45dc77198b2460eac0aca1efd6a7c09e976ee768b0d5109173e521a19daf"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2305517e332a862ef75be8fad3606ea10108662bc6fe08509d5ca99503ac2aee"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42430ff511571940d51e75cf42f1e4dbdded477e71c1b7a17f4da76c1da8ea76"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3150078118f62371375e1e69b13b48288e44f6691c1069340081c3fd12c94d5b"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c15163b6125db87c8f53c98baa5e785782078fbd2dbeaa04c6141935eb6dab7a"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4d04acba75c72e6eb90745447d69f84e6c9056390f7a9724605ca9c56b4afcc6"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e7fd20d6576c10306dea2d6a5765f46f0ac5d6f53436217913e952d19237efc4"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:75c16b2a900b3536dfc7014905a128a2bea8fb01f9ee26d2d7d8db0a08e7cb2c"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6d88056a04860a98341a0cf53e950e3ac9f4e51d1b6f61a53b0609df342cc8b2"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-win32.whl", hash = "sha256:fb742dcdd5eec9f26b61224c23baea46c9055cf16f62475e11b9b15dfd5c117b"},
|
||||
{file = "yarl-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:8c46d3d89902c393a1d1e243ac847e0442d0196bbd81aecc94fcebbc2fd5857c"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ceff9722e0df2e0a9e8a79c610842004fa54e5b309fe6d218e47cd52f791d7ef"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f6b4aca43b602ba0f1459de647af954769919c4714706be36af670a5f44c9c1"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1684a9bd9077e922300ecd48003ddae7a7474e0412bea38d4631443a91d61077"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebb78745273e51b9832ef90c0898501006670d6e059f2cdb0e999494eb1450c2"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3adeef150d528ded2a8e734ebf9ae2e658f4c49bf413f5f157a470e17a4a2e89"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57a7c87927a468e5a1dc60c17caf9597161d66457a34273ab1760219953f7f4c"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:efff27bd8cbe1f9bd127e7894942ccc20c857aa8b5a0327874f30201e5ce83d0"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a783cd344113cb88c5ff7ca32f1f16532a6f2142185147822187913eb989f739"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:705227dccbe96ab02c7cb2c43e1228e2826e7ead880bb19ec94ef279e9555b5b"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:34c09b43bd538bf6c4b891ecce94b6fa4f1f10663a8d4ca589a079a5018f6ed7"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a48f4f7fea9a51098b02209d90297ac324241bf37ff6be6d2b0149ab2bd51b37"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-win32.whl", hash = "sha256:0414fd91ce0b763d4eadb4456795b307a71524dbacd015c657bb2a39db2eab89"},
|
||||
{file = "yarl-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:d881d152ae0007809c2c02e22aa534e702f12071e6b285e90945aa3c376463c5"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5df5e3d04101c1e5c3b1d69710b0574171cc02fddc4b23d1b2813e75f35a30b1"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7a66c506ec67eb3159eea5096acd05f5e788ceec7b96087d30c7d2865a243918"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2b4fa2606adf392051d990c3b3877d768771adc3faf2e117b9de7eb977741229"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e21fb44e1eff06dd6ef971d4bdc611807d6bd3691223d9c01a18cec3677939e"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93202666046d9edadfe9f2e7bf5e0782ea0d497b6d63da322e541665d65a044e"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc77086ce244453e074e445104f0ecb27530d6fd3a46698e33f6c38951d5a0f1"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dd68a92cab699a233641f5929a40f02a4ede8c009068ca8aa1fe87b8c20ae3"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b372aad2b5f81db66ee7ec085cbad72c4da660d994e8e590c997e9b01e44901"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e6f3515aafe0209dd17fb9bdd3b4e892963370b3de781f53e1746a521fb39fc0"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dfef7350ee369197106805e193d420b75467b6cceac646ea5ed3049fcc950a05"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:728be34f70a190566d20aa13dc1f01dc44b6aa74580e10a3fb159691bc76909d"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ff205b58dc2929191f68162633d5e10e8044398d7a45265f90a0f1d51f85f72c"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baf211dcad448a87a0d9047dc8282d7de59473ade7d7fdf22150b1d23859f946"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-win32.whl", hash = "sha256:272b4f1599f1b621bf2aabe4e5b54f39a933971f4e7c9aa311d6d7dc06965165"},
|
||||
{file = "yarl-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:326dd1d3caf910cd26a26ccbfb84c03b608ba32499b5d6eeb09252c920bcbe4f"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f8ca8ad414c85bbc50f49c0a106f951613dfa5f948ab69c10ce9b128d368baf8"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:418857f837347e8aaef682679f41e36c24250097f9e2f315d39bae3a99a34cbf"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae0eec05ab49e91a78700761777f284c2df119376e391db42c38ab46fd662b77"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:009a028127e0a1755c38b03244c0bea9d5565630db9c4cf9572496e947137a87"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3edac5d74bb3209c418805bda77f973117836e1de7c000e9755e572c1f7850d0"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da65c3f263729e47351261351b8679c6429151ef9649bba08ef2528ff2c423b2"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef8fb25e52663a1c85d608f6dd72e19bd390e2ecaf29c17fb08f730226e3a08"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcd7bb1e5c45274af9a1dd7494d3c52b2be5e6bd8d7e49c612705fd45420b12d"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44ceac0450e648de86da8e42674f9b7077d763ea80c8ceb9d1c3e41f0f0a9951"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:97209cc91189b48e7cfe777237c04af8e7cc51eb369004e061809bcdf4e55220"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:48dd18adcf98ea9cd721a25313aef49d70d413a999d7d89df44f469edfb38a06"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e59399dda559688461762800d7fb34d9e8a6a7444fd76ec33220a926c8be1516"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d617c241c8c3ad5c4e78a08429fa49e4b04bedfc507b34b4d8dceb83b4af3588"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-win32.whl", hash = "sha256:cb6d48d80a41f68de41212f3dfd1a9d9898d7841c8f7ce6696cf2fd9cb57ef83"},
|
||||
{file = "yarl-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:6604711362f2dbf7160df21c416f81fac0de6dbcf0b5445a2ef25478ecc4c778"},
|
||||
{file = "yarl-1.8.2.tar.gz", hash = "sha256:49d43402c6e3013ad0978602bf6bf5328535c48d192304b91b97a3c6790b1562"},
|
||||
{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"},
|
||||
]
|
||||
|
||||
+2
-1
@@ -7,7 +7,8 @@ license = "Apache-2.0"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.8, <4.0.0"
|
||||
specklepy = "^2.13.0"
|
||||
specklepy = "^2.14.0"
|
||||
attrs = "^23.1.0"
|
||||
|
||||
# [tool.poetry.group.local_specklepy.dependencies]
|
||||
# specklepy = {path = "../specklepy", develop = true}
|
||||
|
||||
Reference in New Issue
Block a user