Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add option for speckle_type_translations #304

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/specklepy/objects/GIS/CRS.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from typing import Optional
from specklepy.objects import Base
from specklepy.objects.base import Base


class CRS(Base, speckle_type="Objects.GIS.CRS"):
Expand Down
13 changes: 10 additions & 3 deletions src/specklepy/objects/GIS/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
CRS,
)

__all__ = ["VectorLayer", "RasterLayer",
"GisPolygonGeometry", "GisPolygonElement", "GisLineElement", "GisPointElement", "GisRasterElement",
"CRS"]
__all__ = [
"VectorLayer",
"RasterLayer",
"GisPolygonGeometry",
"GisPolygonElement",
"GisLineElement",
"GisPointElement",
"GisRasterElement",
"CRS",
]
46 changes: 33 additions & 13 deletions src/specklepy/objects/GIS/geometry.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
from typing import Optional, Union, List
from specklepy.objects.geometry import (
Point,
Line,
Polyline,
Circle,
Arc,
Polycurve,
Mesh,
)
from specklepy.objects.base import Base

from typing import Optional, Union, List
from specklepy.objects.geometry import Point, Line, Polyline, Circle, Arc, Polycurve, Mesh
from specklepy.objects import Base
from deprecated import deprecated

class GisPolygonGeometry(Base, speckle_type="Objects.GIS.PolygonGeometry", detachable={"displayValue"}):
class GisPolygonGeometry(
Base, speckle_type="Objects.GIS.PolygonGeometry", detachable={"displayValue"}
):
"""GIS Polygon Geometry"""

boundary: Optional[Union[Polyline, Arc, Line, Circle, Polycurve]] = None
voids: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]] ] = None
voids: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]]] = None
displayValue: Optional[List[Mesh]] = None


class GisPolygonElement(Base, speckle_type="Objects.GIS.PolygonElement"):
"""GIS Polygon element"""

geometry: Optional[List[GisPolygonGeometry]] = None
attributes: Optional[Base] = None


class GisLineElement(Base, speckle_type="Objects.GIS.LineElement"):
"""GIS Polyline element"""

geometry: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]]] = None,
attributes: Optional[Base] = None,
geometry: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]]] = (None,)
attributes: Optional[Base] = (None,)


class GisPointElement(Base, speckle_type="Objects.GIS.PointElement"):
"""GIS Point element"""

geometry: Optional[List[Point]] = None,
attributes: Optional[Base] = None,
geometry: Optional[List[Point]] = (None,)
attributes: Optional[Base] = (None,)


class GisRasterElement(Base, speckle_type="Objects.GIS.RasterElement", detachable={"displayValue"}):
class GisRasterElement(
Base, speckle_type="Objects.GIS.RasterElement", detachable={"displayValue"}
):
"""GIS Raster element"""

band_count: Optional[int] = None
Expand All @@ -43,11 +58,16 @@ class GisRasterElement(Base, speckle_type="Objects.GIS.RasterElement", detachabl
noDataValue: Optional[List[float]] = None
displayValue: Optional[List[Mesh]] = None

class GisTopography(GisRasterElement, speckle_type="Objects.GIS.GisTopography", detachable={"displayValue"}):

class GisTopography(
GisRasterElement,
speckle_type="Objects.GIS.GisTopography",
detachable={"displayValue"},
):
"""GIS Raster element with 3d Topography representation"""


class GisNonGeometryElement(Base, speckle_type="Objects.GIS.NonGeometryElement"):
"""GIS Table feature"""

attributes: Optional[Base] = None

97 changes: 24 additions & 73 deletions src/specklepy/objects/GIS/layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,21 @@
from specklepy.objects.GIS.CRS import CRS
from deprecated import deprecated


@deprecated(version="2.15", reason="Use VectorLayer or RasterLayer instead")
class Layer(Base, detachable={"features"}):
"""A GIS Layer"""

def __init__(
self,
name:str=None,
crs:CRS=None,
name: str = None,
crs: CRS = None,
units: str = "m",
features: Optional[List[Base]] = None,
layerType: str = "None",
geomType: str = "None",
renderer: Optional[dict[str, Any]] = None,
**kwargs
**kwargs,
) -> None:
super().__init__(**kwargs)
self.name = name
Expand All @@ -26,80 +28,28 @@ def __init__(
self.type = layerType
self.features = features or []
self.geomType = geomType
self.renderer = renderer or {}

@deprecated(version="2.16", reason="Use VectorLayer or RasterLayer instead")
class VectorLayer(
Collection,
detachable={"elements"},
speckle_type="VectorLayer",
serialize_ignore={"features"}):

"""GIS Vector Layer"""
name: Optional[str]=None
crs: Optional[Union[CRS, Base]]=None
units: Optional[str] = None
elements: Optional[List[Base]] = None
attributes: Optional[Base] = None
geomType: Optional[str] = "None"
renderer: Optional[Dict[str, Any]] = None
collectionType = "VectorLayer"

@property
@deprecated(version="2.14", reason="Use elements")
def features(self) -> Optional[List[Base]]:
return self.elements

@features.setter
def features(self, value: Optional[List[Base]]) -> None:
self.elements = value

@deprecated(version="2.16", reason="Use VectorLayer or RasterLayer instead")
class RasterLayer(
Collection,
detachable={"elements"},
speckle_type="RasterLayer",
serialize_ignore={"features"}):

"""GIS Raster Layer"""

name: Optional[str] = None
crs: Optional[Union[CRS, Base]]=None
units: Optional[str] = None
rasterCrs: Optional[Union[CRS, Base]]=None
elements: Optional[List[Base]] = None
geomType: Optional[str] = "None"
renderer: Optional[Dict[str, Any]] = None
collectionType = "RasterLayer"


@property
@deprecated(version="2.14", reason="Use elements")
def features(self) -> Optional[List[Base]]:
return self.elements

@features.setter
def features(self, value: Optional[List[Base]]) -> None:
self.elements = value
self.renderer = renderer or {}


class VectorLayer(
Collection,
detachable={"elements"},
speckle_type="Objects.GIS.VectorLayer",
serialize_ignore={"features"}):
Collection,
detachable={"elements"},
speckle_type="Objects.GIS.VectorLayer",
serialize_ignore={"features"},
speckle_type_translations=["VectorLayer"],
):

"""GIS Vector Layer"""

name: Optional[str]=None
crs: Optional[Union[CRS, Base]]=None
name: Optional[str] = None
crs: Optional[Union[CRS, Base]] = None
units: Optional[str] = None
elements: Optional[List[Base]] = None
attributes: Optional[Base] = None
geomType: Optional[str] = "None"
renderer: Optional[Dict[str, Any]] = None
collectionType = "VectorLayer"

@property
@deprecated(version="2.14", reason="Use elements")
def features(self) -> Optional[List[Base]]:
Expand All @@ -109,24 +59,26 @@ def features(self) -> Optional[List[Base]]:
def features(self, value: Optional[List[Base]]) -> None:
self.elements = value


class RasterLayer(
Collection,
detachable={"elements"},
speckle_type="Objects.GIS.RasterLayer",
serialize_ignore={"features"}):
Collection,
detachable={"elements"},
speckle_type="Objects.GIS.RasterLayer",
serialize_ignore={"features"},
speckle_type_translations=["RasterLayer"],
):

