Compare commits

...

40 Commits

Author SHA1 Message Date
izzy lyseggen c62538fc8f Merge pull request #78 from specklesystems/izzy/blocks
feat(convert): big refactor !! and blocks 🧊
2022-01-10 17:41:07 +00:00
izzylys fd83e80bbd refactor: final cleanup 2022-01-10 09:40:44 -08:00
izzylys 0a2c1f9f32 refactor(convert): remove unused methods 2022-01-10 09:26:22 -08:00
izzylys 2975737377 feat(convert): col fixes & can_convert_to_native 2022-01-10 09:18:16 -08:00
izzylys 72dea53eee feat(convert): block to speckle 2022-01-10 09:17:51 -08:00
izzylys a1aa267a30 fix(convert): custom props and cols fixes 2022-01-07 10:17:42 -08:00
izzylys df30b65fdb refactor: deleting code is my love language 2022-01-07 09:09:29 -08:00
izzylys 6176abb4a3 refactor(converter): more cleanup 2022-01-06 13:41:43 -08:00
izzylys 5c2d2d195f refactor(converter): to_speckle refactor!! 2022-01-06 11:42:46 -08:00
izzylys 7a784a4a8d fix(convert): unique names for all instances
add the id to the end of the name to ensure this
2022-01-04 13:09:58 -08:00
izzylys 2c8f2c96a9 feat(convert): BIG to native refactor + blocks 2022-01-04 12:42:14 -08:00
izzylys bc7400cb36 Merge branch 'izzy/blocks' of https://github.com/specklesystems/speckle-blender into izzy/blocks 2022-01-03 10:46:35 -08:00
izzy lyseggen 421c68a143 wip: block nonsense from other pc 2022-01-03 18:37:00 +00:00
izzy lyseggen 409adda784 Merge pull request #77 from specklesystems/izzy/nulls-fix
fix(convert): nulls on receive
2022-01-03 17:11:40 +00:00
izzylys f5f1c6a8d0 fix(convert): handle list display val 2022-01-03 17:09:57 +00:00
izzylys 1eca91a030 chore: bump specklepy 2022-01-03 17:09:29 +00:00
izzy lyseggen 6b872f11d9 Merge pull request #75 from specklesystems/izzy/add-parent-type
feat(convert): add parent type to display meshes
2021-12-09 10:59:28 +00:00
izzy lyseggen fd3742b800 feat(convert): add parent type to display meshes
makes it easier to work w geo from places like revit
2021-12-09 10:58:22 +00:00
izzy lyseggen 870174a969 Merge pull request #73 from specklesystems/ci/fix-install-platform
ci: fix install platform
2021-12-07 16:26:58 +00:00
izzy lyseggen 2c6dfcb340 ci: grab py version to ensure all is working 2021-12-07 16:22:42 +00:00
izzy lyseggen 4d3eacbe52 ci: no need to persist now i think 2021-12-07 16:05:51 +00:00
izzy lyseggen df7d631b54 ci: bump to 3.9.2 2021-12-07 16:05:23 +00:00
izzy lyseggen 07ceb07058 ci: try ths install again! 2021-12-07 16:01:16 +00:00
izzy lyseggen 112bc56ded ci: remove install specklepy step 2021-12-07 15:54:59 +00:00
izzy lyseggen 88e2744e93 ci: test in win exe 2021-12-07 15:53:52 +00:00
izzy lyseggen ad1c201c79 Merge pull request #72 from specklesystems/ci/install-changes
ci: preinstall specklepy
2021-12-07 14:54:26 +00:00
Gergő Jedlicska e18569f738 (ci) wait for install 2021-12-07 15:18:03 +01:00
Gergő Jedlicska f7e563f500 (ci) new glob 2021-12-07 15:15:13 +01:00
Gergő Jedlicska 7e56c21395 (ci) what is attached? 2021-12-07 15:01:47 +01:00
Gergő Jedlicska 30b701ee27 Merge branch 'ci/install-changes' of github.com:specklesystems/speckle-blender into ci/install-changes 2021-12-07 14:48:50 +01:00
Gergő Jedlicska 3cdbc09fc0 (ci) update job order 2021-12-07 14:48:43 +01:00
Gergő Jedlicska 656e41f03c (ci) update job order 2021-12-07 14:41:09 +01:00
Gergő Jedlicska 7da26e44b6 Update config.yml
try with glob pattern
2021-12-07 14:27:30 +01:00
izzy lyseggen 830ba842e0 ci: remove unecessary steps 2021-12-07 13:01:31 +00:00
izzy lyseggen d38f990e75 ci: fix modules path 2021-12-07 12:42:51 +00:00
izzy lyseggen c01836806c ci: persist to workspace 2021-12-07 12:38:20 +00:00
izzy lyseggen bf416dd228 ci: remove pip upgrade step? 2021-12-07 12:28:48 +00:00
izzy lyseggen a2e2c489b4 ci: change branch filter 2021-12-07 12:17:12 +00:00
izzy lyseggen c40c2d7955 ci: add specklepy install step 2021-12-07 12:08:37 +00:00
izzy lyseggen b45aa0d6c1 chore: return specklepy V in patch script w no arg
should allow us to grab the version for manual specklepy install in the ci env
2021-12-07 12:07:27 +00:00
30 changed files with 1542 additions and 1265 deletions
+50 -31
View File
@@ -20,9 +20,25 @@ jobs:
- checkout
- attach_workspace:
at: ./
# - run:
# name: upgrade pip and install specklepy
# command: python -m pip install --upgrade pip & python -m pip install --target=.\modules specklepy
- run:
name: Install specklepy with python 3.7
shell: powershell.exe
command: |
$pyarr=(python --version).split(' ')[1].split('.')
$pyver=($pyarr[0..1] -join '.')
echo "using python version:" $pyver
$specklepy=(python patch_version.py)
python -m pip install --target=./modules-$pyver specklepy==$specklepy
- run:
name: Install python 3.9 and specklepy
shell: powershell.exe
command: |
choco install python --version=3.9.2
$pyarr=(C:\Python39\python.exe --version).split(' ')[1].split('.')
$pyver=($pyarr[0..1] -join '.')
echo "using python version:" $pyver
$specklepy=(python patch_version.py)
C:\Python39\python.exe -m pip install --target=./modules-$pyver specklepy==$specklepy
- run:
name: Patch
shell: powershell.exe
@@ -36,13 +52,34 @@ jobs:
# only create the yml if we have a tag
New-Item -Force "speckle-sharp-ci-tools/Installers/blender/$channel.yml" -ItemType File -Value "version: $version"
echo $version
ls
python patch_version.py $version
speckle-sharp-ci-tools\InnoSetup\ISCC.exe speckle-sharp-ci-tools\blender.iss
- persist_to_workspace:
root: ./
paths:
- speckle-sharp-ci-tools/Installers
install-specklepy: # due to ujson dep, we need to match the py version to the install
docker:
- image: "cimg/python:<<parameters.tag>>"
parameters:
tag:
default: "3.9"
type: string
steps:
- checkout
- run:
name: upgrade pip and install specklepy
command: |
specklepyver=$(python patch_version.py)
echo installing specklepy $specklepyver
python -m pip install --target=./modules-<<parameters.tag>> specklepy==$specklepyver
- persist_to_workspace:
root: ./
paths:
- modules-*
get-ci-tools: # Clones our ci tools and persists them to the workspace
docker:
- image: cimg/base:2021.01
@@ -54,10 +91,6 @@ jobs:
root: ./
paths:
- speckle-sharp-ci-tools
- persist_to_workspace:
root: ./
paths:
- speckle-sharp-ci-tools
deploy: # Uploads all installers found to S3
docker:
@@ -77,41 +110,27 @@ jobs:
to: s3://speckle-releases/installers/
workflows:
build:
jobs:
- get-ci-tools:
filters:
branches:
only:
- main
- /ci\/.*/
- build-connector:
slug: blender
requires:
- get-ci-tools
filters:
branches:
only:
- main
- /ci\/.*/
deploy:
main:
jobs:
- get-ci-tools:
filters:
tags:
only: /[0-9]+(\.[0-9]+)*/
only: /.*/
branches:
ignore: /.*/ # For testing only! /ci\/.*/
only:
- main
- /ci\/.*/
- build-connector:
slug: blender
requires:
- get-ci-tools
filters:
tags:
only: /[0-9]+(\.[0-9]+)*/
only: /.*/
branches:
ignore: /.*/ # For testing only! /ci\/.*/
only:
- main
- /ci\/.*/
- deploy:
requires:
- get-ci-tools
-1
View File
@@ -11,4 +11,3 @@ def scb_on_mesh_edit(context):
edit_obj = bpy.context.edit_object
if edit_obj is not None and edit_obj.is_updated_data is True:
print("Mesh edited: {}".format(edit_obj))
# print('>>> Update')
+4 -290
View File
@@ -1,241 +1,14 @@
import bpy, idprop
from mathutils import Matrix
from .from_speckle import *
from .to_speckle import *
from .util import *
from bpy_speckle.functions import _report, get_scale_length
from specklepy.objects.geometry import *
from specklepy.objects.other import RenderMaterial
FROM_SPECKLE_SCHEMAS = {
Mesh: import_mesh,
Brep: import_brep,
Curve: import_curve,
Line: import_curve,
Polyline: import_curve,
Polycurve: import_curve,
Arc: import_curve,
}
TO_SPECKLE = {
"MESH": export_mesh,
"CURVE": export_curve,
"EMPTY": export_empty,
}
def set_transform(speckle_object, blender_object):
transform = None
if hasattr(speckle_object, "transform"):
transform = speckle_object.transform
elif (
hasattr(speckle_object, "properties") and speckle_object.properties is not None
):
transform = speckle_object.properties.get("transform", None)
if transform and len(transform) == 16:
mat = Matrix(
[transform[0:4], transform[4:8], transform[8:12], transform[12:16]]
)
blender_object.matrix_world = mat
def add_blender_material(smesh, blender_object) -> None:
"""Add material to a blender object if the corresponding speckle object has a render material"""
if blender_object.data is None:
return
if not hasattr(smesh, "renderMaterial") and not hasattr(smesh, "@renderMaterial"):
return
speckle_mat = getattr(smesh, "renderMaterial", None) or smesh["@renderMaterial"]
mat_name = getattr(speckle_mat, "name", None) or speckle_mat.__dict__.get("@name")
if not mat_name:
mat_name = speckle_mat.applicationId or speckle_mat.id or speckle_mat.get_id()
blender_mat = bpy.data.materials.get(mat_name)
if not blender_mat:
blender_mat = bpy.data.materials.new(mat_name)
# for now, we're not updating these materials. as per tom's suggestion, we should have a toggle
# that enables this as the blender mats will prob be much more complex than whatever is coming in
blender_mat.use_nodes = True
inputs = blender_mat.node_tree.nodes["Principled BSDF"].inputs
inputs["Base Color"].default_value = to_rgba(speckle_mat.diffuse)
inputs["Emission"].default_value = to_rgba(speckle_mat.emissive)
inputs["Roughness"].default_value = speckle_mat.roughness
inputs["Metallic"].default_value = speckle_mat.metalness
inputs["Alpha"].default_value = speckle_mat.opacity
if speckle_mat.opacity < 1:
blender_mat.blend_method = "BLEND"
blender_object.data.materials.append(blender_mat)
def material_to_speckle(blender_object) -> RenderMaterial:
"""Create and return a render material from a blender object"""
if not getattr(blender_object.data, "materials", None):
return
blender_mat = blender_object.data.materials[0]
speckle_mat = RenderMaterial()
speckle_mat.name = blender_mat.name
if blender_mat.use_nodes is True:
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
else:
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
def try_add_property(speckle_object, blender_object, prop, prop_name):
if prop in speckle_object.keys() and speckle_object[prop] is not None:
blender_object[prop_name] = speckle_object[prop]
# def add_dictionary(prop, blender_object, superkey=None):
# for key in prop.keys():
# key_name = "{}.{}".format(superkey, key) if superkey else "{}".format(key)
# if isinstance(prop[key], dict):
# subtype = prop[key].get("type", None)
# if subtype and subtype in FROM_SPECKLE.keys():
# continue
# else:
# add_dictionary(prop[key], blender_object, key_name)
# elif hasattr(prop[key], "type"):
# subtype = prop[key].type
# if subtype and subtype in FROM_SPECKLE.keys():
# continue
# else:
# try:
# blender_object[key_name] = prop[key]
# except KeyError:
# pass
def add_custom_properties(speckle_object, blender_object):
if blender_object is None:
return
blender_object["_speckle_type"] = type(speckle_object).__name__
# blender_object['_speckle_name'] = "SpeckleObject"
ignore = ["_chunkable", "_units", "units"]
if hasattr(speckle_object, "applicationId"):
blender_object["applicationId"] = speckle_object.applicationId
for key in speckle_object.get_dynamic_member_names():
if key in ignore:
continue
if isinstance(speckle_object[key], (int, str, float, dict)):
blender_object[key] = speckle_object[key]
def dict_to_speckle_object(data):
if "type" in data.keys() and data["type"] in SCHEMAS.keys():
obj = SCHEMAS[data["type"]].parse_obj(data)
for key in obj.properties.keys():
if isinstance(obj.properties[key], dict):
obj.properties[key] = dict_to_speckle_object(obj.properties[key])
elif isinstance(obj.properties[key], list):
for i in range(len(obj.properties[key])):
if isinstance(obj.properties[key][i], dict):
obj.properties[key][i] = dict_to_speckle_object(
obj.properties[key][i]
)
return obj
else:
for key in data.keys():
if isinstance(data[key], dict):
data[key] = dict_to_speckle_object(data[key])
elif isinstance(data[key], list):
for i in range(len(data[key])):
if isinstance(data[key][i], dict):
data[key][i] = dict_to_speckle_object(data[key][i])
return data
def from_speckle_object(speckle_object, scale, name=None):
speckle_name = (
name
or getattr(speckle_object, "name", None)
or speckle_object.speckle_type + f" -- {speckle_object.id}"
)
units = getattr(speckle_object, "units", None)
if units:
scale = get_scale_length(units) / bpy.context.scene.unit_settings.scale_length
# try native conversion
if type(speckle_object) in FROM_SPECKLE_SCHEMAS.keys():
print("Got object type: {}".format(type(speckle_object)))
try:
obdata = FROM_SPECKLE_SCHEMAS[type(speckle_object)](
speckle_object, scale, speckle_name
)
except Exception as e: # conversion error
_report(f"Error converting {speckle_object} \n{e}")
return None
if speckle_name in bpy.data.objects.keys():
blender_object = bpy.data.objects[speckle_name]
blender_object.data = obdata
blender_object.matrix_world = Matrix()
if hasattr(obdata, "materials"):
blender_object.data.materials.clear()
else:
blender_object = bpy.data.objects.new(speckle_name, obdata)
blender_object.speckle.object_id = str(speckle_object.id)
blender_object.speckle.enabled = True
add_custom_properties(speckle_object, blender_object)
add_blender_material(speckle_object, blender_object)
# TODO: chat with tom re transforms
# set_transform(speckle_object, blender_object)
return blender_object
# try display mesh
mesh = getattr(
speckle_object, "displayMesh", getattr(speckle_object, "displayValue", None)
)
if mesh:
return from_speckle_object(mesh, scale, speckle_name)
# return none if fail
_report("Invalid input: {}".format(speckle_object))
return None
from bpy_speckle.convert.to_native import convert_to_native
def get_speckle_subobjects(attr, scale, name):
subobjects = []
for key in attr.keys():
if isinstance(attr[key], dict):
subtype = attr[key].get("type", None)
if subtype:
name = "{}.{}".format(name, key)
# print("{} :: {}".format(name, subtype))
subobject = from_speckle_object(attr[key], scale, name)
add_custom_properties(attr[key], subobject)
name = f"{name}.{key}"
subobject = convert_to_native(attr[key], name)
subobjects.append(subobject)
props = attr[key].get("properties", None)
@@ -245,69 +18,10 @@ def get_speckle_subobjects(attr, scale, name):
subtype = attr[key].type
if subtype:
name = "{}.{}".format(name, key)
# print("{} :: {}".format(name, subtype))
subobject = from_speckle_object(attr[key], scale, name)
add_custom_properties(attr[key], subobject)
subobject = convert_to_native(attr[key], name)
subobjects.append(subobject)
props = attr[key].get("properties", None)
if props:
subobjects.extend(get_speckle_subobjects(props, scale, name))
return subobjects
ignored_keys = [
"speckle",
"_speckle_type",
"_speckle_name",
"_speckle_transform",
"_RNA_UI",
"transform",
"_units",
"_chunkable",
]
def get_blender_custom_properties(obj, max_depth=1000):
global ignored_keys
if max_depth < 0:
return obj
if hasattr(obj, "keys"):
return {
key: get_blender_custom_properties(obj[key], max_depth - 1)
for key in obj.keys()
if key not in ignored_keys and not key.startswith("_")
}
elif isinstance(obj, (list, tuple, idprop.types.IDPropertyArray)):
return [get_blender_custom_properties(o, max_depth - 1) for o in obj]
else:
return obj
def to_speckle_object(blender_object, scale, desgraph=None):
blender_type = blender_object.type
speckle_objects = []
speckle_material = material_to_speckle(blender_object)
if blender_type in TO_SPECKLE.keys():
if desgraph:
blender_object = blender_object.evaluated_get(desgraph)
converted = TO_SPECKLE[blender_type](blender_object, blender_object.data, scale)
if isinstance(converted, list):
speckle_objects.extend([c for c in converted if c != None])
for so in speckle_objects:
so.properties = get_blender_custom_properties(blender_object)
so.applicationId = so.properties.pop("applicationId", None)
if speckle_material:
so["renderMaterial"] = speckle_material
# Set object transform
so.properties["transform"] = [y for x in blender_object.matrix_world for y in x]
# _report(speckle_objects)
return speckle_objects
@@ -1,3 +0,0 @@
from .mesh import import_mesh
from .curve import import_curve
from .brep import import_brep
-24
View File
@@ -1,24 +0,0 @@
import bpy
from .mesh import to_bmesh
from bpy_speckle.util import find_key_case_insensitive
def import_brep(speckle_brep, scale, name=None):
if not name:
name = speckle_brep.geometryHash or speckle_brep.id
display = getattr(
speckle_brep, "displayMesh", getattr(speckle_brep, "displayValue", None)
)
if display:
if name in bpy.data.meshes.keys():
mesh = bpy.data.meshes[name]
else:
mesh = bpy.data.meshes.new(name=name)
to_bmesh(display, mesh, name, scale)
# add_custom_properties(speckle_brep[dvKey], mesh)
else:
mesh = None
return mesh
-237
View File
@@ -1,237 +0,0 @@
import bpy, math
from bpy_speckle.util import find_key_case_insensitive
import mathutils
from specklepy.objects.geometry import *
CONVERT = {}
def import_line(scurve, bcurve, scale):
line = bcurve.splines.new("POLY")
line.points.add(1)
line.points[0].co = (
float(scurve.start.x) * scale,
float(scurve.start.y) * scale,
float(scurve.start.z) * scale,
1,
)
if scurve.end:
line.points[1].co = (
float(scurve.end.x) * scale,
float(scurve.end.y) * scale,
float(scurve.end.z) * scale,
1,
)
return line
CONVERT[Line] = import_line
def import_polyline(scurve, bcurve, scale):
# value = find_key_case_insensitive(scurve, "value")
value = scurve.value
if value:
N = int(len(value) / 3)
polyline = bcurve.splines.new("POLY")
if hasattr(scurve, "closed"):
polyline.use_cyclic_u = scurve.closed
# if "closed" in scurve.keys():
# polyline.use_cyclic_u = scurve["closed"]
polyline.points.add(N - 1)
for i in range(N):
polyline.points[i].co = (
float(value[i * 3]) * scale,
float(value[i * 3 + 1]) * scale,
float(value[i * 3 + 2]) * scale,
1,
)
return polyline
CONVERT[Polyline] = import_polyline
def import_nurbs_curve(scurve, bcurve, scale):
# points = find_key_case_insensitive(scurve, "points")
points = scurve.points
if points:
N = int(len(points) / 3)
nurbs = bcurve.splines.new("NURBS")
if hasattr(scurve, "closed"):
nurbs.use_cyclic_u = scurve.closed != 0
nurbs.points.add(N - 1)
for i in range(N):
nurbs.points[i].co = (
float(points[i * 3]) * scale,
float(points[i * 3 + 1]) * scale,
float(points[i * 3 + 2]) * scale,
1,
)
if len(scurve.weights) == len(nurbs.points):
for i, w in enumerate(scurve.weights):
nurbs.points[i].weight = w
# TODO: anaylize curve knots to decide if use_endpoint_u or use_bezier_u should be enabled
# nurbs.use_endpoint_u = True
nurbs.order_u = scurve.degree + 1
return nurbs
CONVERT[Curve] = import_nurbs_curve
def import_arc(rcurve, bcurve, scale):
"""
Convert Arc object
TODO: improve Blender representation of arc
"""
plane = rcurve.plane
if not plane:
return
origin = plane.origin
normal = mathutils.Vector([plane.normal.x, plane.normal.y, plane.normal.z])
xaxis = plane.xdir
yaxis = plane.ydir
radius = rcurve.radius * scale
startAngle = rcurve.startAngle
endAngle = rcurve.endAngle
startQuat = mathutils.Quaternion(normal, startAngle)
endQuat = mathutils.Quaternion(normal, endAngle)
"""
Get start and end vectors, centre point, angles, etc.
"""
r1 = mathutils.Vector([plane.xdir.x, plane.xdir.y, plane.xdir.z])
r1.rotate(startQuat)
r2 = mathutils.Vector([plane.xdir.x, plane.xdir.y, plane.xdir.z])
r2.rotate(endQuat)
c = mathutils.Vector([plane.origin.x, plane.origin.y, plane.origin.z]) * scale
spt = c + r1 * radius
ept = c + r2 * radius
angle = endAngle - startAngle
t1 = normal.cross(r1)
"""
Initialize arc data and calculate subdivisions
"""
arc = bcurve.splines.new("NURBS")
arc.use_cyclic_u = False
Ndiv = max(int(math.floor(angle / 0.3)), 2)
step = angle / float(Ndiv)
stepQuat = mathutils.Quaternion(normal, step)
tan = math.tan(step / 2) * radius
arc.points.add(Ndiv + 1)
"""
Set start and end points
"""
arc.points[0].co = (spt.x, spt.y, spt.z, 1)
arc.points[Ndiv + 1].co = (ept.x, ept.y, ept.z, 1)
"""
Set intermediate points
"""
for i in range(Ndiv):
t1 = normal.cross(r1)
pt = c + r1 * radius + t1 * tan
arc.points[i + 1].co = (pt.x, pt.y, pt.z, 1)
r1.rotate(stepQuat)
"""
Set curve settings
"""
arc.use_endpoint_u = True
arc.order_u = 3
return arc
CONVERT[Arc] = import_arc
def import_null(speckle_object, bcurve, scale):
"""
Handle unsupported types
"""
print("Failed to convert type", speckle_object["type"])
return None
def import_polycurve(scurve, bcurve, scale):
"""
Convert Polycurve object
"""
segments = scurve.segments
curves = []
for seg in segments:
speckle_type = type(seg)
if speckle_type in CONVERT.keys():
# segcurve = SCHEMAS[speckle_type].parse_obj(seg)
curves.append(CONVERT[speckle_type](seg, bcurve, scale))
else:
print("Unsupported curve type: {}".format(speckle_type))
return curves
CONVERT[Polycurve] = import_polycurve
def import_curve(speckle_curve, scale, name=None):
"""
Convert Curve object
"""
if not name:
name = speckle_curve.geometryHash or speckle_curve.id or "SpeckleCurve"
if name in bpy.data.curves.keys():
curve_data = bpy.data.curves[name]
else:
curve_data = bpy.data.curves.new(name, type="CURVE")
curve_data.dimensions = "3D"
curve_data.resolution_u = 12
if type(speckle_curve) not in CONVERT.keys():
print("Unsupported curve type: {}".format(speckle_curve.type))
return None
CONVERT[type(speckle_curve)](speckle_curve, curve_data, scale)
return curve_data
-145
View File
@@ -1,145 +0,0 @@
import bpy, bmesh, struct
import base64
from bpy_speckle.functions import _report
def add_vertices(smesh, bmesh, scale=1.0):
sverts = smesh.vertices
if sverts and len(sverts) > 0:
for i in range(0, len(sverts), 3):
bmesh.verts.new(
(
float(sverts[i]) * scale,
float(sverts[i + 1]) * scale,
float(sverts[i + 2]) * scale,
)
)
bmesh.verts.ensure_lookup_table()
def add_faces(smesh, bmesh, smooth=False):
sfaces = smesh.faces
if sfaces and len(sfaces) > 0:
i = 0
while i < len(sfaces):
n = sfaces[i]
if n < 3:
n += 3 # 0 -> 3, 1 -> 4
i += 1
try:
f = bmesh.faces.new([bmesh.verts[int(x)] for x in sfaces[i : i + n]])
f.smooth = smooth
except Exception as e:
_report(f"Failed to create face for mesh {smesh.id} \n{e}")
i += n
bmesh.faces.ensure_lookup_table()
bmesh.verts.index_update()
def add_colors(smesh, bmesh):
scolors = smesh.colors
if scolors:
colors = []
if len(scolors) > 0:
for i in range(len(scolors)):
col = int(scolors[i])
(a, r, g, b) = [
int(x) for x in struct.unpack("!BBBB", struct.pack("!i", col))
]
colors.append(
(
float(r) / 255.0,
float(g) / 255.0,
float(b) / 255.0,
float(a) / 255.0,
)
)
# Make vertex colors
if len(scolors) == len(bmesh.verts):
color_layer = bmesh.loops.layers.color.new("Col")
for face in bmesh.faces:
for loop in face.loops:
loop[color_layer] = colors[loop.vert.index]
def add_uv_coords(smesh, bmesh):
if not hasattr(smesh, "properties"):
return
sprops = smesh.properties
if sprops:
texKey = ""
if "texture_coordinates" in sprops.keys():
texKey = "texture_coordinates"
elif "TextureCoordinates" in sprops.keys():
texKey = "TextureCoordinates"
if texKey != "":
try:
decoded = base64.b64decode(sprops[texKey]).decode("utf-8")
s_uvs = decoded.split()
uv = []
if int(len(s_uvs) / 2) == len(bmesh.verts):
for i in range(0, len(s_uvs), 2):
uv.append((float(s_uvs[i]), float(s_uvs[i + 1])))
else:
print(len(s_uvs) * 2)
print(len(bmesh.verts))
print("Failed to match UV coordinates to vert data.")
# Make UVs
uv_layer = bmesh.loops.layers.uv.verify()
for f in bmesh.faces:
for l in f.loops:
luv = l[uv_layer]
luv.uv = uv[l.vert.index]
except:
print("Failed to decode texture coordinates.")
raise
del smesh.properties[texKey]
def to_bmesh(speckle_mesh, blender_mesh, name="SpeckleMesh", scale=1.0):
bm = bmesh.new()
add_vertices(speckle_mesh, bm, scale)
add_faces(speckle_mesh, bm)
add_colors(speckle_mesh, bm)
add_uv_coords(speckle_mesh, bm)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
bm.to_mesh(blender_mesh)
bm.free()
return blender_mesh
def import_mesh(speckle_mesh, scale=1.0, name=None):
"""
Convert Mesh object
"""
if not name:
name = speckle_mesh.geometryHash or speckle_mesh.id
if name in bpy.data.meshes.keys():
mesh = bpy.data.meshes[name]
else:
mesh = bpy.data.meshes.new(name=name)
to_bmesh(speckle_mesh, mesh, name, scale)
return mesh
@@ -1,6 +0,0 @@
import bpy, bmesh, struct
import base64
def import_plane(speckle_plane, scale=1.0, name=None):
return None
+389
View File
@@ -0,0 +1,389 @@
import math
from bpy_speckle.functions import get_scale_length, _report
import mathutils
import bpy, bmesh, bpy_types
from specklepy.objects.other import *
from specklepy.objects.geometry import *
from .util import (
add_blender_material,
add_custom_properties,
add_vertices,
add_faces,
add_colors,
add_uv_coords,
)
SUPPORTED_CURVES = (Line, Polyline, Curve, Arc, Polycurve)
CAN_CONVERT_TO_NATIVE = (
Mesh,
Brep,
*SUPPORTED_CURVES,
Transform,
BlockDefinition,
BlockInstance,
)
def can_convert_to_native(speckle_object):
if type(speckle_object) in CAN_CONVERT_TO_NATIVE:
return True
display = getattr(
speckle_object, "displayMesh", getattr(speckle_object, "displayValue", None)
)
if display:
return True
_report(f"Could not convert unsupported Speckle object: {speckle_object}")
return False
def convert_to_native(speckle_object, name=None):
speckle_type = type(speckle_object)
speckle_name = (
name
or getattr(speckle_object, "name", None)
or speckle_object.speckle_type + f" -- {speckle_object.id}"
)
if speckle_type not in CAN_CONVERT_TO_NATIVE:
display = getattr(
speckle_object, "displayMesh", getattr(speckle_object, "displayValue", None)
)
if not display:
_report(f"Could not convert unsupported Speckle object: {speckle_object}")
return
# 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
if isinstance(display, list):
for item in display:
item.parent_speckle_type = speckle_object.speckle_type
convert_to_native(item)
else:
display.parent_speckle_type = speckle_object.speckle_type
return convert_to_native(display, speckle_name)
units = getattr(speckle_object, "units", None)
if units:
scale = get_scale_length(units) / bpy.context.scene.unit_settings.scale_length
try:
if speckle_type is Mesh:
obj_data = mesh_to_native(speckle_object, name=speckle_name, scale=scale)
elif speckle_type is Brep:
obj_data = brep_to_native(speckle_object, name=speckle_name, scale=scale)
elif speckle_type in SUPPORTED_CURVES:
obj_data = icurve_to_native(speckle_object, name=speckle_name, scale=scale)
elif speckle_type is Transform:
obj_data = transform_to_native(speckle_object, scale=scale)
elif speckle_type is BlockDefinition:
obj_data = block_def_to_native(speckle_object, scale=scale)
elif speckle_type is BlockInstance:
obj_data = block_instance_to_native(speckle_object, scale=scale)
else:
_report(f"Unsupported type {speckle_type}")
return None
except Exception as ex: # conversion error
_report(f"Error converting {speckle_object} \n{ex}")
return None
if speckle_name in bpy.data.objects.keys():
blender_object = bpy.data.objects[speckle_name]
blender_object.data = (
obj_data.data if isinstance(obj_data, bpy_types.Object) else obj_data
)
blender_object.matrix_world = (
blender_object.matrix_world
if speckle_type is BlockInstance
else mathutils.Matrix()
)
if hasattr(obj_data, "materials"):
blender_object.data.materials.clear()
else:
blender_object = (
obj_data
if isinstance(obj_data, bpy_types.Object)
else bpy.data.objects.new(speckle_name, obj_data)
)
blender_object.speckle.object_id = str(speckle_object.id)
blender_object.speckle.enabled = True
add_custom_properties(speckle_object, blender_object)
add_blender_material(speckle_object, blender_object)
return blender_object
def brep_to_native(speckle_brep, name, scale=1.0):
display = getattr(
speckle_brep, "displayMesh", getattr(speckle_brep, "displayValue", None)
)
return mesh_to_native(display, name, scale) if display else None
def mesh_to_native(speckle_mesh, name, scale=1.0):
if name in bpy.data.meshes.keys():
blender_mesh = bpy.data.meshes[name]
else:
blender_mesh = bpy.data.meshes.new(name=name)
bm = bmesh.new()
add_vertices(speckle_mesh, bm, scale)
add_faces(speckle_mesh, bm)
add_colors(speckle_mesh, bm)
add_uv_coords(speckle_mesh, bm)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
bm.to_mesh(blender_mesh)
bm.free()
return blender_mesh
def line_to_native(speckle_curve, blender_curve, scale):
line = blender_curve.splines.new("POLY")
line.points.add(1)
line.points[0].co = (
float(speckle_curve.start.x) * scale,
float(speckle_curve.start.y) * scale,
float(speckle_curve.start.z) * scale,
1,
)
if speckle_curve.end:
line.points[1].co = (
float(speckle_curve.end.x) * scale,
float(speckle_curve.end.y) * scale,
float(speckle_curve.end.z) * scale,
1,
)
return line
def polyline_to_native(scurve, bcurve, scale):
# value = find_key_case_insensitive(scurve, "value")
value = scurve.value
if value:
N = len(value) // 3
polyline = bcurve.splines.new("POLY")
if hasattr(scurve, "closed"):
polyline.use_cyclic_u = scurve.closed
# if "closed" in scurve.keys():
# polyline.use_cyclic_u = scurve["closed"]
polyline.points.add(N - 1)
for i in range(N):
polyline.points[i].co = (
float(value[i * 3]) * scale,
float(value[i * 3 + 1]) * scale,
float(value[i * 3 + 2]) * scale,
1,
)
return polyline
def nurbs_to_native(scurve, bcurve, scale):
# points = find_key_case_insensitive(scurve, "points")
points = scurve.points
if points:
N = len(points) // 3
nurbs = bcurve.splines.new("NURBS")
if hasattr(scurve, "closed"):
nurbs.use_cyclic_u = scurve.closed != 0
nurbs.points.add(N - 1)
for i in range(N):
nurbs.points[i].co = (
float(points[i * 3]) * scale,
float(points[i * 3 + 1]) * scale,
float(points[i * 3 + 2]) * scale,
1,
)
if len(scurve.weights) == len(nurbs.points):
for i, w in enumerate(scurve.weights):
nurbs.points[i].weight = w
# TODO: anaylize curve knots to decide if use_endpoint_u or use_bezier_u should be enabled
# nurbs.use_endpoint_u = True
nurbs.order_u = scurve.degree + 1
return nurbs
def arc_to_native(rcurve, bcurve, scale):
# TODO: improve Blender representation of arc
plane = rcurve.plane
if not plane:
return
normal = mathutils.Vector([plane.normal.x, plane.normal.y, plane.normal.z])
radius = rcurve.radius * scale
startAngle = rcurve.startAngle
endAngle = rcurve.endAngle
startQuat = mathutils.Quaternion(normal, startAngle)
endQuat = mathutils.Quaternion(normal, endAngle)
# Get start and end vectors, centre point, angles, etc.
r1 = mathutils.Vector([plane.xdir.x, plane.xdir.y, plane.xdir.z])
r1.rotate(startQuat)
r2 = mathutils.Vector([plane.xdir.x, plane.xdir.y, plane.xdir.z])
r2.rotate(endQuat)
c = mathutils.Vector([plane.origin.x, plane.origin.y, plane.origin.z]) * scale
spt = c + r1 * radius
ept = c + r2 * radius
angle = endAngle - startAngle
t1 = normal.cross(r1)
# Initialize arc data and calculate subdivisions
arc = bcurve.splines.new("NURBS")
arc.use_cyclic_u = False
Ndiv = max(int(math.floor(angle / 0.3)), 2)
step = angle / float(Ndiv)
stepQuat = mathutils.Quaternion(normal, step)
tan = math.tan(step / 2) * radius
arc.points.add(Ndiv + 1)
# Set start and end points
arc.points[0].co = (spt.x, spt.y, spt.z, 1)
arc.points[Ndiv + 1].co = (ept.x, ept.y, ept.z, 1)
# Set intermediate points
for i in range(Ndiv):
t1 = normal.cross(r1)
pt = c + r1 * radius + t1 * tan
arc.points[i + 1].co = (pt.x, pt.y, pt.z, 1)
r1.rotate(stepQuat)
# Set curve settings
arc.use_endpoint_u = True
arc.order_u = 3
return arc
def polycurve_to_native(scurve, bcurve, scale):
"""
Convert Polycurve object
"""
segments = scurve.segments
curves = []
for seg in segments:
speckle_type = type(seg)
if speckle_type in SUPPORTED_CURVES:
curves.append(icurve_to_native_spline(seg, bcurve, scale=scale))
else:
_report(f"Unsupported curve type: {speckle_type}")
return curves
def icurve_to_native_spline(speckle_curve, blender_curve, scale=1.0):
curve_type = type(speckle_curve)
if curve_type is Line:
return line_to_native(speckle_curve, blender_curve, scale)
if curve_type is Polyline:
return polyline_to_native(speckle_curve, blender_curve, scale)
if curve_type is Curve:
return nurbs_to_native(speckle_curve, blender_curve, scale)
if curve_type is Polycurve:
return polycurve_to_native(speckle_curve, blender_curve, scale)
if curve_type is Arc:
return arc_to_native(speckle_curve, blender_curve, scale)
def icurve_to_native(speckle_curve, name=None, scale=1.0):
curve_type = type(speckle_curve)
if curve_type not in SUPPORTED_CURVES:
_report(f"Unsupported curve type: {curve_type}")
return None
name = name or f"{curve_type} -- {speckle_curve.id}"
blender_curve = (
bpy.data.curves[name]
if name in bpy.data.curves.keys()
else bpy.data.curves.new(name, type="CURVE")
)
blender_curve.dimensions = "3D"
blender_curve.resolution_u = 12
icurve_to_native_spline(speckle_curve, blender_curve, scale)
return blender_curve
def transform_to_native(transform: Transform, scale=1.0):
mat = mathutils.Matrix(
[
transform.value[:4],
transform.value[4:8],
transform.value[8:12],
transform.value[12:16],
]
)
# scale the translation
for i in range(3):
mat[i][3] *= scale
return mat
def block_def_to_native(definition: BlockDefinition, scale=1.0):
native_def = bpy.data.collections.get(definition.name)
if native_def:
return native_def
native_def = bpy.data.collections.new(definition.name)
native_def["applicationId"] = definition.applicationId
for geo in definition.geometry:
b_obj = convert_to_native(geo)
if b_obj:
native_def.objects.link(
b_obj
if isinstance(b_obj, bpy_types.Object)
else bpy.data.objects.new(b_obj.name, b_obj)
)
return native_def
def block_instance_to_native(instance: BlockInstance, scale=1.0):
"""
Convert BlockInstance to native
"""
name = f"{getattr(instance, 'name', None) or instance.blockDefinition.name} -- {instance.id}"
native_def = block_def_to_native(instance.blockDefinition, scale)
native_instance = bpy.data.objects.new(name, None)
# hide the instance axes so they don't clutter the viewport
native_instance.empty_display_size = 0
native_instance.instance_collection = native_def
native_instance.instance_type = "COLLECTION"
native_instance.matrix_world = transform_to_native(instance.transform, scale)
return native_instance
+312
View File
@@ -0,0 +1,312 @@
import bpy
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.util import (
get_blender_custom_properties,
make_knots,
to_argb_int,
)
UNITS = "m"
CAN_CONVERT_TO_SPECKLE = ("MESH", "CURVE", "EMPTY")
def convert_to_speckle(blender_object, scale, desgraph=None):
blender_type = blender_object.type
if blender_type not in CAN_CONVERT_TO_SPECKLE:
return
speckle_objects = []
speckle_material = material_to_speckle(blender_object)
if desgraph:
blender_object = blender_object.evaluated_get(desgraph)
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
if isinstance(converted, list):
speckle_objects.extend([c for c in converted if c != None])
else:
speckle_objects.append(converted)
for so in speckle_objects:
so.properties = get_blender_custom_properties(blender_object)
so.applicationId = so.properties.pop("applicationId", None)
if speckle_material:
so["renderMaterial"] = speckle_material
# Set object transform
if blender_type != "EMPTY":
so.properties["transform"] = transform_to_speckle(
blender_object.matrix_world
)
return speckle_objects
def mesh_to_speckle(blender_object, data, scale=1.0):
if data.loop_triangles is None or len(data.loop_triangles) < 1:
data.calc_loop_triangles()
mat = blender_object.matrix_world
verts = [tuple(mat @ x.co * scale) for x in data.vertices]
faces = [p.vertices for p in data.polygons]
unit_system = bpy.context.scene.unit_settings.system
sm = Mesh(
name=blender_object.name,
vertices=list(sum(verts, ())),
faces=[],
colors=[],
textureCoordinates=[],
units="m" if unit_system == "METRIC" else "ft",
bbox=Box(area=0.0, volume=0.0),
)
if data.uv_layers.active:
for vt in data.uv_layers.active.data:
sm.textureCoordinates.extend([vt.uv.x, vt.uv.y])
for f in faces:
n = len(f)
if n == 3:
sm.faces.append(0)
elif n == 4:
sm.faces.append(1)
else:
sm.faces.append(n)
sm.faces.extend(f)
return [sm]
def bezier_to_speckle(matrix, spline, scale, name=None):
degree = 3
closed = spline.use_cyclic_u
points = []
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))
if i < len(spline.bezier_points) - 1:
points.append(tuple(matrix @ bp.handle_right * scale))
if closed:
points.append(tuple(matrix @ spline.bezier_points[-1].handle_right * scale))
points.append(tuple(matrix @ spline.bezier_points[0].handle_left * scale))
points.append(tuple(matrix @ spline.bezier_points[0].co * scale))
num_points = len(points)
knot_count = num_points + degree - 1
knots = [0] * knot_count
for i in range(1, len(knots)):
knots[i] = i // 3
length = spline.calc_length()
domain = Interval(start=0, end=length, totalChildrenCount=0)
return Curve(
name=name,
degree=degree,
closed=spline.use_cyclic_u,
periodic=spline.use_cyclic_u,
points=list(sum(points, ())), # magic (flatten list of tuples)
weights=[1] * num_points,
knots=knots,
rational=False,
area=0,
volume=0,
length=length,
domain=domain,
units=UNITS,
bbox=Box(area=0.0, volume=0.0),
)
def nurbs_to_speckle(matrix, spline, scale, name=None):
knots = make_knots(spline)
points = [tuple(matrix @ pt.co.xyz * scale) for pt in spline.points]
degree = spline.order_u - 1
length = spline.calc_length()
domain = Interval(start=0, end=length, totalChildrenCount=0)
return Curve(
name=name,
degree=degree,
closed=spline.use_cyclic_u,
periodic=spline.use_cyclic_u,
points=list(sum(points, ())), # magic (flatten list of tuples)
weights=[pt.weight for pt in spline.points],
knots=knots,
rational=False,
area=0,
volume=0,
length=length,
domain=domain,
units=UNITS,
bbox=Box(area=0.0, volume=0.0),
)
def poly_to_speckle(matrix, spline, scale, name=None):
points = [tuple(matrix @ pt.co.xyz * scale) for pt in spline.points]
length = spline.calc_length()
domain = Interval(start=0, end=length, totalChildrenCount=0)
return Polyline(
name=name,
closed=spline.use_cyclic_u,
value=list(sum(points, ())), # magic (flatten list of tuples)
length=length,
domain=domain,
bbox=Box(area=0.0, volume=0.0),
area=0,
units=UNITS,
)
def icurve_to_speckle(blender_object, data, scale=1.0):
UNITS = "m" if bpy.context.scene.unit_settings.system == "METRIC" else "ft"
if blender_object.type != "CURVE":
return None
blender_object = blender_object.evaluated_get(bpy.context.view_layer.depsgraph)
mat = blender_object.matrix_world
curves = []
if data.bevel_mode == "OBJECT" and data.bevel_object != None:
mesh = mesh_to_speckle(blender_object, blender_object.to_mesh(), scale)
curves.extend(mesh)
for spline in data.splines:
if spline.type == "BEZIER":
curves.append(bezier_to_speckle(mat, spline, scale, blender_object.name))
elif spline.type == "NURBS":
curves.append(nurbs_to_speckle(mat, spline, scale, blender_object.name))
elif spline.type == "POLY":
curves.append(poly_to_speckle(mat, spline, scale, blender_object.name))
return curves
def ngons_to_speckle_polylines(blender_object, data, scale=1.0):
UNITS = "m" if bpy.context.scene.unit_settings.system == "METRIC" else "ft"
if blender_object.type != "MESH":
return None
mat = blender_object.matrix_world
verts = data.vertices
polylines = []
for i, poly in enumerate(data.polygons):
value = []
for v in poly.vertices:
value.extend(mat @ verts[v].co * scale)
domain = Interval(start=0, end=1)
poly = Polyline(
name="{}_{}".format(blender_object.name, i),
closed=True,
value=value, # magic (flatten list of tuples)
length=0,
domain=domain,
bbox=Box(area=0.0, volume=0.0),
area=0,
units=UNITS,
)
polylines.append(poly)
return polylines
def material_to_speckle(blender_object) -> RenderMaterial:
"""Create and return a render material from a blender object"""
if not getattr(blender_object.data, "materials", None):
return
blender_mat = blender_object.data.materials[0]
speckle_mat = RenderMaterial()
speckle_mat.name = blender_mat.name
if blender_mat.use_nodes is True:
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
else:
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
def transform_to_speckle(blender_transform, scale=1.0):
units = "m" if bpy.context.scene.unit_settings.system == "METRIC" else "ft"
value = [y for x in blender_transform for y in x]
# scale the translation
for i in (3, 7, 11):
value[i] *= scale
return Transform(value=value, units=units)
def block_def_to_speckle(blender_definition, scale=1.0):
geometry = []
for geo in blender_definition.objects:
geometry.extend(convert_to_speckle(geo, scale))
block_def = BlockDefinition(
units=UNITS,
name=blender_definition.name,
geometry=geometry,
basePoint=Point(units=UNITS),
)
blender_props = get_blender_custom_properties(blender_definition)
block_def.applicationId = blender_props.pop("applicationId", None)
return block_def
def block_instance_to_speckle(blender_instance, scale=1.0):
return BlockInstance(
blockDefinition=block_def_to_speckle(
blender_instance.instance_collection, scale
),
transform=transform_to_speckle(blender_instance.matrix_world),
name=blender_instance.name,
units=UNITS,
)
def empty_to_speckle(blender_object, scale=1.0):
# 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
@@ -1,3 +0,0 @@
from .mesh import export_mesh
from .curve import export_curve, export_ngons_as_polylines
from .empty import export_empty
-224
View File
@@ -1,224 +0,0 @@
import bpy, bmesh, struct
from specklepy.objects.geometry import Curve, Interval, Box, Polyline
from bpy_speckle.convert.to_speckle.mesh import export_mesh
UNITS = "m"
def bezier_to_speckle(matrix, spline, scale, name=None):
degree = 3
closed = spline.use_cyclic_u
points = []
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))
if i < len(spline.bezier_points) - 1:
points.append(tuple(matrix @ bp.handle_right * scale))
if closed:
points.append(tuple(matrix @ spline.bezier_points[-1].handle_right * scale))
points.append(tuple(matrix @ spline.bezier_points[0].handle_left * scale))
points.append(tuple(matrix @ spline.bezier_points[0].co * scale))
num_points = len(points)
knot_count = num_points + degree - 1
knots = [0] * knot_count
for i in range(1, len(knots)):
knots[i] = i // 3
length = spline.calc_length()
domain = Interval(start=0, end=length, totalChildrenCount=0)
return Curve(
name=name,
degree=degree,
closed=spline.use_cyclic_u,
periodic=spline.use_cyclic_u,
points=list(sum(points, ())), # magic (flatten list of tuples)
weights=[1] * num_points,
knots=knots,
rational=False,
area=0,
volume=0,
length=length,
domain=domain,
units=UNITS,
bbox=Box(area=0.0, volume=0.0),
)
def nurbs_to_speckle(matrix, spline, scale, name=None):
knots = makeknots(spline)
# print("knots: {}".format(knots))
points = [tuple(matrix @ pt.co.xyz * scale) for pt in spline.points]
degree = spline.order_u - 1
length = spline.calc_length()
domain = Interval(start=0, end=length, totalChildrenCount=0)
return Curve(
name=name,
degree=degree,
closed=spline.use_cyclic_u,
periodic=spline.use_cyclic_u,
points=list(sum(points, ())), # magic (flatten list of tuples)
weights=[pt.weight for pt in spline.points],
knots=knots,
rational=False,
area=0,
volume=0,
length=length,
domain=domain,
units=UNITS,
bbox=Box(area=0.0, volume=0.0),
)
def poly_to_speckle(matrix, spline, scale, name=None):
points = [tuple(matrix @ pt.co.xyz * scale) for pt in spline.points]
length = spline.calc_length()
domain = Interval(start=0, end=length, totalChildrenCount=0)
return Polyline(
name=name,
closed=spline.use_cyclic_u,
value=list(sum(points, ())), # magic (flatten list of tuples)
length=length,
domain=domain,
bbox=Box(area=0.0, volume=0.0),
area=0,
units=UNITS,
)
def export_curve(blender_object, data, scale=1.0):
UNITS = "m" if bpy.context.scene.unit_settings.system == "METRIC" else "ft"
if blender_object.type != "CURVE":
return None
blender_object = blender_object.evaluated_get(bpy.context.view_layer.depsgraph)
mat = blender_object.matrix_world
curves = []
if data.bevel_mode == "OBJECT" and data.bevel_object != None:
mesh = export_mesh(blender_object, blender_object.to_mesh(), scale)
curves.extend(mesh)
for spline in data.splines:
if spline.type == "BEZIER":
curves.append(bezier_to_speckle(mat, spline, scale, blender_object.name))
elif spline.type == "NURBS":
curves.append(nurbs_to_speckle(mat, spline, scale, blender_object.name))
elif spline.type == "POLY":
curves.append(poly_to_speckle(mat, spline, scale, blender_object.name))
return curves
def export_ngons_as_polylines(blender_object, data, scale=1.0):
UNITS = "m" if bpy.context.scene.unit_settings.system == "METRIC" else "ft"
if blender_object.type != "MESH":
return None
mat = blender_object.matrix_world
verts = data.vertices
polylines = []
for i, poly in enumerate(data.polygons):
value = []
for v in poly.vertices:
value.extend(mat @ verts[v].co * scale)
domain = Interval(start=0, end=1)
poly = Polyline(
name="{}_{}".format(blender_object.name, i),
closed=True,
value=value, # magic (flatten list of tuples)
length=0,
domain=domain,
bbox=Box(area=0.0, volume=0.0),
area=0,
units=UNITS,
)
polylines.append(poly)
return polylines
"""
Python implementation of Blender's NURBS curve generation
from: https://blender.stackexchange.com/a/34276
"""
def macro_knotsu(nu):
return nu.order_u + nu.point_count_u + (nu.order_u - 1 if nu.use_cyclic_u else 0)
def macro_segmentsu(nu):
return nu.point_count_u if nu.use_cyclic_u else nu.point_count_u - 1
def makeknots(nu):
knots = [0.0] * (4 + macro_knotsu(nu))
flag = nu.use_endpoint_u + (nu.use_bezier_u << 1)
if nu.use_cyclic_u:
calcknots(knots, nu.point_count_u, nu.order_u, 0)
makecyclicknots(knots, nu.point_count_u, nu.order_u)
else:
calcknots(knots, nu.point_count_u, nu.order_u, flag)
return knots
def calcknots(knots, pnts, order, flag):
pnts_order = pnts + order
if flag == 1:
k = 0.0
for a in range(1, pnts_order + 1):
knots[a - 1] = k
if a >= order and a <= pnts:
k += 1.0
elif flag == 2:
if order == 4:
k = 0.34
for a in range(pnts_order):
knots[a] = math.floor(k)
k += 1.0 / 3.0
elif order == 3:
k = 0.6
for a in range(pnts_order):
if a >= order and a <= pnts:
k += 0.5
knots[a] = math.floor(k)
else:
for a in range(pnts_order):
knots[a] = a
def makecyclicknots(knots, pnts, order):
order2 = order - 1
if order > 2:
b = pnts + order2
for a in range(1, order2):
if knots[b] != knots[b - a]:
break
if a == order2:
knots[pnts + order - 2] += 1.0
b = order
c = pnts + order + order2
for a in range(pnts + order2, c):
knots[a] = knots[a - 1] + (knots[b] - knots[b - 1])
b -= 1
@@ -1,5 +0,0 @@
import bpy, bmesh, struct
def export_default(blender_object, scale=1.0):
return None
-5
View File
@@ -1,5 +0,0 @@
import bpy, bmesh, struct
def export_empty(blender_object, data, scale=1.0):
return None
-44
View File
@@ -1,44 +0,0 @@
import bpy, bmesh, struct
import base64, hashlib
from time import strftime, gmtime
from specklepy.objects.geometry import Mesh, Interval, Box
def export_mesh(blender_object, data, scale=1.0):
if data.loop_triangles is None or len(data.loop_triangles) < 1:
data.calc_loop_triangles()
mat = blender_object.matrix_world
verts = [tuple(mat @ x.co * scale) for x in data.vertices]
faces = [p.vertices for p in data.polygons]
unit_system = bpy.context.scene.unit_settings.system
sm = Mesh(
name=blender_object.name,
vertices=list(sum(verts, ())),
faces=[],
colors=[],
textureCoordinates=[],
units="m" if unit_system == "METRIC" else "ft",
bbox=Box(area=0.0, volume=0.0),
)
if data.uv_layers.active:
for vt in data.uv_layers.active.data:
sm.textureCoordinates.extend([vt.uv.x, vt.uv.y])
for f in faces:
n = len(f)
if n == 3:
sm.faces.append(0)
elif n == 4:
sm.faces.append(1)
else:
sm.faces.append(n)
sm.faces.extend(f)
return [sm]
+272 -1
View File
@@ -1,4 +1,9 @@
import base64
from typing import Tuple
import bpy, struct, idprop
from specklepy.serialization.base_object_serializer import BaseObjectSerializer
from bpy_speckle.functions import _report
def to_rgba(argb_int: int) -> Tuple[float]:
@@ -13,7 +18,273 @@ def to_rgba(argb_int: int) -> Tuple[float]:
def to_argb_int(diffuse_colour) -> int:
"""Converts an RGBA array to an ARGB integer"""
diffuse_colour = diffuse_colour[-1:] + diffuse_colour[0:3]
diffuse_colour = diffuse_colour[-1:] + diffuse_colour[:3]
diffuse_colour = [int(val * 255) for val in diffuse_colour]
return int.from_bytes(diffuse_colour, byteorder="big", signed=True)
def add_custom_properties(speckle_object, blender_object):
if blender_object is None:
return
serializer = BaseObjectSerializer()
blender_object["_speckle_type"] = type(speckle_object).__name__
app_id = getattr(speckle_object, "applicationId", None)
if app_id:
blender_object["applicationId"] = speckle_object.applicationId
for key in speckle_object.get_dynamic_member_names():
if isinstance(speckle_object[key], (int, str, float)):
blender_object[key] = speckle_object[key]
elif isinstance(speckle_object[key], (dict, list)):
blender_object[key] = serializer.traverse_value(speckle_object[key])
def add_blender_material(speckle_object, blender_object) -> None:
"""Add material to a blender object if the corresponding speckle object has a render material"""
if blender_object.data is None:
return
speckle_mat = getattr(
speckle_object,
"renderMaterial",
getattr(speckle_object, "@renderMaterial", None),
)
if not speckle_mat:
return
mat_name = getattr(speckle_mat, "name", None) or speckle_mat.__dict__.get("@name")
if not mat_name:
mat_name = speckle_mat.applicationId or speckle_mat.id or speckle_mat.get_id()
blender_mat = bpy.data.materials.get(mat_name)
if not blender_mat:
blender_mat = bpy.data.materials.new(mat_name)
# for now, we're not updating these materials. as per tom's suggestion, we should have a toggle
# that enables this as the blender mats will prob be much more complex than whatever is coming in
blender_mat.use_nodes = True
inputs = blender_mat.node_tree.nodes["Principled BSDF"].inputs
inputs["Base Color"].default_value = to_rgba(speckle_mat.diffuse)
inputs["Emission"].default_value = to_rgba(speckle_mat.emissive)
inputs["Roughness"].default_value = speckle_mat.roughness
inputs["Metallic"].default_value = speckle_mat.metalness
inputs["Alpha"].default_value = speckle_mat.opacity
if speckle_mat.opacity < 1:
blender_mat.blend_method = "BLEND"
blender_object.data.materials.append(blender_mat)
def add_vertices(speckle_mesh, blender_mesh, scale=1.0):
sverts = speckle_mesh.vertices
if sverts and len(sverts) > 0:
for i in range(0, len(sverts), 3):
blender_mesh.verts.new(
(
float(sverts[i]) * scale,
float(sverts[i + 1]) * scale,
float(sverts[i + 2]) * scale,
)
)
blender_mesh.verts.ensure_lookup_table()
def add_faces(speckle_mesh, blender_mesh, smooth=False):
sfaces = speckle_mesh.faces
if sfaces and len(sfaces) > 0:
i = 0
while i < len(sfaces):
n = sfaces[i]
if n < 3:
n += 3 # 0 -> 3, 1 -> 4
i += 1
try:
f = blender_mesh.faces.new(
[blender_mesh.verts[int(x)] for x in sfaces[i : i + n]]
)
f.smooth = smooth
except Exception as e:
_report(f"Failed to create face for mesh {speckle_mesh.id} \n{e}")
i += n
blender_mesh.faces.ensure_lookup_table()
blender_mesh.verts.index_update()
def add_colors(speckle_mesh, blender_mesh):
scolors = speckle_mesh.colors
if scolors:
colors = []
if len(scolors) > 0:
for i in range(len(scolors)):
col = int(scolors[i])
(a, r, g, b) = [
int(x) for x in struct.unpack("!BBBB", struct.pack("!i", col))
]
colors.append(
(
float(r) / 255.0,
float(g) / 255.0,
float(b) / 255.0,
float(a) / 255.0,
)
)
# Make vertex colors
if len(scolors) == len(blender_mesh.verts):
color_layer = blender_mesh.loops.layers.color.new("Col")
for face in blender_mesh.faces:
for loop in face.loops:
loop[color_layer] = colors[loop.vert.index]
def add_uv_coords(speckle_mesh, blender_mesh):
if not hasattr(speckle_mesh, "properties"):
return
sprops = speckle_mesh.properties
if sprops:
texKey = ""
if "texture_coordinates" in sprops.keys():
texKey = "texture_coordinates"
elif "TextureCoordinates" in sprops.keys():
texKey = "TextureCoordinates"
if texKey != "":
try:
decoded = base64.b64decode(sprops[texKey]).decode("utf-8")
s_uvs = decoded.split()
uv = []
if len(s_uvs) // 2 == len(blender_mesh.verts):
for i in range(0, len(s_uvs), 2):
uv.append((float(s_uvs[i]), float(s_uvs[i + 1])))
else:
_report(
f"Failed to match UV coordinates to vert data. Blender mesh verts: {len(blender_mesh.verts)}, Speckle UVs * 2: {len(s_uvs) * 2}"
)
# Make UVs
uv_layer = blender_mesh.loops.layers.uv.verify()
for f in blender_mesh.faces:
for l in f.loops:
luv = l[uv_layer]
luv.uv = uv[l.vert.index]
except:
_report("Failed to decode texture coordinates.")
raise
del speckle_mesh.properties[texKey]
ignored_keys = (
"speckle",
"_speckle_type",
"_speckle_name",
"_speckle_transform",
"_RNA_UI",
"transform",
"_units",
"_chunkable",
)
def get_blender_custom_properties(obj, max_depth=1000):
if max_depth < 0:
return obj
if hasattr(obj, "keys"):
return {
key: get_blender_custom_properties(obj[key], max_depth - 1)
for key in obj.keys()
if key not in ignored_keys and not key.startswith("_")
}
elif isinstance(obj, (list, tuple, idprop.types.IDPropertyArray)):
return [get_blender_custom_properties(o, max_depth - 1) for o in obj]
else:
return obj
"""
Python implementation of Blender's NURBS curve generation for to Speckle conversion
from: https://blender.stackexchange.com/a/34276
"""
def macro_knotsu(nu):
return nu.order_u + nu.point_count_u + (nu.order_u - 1 if nu.use_cyclic_u else 0)
def macro_segmentsu(nu):
return nu.point_count_u if nu.use_cyclic_u else nu.point_count_u - 1
def make_knots(nu):
knots = [0.0] * (4 + macro_knotsu(nu))
flag = nu.use_endpoint_u + (nu.use_bezier_u << 1)
if nu.use_cyclic_u:
calc_knots(knots, nu.point_count_u, nu.order_u, 0)
makecyclicknots(knots, nu.point_count_u, nu.order_u)
else:
calc_knots(knots, nu.point_count_u, nu.order_u, flag)
return knots
def calc_knots(knots, point_count, order, flag):
pts_order = point_count + order
if flag == 1:
k = 0.0
for a in range(1, pts_order + 1):
knots[a - 1] = k
if a >= order and a <= point_count:
k += 1.0
elif flag == 2:
if order == 4:
k = 0.34
for a in range(pts_order):
knots[a] = math.floor(k)
k += 1.0 / 3.0
elif order == 3:
k = 0.6
for a in range(pts_order):
if a >= order and a <= point_count:
k += 0.5
knots[a] = math.floor(k)
else:
for a in range(pts_order):
knots[a] = a
def makecyclicknots(knots, point_count, order):
order2 = order - 1
if order > 2:
b = point_count + order2
for a in range(1, order2):
if knots[b] != knots[b - a]:
break
if a == order2:
knots[point_count + order - 2] += 1.0
b = order
c = point_count + order + order2
for a in range(point_count + order2, c):
knots[a] = knots[a - 1] + (knots[b] - knots[b - 1])
b -= 1
-32
View File
@@ -1,4 +1,3 @@
from specklepy.api.client import SpeckleClient
from bpy_speckle.clients import speckle_clients
"""
@@ -71,34 +70,3 @@ def _check_speckle_client_user_stream(scene):
print("Account contains no streams.")
return (user, stream)
def _create_stream(user, stream_name, units="Millimeters"):
"""
Create a new stream
"""
# TODO: double-check, but this should not be accessible through the UI if
# there aren't any active users anyway
# user = context.scene.speckle.users[int(context.scene.speckle.active_user)]
client = speckle_clients[int(bpy.context.scene.speckle.active_user)]
return client.stream.create(
name=stream_name, description="This is a Blender stream.", is_public=True
)
# TODO: Update stream with properties such as units, etc.
def _delete_stream(client, user, stream):
"""
Delete the active stream
TODO: probably doesn't need to be a separate function and can be
folded into the operator
"""
user = context.scene.speckle.users[int(context.scene.speckle.active_user)]
client = speckle_clients[int(context.scene.speckle.active_user)]
if stream:
res = client.streams.delete(stream.id)
_report(res["message"])
-2
View File
@@ -3,7 +3,6 @@ from .object import (
UpdateObject,
ResetObject,
DeleteObject,
UploadObject,
UploadNgonsAsPolylines,
SelectIfSameCustomProperty,
SelectIfHasCustomProperty,
@@ -43,7 +42,6 @@ operator_classes.extend(
UpdateObject,
ResetObject,
DeleteObject,
UploadObject,
UploadNgonsAsPolylines,
SelectIfSameCustomProperty,
SelectIfHasCustomProperty,
+10 -32
View File
@@ -1,23 +1,9 @@
"""
Commit operators
"""
import bpy, os
from bpy.props import (
StringProperty,
BoolProperty,
FloatProperty,
CollectionProperty,
EnumProperty,
)
from bpy_speckle.functions import (
_check_speckle_client_user_stream,
_create_stream,
get_scale_length,
_report,
)
from bpy_speckle.convert import from_speckle_object
import bpy
from bpy.props import BoolProperty
from bpy_speckle.functions import _check_speckle_client_user_stream
from bpy_speckle.clients import speckle_clients
@@ -32,7 +18,8 @@ class DeleteCommit(bpy.types.Operator):
bl_description = "Delete active commit permanently"
are_you_sure: BoolProperty(
name="Confirm", default=False,
name="Confirm",
default=False,
)
def draw(self, context):
@@ -66,20 +53,11 @@ class DeleteCommit(bpy.types.Operator):
stream = user.streams[user.active_stream]
if len(stream.branches) < 1:
return {"CANCELLED"}
else:
branch = stream.branches[int(stream.branch)]
if len(branch.commits) < 1:
return {"CANCELLED"}
else:
commit = branch.commits[int(branch.commit)]
branch = stream.branches[int(stream.branch)]
if len(branch.commits) < 1:
return {"CANCELLED"}
commit = branch.commits[int(branch.commit)]
deleted = client.commit.delete(stream_id=stream.id, commit_id=commit.id)
deleted = client.commit.delete(stream_id=stream.id, commit_id=commit.id)
return {"FINISHED"}
bpy.ops.speckle.load_user_streams()
context.view_layer.update()
if context.area:
context.area.tag_redraw()
return {"FINISHED"}
+7 -74
View File
@@ -2,19 +2,12 @@
Object operators
"""
import bpy, bmesh, os
from bpy.props import (
StringProperty,
BoolProperty,
FloatProperty,
CollectionProperty,
EnumProperty,
import bpy
from bpy.props import BoolProperty, EnumProperty
from bpy_speckle.convert.to_speckle import (
convert_to_speckle,
ngons_to_speckle_polylines,
)
from specklepy.api.client import SpeckleClient
from bpy_speckle.convert import to_speckle_object
from bpy_speckle.convert.to_speckle import export_ngons_as_polylines
from bpy_speckle.functions import get_scale_length, _report
from bpy_speckle.clients import speckle_clients
@@ -58,7 +51,7 @@ class UpdateObject(bpy.types.Operator):
stream_units
)
sm = to_speckle_object(active, scale)
sm = convert_to_speckle(active, scale)
_report("Updating object {}".format(sm["_id"]))
client.objects.update(active.speckle.object_id, sm)
@@ -99,8 +92,6 @@ class DeleteObject(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
user = context.scene.speckle.users[int(context.scene.speckle.active_user)]
client = speckle_clients[int(context.scene.speckle.active_user)]
active = context.object
if active.speckle.enabled:
@@ -112,13 +103,11 @@ class DeleteObject(bpy.types.Operator):
]
if existing is None:
return {"CANCELLED"}
# print("Existing: %s" % SpeckleResource.to_json_pretty(existing))
new_objects = [
x
for x in res["resource"]["objects"]
if x["_id"] != active.speckle.object_id
]
# print (SpeckleResource.to_json_pretty(new_objects))
res = client.GetLayers(active.speckle.stream_id)
new_layers = res["resource"]["layers"]
@@ -166,7 +155,7 @@ class UploadNgonsAsPolylines(bpy.types.Operator):
stream.units
)
sp = export_ngons_as_polylines(active, scale)
sp = ngons_to_speckle_polylines(active, scale)
if sp is None:
return {"CANCELLED"}
@@ -175,16 +164,12 @@ class UploadNgonsAsPolylines(bpy.types.Operator):
for polyline in sp:
res = client.objects.create([polyline])
print(res)
if res is None:
_report(client.me)
continue
placeholders.extend(res)
# polyline['_id'] = res['_id']
# placeholders.append({'type':'Placeholder', '_id':res['_id']})
if not placeholders:
return {"CANCELLED"}
@@ -222,58 +207,6 @@ class UploadNgonsAsPolylines(bpy.types.Operator):
layout.prop(self, "clear_stream")
class UploadObject(bpy.types.Operator):
"""
DEPRECATED
Upload an individual object
"""
bl_idname = "speckle.upload_object"
bl_label = "Upload Object"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
active = context.active_object
if active is not None:
user = context.scene.speckle.users[int(context.scene.speckle.active_user)]
client = speckle_clients[int(context.scene.speckle.active_user)]
stream = user.streams[user.active_stream]
scale = context.scene.unit_settings.scale_length / get_scale_length(
stream.units
)
sm = to_speckle_object(active, scale)
placeholders = client.objects.create([sm])
if placeholders is None:
return {"CANCELLED"}
sstream = client.streams.get(stream.id)
sstream.objects.extend(placeholders)
N = sstream.layers[-1].objectCount
sstream.layers[-1].objectCount = N + 1
sstream.layers[-1].topology = "0-%s" % (N + 1)
_report("Updating stream %s" % stream.id)
res = client.streams.update(stream["id"], sstream)
_report(res)
active.speckle.enabled = True
active.speckle.object_id = sm.id
active.speckle.stream_id = stream.id
active.speckle.send_or_receive = "send"
context.view_layer.update()
_report("Done.")
return {"FINISHED"}
def get_custom_speckle_props(self, context):
ignore = ["speckle", "cycles", "cycles_visibility"]
+24 -26
View File
@@ -3,26 +3,24 @@ Stream operators
"""
from itertools import chain
from typing import Dict
import bpy, bmesh, os
import bpy
from specklepy.api.models import Commit
import webbrowser
from bpy.props import (
StringProperty,
BoolProperty,
FloatProperty,
CollectionProperty,
EnumProperty,
)
from bpy_speckle.convert.to_native import can_convert_to_native, convert_to_native
from bpy_speckle.convert.to_speckle import (
convert_to_speckle,
ngons_to_speckle_polylines,
)
from bpy_speckle.functions import (
_check_speckle_client_user_stream,
_create_stream,
get_scale_length,
_report,
)
from bpy_speckle.convert import to_speckle_object, get_speckle_subobjects
from bpy_speckle.convert.to_speckle import export_ngons_as_polylines
from bpy_speckle.convert import from_speckle_object
from bpy_speckle.convert import get_speckle_subobjects
from bpy_speckle.clients import speckle_clients
from bpy_speckle.operators.users import add_user_stream
@@ -30,7 +28,6 @@ from specklepy.api import operations
from specklepy.api.credentials import StreamWrapper
from specklepy.api.resources.stream import Stream
from specklepy.transports.server import ServerTransport
from specklepy.objects import Base
from specklepy.objects.geometry import *
from specklepy.logging.exceptions import SpeckleException
@@ -70,12 +67,7 @@ def get_objects_nested_lists(items, parent_col=None) -> List:
def get_objects_collections_recursive(base, parent_col=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
object_type = Base.get_registered_type(base.speckle_type)
if (
(object_type and object_type != Base)
or hasattr(base, "displayMesh")
or hasattr(base, "displayValue")
):
if can_convert_to_native(base):
return [base]
# if it's an unknown type, try to drill further down to find convertable objects
@@ -89,9 +81,14 @@ def get_objects_collections_recursive(base, parent_col=None) -> List:
objects.append(item)
if isinstance(value, Base):
col = parent_col.children.get(name)
if not parent_col.children.get(name):
if not col:
col = create_collection(name)
parent_col.children.link(col)
try:
parent_col.children.link(col)
except:
_report(
f"Problem linking collection {col.name} to parent {parent_col.name}; skipping"
)
objects.append({name: get_objects_collections_recursive(value, col)})
return objects
@@ -117,6 +114,7 @@ def bases_to_native(context, collections, scale, stream_id, func=None):
)
elif isinstance(obj, Base):
base_to_native(context, obj, scale, stream_id, col, existing, func)
else:
_report(
f"Something went wrong when receiving collection: {col_name}"
@@ -129,7 +127,7 @@ def bases_to_native(context, collections, scale, stream_id, func=None):
def base_to_native(context, base, scale, stream_id, col, existing, func=None):
new_objects = [from_speckle_object(base, scale)]
new_objects = [convert_to_native(base)]
if hasattr(base, "properties") and base.properties is not None:
new_objects.extend(get_speckle_subobjects(base.properties, scale, base.id))
@@ -224,9 +222,9 @@ def create_nested_hierarchy(base, hierarchy, objects):
child = child[name]
# TODO: what do we call this attribute?
if not hasattr(child, "objects"):
child["objects"] = []
child["objects"].extend(objects)
if not hasattr(child, "@objects"):
child["@objects"] = []
child["@objects"].extend(objects)
return base
@@ -264,7 +262,7 @@ class ReceiveStreamObjects(bpy.types.Operator):
bbranch = bstream.branches[int(bstream.branch)]
if branch.commits.totalCount < 1:
print("No commits found. Probably an empty stream.")
_report("No commits found. Probably an empty stream.")
return {"CANCELLED"}
commit = branch.commits.items[int(bbranch.commit)]
@@ -415,9 +413,9 @@ class SendStreamObjects(bpy.types.Operator):
ngons = obj.get("speckle_ngons_as_polylines", False)
if ngons:
converted = export_ngons_as_polylines(obj, scale)
converted = ngons_to_speckle_polylines(obj, scale)
else:
converted = to_speckle_object(
converted = convert_to_speckle(
obj,
scale,
bpy.context.evaluated_depsgraph_get()
@@ -569,7 +567,7 @@ class CreateStream(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
bl_description = "Create new stream"
stream_name: StringProperty(name="Stream name", default="SpeckleStream")
stream_name: StringProperty(name="Stream name")
stream_description: StringProperty(
name="Stream description", default="This is a Blender stream."
)
+2 -14
View File
@@ -1,23 +1,11 @@
"""
User account operators
"""
from typing import cast
import bpy, bmesh, os
from bpy.props import (
StringProperty,
BoolProperty,
FloatProperty,
CollectionProperty,
EnumProperty,
)
from bpy_speckle.properties.scene import SpeckleUserObject
import bpy
from bpy_speckle.functions import _report
from bpy_speckle.clients import speckle_clients
from specklepy.api.client import SpeckleClient
from specklepy.api.credentials import get_default_account, get_local_accounts
from specklepy.api.credentials import get_local_accounts
class LoadUsers(bpy.types.Operator):
-2
View File
@@ -1,9 +1,7 @@
"""
Addon properties
"""
import bpy
from bpy.props import BoolProperty
class SpeckleAddonPreferences(bpy.types.AddonPreferences):
-2
View File
@@ -1,9 +1,7 @@
"""
Collection properties
"""
import bpy
from bpy.props import StringProperty, BoolProperty, EnumProperty
class SpeckleCollectionSettings(bpy.types.PropertyGroup):
-2
View File
@@ -1,9 +1,7 @@
"""
Object properties
"""
import bpy
from bpy.props import StringProperty, BoolProperty, EnumProperty
class SpeckleObjectSettings(bpy.types.PropertyGroup):
+4 -5
View File
@@ -1,7 +1,6 @@
"""
Scene properties
"""
import bpy
from bpy.props import (
StringProperty,
@@ -12,7 +11,6 @@ from bpy.props import (
IntProperty,
PointerProperty,
)
from specklepy.api.client import SpeckleClient
class SpeckleSceneObject(bpy.types.PropertyGroup):
@@ -82,9 +80,10 @@ class SpeckleUserObject(bpy.types.PropertyGroup):
class SpeckleSceneSettings(bpy.types.PropertyGroup):
def get_scripts(self, context):
seq = [("<none>", "<none>", "<none>")]
seq.extend([(t.name, t.name, t.name) for t in bpy.data.texts])
return seq
return [
("<none>", "<none>", "<none>"),
*[(t.name, t.name, t.name) for t in bpy.data.texts],
]
streams: EnumProperty(
name="Available streams",
+1 -3
View File
@@ -84,9 +84,8 @@ class VIEW3D_UL_SpeckleStreams(bpy.types.UIList):
def draw_item(self, context, layout, data, stream, active_data, active_propname):
if self.layout_type in {"DEFAULT", "COMPACT"}:
if stream:
# layout.prop(user, "name", text=user.name, emboss=False, icon_value=0)
layout.label(
text="{} ({})".format(stream.name, stream.id),
text=f"{stream.name} ({stream.id})",
translate=False,
icon_value=0,
)
@@ -118,7 +117,6 @@ class VIEW3D_PT_SpeckleUser(bpy.types.Panel):
if len(speckle.users) < 1:
col.label(text="No users found.")
else:
# col.label(text="User")
col.prop(speckle, "active_user", text="")
user = speckle.users[int(speckle.active_user)]
col.label(text="{} ({})".format(user.server_name, user.server_url))
+1
View File
@@ -50,6 +50,7 @@ def get_specklepy_version():
def main():
if len(sys.argv) < 2:
print(get_specklepy_version())
return
tag = sys.argv[1]
Generated
+463 -51
View File
@@ -25,6 +25,20 @@ category = "main"
optional = false
python-versions = "*"
[[package]]
name = "astroid"
version = "2.9.1"
description = "An abstract syntax tree for Python with inference support."
category = "dev"
optional = false
python-versions = ">=3.6.2"
[package.dependencies]
lazy-object-proxy = ">=1.4.0"
typed-ast = {version = ">=1.4.0,<2.0", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""}
typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""}
wrapt = ">=1.11,<1.14"
[[package]]
name = "async-timeout"
version = "3.0.1"
@@ -47,6 +61,46 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
[[package]]
name = "black"
version = "21.12b0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
python-versions = ">=3.6.2"
[package.dependencies]
click = ">=7.1.2"
mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0,<1"
platformdirs = ">=2"
tomli = ">=0.2.6,<2.0.0"
typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""}
typing-extensions = ">=3.10.0.0"
[package.extras]
colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
python2 = ["typed-ast (>=1.4.3)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "botocore"
version = "1.23.26"
description = "Low-level, data-driven core of boto 3."
category = "main"
optional = false
python-versions = ">= 3.6"
[package.dependencies]
jmespath = ">=0.7.1,<1.0.0"
python-dateutil = ">=2.1,<3.0.0"
urllib3 = ">=1.25.4,<1.27"
[package.extras]
crt = ["awscrt (==0.12.5)"]
[[package]]
name = "bpy"
version = "2.82.1"
@@ -97,6 +151,18 @@ python-versions = ">=3.5.0"
[package.extras]
unicode_backport = ["unicodedata2"]
[[package]]
name = "click"
version = "8.0.3"
description = "Composable command line interface toolkit"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
[[package]]
name = "cmake"
version = "3.22.0"
@@ -116,6 +182,14 @@ category = "dev"
optional = false
python-versions = ">=3.4.0"
[[package]]
name = "colorama"
version = "0.4.4"
description = "Cross-platform colored terminal text."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "devtools"
version = "0.6.1"
@@ -160,29 +234,31 @@ typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.10\"
[[package]]
name = "gql"
version = "3.0.0b1"
version = "3.0.0rc0"
description = "GraphQL client for Python"
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
aiohttp = {version = ">=3.7.1,<3.8.0", optional = true, markers = "extra == \"all\""}
aiohttp = {version = ">=3.7.1,<3.9.0", optional = true, markers = "extra == \"all\""}
botocore = {version = ">=1.21,<2", optional = true, markers = "extra == \"all\""}
graphql-core = ">=3.1.5,<3.2"
requests = {version = ">=2.26,<3", optional = true, markers = "extra == \"all\""}
requests_toolbelt = {version = ">=0.9.1,<1", optional = true, markers = "extra == \"all\""}
urllib3 = {version = ">=1.26", optional = true, markers = "extra == \"all\""}
websockets = {version = ">=9,<10", optional = true, markers = "extra == \"all\""}
websockets = {version = ">=10,<11", optional = true, markers = "python_version > \"3.6\" and extra == \"all\""}
yarl = ">=1.6,<2.0"
[package.extras]
aiohttp = ["aiohttp (>=3.7.1,<3.8.0)"]
all = ["aiohttp (>=3.7.1,<3.8.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "websockets (>=9,<10)"]
dev = ["aiohttp (>=3.7.1,<3.8.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "websockets (>=9,<10)", "black (==19.10b0)", "check-manifest (>=0.42,<1)", "flake8 (==3.8.1)", "isort (==4.3.21)", "mypy (==0.770)", "sphinx (>=3.0.0,<4)", "sphinx_rtd_theme (>=0.4,<1)", "sphinx-argparse (==0.2.5)", "parse (==1.15.0)", "pytest (==5.4.2)", "pytest-asyncio (==0.11.0)", "pytest-cov (==2.8.1)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles"]
aiohttp = ["aiohttp (>=3.7.1,<3.9.0)"]
all = ["aiohttp (>=3.7.1,<3.9.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "botocore (>=1.21,<2)", "websockets (>=9,<10)", "websockets (>=10,<11)"]
botocore = ["botocore (>=1.21,<2)"]
dev = ["aiohttp (>=3.7.1,<3.9.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "botocore (>=1.21,<2)", "black (==19.10b0)", "check-manifest (>=0.42,<1)", "flake8 (==3.8.1)", "isort (==4.3.21)", "mypy (==0.910)", "sphinx (>=3.0.0,<4)", "sphinx_rtd_theme (>=0.4,<1)", "sphinx-argparse (==0.2.5)", "types-aiofiles", "types-mock", "types-requests", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-cov (==3.0.0)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles", "websockets (>=9,<10)", "websockets (>=10,<11)"]
requests = ["requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)"]
test = ["aiohttp (>=3.7.1,<3.8.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "websockets (>=9,<10)", "parse (==1.15.0)", "pytest (==5.4.2)", "pytest-asyncio (==0.11.0)", "pytest-cov (==2.8.1)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles"]
test_no_transport = ["parse (==1.15.0)", "pytest (==5.4.2)", "pytest-asyncio (==0.11.0)", "pytest-cov (==2.8.1)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles"]
websockets = ["websockets (>=9,<10)"]
test = ["aiohttp (>=3.7.1,<3.9.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "botocore (>=1.21,<2)", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-cov (==3.0.0)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles", "websockets (>=9,<10)", "websockets (>=10,<11)"]
test_no_transport = ["parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-cov (==3.0.0)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles"]
websockets = ["websockets (>=9,<10)", "websockets (>=10,<11)"]
[[package]]
name = "graphql-core"
@@ -200,6 +276,61 @@ category = "main"
optional = false
python-versions = ">=3.5"
[[package]]
name = "importlib-metadata"
version = "4.10.0"
description = "Read metadata from Python packages"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.dependencies]
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
zipp = ">=0.5"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
perf = ["ipython"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
[[package]]
name = "isort"
version = "5.10.1"
description = "A Python utility / library to sort Python imports."
category = "dev"
optional = false
python-versions = ">=3.6.1,<4.0"
[package.extras]
pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
requirements_deprecated_finder = ["pipreqs", "pip-api"]
colors = ["colorama (>=0.4.3,<0.5.0)"]
plugins = ["setuptools"]
[[package]]
name = "jmespath"
version = "0.10.0"
description = "JSON Matching Expressions"
category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "lazy-object-proxy"
version = "1.7.1"
description = "A fast and thorough lazy object proxy."
category = "dev"
optional = false
python-versions = ">=3.6"
[[package]]
name = "mccabe"
version = "0.6.1"
description = "McCabe checker, plugin for flake8"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "multidict"
version = "5.2.0"
@@ -208,6 +339,14 @@ category = "main"
optional = false
python-versions = ">=3.6"
[[package]]
name = "mypy-extensions"
version = "0.4.3"
description = "Experimental type system extensions for programs checked with the mypy typechecker."
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "nose"
version = "1.3.7"
@@ -224,6 +363,26 @@ category = "dev"
optional = false
python-versions = ">=3.7,<3.11"
[[package]]
name = "pathspec"
version = "0.9.0"
description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[[package]]
name = "platformdirs"
version = "2.4.1"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"]
test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]
[[package]]
name = "pydantic"
version = "1.8.2"
@@ -239,11 +398,28 @@ typing-extensions = ">=3.7.4.3"
dotenv = ["python-dotenv (>=0.10.4)"]
email = ["email-validator (>=1.0.3)"]
[[package]]
name = "pylint"
version = "2.12.2"
description = "python code static checker"
category = "dev"
optional = false
python-versions = ">=3.6.2"
[package.dependencies]
astroid = ">=2.9.0,<2.10"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
isort = ">=4.2.5,<6"
mccabe = ">=0.6,<0.7"
platformdirs = ">=2.2.0"
toml = ">=0.9.2"
typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
[[package]]
name = "python-dateutil"
version = "2.8.2"
description = "Extensions to the standard Python datetime module"
category = "dev"
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
@@ -283,7 +459,7 @@ requests = ">=2.0.1,<3.0.0"
name = "six"
version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
category = "dev"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
@@ -297,7 +473,7 @@ python-versions = ">=3.6"
[[package]]
name = "specklepy"
version = "2.4.2"
version = "2.5.1"
description = "The Python SDK for Speckle 2.0"
category = "main"
optional = false
@@ -321,6 +497,30 @@ python-versions = "*"
nose = "*"
python-dateutil = ">=2.2"
[[package]]
name = "toml"
version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language"
category = "dev"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "tomli"
version = "1.2.3"
description = "A lil' TOML parser"
category = "dev"
optional = false
python-versions = ">=3.6"
[[package]]
name = "typed-ast"
version = "1.5.1"
description = "a fork of Python 2 and 3 ast modules with type comment support"
category = "dev"
optional = false
python-versions = ">=3.6"
[[package]]
name = "typing-extensions"
version = "4.0.0"
@@ -352,11 +552,19 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "websockets"
version = "9.1"
version = "10.1"
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
category = "main"
optional = false
python-versions = ">=3.6.1"
python-versions = ">=3.7"
[[package]]
name = "wrapt"
version = "1.13.3"
description = "Module for decorators, wrappers and monkey patching."
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[[package]]
name = "yarl"
@@ -371,10 +579,22 @@ idna = ">=2.0"
multidict = ">=4.0"
typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
[[package]]
name = "zipp"
version = "3.7.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
[metadata]
lock-version = "1.1"
python-versions = ">=3.7,<3.8"
content-hash = "1459bac4b94b1801e6c6a0daebc87550e8cd6605ecfeb877aa0be1055c1d9380"
content-hash = "36520659c57db65e403de8b9cbb257e786d870aa01e87f6b4d943a334b896410"
[metadata.files]
aiohttp = [
@@ -420,6 +640,10 @@ appdirs = [
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
]
astroid = [
{file = "astroid-2.9.1-py3-none-any.whl", hash = "sha256:bfd6c41149d1a368e9b7d3cc90470528e080efdd57fbc0c95426794e0be91c5b"},
{file = "astroid-2.9.1.tar.gz", hash = "sha256:f973b3622700431b6e8734ce66f6c18503922a13fb8eb8592e78bd4506823efb"},
]
async-timeout = [
{file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"},
{file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"},
@@ -428,6 +652,14 @@ attrs = [
{file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
{file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
]
black = [
{file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"},
{file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"},
]
botocore = [
{file = "botocore-1.23.26-py3-none-any.whl", hash = "sha256:298f4d4e29504f65f73e8f78084f830af45cec49087d7d8fcf09481e243b26ec"},
{file = "botocore-1.23.26.tar.gz", hash = "sha256:0a933e3af6ecf79666beb2dfcb52a60f8ad1fee7df507f2a9202fe26fe569483"},
]
bpy = [
{file = "bpy-2.82.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ccbd1b7a62ffe67978723e91ff4df733c1a6b7c35a83bc0364b012ce4390167a"},
{file = "bpy-2.82.1.tar.gz", hash = "sha256:5f84452552724ae32faca9d001741e982f9cd61640c39975c6a6b734b29f5c35"},
@@ -448,6 +680,10 @@ charset-normalizer = [
{file = "charset-normalizer-2.0.8.tar.gz", hash = "sha256:735e240d9a8506778cd7a453d97e817e536bb1fc29f4f6961ce297b9c7a917b0"},
{file = "charset_normalizer-2.0.8-py3-none-any.whl", hash = "sha256:83fcdeb225499d6344c8f7f34684c2981270beacc32ede2e669e94f7fa544405"},
]
click = [
{file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"},
{file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"},
]
cmake = [
{file = "cmake-3.22.0-py2.py3-none-macosx_10_9_universal2.macosx_10_9_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:99b53d7c4aeea6ec6c61929c642b20265f56d3471a0c38858ea4894d1554683a"},
{file = "cmake-3.22.0-py2.py3-none-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:282dbb00f1c0aeb58243b490cb1e033ac159b9c13154c78afb08f18126472660"},
@@ -470,6 +706,10 @@ cmake-generators = [
{file = "cmake-generators-1.0.9.tar.gz", hash = "sha256:2b03bdcd69345c03ffa56aa025b3163bd26b1465561c365a79cf1c6a31672ebf"},
{file = "cmake_generators-1.0.9-py3-none-any.whl", hash = "sha256:23428a5b7c6b1f54071dcf88f962fdf958f5c344d9df22330541378c83bf386b"},
]
colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
]
devtools = [
{file = "devtools-0.6.1-py3-none-any.whl", hash = "sha256:7334183972a8d04e81d08b7f62126abca9b6f4de51d825c5fdcb9c88f252601a"},
{file = "devtools-0.6.1.tar.gz", hash = "sha256:a054307594d35d28fae8df7629967363e851ae0ac7b2152640a8a401c39d42d7"},
@@ -487,7 +727,7 @@ gitpython = [
{file = "GitPython-3.1.24.tar.gz", hash = "sha256:df83fdf5e684fef7c6ee2c02fc68a5ceb7e7e759d08b694088d0cacb4eba59e5"},
]
gql = [
{file = "gql-3.0.0b1.tar.gz", hash = "sha256:a08195e73ed08785e1aef71a540e514f80dbfa711b9effba31ba15fcb687f1fd"},
{file = "gql-3.0.0rc0.tar.gz", hash = "sha256:f2fcc17f3378480aeb9cffc4b01b9d43bfd061b9d96cfbb772def2bf8acc3a8b"},
]
graphql-core = [
{file = "graphql-core-3.1.6.tar.gz", hash = "sha256:e65975b6a13878f9113a1fa5320760585b522d139944e005936b1b8358d0651a"},
@@ -497,6 +737,61 @@ idna = [
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
]
importlib-metadata = [
{file = "importlib_metadata-4.10.0-py3-none-any.whl", hash = "sha256:b7cf7d3fef75f1e4c80a96ca660efbd51473d7e8f39b5ab9210febc7809012a4"},
{file = "importlib_metadata-4.10.0.tar.gz", hash = "sha256:92a8b58ce734b2a4494878e0ecf7d79ccd7a128b5fc6014c401e0b61f006f0f6"},
]
isort = [
{file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
{file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
]
jmespath = [
{file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"},
{file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"},
]
lazy-object-proxy = [
{file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"},
{file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"},
{file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"},
{file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"},
{file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"},
{file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"},
{file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"},
{file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"},
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"},
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"},
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"},
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"},
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"},
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"},
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"},
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"},
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"},
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"},
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"},
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"},
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"},
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"},
{file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"},
{file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"},
{file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"},
{file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"},
{file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"},
{file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"},
{file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"},
{file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"},
{file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"},
{file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"},
{file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"},
{file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"},
{file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"},
{file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"},
{file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"},
]
mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
]
multidict = [
{file = "multidict-5.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3822c5894c72e3b35aae9909bef66ec83e44522faf767c0ad39e0e2de11d3b55"},
{file = "multidict-5.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:28e6d883acd8674887d7edc896b91751dc2d8e87fbdca8359591a13872799e4e"},
@@ -571,6 +866,10 @@ multidict = [
{file = "multidict-5.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:c9631c642e08b9fff1c6255487e62971d8b8e821808ddd013d8ac058087591ac"},
{file = "multidict-5.2.0.tar.gz", hash = "sha256:0dd1c93edb444b33ba2274b66f63def8a327d607c6c790772f448a53b6ea59ce"},
]
mypy-extensions = [
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
]
nose = [
{file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"},
{file = "nose-1.3.7-py3-none-any.whl", hash = "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac"},
@@ -608,6 +907,14 @@ numpy = [
{file = "numpy-1.21.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a3deb31bc84f2b42584b8c4001c85d1934dbfb4030827110bc36bfd11509b7bf"},
{file = "numpy-1.21.4.zip", hash = "sha256:e6c76a87633aa3fa16614b61ccedfae45b91df2767cf097aa9c933932a7ed1e0"},
]
pathspec = [
{file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
]
platformdirs = [
{file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"},
{file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"},
]
pydantic = [
{file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"},
{file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"},
@@ -632,6 +939,10 @@ pydantic = [
{file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"},
{file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"},
]
pylint = [
{file = "pylint-2.12.2-py3-none-any.whl", hash = "sha256:daabda3f7ed9d1c60f52d563b1b854632fd90035bcf01443e234d3dc794e3b74"},
{file = "pylint-2.12.2.tar.gz", hash = "sha256:9d945a73640e1fec07ee34b42f5669b770c759acd536ec7b16d7e4b87a9c9ff9"},
]
python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
@@ -653,12 +964,41 @@ smmap = [
{file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"},
]
specklepy = [
{file = "specklepy-2.4.2-py3-none-any.whl", hash = "sha256:8906f69f4c3e7ba950873eb905b6e752c85d6aa2b2decb905165c6d401aebe20"},
{file = "specklepy-2.4.2.tar.gz", hash = "sha256:49fd6d8e1f2c6e190a0b6e85a08098984a8616eb46933b2516fcc769995452a6"},
{file = "specklepy-2.5.1-py3-none-any.whl", hash = "sha256:fd89ce56d2ed14209dee0bb424bf8ccd9b27718919a27b6f7bb69c099ebf4ffb"},
{file = "specklepy-2.5.1.tar.gz", hash = "sha256:d0db5d24c6118186a8f0c0902e3028193d47a529d639b1ae5ae6cb20213dfa2b"},
]
svn = [
{file = "svn-1.0.1.tar.gz", hash = "sha256:55f81f07853cc1d66d4800b0cfe2d3376ff02361a2b2361459dc22a0fab95247"},
]
toml = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
tomli = [
{file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"},
{file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"},
]
typed-ast = [
{file = "typed_ast-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d8314c92414ce7481eee7ad42b353943679cf6f30237b5ecbf7d835519e1212"},
{file = "typed_ast-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b53ae5de5500529c76225d18eeb060efbcec90ad5e030713fe8dab0fb4531631"},
{file = "typed_ast-1.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:24058827d8f5d633f97223f5148a7d22628099a3d2efe06654ce872f46f07cdb"},
{file = "typed_ast-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:a6d495c1ef572519a7bac9534dbf6d94c40e5b6a608ef41136133377bba4aa08"},
{file = "typed_ast-1.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:de4ecae89c7d8b56169473e08f6bfd2df7f95015591f43126e4ea7865928677e"},
{file = "typed_ast-1.5.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:256115a5bc7ea9e665c6314ed6671ee2c08ca380f9d5f130bd4d2c1f5848d695"},
{file = "typed_ast-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:7c42707ab981b6cf4b73490c16e9d17fcd5227039720ca14abe415d39a173a30"},
{file = "typed_ast-1.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:71dcda943a471d826ea930dd449ac7e76db7be778fcd722deb63642bab32ea3f"},
{file = "typed_ast-1.5.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4f30a2bcd8e68adbb791ce1567fdb897357506f7ea6716f6bbdd3053ac4d9471"},
{file = "typed_ast-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ca9e8300d8ba0b66d140820cf463438c8e7b4cdc6fd710c059bfcfb1531d03fb"},
{file = "typed_ast-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9caaf2b440efb39ecbc45e2fabde809cbe56272719131a6318fd9bf08b58e2cb"},
{file = "typed_ast-1.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c9bcad65d66d594bffab8575f39420fe0ee96f66e23c4d927ebb4e24354ec1af"},
{file = "typed_ast-1.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:591bc04e507595887160ed7aa8d6785867fb86c5793911be79ccede61ae96f4d"},
{file = "typed_ast-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:a80d84f535642420dd17e16ae25bb46c7f4c16ee231105e7f3eb43976a89670a"},
{file = "typed_ast-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:38cf5c642fa808300bae1281460d4f9b7617cf864d4e383054a5ef336e344d32"},
{file = "typed_ast-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b6ab14c56bc9c7e3c30228a0a0b54b915b1579613f6e463ba6f4eb1382e7fd4"},
{file = "typed_ast-1.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2b8d7007f6280e36fa42652df47087ac7b0a7d7f09f9468f07792ba646aac2d"},
{file = "typed_ast-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:b6d17f37f6edd879141e64a5db17b67488cfeffeedad8c5cec0392305e9bc775"},
{file = "typed_ast-1.5.1.tar.gz", hash = "sha256:484137cab8ecf47e137260daa20bafbba5f4e3ec7fda1c1e69ab299b75fa81c5"},
]
typing-extensions = [
{file = "typing_extensions-4.0.0-py3-none-any.whl", hash = "sha256:829704698b22e13ec9eaf959122315eabb370b0884400e9818334d8b677023d9"},
{file = "typing_extensions-4.0.0.tar.gz", hash = "sha256:2cdf80e4e04866a9b3689a51869016d36db0814d84b8d8a568d22781d45d27ed"},
@@ -714,39 +1054,107 @@ urllib3 = [
{file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"},
]
websockets = [
{file = "websockets-9.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d144b350045c53c8ff09aa1cfa955012dd32f00c7e0862c199edcabb1a8b32da"},
{file = "websockets-9.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b4ad84b156cf50529b8ac5cc1638c2cf8680490e3fccb6121316c8c02620a2e4"},
{file = "websockets-9.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2cf04601633a4ec176b9cc3d3e73789c037641001dbfaf7c411f89cd3e04fcaf"},
{file = "websockets-9.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:5c8f0d82ea2468282e08b0cf5307f3ad022290ed50c45d5cb7767957ca782880"},
{file = "websockets-9.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:caa68c95bc1776d3521f81eeb4d5b9438be92514ec2a79fececda814099c8314"},
{file = "websockets-9.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d2c2d9b24d3c65b5a02cac12cbb4e4194e590314519ed49db2f67ef561c3cf58"},
{file = "websockets-9.1-cp36-cp36m-win32.whl", hash = "sha256:f31722f1c033c198aa4a39a01905951c00bd1c74f922e8afc1b1c62adbcdd56a"},
{file = "websockets-9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:3ddff38894c7857c476feb3538dd847514379d6dc844961dc99f04b0384b1b1b"},
{file = "websockets-9.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:51d04df04ed9d08077d10ccbe21e6805791b78eac49d16d30a1f1fe2e44ba0af"},
{file = "websockets-9.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f68c352a68e5fdf1e97288d5cec9296664c590c25932a8476224124aaf90dbcd"},
{file = "websockets-9.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:b43b13e5622c5a53ab12f3272e6f42f1ce37cd5b6684b2676cb365403295cd40"},
{file = "websockets-9.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:9147868bb0cc01e6846606cd65cbf9c58598f187b96d14dd1ca17338b08793bb"},
{file = "websockets-9.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:836d14eb53b500fd92bd5db2fc5894f7c72b634f9c2a28f546f75967503d8e25"},
{file = "websockets-9.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:48c222feb3ced18f3dc61168ca18952a22fb88e5eb8902d2bf1b50faefdc34a2"},
{file = "websockets-9.1-cp37-cp37m-win32.whl", hash = "sha256:900589e19200be76dd7cbaa95e9771605b5ce3f62512d039fb3bc5da9014912a"},
{file = "websockets-9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ab5ee15d3462198c794c49ccd31773d8a2b8c17d622aa184f669d2b98c2f0857"},
{file = "websockets-9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:85e701a6c316b7067f1e8675c638036a796fe5116783a4c932e7eb8e305a3ffe"},
{file = "websockets-9.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b2e71c4670ebe1067fa8632f0d081e47254ee2d3d409de54168b43b0ba9147e0"},
{file = "websockets-9.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:230a3506df6b5f446fed2398e58dcaafdff12d67fe1397dff196411a9e820d02"},
{file = "websockets-9.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:7df3596838b2a0c07c6f6d67752c53859a54993d4f062689fdf547cb56d0f84f"},
{file = "websockets-9.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:826ccf85d4514609219725ba4a7abd569228c2c9f1968e8be05be366f68291ec"},
{file = "websockets-9.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:0dd4eb8e0bbf365d6f652711ce21b8fd2b596f873d32aabb0fbb53ec604418cc"},
{file = "websockets-9.1-cp38-cp38-win32.whl", hash = "sha256:1d0971cc7251aeff955aa742ec541ee8aaea4bb2ebf0245748fbec62f744a37e"},
{file = "websockets-9.1-cp38-cp38-win_amd64.whl", hash = "sha256:7189e51955f9268b2bdd6cc537e0faa06f8fffda7fb386e5922c6391de51b077"},
{file = "websockets-9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e9e5fd6dbdf95d99bc03732ded1fc8ef22ebbc05999ac7e0c7bf57fe6e4e5ae2"},
{file = "websockets-9.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9e7fdc775fe7403dbd8bc883ba59576a6232eac96dacb56512daacf7af5d618d"},
{file = "websockets-9.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:597c28f3aa7a09e8c070a86b03107094ee5cdafcc0d55f2f2eac92faac8dc67d"},
{file = "websockets-9.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:ad893d889bc700a5835e0a95a3e4f2c39e91577ab232a3dc03c262a0f8fc4b5c"},
{file = "websockets-9.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:1d6b4fddb12ab9adf87b843cd4316c4bd602db8d5efd2fb83147f0458fe85135"},
{file = "websockets-9.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:ebf459a1c069f9866d8569439c06193c586e72c9330db1390af7c6a0a32c4afd"},
{file = "websockets-9.1-cp39-cp39-win32.whl", hash = "sha256:be5fd35e99970518547edc906efab29afd392319f020c3c58b0e1a158e16ed20"},
{file = "websockets-9.1-cp39-cp39-win_amd64.whl", hash = "sha256:85db8090ba94e22d964498a47fdd933b8875a1add6ebc514c7ac8703eb97bbf0"},
{file = "websockets-9.1.tar.gz", hash = "sha256:276d2339ebf0df4f45df453923ebd2270b87900eda5dfd4a6b0cfa15f82111c3"},
{file = "websockets-10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:38db6e2163b021642d0a43200ee2dec8f4980bdbda96db54fde72b283b54cbfc"},
{file = "websockets-10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e1b60fd297adb9fc78375778a5220da7f07bf54d2a33ac781319650413fc6a60"},
{file = "websockets-10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3477146d1f87ead8df0f27e8960249f5248dceb7c2741e8bbec9aa5338d0c053"},
{file = "websockets-10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb01ea7b5f52e7125bdc3c5807aeaa2d08a0553979cf2d96a8b7803ea33e15e7"},
{file = "websockets-10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9fd62c6dc83d5d35fb6a84ff82ec69df8f4657fff05f9cd6c7d9bec0dd57f0f6"},
{file = "websockets-10.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3bbf080f3892ba1dc8838786ec02899516a9d227abe14a80ef6fd17d4fb57127"},
{file = "websockets-10.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5560558b0dace8312c46aa8915da977db02738ac8ecffbc61acfbfe103e10155"},
{file = "websockets-10.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:667c41351a6d8a34b53857ceb8343a45c85d438ee4fd835c279591db8aeb85be"},
{file = "websockets-10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:468f0031fdbf4d643f89403a66383247eb82803430b14fa27ce2d44d2662ca37"},
{file = "websockets-10.1-cp310-cp310-win32.whl", hash = "sha256:d0d81b46a5c87d443e40ce2272436da8e6092aa91f5fbeb60d1be9f11eff5b4c"},
{file = "websockets-10.1-cp310-cp310-win_amd64.whl", hash = "sha256:b68b6caecb9a0c6db537aa79750d1b592a841e4f1a380c6196091e65b2ad35f9"},
{file = "websockets-10.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a249139abc62ef333e9e85064c27fefb113b16ffc5686cefc315bdaef3eefbc8"},
{file = "websockets-10.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8877861e3dee38c8d302eee0d5dbefa6663de3b46dc6a888f70cd7e82562d1f7"},
{file = "websockets-10.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e3872ae57acd4306ecf937d36177854e218e999af410a05c17168cd99676c512"},
{file = "websockets-10.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b66e6d514f12c28d7a2d80bb2a48ef223342e99c449782d9831b0d29a9e88a17"},
{file = "websockets-10.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9f304a22ece735a3da8a51309bc2c010e23961a8f675fae46fdf62541ed62123"},
{file = "websockets-10.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:189ed478395967d6a98bb293abf04e8815349e17456a0a15511f1088b6cb26e4"},
{file = "websockets-10.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:08a42856158307e231b199671c4fce52df5786dd3d703f36b5d8ac76b206c485"},
{file = "websockets-10.1-cp37-cp37m-win32.whl", hash = "sha256:3ef6f73854cded34e78390dbdf40dfdcf0b89b55c0e282468ef92646fce8d13a"},
{file = "websockets-10.1-cp37-cp37m-win_amd64.whl", hash = "sha256:89e985d40d407545d5f5e2e58e1fdf19a22bd2d8cd54d20a882e29f97e930a0a"},
{file = "websockets-10.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:002071169d2e44ce8eb9e5ebac9fbce142ba4b5146eef1cfb16b177a27662657"},
{file = "websockets-10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cfae282c2aa7f0c4be45df65c248481f3509f8c40ca8b15ed96c35668ae0ff69"},
{file = "websockets-10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:97b4b68a2ddaf5c4707ae79c110bfd874c5be3c6ac49261160fb243fa45d8bbb"},
{file = "websockets-10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c9407719f42cb77049975410490c58a705da6af541adb64716573e550e5c9db"},
{file = "websockets-10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1d858fb31e5ac992a2cdf17e874c95f8a5b1e917e1fb6b45ad85da30734b223f"},
{file = "websockets-10.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7bdd3d26315db0a9cf8a0af30ca95e0aa342eda9c1377b722e71ccd86bc5d1dd"},
{file = "websockets-10.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e259be0863770cb91b1a6ccf6907f1ac2f07eff0b7f01c249ed751865a70cb0d"},
{file = "websockets-10.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6b014875fae19577a392372075e937ebfebf53fd57f613df07b35ab210f31534"},
{file = "websockets-10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:98de71f86bdb29430fd7ba9997f47a6b10866800e3ea577598a786a785701bb0"},
{file = "websockets-10.1-cp38-cp38-win32.whl", hash = "sha256:3a02ab91d84d9056a9ee833c254895421a6333d7ae7fff94b5c68e4fa8095519"},
{file = "websockets-10.1-cp38-cp38-win_amd64.whl", hash = "sha256:7d6673b2753f9c5377868a53445d0c321ef41ff3c8e3b6d57868e72054bfce5f"},
{file = "websockets-10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ddab2dc69ee5ae27c74dbfe9d7bb6fee260826c136dca257faa1a41d1db61a89"},
{file = "websockets-10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:14e9cf68a08d1a5d42109549201aefba473b1d925d233ae19035c876dd845da9"},
{file = "websockets-10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e4819c6fb4f336fd5388372cb556b1f3a165f3f68e66913d1a2fc1de55dc6f58"},
{file = "websockets-10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05e7f098c76b0a4743716590bb8f9706de19f1ef5148d61d0cf76495ec3edb9c"},
{file = "websockets-10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5bb6256de5a4fb1d42b3747b4e2268706c92965d75d0425be97186615bf2f24f"},
{file = "websockets-10.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:888a5fa2a677e0c2b944f9826c756475980f1b276b6302e606f5c4ff5635be9e"},
{file = "websockets-10.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6fdec1a0b3e5630c58e3d8704d2011c678929fce90b40908c97dfc47de8dca72"},
{file = "websockets-10.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:531d8eb013a9bc6b3ad101588182aa9b6dd994b190c56df07f0d84a02b85d530"},
{file = "websockets-10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0d93b7cadc761347d98da12ec1930b5c71b2096f1ceed213973e3cda23fead9c"},
{file = "websockets-10.1-cp39-cp39-win32.whl", hash = "sha256:d9b245db5a7e64c95816e27d72830e51411c4609c05673d1ae81eb5d23b0be54"},
{file = "websockets-10.1-cp39-cp39-win_amd64.whl", hash = "sha256:882c0b8bdff3bf1bd7f024ce17c6b8006042ec4cceba95cf15df57e57efa471c"},
{file = "websockets-10.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:10edd9d7d3581cfb9ff544ac09fc98cab7ee8f26778a5a8b2d5fd4b0684c5ba5"},
{file = "websockets-10.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa83174390c0ff4fc1304fbe24393843ac7a08fdd59295759c4b439e06b1536"},
{file = "websockets-10.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:483edee5abed738a0b6a908025be47f33634c2ad8e737edd03ffa895bd600909"},
{file = "websockets-10.1-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:816ae7dac2c6522cfa620947ead0ca95ac654916eebf515c94d7c28de5601a6e"},
{file = "websockets-10.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1dafe98698ece09b8ccba81b910643ff37198e43521d977be76caf37709cf62b"},
{file = "websockets-10.1.tar.gz", hash = "sha256:181d2b25de5a437b36aefedaf006ecb6fa3aa1328ec0236cdde15f32f9d3ff6d"},
]
wrapt = [
{file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"},
{file = "wrapt-1.13.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489"},
{file = "wrapt-1.13.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909"},
{file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229"},
{file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af"},
{file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de"},
{file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb"},
{file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80"},
{file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca"},
{file = "wrapt-1.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44"},
{file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056"},
{file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785"},
{file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096"},
{file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33"},
{file = "wrapt-1.13.3-cp310-cp310-win32.whl", hash = "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f"},
{file = "wrapt-1.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e"},
{file = "wrapt-1.13.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d"},
{file = "wrapt-1.13.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179"},
{file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3"},
{file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755"},
{file = "wrapt-1.13.3-cp35-cp35m-win32.whl", hash = "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851"},
{file = "wrapt-1.13.3-cp35-cp35m-win_amd64.whl", hash = "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13"},
{file = "wrapt-1.13.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918"},
{file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade"},
{file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc"},
{file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf"},
{file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125"},
{file = "wrapt-1.13.3-cp36-cp36m-win32.whl", hash = "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36"},
{file = "wrapt-1.13.3-cp36-cp36m-win_amd64.whl", hash = "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10"},
{file = "wrapt-1.13.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068"},
{file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709"},
{file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df"},
{file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2"},
{file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b"},
{file = "wrapt-1.13.3-cp37-cp37m-win32.whl", hash = "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829"},
{file = "wrapt-1.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"},
{file = "wrapt-1.13.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9"},
{file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554"},
{file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c"},
{file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b"},
{file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce"},
{file = "wrapt-1.13.3-cp38-cp38-win32.whl", hash = "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79"},
{file = "wrapt-1.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb"},
{file = "wrapt-1.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb"},
{file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32"},
{file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7"},
{file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e"},
{file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640"},
{file = "wrapt-1.13.3-cp39-cp39-win32.whl", hash = "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374"},
{file = "wrapt-1.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb"},
{file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"},
]
yarl = [
{file = "yarl-1.7.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2a8508f7350512434e41065684076f640ecce176d262a7d54f0da41d99c5a95"},
@@ -822,3 +1230,7 @@ yarl = [
{file = "yarl-1.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:797c2c412b04403d2da075fb93c123df35239cd7b4cc4e0cd9e5839b73f52c58"},
{file = "yarl-1.7.2.tar.gz", hash = "sha256:45399b46d60c253327a460e99856752009fcee5f5d3c80b2f7c0cae1c38d56dd"},
]
zipp = [
{file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"},
{file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"},
]
+3 -1
View File
@@ -7,13 +7,15 @@ license = "Apache-2.0"
[tool.poetry.dependencies]
python = ">=3.7,<3.8"
specklepy = "2.4.2"
specklepy = "^2.5.1"
[tool.poetry.dev-dependencies]
devtools = "^0.6.1"
numpy = "^1.20.2"
bpy = "^2.82.1"
bpy-build = "^2.1.0"
black = "^21.12b0"
pylint = "^2.12.2"
[build-system]
requires = ["poetry-core>=1.0.0"]