Compare commits

..

23 Commits

Author SHA1 Message Date
Gergő Jedlicska 12b9602577 Merge pull request #397 from specklesystems/gergo/nostringcase
chore: remove stringcase as a dependency
2025-03-27 15:27:06 +01:00
Gergő Jedlicska d6e31a9752 chore: fix compose file 2025-03-27 15:19:25 +01:00
Gergő Jedlicska 09c61424d7 tests: update some tests with new server standards 2025-03-27 13:56:19 +01:00
Gergő Jedlicska e9bdf0ceb8 chore: update poetry lock 2025-03-24 20:22:03 +01:00
Gergő Jedlicska 7e6174ebc1 chore: remove stringcase as a dependency 2025-03-24 19:47:07 +01:00
Gergő Jedlicska 6c33c61a6d Merge pull request #382 from specklesystems/gergo/fixServerTransportHeader
fix: server transport always accept text/plain
2025-02-12 13:03:00 +01:00
Gergő Jedlicska 71afb1275f fix: server transport always accept text/plain 2025-02-12 12:35:11 +01:00
Chuck Driesler 78c55b787f chore(automate): improve error message when automate fails to receive a model version (#376)
Co-authored-by: Björn Steinhagen <steinhagen.bjoern@gmail.com>
2025-01-24 11:28:15 +00:00
Jedd Morgan 34f2dc2ab6 author now optional (#377) 2025-01-24 11:01:09 +00:00
Gergő Jedlicska d71b616e2b Merge pull request #363 from specklesystems/jrm/filter-tests
Added tests for filters
2024-12-11 14:21:54 +01:00
Jedd Morgan 35750f12c5 Merge branch 'main' into jrm/filter-tests 2024-12-11 13:05:18 +00:00
Jedd Morgan 82b6dbbe78 isort 2024-12-11 12:09:56 +00:00
Jedd Morgan 883be4b27b reexport inputs 2024-12-11 12:07:37 +00:00
Gergő Jedlicska 8dcc67fb31 Merge pull request #365 from specklesystems/jedd/cxpla-132-update-connectors-usage-of-user-queries-to-use-activeuser
updated active user streams
2024-12-10 15:57:04 +01:00
Jedd Morgan ed84820995 fix 2024-12-10 14:27:19 +00:00
Jedd Morgan 5c3dcb7bc0 updated active user streams 2024-12-10 14:14:31 +00:00
Gergő Jedlicska a0e10aae99 Merge pull request #362 from specklesystems/jrm/deps
Updated dependencies
2024-12-09 12:26:56 +01:00
Jedd Morgan bbea2a0d76 Aligned pre-commit-hooks 2024-12-09 11:24:38 +00:00
Jedd Morgan a05ac3479b Black reformat 2024-12-09 11:17:26 +00:00
Jedd Morgan 0bd972945e update dependencies 2024-12-09 11:14:54 +00:00
Jedd Morgan f200544065 Moved UserProjectsFilter to UserInputs 2024-12-09 10:58:31 +00:00
Jedd Morgan 68ce9823ae added filter tests 2024-12-09 10:56:17 +00:00
Mucahit Bilal GOKER a920352407 fix(api): rename 'onlyWithRole' to 'onlyWithRoles' in UserProjectsFilter (#361) 2024-12-06 15:53:10 +00:00
53 changed files with 2622 additions and 1146 deletions
+2
View File
@@ -2,6 +2,8 @@
.envrc
reports/
.volumes/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
+3 -3
View File
@@ -2,7 +2,7 @@ repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
hooks:
- id: ruff
rev: v0.1.6
rev: v0.8.2
- repo: https://github.com/commitizen-tools/commitizen
hooks:
@@ -13,12 +13,12 @@ repos:
rev: v3.13.0
- repo: https://github.com/pycqa/isort
rev: 5.12.0
rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/psf/black
rev: 23.11.0
rev: 24.10.0
hooks:
- id: black
# It is recommended to specify the latest version of Python
+4 -3
View File
@@ -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:
[
@@ -109,6 +109,7 @@ services:
POSTGRES_PASSWORD: "speckle"
POSTGRES_DB: "speckle"
ENABLE_MP: "false"
FRONTEND_ORIGIN: "http://127.0.0.1:8080"
networks:
default:
Generated
+947 -860
View File
File diff suppressed because it is too large Load Diff
+9 -11
View File
@@ -9,36 +9,35 @@ repository = "https://github.com/specklesystems/speckle-py"
documentation = "https://speckle.guide/dev/py-examples.html"
homepage = "https://speckle.systems/"
packages = [
{ include = "specklepy", from = "src" },
{ include = "speckle_automate", from = "src" },
{ include = "specklepy", from = "src" },
{ include = "speckle_automate", from = "src" },
]
[tool.poetry.dependencies]
python = ">=3.8.0, <4.0"
python = ">=3.9.0, <4.0"
pydantic = "^2.5"
appdirs = "^1.4.4"
gql = { extras = ["requests", "websockets"], version = "^3.3.0" }
ujson = "^5.3.0"
Deprecated = "^1.2.13"
stringcase = "^1.2.0"
attrs = "^23.1.0"
httpx = "^0.25.0"
[tool.poetry.group.dev.dependencies]
black = "23.11.0"
isort = "^5.7.0"
black = "24.10.0"
isort = "^5.13.2"
pytest = "^7.1.3"
pytest-asyncio = "^0.23.0"
pytest-ordering = "^0.6"
pytest-cov = "^3.0.0"
devtools = "^0.8.0"
pylint = "^2.14.4"
pylint = "^3.3.2"
pydantic-settings = "^2.3.0"
mypy = "^0.982"
pre-commit = "^2.20.0"
commitizen = "^2.38.0"
ruff = "^0.4.4"
commitizen = "^3.13.0"
ruff = "^0.8.2"
types-deprecated = "^1.2.9"
types-ujson = "^5.6.0.0"
types-requests = "^2.28.11.5"
@@ -60,8 +59,7 @@ exclude = '''
'''
include = '\.pyi?$'
line-length = 88
target-version = ["py37", "py38", "py39", "py310", "py311"]
target-version = ["py39", "py310", "py311", "py312", "py313"]
[tool.commitizen]
name = "cz_conventional_commits"
+11 -2
View File
@@ -101,8 +101,17 @@ class AutomationContext:
commit = self.speckle_client.commit.get(
self.automation_run_data.project_id, version_id
)
if not commit.referencedObject:
raise ValueError("The commit has no referencedObject, cannot receive it.")
if not commit or not commit.referencedObject:
raise ValueError(
f"""\
Could not receive specified version.
{"The commit has no referencedObject." if not commit.referencedObject else ""}
Is your environment configured correctly?
project_id: {self.automation_run_data.project_id}
model_id: {self.automation_run_data.triggers[0].payload.model_id}
version_id: {self.automation_run_data.triggers[0].payload.version_id}
"""
)
base = operations.receive(
commit.referencedObject, self._server_transport, self._memory_transport
)
+1
View File
@@ -1,4 +1,5 @@
"""Some useful helpers for working with automation data."""
import secrets
import string
+4 -8
View File
@@ -61,15 +61,13 @@ def _parse_input_data(
def execute_automate_function(
automate_function: AutomateFunction[T],
input_schema: type[T],
) -> None:
...
) -> None: ...
@overload
def execute_automate_function(
automate_function: AutomateFunctionWithoutInputs,
) -> None:
...
) -> None: ...
class AutomateGenerateJsonSchema(GenerateJsonSchema):
@@ -146,16 +144,14 @@ def run_function(
automation_context: AutomationContext,
automate_function: AutomateFunction[T],
inputs: T,
) -> AutomationContext:
...
) -> AutomationContext: ...
@overload
def run_function(
automation_context: AutomationContext,
automate_function: AutomateFunctionWithoutInputs,
) -> AutomationContext:
...
) -> AutomationContext: ...
def run_function(
+4 -4
View File
@@ -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=()
)
+2 -2
View File
@@ -7,12 +7,12 @@ from specklepy.api.resources import (
OtherUserResource,
ProjectInviteResource,
ProjectResource,
ServerResource,
SubscriptionResource,
VersionResource,
branch,
commit,
object,
server,
stream,
subscriptions,
user,
@@ -69,7 +69,7 @@ class SpeckleClient(CoreSpeckleClient):
self.account = Account()
def _init_resources(self) -> None:
self.server = server.Resource(
self.server = ServerResource(
account=self.account, basepath=self.url, client=self.httpclient
)
@@ -3,8 +3,7 @@ from typing import List, Optional, overload
from deprecated import deprecated
from specklepy.core.api.inputs.project_inputs import UserProjectsFilter
from specklepy.core.api.inputs.user_inputs import UserUpdateInput
from specklepy.core.api.inputs.user_inputs import UserProjectsFilter, UserUpdateInput
from specklepy.core.api.models import (
PendingStreamCollaborator,
Project,
@@ -44,12 +43,10 @@ class ActiveUserResource(CoreResource):
company: Optional[str] = None,
bio: Optional[str] = None,
avatar: Optional[str] = None,
) -> User:
...
) -> User: ...
@overload
def update(self, *, input: UserUpdateInput) -> User:
...
def update(self, *, input: UserUpdateInput) -> User: ...
def update(
self,
@@ -4,6 +4,6 @@ from specklepy.api.resources import ServerResource
from specklepy.core.api.models.deprecated import FE1_DEPRECATION_VERSION
@deprecated(reason="Renamed to ActiveUserResource", version=FE1_DEPRECATION_VERSION)
@deprecated(reason="Renamed to ServerResource", version=FE1_DEPRECATION_VERSION)
class Resource(ServerResource):
"""Renamed to ServerResource"""
+1 -1
View File
@@ -4,7 +4,7 @@ from enum import Enum
class ProjectVisibility(str, Enum):
PRIVATE = "PRIVATE"
PUBLIC = "PUBLIC"
UNLISTEd = "UNLISTED"
UNLISTED = "UNLISTED"
class UserProjectsUpdatedMessageType(str, Enum):
+42
View File
@@ -0,0 +1,42 @@
from specklepy.core.api.inputs.model_inputs import (
CreateModelInput,
DeleteModelInput,
ModelVersionsFilter,
UpdateModelInput,
)
from specklepy.core.api.inputs.project_inputs import (
ProjectCreateInput,
ProjectInviteCreateInput,
ProjectInviteUseInput,
ProjectModelsFilter,
ProjectUpdateInput,
ProjectUpdateRoleInput,
)
from specklepy.core.api.inputs.user_inputs import UserProjectsFilter, UserUpdateInput
from specklepy.core.api.inputs.version_inputs import (
CreateVersionInput,
DeleteVersionsInput,
MarkReceivedVersionInput,
MoveVersionsInput,
UpdateVersionInput,
)
__all__ = [
"CreateModelInput",
"DeleteModelInput",
"UpdateModelInput",
"ModelVersionsFilter",
"ProjectCreateInput",
"ProjectInviteCreateInput",
"ProjectInviteUseInput",
"ProjectModelsFilter",
"ProjectUpdateInput",
"ProjectUpdateRoleInput",
"UserProjectsFilter",
"UserUpdateInput",
"UpdateVersionInput",
"MoveVersionsInput",
"DeleteVersionsInput",
"CreateVersionInput",
"MarkReceivedVersionInput",
]
@@ -45,8 +45,3 @@ class ProjectUpdateRoleInput(BaseModel):
userId: str
projectId: str
role: Optional[str]
class UserProjectsFilter(BaseModel):
search: str
onlyWithRole: Optional[Sequence[str]] = None
+6 -1
View File
@@ -1,4 +1,4 @@
from typing import Optional
from typing import Optional, Sequence
from pydantic import BaseModel
@@ -8,3 +8,8 @@ class UserUpdateInput(BaseModel):
bio: Optional[str] = None
company: Optional[str] = None
name: Optional[str] = None
class UserProjectsFilter(BaseModel):
search: str
onlyWithRoles: Optional[Sequence[str]] = None
@@ -29,8 +29,6 @@ from specklepy.core.api.models.deprecated import (
Stream,
Streams,
)
from specklepy.core.api.models.instances import InstanceDefinitionProxy, InstanceProxy
from specklepy.core.api.models.proxies import ColorProxy, GroupProxy
from specklepy.core.api.models.subscription_messages import (
ProjectModelsUpdatedMessage,
ProjectUpdatedMessage,
@@ -70,8 +68,4 @@ __all__ = [
"Streams",
"Activity",
"ActivityCollection",
"InstanceProxy",
"InstanceDefinitionProxy",
"ColorProxy",
"GroupProxy",
]
+1 -1
View File
@@ -126,7 +126,7 @@ class Version(BaseModel):
class Model(BaseModel):
author: LimitedUser
author: Optional[LimitedUser]
createdAt: datetime
description: Optional[str]
displayName: str
@@ -1,28 +0,0 @@
from specklepy.objects.base import Base
class InstanceProxy(
Base,
speckle_type="Speckle.Core.Models.Instances.InstanceProxy",
):
"""
A proxy class for an instance (e.g, a rhino block, or an autocad block reference).
"""
definitionId: str
transform: list[float]
units: str
maxDepth: int
class InstanceDefinitionProxy(
Base,
speckle_type="Speckle.Core.Models.Instances.InstanceDefinitionProxy",
):
"""
A proxy class for an instance definition.
"""
objects: list[str]
maxDepth: int
name: str
-27
View File
@@ -1,27 +0,0 @@
from specklepy.objects.base import Base
class ColorProxy(
Base,
speckle_type="Speckle.Core.Models.Proxies.ColorProxy",
):
"""
Represents a color that is found on objects and collections in a root collection.
"""
objects: list[str]
value: int
name: str | None # nullable but required
class GroupProxy(
Base,
speckle_type="Speckle.Core.Models.Proxies.GroupProxy",
):
"""
Grouped objects with a meaningful way for host application so use this proxy if you want to group object references for any purpose.
i.e. in rhino -> creating group make objects selectable/moveable/editable together.
"""
objects: list[str]
name: str
@@ -4,8 +4,7 @@ from typing import List, Optional, overload
from deprecated import deprecated
from gql import gql
from specklepy.core.api.inputs.project_inputs import UserProjectsFilter
from specklepy.core.api.inputs.user_inputs import UserUpdateInput
from specklepy.core.api.inputs.user_inputs import UserProjectsFilter, UserUpdateInput
from specklepy.core.api.models import (
ActivityCollection,
PendingStreamCollaborator,
@@ -100,12 +99,10 @@ class ActiveUserResource(ResourceBase):
company: Optional[str] = None,
bio: Optional[str] = None,
avatar: Optional[str] = None,
) -> User:
...
) -> User: ...
@overload
def update(self, *, input: UserUpdateInput) -> User:
...
def update(self, *, input: UserUpdateInput) -> User: ...
def update(
self,
@@ -127,9 +127,11 @@ class ModelResource(ResourceBase):
"modelId": model_id,
"versionsLimit": versions_limit,
"versionsCursor": versions_cursor,
"versionsFilter": versions_filter.model_dump(warnings="error")
if versions_filter
else None,
"versionsFilter": (
versions_filter.model_dump(warnings="error")
if versions_filter
else None
),
}
return self.make_request_and_parse_response(
@@ -179,9 +181,9 @@ class ModelResource(ResourceBase):
"projectId": project_id,
"modelsLimit": models_limit,
"modelsCursor": models_cursor,
"modelsFilter": models_filter.model_dump(warnings="error")
if models_filter
else None,
"modelsFilter": (
models_filter.model_dump(warnings="error") if models_filter else None
),
}
return self.make_request_and_parse_response(
@@ -108,9 +108,9 @@ class ProjectResource(ResourceBase):
"projectId": project_id,
"modelsLimit": models_limit,
"modelsCursor": models_cursor,
"modelsFilter": models_filter.model_dump(warnings="error")
if models_filter
else None,
"modelsFilter": (
models_filter.model_dump(warnings="error") if models_filter else None
),
}
return self.make_request_and_parse_response(
@@ -111,7 +111,7 @@ class Resource(ResourceBase):
query = gql(
"""
query User($stream_limit: Int!) {
user {
activeUser {
id
bio
name
@@ -149,7 +149,7 @@ class Resource(ResourceBase):
params = {"stream_limit": stream_limit}
return self.make_request(
query=query, params=params, return_type=["user", "streams", "items"]
query=query, params=params, return_type=["activeUser", "streams", "items"]
)
@deprecated(reason=FE1_DEPRECATION_REASON, version=FE1_DEPRECATION_VERSION)
@@ -1,6 +1,7 @@
"""
Provides uniform and consistent path helpers for `specklepy`
"""
import os
import sys
from pathlib import Path
+15
View File
@@ -0,0 +1,15 @@
from typing import Optional
from specklepy.objects.base import Base
class CRS(Base, speckle_type="Objects.GIS.CRS"):
"""A Coordinate Reference System stored in wkt format"""
name: Optional[str] = None
authority_id: Optional[str] = None
wkt: Optional[str] = None
units_native: Optional[str] = None
offset_x: Optional[float] = None
offset_y: Optional[float] = None
rotation: Optional[float] = None
+24
View File
@@ -0,0 +1,24 @@
"""Builtin Speckle object kit."""
from specklepy.objects.GIS.CRS import CRS
from specklepy.objects.GIS.geometry import (
GisLineElement,
GisPointElement,
GisPolygonElement,
GisPolygonGeometry,
GisRasterElement,
PolygonGeometry,
)
from specklepy.objects.GIS.layers import RasterLayer, VectorLayer
__all__ = [
"VectorLayer",
"RasterLayer",
"GisPolygonGeometry",
"PolygonGeometry",
"GisPolygonElement",
"GisLineElement",
"GisPointElement",
"GisRasterElement",
"CRS",
]
+74
View File
@@ -0,0 +1,74 @@
from typing import List, Optional, Union
from specklepy.objects.base import Base
from specklepy.objects.geometry import (
Arc,
Circle,
Line,
Mesh,
Point,
Polycurve,
Polyline,
)
class PolygonGeometry(Base, speckle_type="Objects.GIS.PolygonGeometry"):
"""GIS Polygon Geometry"""
boundary: Optional[Polyline]
voids: Optional[List[Polyline]]
GisPolygonGeometry = PolygonGeometry
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
class GisPointElement(Base, speckle_type="Objects.GIS.PointElement"):
"""GIS Point element"""
geometry: Optional[List[Point]] = None
attributes: Optional[Base] = None
class GisRasterElement(
Base, speckle_type="Objects.GIS.RasterElement", detachable={"displayValue"}
):
"""GIS Raster element"""
band_count: Optional[int] = None
band_names: Optional[List[str]] = None
x_origin: Optional[float] = None
y_origin: Optional[float] = None
x_size: Optional[int] = None
y_size: Optional[int] = None
x_resolution: Optional[float] = None
y_resolution: Optional[float] = None
noDataValue: Optional[List[float]] = None
displayValue: Optional[List[Mesh]] = None
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
+142
View File
@@ -0,0 +1,142 @@
from typing import Any, Dict, List, Optional, Union
from deprecated import deprecated
from specklepy.objects.base import Base
from specklepy.objects.GIS.CRS import CRS
from specklepy.objects.other import Collection
@deprecated(version="2.15", reason="Use VectorLayer or RasterLayer instead")
class Layer(Base, detachable={"features"}):
"""A GIS Layer"""
def __init__(
self,
name: Optional[str] = None,
crs: Optional[CRS] = None,
units: str = "m",
features: Optional[List[Base]] = None,
layerType: str = "None",
geomType: str = "None",
renderer: Optional[Dict[str, Any]] = None,
**kwargs,
) -> None:
super().__init__(**kwargs)
self.name = name
self.crs = crs
self.units = units
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
class VectorLayer( # noqa: F811
Collection,
detachable={"elements"},
speckle_type="Objects.GIS.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
class RasterLayer( # noqa: F811
Collection,
detachable={"elements"},
speckle_type="Objects.GIS.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
+11 -1
View File
@@ -1,6 +1,14 @@
"""Builtin Speckle object kit."""
from specklepy.objects import encoding, geometry, other, primitive, units
from specklepy.objects import (
GIS,
encoding,
geometry,
other,
primitive,
structural,
units,
)
from specklepy.objects.base import Base
__all__ = [
@@ -9,5 +17,7 @@ __all__ = [
"geometry",
"other",
"units",
"structural",
"primitive",
"GIS",
]
+2 -2
View File
@@ -16,7 +16,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, SpeckleInvalidUnitException
from specklepy.objects.units import Units
@@ -148,7 +148,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__}"
+98 -13
View File
@@ -1,12 +1,13 @@
from typing import List, Optional
from typing import Any, List, Optional
from deprecated import deprecated
from specklepy.objects.geometry import Point, Vector
from specklepy.objects.geometry import Plane, Point, Polyline, Vector
from .base import Base
OTHER = "Objects.Other."
OTHER_REVIT = OTHER + "Revit."
IDENTITY_TRANSFORM = [
1.0,
@@ -28,6 +29,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
@@ -37,16 +53,36 @@ class RenderMaterial(Base, speckle_type=OTHER + "RenderMaterial"):
emissive: int = -16777216 # black arbg
class RenderMaterialProxy(
Base,
speckle_type="Speckle.Core.Models.Proxies.RenderMaterialProxy",
):
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"):
"""
Used to store render material to object relationships in root collections.
Minimal display style class.
Developed primarily for display styles in Rhino and AutoCAD.
Rhino object attributes uses OpenNURBS definition for linetypes and lineweights.
"""
objects: list[str]
value: RenderMaterial
name: Optional[str] = None
color: int = -2894893 # light gray arbg
linetype: Optional[str] = None
lineweight: float = 0
class Text(Base, speckle_type=OTHER + "Text"):
"""
Text object to render it on viewer.
"""
plane: Plane
value: str
height: float
rotation: float
displayValue: Optional[List[Polyline]] = None
richText: Optional[str] = None
class Transform(
@@ -217,10 +253,59 @@ class Transform(
return cls(value=value)
class Collection(
Base,
speckle_type="Speckle.Core.Models.Collections.Collection",
detachable={"elements"},
class BlockDefinition(
Base, speckle_type=OTHER + "BlockDefinition", detachable={"geometry"}
):
name: Optional[str] = None
basePoint: Optional[Point] = None
geometry: Optional[List[Base]] = None
class Instance(Base, speckle_type=OTHER + "Instance", detachable={"definition"}):
transform: Optional[Transform] = None
definition: Optional[Base] = None
class BlockInstance(
Instance, speckle_type=OTHER + "BlockInstance", serialize_ignore={"blockDefinition"}
):
@property
@deprecated(version="2.13", reason="Use definition")
def blockDefinition(self) -> Optional[BlockDefinition]:
if isinstance(self.definition, BlockDefinition):
return self.definition
return None
@blockDefinition.setter
def blockDefinition(self, value: Optional[BlockDefinition]) -> None:
self.definition = value
class RevitInstance(Instance, speckle_type=OTHER_REVIT + "RevitInstance"):
level: Optional[Base] = None
facingFlipped: bool
handFlipped: bool
parameters: Optional[Base] = None
elementId: Optional[str]
# 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: Optional[str] = None
value: Any = None
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
class Collection(
Base, speckle_type="Speckle.Core.Models.Collection", detachable={"elements"}
):
name: Optional[str] = None
collectionType: Optional[str] = None
elements: Optional[List[Base]] = None
@@ -0,0 +1,142 @@
"""Builtin Speckle object kit."""
from specklepy.objects.structural.analysis import (
Model,
ModelInfo,
ModelSettings,
ModelUnits,
)
from specklepy.objects.structural.axis import Axis, AxisType
from specklepy.objects.structural.geometry import (
Element1D,
Element2D,
Element3D,
ElementType1D,
ElementType2D,
ElementType3D,
Node,
Restraint,
)
from specklepy.objects.structural.loading import (
ActionType,
BeamLoadType,
CombinationType,
FaceLoadType,
Load,
LoadAxisType,
LoadBeam,
LoadCase,
LoadCombinations,
LoadDirection,
LoadDirection2D,
LoadFace,
LoadGravity,
LoadNode,
LoadType,
)
from specklepy.objects.structural.materials import (
Concrete,
MaterialType,
Steel,
StructuralMaterial,
Timber,
)
from specklepy.objects.structural.properties import (
BaseReferencePoint,
MemberType,
Property,
Property1D,
Property2D,
Property3D,
PropertyDamper,
PropertyMass,
PropertySpring,
PropertyType2D,
PropertyType3D,
PropertyTypeDamper,
PropertyTypeSpring,
ReferenceSurface,
ReferenceSurfaceEnum,
SectionProfile,
ShapeType,
shapeType,
)
from specklepy.objects.structural.results import (
Result,
Result1D,
Result2D,
Result3D,
ResultGlobal,
ResultNode,
ResultSet1D,
ResultSet2D,
ResultSet3D,
ResultSetAll,
ResultSetNode,
)
__all__ = [
"Element1D",
"Element2D",
"Element3D",
"ElementType1D",
"ElementType2D",
"ElementType3D",
"AxisType",
"Axis",
"Node",
"Restraint",
"Load",
"LoadType",
"ActionType",
"BeamLoadType",
"FaceLoadType",
"LoadDirection",
"LoadDirection2D",
"LoadAxisType",
"CombinationType",
"LoadBeam",
"LoadCase",
"LoadCombinations",
"LoadFace",
"LoadGravity",
"LoadNode",
"Model",
"ModelInfo",
"ModelSettings",
"ModelUnits",
"MaterialType",
"Concrete",
"StructuralMaterial",
"Steel",
"Timber",
"Property",
"Property1D",
"Property2D",
"Property3D",
"PropertyDamper",
"PropertyMass",
"PropertySpring",
"SectionProfile",
"MemberType",
"BaseReferencePoint",
"ReferenceSurface",
"PropertyType2D",
"PropertyType3D",
"ShapeType",
"PropertyTypeSpring",
"PropertyTypeDamper",
"ReferenceSurfaceEnum",
"shapeType",
"Result",
"Result1D",
"ResultSet1D",
"Result2D",
"ResultSet2D",
"Result3D",
"ResultSet3D",
"ResultGlobal",
"ResultSetNode",
"ResultNode",
"ResultSetAll",
]
@@ -0,0 +1,49 @@
from typing import List, Optional
from specklepy.objects.base import Base
STRUCTURAL_ANALYSIS = "Objects.Structural.Analysis."
class ModelUnits(Base, speckle_type=STRUCTURAL_ANALYSIS + "ModelUnits"):
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: Optional[ModelUnits] = None
steelCode: Optional[str] = None
concreteCode: Optional[str] = None
coincidenceTolerance: float = 0.0
class ModelInfo(Base, speckle_type=STRUCTURAL_ANALYSIS + "ModelInfo"):
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: 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
+17
View File
@@ -0,0 +1,17 @@
from enum import Enum
from typing import Optional
from specklepy.objects.base import Base
from specklepy.objects.geometry import Plane
class AxisType(int, Enum):
Cartesian = 0
Cylindrical = 1
Spherical = 2
class Axis(Base, speckle_type="Objects.Structural.Geometry.Axis"):
name: Optional[str] = None
axisType: Optional[AxisType] = None
plane: Optional[Plane] = None
@@ -0,0 +1,110 @@
from enum import Enum
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,
Property3D,
PropertyDamper,
PropertyMass,
PropertySpring,
)
STRUCTURAL_GEOMETRY = "Objects.Structural.Geometry"
class ElementType1D(int, Enum):
Beam = 0
Brace = 1
Bar = 2
Column = 3
Rod = 4
Spring = 5
Tie = 6
Strut = 7
Link = 8
Damper = 9
Cable = 10
Spacer = 11
Other = 12
Null = 13
class ElementType2D(int, Enum):
Quad4 = 0
Quad8 = 1
Triangle3 = 2
Triangle6 = 3
class ElementType3D(int, Enum):
Brick8 = 0
Wedge6 = 1
Pyramid5 = 2
Tetra4 = 3
class Restraint(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Restraint"):
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
class Node(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Node"):
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
class Element1D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element1D"):
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: Optional[Plane] = None
parent: Optional[Base] = None
end1Node: Optional[Node] = None
end2Node: Optional[Node] = None
topology: Optional[List] = None
displayMesh: Optional[Mesh] = None
class Element2D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element2D"):
name: Optional[str] = None
property: Optional[Property2D] = None
type: Optional[ElementType2D] = None
offset: float = 0.0
orientationAngle: float = 0.0
parent: Optional[Base] = None
topology: Optional[List] = None
displayMesh: Optional[Mesh] = None
class Element3D(Base, speckle_type=STRUCTURAL_GEOMETRY + ".Element3D"):
name: Optional[str] = None
baseMesh: Optional[Mesh] = None
property: Optional[Property3D] = None
type: Optional[ElementType3D] = None
orientationAngle: float = 0.0
parent: Optional[Base] = None
topology: List
# class Storey needs ependency on built elements first
+137
View File
@@ -0,0 +1,137 @@
from enum import Enum
from typing import List, Optional
from specklepy.objects.base import Base
from specklepy.objects.geometry import Vector
from specklepy.objects.structural.axis import Axis
STRUCTURAL_LOADING = "Objects.Structural.Loading."
class LoadType(int, Enum):
none = 0
Dead = 1
SuperDead = 2
Soil = 3
Live = 4
LiveRoof = 5
ReducibleLive = 6
Wind = 7
Snow = 8
Rain = 9
Thermal = 10
Notional = 11
Prestress = 12
Equivalent = 13
Accidental = 14
SeismicRSA = 15
SeismicAccTorsion = 16
SeismicStatic = 17
Other = 18
class ActionType(int, Enum):
none = 0
Permanent = 1
Variable = 2
Accidental = 3
class BeamLoadType(int, Enum):
Point = 0
Uniform = 1
Linear = 2
Patch = 3
TriLinear = 4
class FaceLoadType(int, Enum):
Constant = 0
Variable = 1
Point = 2
class LoadDirection2D(int, Enum):
X = 0
Y = 1
Z = 2
class LoadDirection(int, Enum):
X = 0
Y = 1
Z = 2
XX = 3
YY = 4
ZZ = 5
class LoadAxisType(int, Enum):
Global = 0
Local = 1 # local element axes
DeformedLocal = (
2 # element local axis that is embedded in the element as it deforms
)
class CombinationType(int, Enum):
LinearAdd = 0
Envelope = 1
AbsoluteAdd = 2
SRSS = 3
RangeAdd = 4
class LoadCase(Base, speckle_type=STRUCTURAL_LOADING + "LoadCase"):
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: Optional[str] = None
loadCase: Optional[LoadCase] = None
class LoadBeam(Load, speckle_type=STRUCTURAL_LOADING + "LoadBeam"):
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: Optional[str] = None
loadCases: List
loadFactors: List
combinationType: CombinationType
class LoadFace(Load, speckle_type=STRUCTURAL_LOADING + "LoadFace"):
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: Optional[List] = None
nodes: Optional[List] = None
gravityFactors: Optional[Vector] = None
class LoadNode(Load, speckle_type=STRUCTURAL_LOADING + "LoadNode"):
nodes: Optional[List] = None
loadAxis: Optional[Axis] = None
direction: Optional[LoadDirection] = None
value: float = 0.0
@@ -0,0 +1,61 @@
from enum import Enum
from typing import Optional
from specklepy.objects.base import Base
STRUCTURAL_MATERIALS = "Objects.Structural.Materials"
class MaterialType(int, Enum):
Concrete = 0
Steel = 1
Timber = 2
Aluminium = 3
Masonry = 4
FRP = 5
Glass = 6
Fabric = 7
Rebar = 8
Tendon = 9
ColdFormed = 10
Other = 11
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
shearModulus: float = 0.0
density: float = 0.0
thermalExpansivity: float = 0.0
dampingRatio: float = 0.0
cost: float = 0.0
materialSafetyFactor: float = 0.0
class Concrete(StructuralMaterial):
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: Optional[bool] = None
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(StructuralMaterial, speckle_type=STRUCTURAL_MATERIALS + ".Timber"):
species: Optional[str] = None
@@ -0,0 +1,212 @@
from enum import Enum
from typing import Optional
from specklepy.objects.base import Base
from specklepy.objects.structural.axis import Axis
from specklepy.objects.structural.materials import StructuralMaterial
STRUCTURAL_PROPERTY = "Objects.Structural.Properties"
class MemberType(int, Enum):
Beam = 0
Column = 1
Generic1D = 2
Slab = 3
Wall = 4
Generic2D = 5
VoidCutter1D = 6
VoidCutter2D = 7
class BaseReferencePoint(int, Enum):
Centroid = 0
TopLeft = 1
TopCentre = 2
TopRight = 3
MidLeft = 4
MidRight = 5
BotLeft = 6
BotCentre = 7
BotRight = 8
class ReferenceSurface(int, Enum):
Top = 0
Middle = 1
Bottom = 2
class PropertyType2D(int, Enum):
Stress = 0
Fabric = 1
Plate = 2
Shell = 3
Curved = 4
Wall = 5
Strain = 6
Axi = 7
Load = 8
class PropertyType3D(int, Enum):
Solid = 0
Infinite = 1
class ShapeType(int, Enum):
Rectangular = 0
Circular = 1
I = 2 # noqa: E741
Tee = 3
Angle = 4
Channel = 5
Perimeter = 6
Box = 7
Catalogue = 8
Explicit = 9
Undefined = 10
class PropertyTypeSpring(int, Enum):
Axial = 0
Torsional = 1
General = 2
Matrix = 3
TensionOnly = 4
CompressionOnly = 5
Connector = 6
LockUp = 7
Gap = 8
Friction = 9
class PropertyTypeDamper(int, Enum):
Axial = 0
Torsional = 1
General = 2
class Property(Base, speckle_type=STRUCTURAL_PROPERTY):
name: Optional[str] = None
class SectionProfile(
Base, speckle_type=STRUCTURAL_PROPERTY + ".Profiles.SectionProfile"
):
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
class Property1D(Property, speckle_type=STRUCTURAL_PROPERTY + ".Property1D"):
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: Optional[PropertyType2D] = None
thickness: float = 0.0
material: Optional[StructuralMaterial] = None
orientationAxis: Optional[Axis] = None
refSurface: Optional[ReferenceSurface] = None
zOffset: float = 0.0
modifierInPlane: float = 0.0
modifierBending: float = 0.0
modifierShear: float = 0.0
modifierVolume: float = 0.0
class Property3D(Property, speckle_type=STRUCTURAL_PROPERTY + ".Property3D"):
type: Optional[PropertyType3D] = None
material: Optional[StructuralMaterial] = None
orientationAxis: Optional[Axis] = None
class PropertyDamper(Property, speckle_type=STRUCTURAL_PROPERTY + ".PropertyDamper"):
damperType: Optional[PropertyTypeDamper] = None
dampingX: float = 0.0
dampingY: float = 0.0
dampingZ: float = 0.0
dampingXX: float = 0.0
dampingYY: float = 0.0
dampingZZ: float = 0.0
class PropertyMass(Property, speckle_type=STRUCTURAL_PROPERTY + ".PropertyMass"):
mass: float = 0.0
inertiaXX: float = 0.0
inertiaYY: float = 0.0
inertiaZZ: float = 0.0
inertiaXY: float = 0.0
inertiaYZ: float = 0.0
inertiaZX: float = 0.0
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: Optional[PropertyTypeSpring] = None
springCurveX: float = 0.0
stiffnessX: float = 0.0
springCurveY: float = 0.0
stiffnessY: float = 0.0
springCurveZ: float = 0.0
stiffnessZ: float = 0.0
springCurveXX: float = 0.0
stiffnessXX: float = 0.0
springCurveYY: float = 0.0
stiffnessYY: float = 0.0
springCurveZZ: float = 0.0
stiffnessZZ: float = 0.0
dampingRatio: float = 0.0
dampingX: float = 0.0
dampingY: float = 0.0
dampingZ: float = 0.0
dampingXX: float = 0.0
dampingYY: float = 0.0
dampingZZ: float = 0.0
matrix: float = 0.0
postiveLockup: float = 0.0
frictionCoefficient: float = 0.0
class ReferenceSurfaceEnum(int, Enum):
Concrete = 0
Steel = 1
Timber = 2
Aluminium = 3
Masonry = 4
FRP = 5
Glass = 6
Fabric = 7
Rebar = 8
Tendon = 9
ColdFormed = 10
Other = 11
class shapeType(int, Enum):
Concrete = 0
Steel = 1
Timber = 2
Aluminium = 3
Masonry = 4
FRP = 5
Glass = 6
Fabric = 7
Rebar = 8
Tendon = 9
ColdFormed = 10
Other = 11
+172
View File
@@ -0,0 +1,172 @@
from typing import List, Optional
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: Optional[Base] = None
permutation: Optional[str] = None
description: Optional[str] = None
class ResultSet1D(Result, speckle_type=STRUCTURAL_RESULTS + "ResultSet1D"):
results1D: List
class Result1D(Result, speckle_type=STRUCTURAL_RESULTS + "Result1D"):
element: Optional[Element1D] = None
position: Optional[float] = None
dispX: Optional[float] = None
dispY: Optional[float] = None
dispZ: Optional[float] = None
rotXX: Optional[float] = None
rotYY: Optional[float] = None
rotZZ: Optional[float] = None
forceX: Optional[float] = None
forceY: Optional[float] = None
forceZ: Optional[float] = None
momentXX: Optional[float] = None
momentYY: Optional[float] = None
momentZZ: Optional[float] = None
axialStress: Optional[float] = None
shearStressY: Optional[float] = None
shearStressZ: Optional[float] = None
bendingStressYPos: Optional[float] = None
bendingStressYNeg: Optional[float] = None
bendingStressZPos: Optional[float] = None
bendingStressZNeg: Optional[float] = None
combinedStressMax: Optional[float] = None
combinedStressMin: Optional[float] = None
class ResultSet2D(Result, speckle_type=STRUCTURAL_RESULTS + "ResultSet2D"):
results2D: List
class Result2D(Result, speckle_type=STRUCTURAL_RESULTS + "Result2D"):
element: Optional[Element2D] = None
position: List
dispX: Optional[float] = None
dispY: Optional[float] = None
dispZ: Optional[float] = None
forceXX: Optional[float] = None
forceYY: Optional[float] = None
forceXY: Optional[float] = None
momentXX: Optional[float] = None
momentYY: Optional[float] = None
momentXY: Optional[float] = None
shearX: Optional[float] = None
shearY: Optional[float] = None
stressTopXX: Optional[float] = None
stressTopYY: Optional[float] = None
stressTopZZ: Optional[float] = None
stressTopXY: Optional[float] = None
stressTopYZ: Optional[float] = None
stressTopZX: Optional[float] = None
stressMidXX: Optional[float] = None
stressMidYY: Optional[float] = None
stressMidZZ: Optional[float] = None
stressMidXY: Optional[float] = None
stressMidYZ: Optional[float] = None
stressMidZX: Optional[float] = None
stressBotXX: Optional[float] = None
stressBotYY: Optional[float] = None
stressBotZZ: Optional[float] = None
stressBotXY: Optional[float] = None
stressBotYZ: Optional[float] = None
stressBotZX: Optional[float] = None
class ResultSet3D(Result, speckle_type=STRUCTURAL_RESULTS + "ResultSet3D"):
results3D: List
class Result3D(Result, speckle_type=STRUCTURAL_RESULTS + "Result3D"):
element: Optional[Element3D] = None
position: List
dispX: Optional[float] = None
dispY: Optional[float] = None
dispZ: Optional[float] = None
stressXX: Optional[float] = None
stressYY: Optional[float] = None
stressZZ: Optional[float] = None
stressXY: Optional[float] = None
stressYZ: Optional[float] = None
stressZX: Optional[float] = None
class ResultGlobal(Result, speckle_type=STRUCTURAL_RESULTS + "ResultGlobal"):
model: Optional[Model] = None
loadX: Optional[float] = None
loadY: Optional[float] = None
loadZ: Optional[float] = None
loadXX: Optional[float] = None
loadYY: Optional[float] = None
loadZZ: Optional[float] = None
reactionX: Optional[float] = None
reactionY: Optional[float] = None
reactionZ: Optional[float] = None
reactionXX: Optional[float] = None
reactionYY: Optional[float] = None
reactionZZ: Optional[float] = None
mode: Optional[float] = None
frequency: Optional[float] = None
loadFactor: Optional[float] = None
modalStiffness: Optional[float] = None
modalGeoStiffness: Optional[float] = None
effMassX: Optional[float] = None
effMassY: Optional[float] = None
effMassZ: Optional[float] = None
effMassXX: Optional[float] = None
effMassYY: Optional[float] = None
effMassZZ: Optional[float] = None
class ResultSetNode(Result, speckle_type=STRUCTURAL_RESULTS + "ResultSetNode"):
resultsNode: List
class ResultNode(Result, speckle_type=STRUCTURAL_RESULTS + " ResultNode"):
node: Optional[Node] = None
dispX: Optional[float] = None
dispY: Optional[float] = None
dispZ: Optional[float] = None
rotXX: Optional[float] = None
rotYY: Optional[float] = None
rotZZ: Optional[float] = None
reactionX: Optional[float] = None
reactionY: Optional[float] = None
reactionZ: Optional[float] = None
reactionXX: Optional[float] = None
reactionYY: Optional[float] = None
reactionZZ: Optional[float] = None
constraintX: Optional[float] = None
constraintY: Optional[float] = None
constraintZ: Optional[float] = None
constraintXX: Optional[float] = None
constraintYY: Optional[float] = None
constraintZZ: Optional[float] = None
velX: Optional[float] = None
velY: Optional[float] = None
velZ: Optional[float] = None
velXX: Optional[float] = None
velYY: Optional[float] = None
velZZ: Optional[float] = None
accX: Optional[float] = None
accY: Optional[float] = None
accZ: Optional[float] = None
accXX: Optional[float] = None
accYY: Optional[float] = None
accZZ: Optional[float] = None
class ResultSetAll(Base, speckle_type=None):
resultSet1D: Optional[ResultSet1D] = None
resultSet2D: Optional[ResultSet2D] = None
resultSet3D: Optional[ResultSet3D] = None
resultsGlobal: Optional[ResultGlobal] = None
resultsNode: Optional[ResultSetNode] = None
+6 -1
View File
@@ -86,6 +86,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
@@ -93,7 +99,6 @@ class ServerTransport(AbstractTransport):
self.session.headers.update(
{
"Authorization": f"Bearer {self.account.token}",
"Accept": "text/plain",
}
)
@@ -2,7 +2,7 @@ import pytest
from specklepy.api.client import SpeckleClient
from specklepy.core.api.inputs.project_inputs import ProjectCreateInput
from specklepy.core.api.inputs.user_inputs import UserUpdateInput
from specklepy.core.api.inputs.user_inputs import UserProjectsFilter, UserUpdateInput
from specklepy.core.api.models import ResourceCollection, User
@@ -42,3 +42,21 @@ class TestActiveUserResource:
assert len(res.items) == len(existing.items) + 2
assert any(project.id == p1.id for project in res.items)
assert any(project.id == p2.id for project in res.items)
def test_active_user_get_projects_with_filter(self, client: SpeckleClient):
# Since the client may be reused for other tests,
# this test does rely on no other test creating a project with "Search for me" in its name
p1 = client.project.create(
ProjectCreateInput(name="Search for me!", description=None, visibility=None)
)
_ = client.project.create(
ProjectCreateInput(name="But not me!", description=None, visibility=None)
)
filter = UserProjectsFilter(search="Search for me")
res = client.active_user.get_projects(filter=filter)
assert isinstance(res, ResourceCollection)
assert len(res.items) == 1
assert res.totalCount == 1
assert res.items[0].id == p1.id
@@ -6,7 +6,10 @@ from specklepy.core.api.inputs.model_inputs import (
DeleteModelInput,
UpdateModelInput,
)
from specklepy.core.api.inputs.project_inputs import ProjectCreateInput
from specklepy.core.api.inputs.project_inputs import (
ProjectCreateInput,
ProjectModelsFilter,
)
from specklepy.core.api.models.current import (
Model,
Project,
@@ -65,6 +68,18 @@ class TestModelResource:
assert result.createdAt == test_model.createdAt
assert result.updatedAt == test_model.updatedAt
def test_models_get_with_filter(
self, client: SpeckleClient, test_model: Model, test_project: Project
):
filter = ProjectModelsFilter(search=test_model.name)
result = client.model.get_models(test_project.id, models_filter=filter)
assert isinstance(result, ResourceCollection)
assert len(result.items) == 1
assert result.totalCount == 1
assert result.items[0].id == test_model.id
def test_get_models(
self, client: SpeckleClient, test_project: Project, test_model: Model
):
@@ -82,6 +97,20 @@ class TestModelResource:
assert isinstance(result, ProjectWithModels)
assert result.id == test_project.id
assert isinstance(result.models, ResourceCollection)
assert len(result.models.items) == 1
assert result.models.totalCount == 1
assert result.models.items[0].id == test_model.id
def test_project_get_models_with_filter(
self, client: SpeckleClient, test_project: Project, test_model: Model
):
filter = ProjectModelsFilter(search=test_model.name)
result = client.project.get_with_models(test_project.id, models_filter=filter)
assert isinstance(result, ProjectWithModels)
assert result.id == test_project.id
assert isinstance(result.models, ResourceCollection)
assert len(result.models.items) == 1
assert result.models.totalCount == 1
assert result.models.items[0].id == test_model.id
@@ -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."""
@@ -1,7 +1,7 @@
import pytest
from specklepy.api.client import SpeckleClient
from specklepy.core.api.inputs.model_inputs import CreateModelInput
from specklepy.core.api.inputs.model_inputs import CreateModelInput, ModelVersionsFilter
from specklepy.core.api.inputs.project_inputs import ProjectCreateInput
from specklepy.core.api.inputs.version_inputs import (
DeleteVersionsInput,
@@ -76,6 +76,26 @@ class TestVersionResource:
assert result.totalCount == 1
assert result.items[0].id == test_version.id
def test_versions_get_with_filter(
self,
client: SpeckleClient,
test_model_1: Model,
test_project: Project,
test_version: Version,
):
filter = ModelVersionsFilter(
priorityIds=[test_version.id], priorityIdsOnly=True
)
result = client.version.get_versions(
test_model_1.id, test_project.id, filter=filter
)
assert isinstance(result, ResourceCollection)
assert len(result.items) == 1
assert result.totalCount == 1
assert result.items[0].id == test_version.id
def test_version_received(
self, client: SpeckleClient, test_version: Version, test_project: Project
):
@@ -103,6 +123,27 @@ class TestVersionResource:
assert result.versions.totalCount == 1
assert result.versions.items[0].id == test_version.id
def test_model_get_with_versions_with_filter(
self,
client: SpeckleClient,
test_model_1: Model,
test_project: Project,
test_version: Version,
):
filter = ModelVersionsFilter(
priorityIds=[test_version.id], priorityIdsOnly=True
)
result = client.model.get_with_versions(
test_model_1.id, test_project.id, versions_filter=filter
)
assert isinstance(result, ModelWithVersions)
assert len(result.versions.items) == 1
assert result.versions.totalCount == 1
assert isinstance(result.versions, ResourceCollection)
assert result.versions.items[0].id == test_version.id
def test_version_update(
self, client: SpeckleClient, test_version: Version, test_project: Project
):
@@ -4,49 +4,53 @@ from specklepy.api.client import SpeckleClient
from specklepy.api.models import ServerInfo
class TestServer:
@pytest.fixture(scope="module")
def token_info(self):
return {
"token": None,
"name": "super secret token",
"scopes": ["streams:read", "streams:write"],
"lifespan": 9001,
}
@pytest.fixture(scope="module")
def token_info():
return {
"token": None,
"name": "super secret token",
"scopes": ["streams:read", "streams:write"],
"lifespan": 9001,
}
def test_server_get(self, client: SpeckleClient):
server = client.server.get()
assert isinstance(server, ServerInfo)
assert isinstance(server.frontend2, bool)
def test_server_get(client: SpeckleClient):
server = client.server.get()
def test_server_version(self, client: SpeckleClient):
version = client.server.version()
assert isinstance(server, ServerInfo)
assert isinstance(server.frontend2, bool)
assert isinstance(version, tuple)
if len(version) == 1:
assert version[0] == "dev"
else:
assert isinstance(version[0], int)
assert len(version) >= 3
def test_server_apps(self, client: SpeckleClient):
apps = client.server.apps()
def test_server_version(client: SpeckleClient):
version = client.server.version()
assert isinstance(apps, list)
assert len(apps) >= 1
assert any(app["name"] == "Speckle Web Manager" for app in apps)
assert isinstance(version, tuple)
if len(version) == 1:
assert version[0] == "dev"
else:
assert isinstance(version[0], int)
assert len(version) >= 3
def test_server_create_token(self, client, token_info):
token_info["token"] = client.server.create_token(
name=token_info["name"],
scopes=token_info["scopes"],
lifespan=token_info["lifespan"],
)
assert isinstance(token_info["token"], str)
def test_server_apps(client: SpeckleClient):
apps = client.server.apps()
def test_server_revoke_token(self, client, token_info):
revoked = client.server.revoke_token(token=token_info["token"])
assert isinstance(apps, list)
assert len(apps) >= 1
assert any(app["name"] == "Speckle Web Manager" for app in apps)
assert revoked is True
def test_server_create_token(client, token_info):
token_info["token"] = client.server.create_token(
name=token_info["name"],
scopes=token_info["scopes"],
lifespan=token_info["lifespan"],
)
assert isinstance(token_info["token"], str)
def test_server_revoke_token(client, token_info):
revoked = client.server.revoke_token(token=token_info["token"])
assert revoked is True
@@ -1,4 +1,5 @@
"""Run integration tests with a speckle server."""
import os
from pathlib import Path
from typing import Dict
+1 -1
View File
@@ -72,7 +72,7 @@ def line(point, interval):
start=point,
end=point,
domain=interval,
units="none"
units="none",
# These attributes are not handled in C#
# bbox=None,
# length=None
-38
View File
@@ -1,38 +0,0 @@
# pylint: disable=redefined-outer-name
import pytest
from specklepy.core.api.models.instances import InstanceDefinitionProxy, InstanceProxy
@pytest.fixture()
def instance_proxy():
return InstanceProxy(
definitionId="definitionId", transform=[1, 23.5], units="unit", maxDepth=3
)
@pytest.fixture()
def instance_definition_proxy():
return InstanceDefinitionProxy(
objects=["app_id_1", "app_id_2"], maxDepth=2, name="group_proxy_name"
)
def test_create_instance_proxy():
try:
InstanceProxy(definitionId="", transform="", units="", maxDepth=1) # wrong type
assert False
except TypeError:
assert True
except:
assert False
def test_create_instance_definition_proxy():
try:
InstanceDefinitionProxy(objects="", maxDepth=1, name="") # wrong type
assert False
except TypeError:
assert True
except:
assert False
-59
View File
@@ -1,59 +0,0 @@
# pylint: disable=redefined-outer-name
import pytest
from specklepy.core.api.models.proxies import ColorProxy, GroupProxy
from specklepy.objects.other import RenderMaterial, RenderMaterialProxy
@pytest.fixture()
def color_proxy():
return ColorProxy(
objects=["app_id_1", "app_id_2"], value=11111, name="color_proxy_name"
)
@pytest.fixture()
def group_proxy():
return GroupProxy(objects=["app_id_1", "app_id_2"], name="group_proxy_name")
@pytest.fixture()
def material():
return RenderMaterial(
name="name", opacity=0.3, metalness=0, roughness=0, diffuse=1, emissive=1
)
@pytest.fixture()
def material_proxy():
return RenderMaterialProxy(objects=["app_id_1", "app_id_2"], value=material())
def test_create_color_proxy():
try:
ColorProxy(objects="", value=2, name="") # wrong type
assert False
except TypeError:
assert True
except:
assert False
def test_create_group_proxy():
try:
GroupProxy(objects="", name="") # wrong type
assert False
except TypeError:
assert True
except:
assert False
def test_create_material_proxy():
try:
RenderMaterialProxy(objects="", name="") # wrong type
assert False
except TypeError:
assert True
except:
assert False
+4 -4
View File
@@ -3,7 +3,7 @@ from typing import Type
import pytest
from specklepy.objects.base import Base
from specklepy.objects.geometry import Line
from specklepy.objects.structural import Concrete
class Foo(Base):
@@ -29,8 +29,8 @@ class Baz(Bar):
"Tests.Unit.TestRegisteringBase.Foo:Custom.Bar:Tests.Unit.TestRegisteringBase.Baz",
),
(
Line,
"Objects.Geometry.Line",
Concrete,
"Objects.Structural.Materials.StructuralMaterial:Objects.Structural.Materials.Concrete",
),
],
)
@@ -43,7 +43,7 @@ def test_determine_speckle_type(klass: Type[Base], speckle_type: str):
[
(Base, "Base"),
(Foo, "Tests.Unit.TestRegisteringBase.Foo"),
(Line, "Objects.Geometry.Line"),
(Concrete, "Objects.Structural.Materials.Concrete"),
],
)
def test_full_name(klass: Type[Base], fully_qualified_name: str):
+143
View File
@@ -0,0 +1,143 @@
import pytest
from specklepy.objects.geometry import Line, Mesh, Point, Vector
from specklepy.objects.structural.analysis import Model
from specklepy.objects.structural.geometry import (
Element1D,
Element2D,
ElementType1D,
ElementType2D,
Node,
Restraint,
)
from specklepy.objects.structural.loading import LoadGravity
from specklepy.objects.structural.materials import StructuralMaterial
from specklepy.objects.structural.properties import (
MemberType,
Property1D,
Property2D,
SectionProfile,
ShapeType,
)
@pytest.fixture()
def point():
return Point(x=1, y=10, z=0)
@pytest.fixture()
def vector():
return Vector(x=0, y=0, z=-1)
@pytest.fixture()
def line(point, interval):
return Line(
start=point,
end=point,
domain=interval,
# These attributes are not handled in C#
# bbox=None,
# length=None
)
@pytest.fixture()
def mesh(box):
return Mesh(
vertices=[2, 1, 2, 4, 77.3, 5, 33, 4, 2],
faces=[1, 2, 3, 4, 5, 6, 7],
colors=[111, 222, 333, 444, 555, 666, 777],
bbox=box,
area=233,
volume=232.2,
)
@pytest.fixture()
def restraint():
return Restraint(code="FFFFFF")
@pytest.fixture()
def node(restraint, point):
return Node(basePoint=point, restraint=restraint, name="node1")
@pytest.fixture()
def material():
return StructuralMaterial(name="TestMaterial")
@pytest.fixture()
def memberType():
return MemberType(0)
@pytest.fixture()
def shapeType():
return ShapeType(8)
@pytest.fixture()
def sectionProfile(shapeType):
return SectionProfile(name="Test", shapeType=shapeType)
@pytest.fixture()
def property1D(memberType, sectionProfile, material):
return Property1D(
Material=material,
SectionProfile=sectionProfile,
memberType=memberType,
)
@pytest.fixture()
def elementType1D():
return ElementType1D(0)
@pytest.fixture()
def element1D(line, restraint, elementType1D, property1D):
return Element1D(
baseLine=line,
end1Releases=restraint,
end2Releases=restraint,
type=elementType1D,
property=property1D,
)
@pytest.fixture()
def property2D(material):
return Property2D(Material=material)
@pytest.fixture()
def elementType2D():
return ElementType2D(0)
@pytest.fixture()
def element2D(point, elementType2D):
return Element2D(
topology=[point],
type=elementType2D,
)
@pytest.fixture()
def loadGravity(element1D, element2D, vector):
return LoadGravity(elements=[element1D, element2D], gravityFactors=vector)
@pytest.fixture()
def model(loadGravity, element1D, element2D, material, property1D, property2D):
return Model(
loads=[loadGravity],
elements=[element1D, element2D],
materials=[material],
properties=[property1D, property2D],
)
+1
View File
@@ -1,6 +1,7 @@
"""
Provides uniform and consistent path helpers for `specklepy`
"""
import os
import sys
from importlib import import_module, invalidate_caches