"""GIS Raster Layer"""

name: Optional[str] = None
crs: Optional[Union[CRS, Base]]=None
crs: Optional[Union[CRS, Base]] = None
units: Optional[str] = None
rasterCrs: Optional[Union[CRS, Base]]=None
rasterCrs: Optional[Union[CRS, Base]] = None
elements: Optional[List[Base]] = None
geomType: Optional[str] = "None"
renderer: Optional[Dict[str, Any]] = None
collectionType = "RasterLayer"


@property
@deprecated(version="2.14", reason="Use elements")
def features(self) -> Optional[List[Base]]:
Expand All @@ -135,4 +87,3 @@ def features(self) -> Optional[List[Base]]:
@features.setter
def features(self, value: Optional[List[Base]]) -> None:
self.elements = value

21 changes: 19 additions & 2 deletions src/specklepy/objects/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
"""Builtin Speckle object kit."""

from specklepy.objects import encoding, geometry, other, primitive, structural, units
from specklepy.objects import (
encoding,
geometry,
other,
primitive,
structural,
units,
GIS,
)
from specklepy.objects.base import Base

__all__ = ["Base", "encoding", "geometry", "other", "units", "structural", "primitive"]
__all__ = [
"Base",
"encoding",
"geometry",
"other",
"units",
"structural",
"primitive",
"GIS",
]
9 changes: 8 additions & 1 deletion src/specklepy/objects/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class _RegisteringBase:
The type registry is a base for accurate type based (de)serialization.
"""

_translations: ClassVar[Dict[str, str]] = {}
speckle_type: ClassVar[str]
_speckle_type_override: ClassVar[Optional[str]] = None
_speckle_namespace: ClassVar[Optional[str]] = None
Expand All @@ -108,7 +109,8 @@ class _RegisteringBase:
def get_registered_type(cls, speckle_type: str) -> Optional[Type["Base"]]:
"""Get the registered type from the protected mapping via the `speckle_type`"""
for full_name in reversed(speckle_type.split(":")):
maybe_type = cls._type_registry.get(full_name, None)
translated_name = cls._translations.get(full_name, full_name)
maybe_type = cls._type_registry.get(translated_name, None)
if maybe_type:
return maybe_type
return None
Expand Down Expand Up @@ -159,6 +161,7 @@ def __init_subclass__(
chunkable: Optional[Dict[str, int]] = None,
detachable: Optional[Set[str]] = None,
serialize_ignore: Optional[Set[str]] = None,
speckle_type_translations: Optional[List[str]] = None,
**kwargs: Dict[str, Any],
):
"""
Expand Down Expand Up @@ -188,6 +191,10 @@ def __init_subclass__(
cls._detachable = cls._detachable.union(detachable)
if serialize_ignore:
cls._serialize_ignore = cls._serialize_ignore.union(serialize_ignore)
if speckle_type_translations:
cls._translations.update(
{trans: cls.speckle_type for trans in speckle_type_translations}
)
super().__init_subclass__(**kwargs)


Expand Down
22 changes: 22 additions & 0 deletions tests/unit/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,25 @@ def test_cached_deserialization() -> None:
deserialized = operations.deserialize(serialized)

assert deserialized["a"]["@material"] is deserialized["b"]["@material"]


def test_translations() -> None:
speckle_type_override = "TrickyToTranslate"
translated_speckle_type = "ItMeansThis🪂"

maybe_type = Base.get_registered_type(speckle_type_override)

assert maybe_type == None

class TrickyToTranslate(
Base,
speckle_type=speckle_type_override,
speckle_type_translations=[translated_speckle_type],
):
"""This is just a test class with no body."""

maybe_type = Base.get_registered_type(speckle_type_override)
assert maybe_type == TrickyToTranslate

maybe_type = Base.get_registered_type(translated_speckle_type)
assert maybe_type == TrickyToTranslate