Exemple #1
0
def add_base_methods(object: typing.Any) -> typing.Any:
    """
    This function / decorator adds methods to a given object.
    These added methods are useful for:
    - handling linkage (parent/child relationships),
    - serialization (JSON)
    - hashing
    - implementing the "listener" design pattern
    - etc
    """
    def _to_json_serializable(to_convert=None):
        """
        Convert this object to a representation that
        can be serialized as JSON
        """
        if isinstance(to_convert, dict):
            return {
                to_json_serializable(k): to_json_serializable(v)
                for k, v in to_convert.items()
            }
        if isinstance(to_convert, list):
            return [to_json_serializable(x) for x in to_convert]
        if isinstance(to_convert, Decimal):
            return float(to_convert)
        if (isinstance(to_convert, HexadecimalString)
                or isinstance(to_convert, String)
                or isinstance(to_convert, Name)
                or isinstance(to_convert, CanvasOperatorName)):
            return str(to_convert)
        return None

    def to_json_serializable(self):
        """
        This function converts this Object to something that can be JSON serialized
        """
        return _to_json_serializable(self)

    def image_hash_method(self):
        """
        This function hashes Image objects
        """
        w = self.width
        h = self.height
        pixels = [
            self.getpixel((0, 0)),
            self.getpixel((0, h - 1)),
            self.getpixel((w - 1, 0)),
            self.getpixel((w - 1, h - 1)),
        ]
        hashcode = 1
        for p in pixels:
            if isinstance(p, typing.List) or isinstance(p, typing.Tuple):
                hashcode += 32 * hashcode + sum(p)
            else:
                hashcode += 32 * hashcode + p
        return hashcode

    def deepcopy_mod(self, memodict={}):
        """
        This function overrides the __deepcopy__ method
        this was needed
        """
        prev_function_ptr = self.__deepcopy__
        self.__deepcopy__ = None
        # copy
        out = copy.deepcopy(self, memodict)
        # restore
        self.__deepcopy__ = prev_function_ptr
        # add base methods
        add_base_methods(out)
        # return
        return out

    # get_parent
    def get_parent(self):
        """
        This function returns the parent Object of the current Object
        """
        if "_parent" not in vars(self):
            setattr(self, "_parent", None)
        return self._parent

    # set_parent
    def set_parent(self, parent):
        """
        This function sets the parent Object of the current Object
        """
        if "_parent" not in vars(self):
            setattr(self, "_parent", None)
        self._parent = parent
        return self

    # get_root
    def get_root(self):
        """
        This function returns the root parent Object of the current Object
        """
        e = self
        while e.get_parent() is not None:
            e = e.get_parent()
        return e

    # add_event_listener
    def add_event_listener(self, event_listener: "EventListener"):
        """
        This function adds an EventListener to this Object
        """
        if "_event_listeners" not in vars(self):
            setattr(self, "_event_listeners", [])
        self._event_listeners.append(event_listener)
        return self

    # get_event_listener
    def get_event_listeners(self) -> typing.List["EventListener"]:
        """
        This function returns a typing.List[EventListener] for this Object
        """
        if "_event_listeners" not in vars(self):
            setattr(self, "_event_listeners", [])
        return self._event_listeners

    # _event_occurred
    def _event_occurred(self, event: "Event"):  # type: ignore [name-defined]
        if "_event_listeners" not in vars(self):
            setattr(self, "_event_listeners", [])
        for l in self._event_listeners:
            l._event_occurred(event)
        if self.get_parent() is not None:
            self.get_parent()._event_occurred(event)
        return self

    # set_reference
    def set_reference(self, reference: "Reference"):
        """
        This function sets the Reference for this Object, returning self
        """
        if "_reference" not in vars(self):
            setattr(self, "_reference", None)
        assert (self._reference is None or reference is None
                or self._reference.object_number == reference.object_number
                or (self._reference.parent_stream_object_number
                    == reference.parent_stream_object_number
                    and self._reference.index_in_parent_stream
                    == reference.index_in_parent_stream))
        self._reference = reference
        return self

    # get_reference
    def get_reference(self) -> typing.Optional["Reference"]:
        """
        This function returns the Reference for this Object or None if no Reference was set
        """
        if "_reference" not in vars(self):
            setattr(self, "_reference", None)
        return self._reference

    # set_can_be_referenced
    def set_can_be_referenced(self, a_flag: bool):
        """
        This function sets whether or not this Object can be referenced.
        When an object can not be referenced, it is always embedded immediately in the PDF byte stream.
        """
        if "_can_be_referenced" not in vars(self):
            setattr(self, "_can_be_referenced", None)
        self._can_be_referenced = a_flag
        return self

    # can_be_referenced
    def can_be_referenced(self) -> bool:
        """
        This function returns whether or not this Object can be referenced.
        When an object can not be referenced, it is always embedded immediately in the PDF byte stream.
        """
        if "_can_be_referenced" not in vars(self):
            setattr(self, "_can_be_referenced", True)
        return self._can_be_referenced

    object.set_parent = types.MethodType(set_parent, object)
    object.get_parent = types.MethodType(get_parent, object)
    object.get_root = types.MethodType(get_root, object)
    object.add_event_listener = types.MethodType(add_event_listener, object)
    object.get_event_listeners = types.MethodType(get_event_listeners, object)
    object._event_occurred = types.MethodType(_event_occurred, object)
    object.set_reference = types.MethodType(set_reference, object)
    object.get_reference = types.MethodType(get_reference, object)
    object.set_can_be_referenced = types.MethodType(set_can_be_referenced,
                                                    object)
    object.can_be_referenced = types.MethodType(can_be_referenced, object)
    object.to_json_serializable = types.MethodType(to_json_serializable,
                                                   object)
    if isinstance(object, Image):
        object.__deepcopy__ = types.MethodType(deepcopy_mod, object)
        object.__hash__ = types.MethodType(image_hash_method, object)