Files
specklepy/specklepy/api/operations.py
T
izzy lyseggen d1adccba00 feat(serialization): cache bases on deserialize (#200)
* feat(serialization): cache bases on deserialize

allows the deserializer to return the same instance when encountering
objects with the same id

closes #191

* feat(serialization): cache bases on deserialize

allows the deserializer to return the same instance when encountering
objects with the same id

closes #191

* fix(serialization): check before accessing id

obj may not be detached and therefore might not have an id

* feat(serializer): cache w id from obj not base

* chore: update deps

* feat(operations): lil send helper

on send, if `transports` is just a transport, add it to a list.
i see this error a lot so just a friendly lil fix!

* feat(objects): breps omg!

* test(geometry): updates for breps

* test(geometry): more brep serialization tests

* refactor(test): formatting

* style: formatting

* test(geometry): clean up test file

* fix(test): brep trims test fix

* refactor(geometry): clean up encoding outputs

* feat(objects): allow kwargs in encoding

* feat(objects): align curve encodings w sharp

* test(geometry): new curve encodings

* feat(client): update stream permission mutation

guess this changed some time recently and i wasn't made aware of it

* fix(objects): brep face and edge encoding

* fix(geometry): breps units 'none' fix

* test(objects): fix 'none' units issue

* revert(486ea99): use `streamGrantPermission`

to be updated for next server release
2022-07-20 18:02:25 +01:00

127 lines
4.4 KiB
Python

from typing import List
from specklepy.logging import metrics
from specklepy.objects.base import Base
from specklepy.transports.sqlite import SQLiteTransport
from specklepy.transports.server import ServerTransport
from specklepy.logging.exceptions import SpeckleException
from specklepy.transports.abstract_transport import AbstractTransport
from specklepy.serialization.base_object_serializer import BaseObjectSerializer
def send(
base: Base,
transports: List[AbstractTransport] = None,
use_default_cache: bool = True,
):
"""Sends an object via the provided transports. Defaults to the local cache.
Arguments:
obj {Base} -- the object you want to send
transports {list} -- where you want to send them
use_default_cache {bool} -- toggle for the default cache. If set to false, it will only send to the provided transports
Returns:
str -- the object id of the sent object
"""
if not transports and not use_default_cache:
raise SpeckleException(
message="You need to provide at least one transport: cannot send with an empty transport list and no default cache"
)
if isinstance(transports, AbstractTransport):
transports = [transports]
if transports is None:
metrics.track(metrics.SEND)
transports = []
else:
metrics.track(metrics.SEND, getattr(transports[0], "account", None))
if use_default_cache:
transports.insert(0, SQLiteTransport())
serializer = BaseObjectSerializer(write_transports=transports)
obj_hash, _ = serializer.write_json(base=base)
return obj_hash
def receive(
obj_id: str,
remote_transport: AbstractTransport = None,
local_transport: AbstractTransport = None,
) -> Base:
"""Receives an object from a transport.
Arguments:
obj_id {str} -- the id of the object to receive
remote_transport {Transport} -- the transport to receive from
local_transport {Transport} -- the local cache to check for existing objects
(defaults to `SQLiteTransport`)
Returns:
Base -- the base object
"""
metrics.track(metrics.RECEIVE, getattr(remote_transport, "account", None))
if not local_transport:
local_transport = SQLiteTransport()
serializer = BaseObjectSerializer(read_transport=local_transport)
# try local transport first. if the parent is there, we assume all the children are there and continue with deserialisation using the local transport
obj_string = local_transport.get_object(obj_id)
if obj_string:
return serializer.read_json(obj_string=obj_string)
if not remote_transport:
raise SpeckleException(
message="Could not find the specified object using the local transport, and you didn't provide a fallback remote from which to pull it."
)
obj_string = remote_transport.copy_object_and_children(
id=obj_id, target_transport=local_transport
)
return serializer.read_json(obj_string=obj_string)
def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str:
"""
Serialize a base object. If no write transports are provided, the object will be serialized
without detaching or chunking any of the attributes.
Arguments:
base {Base} -- the object to serialize
write_transports {List[AbstractTransport]} -- optional: the transports to write to
Returns:
str -- the serialized object
"""
metrics.track(metrics.SERIALIZE)
serializer = BaseObjectSerializer(write_transports=write_transports)
return serializer.write_json(base)[1]
def deserialize(obj_string: str, read_transport: AbstractTransport = None) -> Base:
"""
Deserialize a string object into a Base object. If the object contains referenced child objects that are not stored in the local db, a read transport needs to be provided in order to recompose the base with the children objects.
Arguments:
obj_string {str} -- the string object to deserialize
read_transport {AbstractTransport} -- the transport to fetch children objects from
(defaults to SQLiteTransport)
Returns:
Base -- the deserialized object
"""
metrics.track(metrics.DESERIALIZE)
if not read_transport:
read_transport = SQLiteTransport()
serializer = BaseObjectSerializer(read_transport=read_transport)
return serializer.read_json(obj_string=obj_string)