Source code for syft.core.node.common.action.get_object_action

# stdlib
from typing import Optional

# third party
from google.protobuf.reflection import GeneratedProtocolMessageType
from nacl.signing import VerifyKey

# syft relative
from ..... import serialize
from .....logger import critical
from .....logger import debug
from .....logger import traceback_and_raise
from .....logger import warning
from .....proto.core.node.common.action.get_object_pb2 import (
    GetObjectAction as GetObjectAction_PB,
)
from .....proto.core.node.common.action.get_object_pb2 import (
    GetObjectResponseMessage as GetObjectResponseMessage_PB,
)
from .....util import get_fully_qualified_name
from .....util import validate_type
from ....common.message import ImmediateSyftMessageWithoutReply
from ....common.serde.deserialize import _deserialize
from ....common.serde.serializable import bind_protobuf
from ....common.uid import UID
from ....io.address import Address
from ....store.storeable_object import StorableObject
from ...abstract.node import AbstractNode
from ..service.auth import AuthorizationException
from .common import ImmediateActionWithReply


[docs]@bind_protobuf class GetObjectResponseMessage(ImmediateSyftMessageWithoutReply): """ GetObjectResponseMessages are the type of messages that are sent in reponse to a :class:`GetObjectAction`. They contain the object that was asked for. Attributes: obj: the object being sent back to the asker. """ def __init__( self, obj: StorableObject, address: Address, msg_id: Optional[UID] = None ) -> None: super().__init__(address=address, msg_id=msg_id) self.obj = obj def _object2proto(self) -> GetObjectResponseMessage_PB: """Returns a protobuf serialization of self. As a requirement of all objects which inherit from Serializable, this method transforms the current object into the corresponding Protobuf object so that it can be further serialized. :return: returns a protobuf object :rtype: GetObjectResponseMessage_PB .. note:: This method is purely an internal method. Please use serialize(object) or one of the other public serialization methods if you wish to serialize an object. """ ser = serialize(self.obj) return GetObjectResponseMessage_PB( msg_id=serialize(self.id), address=serialize(self.address), obj=ser, ) @staticmethod def _proto2object(proto: GetObjectResponseMessage_PB) -> "GetObjectResponseMessage": """Creates a ObjectWithID from a protobuf As a requirement of all objects which inherit from Serializable, this method transforms a protobuf object into an instance of this class. :return: returns an instance of GetObjectResponseMessage :rtype: GetObjectResponseMessage .. note:: This method is purely an internal method. Please use syft.deserialize() if you wish to deserialize an object. """ return GetObjectResponseMessage( obj=_deserialize(blob=proto.obj), msg_id=_deserialize(blob=proto.msg_id), address=_deserialize(blob=proto.address), ) @property def data(self) -> object: data = self.obj.data try: # TODO: Make only for DataFrames etc # Issue: https://github.com/OpenMined/PySyft/issues/5322 if get_fully_qualified_name(obj=self.obj.data) not in [ "pandas.core.frame.DataFrame", "pandas.core.series.Series", ]: data.tags = self.obj.tags data.description = self.obj.description except AttributeError: warning( f"'tags' and 'description' can't be attached to {type(data)} object." ) return data
[docs] @staticmethod def get_protobuf_schema() -> GeneratedProtocolMessageType: """Return the type of protobuf object which stores a class of this type As a part of serialization and deserialization, we need the ability to lookup the protobuf object type directly from the object type. This static method allows us to do this. Importantly, this method is also used to create the reverse lookup ability within the metaclass of Serializable. In the metaclass, it calls this method and then it takes whatever type is returned from this method and adds an attribute to it with the type of this class attached to it. See the MetaSerializable class for details. :return: the type of protobuf object which corresponds to this class. :rtype: GeneratedProtocolMessageType """ return GetObjectResponseMessage_PB
[docs]@bind_protobuf class GetObjectAction(ImmediateActionWithReply): """ This kind of action is used when a Node wants to get an object located on another Node. The Node receiving this action first check that the asker does have the permission to fetch the object he asked for. If it's the case, a :class:`GetObjectResponseMessage` containing the object is sent back to the asker. Attributes: id_at_location: the pointer id of the object asked for. """ def __init__( self, id_at_location: UID, address: Address, reply_to: Address, msg_id: Optional[UID] = None, delete_obj: bool = True, ): self.id_at_location = id_at_location self.delete_obj = delete_obj # the logger needs self.id_at_location to be set already - so we call this later super().__init__(address=address, msg_id=msg_id, reply_to=reply_to) def execute_action( self, node: AbstractNode, verify_key: VerifyKey ) -> ImmediateSyftMessageWithoutReply: try: try: storable_object = node.store[self.id_at_location] except Exception as e: log = ( f"Unable to Get Object with ID {self.id_at_location} from store. " + f"Possible dangling Pointer. {e}" ) traceback_and_raise(Exception(log)) # if you are not the root user check if your verify_key has read_permission if ( verify_key != node.root_verify_key and verify_key not in storable_object.read_permissions ): log = ( f"You do not have permission to .get() Object with ID: {self.id_at_location}" + "Please submit a request." ) traceback_and_raise(AuthorizationException(log)) obj = validate_type(storable_object.clean_copy(), StorableObject) msg = GetObjectResponseMessage(obj=obj, address=self.reply_to, msg_id=None) if self.delete_obj: try: # TODO: send EventualActionWithoutReply to delete the object at the node's # convenience instead of definitely having to delete it now debug( f"Calling delete on Object with ID {self.id_at_location} in store." ) node.store.delete(key=self.id_at_location) except Exception as e: log = ( f"> GetObjectAction delete exception {self.id_at_location} {e}" ) critical(log) else: debug(f"Copying Object with ID {self.id_at_location} in store.") debug( f"Returning Object with ID: {self.id_at_location} {type(storable_object.data)}" ) return msg except Exception as e: traceback_and_raise(e) @property def pprint(self) -> str: return f"GetObjectAction({self.id_at_location})" def _object2proto(self) -> GetObjectAction_PB: """Returns a protobuf serialization of self. As a requirement of all objects which inherit from Serializable, this method transforms the current object into the corresponding Protobuf object so that it can be further serialized. :return: returns a protobuf object :rtype: ObjectWithID_PB .. note:: This method is purely an internal method. Please use serialize(object) or one of the other public serialization methods if you wish to serialize an object. """ return GetObjectAction_PB( id_at_location=serialize(self.id_at_location, to_proto=True), msg_id=serialize(self.id, to_proto=True), address=serialize(self.address, to_proto=True), reply_to=serialize(self.reply_to, to_proto=True), delete_obj=self.delete_obj, ) @staticmethod def _proto2object(proto: GetObjectAction_PB) -> "GetObjectAction": """Creates a ObjectWithID from a protobuf As a requirement of all objects which inherit from Serializable, this method transforms a protobuf object into an instance of this class. :return: returns an instance of GetObjectAction :rtype: GetObjectAction .. note:: This method is purely an internal method. Please use syft.deserialize() if you wish to deserialize an object. """ return GetObjectAction( id_at_location=_deserialize(blob=proto.id_at_location), msg_id=_deserialize(blob=proto.msg_id), address=_deserialize(blob=proto.address), reply_to=_deserialize(blob=proto.reply_to), delete_obj=proto.delete_obj, )
[docs] @staticmethod def get_protobuf_schema() -> GeneratedProtocolMessageType: """Return the type of protobuf object which stores a class of this type As a part of serialization and deserialization, we need the ability to lookup the protobuf object type directly from the object type. This static method allows us to do this. Importantly, this method is also used to create the reverse lookup ability within the metaclass of Serializable. In the metaclass, it calls this method and then it takes whatever type is returned from this method and adds an attribute to it with the type of this class attached to it. See the MetaSerializable class for details. :return: the type of protobuf object which corresponds to this class. :rtype: GeneratedProtocolMessageType """ return GetObjectAction_PB