From f01fcb8e66c3b2004ad3ba5e3c927b8e8c6bfd76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 9 Dec 2022 19:45:20 +0100 Subject: [PATCH 01/13] fix(base): update speckle_type creation to better match Core --- src/specklepy/objects/base.py | 51 ++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/src/specklepy/objects/base.py b/src/specklepy/objects/base.py index 0507d0f..9bf61d7 100644 --- a/src/specklepy/objects/base.py +++ b/src/specklepy/objects/base.py @@ -14,7 +14,7 @@ import contextlib from enum import EnumMeta from warnings import warn -from specklepy.logging.exceptions import SpeckleException, SpeckleInvalidUnitException +from specklepy.logging.exceptions import SpeckleException from specklepy.objects.units import get_units_from_string, Units from specklepy.transports.memory import MemoryTransport @@ -90,7 +90,8 @@ class _RegisteringBase: """ speckle_type: ClassVar[str] - _type_registry: ClassVar[Dict[str, "Base"]] = {} + _speckle_type_override: ClassVar[Optional[str]] = None + _type_registry: ClassVar[Dict[str, Type["Base"]]] = {} _attr_types: ClassVar[Dict[str, Type]] = {} # dict of chunkable props and their max chunk size _chunkable: Dict[str, int] = {} @@ -98,22 +99,40 @@ class _RegisteringBase: _detachable: Set[str] = set() # list of defined detachable props _serialize_ignore: Set[str] = set() - class Config: - validate_assignment = True - @classmethod - def get_registered_type( - cls, speckle_type: str - ) -> Union["Base", Type["Base"], None]: + def get_registered_type(cls, speckle_type: str) -> Optional[Type["Base"]]: """Get the registered type from the protected mapping via the `speckle_type`""" return cls._type_registry.get(speckle_type, None) + @classmethod + def _determine_speckle_type(cls) -> str: + """ + This method brings the speckle_type construction in par with peckle-sharp/Core. + + The implementation differs, because in Core the basis of the speckle_type if + type.FullName, which includes the dotnet namespace name too. + Copying that behavior is hard in python, where the concept of namespaces + means something entirely different. + + So we enabled a speckle_type override mechanism, that enables + """ + base_name = "Base" + if cls.__name__ == base_name: + return base_name + + bases = [ + b._speckle_type_override if b._speckle_type_override else b.__name__ + for b in reversed(cls.mro()) + if issubclass(b, Base) and b.__name__ != base_name + ] + return ":".join(bases) + def __init_subclass__( cls, - speckle_type: str = None, - chunkable: Dict[str, int] = None, - detachable: Set[str] = None, - serialize_ignore: Set[str] = None, + speckle_type: Optional[str] = None, + chunkable: Optional[Dict[str, int]] = None, + detachable: Optional[Set[str]] = None, + serialize_ignore: Optional[Set[str]] = None, **kwargs: Dict[str, Any], ): """ @@ -123,13 +142,14 @@ class _RegisteringBase: initialization. This is reused to register each subclassing type into a class level dictionary. """ - if speckle_type in cls._type_registry: + cls._speckle_type_override = speckle_type + cls.speckle_type = cls._determine_speckle_type() + if cls.speckle_type in cls._type_registry: raise ValueError( f"The speckle_type: {speckle_type} is already registered for type: " - f"{cls._type_registry[speckle_type].__name__}. " + f"{cls._type_registry[cls.speckle_type].__name__}. " f"Please choose a different type name." ) - cls.speckle_type = speckle_type or cls.__name__ cls._type_registry[cls.speckle_type] = cls # type: ignore try: cls._attr_types = get_type_hints(cls) @@ -423,3 +443,4 @@ class DataChunk(Base, speckle_type="Speckle.Core.Models.DataChunk"): def __init__(self) -> None: super().__init__() self.data = [] + From 1a9b847c44f68e0ac3baf56af8d7baf85b01f758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 9 Dec 2022 19:46:09 +0100 Subject: [PATCH 02/13] test(base): update base tests to properly test the speckle_type generation --- tests/test_base.py | 9 +++++---- tests/test_registering_base.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 tests/test_registering_base.py diff --git a/tests/test_base.py b/tests/test_base.py index c6dfb10..b8360f7 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,4 +1,3 @@ -from codecs import ascii_encode from enum import Enum from typing import Dict, List, Optional, Union from contextlib import ExitStack as does_not_raise @@ -6,7 +5,7 @@ from contextlib import ExitStack as does_not_raise import pytest from specklepy.api import operations from specklepy.logging.exceptions import SpeckleException, SpeckleInvalidUnitException -from specklepy.objects.base import Base, DataChunk +from specklepy.objects.base import Base from specklepy.objects.units import Units @@ -29,12 +28,14 @@ def test_empty_prop_names(invalid_prop_name: str) -> None: class FakeModel(Base): """Just a test class type.""" - foo: str = "" +class FakeSub(FakeModel): + """Just a test class type.""" def test_new_type_registration() -> None: """Test if a new subclass is registered into the type register.""" - assert Base.get_registered_type("FakeModel") == FakeModel + assert Base.get_registered_type(FakeModel.speckle_type) == FakeModel + assert Base.get_registered_type(FakeSub.speckle_type) == FakeSub assert Base.get_registered_type("🐺️") is None diff --git a/tests/test_registering_base.py b/tests/test_registering_base.py new file mode 100644 index 0000000..5f5a8b7 --- /dev/null +++ b/tests/test_registering_base.py @@ -0,0 +1,33 @@ +from typing import Type +import pytest +from specklepy.objects.base import Base +from specklepy.objects.structural import Concrete + + +class Foo(Base): + """This is a Foo inheriting from Base.""" + + +class Bar(Foo, speckle_type="Custom.Bar"): + """This is a Bar inheriting from Foo.""" + + +class Baz(Bar): + """This is a Bar inheriting from Foo.""" + + +@pytest.mark.parametrize( + "klass, speckle_type", + [ + (Base, "Base"), + (Foo, "Foo"), + (Bar, "Foo:Custom.Bar"), + (Baz, "Foo:Custom.Bar:Baz"), + ( + Concrete, + "Objects.Structural.Materials.StructuralMaterial:Objects.Structural.Materials.Concrete", + ), + ], +) +def test_determine_speckle_type(klass: Type[Base], speckle_type: str): + assert klass._determine_speckle_type() == speckle_type From c8808b07b3447a083285e80c2efea96eb53479df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 9 Dec 2022 19:46:48 +0100 Subject: [PATCH 03/13] fix(objects): update structural objects to better match core --- src/specklepy/objects/structural/material.py | 27 +++++++----- .../objects/structural/properties.py | 44 +++++++++---------- src/specklepy/objects/units.py | 10 ++++- tests/test_structural.py | 12 +---- 4 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/specklepy/objects/structural/material.py b/src/specklepy/objects/structural/material.py index 2ab0f67..e7fc521 100644 --- a/src/specklepy/objects/structural/material.py +++ b/src/specklepy/objects/structural/material.py @@ -1,6 +1,7 @@ from enum import Enum +from typing import Optional -from ..base import Base +from specklepy.objects.base import Base STRUCTURAL_MATERIALS = "Objects.Structural.Materials" @@ -21,12 +22,14 @@ class MaterialType(int, Enum): Other = 11 -class Material(Base, speckle_type=STRUCTURAL_MATERIALS): - name: str = None - grade: str = None - materialType: MaterialType = None - designCode: str = None - codeYear: str = None +class StructuralMaterial( + Base, speckle_type=STRUCTURAL_MATERIALS + ".StructuralMaterial" +): + name: Optional[str] = None + grade: Optional[str] = None + materialType: Optional[MaterialType] = None + designCode: Optional[str] = None + codeYear: Optional[str] = None strength: float = 0.0 elasticModulus: float = 0.0 poissonsRatio: float = 0.0 @@ -38,22 +41,22 @@ class Material(Base, speckle_type=STRUCTURAL_MATERIALS): materialSafetyFactor: float = 0.0 -class Concrete(Material, speckle_type=STRUCTURAL_MATERIALS + ".Concrete"): +class Concrete(StructuralMaterial, speckle_type=STRUCTURAL_MATERIALS + ".Concrete"): compressiveStrength: float = 0.0 tensileStrength: float = 0.0 flexuralStrength: float = 0.0 maxCompressiveStrain: float = 0.0 maxTensileStrain: float = 0.0 maxAggregateSize: float = 0.0 - lightweight: bool = None + lightweight: Optional[bool] = None -class Steel(Material, speckle_type=STRUCTURAL_MATERIALS + ".Steel"): +class Steel(StructuralMaterial, speckle_type=STRUCTURAL_MATERIALS + ".Steel"): yieldStrength: float = 0.0 ultimateStrength: float = 0.0 maxStrain: float = 0.0 strainHardeningModulus: float = 0.0 -class Timber(Material, speckle_type=STRUCTURAL_MATERIALS + ".Timber"): - species: str = None +class Timber(StructuralMaterial, speckle_type=STRUCTURAL_MATERIALS + ".Timber"): + species: Optional[str] = None diff --git a/src/specklepy/objects/structural/properties.py b/src/specklepy/objects/structural/properties.py index 8697f58..de9e402 100644 --- a/src/specklepy/objects/structural/properties.py +++ b/src/specklepy/objects/structural/properties.py @@ -1,9 +1,9 @@ from enum import Enum +from typing import Optional -from ..base import Base - -from .material import * -from .axis import Axis +from specklepy.objects.base import Base +from specklepy.objects.structural.material import StructuralMaterial +from specklepy.objects.structural.axis import Axis STRUCTURAL_PROPERTY = "Objectives.Structural.Properties" @@ -89,36 +89,36 @@ class PropertyTypeDamper(int, Enum): class Property(Base, speckle_type=STRUCTURAL_PROPERTY): - name: str = None + name: Optional[str] = None class SectionProfile(Base, speckle_type=STRUCTURAL_PROPERTY + ".SectionProfile"): - name: str = None - shapeType: ShapeType = None + name: Optional[str] = None + shapeType: Optional[ShapeType] = None area: float = 0.0 Iyy: float = 0.0 Izz: float = 0.0 J: float = 0.0 Ky: float = 0.0 weight: float = 0.0 - units: str = None + units: Optional[str] = None class Property1D(Property, speckle_type=STRUCTURAL_PROPERTY + ".Property1D"): - memberType: MemberType = None - material : Material = None - profile: SectionProfile = None - referencePoint : BaseReferencePoint = None + memberType: Optional[MemberType] = None + material: Optional[StructuralMaterial] = None + profile: Optional[SectionProfile] = None + referencePoint: Optional[BaseReferencePoint] = None offsetY: float = 0.0 offsetZ: float = 0.0 class Property2D(Property, speckle_type=STRUCTURAL_PROPERTY + ".Property2D"): - type: PropertyType2D = None + type: Optional[PropertyType2D] = None thickness: float = 0.0 - material: Material = None - orientationAxis : Axis = None - refSurface : ReferenceSurface = None + material: Optional[StructuralMaterial] = None + orientationAxis: Optional[Axis] = None + refSurface: Optional[ReferenceSurface] = None zOffset: float = 0.0 modifierInPlane: float = 0.0 modifierBending: float = 0.0 @@ -127,13 +127,13 @@ class Property2D(Property, speckle_type=STRUCTURAL_PROPERTY + ".Property2D"): class Property3D(Property, speckle_type=STRUCTURAL_PROPERTY + ".Property3D"): - type: PropertyType3D = None - material: Material = None - orientationAxis: Axis = None + type: Optional[PropertyType3D] = None + material: Optional[StructuralMaterial] = None + orientationAxis: Optional[Axis] = None class PropertyDamper(Property, speckle_type=STRUCTURAL_PROPERTY + ".PropertyDamper"): - damperType: PropertyTypeDamper = None + damperType: Optional[PropertyTypeDamper] = None dampingX: float = 0.0 dampingY: float = 0.0 dampingZ: float = 0.0 @@ -150,14 +150,14 @@ class PropertyMass(Property, speckle_type=STRUCTURAL_PROPERTY + ".PropertyMass") inertiaXY: float = 0.0 inertiaYZ: float = 0.0 inertiaZX: float = 0.0 - massModified: bool = None + massModified: Optional[bool] = None massModifierX: float = 0.0 massModifierY: float = 0.0 massModifierZ: float = 0.0 class PropertySpring(Property, speckle_type=STRUCTURAL_PROPERTY + ".PropertySpring"): - springType: PropertyTypeSpring = None + springType: Optional[PropertyTypeSpring] = None springCurveX: float = 0.0 stiffnessX: float = 0.0 springCurveY: float = 0.0 diff --git a/src/specklepy/objects/units.py b/src/specklepy/objects/units.py index 4f12b27..47276b5 100644 --- a/src/specklepy/objects/units.py +++ b/src/specklepy/objects/units.py @@ -57,7 +57,10 @@ def get_units_from_encoding(unit: int): return name raise SpeckleException( - message=f"Could not understand what unit {unit} is referring to. Please enter a valid unit encoding (eg {UNITS_ENCODINGS})." + message=( + f"Could not understand what unit {unit} is referring to." + f"Please enter a valid unit encoding (eg {UNITS_ENCODINGS})." + ) ) @@ -66,5 +69,8 @@ def get_encoding_from_units(unit: Union[Units, None]): return UNITS_ENCODINGS[unit] except KeyError as e: raise SpeckleException( - message=f"No encoding exists for unit {unit}. Please enter a valid unit to encode (eg {UNITS_ENCODINGS})." + message=( + f"No encoding exists for unit {unit}." + f"Please enter a valid unit to encode (eg {UNITS_ENCODINGS})." + ) ) from e diff --git a/tests/test_structural.py b/tests/test_structural.py index 9c5f0be..b899d59 100644 --- a/tests/test_structural.py +++ b/tests/test_structural.py @@ -1,18 +1,10 @@ -import json -from typing import Callable - import pytest -from specklepy.api import operations -from specklepy.logging.exceptions import SpeckleException -from specklepy.objects.base import Base -from specklepy.objects.encoding import CurveArray, ObjectArray from specklepy.objects.geometry import ( Line, Mesh, Point, Vector, ) -from specklepy.transports.memory import MemoryTransport from specklepy.objects.structural.geometry import ( Node, Element1D, @@ -29,7 +21,7 @@ from specklepy.objects.structural.properties import ( ShapeType, ) from specklepy.objects.structural.material import ( - Material, + StructuralMaterial, ) from specklepy.objects.structural.analysis import Model @@ -82,7 +74,7 @@ def node(restraint, point): @pytest.fixture() def material(): - return Material(name="TestMaterial") + return StructuralMaterial(name="TestMaterial") @pytest.fixture() From 5a1d624979537cad776cb06591daac3a8772e22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 9 Dec 2022 20:47:16 +0100 Subject: [PATCH 04/13] refactor(objects): fix import structure and typing errors for objects --- src/specklepy/api/resources/__init__.py | 1 - src/specklepy/objects/__init__.py | 3 +- src/specklepy/objects/encoding.py | 4 +- src/specklepy/objects/fakemesh.py | 24 +- src/specklepy/objects/geometry.py | 266 +++++++++--------- src/specklepy/objects/other.py | 28 +- src/specklepy/objects/structural/__init__.py | 115 +++++++- src/specklepy/objects/structural/analysis.py | 68 +++-- src/specklepy/objects/structural/axis.py | 12 +- src/specklepy/objects/structural/geometry.py | 95 ++++--- src/specklepy/objects/structural/loading.py | 69 ++--- .../objects/structural/properties.py | 2 +- src/specklepy/objects/structural/results.py | 37 ++- src/specklepy/objects/units.py | 8 + 14 files changed, 425 insertions(+), 307 deletions(-) diff --git a/src/specklepy/api/resources/__init__.py b/src/specklepy/api/resources/__init__.py index acf781a..ad56df9 100644 --- a/src/specklepy/api/resources/__init__.py +++ b/src/specklepy/api/resources/__init__.py @@ -1,4 +1,3 @@ -from pathlib import Path import sys import pkgutil from importlib import import_module diff --git a/src/specklepy/objects/__init__.py b/src/specklepy/objects/__init__.py index 34a6d83..d10fb2f 100644 --- a/src/specklepy/objects/__init__.py +++ b/src/specklepy/objects/__init__.py @@ -1,5 +1,6 @@ """Builtin Speckle object kit.""" from specklepy.objects.base import Base +from specklepy.objects import encoding, geometry, other, units, structural -__all__ = ["Base"] +__all__ = ["Base", "encoding", "geometry", "other", "units", "structural"] diff --git a/src/specklepy/objects/encoding.py b/src/specklepy/objects/encoding.py index dd4f0f1..c6b6361 100644 --- a/src/specklepy/objects/encoding.py +++ b/src/specklepy/objects/encoding.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import Any, Callable, List, Type, Dict +from typing import Any, Callable, List, Optional, Type, Dict from specklepy.logging.exceptions import SpeckleException from specklepy.objects.base import Base @@ -43,7 +43,7 @@ def curve_from_list(args: List[float]): class ObjectArray: - def __init__(self, data: list = None) -> None: + def __init__(self, data: Optional[list] = None) -> None: self.data = data or [] @classmethod diff --git a/src/specklepy/objects/fakemesh.py b/src/specklepy/objects/fakemesh.py index 319a130..c8ac5a7 100644 --- a/src/specklepy/objects/fakemesh.py +++ b/src/specklepy/objects/fakemesh.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import List +from typing import List, Optional from specklepy.objects.geometry import Point from .base import Base @@ -16,8 +16,8 @@ DETACHABLE = {"detach_this", "origin", "detached_list"} class FakeGeo(Base, chunkable={"dots": 50}, detachable={"pointslist"}): - pointslist: List[Base] = None - dots: List[int] = None + pointslist: Optional[List[Base]] = None + dots: Optional[List[int]] = None class FakeDirection(Enum): @@ -28,15 +28,15 @@ class FakeDirection(Enum): class FakeMesh(FakeGeo, chunkable=CHUNKABLE_PROPS, detachable=DETACHABLE): - vertices: List[float] = None - faces: List[int] = None - colors: List[int] = None - textureCoordinates: List[float] = None - cardinal_dir: FakeDirection = None - test_bases: List[Base] = None - detach_this: Base = None - detached_list: List[Base] = None - _origin: Point = None + vertices: Optional[List[float]] = None + faces: Optional[List[int]] = None + colors: Optional[List[int]] = None + textureCoordinates: Optional[List[float]] = None + cardinal_dir: Optional[FakeDirection] = None + test_bases: Optional[List[Base]] = None + detach_this: Optional[Base] = None + detached_list: Optional[List[Base]] = None + _origin: Optional[Point] = None # def __init__(self, **kwargs) -> None: # super(FakeMesh, self).__init__(**kwargs) diff --git a/src/specklepy/objects/geometry.py b/src/specklepy/objects/geometry.py index 664ad17..7bf000b 100644 --- a/src/specklepy/objects/geometry.py +++ b/src/specklepy/objects/geometry.py @@ -1,9 +1,9 @@ from enum import Enum from typing import Any, List, Optional -from .base import Base -from .encoding import CurveArray, CurveTypeEncoding, ObjectArray -from .units import get_encoding_from_units, get_units_from_encoding +from specklepy.objects.base import Base +from specklepy.objects.encoding import CurveArray, CurveTypeEncoding, ObjectArray +from specklepy.objects.units import get_encoding_from_units, get_units_from_encoding GEOMETRY = "Objects.Geometry." @@ -52,7 +52,7 @@ class Vector(Point, speckle_type=GEOMETRY + "Vector"): class ControlPoint(Point, speckle_type=GEOMETRY + "ControlPoint"): - weight: float = None + weight: Optional[float] = None class Plane(Base, speckle_type=GEOMETRY + "Plane"): @@ -86,16 +86,16 @@ class Box(Base, speckle_type=GEOMETRY + "Box"): ySize: Interval = Interval() zSize: Interval = Interval() xSize: Interval = Interval() - area: float = None - volume: float = None + area: Optional[float] = None + volume: Optional[float] = None class Line(Base, speckle_type=GEOMETRY + "Line"): start: Point = Point() - end: Point = None - domain: Interval = None - bbox: Box = None - length: float = None + end: Optional[Point] = None + domain: Optional[Interval] = None + bbox: Optional[Box] = None + length: Optional[float] = None @classmethod def from_list(cls, args: List[Any]) -> "Line": @@ -118,18 +118,18 @@ class Line(Base, speckle_type=GEOMETRY + "Line"): class Arc(Base, speckle_type=GEOMETRY + "Arc"): - radius: float = None - startAngle: float = None - endAngle: float = None - angleRadians: float = None - plane: Plane = None - domain: Interval = None - startPoint: Point = None - midPoint: Point = None - endPoint: Point = None - bbox: Box = None - area: float = None - length: float = None + radius: Optional[float] = None + startAngle: Optional[float] = None + endAngle: Optional[float] = None + angleRadians: Optional[float] = None + plane: Optional[Plane] = None + domain: Optional[Interval] = None + startPoint: Optional[Point] = None + midPoint: Optional[Point] = None + endPoint: Optional[Point] = None + bbox: Optional[Box] = None + area: Optional[float] = None + length: Optional[float] = None @classmethod def from_list(cls, args: List[Any]) -> "Arc": @@ -163,12 +163,12 @@ class Arc(Base, speckle_type=GEOMETRY + "Arc"): class Circle(Base, speckle_type=GEOMETRY + "Circle"): - radius: float = None - plane: Plane = None - domain: Interval = None - bbox: Box = None - area: float = None - length: float = None + radius: Optional[float] = None + plane: Optional[Plane] = None + domain: Optional[Interval] = None + bbox: Optional[Box] = None + area: Optional[float] = None + length: Optional[float] = None @classmethod def from_list(cls, args: List[Any]) -> "Circle": @@ -190,14 +190,14 @@ class Circle(Base, speckle_type=GEOMETRY + "Circle"): class Ellipse(Base, speckle_type=GEOMETRY + "Ellipse"): - firstRadius: float = None - secondRadius: float = None - plane: Plane = None - domain: Interval = None - trimDomain: Interval = None - bbox: Box = None - area: float = None - length: float = None + firstRadius: Optional[float] = None + secondRadius: Optional[float] = None + plane: Optional[Plane] = None + domain: Optional[Interval] = None + trimDomain: Optional[Interval] = None + bbox: Optional[Box] = None + area: Optional[float] = None + length: Optional[float] = None @classmethod def from_list(cls, args: List[Any]) -> "Ellipse": @@ -222,9 +222,9 @@ class Ellipse(Base, speckle_type=GEOMETRY + "Ellipse"): class Polyline(Base, speckle_type=GEOMETRY + "Polyline", chunkable={"value": 20000}): value: List[float] = None - closed: bool = None - domain: Interval = None - bbox: Box = None + closed: Optional[bool] = None + domain: Optional[Interval] = None + bbox: Optional[Box] = None area: float = None length: float = None @@ -277,18 +277,18 @@ class Curve( speckle_type=GEOMETRY + "Curve", chunkable={"points": 20000, "weights": 20000, "knots": 20000}, ): - degree: int = None - periodic: bool = None - rational: bool = None - points: List[float] = None - weights: List[float] = None - knots: List[float] = None - domain: Interval = None - displayValue: Polyline = None - closed: bool = None - bbox: Box = None - area: float = None - length: float = None + degree: Optional[int] = None + periodic: Optional[bool] = None + rational: Optional[bool] = None + points: Optional[List[float]] = None + weights: Optional[List[float]] = None + knots: Optional[List[float]] = None + domain: Optional[Interval] = None + displayValue: Optional[Polyline] = None + closed: Optional[bool] = None + bbox: Optional[Box] = None + area: Optional[float] = None + length: Optional[float] = None def as_points(self) -> List[Point]: """Converts the `value` attribute to a list of Points""" @@ -345,12 +345,12 @@ class Curve( class Polycurve(Base, speckle_type=GEOMETRY + "Polycurve"): - segments: List[Base] = None - domain: Interval = None - closed: bool = None - bbox: Box = None - area: float = None - length: float = None + segments: Optional[List[Base]] = None + domain: Optional[Interval] = None + closed: Optional[bool] = None + bbox: Optional[Box] = None + area: Optional[float] = None + length: Optional[float] = None @classmethod def from_list(cls, args: List[Any]) -> "Polycurve": @@ -375,17 +375,17 @@ class Polycurve(Base, speckle_type=GEOMETRY + "Polycurve"): class Extrusion(Base, speckle_type=GEOMETRY + "Extrusion"): - capped: bool = None - profile: Base = None - pathStart: Point = None - pathEnd: Point = None - pathCurve: Base = None - pathTangent: Base = None - profiles: List[Base] = None - length: float = None - area: float = None - volume: float = None - bbox: Box = None + capped: Optional[bool] = None + profile: Optional[Base] = None + pathStart: Optional[Point] = None + pathEnd: Optional[Point] = None + pathCurve: Optional[Base] = None + pathTangent: Optional[Base] = None + profiles: Optional[List[Base]] = None + length: Optional[float] = None + area: Optional[float] = None + volume: Optional[float] = None + bbox: Optional[Box] = None class Mesh( @@ -398,21 +398,21 @@ class Mesh( "textureCoordinates": 2000, }, ): - vertices: List[float] = None - faces: List[int] = None - colors: List[int] = None - textureCoordinates: List[float] = None - bbox: Box = None - area: float = None - volume: float = None + vertices: Optional[List[float]] = None + faces: Optional[List[int]] = None + colors: Optional[List[int]] = None + textureCoordinates: Optional[List[float]] = None + bbox: Optional[Box] = None + area: Optional[float] = None + volume: Optional[float] = None @classmethod def create( cls, vertices: List[float], faces: List[int], - colors: List[int] = None, - texture_coordinates: List[float] = None, + colors: Optional[List[int]] = None, + texture_coordinates: Optional[List[float]] = None, ) -> "Mesh": """ Create a new Mesh from lists representing its vertices, faces, @@ -430,20 +430,20 @@ class Mesh( class Surface(Base, speckle_type=GEOMETRY + "Surface"): - degreeU: int = None - degreeV: int = None - rational: bool = None - area: float = None - pointData: List[float] = None - countU: int = None - countV: int = None - bbox: Box = None - closedU: bool = None - closedV: bool = None - domainU: Interval = None - domainV: Interval = None - knotsU: List[float] = None - knotsV: List[float] = None + degreeU: Optional[int] = None + degreeV: Optional[int] = None + rational: Optional[bool] = None + area: Optional[float] = None + pointData: Optional[List[float]] = None + countU: Optional[int] = None + countV: Optional[int] = None + bbox: Optional[Box] = None + closedU: Optional[bool] = None + closedV: Optional[bool] = None + domainU: Optional[Interval] = None + domainV: Optional[Interval] = None + knotsU: Optional[List[float]] = None + knotsV: Optional[List[float]] = None @classmethod def from_list(cls, args: List[Any]) -> "Surface": @@ -493,11 +493,11 @@ class Surface(Base, speckle_type=GEOMETRY + "Surface"): class BrepFace(Base, speckle_type=GEOMETRY + "BrepFace"): - _Brep: "Brep" = None - SurfaceIndex: int = None - OuterLoopIndex: int = None - OrientationReversed: bool = None - LoopIndices: List[int] = None + _Brep: Optional["Brep"] = None + SurfaceIndex: Optional[int] = None + OuterLoopIndex: Optional[int] = None + OrientationReversed: Optional[bool] = None + LoopIndices: Optional[List[int]] = None @property def _outer_loop(self): @@ -533,13 +533,13 @@ class BrepFace(Base, speckle_type=GEOMETRY + "BrepFace"): class BrepEdge(Base, speckle_type=GEOMETRY + "BrepEdge"): - _Brep: "Brep" = None - Curve3dIndex: int = None - TrimIndices: List[int] = None - StartIndex: int = None - EndIndex: int = None - ProxyCurveIsReversed: bool = None - Domain: Interval = None + _Brep: Optional["Brep"] = None + Curve3dIndex: Optional[int] = None + TrimIndices: Optional[List[int]] = None + StartIndex: Optional[int] = None + EndIndex: Optional[int] = None + ProxyCurveIsReversed: Optional[bool] = None + Domain: Optional[Interval] = None @property def _start_vertex(self): @@ -600,10 +600,10 @@ class BrepLoopType(int, Enum): class BrepLoop(Base, speckle_type=GEOMETRY + "BrepLoop"): - _Brep: "Brep" = None - FaceIndex: int = None - TrimIndices: List[int] = None - Type: BrepLoopType = None + _Brep: Optional["Brep"] = None + FaceIndex: Optional[Optional[int]] = None + TrimIndices: Optional[List[int]] = None + Type: Optional[BrepLoopType] = None @property def _face(self): @@ -644,17 +644,17 @@ class BrepTrimType(int, Enum): class BrepTrim(Base, speckle_type=GEOMETRY + "BrepTrim"): - _Brep: "Brep" = None - EdgeIndex: int = None - StartIndex: int = None - EndIndex: int = None - FaceIndex: int = None - LoopIndex: int = None - CurveIndex: int = None - IsoStatus: int = None - TrimType: BrepTrimType = None - IsReversed: bool = None - Domain: Interval = None + _Brep: Optional["Brep"] = None + EdgeIndex: Optional[int] = None + StartIndex: Optional[int] = None + EndIndex: Optional[int] = None + FaceIndex: Optional[int] = None + LoopIndex: Optional[int] = None + CurveIndex: Optional[int] = None + IsoStatus: Optional[int] = None + TrimType: Optional[BrepTrimType] = None + IsReversed: Optional[bool] = None + Domain: Optional[Interval] = None @property def _face(self): @@ -731,21 +731,21 @@ class Brep( "Faces", }, ): - provenance: str = None - bbox: Box = None - area: float = None - volume: float = None - _displayValue: List[Mesh] = None - Surfaces: List[Surface] = None - Curve3D: List[Base] = None - Curve2D: List[Base] = None - Vertices: List[Point] = None - Edges: List[BrepEdge] = None - Loops: List[BrepLoop] = None - Faces: List[BrepFace] = None - Trims: List[BrepTrim] = None - IsClosed: bool = None - Orientation: int = None + provenance: Optional[str] = None + bbox: Optional[Box] = None + area: Optional[float] = None + volume: Optional[float] = None + _displayValue: Optional[List[Mesh]] = None + Surfaces: Optional[List[Surface]] = None + Curve3D: Optional[List[Base]] = None + Curve2D: Optional[List[Base]] = None + Vertices: Optional[List[Point]] = None + Edges: Optional[List[BrepEdge]] = None + Loops: Optional[List[BrepLoop]] = None + Faces: Optional[List[BrepFace]] = None + Trims: Optional[List[BrepTrim]] = None + IsClosed: Optional[bool] = None + Orientation: Optional[int] = None def _inject_self_into_children(self, children: Optional[List[Base]]) -> List[Base]: if children is None: diff --git a/src/specklepy/objects/other.py b/src/specklepy/objects/other.py index 7d32bef..b184c3b 100644 --- a/src/specklepy/objects/other.py +++ b/src/specklepy/objects/other.py @@ -1,4 +1,4 @@ -from typing import Any, List +from typing import Any, List, Optional from specklepy.objects.geometry import Point, Vector from .base import Base @@ -25,7 +25,7 @@ IDENTITY_TRANSFORM = [ class RenderMaterial(Base, speckle_type=OTHER + "RenderMaterial"): - name: str = None + name: Optional[str] = None opacity: float = 1 metalness: float = 0 roughness: float = 1 @@ -44,7 +44,7 @@ class Transform( The 4th column defines translation, where the last value is a divisor (usually equal to 1). """ - _value: List[float] = None + _value: Optional[List[float]] = None @property def value(self) -> List[float]: @@ -188,27 +188,27 @@ class Transform( class BlockDefinition( Base, speckle_type=OTHER + "BlockDefinition", detachable={"geometry"} ): - name: str = None - basePoint: Point = None - geometry: List[Base] = None + name: Optional[str] = None + basePoint: Optional[Point] = None + geometry: Optional[List[Base]] = None class BlockInstance( Base, speckle_type=OTHER + "BlockInstance", detachable={"blockDefinition"} ): - blockDefinition: BlockDefinition = None - transform: Transform = None + blockDefinition: Optional[BlockDefinition] = None + transform: Optional[Transform] = None # TODO: prob move this into a built elements module, but just trialling this for now class RevitParameter(Base, speckle_type="Objects.BuiltElements.Revit.Parameter"): - name: str = None + name: Optional[str] = None value: Any = None - applicationUnitType: str = None # eg UnitType UT_Length - applicationUnit: str = None # DisplayUnitType eg DUT_MILLIMITERS - applicationInternalName: str = ( - None # BuiltInParameterName or GUID for shared parameter - ) + applicationUnitType: Optional[str] = None # eg UnitType UT_Length + applicationUnit: Optional[str] = None # DisplayUnitType eg DUT_MILLIMITERS + applicationInternalName: Optional[ + str + ] = None # BuiltInParameterName or GUID for shared parameter isShared: bool = False isReadOnly: bool = False isTypeParameter: bool = False diff --git a/src/specklepy/objects/structural/__init__.py b/src/specklepy/objects/structural/__init__.py index 4c182fd..719819c 100644 --- a/src/specklepy/objects/structural/__init__.py +++ b/src/specklepy/objects/structural/__init__.py @@ -1,20 +1,101 @@ """Builtin Speckle object kit.""" -from specklepy.objects.structural.analysis import * -from specklepy.objects.structural.properties import * -from specklepy.objects.structural.material import * -from specklepy.objects.structural.geometry import * -from specklepy.objects.structural.loading import * +from specklepy.objects.structural.analysis import ( + Model, + ModelInfo, + ModelSettings, + ModelUnits, +) from specklepy.objects.structural.axis import Axis +from specklepy.objects.structural.geometry import ( + ElementType1D, + ElementType2D, + ElementType3D, + Node, + Restraint, + Element1D, + Element2D, + Element3D, +) +from specklepy.objects.structural.loading import ( + Load, + LoadType, + ActionType, + BeamLoadType, + FaceLoadType, + LoadDirection, + LoadDirection2D, + LoadAxisType, + CombinationType, + LoadCase, + LoadBeam, + LoadCombinations, + LoadFace, + LoadGravity, + LoadNode, +) +from specklepy.objects.structural.material import ( + MaterialType, + StructuralMaterial, + Concrete, + Steel, + Timber, +) + +from specklepy.objects.structural.properties import ( + MemberType, + BaseReferencePoint, + ReferenceSurface, + PropertyType2D, + PropertyType3D, + ShapeType, + PropertyTypeSpring, + PropertyTypeDamper, + Property, + SectionProfile, + Property1D, + Property2D, + Property3D, + PropertyDamper, + PropertyMass, + PropertySpring, + ReferenceSurfaceEnum, + shapeType, +) + +from specklepy.objects.structural.results import ( + Result, + Result1D, + ResultSet1D, + Result2D, + ResultSet2D, + Result3D, + ResultSet3D, + ResultGlobal, + ResultSetNode, + ResultNode, + ResultSetAll, +) __all__ = [ "Element1D", "Element2D", "Element3D", + "ElementType1D", + "ElementType2D", + "ElementType3D", "Axis", "Node", "Restraint", "Load", + "LoadType", + "ActionType", + "BeamLoadType", + "FaceLoadType", + "LoadDirection", + "LoadDirection2D", + "LoadAxisType", + "CombinationType", "LoadBeam", "LoadCase", "LoadCombinations", @@ -25,8 +106,9 @@ __all__ = [ "ModelInfo", "ModelSettings", "ModelUnits", + "MaterialType", "Concrete", - "Material", + "StructuralMaterial", "Steel", "Timber", "Property", @@ -37,4 +119,25 @@ __all__ = [ "PropertyMass", "PropertySpring", "SectionProfile", + "MemberType", + "BaseReferencePoint", + "ReferenceSurface", + "PropertyType2D", + "PropertyType3D", + "ShapeType", + "PropertyTypeSpring", + "PropertyTypeDamper", + "ReferenceSurfaceEnum", + "shapeType", + "Result", + "Result1D", + "ResultSet1D", + "Result2D", + "ResultSet2D", + "Result3D", + "ResultSet3D", + "ResultGlobal", + "ResultSetNode", + "ResultNode", + "ResultSetAll", ] diff --git a/src/specklepy/objects/structural/analysis.py b/src/specklepy/objects/structural/analysis.py index d1612dd..ee82eea 100644 --- a/src/specklepy/objects/structural/analysis.py +++ b/src/specklepy/objects/structural/analysis.py @@ -1,51 +1,49 @@ -from typing import List +from typing import List, Optional -from ..base import Base -from ..geometry import * -from .properties import * +from specklepy.objects.base import Base STRUCTURAL_ANALYSIS = "Objects.Structural.Analysis." class ModelUnits(Base, speckle_type=STRUCTURAL_ANALYSIS + "ModelUnits"): - length: str = None - sections: str = None - displacements: str = None - stress: str = None - force: str = None - mass: str = None - time: str = None - temperature: str = None - velocity: str = None - acceleration: str = None - energy: str = None - angle: str = None - strain: str = None + length: Optional[str] = None + sections: Optional[str] = None + displacements: Optional[str] = None + stress: Optional[str] = None + force: Optional[str] = None + mass: Optional[str] = None + time: Optional[str] = None + temperature: Optional[str] = None + velocity: Optional[str] = None + acceleration: Optional[str] = None + energy: Optional[str] = None + angle: Optional[str] = None + strain: Optional[str] = None class ModelSettings(Base, speckle_type=STRUCTURAL_ANALYSIS + "ModelSettings"): - modelUnits: ModelUnits = None - steelCode: str = None - concreteCode: str = None + modelUnits: Optional[ModelUnits] = None + steelCode: Optional[str] = None + concreteCode: Optional[str] = None coincidenceTolerance: float = 0.0 class ModelInfo(Base, speckle_type=STRUCTURAL_ANALYSIS + "ModelInfo"): - name: str = None - description: str = None - projectNumber: str = None - projectName: str = None - settings: ModelSettings = None - initials: str = None - application: str = None + name: Optional[str] = None + description: Optional[str] = None + projectNumber: Optional[str] = None + projectName: Optional[str] = None + settings: Optional[ModelSettings] = None + initials: Optional[str] = None + application: Optional[str] = None class Model(Base, speckle_type=STRUCTURAL_ANALYSIS + "Model"): - specs: ModelInfo = None - nodes: List = None - elements: List = None - loads: List = None - restraints: List = None - properties: List = None - materials: List = None - layerDescription: str = None + specs: Optional[ModelInfo] = None + nodes: Optional[List] = None + elements: Optional[List] = None + loads: Optional[List] = None + restraints: Optional[List] = None + properties: Optional[List] = None + materials: Optional[List] = None + layerDescription: Optional[str] = None diff --git a/src/specklepy/objects/structural/axis.py b/src/specklepy/objects/structural/axis.py index 574fe9c..a7fc06e 100644 --- a/src/specklepy/objects/structural/axis.py +++ b/src/specklepy/objects/structural/axis.py @@ -1,8 +1,10 @@ -from ..base import Base -from ..geometry import Plane +from typing import Optional + +from specklepy.objects.base import Base +from specklepy.objects.geometry import Plane class Axis(Base, speckle_type="Objects.Structural.Geometry.Axis"): - name: str = None - axisType: str = None - plane: Plane = None + name: Optional[str] = None + axisType: Optional[str] = None + plane: Optional[Plane] = None diff --git a/src/specklepy/objects/structural/geometry.py b/src/specklepy/objects/structural/geometry.py index ce9e63d..70b2a64 100644 --- a/src/specklepy/objects/structural/geometry.py +++ b/src/specklepy/objects/structural/geometry.py @@ -1,10 +1,17 @@ from enum import Enum -from typing import List +from typing import List, Optional -from ..base import Base -from ..geometry import * -from .properties import * -from .axis import Axis +from specklepy.objects.base import Base +from specklepy.objects.geometry import Line, Mesh, Plane, Point, Vector +from specklepy.objects.structural.properties import ( + Property1D, + Property2D, + Property3D, + PropertyDamper, + PropertyMass, + PropertySpring, +) +from specklepy.objects.structural.axis import Axis STRUCTURAL_GEOMETRY = "Objects.Structural.Geometry" @@ -41,68 +48,68 @@ class ElementType3D(int, Enum): class Restraint(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Restraint"): - code: str = None + code: Optional[str] = None stiffnessX: float = 0.0 stiffnessY: float = 0.0 stiffnessZ: float = 0.0 stiffnessXX: float = 0.0 stiffnessYY: float = 0.0 stiffnessZZ: float = 0.0 - units: str = None + units: Optional[str] = None class Node(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Node"): - name: str = None - basePoint: Point = None - constraintAxis: Axis = None - restraint: Restraint = None - springProperty: PropertySpring = None - massProperty: PropertyMass = None - damperProperty: PropertyDamper = None - units: str = None + name: Optional[str] = None + basePoint: Optional[Point] = None + constraintAxis: Optional[Axis] = None + restraint: Optional[Restraint] = None + springProperty: Optional[PropertySpring] = None + massProperty: Optional[PropertyMass] = None + damperProperty: Optional[PropertyDamper] = None + units: Optional[str] = None class Element1D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element1D"): - name: str = None - baseLine: Line = None - property: Property1D = None - type: ElementType1D = None - end1Releases: Restraint = None - end2Releases: Restraint = None - end1Offset: Vector = None - end2Offset: Vector = None - orientationNode: Node = None + name: Optional[str] = None + baseLine: Optional[Line] = None + property: Optional[Property1D] = None + type: Optional[ElementType1D] = None + end1Releases: Optional[Restraint] = None + end2Releases: Optional[Restraint] = None + end1Offset: Optional[Vector] = None + end2Offset: Optional[Vector] = None + orientationNode: Optional[Node] = None orinetationAngle: float = 0.0 - localAxis: Plane = None - parent: Base = None - end1Node: Node = Node - end2Node: Node = Node - topology: List = None - displayMesh: Mesh = None - units: str = None + localAxis: Optional[Plane] = None + parent: Optional[Base] = None + end1Node: Optional[Node] = None + end2Node: Optional[Node] = None + topology: Optional[List] = None + displayMesh: Optional[Mesh] = None + units: Optional[str] = None class Element2D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element2D"): - name: str = None - property: Property2D = None - type: ElementType2D = None + name: Optional[str] = None + property: Optional[Property2D] = None + type: Optional[ElementType2D] = None offset: float = 0.0 orientationAngle: float = 0.0 - parent: Base = None - topology: List = None - displayMesh: Mesh = None - units: str = None + parent: Optional[Base] = None + topology: Optional[List] = None + displayMesh: Optional[Mesh] = None + units: Optional[str] = None class Element3D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element3D"): - name: str = None - baseMesh: Mesh = None - property: Property3D = None - type: ElementType3D = None + name: Optional[str] = None + baseMesh: Optional[Mesh] = None + property: Optional[Property3D] = None + type: Optional[ElementType3D] = None orientationAngle: float = 0.0 - parent: Base = None + parent: Optional[Base] = None topology: List - units: str = None + units: Optional[str] = None # class Storey needs ependency on built elements first diff --git a/src/specklepy/objects/structural/loading.py b/src/specklepy/objects/structural/loading.py index dc5ff9d..bba7e81 100644 --- a/src/specklepy/objects/structural/loading.py +++ b/src/specklepy/objects/structural/loading.py @@ -1,8 +1,9 @@ from enum import Enum -from typing import List +from typing import List, Optional -from ..base import Base -from .geometry import * +from specklepy.objects.base import Base +from specklepy.objects.geometry import Vector +from specklepy.objects.structural.axis import Axis STRUCTURAL_LOADING = "Objects.Structural.Loading." @@ -89,56 +90,56 @@ class CombinationType(int, Enum): class LoadCase(Base, speckle_type=STRUCTURAL_LOADING + "LoadCase"): - name: str = None - loadType: LoadType = None - group: str = None - actionType: ActionType = None - description: str = None + name: Optional[str] = None + loadType: Optional[LoadType] = None + group: Optional[str] = None + actionType: Optional[ActionType] = None + description: Optional[str] = None class Load(Base, speckle_type=STRUCTURAL_LOADING + "Load"): - name: str = None - units: str = None - loadCase: LoadCase = None + name: Optional[str] = None + units: Optional[str] = None + loadCase: Optional[LoadCase] = None class LoadBeam(Load, speckle_type=STRUCTURAL_LOADING + "LoadBeam"): - elements: List = None - loadType: BeamLoadType = None - direction: LoadDirection = None - loadAxis: Axis = None - loadAxisType: LoadAxisType = None - isProjected: bool = None - values: List = None - positions: List = None + elements: Optional[List] = None + loadType: Optional[BeamLoadType] = None + direction: Optional[LoadDirection] = None + loadAxis: Optional[Axis] = None + loadAxisType: Optional[LoadAxisType] = None + isProjected: Optional[bool] = None + values: Optional[List] = None + positions: Optional[List] = None class LoadCombinations(Base, speckle_type=STRUCTURAL_LOADING + "LoadCombination"): - name: str = None + name: Optional[str] = None loadCases: List loadFactors: List combinationType: CombinationType class LoadFace(Load, speckle_type=STRUCTURAL_LOADING + "LoadFace"): - elements: List = None - loadType: FaceLoadType = None - direction: LoadDirection2D = None - loadAxis: Axis = None - loadAxisType: LoadAxisType = None - isProjected: bool = None - values: List = None - positions: List = None + elements: Optional[List] = None + loadType: Optional[FaceLoadType] = None + direction: Optional[LoadDirection2D] = None + loadAxis: Optional[Axis] = None + loadAxisType: Optional[LoadAxisType] = None + isProjected: Optional[bool] = None + values: Optional[List] = None + positions: Optional[List] = None class LoadGravity(Load, speckle_type=STRUCTURAL_LOADING + "LoadGravity"): - elements: List = None - nodes: List = None - gravityFactors: Vector = None + elements: Optional[List] = None + nodes: Optional[List] = None + gravityFactors: Optional[Vector] = None class LoadNode(Load, speckle_type=STRUCTURAL_LOADING + "LoadNode"): - nodes: List = None - loadAxis: Axis = None - direction: LoadDirection = None + nodes: Optional[List] = None + loadAxis: Optional[Axis] = None + direction: Optional[LoadDirection] = None value: float = 0.0 diff --git a/src/specklepy/objects/structural/properties.py b/src/specklepy/objects/structural/properties.py index de9e402..4eab229 100644 --- a/src/specklepy/objects/structural/properties.py +++ b/src/specklepy/objects/structural/properties.py @@ -59,7 +59,7 @@ class PropertyType3D(int, Enum): class ShapeType(int, Enum): Rectangular = 0 Circular = 1 - I = 2 + I = 2 # noqa: E741 Tee = 3 Angle = 4 Channel = 5 diff --git a/src/specklepy/objects/structural/results.py b/src/specklepy/objects/structural/results.py index 49e2c99..293211e 100644 --- a/src/specklepy/objects/structural/results.py +++ b/src/specklepy/objects/structural/results.py @@ -1,18 +1,16 @@ -from typing import List +from typing import List, Optional -from ..base import Base -from ..geometry import * -from .loading import * -from .geometry import * -from .analysis import Model +from specklepy.objects.base import Base +from specklepy.objects.structural.analysis import Model +from specklepy.objects.structural.geometry import Element1D, Element2D, Element3D, Node STRUCTURAL_RESULTS = "Objects.Structural.Results." class Result(Base, speckle_type=STRUCTURAL_RESULTS + "Result"): - resultCase: Base = None - permutation: str = None - description: str = None + resultCase: Optional[Base] = None + permutation: Optional[str] = None + description: Optional[str] = None class ResultSet1D(Result, speckle_type=STRUCTURAL_RESULTS + "ResultSet1D"): @@ -20,7 +18,7 @@ class ResultSet1D(Result, speckle_type=STRUCTURAL_RESULTS + "ResultSet1D"): class Result1D(Result, speckle_type=STRUCTURAL_RESULTS + "Result1D"): - element: Element1D = None + element: Optional[Element1D] = None position: float = 0.0 dispX: float = 0.0 dispY: float = 0.0 @@ -50,7 +48,7 @@ class ResultSet2D(Result, speckle_type=STRUCTURAL_RESULTS + "ResultSet2D"): class Result2D(Result, speckle_type=STRUCTURAL_RESULTS + "Result2D"): - element: Element2D = None + element: Optional[Element2D] = None position: List dispX: float = 0.0 dispY: float = 0.0 @@ -88,7 +86,7 @@ class ResultSet3D(Result, speckle_type=STRUCTURAL_RESULTS + "ResultSet3D"): class Result3D(Result, speckle_type=STRUCTURAL_RESULTS + "Result3D"): - element: Element3D = None + element: Optional[Element3D] = None position: List dispX: float = 0.0 dispY: float = 0.0 @@ -102,7 +100,7 @@ class Result3D(Result, speckle_type=STRUCTURAL_RESULTS + "Result3D"): class ResultGlobal(Result, speckle_type=STRUCTURAL_RESULTS + "ResultGlobal"): - model: Model = None + model: Optional[Model] = None loadX: float = 0.0 loadY: float = 0.0 loadZ: float = 0.0 @@ -133,7 +131,7 @@ class ResultSetNode(Result, speckle_type=STRUCTURAL_RESULTS + "ResultSetNode"): class ResultNode(Result, speckle_type=STRUCTURAL_RESULTS + " ResultNode"): - node: Node = None + node: Optional[Node] = None dispX: float = 0.0 dispY: float = 0.0 dispZ: float = 0.0 @@ -167,8 +165,9 @@ class ResultNode(Result, speckle_type=STRUCTURAL_RESULTS + " ResultNode"): class ResultSetAll(Base, speckle_type=None): - resultSet1D: ResultSet1D = None - resultSet2D: ResultSet2D = None - resultSet3D: ResultSet3D = None - resultsGlobal: ResultGlobal = None - resultsNode: ResultSetNode = None + resultSet1D: Optional[ResultSet1D] = None + resultSet2D: Optional[ResultSet2D] = None + resultSet3D: Optional[ResultSet3D] = None + resultsGlobal: Optional[ResultGlobal] = None + resultsNode: Optional[ResultSetNode] = None + diff --git a/src/specklepy/objects/units.py b/src/specklepy/objects/units.py index 47276b5..f1036c4 100644 --- a/src/specklepy/objects/units.py +++ b/src/specklepy/objects/units.py @@ -3,6 +3,14 @@ from specklepy.logging.exceptions import SpeckleException, SpeckleInvalidUnitExc from enum import Enum +__all__ = [ + "Units", + "get_encoding_from_units", + "get_units_from_encoding", + "get_units_from_string", +] + + class Units(Enum): mm = "mm" cm = "cm" From e805b8ac6e36553ef68ec20d41004d6b727de3b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 9 Dec 2022 20:48:02 +0100 Subject: [PATCH 05/13] style(all): sort imports with isort --- example/many_children.py | 15 +++--- example/stream_objects.py | 7 +-- example/using_speckle_base.py | 5 +- pyproject.toml | 3 ++ src/specklepy/api/client.py | 38 +++++++------- src/specklepy/api/credentials.py | 12 +++-- src/specklepy/api/host_applications.py | 2 +- src/specklepy/api/models.py | 1 - src/specklepy/api/operations.py | 7 +-- src/specklepy/api/resource.py | 8 +-- src/specklepy/api/resources/__init__.py | 3 +- src/specklepy/api/resources/active_user.py | 9 ++-- src/specklepy/api/resources/branch.py | 3 +- src/specklepy/api/resources/commit.py | 11 ++-- src/specklepy/api/resources/object.py | 2 + src/specklepy/api/resources/other_user.py | 11 ++-- src/specklepy/api/resources/server.py | 3 +- src/specklepy/api/resources/stream.py | 7 +-- src/specklepy/api/resources/subscriptions.py | 4 +- src/specklepy/api/resources/user.py | 11 ++-- src/specklepy/api/wrapper.py | 7 +-- src/specklepy/logging/metrics.py | 18 +++---- src/specklepy/objects/__init__.py | 2 +- src/specklepy/objects/base.py | 15 +----- src/specklepy/objects/encoding.py | 2 +- src/specklepy/objects/fakemesh.py | 1 + src/specklepy/objects/other.py | 2 + src/specklepy/objects/structural/__init__.py | 50 +++++++++---------- src/specklepy/objects/structural/geometry.py | 2 +- src/specklepy/objects/structural/material.py | 1 - .../objects/structural/properties.py | 3 +- src/specklepy/objects/units.py | 4 +- src/specklepy/paths.py | 1 + .../serialization/base_object_serializer.py | 18 +++---- .../transports/abstract_transport.py | 3 +- src/specklepy/transports/memory.py | 3 +- .../transports/server/batch_sender.py | 5 +- src/specklepy/transports/server/server.py | 4 +- src/specklepy/transports/sqlite.py | 5 +- tests/conftest.py | 12 +++-- tests/test_active_user.py | 1 + tests/test_base.py | 3 +- tests/test_branch.py | 3 +- tests/test_client_and_ops.py | 5 +- tests/test_commit.py | 1 + tests/test_geometry.py | 3 +- tests/test_host_applications.py | 3 +- tests/test_objects.py | 1 + tests/test_other_user.py | 1 + tests/test_registering_base.py | 2 + tests/test_serialization.py | 10 ++-- tests/test_server.py | 3 +- tests/test_stream.py | 8 +-- tests/test_structural.py | 23 +++------ tests/test_transforms.py | 8 +-- tests/test_user.py | 1 + tests/test_wrapper.py | 8 +-- 57 files changed, 214 insertions(+), 190 deletions(-) diff --git a/example/many_children.py b/example/many_children.py index d4eac7c..64a1554 100644 --- a/example/many_children.py +++ b/example/many_children.py @@ -1,12 +1,13 @@ -from typing import List -from specklepy.objects import Base -from specklepy.api import operations -from specklepy.transports.sqlite import SQLiteTransport +import os +import random +import string import time from pathlib import Path -import os -import string -import random +from typing import List + +from specklepy.api import operations +from specklepy.objects import Base +from specklepy.transports.sqlite import SQLiteTransport class Sub(Base): diff --git a/example/stream_objects.py b/example/stream_objects.py index 6fd0375..cc4ecb8 100644 --- a/example/stream_objects.py +++ b/example/stream_objects.py @@ -1,9 +1,10 @@ +import random +import string from typing import List + +from specklepy.api import operations from specklepy.api.wrapper import StreamWrapper from specklepy.objects import Base -from specklepy.api import operations -import string -import random class Sub(Base): diff --git a/example/using_speckle_base.py b/example/using_speckle_base.py index a8e73d9..753fbed 100644 --- a/example/using_speckle_base.py +++ b/example/using_speckle_base.py @@ -1,10 +1,11 @@ """This is an example showcasing the usage of speckle `Base` class.""" # the speckle.objects module exposes all speckle provided classes -from specklepy.objects import Base -from specklepy.api import operations from devtools import debug +from specklepy.api import operations +from specklepy.objects import Base + class ExampleSub(Base): """ diff --git a/pyproject.toml b/pyproject.toml index 1689895..7545297 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,3 +54,6 @@ target-version = ["py37", "py38", "py39", "py310"] [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" + +[tool.isort] +profile = "black" \ No newline at end of file diff --git a/src/specklepy/api/client.py b/src/specklepy/api/client.py index e81502a..d1b78ee 100644 --- a/src/specklepy/api/client.py +++ b/src/specklepy/api/client.py @@ -1,30 +1,28 @@ import re -from warnings import warn -from deprecated import deprecated -from specklepy.api.credentials import Account, get_account_from_token -from specklepy.logging import metrics -from specklepy.logging.exceptions import ( - SpeckleException, - SpeckleWarning, -) from typing import Dict +from warnings import warn -from specklepy.api import resources -from specklepy.api.resources import ( - branch, - commit, - stream, - object, - server, - user, - subscriptions, - other_user, - active_user -) +from deprecated import deprecated from gql import Client from gql.transport.requests import RequestsHTTPTransport from gql.transport.websockets import WebsocketsTransport +from specklepy.api import resources +from specklepy.api.credentials import Account, get_account_from_token +from specklepy.api.resources import ( + active_user, + branch, + commit, + object, + other_user, + server, + stream, + subscriptions, + user, +) +from specklepy.logging import metrics +from specklepy.logging.exceptions import SpeckleException, SpeckleWarning + class SpeckleClient: """ diff --git a/src/specklepy/api/credentials.py b/src/specklepy/api/credentials.py index 2a8ca87..d68a9a5 100644 --- a/src/specklepy/api/credentials.py +++ b/src/specklepy/api/credentials.py @@ -1,11 +1,13 @@ import os -from pydantic import BaseModel, Field # pylint: disable=no-name-in-module from typing import List, Optional -from specklepy.logging import metrics -from specklepy.api.models import ServerInfo -from specklepy.transports.sqlite import SQLiteTransport -from specklepy.logging.exceptions import SpeckleException + +from pydantic import BaseModel, Field # pylint: disable=no-name-in-module + from specklepy import paths +from specklepy.api.models import ServerInfo +from specklepy.logging import metrics +from specklepy.logging.exceptions import SpeckleException +from specklepy.transports.sqlite import SQLiteTransport class UserInfo(BaseModel): diff --git a/src/specklepy/api/host_applications.py b/src/specklepy/api/host_applications.py index 8851256..0a36283 100644 --- a/src/specklepy/api/host_applications.py +++ b/src/specklepy/api/host_applications.py @@ -1,5 +1,5 @@ -from enum import Enum from dataclasses import dataclass +from enum import Enum from unicodedata import name diff --git a/src/specklepy/api/models.py b/src/specklepy/api/models.py index 3f92b56..a5cc414 100644 --- a/src/specklepy/api/models.py +++ b/src/specklepy/api/models.py @@ -1,7 +1,6 @@ from datetime import datetime from typing import List, Optional - from pydantic import BaseModel, Field diff --git a/src/specklepy/api/operations.py b/src/specklepy/api/operations.py index cb778ca..722cd40 100644 --- a/src/specklepy/api/operations.py +++ b/src/specklepy/api/operations.py @@ -1,10 +1,11 @@ from typing import List, Optional + from specklepy.logging import metrics -from specklepy.objects.base import Base -from specklepy.transports.sqlite import SQLiteTransport from specklepy.logging.exceptions import SpeckleException -from specklepy.transports.abstract_transport import AbstractTransport +from specklepy.objects.base import Base from specklepy.serialization.base_object_serializer import BaseObjectSerializer +from specklepy.transports.abstract_transport import AbstractTransport +from specklepy.transports.sqlite import SQLiteTransport def send( diff --git a/src/specklepy/api/resource.py b/src/specklepy/api/resource.py index 83af7e6..fd1519b 100644 --- a/src/specklepy/api/resource.py +++ b/src/specklepy/api/resource.py @@ -1,15 +1,17 @@ -from graphql import DocumentNode -from specklepy.api.credentials import Account -from specklepy.transports.sqlite import SQLiteTransport from typing import Any, Dict, List, Optional, Tuple, Type, Union + from gql.client import Client from gql.transport.exceptions import TransportQueryError +from graphql import DocumentNode + +from specklepy.api.credentials import Account from specklepy.logging.exceptions import ( GraphQLException, SpeckleException, UnsupportedException, ) from specklepy.serialization.base_object_serializer import BaseObjectSerializer +from specklepy.transports.sqlite import SQLiteTransport class ResourceBase(object): diff --git a/src/specklepy/api/resources/__init__.py b/src/specklepy/api/resources/__init__.py index ad56df9..42512fa 100644 --- a/src/specklepy/api/resources/__init__.py +++ b/src/specklepy/api/resources/__init__.py @@ -1,8 +1,7 @@ -import sys import pkgutil +import sys from importlib import import_module - for (_, name, _) in pkgutil.iter_modules(__path__): imported_module = import_module("." + name, package=__name__) diff --git a/src/specklepy/api/resources/active_user.py b/src/specklepy/api/resources/active_user.py index 0eb017f..46fb6b7 100644 --- a/src/specklepy/api/resources/active_user.py +++ b/src/specklepy/api/resources/active_user.py @@ -1,11 +1,12 @@ -from typing import List, Optional from datetime import datetime, timezone +from typing import List, Optional + from gql import gql + +from specklepy.api.models import ActivityCollection, PendingStreamCollaborator, User +from specklepy.api.resource import ResourceBase from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException -from specklepy.api.resource import ResourceBase -from specklepy.api.models import ActivityCollection, PendingStreamCollaborator, User - NAME = "active_user" diff --git a/src/specklepy/api/resources/branch.py b/src/specklepy/api/resources/branch.py index dccb7cd..5e8aa10 100644 --- a/src/specklepy/api/resources/branch.py +++ b/src/specklepy/api/resources/branch.py @@ -1,6 +1,7 @@ from gql import gql -from specklepy.api.resource import ResourceBase + from specklepy.api.models import Branch +from specklepy.api.resource import ResourceBase from specklepy.logging import metrics NAME = "branch" diff --git a/src/specklepy/api/resources/commit.py b/src/specklepy/api/resources/commit.py index 7312de4..b3eed8f 100644 --- a/src/specklepy/api/resources/commit.py +++ b/src/specklepy/api/resources/commit.py @@ -1,9 +1,10 @@ -from typing import Optional, List -from gql import gql -from specklepy.api.resource import ResourceBase -from specklepy.api.models import Commit -from specklepy.logging import metrics +from typing import List, Optional +from gql import gql + +from specklepy.api.models import Commit +from specklepy.api.resource import ResourceBase +from specklepy.logging import metrics NAME = "commit" diff --git a/src/specklepy/api/resources/object.py b/src/specklepy/api/resources/object.py index 36c0675..dd80238 100644 --- a/src/specklepy/api/resources/object.py +++ b/src/specklepy/api/resources/object.py @@ -1,5 +1,7 @@ from typing import Dict, List + from gql import gql + from specklepy.api.resource import ResourceBase from specklepy.objects.base import Base diff --git a/src/specklepy/api/resources/other_user.py b/src/specklepy/api/resources/other_user.py index 7d5f313..8496c79 100644 --- a/src/specklepy/api/resources/other_user.py +++ b/src/specklepy/api/resources/other_user.py @@ -1,13 +1,12 @@ -from typing import List, Optional, Union from datetime import datetime, timezone +from typing import List, Optional, Union + from gql import gql + +from specklepy.api.models import ActivityCollection, LimitedUser +from specklepy.api.resource import ResourceBase from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException -from specklepy.api.resource import ResourceBase -from specklepy.api.models import ( - ActivityCollection, - LimitedUser, -) NAME = "other_user" diff --git a/src/specklepy/api/resources/server.py b/src/specklepy/api/resources/server.py index c8b42e0..c2d4163 100644 --- a/src/specklepy/api/resources/server.py +++ b/src/specklepy/api/resources/server.py @@ -1,12 +1,13 @@ import re from typing import Any, Dict, List, Tuple + from gql import gql + from specklepy.api.models import ServerInfo from specklepy.api.resource import ResourceBase from specklepy.logging import metrics from specklepy.logging.exceptions import GraphQLException - NAME = "server" diff --git a/src/specklepy/api/resources/stream.py b/src/specklepy/api/resources/stream.py index 921a6ec..a1306cf 100644 --- a/src/specklepy/api/resources/stream.py +++ b/src/specklepy/api/resources/stream.py @@ -1,12 +1,13 @@ from datetime import datetime, timezone from typing import List, Optional + from deprecated import deprecated from gql import gql -from specklepy.logging import metrics + from specklepy.api.models import ActivityCollection, PendingStreamCollaborator, Stream from specklepy.api.resource import ResourceBase -from specklepy.logging.exceptions import UnsupportedException, SpeckleException - +from specklepy.logging import metrics +from specklepy.logging.exceptions import SpeckleException, UnsupportedException NAME = "stream" diff --git a/src/specklepy/api/resources/subscriptions.py b/src/specklepy/api/resources/subscriptions.py index db1fe94..8bdf021 100644 --- a/src/specklepy/api/resources/subscriptions.py +++ b/src/specklepy/api/resources/subscriptions.py @@ -1,7 +1,9 @@ -from typing import Callable, Dict, List, Union from functools import wraps +from typing import Callable, Dict, List, Union + from gql import gql from graphql import DocumentNode + from specklepy.api.resource import ResourceBase from specklepy.api.resources.stream import Stream from specklepy.logging.exceptions import SpeckleException diff --git a/src/specklepy/api/resources/user.py b/src/specklepy/api/resources/user.py index fd718e6..4e23417 100644 --- a/src/specklepy/api/resources/user.py +++ b/src/specklepy/api/resources/user.py @@ -1,12 +1,13 @@ -from typing import List, Optional, Union from datetime import datetime, timezone +from typing import List, Optional, Union + +from deprecated import deprecated from gql import gql + +from specklepy.api.models import ActivityCollection, PendingStreamCollaborator, User +from specklepy.api.resource import ResourceBase from specklepy.logging import metrics from specklepy.logging.exceptions import SpeckleException -from specklepy.api.resource import ResourceBase -from specklepy.api.models import ActivityCollection, PendingStreamCollaborator, User -from deprecated import deprecated - NAME = "user" diff --git a/src/specklepy/api/wrapper.py b/src/specklepy/api/wrapper.py index 558118e..d6e3b01 100644 --- a/src/specklepy/api/wrapper.py +++ b/src/specklepy/api/wrapper.py @@ -1,14 +1,15 @@ +from urllib.parse import unquote, urlparse from warnings import warn -from urllib.parse import urlparse, unquote + +from specklepy.api.client import SpeckleClient from specklepy.api.credentials import ( Account, get_account_from_token, get_local_accounts, ) from specklepy.logging import metrics -from specklepy.api.client import SpeckleClient -from specklepy.transports.server.server import ServerTransport from specklepy.logging.exceptions import SpeckleException, SpeckleWarning +from specklepy.transports.server.server import ServerTransport class StreamWrapper: diff --git a/src/specklepy/logging/metrics.py b/src/specklepy/logging/metrics.py index ee095e9..fc197aa 100644 --- a/src/specklepy/logging/metrics.py +++ b/src/specklepy/logging/metrics.py @@ -1,14 +1,14 @@ -import sys -import queue -import hashlib -import getpass -import logging -from typing import Optional -import requests -import threading -import platform import contextlib +import getpass +import hashlib +import logging +import platform +import queue +import sys +import threading +from typing import Optional +import requests """ Anonymous telemetry to help us understand how to make a better Speckle. diff --git a/src/specklepy/objects/__init__.py b/src/specklepy/objects/__init__.py index d10fb2f..d83b8b4 100644 --- a/src/specklepy/objects/__init__.py +++ b/src/specklepy/objects/__init__.py @@ -1,6 +1,6 @@ """Builtin Speckle object kit.""" +from specklepy.objects import encoding, geometry, other, structural, units from specklepy.objects.base import Base -from specklepy.objects import encoding, geometry, other, units, structural __all__ = ["Base", "encoding", "geometry", "other", "units", "structural"] diff --git a/src/specklepy/objects/base.py b/src/specklepy/objects/base.py index 9bf61d7..2ec8814 100644 --- a/src/specklepy/objects/base.py +++ b/src/specklepy/objects/base.py @@ -1,21 +1,10 @@ -from typing import ( - Any, - ClassVar, - Dict, - List, - Optional, - Union, - Set, - Type, - get_type_hints, -) - import contextlib from enum import EnumMeta +from typing import Any, ClassVar, Dict, List, Optional, Set, Type, Union, get_type_hints from warnings import warn from specklepy.logging.exceptions import SpeckleException -from specklepy.objects.units import get_units_from_string, Units +from specklepy.objects.units import Units, get_units_from_string from specklepy.transports.memory import MemoryTransport PRIMITIVES = (int, float, str, bool) diff --git a/src/specklepy/objects/encoding.py b/src/specklepy/objects/encoding.py index c6b6361..c65915d 100644 --- a/src/specklepy/objects/encoding.py +++ b/src/specklepy/objects/encoding.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import Any, Callable, List, Optional, Type, Dict +from typing import Any, Callable, Dict, List, Optional, Type from specklepy.logging.exceptions import SpeckleException from specklepy.objects.base import Base diff --git a/src/specklepy/objects/fakemesh.py b/src/specklepy/objects/fakemesh.py index c8ac5a7..413d4b1 100644 --- a/src/specklepy/objects/fakemesh.py +++ b/src/specklepy/objects/fakemesh.py @@ -1,5 +1,6 @@ from enum import Enum from typing import List, Optional + from specklepy.objects.geometry import Point from .base import Base diff --git a/src/specklepy/objects/other.py b/src/specklepy/objects/other.py index b184c3b..dab41a6 100644 --- a/src/specklepy/objects/other.py +++ b/src/specklepy/objects/other.py @@ -1,5 +1,7 @@ from typing import Any, List, Optional + from specklepy.objects.geometry import Point, Vector + from .base import Base OTHER = "Objects.Other." diff --git a/src/specklepy/objects/structural/__init__.py b/src/specklepy/objects/structural/__init__.py index 719819c..c7bdae9 100644 --- a/src/specklepy/objects/structural/__init__.py +++ b/src/specklepy/objects/structural/__init__.py @@ -8,73 +8,71 @@ from specklepy.objects.structural.analysis import ( ) from specklepy.objects.structural.axis import Axis from specklepy.objects.structural.geometry import ( + Element1D, + Element2D, + Element3D, ElementType1D, ElementType2D, ElementType3D, Node, Restraint, - Element1D, - Element2D, - Element3D, ) from specklepy.objects.structural.loading import ( - Load, - LoadType, ActionType, BeamLoadType, + CombinationType, FaceLoadType, + Load, + LoadAxisType, + LoadBeam, + LoadCase, + LoadCombinations, LoadDirection, LoadDirection2D, - LoadAxisType, - CombinationType, - LoadCase, - LoadBeam, - LoadCombinations, LoadFace, LoadGravity, LoadNode, + LoadType, ) from specklepy.objects.structural.material import ( - MaterialType, - StructuralMaterial, Concrete, + MaterialType, Steel, + StructuralMaterial, Timber, ) - from specklepy.objects.structural.properties import ( - MemberType, BaseReferencePoint, - ReferenceSurface, - PropertyType2D, - PropertyType3D, - ShapeType, - PropertyTypeSpring, - PropertyTypeDamper, + MemberType, Property, - SectionProfile, Property1D, Property2D, Property3D, PropertyDamper, PropertyMass, PropertySpring, + PropertyType2D, + PropertyType3D, + PropertyTypeDamper, + PropertyTypeSpring, + ReferenceSurface, ReferenceSurfaceEnum, + SectionProfile, + ShapeType, shapeType, ) - from specklepy.objects.structural.results import ( Result, Result1D, - ResultSet1D, Result2D, - ResultSet2D, Result3D, - ResultSet3D, ResultGlobal, - ResultSetNode, ResultNode, + ResultSet1D, + ResultSet2D, + ResultSet3D, ResultSetAll, + ResultSetNode, ) __all__ = [ diff --git a/src/specklepy/objects/structural/geometry.py b/src/specklepy/objects/structural/geometry.py index 70b2a64..1ff129d 100644 --- a/src/specklepy/objects/structural/geometry.py +++ b/src/specklepy/objects/structural/geometry.py @@ -3,6 +3,7 @@ from typing import List, Optional from specklepy.objects.base import Base from specklepy.objects.geometry import Line, Mesh, Plane, Point, Vector +from specklepy.objects.structural.axis import Axis from specklepy.objects.structural.properties import ( Property1D, Property2D, @@ -11,7 +12,6 @@ from specklepy.objects.structural.properties import ( PropertyMass, PropertySpring, ) -from specklepy.objects.structural.axis import Axis STRUCTURAL_GEOMETRY = "Objects.Structural.Geometry" diff --git a/src/specklepy/objects/structural/material.py b/src/specklepy/objects/structural/material.py index e7fc521..a18e8d1 100644 --- a/src/specklepy/objects/structural/material.py +++ b/src/specklepy/objects/structural/material.py @@ -3,7 +3,6 @@ from typing import Optional from specklepy.objects.base import Base - STRUCTURAL_MATERIALS = "Objects.Structural.Materials" diff --git a/src/specklepy/objects/structural/properties.py b/src/specklepy/objects/structural/properties.py index 4eab229..803bf65 100644 --- a/src/specklepy/objects/structural/properties.py +++ b/src/specklepy/objects/structural/properties.py @@ -2,9 +2,8 @@ from enum import Enum from typing import Optional from specklepy.objects.base import Base -from specklepy.objects.structural.material import StructuralMaterial from specklepy.objects.structural.axis import Axis - +from specklepy.objects.structural.material import StructuralMaterial STRUCTURAL_PROPERTY = "Objectives.Structural.Properties" diff --git a/src/specklepy/objects/units.py b/src/specklepy/objects/units.py index f1036c4..e89dbc7 100644 --- a/src/specklepy/objects/units.py +++ b/src/specklepy/objects/units.py @@ -1,7 +1,7 @@ -from typing import Union -from specklepy.logging.exceptions import SpeckleException, SpeckleInvalidUnitException from enum import Enum +from typing import Union +from specklepy.logging.exceptions import SpeckleException, SpeckleInvalidUnitException __all__ = [ "Units", diff --git a/src/specklepy/paths.py b/src/specklepy/paths.py index 24f736c..d32385b 100644 --- a/src/specklepy/paths.py +++ b/src/specklepy/paths.py @@ -1,5 +1,6 @@ import sys from pathlib import Path + from appdirs import user_data_dir diff --git a/src/specklepy/serialization/base_object_serializer.py b/src/specklepy/serialization/base_object_serializer.py index d11faba..7d4f154 100644 --- a/src/specklepy/serialization/base_object_serializer.py +++ b/src/specklepy/serialization/base_object_serializer.py @@ -1,21 +1,19 @@ -import re -import ujson import hashlib +import re import warnings -from uuid import uuid4 from enum import Enum -from warnings import warn from typing import Any, Dict, List, Tuple -from specklepy.objects.base import Base, DataChunk -from specklepy.logging.exceptions import ( - SpeckleException, - SpeckleWarning, -) -from specklepy.transports.abstract_transport import AbstractTransport +from uuid import uuid4 +from warnings import warn + +import ujson # import for serialization import specklepy.objects.geometry import specklepy.objects.other +from specklepy.logging.exceptions import SpeckleException, SpeckleWarning +from specklepy.objects.base import Base, DataChunk +from specklepy.transports.abstract_transport import AbstractTransport PRIMITIVES = (int, float, str, bool) diff --git a/src/specklepy/transports/abstract_transport.py b/src/specklepy/transports/abstract_transport.py index b0e2277..3235557 100644 --- a/src/specklepy/transports/abstract_transport.py +++ b/src/specklepy/transports/abstract_transport.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod -from typing import Optional, List, Dict +from typing import Dict, List, Optional + from pydantic import BaseModel from pydantic.config import Extra diff --git a/src/specklepy/transports/memory.py b/src/specklepy/transports/memory.py index 0f61bff..530dd5b 100644 --- a/src/specklepy/transports/memory.py +++ b/src/specklepy/transports/memory.py @@ -1,4 +1,5 @@ -from typing import Any, List, Dict +from typing import Any, Dict, List + from specklepy.transports.abstract_transport import AbstractTransport diff --git a/src/specklepy/transports/server/batch_sender.py b/src/specklepy/transports/server/batch_sender.py index f25aaf5..55c7f2a 100644 --- a/src/specklepy/transports/server/batch_sender.py +++ b/src/specklepy/transports/server/batch_sender.py @@ -1,10 +1,11 @@ +import gzip import json import logging -import threading import queue -import gzip +import threading import requests + from specklepy.logging.exceptions import SpeckleException LOG = logging.getLogger(__name__) diff --git a/src/specklepy/transports/server/server.py b/src/specklepy/transports/server/server.py index 56ac4a3..805799f 100644 --- a/src/specklepy/transports/server/server.py +++ b/src/specklepy/transports/server/server.py @@ -1,8 +1,8 @@ import json -import requests +from typing import Any, Dict, List from warnings import warn -from typing import Any, Dict, List +import requests from specklepy.api.client import SpeckleClient from specklepy.api.credentials import Account, get_account_from_token diff --git a/src/specklepy/transports/sqlite.py b/src/specklepy/transports/sqlite.py index b62da42..d79b526 100644 --- a/src/specklepy/transports/sqlite.py +++ b/src/specklepy/transports/sqlite.py @@ -1,10 +1,11 @@ import os import sqlite3 -from typing import Any, List, Dict, Optional, Tuple from contextlib import closing -from specklepy.transports.abstract_transport import AbstractTransport +from typing import Any, Dict, List, Optional, Tuple + from specklepy.logging.exceptions import SpeckleException from specklepy.paths import base_path +from specklepy.transports.abstract_transport import AbstractTransport class SQLiteTransport(AbstractTransport): diff --git a/tests/conftest.py b/tests/conftest.py index 3dbfe01..f0c3ba0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,13 +1,15 @@ -import uuid import random +import uuid + import pytest import requests -from specklepy.api.models import Stream + from specklepy.api.client import SpeckleClient -from specklepy.objects.base import Base -from specklepy.objects.geometry import Point -from specklepy.objects.fakemesh import FakeDirection, FakeMesh +from specklepy.api.models import Stream from specklepy.logging import metrics +from specklepy.objects.base import Base +from specklepy.objects.fakemesh import FakeDirection, FakeMesh +from specklepy.objects.geometry import Point metrics.disable() diff --git a/tests/test_active_user.py b/tests/test_active_user.py index b027025..8f3ff3f 100644 --- a/tests/test_active_user.py +++ b/tests/test_active_user.py @@ -1,4 +1,5 @@ import pytest + from specklepy.api.client import SpeckleClient from specklepy.api.models import Activity, ActivityCollection, User from specklepy.logging.exceptions import SpeckleException diff --git a/tests/test_base.py b/tests/test_base.py index b8360f7..5c27aa2 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,8 +1,9 @@ +from contextlib import ExitStack as does_not_raise from enum import Enum from typing import Dict, List, Optional, Union -from contextlib import ExitStack as does_not_raise import pytest + from specklepy.api import operations from specklepy.logging.exceptions import SpeckleException, SpeckleInvalidUnitException from specklepy.objects.base import Base diff --git a/tests/test_branch.py b/tests/test_branch.py index 46ddf36..27bf8ba 100644 --- a/tests/test_branch.py +++ b/tests/test_branch.py @@ -1,7 +1,8 @@ import pytest + from specklepy.api import operations -from specklepy.transports.server import ServerTransport from specklepy.api.models import Branch, Commit, Stream +from specklepy.transports.server import ServerTransport class TestBranch: diff --git a/tests/test_client_and_ops.py b/tests/test_client_and_ops.py index ed47a6f..a534a5d 100644 --- a/tests/test_client_and_ops.py +++ b/tests/test_client_and_ops.py @@ -1,10 +1,11 @@ import pytest + from specklepy.api import operations from specklepy.api.client import SpeckleClient -from specklepy.objects.base import Base -from specklepy.transports.server import ServerTransport from specklepy.api.credentials import Account, get_account_from_token from specklepy.logging.exceptions import SpeckleException, SpeckleWarning +from specklepy.objects.base import Base +from specklepy.transports.server import ServerTransport def test_invalid_authentication(): diff --git a/tests/test_commit.py b/tests/test_commit.py index 0443315..f9347e2 100644 --- a/tests/test_commit.py +++ b/tests/test_commit.py @@ -1,4 +1,5 @@ import pytest + from specklepy.api import operations from specklepy.api.models import Commit, Stream from specklepy.transports.server.server import ServerTransport diff --git a/tests/test_geometry.py b/tests/test_geometry.py index 8d14959..9c63cfd 100644 --- a/tests/test_geometry.py +++ b/tests/test_geometry.py @@ -2,10 +2,10 @@ import json import pytest + from specklepy.api import operations from specklepy.logging.exceptions import SpeckleException from specklepy.objects.base import Base -from specklepy.objects.units import Units from specklepy.objects.encoding import CurveArray, ObjectArray from specklepy.objects.geometry import ( Arc, @@ -30,6 +30,7 @@ from specklepy.objects.geometry import ( Surface, Vector, ) +from specklepy.objects.units import Units from specklepy.transports.memory import MemoryTransport diff --git a/tests/test_host_applications.py b/tests/test_host_applications.py index 0834c5b..de65bd3 100644 --- a/tests/test_host_applications.py +++ b/tests/test_host_applications.py @@ -1,7 +1,8 @@ import pytest + from specklepy.api.host_applications import ( - get_host_app_from_string, _app_name_host_app_mapping, + get_host_app_from_string, ) diff --git a/tests/test_objects.py b/tests/test_objects.py index 1018b71..f921ee6 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -1,4 +1,5 @@ import pytest + from specklepy.api.models import Stream from specklepy.objects import Base from specklepy.objects.encoding import ObjectArray diff --git a/tests/test_other_user.py b/tests/test_other_user.py index 92b0e83..bd17147 100644 --- a/tests/test_other_user.py +++ b/tests/test_other_user.py @@ -1,4 +1,5 @@ import pytest + from specklepy.api.client import SpeckleClient from specklepy.api.models import Activity, ActivityCollection, LimitedUser from specklepy.logging.exceptions import SpeckleException diff --git a/tests/test_registering_base.py b/tests/test_registering_base.py index 5f5a8b7..b3f3055 100644 --- a/tests/test_registering_base.py +++ b/tests/test_registering_base.py @@ -1,5 +1,7 @@ from typing import Type + import pytest + from specklepy.objects.base import Base from specklepy.objects.structural import Concrete diff --git a/tests/test_serialization.py b/tests/test_serialization.py index 5397b69..474bc70 100644 --- a/tests/test_serialization.py +++ b/tests/test_serialization.py @@ -1,12 +1,14 @@ import json + import pytest + from specklepy.api import operations -from specklepy.transports.server import ServerTransport -from specklepy.transports.memory import MemoryTransport -from specklepy.serialization.base_object_serializer import BaseObjectSerializer from specklepy.objects import Base -from specklepy.objects.geometry import Point from specklepy.objects.fakemesh import FakeMesh +from specklepy.objects.geometry import Point +from specklepy.serialization.base_object_serializer import BaseObjectSerializer +from specklepy.transports.memory import MemoryTransport +from specklepy.transports.server import ServerTransport @pytest.mark.run(order=5) diff --git a/tests/test_server.py b/tests/test_server.py index 5e0707c..884ef33 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -1,6 +1,7 @@ import pytest -from specklepy.api.models import ServerInfo + from specklepy.api.client import SpeckleClient +from specklepy.api.models import ServerInfo class TestServer: diff --git a/tests/test_stream.py b/tests/test_stream.py index 465072f..3111a6b 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -1,13 +1,15 @@ -import pytest from datetime import datetime + +import pytest + +from specklepy.api.client import SpeckleClient from specklepy.api.models import ( - ActivityCollection, Activity, + ActivityCollection, PendingStreamCollaborator, Stream, User, ) -from specklepy.api.client import SpeckleClient from specklepy.logging.exceptions import ( GraphQLException, SpeckleException, diff --git a/tests/test_structural.py b/tests/test_structural.py index b899d59..95ea1b0 100644 --- a/tests/test_structural.py +++ b/tests/test_structural.py @@ -1,31 +1,24 @@ import pytest -from specklepy.objects.geometry import ( - Line, - Mesh, - Point, - Vector, -) + +from specklepy.objects.geometry import Line, Mesh, Point, Vector +from specklepy.objects.structural.analysis import Model from specklepy.objects.structural.geometry import ( - Node, Element1D, Element2D, - Restraint, ElementType1D, ElementType2D, + Node, + Restraint, ) +from specklepy.objects.structural.loading import LoadGravity +from specklepy.objects.structural.material import StructuralMaterial from specklepy.objects.structural.properties import ( + MemberType, Property1D, Property2D, SectionProfile, - MemberType, ShapeType, ) -from specklepy.objects.structural.material import ( - StructuralMaterial, -) -from specklepy.objects.structural.analysis import Model - -from specklepy.objects.structural.loading import LoadGravity @pytest.fixture() diff --git a/tests/test_transforms.py b/tests/test_transforms.py index e276224..2e8c878 100644 --- a/tests/test_transforms.py +++ b/tests/test_transforms.py @@ -1,12 +1,14 @@ from typing import List + import pytest + from specklepy.api import operations from specklepy.objects.geometry import Point, Vector from specklepy.objects.other import ( - Transform, - BlockInstance, - BlockDefinition, IDENTITY_TRANSFORM, + BlockDefinition, + BlockInstance, + Transform, ) diff --git a/tests/test_user.py b/tests/test_user.py index 98a8430..7128309 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -1,4 +1,5 @@ import pytest + from specklepy.api.client import SpeckleClient from specklepy.api.models import Activity, ActivityCollection, User from specklepy.logging.exceptions import SpeckleException diff --git a/tests/test_wrapper.py b/tests/test_wrapper.py index a818f3c..5099110 100644 --- a/tests/test_wrapper.py +++ b/tests/test_wrapper.py @@ -1,10 +1,12 @@ import json -from specklepy.api.wrapper import StreamWrapper -from specklepy.transports.sqlite import SQLiteTransport -from specklepy.paths import accounts_path from pathlib import Path + import pytest +from specklepy.api.wrapper import StreamWrapper +from specklepy.paths import accounts_path +from specklepy.transports.sqlite import SQLiteTransport + def test_parse_stream(): wrap = StreamWrapper("https://testing.speckle.dev/streams/a75ab4f10f") From 9a2061d9004992590840e40a8d351abd443fb9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 16 Dec 2022 13:40:43 +0100 Subject: [PATCH 06/13] add missing object definitions from core --- src/specklepy/objects/__init__.py | 4 +- src/specklepy/objects/encoding.py | 2 +- src/specklepy/objects/geometry.py | 93 +++++++++++++++++++++++------- src/specklepy/objects/other.py | 35 +++++++++++ src/specklepy/objects/primitive.py | 24 ++++++++ 5 files changed, 133 insertions(+), 25 deletions(-) create mode 100644 src/specklepy/objects/primitive.py diff --git a/src/specklepy/objects/__init__.py b/src/specklepy/objects/__init__.py index d83b8b4..6b78337 100644 --- a/src/specklepy/objects/__init__.py +++ b/src/specklepy/objects/__init__.py @@ -1,6 +1,6 @@ """Builtin Speckle object kit.""" -from specklepy.objects import encoding, geometry, other, structural, units +from specklepy.objects import encoding, geometry, other, structural, units, primitive from specklepy.objects.base import Base -__all__ = ["Base", "encoding", "geometry", "other", "units", "structural"] +__all__ = ["Base", "encoding", "geometry", "other", "units", "structural", "primitive"] diff --git a/src/specklepy/objects/encoding.py b/src/specklepy/objects/encoding.py index c65915d..eab2d87 100644 --- a/src/specklepy/objects/encoding.py +++ b/src/specklepy/objects/encoding.py @@ -68,7 +68,7 @@ class ObjectArray: def decode_data( data: List[Any], decoder: Callable[[List[Any]], Base], **kwargs: Dict[str, Any] ) -> List[Base]: - bases = [] + bases: List[Base] = [] if not data: return bases index = 0 diff --git a/src/specklepy/objects/geometry.py b/src/specklepy/objects/geometry.py index 7bf000b..2724705 100644 --- a/src/specklepy/objects/geometry.py +++ b/src/specklepy/objects/geometry.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import Enum, IntEnum, auto from typing import Any, List, Optional from specklepy.objects.base import Base @@ -8,21 +8,6 @@ from specklepy.objects.units import get_encoding_from_units, get_units_from_enco GEOMETRY = "Objects.Geometry." -class Interval(Base, speckle_type="Objects.Primitive.Interval"): - start: float = 0.0 - end: float = 0.0 - - def length(self): - return abs(self.start - self.end) - - @classmethod - def from_list(cls, args: List[Any]) -> "Interval": - return cls(start=args[0], end=args[1]) - - def to_list(self) -> List[Any]: - return [self.start, self.end] - - class Point(Base, speckle_type=GEOMETRY + "Point"): x: float = 0.0 y: float = 0.0 @@ -47,8 +32,43 @@ class Point(Base, speckle_type=GEOMETRY + "Point"): return pt -class Vector(Point, speckle_type=GEOMETRY + "Vector"): - pass +class Pointcloud(Base, speckle_type=GEOMETRY + "Pointcloud"): + points: Optional[List[float]] = None + colors: Optional[List[int]] = None + sizes: Optional[List[float]] = None + bbox: Optional["Box"] = None + + +class Vector(Base, speckle_type=GEOMETRY + "Vector"): + x: float = 0.0 + y: float = 0.0 + z: float = 0.0 + applicationId: Optional[str] = None + units: Optional[str] = None + + def __repr__(self) -> str: + return ( + f"{self.__class__.__name__} " + "(x: {self.x}, y: {self.y}, z: {self.z}, id: {self.id}, " + "speckle_type: {self.speckle_type})" + ) + + @classmethod + def from_list(cls, args: List[float]) -> "Vector": + """ + Create from a list of three floats representing the x, y, and z coordinates. + """ + return cls(x=args[0], y=args[1], z=args[2]) + + def to_list(self) -> List[float]: + return [self.x, self.y, self.z] + + @classmethod + def from_coords(cls, x: float = 0.0, y: float = 0.0, z: float = 0.0) -> "Vector": + """Create a new Point from x, y, and z values""" + v = Vector() + v.x, v.y, v.z = x, y, z + return v class ControlPoint(Point, speckle_type=GEOMETRY + "ControlPoint"): @@ -83,9 +103,9 @@ class Plane(Base, speckle_type=GEOMETRY + "Plane"): class Box(Base, speckle_type=GEOMETRY + "Box"): basePlane: Plane = Plane() + xSize: Interval = Interval() ySize: Interval = Interval() zSize: Interval = Interval() - xSize: Interval = Interval() area: Optional[float] = None volume: Optional[float] = None @@ -130,6 +150,7 @@ class Arc(Base, speckle_type=GEOMETRY + "Arc"): bbox: Optional[Box] = None area: Optional[float] = None length: Optional[float] = None + units: Optional[str] = None @classmethod def from_list(cls, args: List[Any]) -> "Arc": @@ -221,12 +242,12 @@ class Ellipse(Base, speckle_type=GEOMETRY + "Ellipse"): class Polyline(Base, speckle_type=GEOMETRY + "Polyline", chunkable={"value": 20000}): - value: List[float] = None + value: Optional[List[float]] = None closed: Optional[bool] = None domain: Optional[Interval] = None bbox: Optional[Box] = None - area: float = None - length: float = None + area: Optional[float] = None + length: Optional[float] = None @classmethod def from_points(cls, points: List[Point]): @@ -272,6 +293,34 @@ class Polyline(Base, speckle_type=GEOMETRY + "Polyline", chunkable={"value": 200 ] +class SpiralType(Enum): + Biquadratic = (0,) + BiquadraticParabola = (1,) + Bloss = (2,) + Clothoid = (3,) + Cosine = (4,) + Cubic = (5,) + CubicParabola = (6,) + Radioid = (7,) + Sinusoid = (8,) + Unknown = 9 + + +class Spiral(Base, speckle_type=GEOMETRY + "Spiral", detachable={"displayValue"}): + startPoint: Optional[Point] = None + endPoint: Optional[Point] + plane: Optional[Plane] + turns: Optional[int] + pitchAxis: Optional[Vector] = Vector() + pitch: float = 0 + spiralType: Optional[SpiralType] = None + displayValue: Optional[Polyline] = None + bbox: Optional[Box] = None + length: Optional[float] = None + domain: Optional[Interval] = None + units: Optional[str] = None + + class Curve( Base, speckle_type=GEOMETRY + "Curve", diff --git a/src/specklepy/objects/other.py b/src/specklepy/objects/other.py index dab41a6..bd035f0 100644 --- a/src/specklepy/objects/other.py +++ b/src/specklepy/objects/other.py @@ -26,6 +26,21 @@ IDENTITY_TRANSFORM = [ ] +class Material(Base, speckle_type=OTHER + "Material"): + """Generic class for materials containing generic parameters.""" + + name: Optional[str] = None + + +class RevitMaterial(Material, speckle_type="Objects.Other.Revit." + "RevitMaterial"): + materialCategory: Optional[str] = None + materialClass: Optional[str] = None + shininess: Optional[int] = None + smoothness: Optional[int] = None + transparency: Optional[int] = None + parameters: Optional[Base] = None + + class RenderMaterial(Base, speckle_type=OTHER + "RenderMaterial"): name: Optional[str] = None opacity: float = 1 @@ -35,6 +50,26 @@ class RenderMaterial(Base, speckle_type=OTHER + "RenderMaterial"): emissive: int = -16777216 # black arbg +class MaterialQuantity(Base, speckle_type=OTHER + "MaterialQuantity"): + material: Optional[Material] = None + volume: Optional[float] = None + area: Optional[float] = None + + +class DisplayStyle(Base, speckle_type=OTHER + "DisplayStyle"): + """ + Minimal display style class. + Developed primarily for display styles in Rhino and AutoCAD. + Rhino object attributes uses OpenNURBS definition for linetypes and lineweights. + """ + + name: Optional[str] = None + color: int = -2894893 # light gray arbg + linetype: Optional[str] = None + lineweight: float = 0 + units: Optional[str] = None + + class Transform( Base, speckle_type=OTHER + "Transform", diff --git a/src/specklepy/objects/primitive.py b/src/specklepy/objects/primitive.py new file mode 100644 index 0000000..cc8e47b --- /dev/null +++ b/src/specklepy/objects/primitive.py @@ -0,0 +1,24 @@ +from typing import Any, List +from specklepy.objects.base import Base + +NAMESPACE = "Objects.Primitive" + + +class Interval(Base, speckle_type=f"{NAMESPACE}.Interval"): + start: float = 0.0 + end: float = 0.0 + + def length(self): + return abs(self.start - self.end) + + @classmethod + def from_list(cls, args: List[Any]) -> "Interval": + return cls(start=args[0], end=args[1]) + + def to_list(self) -> List[Any]: + return [self.start, self.end] + + +class Interval2d(Base, speckle_type=f"{NAMESPACE}.Interval2d"): + u: Interval + v: Interval From 15636dbe621e6e139a7cb2b0513f2b78720bd960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 16 Dec 2022 13:41:07 +0100 Subject: [PATCH 07/13] rework type checking in base --- src/specklepy/objects/base.py | 160 +++++++++++++++++++++++++--------- tests/test_base.py | 1 + tests/test_type_validation.py | 77 ++++++++++++++++ 3 files changed, 196 insertions(+), 42 deletions(-) create mode 100644 tests/test_type_validation.py diff --git a/src/specklepy/objects/base.py b/src/specklepy/objects/base.py index 2ec8814..3e8426a 100644 --- a/src/specklepy/objects/base.py +++ b/src/specklepy/objects/base.py @@ -1,6 +1,18 @@ import contextlib -from enum import EnumMeta -from typing import Any, ClassVar, Dict, List, Optional, Set, Type, Union, get_type_hints +from enum import Enum +from inspect import isclass +from typing import ( + Any, + ClassVar, + Dict, + List, + Optional, + Set, + Tuple, + Type, + Union, + get_type_hints, +) from warnings import warn from specklepy.logging.exceptions import SpeckleException @@ -103,7 +115,7 @@ class _RegisteringBase: Copying that behavior is hard in python, where the concept of namespaces means something entirely different. - So we enabled a speckle_type override mechanism, that enables + So we enabled a speckle_type override mechanism, that enables """ base_name = "Base" if cls.__name__ == base_name: @@ -154,6 +166,99 @@ class _RegisteringBase: super().__init_subclass__(**kwargs) +# T = TypeVar("T") + +# how i wish the code below would be correct, but we're also parsing into floats +# and converting into strings if the original type is string, but the value isn't +# def _validate_type(t: type, value: T) -> Tuple[bool, T]: + + +def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]: + # this should be reworked. Its only ok to return null for Optionals... + # if t is None and value is None: + if value is None: + return True, value + + # after fixing the None t above, this should be + # if t is Any: + if t is None or t is Any: + return True, value + + if isclass(t) and issubclass(t, Enum): + if isinstance(value, t): + return True, value + if value in t._value2member_map_: + return True, t(value) + + if getattr(t, "__module__", None) == "typing": + origin = getattr(t, "__origin__") + # below is what in nicer for >= py38 + # origin = get_origin(t) + + # recursive validation for Unions on both types preferring the fist type + if origin is Union: + t_1, t_2 = t.__args__ # type: ignore + # below is what in nicer for >= py38 + # t_1, t_2 = get_args(t) + t_1_success, t_1_value = _validate_type(t_1, value) + if t_1_success: + return True, t_1_value + return _validate_type(t_2, value) + if origin is dict: + if not isinstance(value, dict): + return False, value + if value == {}: + return True, value + t_key, t_value = t.__args__ # type: ignore + # we're only checking the first item, but the for loop and return after + # evaluating the first item is the fastest way + for dict_key, dict_value in value.items(): + valid_key, _ = _validate_type(t_key, dict_key) + valid_value, _ = _validate_type(t_value, dict_value) + + if valid_key and valid_value: + return True, value + return False, value + if origin is list: + if not isinstance(value, list): + return False, value + if value == []: + return True, value + t_items = t.__args__[0] # type: ignore + first_item_valid, _ = _validate_type(t_items, value[0]) + if first_item_valid: + return True, value + return False, value + + if origin is tuple: + if not isinstance(value, tuple): + return False, value + args = t.__args__ # type: ignore + # we're not checking for empty tuple, cause tuple lengths must match + if len(args) != len(value): + return False, value + values = [] + for t_item, v_item in zip(args, value): + item_valid, item_value = _validate_type(t_item, v_item) + if not item_valid: + return False, value + values.append(item_value) + return True, tuple(values) + + if isinstance(value, t): + return True, value + + with contextlib.suppress(ValueError): + if t is float and value: + return True, float(value) + # TODO: dafuq, i had to add this not list check + # but it would also fail for objects and other complex values + if t is str and value and not isinstance(value, list): + return True, str(value) + + return False, value + + class Base(_RegisteringBase): id: Union[str, None] = None totalChildrenCount: Union[int, None] = None @@ -251,55 +356,27 @@ class Base(_RegisteringBase): "Invalid Name: Base member names cannot contain characters '.' or '/'", ) - def _type_check(self, name: str, value: Any): + def _type_check(self, name: str, value: Any) -> Any: """ Lightweight type checking of values before setting them - NOTE: Does not check subscripted types within generics as the performance hit of checking - each item within a given collection isn't worth it. Eg if you have a type Dict[str, float], + NOTE: Does not check subscripted types within generics as the performance hit + of checking each item within a given collection isn't worth it. + Eg if you have a type Dict[str, float], we will only check if the value you're trying to set is a dict. """ types = getattr(self, "_attr_types", {}) t = types.get(name, None) - if t is None or t is Any: - return value + valid, checked_value = _validate_type(t, value) - if value is None: - return None - - if isinstance(t, EnumMeta) and (value in t._value2member_map_): - return t(value) - - if t.__module__ == "typing": - origin = getattr(t, "__origin__") - t = ( - tuple(getattr(sub_t, "__origin__", sub_t) for sub_t in t.__args__) - if origin is Union - else origin - ) - - if not isinstance(t, (type, tuple)): - warn( - f"Unrecognised type '{t}' provided for attribute '{name}'. Type will not been validated." - ) - return value - if isinstance(value, t): - return value - - # to be friendly, we'll parse ints and strs into floats, but not the other way around - # (to avoid unexpected rounding) - if isinstance(t, tuple): - t = t[0] - - with contextlib.suppress(ValueError): - if t is float: - return float(value) - if t is str and value: - return str(value) + if valid: + return checked_value raise SpeckleException( - f"Cannot set '{self.__class__.__name__}.{name}': it expects type '{t.__name__}', but received type '{type(value).__name__}'" + f"Cannot set '{self.__class__.__name__}.{name}':" + f"it expects type '{t.__name__ if t else None}'," + f"but received type '{type(value).__name__}'" ) def add_chunkable_attrs(self, **kwargs: int) -> None: @@ -432,4 +509,3 @@ class DataChunk(Base, speckle_type="Speckle.Core.Models.DataChunk"): def __init__(self) -> None: super().__init__() self.data = [] - diff --git a/tests/test_base.py b/tests/test_base.py index 5c27aa2..fdd78a4 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -152,6 +152,7 @@ def test_type_checking() -> None: order.flavours = ["strawberry", "lychee", "peach", "pineapple"] assert order.price == 7.0 + assert order.dietary == DietaryRestrictions.VEGAN def test_cached_deserialization() -> None: diff --git a/tests/test_type_validation.py b/tests/test_type_validation.py new file mode 100644 index 0000000..3cef081 --- /dev/null +++ b/tests/test_type_validation.py @@ -0,0 +1,77 @@ +from enum import Enum, IntEnum +import pytest +from typing import Any, Dict, List, Optional, Tuple +from specklepy.objects.base import Base, _validate_type + +test_base = Base() + + +class FakeEnum(Enum): + foo = "foo" + bar = "bar" + + +class FakeIntEnum(IntEnum): + one = 1 + + +@pytest.mark.parametrize( + "input_type, value, is_valid, return_value", + [ + (str, 10, True, "10"), + (str, "foo_bar", True, "foo_bar"), + ( + str, + {"foo": "bar"}, + True, + "{'foo': 'bar'}", + ), + # why are we allowing this??? We're lying to our users and ourselves too. + (str, None, True, None), + (bool, None, True, None), + # any value is allowed for Any + (Any, "foo", True, "foo"), + (Any, test_base, True, test_base), + # any value is allowed for None as a type. Why is none as a type allowed? + (None, True, True, True), + (None, "True", True, "True"), + (None, {"foo": 1}, True, {"foo": 1}), + (FakeEnum, FakeEnum.bar, True, FakeEnum.bar), + (FakeEnum, FakeEnum.bar.value, True, FakeEnum.bar), + (FakeEnum, "baz", False, "baz"), + (FakeIntEnum, FakeIntEnum.one.value, True, FakeIntEnum.one), + (FakeIntEnum, FakeIntEnum.one, True, FakeIntEnum.one), + (FakeIntEnum, 2, False, 2), + (FakeIntEnum, 123., False, 123.), + (Base, test_base, True, test_base), + (Base, 123, False, 123), + (Optional[int], 1, True, 1), + (Optional[int], None, True, None), + (Optional[FakeEnum], None, True, None), + (Optional[FakeEnum], FakeEnum.bar, True, FakeEnum.bar), + (Optional[FakeEnum], FakeEnum.bar.value, True, FakeEnum.bar), + (Optional[FakeEnum], "baz", False, "baz"), + (Optional[Base], test_base, True, test_base), + (Optional[Base], None, True, None), + (List[int], [1, 2], True, [1, 2]), + (List[int], ["1", 2], False, ["1", 2]), + # same as the dict typing below... + (List[int], [None, 2], True, [None, 2]), + (List[Optional[int]], [None, 2], True, [None, 2]), + (Dict[str, int], {"foo": 1}, True, {"foo": 1}), + (Dict[str, Optional[int]], {"foo": None}, True, {"foo": None}), + # this case should be + # (Dict[int, Base], {1: None}, False, {1: None}), + # but type checking currently allows everything to be None + (Dict[int, Base], {1: None}, True, {1: None}), + (Dict[int, Base], {1: test_base}, True, {1: test_base}), + (Tuple[int, str, str], (1, "foo", "bar"), True, (1, "foo", "bar")), + # given our current rules, this is the reality. Its just sad... + (Tuple[str, str, str], (1, "foo", "bar"), True, ("1", "foo", "bar")), + (Tuple[str, Optional[str], str], (1, None, "bar"), True, ("1", None, "bar")), + ], +) +def test_validate_type( + input_type: type, value: Any, is_valid: bool, return_value: Any +) -> None: + assert (is_valid, return_value) == _validate_type(input_type, value) From 7a46176803771f6f0a4623c858d50ce5f27be35c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 16 Dec 2022 21:17:39 +0100 Subject: [PATCH 08/13] additional test cases for type validation --- src/specklepy/objects/base.py | 3 +++ tests/test_type_validation.py | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/specklepy/objects/base.py b/src/specklepy/objects/base.py index 3e8426a..64de464 100644 --- a/src/specklepy/objects/base.py +++ b/src/specklepy/objects/base.py @@ -181,6 +181,8 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]: # after fixing the None t above, this should be # if t is Any: + # if t is None: + if t is None or t is Any: return True, value @@ -219,6 +221,7 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]: if valid_key and valid_value: return True, value return False, value + if origin is list: if not isinstance(value, list): return False, value diff --git a/tests/test_type_validation.py b/tests/test_type_validation.py index 3cef081..cdec888 100644 --- a/tests/test_type_validation.py +++ b/tests/test_type_validation.py @@ -42,10 +42,12 @@ class FakeIntEnum(IntEnum): (FakeIntEnum, FakeIntEnum.one.value, True, FakeIntEnum.one), (FakeIntEnum, FakeIntEnum.one, True, FakeIntEnum.one), (FakeIntEnum, 2, False, 2), - (FakeIntEnum, 123., False, 123.), + (FakeIntEnum, 123.0, False, 123.0), (Base, test_base, True, test_base), (Base, 123, False, 123), (Optional[int], 1, True, 1), + # this is just silly... + (Optional[int], [1, 2, 3], True, [1, 2, 3]), (Optional[int], None, True, None), (Optional[FakeEnum], None, True, None), (Optional[FakeEnum], FakeEnum.bar, True, FakeEnum.bar), From 07a3213ee92971f09d58a559749e8eb297255650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 16 Dec 2022 21:21:13 +0100 Subject: [PATCH 09/13] fix objects import --- src/specklepy/objects/geometry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/specklepy/objects/geometry.py b/src/specklepy/objects/geometry.py index 2724705..ab764a0 100644 --- a/src/specklepy/objects/geometry.py +++ b/src/specklepy/objects/geometry.py @@ -3,6 +3,7 @@ from typing import Any, List, Optional from specklepy.objects.base import Base from specklepy.objects.encoding import CurveArray, CurveTypeEncoding, ObjectArray +from specklepy.objects.primitive import Interval from specklepy.objects.units import get_encoding_from_units, get_units_from_encoding GEOMETRY = "Objects.Geometry." From 08aaa41b6cbf2341a59db2aa85b84821a5fd27c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 16 Dec 2022 21:45:04 +0100 Subject: [PATCH 10/13] fix units --- src/specklepy/objects/base.py | 2 +- src/specklepy/objects/geometry.py | 3 --- src/specklepy/objects/other.py | 1 - src/specklepy/objects/structural/geometry.py | 5 ----- src/specklepy/objects/structural/loading.py | 1 - src/specklepy/objects/structural/properties.py | 1 - tests/test_type_validation.py | 9 ++++++++- 7 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/specklepy/objects/base.py b/src/specklepy/objects/base.py index 64de464..cc347a5 100644 --- a/src/specklepy/objects/base.py +++ b/src/specklepy/objects/base.py @@ -252,7 +252,7 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]: return True, value with contextlib.suppress(ValueError): - if t is float and value: + if t is float and value is not None: return True, float(value) # TODO: dafuq, i had to add this not list check # but it would also fail for objects and other complex values diff --git a/src/specklepy/objects/geometry.py b/src/specklepy/objects/geometry.py index ab764a0..78d9a34 100644 --- a/src/specklepy/objects/geometry.py +++ b/src/specklepy/objects/geometry.py @@ -45,7 +45,6 @@ class Vector(Base, speckle_type=GEOMETRY + "Vector"): y: float = 0.0 z: float = 0.0 applicationId: Optional[str] = None - units: Optional[str] = None def __repr__(self) -> str: return ( @@ -151,7 +150,6 @@ class Arc(Base, speckle_type=GEOMETRY + "Arc"): bbox: Optional[Box] = None area: Optional[float] = None length: Optional[float] = None - units: Optional[str] = None @classmethod def from_list(cls, args: List[Any]) -> "Arc": @@ -319,7 +317,6 @@ class Spiral(Base, speckle_type=GEOMETRY + "Spiral", detachable={"displayValue"} bbox: Optional[Box] = None length: Optional[float] = None domain: Optional[Interval] = None - units: Optional[str] = None class Curve( diff --git a/src/specklepy/objects/other.py b/src/specklepy/objects/other.py index bd035f0..705e05d 100644 --- a/src/specklepy/objects/other.py +++ b/src/specklepy/objects/other.py @@ -67,7 +67,6 @@ class DisplayStyle(Base, speckle_type=OTHER + "DisplayStyle"): color: int = -2894893 # light gray arbg linetype: Optional[str] = None lineweight: float = 0 - units: Optional[str] = None class Transform( diff --git a/src/specklepy/objects/structural/geometry.py b/src/specklepy/objects/structural/geometry.py index 1ff129d..f232529 100644 --- a/src/specklepy/objects/structural/geometry.py +++ b/src/specklepy/objects/structural/geometry.py @@ -55,7 +55,6 @@ class Restraint(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Restraint"): stiffnessXX: float = 0.0 stiffnessYY: float = 0.0 stiffnessZZ: float = 0.0 - units: Optional[str] = None class Node(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Node"): @@ -66,7 +65,6 @@ class Node(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Node"): springProperty: Optional[PropertySpring] = None massProperty: Optional[PropertyMass] = None damperProperty: Optional[PropertyDamper] = None - units: Optional[str] = None class Element1D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element1D"): @@ -86,7 +84,6 @@ class Element1D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element1D"): end2Node: Optional[Node] = None topology: Optional[List] = None displayMesh: Optional[Mesh] = None - units: Optional[str] = None class Element2D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element2D"): @@ -98,7 +95,6 @@ class Element2D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element2D"): parent: Optional[Base] = None topology: Optional[List] = None displayMesh: Optional[Mesh] = None - units: Optional[str] = None class Element3D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element3D"): @@ -109,7 +105,6 @@ class Element3D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element3D"): orientationAngle: float = 0.0 parent: Optional[Base] = None topology: List - units: Optional[str] = None # class Storey needs ependency on built elements first diff --git a/src/specklepy/objects/structural/loading.py b/src/specklepy/objects/structural/loading.py index bba7e81..95d92fd 100644 --- a/src/specklepy/objects/structural/loading.py +++ b/src/specklepy/objects/structural/loading.py @@ -99,7 +99,6 @@ class LoadCase(Base, speckle_type=STRUCTURAL_LOADING + "LoadCase"): class Load(Base, speckle_type=STRUCTURAL_LOADING + "Load"): name: Optional[str] = None - units: Optional[str] = None loadCase: Optional[LoadCase] = None diff --git a/src/specklepy/objects/structural/properties.py b/src/specklepy/objects/structural/properties.py index 803bf65..a3e3138 100644 --- a/src/specklepy/objects/structural/properties.py +++ b/src/specklepy/objects/structural/properties.py @@ -100,7 +100,6 @@ class SectionProfile(Base, speckle_type=STRUCTURAL_PROPERTY + ".SectionProfile") J: float = 0.0 Ky: float = 0.0 weight: float = 0.0 - units: Optional[str] = None class Property1D(Property, speckle_type=STRUCTURAL_PROPERTY + ".Property1D"): diff --git a/tests/test_type_validation.py b/tests/test_type_validation.py index cdec888..3301897 100644 --- a/tests/test_type_validation.py +++ b/tests/test_type_validation.py @@ -2,6 +2,7 @@ from enum import Enum, IntEnum import pytest from typing import Any, Dict, List, Optional, Tuple from specklepy.objects.base import Base, _validate_type +from specklepy.objects.primitive import Interval test_base = Base() @@ -26,6 +27,7 @@ class FakeIntEnum(IntEnum): True, "{'foo': 'bar'}", ), + (float, 1, True, 1), # why are we allowing this??? We're lying to our users and ourselves too. (str, None, True, None), (bool, None, True, None), @@ -47,7 +49,7 @@ class FakeIntEnum(IntEnum): (Base, 123, False, 123), (Optional[int], 1, True, 1), # this is just silly... - (Optional[int], [1, 2, 3], True, [1, 2, 3]), + (Optional[int], [1, 2, 3], False, [1, 2, 3]), (Optional[int], None, True, None), (Optional[FakeEnum], None, True, None), (Optional[FakeEnum], FakeEnum.bar, True, FakeEnum.bar), @@ -77,3 +79,8 @@ def test_validate_type( input_type: type, value: Any, is_valid: bool, return_value: Any ) -> None: assert (is_valid, return_value) == _validate_type(input_type, value) + + +def test_intervar_type(): + i = Interval(start=5, end=10) + assert i \ No newline at end of file From a3a22a43d5ce05f6eb6f49d8de7470c9cf5ec901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 16 Dec 2022 21:45:24 +0100 Subject: [PATCH 11/13] formatting fixes --- src/specklepy/api/credentials.py | 2 +- src/specklepy/api/models.py | 18 +++++++++--------- src/specklepy/objects/structural/results.py | 1 - tests/conftest.py | 4 ++-- tests/test_base.py | 1 + tests/test_type_validation.py | 2 +- tests/test_user.py | 5 +++-- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/specklepy/api/credentials.py b/src/specklepy/api/credentials.py index d68a9a5..689c5b9 100644 --- a/src/specklepy/api/credentials.py +++ b/src/specklepy/api/credentials.py @@ -66,7 +66,7 @@ def get_local_accounts(base_path: Optional[str] = None) -> List[Account]: json_acct_files.extend( file for file in os.listdir(json_path) if file.endswith(".json") ) - + except Exception: # cannot find or get the json account paths pass diff --git a/src/specklepy/api/models.py b/src/specklepy/api/models.py index a5cc414..4729095 100644 --- a/src/specklepy/api/models.py +++ b/src/specklepy/api/models.py @@ -59,20 +59,20 @@ class Branches(BaseModel): class Stream(BaseModel): - id: Optional[str] = None + id: Optional[str] = None name: Optional[str] role: Optional[str] = None isPublic: Optional[bool] = None description: Optional[str] = None - createdAt: Optional[datetime] = None - updatedAt: Optional[datetime] = None + createdAt: Optional[datetime] = None + updatedAt: Optional[datetime] = None collaborators: List[Collaborator] = Field(default_factory=list) - branches: Optional[Branches] = None - commit: Optional[Commit] = None - object: Optional[Object] = None - commentCount: Optional[int] = None - favoritedDate: Optional[datetime] = None - favoritesCount: Optional[int] = None + branches: Optional[Branches] = None + commit: Optional[Commit] = None + object: Optional[Object] = None + commentCount: Optional[int] = None + favoritedDate: Optional[datetime] = None + favoritesCount: Optional[int] = None def __repr__(self): return f"Stream( id: {self.id}, name: {self.name}, description: {self.description}, isPublic: {self.isPublic})" diff --git a/src/specklepy/objects/structural/results.py b/src/specklepy/objects/structural/results.py index 293211e..6a97d42 100644 --- a/src/specklepy/objects/structural/results.py +++ b/src/specklepy/objects/structural/results.py @@ -170,4 +170,3 @@ class ResultSetAll(Base, speckle_type=None): resultSet3D: Optional[ResultSet3D] = None resultsGlobal: Optional[ResultGlobal] = None resultsNode: Optional[ResultSetNode] = None - diff --git a/tests/conftest.py b/tests/conftest.py index f0c3ba0..b920134 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,10 +31,10 @@ def seed_user(host): r = requests.post( url=f"http://{host}/auth/local/register?challenge=pyspeckletests", data=user_dict, - # do not follow redirects here, they lead to the frontend, which might not be + # do not follow redirects here, they lead to the frontend, which might not be # running in a test environment # causing the response to not be OK in the end - allow_redirects=False + allow_redirects=False, ) if not r.ok: raise Exception(f"Cannot seed user: {r.reason}") diff --git a/tests/test_base.py b/tests/test_base.py index fdd78a4..dd667a9 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -29,6 +29,7 @@ def test_empty_prop_names(invalid_prop_name: str) -> None: class FakeModel(Base): """Just a test class type.""" + class FakeSub(FakeModel): """Just a test class type.""" diff --git a/tests/test_type_validation.py b/tests/test_type_validation.py index 3301897..fae6320 100644 --- a/tests/test_type_validation.py +++ b/tests/test_type_validation.py @@ -83,4 +83,4 @@ def test_validate_type( def test_intervar_type(): i = Interval(start=5, end=10) - assert i \ No newline at end of file + assert i diff --git a/tests/test_user.py b/tests/test_user.py index 7128309..5885985 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -19,7 +19,9 @@ class TestUser: def test_user_search(self, client, second_user_dict): with pytest.deprecated_call(): - search_results = client.user.search(search_query=second_user_dict["name"][:5]) + search_results = client.user.search( + search_query=second_user_dict["name"][:5] + ) assert isinstance(search_results, list) assert isinstance(search_results[0], User) @@ -50,7 +52,6 @@ class TestUser: updated = client.user.update(bio=bio) assert updated is True - with pytest.deprecated_call(): me = client.user.get() assert me.bio == bio From 6804282fac8639d82f93d2268a49708b9e13d122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 16 Dec 2022 21:45:47 +0100 Subject: [PATCH 12/13] import ordering --- src/specklepy/objects/__init__.py | 2 +- src/specklepy/objects/primitive.py | 1 + tests/test_type_validation.py | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/specklepy/objects/__init__.py b/src/specklepy/objects/__init__.py index 6b78337..fef8b55 100644 --- a/src/specklepy/objects/__init__.py +++ b/src/specklepy/objects/__init__.py @@ -1,6 +1,6 @@ """Builtin Speckle object kit.""" -from specklepy.objects import encoding, geometry, other, structural, units, primitive +from specklepy.objects import encoding, geometry, other, primitive, structural, units from specklepy.objects.base import Base __all__ = ["Base", "encoding", "geometry", "other", "units", "structural", "primitive"] diff --git a/src/specklepy/objects/primitive.py b/src/specklepy/objects/primitive.py index cc8e47b..d4a4aae 100644 --- a/src/specklepy/objects/primitive.py +++ b/src/specklepy/objects/primitive.py @@ -1,4 +1,5 @@ from typing import Any, List + from specklepy.objects.base import Base NAMESPACE = "Objects.Primitive" diff --git a/tests/test_type_validation.py b/tests/test_type_validation.py index fae6320..52581b5 100644 --- a/tests/test_type_validation.py +++ b/tests/test_type_validation.py @@ -1,6 +1,8 @@ from enum import Enum, IntEnum -import pytest from typing import Any, Dict, List, Optional, Tuple + +import pytest + from specklepy.objects.base import Base, _validate_type from specklepy.objects.primitive import Interval From 59a6950eed34c80ab602f249da2135adea05e270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Fri, 16 Dec 2022 22:01:56 +0100 Subject: [PATCH 13/13] fix type checking error message --- src/specklepy/objects/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/specklepy/objects/base.py b/src/specklepy/objects/base.py index cc347a5..6e5ac0a 100644 --- a/src/specklepy/objects/base.py +++ b/src/specklepy/objects/base.py @@ -378,7 +378,7 @@ class Base(_RegisteringBase): raise SpeckleException( f"Cannot set '{self.__class__.__name__}.{name}':" - f"it expects type '{t.__name__ if t else None}'," + f"it expects type '{str(t)}'," f"but received type '{type(value).__name__}'" )