Compare commits

..

1 Commits

Author SHA1 Message Date
Jonathon Broughton abc62f0811 AutomateGenerateJsonSchema(GenerateJsonSchema)
Adds additional processing the the OOTB GenerateJsonSchema for types created in pydantic that moves the requirement from users function to the SDK
2024-08-18 16:28:22 +01:00
7 changed files with 604 additions and 856 deletions
+52 -10
View File
@@ -52,26 +52,28 @@ services:
####
# Speckle Server
#######
speckle-frontend:
image: speckle/speckle-frontend-2:latest
image: speckle/speckle-frontend:latest
restart: always
ports:
- "0.0.0.0:8080:8080"
environment:
FILE_SIZE_LIMIT_MB: 100
speckle-server:
image: speckle/speckle-server:latest
restart: always
healthcheck:
test:
- CMD
- /nodejs/bin/node
- -e
- "try { require('node:http').request({headers: {'Content-Type': 'application/json'}, port:3000, hostname:'127.0.0.1', path:'/readiness', method: 'GET', timeout: 2000 }, (res) => { body = ''; res.on('data', (chunk) => {body += chunk;}); res.on('end', () => {process.exit(res.statusCode != 200 || body.toLowerCase().includes('error'));}); }).end(); } catch { process.exit(1); }"
[
"CMD",
"node",
"-e",
"require('node:http').request({headers: {'Content-Type': 'application/json'}, port:3000, hostname:'127.0.0.1', path:'/graphql?query={serverInfo{version}}', method: 'GET' }, (res) => { body = ''; res.on('data', (chunk) => {body += chunk;}); res.on('end', () => {process.exit(res.statusCode != 200 || body.toLowerCase().includes('error'));}); }).end();",
]
interval: 10s
timeout: 10s
retries: 3
start_period: 90s
timeout: 3s
retries: 30
ports:
- "0.0.0.0:3000:3000"
depends_on:
@@ -96,7 +98,6 @@ services:
S3_CREATE_BUCKET: "true"
FILE_SIZE_LIMIT_MB: 100
MAX_PROJECT_MODELS_PER_PAGE: 500
# TODO: Change this to a unique secret for this server
SESSION_SECRET: "TODO:ReplaceWithLongString"
@@ -110,6 +111,47 @@ services:
POSTGRES_DB: "speckle"
ENABLE_MP: "false"
preview-service:
image: speckle/speckle-preview-service:latest
restart: always
depends_on:
speckle-server:
condition: service_healthy
mem_limit: "1000m"
memswap_limit: "1000m"
environment:
DEBUG: "preview-service:*"
PG_CONNECTION_STRING: "postgres://speckle:speckle@postgres/speckle"
webhook-service:
image: speckle/speckle-webhook-service:latest
restart: always
depends_on:
speckle-server:
condition: service_healthy
environment:
DEBUG: "webhook-service:*"
PG_CONNECTION_STRING: "postgres://speckle:speckle@postgres/speckle"
WAIT_HOSTS: postgres:5432
fileimport-service:
image: speckle/speckle-fileimport-service:latest
restart: always
depends_on:
speckle-server:
condition: service_healthy
environment:
DEBUG: "fileimport-service:*"
PG_CONNECTION_STRING: "postgres://speckle:speckle@postgres/speckle"
WAIT_HOSTS: postgres:5432
S3_ENDPOINT: "http://minio:9000"
S3_ACCESS_KEY: "minioadmin"
S3_SECRET_KEY: "minioadmin"
S3_BUCKET: "speckle-server"
SPECKLE_SERVER_URL: "http://speckle-server:3000"
networks:
default:
name: speckle-server
Generated
+473 -637
View File
File diff suppressed because it is too large Load Diff
+69 -8
View File
@@ -9,6 +9,7 @@ import sys
import traceback
from pathlib import Path
from typing import Callable, Optional, Tuple, TypeVar, Union, overload
from enum import Enum
from pydantic import create_model
from pydantic.json_schema import GenerateJsonSchema
@@ -70,14 +71,7 @@ def execute_automate_function(
automate_function: AutomateFunctionWithoutInputs,
) -> None:
...
class AutomateGenerateJsonSchema(GenerateJsonSchema):
def generate(self, schema, mode="validation"):
json_schema = super().generate(schema, mode=mode)
json_schema["$schema"] = self.schema_dialect
return json_schema
def execute_automate_function(
automate_function: Union[AutomateFunction[T], AutomateFunctionWithoutInputs],
@@ -195,3 +189,70 @@ def run_function(
automation_context.set_context_view()
automation_context.report_run_status()
return automation_context
class AutomateGenerateJsonSchema(GenerateJsonSchema):
def __init__(self, by_alias: bool = True, ref_template: str = "#/$defs/{model}"):
super().__init__(by_alias=by_alias, ref_template=ref_template)
self.schema_dialect = "https://json-schema.org/draft/2020-12/schema"
def generate(self, schema, mode="validation"):
json_schema = super().generate(schema, mode=mode)
json_schema["$schema"] = self.schema_dialect
if "properties" in json_schema:
for prop, details in json_schema["properties"].items():
self._process_property(
details, json_schema.get("$defs", {}), getattr(schema, prop, None)
)
if "$defs" in json_schema:
for def_name, def_schema in json_schema["$defs"].items():
self._process_property(def_schema, json_schema["$defs"], None)
return json_schema
def _process_property(self, property_schema, defs, field):
if "allOf" in property_schema and len(property_schema["allOf"]) == 1:
ref = property_schema["allOf"][0].get("$ref")
if ref and ref.startswith("#/$defs/"):
enum_name = ref.split("/")[-1]
if enum_name in defs:
enum_schema = defs[enum_name]
property_schema.update(enum_schema)
del property_schema["allOf"]
if "enum" in property_schema:
enum_values = property_schema["enum"]
property_schema["oneOf"] = [
{"const": value, "title": str(value).upper()} for value in enum_values
]
del property_schema["enum"]
if isinstance(field, Enum):
property_schema["oneOf"] = [
{"const": item.value, "title": item.name} for item in field.__class__
]
if "default" in property_schema:
property_schema["default"] = property_schema["default"].value
if "type" not in property_schema:
if "oneOf" in property_schema:
property_schema["type"] = "string"
elif "default" in property_schema:
property_schema["type"] = self._infer_type(property_schema["default"])
else:
property_schema["type"] = "object"
@staticmethod
def _infer_type(value):
if isinstance(value, bool):
return "boolean"
elif isinstance(value, int):
return "integer"
elif isinstance(value, float):
return "number"
elif isinstance(value, str):
return "string"
else:
return "object"
-18
View File
@@ -1,22 +1,12 @@
"""Builtin Speckle object kit."""
from specklepy.objects.GIS.CRS import CRS
from specklepy.objects.GIS.features import (
GisMultipatchFeature,
GisNonGeometricFeature,
GisPointFeature,
GisPolygonFeature,
GisPolylineFeature,
)
from specklepy.objects.GIS.geometry import (
GisLineElement,
GisPointElement,
GisPolygonElement,
GisPolygonGeometry,
GisRasterElement,
PolygonGeometry,
PolygonGeometry3d,
GisMultipatchGeometry,
)
from specklepy.objects.GIS.layers import RasterLayer, VectorLayer
@@ -24,17 +14,9 @@ __all__ = [
"VectorLayer",
"RasterLayer",
"GisPolygonGeometry",
"PolygonGeometry",
"PolygonGeometry3d",
"GisMultipatchGeometry",
"GisPolygonElement",
"GisLineElement",
"GisPointElement",
"GisRasterElement",
"CRS",
"GisPointFeature",
"GisPolylineFeature",
"GisPolygonFeature",
"GisMultipatchFeature",
"GisNonGeometricFeature",
]
-107
View File
@@ -1,107 +0,0 @@
from typing import List, Optional
from specklepy.objects.base import Base
from specklepy.objects.geometry import Mesh, Point, Polyline
from specklepy.objects.GIS.geometry import PolygonGeometry
class GisNonGeometricFeature(Base, speckle_type="Objects.GIS.GisNonGeometricFeature"):
"""GIS Table feature"""
attributes: Base
def __init__(
self,
attributes: Optional[Base] = None,
) -> None:
self.attributes = attributes or Base()
class GisPointFeature(
Base,
detachable={"displayValue"},
speckle_type="Objects.GIS.GisPointFeature",
):
"""Gis Point Feature"""
attributes: Base
displayValue: List[Point]
@property
def geometry(self) -> List[Point]:
return self.displayValue
def __init__(
self,
attributes: Optional[Base] = None,
displayValue: Optional[List[Point]] = None,
) -> None:
self.attributes = attributes or Base()
displayValue = displayValue or []
class GisPolylineFeature(
Base,
detachable={"displayValue"},
speckle_type="Objects.GIS.GisPolylineFeature",
):
"""Gis Polyline Feature"""
attributes: Base
displayValue: List[Polyline]
@property
def geometry(self) -> List[Polyline]:
return self.displayValue
def __init__(
self,
attributes: Optional[Base] = None,
displayValue: Optional[List[Point]] = None,
) -> None:
self.attributes = attributes or Base()
displayValue = displayValue or []
class GisPolygonFeature(
Base,
detachable={"displayValue", "geometry"},
speckle_type="Objects.GIS.GisPolygonFeature",
):
"""Gis Polygon Feature"""
attributes: Base
displayValue: List[Mesh]
geometry: List[PolygonGeometry]
def __init__(
self,
geometry: List[PolygonGeometry],
attributes: Optional[Base] = None,
displayValue: Optional[List[Point]] = None,
) -> None:
self.geometry = geometry
self.attributes = attributes or Base()
displayValue = displayValue or []
class GisMultipatchFeature(
Base,
detachable={"displayValue", "geometry"},
speckle_type="Objects.GIS.GisMultipatchFeature",
):
"""Gis Multipatch Feature"""
attributes: Base
displayValue: List[Mesh]
geometry: List[Base] # GisMultipatchGeometry or PolygonGeometry3d
def __init__(
self,
geometry: List[Base],
attributes: Optional[Base] = None,
displayValue: Optional[List[Point]] = None,
) -> None:
self.geometry = geometry
self.attributes = attributes or Base()
displayValue = displayValue or []
+7 -57
View File
@@ -1,7 +1,5 @@
from typing import List, Optional, Union
from deprecated import deprecated
from specklepy.objects.base import Base
from specklepy.objects.geometry import (
Arc,
@@ -14,69 +12,23 @@ from specklepy.objects.geometry import (
)
class PolygonGeometry(Base, speckle_type="Objects.GIS.PolygonGeometry"):
class GisPolygonGeometry(
Base, speckle_type="Objects.GIS.PolygonGeometry", detachable={"displayValue"}
):
"""GIS Polygon Geometry"""
boundary: Polyline
voids: List[Polyline]
def __init__(
self,
units: str,
boundary: Polyline,
voids: Optional[List[Polyline]] = None,
) -> None:
super().__init__(units=units)
self.boundary = boundary
self.voids = voids or []
boundary: Optional[Union[Polyline, Arc, Line, Circle, Polycurve]] = None
voids: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]]] = None
displayValue: Optional[List[Mesh]] = None
GisPolygonGeometry = PolygonGeometry
class PolygonGeometry3d(
PolygonGeometry,
speckle_type="Objects.GIS.PolygonGeometry3d",
):
"""GIS Polygon3d Geometry"""
def __init__(
self,
units: str,
boundary: Polyline,
voids: Optional[List[Polyline]] = None,
) -> None:
super().__init__(units=units, boundary=boundary, voids=voids)
class GisMultipatchGeometry(
Base,
speckle_type="Objects.GIS.GisMultipatchGeometry",
):
"""GIS Polygon3d Geometry"""
def __init__(
self,
units: str,
faces: List[int],
vertices: List[float],
colors: Optional[List[int]],
) -> None:
super().__init__(units=units)
self.faces = faces
self.vertices = vertices
self.colors = colors or []
@deprecated(version="2.20", reason="Replaced with GisPolygonFeature")
class GisPolygonElement(Base, speckle_type="Objects.GIS.PolygonElement"):
"""GIS Polygon element"""
geometry: Optional[List[PolygonGeometry]] = None
geometry: Optional[List[GisPolygonGeometry]] = None
attributes: Optional[Base] = None
@deprecated(version="2.20", reason="Replaced with GisPolyineFeature")
class GisLineElement(Base, speckle_type="Objects.GIS.LineElement"):
"""GIS Polyline element"""
@@ -84,7 +36,6 @@ class GisLineElement(Base, speckle_type="Objects.GIS.LineElement"):
attributes: Optional[Base] = None
@deprecated(version="2.20", reason="Replaced with GisPointFeature")
class GisPointElement(Base, speckle_type="Objects.GIS.PointElement"):
"""GIS Point element"""
@@ -117,7 +68,6 @@ class GisTopography(
"""GIS Raster element with 3d Topography representation"""
@deprecated(version="2.20", reason="Replaced with GisNonGeometricFeature")
class GisNonGeometryElement(Base, speckle_type="Objects.GIS.NonGeometryElement"):
"""GIS Table feature"""
+3 -19
View File
@@ -295,33 +295,17 @@ class RevitParameter(Base, speckle_type="Objects.BuiltElements.Revit.Parameter")
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
)
applicationInternalName: Optional[
str
] = None # BuiltInParameterName or GUID for shared parameter
isShared: bool = False
isReadOnly: bool = False
isTypeParameter: bool = False
@deprecated(
version="2.20", reason="Collections namespace changed, collectionType deprecated"
)
class Collection(
Base, speckle_type="Speckle.Core.Models.Collection", detachable={"elements"}
):
name: Optional[str] = None
collectionType: Optional[str] = None
elements: Optional[List[Base]] = None
class Collection( # noqa: F811
Base,
speckle_type="Speckle.Core.Models.Collections.Collection",
detachable={"elements"},
):
name: str
elements: List[Base]
def init(self, name: str, elements: Optional[List[Base]] = None):
self.name = name
self.elements = elements or []