Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 22ecd2c2b3 | |||
| f7f9f73e7b | |||
| a7bada391b | |||
| 81ff5d82cb | |||
| d25edbb3d7 | |||
| 7dedff68f4 | |||
| d6e31a9752 | |||
| 09c61424d7 | |||
| e9bdf0ceb8 | |||
| 7e6174ebc1 | |||
| b8ae3ca8c8 | |||
| d690c45b35 | |||
| 5d3a824986 | |||
| 6f56ecb0c0 | |||
| 6c33c61a6d | |||
| 71afb1275f |
@@ -11,5 +11,7 @@ jobs:
|
||||
# Orchestrate our job run sequence
|
||||
workflows:
|
||||
build_and_test:
|
||||
when:
|
||||
false
|
||||
jobs:
|
||||
- build
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
.envrc
|
||||
reports/
|
||||
|
||||
.volumes/
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
+4
-3
@@ -13,7 +13,7 @@ services:
|
||||
POSTGRES_USER: speckle
|
||||
POSTGRES_PASSWORD: speckle
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data/
|
||||
- ./.volumes/postgres-data:/var/lib/postgresql/data/
|
||||
healthcheck:
|
||||
# the -U user has to match the POSTGRES_USER value
|
||||
test: ["CMD-SHELL", "pg_isready -U speckle"]
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
image: "redis:6.0-alpine"
|
||||
restart: always
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
- ./.volumes/redis-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
|
||||
interval: 5s
|
||||
@@ -37,7 +37,7 @@ services:
|
||||
command: server /data --console-address ":9001"
|
||||
restart: always
|
||||
volumes:
|
||||
- minio-data:/data
|
||||
- ./.volumes/minio-data:/data
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
@@ -100,6 +100,7 @@ services:
|
||||
POSTGRES_PASSWORD: "speckle"
|
||||
POSTGRES_DB: "speckle"
|
||||
ENABLE_MP: "false"
|
||||
FRONTEND_ORIGIN: "http://127.0.0.1:8080"
|
||||
|
||||
networks:
|
||||
default:
|
||||
|
||||
@@ -15,7 +15,6 @@ dependencies = [
|
||||
"httpx>=0.28.1",
|
||||
"pydantic>=2.10.5",
|
||||
"pydantic-settings>=2.7.1",
|
||||
"stringcase>=1.2.0",
|
||||
"ujson>=5.10.0",
|
||||
]
|
||||
|
||||
|
||||
@@ -332,7 +332,7 @@ class AutomationContext:
|
||||
def attach_error_to_objects(
|
||||
self,
|
||||
category: str,
|
||||
objects: Union[Base, List[Base]],
|
||||
object_ids: Union[str, List[str]],
|
||||
message: Optional[str] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
visual_overrides: Optional[Dict[str, Any]] = None,
|
||||
@@ -351,7 +351,7 @@ class AutomationContext:
|
||||
self.attach_result_to_objects(
|
||||
ObjectResultLevel.ERROR,
|
||||
category,
|
||||
objects,
|
||||
object_ids,
|
||||
message,
|
||||
metadata,
|
||||
visual_overrides,
|
||||
@@ -360,7 +360,7 @@ class AutomationContext:
|
||||
def attach_warning_to_objects(
|
||||
self,
|
||||
category: str,
|
||||
objects: Union[Base, List[Base]],
|
||||
object_ids: Union[str, List[str]],
|
||||
message: Optional[str] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
visual_overrides: Optional[Dict[str, Any]] = None,
|
||||
@@ -369,7 +369,7 @@ class AutomationContext:
|
||||
self.attach_result_to_objects(
|
||||
ObjectResultLevel.WARNING,
|
||||
category,
|
||||
objects,
|
||||
object_ids,
|
||||
message,
|
||||
metadata,
|
||||
visual_overrides,
|
||||
@@ -378,7 +378,7 @@ class AutomationContext:
|
||||
def attach_success_to_objects(
|
||||
self,
|
||||
category: str,
|
||||
objects: Union[Base, List[Base]],
|
||||
object_ids: Union[str, List[str]],
|
||||
message: Optional[str] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
visual_overrides: Optional[Dict[str, Any]] = None,
|
||||
@@ -387,7 +387,7 @@ class AutomationContext:
|
||||
self.attach_result_to_objects(
|
||||
ObjectResultLevel.SUCCESS,
|
||||
category,
|
||||
objects,
|
||||
object_ids,
|
||||
message,
|
||||
metadata,
|
||||
visual_overrides,
|
||||
@@ -396,7 +396,7 @@ class AutomationContext:
|
||||
def attach_info_to_objects(
|
||||
self,
|
||||
category: str,
|
||||
objects: Union[Base, List[Base]],
|
||||
object_ids: Union[str, List[str]],
|
||||
message: Optional[str] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
visual_overrides: Optional[Dict[str, Any]] = None,
|
||||
@@ -405,7 +405,7 @@ class AutomationContext:
|
||||
self.attach_result_to_objects(
|
||||
ObjectResultLevel.INFO,
|
||||
category,
|
||||
objects,
|
||||
object_ids,
|
||||
message,
|
||||
metadata,
|
||||
visual_overrides,
|
||||
@@ -415,22 +415,19 @@ class AutomationContext:
|
||||
self,
|
||||
level: ObjectResultLevel,
|
||||
category: str,
|
||||
objects: Union[Base, List[Base]],
|
||||
object_ids: Union[str, List[str]],
|
||||
message: Optional[str] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
visual_overrides: Optional[Dict[str, Any]] = None,
|
||||
) -> None:
|
||||
if isinstance(objects, list):
|
||||
if len(objects) < 1:
|
||||
if isinstance(object_ids, list):
|
||||
if len(object_ids) < 1:
|
||||
raise ValueError(
|
||||
f"Need atleast one object_id to report a(n) {level.value.upper()}"
|
||||
)
|
||||
id_list = [o.id for o in objects]
|
||||
application_ids = [o.applicationId for o in objects]
|
||||
id_list = object_ids
|
||||
else:
|
||||
id_list = [objects.id]
|
||||
application_ids = [objects.applicationId]
|
||||
metadata["applicationIds"] = application_ids
|
||||
id_list = [object_ids]
|
||||
print(
|
||||
f"Created new {level.value.upper()}"
|
||||
f" category: {category} caused by: {message}"
|
||||
|
||||
@@ -4,13 +4,13 @@ from enum import Enum
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from stringcase import camelcase
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
|
||||
class AutomateBase(BaseModel):
|
||||
"""Use this class as a base model for automate related DTO."""
|
||||
|
||||
model_config = ConfigDict(alias_generator=camelcase, populate_by_name=True)
|
||||
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
|
||||
|
||||
|
||||
class VersionCreationTriggerPayload(AutomateBase):
|
||||
@@ -39,7 +39,7 @@ class AutomationRunData(BaseModel):
|
||||
triggers: List[VersionCreationTrigger]
|
||||
|
||||
model_config = ConfigDict(
|
||||
alias_generator=camelcase, populate_by_name=True, protected_namespaces=()
|
||||
alias_generator=to_camel, populate_by_name=True, protected_namespaces=()
|
||||
)
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class TestAutomationRunData(BaseModel):
|
||||
triggers: List[VersionCreationTrigger]
|
||||
|
||||
model_config = ConfigDict(
|
||||
alias_generator=camelcase, populate_by_name=True, protected_namespaces=()
|
||||
alias_generator=to_camel, populate_by_name=True, protected_namespaces=()
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from enum import Enum
|
||||
class ProjectVisibility(str, Enum):
|
||||
PRIVATE = "PRIVATE"
|
||||
PUBLIC = "PUBLIC"
|
||||
UNLISTEd = "UNLISTED"
|
||||
UNLISTED = "UNLISTED"
|
||||
|
||||
|
||||
class UserProjectsUpdatedMessageType(str, Enum):
|
||||
|
||||
@@ -82,6 +82,16 @@ class LimitedUser(GraphQLBaseModel):
|
||||
verified: Optional[bool]
|
||||
role: Optional[str]
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"(name: {self.name}, "
|
||||
f"id: {self.id}, "
|
||||
f"bio: {self.bio}, "
|
||||
f"company: {self.company}, "
|
||||
f"verified: {self.verified}, "
|
||||
f"role: {self.role})"
|
||||
)
|
||||
|
||||
|
||||
class PendingStreamCollaborator(GraphQLBaseModel):
|
||||
id: str
|
||||
|
||||
@@ -17,7 +17,7 @@ from typing import (
|
||||
)
|
||||
from warnings import warn
|
||||
|
||||
from stringcase import pascalcase
|
||||
from pydantic.alias_generators import to_pascal
|
||||
|
||||
from specklepy.logging.exceptions import SpeckleException
|
||||
from specklepy.transports.memory import MemoryTransport
|
||||
@@ -147,7 +147,7 @@ class _RegisteringBase:
|
||||
# convert the module names to PascalCase to match c# namespace naming convention
|
||||
# also drop specklepy from the beginning
|
||||
namespace = ".".join(
|
||||
pascalcase(m)
|
||||
to_pascal(m)
|
||||
for m in filter(lambda name: name != "specklepy", cls.__module__.split("."))
|
||||
)
|
||||
return f"{namespace}.{cls.__name__}"
|
||||
|
||||
@@ -2,6 +2,7 @@ from .arc import Arc
|
||||
from .box import Box
|
||||
from .circle import Circle
|
||||
from .control_point import ControlPoint
|
||||
from .curve import Curve
|
||||
from .ellipse import Ellipse
|
||||
from .line import Line
|
||||
from .mesh import Mesh
|
||||
@@ -10,6 +11,7 @@ from .point import Point
|
||||
from .point_cloud import PointCloud
|
||||
from .polycurve import Polycurve
|
||||
from .polyline import Polyline
|
||||
from .region import Region
|
||||
from .spiral import Spiral
|
||||
from .surface import Surface
|
||||
from .vector import Vector
|
||||
@@ -22,6 +24,7 @@ __all__ = [
|
||||
"Plane",
|
||||
"Point",
|
||||
"Polyline",
|
||||
"Region",
|
||||
"Vector",
|
||||
"Box",
|
||||
"Circle",
|
||||
@@ -31,4 +34,5 @@ __all__ = [
|
||||
"Polycurve",
|
||||
"Spiral",
|
||||
"Surface",
|
||||
"Curve",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Optional
|
||||
|
||||
from specklepy.objects.base import Base
|
||||
from specklepy.objects.geometry.box import Box
|
||||
from specklepy.objects.geometry.polyline import Polyline
|
||||
from specklepy.objects.interfaces import ICurve, IHasArea, IHasUnits
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class Curve(
|
||||
Base,
|
||||
ICurve,
|
||||
IHasArea,
|
||||
IHasUnits,
|
||||
speckle_type="Objects.Geometry.Curve",
|
||||
detachable={"points", "weights", "knots", "displayValue"},
|
||||
chunkable={"points": 31250, "weights": 31250, "knots": 31250},
|
||||
):
|
||||
"""
|
||||
a NURBS curve
|
||||
"""
|
||||
|
||||
degree: int
|
||||
periodic: bool
|
||||
rational: bool
|
||||
points: List[float]
|
||||
weights: List[float]
|
||||
knots: List[float]
|
||||
closed: bool
|
||||
displayValue: Polyline
|
||||
bbox: Optional[Box] = None
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"{self.__class__.__name__}("
|
||||
f"degree: {self.degree}, "
|
||||
f"periodic: {self.periodic}, "
|
||||
f"rational: {self.rational}, "
|
||||
f"closed: {self.closed}, "
|
||||
f"units: {self.units})"
|
||||
)
|
||||
|
||||
@property
|
||||
def length(self) -> float:
|
||||
return self.__dict__.get("_length", 0.0)
|
||||
|
||||
@length.setter
|
||||
def length(self, value: float) -> None:
|
||||
self.__dict__["_length"] = value
|
||||
|
||||
@property
|
||||
def area(self) -> float:
|
||||
return self.__dict__.get("_area", 0.0)
|
||||
|
||||
@area.setter
|
||||
def area(self, value: float) -> None:
|
||||
self.__dict__["_area"] = value
|
||||
@@ -49,9 +49,8 @@ class Mesh(
|
||||
|
||||
if len(self.vertices) % 3 != 0:
|
||||
raise ValueError(
|
||||
f"Invalid vertices list: length ({
|
||||
len(self.vertices)
|
||||
}) must be a multiple of 3"
|
||||
f"Invalid vertices list: length {len(self.vertices)} "
|
||||
f"must be a multiple of 3"
|
||||
)
|
||||
return len(self.vertices) // 3
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List
|
||||
|
||||
from specklepy.logging.exceptions import SpeckleException
|
||||
from specklepy.objects.base import Base
|
||||
from specklepy.objects.geometry.box import Box
|
||||
from specklepy.objects.geometry.mesh import Mesh
|
||||
from specklepy.objects.interfaces import ICurve, IDisplayValue, IHasArea, IHasUnits
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class Region(
|
||||
Base,
|
||||
IHasArea,
|
||||
IDisplayValue[List[Mesh]],
|
||||
IHasUnits,
|
||||
speckle_type="Objects.Geometry.Region",
|
||||
detachable={"displayValue"},
|
||||
):
|
||||
"""
|
||||
Flat shape, defined by an outer boundary and inner loops.
|
||||
"""
|
||||
|
||||
boundary: ICurve
|
||||
innerLoops: List[ICurve]
|
||||
hasHatchPattern: bool
|
||||
bbox: Box | None = None
|
||||
# unlike C#, constructor will require displayValue, even if it's empty
|
||||
displayValue: List[Mesh]
|
||||
_displayValue: List[Mesh] = field(repr=False, init=False)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"{self.__class__.__name__}("
|
||||
f"units: {self.units}, "
|
||||
f"has_hatch_pattern: {self.hasHatchPattern}, "
|
||||
f"inner_loops: {len(self.innerLoops)})"
|
||||
)
|
||||
|
||||
@property
|
||||
def area(self) -> float:
|
||||
return self.__dict__.get("_area", 0.0)
|
||||
|
||||
@area.setter
|
||||
def area(self, value: float) -> None:
|
||||
self.__dict__["_area"] = value
|
||||
|
||||
@property
|
||||
def displayValue(self) -> List[Mesh]:
|
||||
print(self._displayValue)
|
||||
return self._displayValue
|
||||
|
||||
@displayValue.setter
|
||||
def displayValue(self, value: list):
|
||||
if isinstance(value, list):
|
||||
self._displayValue = value
|
||||
else:
|
||||
raise SpeckleException(
|
||||
f"'displayValue' value should be List, received {type(value)}"
|
||||
)
|
||||
@@ -7,7 +7,6 @@ from specklepy.objects.base import Base
|
||||
class RenderMaterial(
|
||||
Base,
|
||||
speckle_type="Objects.Other.RenderMaterial",
|
||||
serialize_ignore={"diffuse", "emissive"},
|
||||
):
|
||||
"""
|
||||
Minimal physically based material DTO class. Based on references from
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
import pytest
|
||||
|
||||
from specklepy.core.api.operations import deserialize, serialize
|
||||
from specklepy.objects.geometry import Curve, Plane, Point, Polyline, Vector
|
||||
from specklepy.objects.models.units import Units
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_polyline():
|
||||
"""
|
||||
sample polyline
|
||||
"""
|
||||
return Polyline(value=[0, 0, 0, 1, 0, 0, 1, 1, 0], units=Units.m)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_plane():
|
||||
"""
|
||||
sample plane for bbox creation
|
||||
"""
|
||||
origin = Point(x=0, y=0, z=0, units=Units.m)
|
||||
normal = Vector(x=0, y=0, z=1, units=Units.m)
|
||||
xdir = Vector(x=1, y=0, z=0, units=Units.m)
|
||||
ydir = Vector(x=0, y=1, z=0, units=Units.m)
|
||||
return Plane(origin=origin, normal=normal, xdir=xdir, ydir=ydir, units=Units.m)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_curve(sample_polyline):
|
||||
"""
|
||||
sample curve for testing
|
||||
"""
|
||||
return Curve(
|
||||
degree=3,
|
||||
periodic=False,
|
||||
rational=False,
|
||||
points=[0, 0, 0, 1, 1, 0, 2, 0, 0, 3, 1, 0],
|
||||
weights=[1, 1, 1, 1],
|
||||
knots=[0, 0, 0, 0, 1, 1, 1, 1],
|
||||
closed=False,
|
||||
displayValue=sample_polyline,
|
||||
units=Units.m,
|
||||
)
|
||||
|
||||
|
||||
def test_curve_creation(sample_polyline):
|
||||
"""
|
||||
test curve initialization
|
||||
"""
|
||||
curve = Curve(
|
||||
degree=3,
|
||||
periodic=False,
|
||||
rational=False,
|
||||
points=[0, 0, 0, 1, 1, 0, 2, 0, 0, 3, 1, 0],
|
||||
weights=[1, 1, 1, 1],
|
||||
knots=[0, 0, 0, 0, 1, 1, 1, 1],
|
||||
closed=False,
|
||||
displayValue=sample_polyline,
|
||||
units=Units.m,
|
||||
)
|
||||
|
||||
assert curve.degree == 3
|
||||
assert curve.periodic is False
|
||||
assert curve.rational is False
|
||||
assert curve.points == [0, 0, 0, 1, 1, 0, 2, 0, 0, 3, 1, 0]
|
||||
assert curve.weights == [1, 1, 1, 1]
|
||||
assert curve.knots == [0, 0, 0, 0, 1, 1, 1, 1]
|
||||
assert curve.closed is False
|
||||
assert curve.units == Units.m.value
|
||||
assert curve.displayValue == sample_polyline
|
||||
|
||||
|
||||
def test_length_property(sample_polyline):
|
||||
"""
|
||||
test the length property setter and getter
|
||||
"""
|
||||
curve = Curve(
|
||||
degree=1,
|
||||
periodic=False,
|
||||
rational=False,
|
||||
points=[0, 0, 0, 1, 0, 0],
|
||||
weights=[1, 1],
|
||||
knots=[0, 0, 1, 1],
|
||||
closed=False,
|
||||
displayValue=sample_polyline,
|
||||
units=Units.m,
|
||||
)
|
||||
|
||||
assert curve.length == 0.0
|
||||
|
||||
curve.length = 1.5
|
||||
assert curve.length == 1.5
|
||||
|
||||
|
||||
def test_area_property(sample_polyline):
|
||||
"""
|
||||
test the area property setter and getter
|
||||
"""
|
||||
polyline = Polyline(
|
||||
value=[0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0], units=Units.m
|
||||
)
|
||||
|
||||
curve = Curve(
|
||||
degree=1,
|
||||
periodic=False,
|
||||
rational=False,
|
||||
points=[0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0],
|
||||
weights=[1, 1, 1, 1, 1],
|
||||
knots=[0, 0, 1, 2, 3, 4, 4],
|
||||
closed=True,
|
||||
displayValue=polyline,
|
||||
units=Units.m,
|
||||
)
|
||||
|
||||
assert curve.area == 0.0
|
||||
|
||||
curve.area = 1.0
|
||||
assert curve.area == 1.0
|
||||
|
||||
|
||||
def test_curve_serialization(sample_curve):
|
||||
"""
|
||||
test serialization and deserialization of the curve
|
||||
"""
|
||||
serialized = serialize(sample_curve)
|
||||
deserialized = deserialize(serialized)
|
||||
|
||||
assert deserialized.degree == sample_curve.degree
|
||||
assert deserialized.periodic == sample_curve.periodic
|
||||
assert deserialized.rational == sample_curve.rational
|
||||
assert deserialized.points == sample_curve.points
|
||||
assert deserialized.weights == sample_curve.weights
|
||||
assert deserialized.knots == sample_curve.knots
|
||||
assert deserialized.closed == sample_curve.closed
|
||||
assert deserialized.units == sample_curve.units
|
||||
|
||||
|
||||
@pytest.mark.parametrize("new_units", ["mm", "cm", "in"])
|
||||
def test_curve_units(sample_polyline, new_units):
|
||||
"""
|
||||
test changing units of a curve
|
||||
"""
|
||||
curve = Curve(
|
||||
degree=3,
|
||||
periodic=False,
|
||||
rational=False,
|
||||
points=[0, 0, 0, 1, 1, 0, 2, 0, 0, 3, 1, 0],
|
||||
weights=[1, 1, 1, 1],
|
||||
knots=[0, 0, 0, 0, 1, 1, 1, 1],
|
||||
closed=False,
|
||||
displayValue=sample_polyline,
|
||||
units=Units.m,
|
||||
)
|
||||
|
||||
assert curve.units == Units.m.value
|
||||
|
||||
curve.units = new_units
|
||||
assert curve.units == new_units
|
||||
@@ -0,0 +1,84 @@
|
||||
# ignoring "line too long" check from linter
|
||||
# to match with SpeckleExceptions
|
||||
# ruff: noqa: E501
|
||||
|
||||
import pytest
|
||||
|
||||
from specklepy.core.api.operations import deserialize, serialize
|
||||
from specklepy.objects.geometry.polyline import Polyline
|
||||
from specklepy.objects.geometry.region import Region
|
||||
from specklepy.objects.models.units import Units
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_boundary():
|
||||
return Polyline(
|
||||
# possibly replace same start-end Polyline point with "closed" property
|
||||
value=[-10, -10, 0, 10, -10, 0, 10, 10, 0, -10, 10, 0, -10, -10, 0],
|
||||
units=Units.m,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_loop1():
|
||||
return Polyline(
|
||||
# possibly replace same start-end Polyline point with "closed" property
|
||||
value=[-9, -9, 0, -5, -9, 0, -5, -5, 0, -9, -5, 0, -9, -9, 0],
|
||||
units=Units.m,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_loop2():
|
||||
return Polyline(
|
||||
# possibly replace same start-end Polyline point with "closed" property
|
||||
value=[5, 5, 0, 9, 5, 0, 9, 9, 0, 5, 9, 0, 5, 5, 0],
|
||||
units=Units.m,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_region(sample_boundary, sample_loop1, sample_loop2):
|
||||
return Region(
|
||||
boundary=sample_boundary,
|
||||
innerLoops=[sample_loop1, sample_loop2],
|
||||
hasHatchPattern=True,
|
||||
units=Units.m,
|
||||
displayValue=[],
|
||||
)
|
||||
|
||||
|
||||
def test_region_creation(sample_boundary, sample_loop1, sample_loop2):
|
||||
has_hatch_pattern = True
|
||||
region = Region(
|
||||
boundary=sample_boundary,
|
||||
innerLoops=[sample_loop1, sample_loop2],
|
||||
hasHatchPattern=has_hatch_pattern,
|
||||
units=Units.m,
|
||||
displayValue=[],
|
||||
)
|
||||
assert region.boundary == sample_boundary
|
||||
assert region.innerLoops[0] == sample_loop1
|
||||
assert region.innerLoops[1] == sample_loop2
|
||||
assert region.hasHatchPattern == has_hatch_pattern
|
||||
assert len(region.displayValue) == 0
|
||||
assert region.units == Units.m.value
|
||||
|
||||
|
||||
def test_region_serialization(sample_region):
|
||||
serialized = serialize(sample_region)
|
||||
deserialized = deserialize(serialized)
|
||||
|
||||
assert deserialized.hasHatchPattern == sample_region.hasHatchPattern
|
||||
assert deserialized.units == sample_region.units
|
||||
|
||||
assert deserialized.boundary.length == sample_region.boundary.length
|
||||
assert deserialized.boundary.domain.length == sample_region.boundary.domain.length
|
||||
assert deserialized.boundary.domain.start == sample_region.boundary.domain.start
|
||||
assert deserialized.boundary.domain.end == sample_region.boundary.domain.end
|
||||
|
||||
for i, loop in enumerate(sample_region.innerLoops):
|
||||
assert deserialized.innerLoops[i].length == loop.length
|
||||
assert deserialized.innerLoops[i].domain.length == loop.domain.length
|
||||
assert deserialized.innerLoops[i].domain.start == loop.domain.start
|
||||
assert deserialized.innerLoops[i].domain.end == loop.domain.end
|
||||
@@ -94,6 +94,12 @@ class ServerTransport(AbstractTransport):
|
||||
|
||||
self.session = requests.Session()
|
||||
|
||||
self.session.headers.update(
|
||||
{
|
||||
"Accept": "text/plain",
|
||||
}
|
||||
)
|
||||
|
||||
if self.account is not None:
|
||||
self._batch_sender = BatchSender(
|
||||
self.url, self.stream_id, self.account.token, max_batch_size_mb=1
|
||||
@@ -101,7 +107,6 @@ class ServerTransport(AbstractTransport):
|
||||
self.session.headers.update(
|
||||
{
|
||||
"Authorization": f"Bearer {self.account.token}",
|
||||
"Accept": "text/plain",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ class TestProjectResource:
|
||||
"name, description, visibility",
|
||||
[
|
||||
("Very private project", "My secret project", ProjectVisibility.PRIVATE),
|
||||
("Very discoverable project", None, ProjectVisibility.UNLISTED),
|
||||
("Very public project", None, ProjectVisibility.PUBLIC),
|
||||
],
|
||||
)
|
||||
@@ -48,7 +49,11 @@ class TestProjectResource:
|
||||
assert result.id is not None
|
||||
assert result.name == name
|
||||
assert result.description == (description or "")
|
||||
assert result.visibility == visibility
|
||||
# we've disabled creation of public projects for now, they fall back to unlisted
|
||||
if visibility == ProjectVisibility.PUBLIC:
|
||||
assert result.visibility == ProjectVisibility.UNLISTED
|
||||
else:
|
||||
assert result.visibility == visibility
|
||||
|
||||
def test_project_get(self, client: SpeckleClient, test_project: Project):
|
||||
result = client.project.get(test_project.id)
|
||||
@@ -78,7 +83,11 @@ class TestProjectResource:
|
||||
assert updated_project.id == test_project.id
|
||||
assert updated_project.name == new_name
|
||||
assert updated_project.description == new_description
|
||||
assert updated_project.visibility == new_visibility
|
||||
# we've disabled creation of public projects for now, they fall back to unlisted
|
||||
if new_visibility == ProjectVisibility.PUBLIC:
|
||||
assert updated_project.visibility == ProjectVisibility.UNLISTED
|
||||
else:
|
||||
assert updated_project.visibility == new_visibility
|
||||
|
||||
def test_project_delete(self, client: SpeckleClient):
|
||||
"""Test deleting a project."""
|
||||
|
||||
@@ -133,7 +133,7 @@ def automate_function(
|
||||
raise ValueError("Cannot operate on objects without their id's.")
|
||||
automation_context.attach_error_to_objects(
|
||||
"Forbidden speckle_type",
|
||||
version_root_object,
|
||||
version_root_object.id,
|
||||
"This project should not contain the type: "
|
||||
f"{function_inputs.forbidden_speckle_type}",
|
||||
)
|
||||
|
||||
@@ -1392,7 +1392,6 @@ dependencies = [
|
||||
{ name = "httpx" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-settings" },
|
||||
{ name = "stringcase" },
|
||||
{ name = "ujson" },
|
||||
]
|
||||
|
||||
@@ -1422,7 +1421,6 @@ requires-dist = [
|
||||
{ name = "httpx", specifier = ">=0.28.1" },
|
||||
{ name = "pydantic", specifier = ">=2.10.5" },
|
||||
{ name = "pydantic-settings", specifier = ">=2.7.1" },
|
||||
{ name = "stringcase", specifier = ">=1.2.0" },
|
||||
{ name = "ujson", specifier = ">=5.10.0" },
|
||||
]
|
||||
|
||||
@@ -1443,12 +1441,6 @@ dev = [
|
||||
{ name = "types-ujson", specifier = ">=5.10.0.20240515" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stringcase"
|
||||
version = "1.2.0"
|
||||
source = { registry = "https://pypi.org/simple/" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f3/1f/1241aa3d66e8dc1612427b17885f5fcd9c9ee3079fc0d28e9a3aeeb36fa3/stringcase-1.2.0.tar.gz", hash = "sha256:48a06980661908efe8d9d34eab2b6c13aefa2163b3ced26972902e3bdfd87008", size = 2958 }
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "2.5.0"
|
||||
|
||||
Reference in New Issue
Block a user