Skip to content

hololinked.injection.Serializers

Bases: Registry

A singleton class that holds all serializers and provides a registry for content types.

All members are class attributes and settings are applied process-wide (python process). Registration of serializer is not mandatory for any property, action or event. The default serializer is JSONSerializer, which will be provided to any unregistered object.

Source code in repo/hololinked/hololinked/injection.py
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
class Serializers(Registry):
    """
    A singleton class that holds all serializers and provides a registry for content types.

    All members are class attributes and settings are applied process-wide (python process).
    Registration of serializer is not mandatory for any property, action or event.
    The default serializer is `JSONSerializer`, which will be provided to any unregistered object.
    """

    adapter_kind: ClassVar[str] = "serializer"
    instantiate: ClassVar[bool] = True
    package: ClassVar[str] = "hololinked.serializers"
    tables: ClassVar[tuple[str, ...]] = ("modules", "content_type_names")

    modules: ClassVar[dict[str, str | tuple[str, str]]] = {
        "default": "JSONSerializer",
        "json": "JSONSerializer",
        "msgpack": "MsgpackSerializer",
        "pickle": "PickleSerializer",
        "text": "TextSerializer",
        "serpent": "SerpentSerializer",
    }

    content_type_names: ClassVar[dict[str, str]] = {
        "application/json": "json",
        "application/msgpack": "msgpack",
        "application/x-pickle": "pickle",
        "text/plain": "text",
    }
    # Content type mapped to the name of the serializer that handles it.
    # Must be answerable without importing the serializer it names, since it is what decides which serializer to
    # import in the first place.

    default: BaseSerializer
    """The default serializer."""
    # some known types:
    json: BaseSerializer
    msgpack: BaseSerializer
    pickle: BaseSerializer
    text: BaseSerializer

    _content_types: ClassVar[ContentTypeMap | None] = None

    default_content_type = String(
        fget=lambda self: self.default.content_type,
        class_member=True,
        doc="The default content type for the default serializer",
    )  # type: str

    content_types = Parameter(
        default=None,
        doc="A dictionary of content types and their serializers",
        readonly=True,
        class_member=True,
    )  # type: dict[str, BaseSerializer]
    """A dictionary of content types and their serializers"""

    allowed_content_types = Parameter(
        default=None,
        class_member=True,
        doc="A list of content types that are usually considered safe and will be supported by default without any configuration",
        readonly=True,
    )  # type: list[str]
    """
    A list of content types that are usually considered safe
    and will be supported by default without any configuration
    """

    object_content_type_map = Parameter(
        default=dict(),
        class_member=True,
        doc="A dictionary of content types for specific properties, actions and events",
        readonly=True,
    )  # type: dict[str, dict[str, str]]
    """A dictionary of content types for specific properties, actions and events"""

    object_serializer_map = Parameter(
        default=dict(),
        class_member=True,
        doc="A dictionary of serializer for specific properties, actions and events",
        readonly=True,
    )  # type: dict[str, dict[str, BaseSerializer]]
    """A dictionary of serializer for specific properties, actions and events"""

    protocol_serializer_map = Parameter(
        default=dict(),
        class_member=True,
        doc="A dictionary of serializer for a specific protocol",
        readonly=True,
    )  # type: dict[str, BaseSerializer]
    """A dictionary of default serializer for a specific protocol, currently unimplemented"""

    @classmethod
    def register(cls, serializer: BaseSerializer, name: str | None = None, override: bool = False) -> None:
        """
        Register a new serializer to be generally available for the running application.

        It is recommended to implement a content type property/attribute for the serializer
        to facilitate automatic deserialization on client side, otherwise deserialization is not gauranteed.
        Moreover, the said serializer must be defined on both client and server side if running in a distributed
        environment.

        Parameters
        ----------
        serializer: BaseSerializer
            the serializer to register
        name: str, optional
            the name of the serializer to be accessible under the object namespace. If not provided, the name of the
            serializer class is used.
        override: bool, optional
            whether to override the serializer if the content type is already registered,
            by default False & raises ValueError for duplicate content type. For example, registering
            a custom JSON serializer will conflict with the default JSONSerializer, so set `override=True`.

        Raises
        ------
        ValueError
            if the serializer content type is already registered
        """
        name = name or serializer.__class__.__name__
        try:
            if serializer.content_type in cls.content_type_names and not override:
                raise ValueError(f"content type already registered : {serializer.content_type}")
            cls.content_type_names[serializer.content_type] = name
        except NotImplementedError:
            warnings.warn("serializer does not implement a content type", category=UserWarning)
        cls.install(name, serializer)

    @classmethod
    def for_object(cls, thing_id: str, thing_cls: str, objekt: str) -> BaseSerializer:
        """
        Retrieve a serializer for a given property, action or event.

        Parameters
        ----------
        thing_id: str | Any
            the id of the Thing or the Thing that owns the property, action or event
        thing_cls: str | Any
            the class name of the Thing or the Thing that owns the property, action or event
        objekt: str
            the name of the property, action or event

        Returns
        -------
        BaseSerializer | JSONSerializer
            the serializer for the property, action or event. If no serializer is found, the default JSONSerializer is
            returned.
        """
        if len(cls.object_serializer_map) == 0 and len(cls.object_content_type_map) == 0:
            return cls.default
        for thing in [thing_id, thing_cls]:  # first thing id, then thing cls
            if thing in cls.object_serializer_map and objekt in cls.object_serializer_map[thing]:
                return cls.object_serializer_map[thing][objekt]
            if thing in cls.object_content_type_map and objekt in cls.object_content_type_map[thing]:
                return cls.content_types.get(cls.object_content_type_map[thing][objekt], None)
                # if said content type has no serializer, return None instead of default serializer
        return cls.default  # JSON is default serializer

    @classmethod
    def get_content_type_for_object(self, thing_id: str, thing_cls: str, objekt: str) -> str:
        """
        Retrieve a content type for a given property, action or event.

        Parameters
        ----------
        thing_id: str | Any
            the id of the Thing or the Thing that owns the property, action or event
        thing_cls: str | Any
            the class name of the Thing or the Thing that owns the property, action or event
        objekt: str
            the name of the property, action or event

        Returns
        -------
        str
            the content type for the property, action or event. If no content type is found, the default content type is
            returned.
        """
        if len(self.object_serializer_map) == 0 and len(self.object_content_type_map) == 0:
            return self.default_content_type
        for thing in [thing_id, thing_cls]:  # first thing id, then thing cls
            if thing in self.object_content_type_map and objekt in self.object_content_type_map[thing]:
                return self.object_content_type_map[thing][objekt]
        return self.default_content_type  # JSON is default serializer

    @classmethod
    def register_for_object(cls, objekt: Any, serializer: BaseSerializer) -> None:
        """
        Register (an existing) serializer for a property, action or event.

        Other option is to register a content type, the effects are similar.

        Parameters
        ----------
        objekt: str | Property | Action | Event
            the property, action or event
        serializer: BaseSerializer
            the serializer to be used

        Raises
        ------
        ValueError
            if the object is not a Property, Action or Event, or Thing class
        """
        from hololinked.core import Action, Event, Property, Thing

        if not isinstance(serializer, BaseSerializer):
            raise ValueError(f"serializer must be an instance of BaseSerializer, given : {type(serializer)}")
        if not isinstance(objekt, (Property, Action, Event)) and not issubklass(objekt, Thing):
            raise ValueError(f"object must be a Property, Action or Event, or Thing, got : {type(objekt)}")
        if issubklass(objekt, Thing):
            owner = objekt.__name__
        elif not objekt.owner:
            raise ValueError(f"object owner cannot be determined : {objekt}")
        else:
            owner = objekt.owner.__name__
        if owner not in cls.object_serializer_map:
            cls.object_serializer_map[owner] = dict()
        if issubklass(objekt, Thing):
            cls.object_serializer_map[owner][objekt.__name__] = serializer
        else:
            cls.object_serializer_map[owner][objekt.name] = serializer

    # @validate_call
    @classmethod
    def register_content_type_for_object(cls, objekt: Any, content_type: str) -> None:
        """
        Register content type for a property, action, event, or a `Thing` class to use a specific serializer.

        If no serializer is found, content type could still be used as metadata.

        Parameters
        ----------
        objekt: Property | Action | Event | Thing
            the property, action or event. string is not accepted - use `register_content_type_for_object_by_name()` instead.
        content_type: str
            the content type for the value of the objekt or the serializer to be used

        Raises
        ------
        ValueError
            if the object is not a Property, Action or Event
        """
        from hololinked.core import Action, Event, Property, Thing

        if not isinstance(objekt, (Property, Action, Event)) and not issubklass(objekt, Thing):
            raise ValueError(f"object must be a Property, Action or Event, got : {type(objekt)}")
        if issubklass(objekt, Thing):
            owner = objekt.__name__
        elif not objekt.owner:
            raise ValueError(f"object owner cannot be determined, cannot register content type: {objekt}")
        else:
            owner = objekt.owner.__name__
        if owner not in cls.object_content_type_map:
            cls.object_content_type_map[owner] = dict()
        if issubklass(objekt, Thing):
            cls.object_content_type_map[owner][objekt.__name__] = content_type
            # its a redundant key, TODO - may be there is a better way to structure this map
        else:
            cls.object_content_type_map[owner][objekt.name] = content_type

    # @validate_call
    @classmethod
    def register_content_type_for_object_per_thing_instance(
        cls,
        thing_id: str,
        objekt: str | Any,
        content_type: str,
    ) -> None:
        """
        Register a content type for a property, action or event to use a specific serializer.

        Other option is to register a serializer directly, the effects are similar. If no serializer is found,
        content type could still be used as metadata.

        Parameters
        ----------
        thing_id: str
            the id of the Thing that owns the property, action or event
        objekt: str
            the name of the property, action or event
        content_type: str
            the content type to be used

        Raises
        ------
        ValueError
            if the object is not a Property, Action or Event
        """
        from hololinked.core import Action, Event, Property, Thing  # noqa

        if not isinstance(objekt, (Property, Action, Event, str)):
            raise ValueError(f"object must be a Property, Action or Event, got : {type(objekt)}")
        if not isinstance(objekt, str):
            objekt = objekt.name
        if thing_id not in cls.object_content_type_map:
            cls.object_content_type_map[thing_id] = dict()
        cls.object_content_type_map[thing_id][objekt] = content_type

    @classmethod
    def register_content_type_for_thing_instance(cls, thing_id: str, content_type: str) -> None:
        """
        Register a content type for a specific Thing instance.

        Parameters
        ----------
        thing_id: str
            the id of the Thing
        content_type: str
            the content type to be used
        """
        cls.object_content_type_map[thing_id][thing_id] = content_type
        # remember, its a redundant key, TODO

    @classmethod
    def register_for_object_per_thing_instance(cls, thing_id: str, objekt: str, serializer: BaseSerializer) -> None:
        """
        Register a serializer for a property, action or event for a specific Thing instance.

        If no serializer is found, content type could still be used as metadata.

        Parameters
        ----------
        thing_id: str
            the id of the Thing that owns the property, action or event
        objekt: str
            the name of the property, action or event
        serializer: BaseSerializer
            the serializer to be used
        """
        if thing_id not in cls.object_serializer_map:
            cls.object_serializer_map[thing_id] = dict()
        cls.object_serializer_map[thing_id][objekt] = serializer

    @classmethod
    def register_for_thing_instance(cls, thing_id: str, serializer: BaseSerializer) -> None:
        """
        Register a serializer for a specific Thing instance.

        Parameters
        ----------
        thing_id: str
            the id of the Thing
        serializer: BaseSerializer
            the serializer to be used
        """
        if thing_id not in cls.object_serializer_map:
            cls.object_serializer_map[thing_id] = dict()
        cls.object_serializer_map[thing_id][thing_id] = serializer

    @classmethod
    def reset(cls) -> None:
        """Reset the serializer registry."""
        cls.object_content_type_map.clear()
        cls.object_serializer_map.clear()
        cls.protocol_serializer_map.clear()
        cls.forget_adapters()

    @content_types.getter
    def get_content_types(cls: type[Serializers]) -> ContentTypeMap:
        """
        Get the mapping of content type to serializer.

        Returns
        -------
        ContentTypeMap
            a read-only mapping that imports a serializer only when one is looked up
        """
        if cls._content_types is None:
            cls._content_types = ContentTypeMap(cls)
        return cls._content_types

    @allowed_content_types.getter
    def get_allowed_content_types(cls) -> list[str]:
        """
        Get a list of all allowed content types for serialization.

        Set `global_config.ALLOW_PICKLE` to `True` to allow pickle content type,
        which is not allowed by default for security reasons.

        Returns
        -------
        list[str]
            a list of allowed content types
        """
        _allowed_content_types = list(cls.content_type_names.keys())
        for content_type, name in list(cls.content_type_names.items()):
            # the name is compared instead of the serializer, so that asking which content types are allowed
            # never imports the pickle serializer
            if name != "pickle":
                continue
            _allowed_content_types.remove(content_type)
            if global_config.ALLOW_PICKLE:
                _allowed_content_types.append(content_type)
        return _allowed_content_types

Attributes

default instance-attribute

default: BaseSerializer

The default serializer.

json instance-attribute

json: BaseSerializer

msgpack instance-attribute

msgpack: BaseSerializer

pickle instance-attribute

pickle: BaseSerializer

text instance-attribute

text: BaseSerializer

default_content_type class-attribute instance-attribute

default_content_type = String(fget=lambda self: content_type, class_member=True, doc='The default content type for the default serializer')

content_types class-attribute instance-attribute

content_types = Parameter(default=None, doc='A dictionary of content types and their serializers', readonly=True, class_member=True)

A dictionary of content types and their serializers

allowed_content_types class-attribute instance-attribute

allowed_content_types = Parameter(default=None, class_member=True, doc='A list of content types that are usually considered safe and will be supported by default without any configuration', readonly=True)

A list of content types that are usually considered safe and will be supported by default without any configuration

Functions

for_object classmethod

for_object(thing_id: str, thing_cls: str, objekt: str) -> BaseSerializer

Retrieve a serializer for a given property, action or event.

Parameters:

Name Type Description Default

thing_id

str

the id of the Thing or the Thing that owns the property, action or event

required

thing_cls

str

the class name of the Thing or the Thing that owns the property, action or event

required

objekt

str

the name of the property, action or event

required

Returns:

Type Description
BaseSerializer | JSONSerializer

the serializer for the property, action or event. If no serializer is found, the default JSONSerializer is returned.

Source code in repo/hololinked/hololinked/injection.py
@classmethod
def for_object(cls, thing_id: str, thing_cls: str, objekt: str) -> BaseSerializer:
    """
    Retrieve a serializer for a given property, action or event.

    Parameters
    ----------
    thing_id: str | Any
        the id of the Thing or the Thing that owns the property, action or event
    thing_cls: str | Any
        the class name of the Thing or the Thing that owns the property, action or event
    objekt: str
        the name of the property, action or event

    Returns
    -------
    BaseSerializer | JSONSerializer
        the serializer for the property, action or event. If no serializer is found, the default JSONSerializer is
        returned.
    """
    if len(cls.object_serializer_map) == 0 and len(cls.object_content_type_map) == 0:
        return cls.default
    for thing in [thing_id, thing_cls]:  # first thing id, then thing cls
        if thing in cls.object_serializer_map and objekt in cls.object_serializer_map[thing]:
            return cls.object_serializer_map[thing][objekt]
        if thing in cls.object_content_type_map and objekt in cls.object_content_type_map[thing]:
            return cls.content_types.get(cls.object_content_type_map[thing][objekt], None)
            # if said content type has no serializer, return None instead of default serializer
    return cls.default  # JSON is default serializer

register classmethod

register(serializer: BaseSerializer, name: str | None = None, override: bool = False) -> None

Register a new serializer to be generally available for the running application.

It is recommended to implement a content type property/attribute for the serializer to facilitate automatic deserialization on client side, otherwise deserialization is not gauranteed. Moreover, the said serializer must be defined on both client and server side if running in a distributed environment.

Parameters:

Name Type Description Default

serializer

BaseSerializer

the serializer to register

required

name

str | None

the name of the serializer to be accessible under the object namespace. If not provided, the name of the serializer class is used.

None

override

bool

whether to override the serializer if the content type is already registered, by default False & raises ValueError for duplicate content type. For example, registering a custom JSON serializer will conflict with the default JSONSerializer, so set override=True.

False

Raises:

Type Description
ValueError

if the serializer content type is already registered

Source code in repo/hololinked/hololinked/injection.py
@classmethod
def register(cls, serializer: BaseSerializer, name: str | None = None, override: bool = False) -> None:
    """
    Register a new serializer to be generally available for the running application.

    It is recommended to implement a content type property/attribute for the serializer
    to facilitate automatic deserialization on client side, otherwise deserialization is not gauranteed.
    Moreover, the said serializer must be defined on both client and server side if running in a distributed
    environment.

    Parameters
    ----------
    serializer: BaseSerializer
        the serializer to register
    name: str, optional
        the name of the serializer to be accessible under the object namespace. If not provided, the name of the
        serializer class is used.
    override: bool, optional
        whether to override the serializer if the content type is already registered,
        by default False & raises ValueError for duplicate content type. For example, registering
        a custom JSON serializer will conflict with the default JSONSerializer, so set `override=True`.

    Raises
    ------
    ValueError
        if the serializer content type is already registered
    """
    name = name or serializer.__class__.__name__
    try:
        if serializer.content_type in cls.content_type_names and not override:
            raise ValueError(f"content type already registered : {serializer.content_type}")
        cls.content_type_names[serializer.content_type] = name
    except NotImplementedError:
        warnings.warn("serializer does not implement a content type", category=UserWarning)
    cls.install(name, serializer)

register_for_object classmethod

register_for_object(objekt: Any, serializer: BaseSerializer) -> None

Register (an existing) serializer for a property, action or event.

Other option is to register a content type, the effects are similar.

Parameters:

Name Type Description Default

objekt

Any

the property, action or event

required

serializer

BaseSerializer

the serializer to be used

required

Raises:

Type Description
ValueError

if the object is not a Property, Action or Event, or Thing class

Source code in repo/hololinked/hololinked/injection.py
@classmethod
def register_for_object(cls, objekt: Any, serializer: BaseSerializer) -> None:
    """
    Register (an existing) serializer for a property, action or event.

    Other option is to register a content type, the effects are similar.

    Parameters
    ----------
    objekt: str | Property | Action | Event
        the property, action or event
    serializer: BaseSerializer
        the serializer to be used

    Raises
    ------
    ValueError
        if the object is not a Property, Action or Event, or Thing class
    """
    from hololinked.core import Action, Event, Property, Thing

    if not isinstance(serializer, BaseSerializer):
        raise ValueError(f"serializer must be an instance of BaseSerializer, given : {type(serializer)}")
    if not isinstance(objekt, (Property, Action, Event)) and not issubklass(objekt, Thing):
        raise ValueError(f"object must be a Property, Action or Event, or Thing, got : {type(objekt)}")
    if issubklass(objekt, Thing):
        owner = objekt.__name__
    elif not objekt.owner:
        raise ValueError(f"object owner cannot be determined : {objekt}")
    else:
        owner = objekt.owner.__name__
    if owner not in cls.object_serializer_map:
        cls.object_serializer_map[owner] = dict()
    if issubklass(objekt, Thing):
        cls.object_serializer_map[owner][objekt.__name__] = serializer
    else:
        cls.object_serializer_map[owner][objekt.name] = serializer

register_for_thing_instance classmethod

register_for_thing_instance(thing_id: str, serializer: BaseSerializer) -> None

Register a serializer for a specific Thing instance.

Parameters:

Name Type Description Default

thing_id

str

the id of the Thing

required

serializer

BaseSerializer

the serializer to be used

required
Source code in repo/hololinked/hololinked/injection.py
@classmethod
def register_for_thing_instance(cls, thing_id: str, serializer: BaseSerializer) -> None:
    """
    Register a serializer for a specific Thing instance.

    Parameters
    ----------
    thing_id: str
        the id of the Thing
    serializer: BaseSerializer
        the serializer to be used
    """
    if thing_id not in cls.object_serializer_map:
        cls.object_serializer_map[thing_id] = dict()
    cls.object_serializer_map[thing_id][thing_id] = serializer

register_for_object_per_thing_instance classmethod

register_for_object_per_thing_instance(thing_id: str, objekt: str, serializer: BaseSerializer) -> None

Register a serializer for a property, action or event for a specific Thing instance.

If no serializer is found, content type could still be used as metadata.

Parameters:

Name Type Description Default

thing_id

str

the id of the Thing that owns the property, action or event

required

objekt

str

the name of the property, action or event

required

serializer

BaseSerializer

the serializer to be used

required
Source code in repo/hololinked/hololinked/injection.py
@classmethod
def register_for_object_per_thing_instance(cls, thing_id: str, objekt: str, serializer: BaseSerializer) -> None:
    """
    Register a serializer for a property, action or event for a specific Thing instance.

    If no serializer is found, content type could still be used as metadata.

    Parameters
    ----------
    thing_id: str
        the id of the Thing that owns the property, action or event
    objekt: str
        the name of the property, action or event
    serializer: BaseSerializer
        the serializer to be used
    """
    if thing_id not in cls.object_serializer_map:
        cls.object_serializer_map[thing_id] = dict()
    cls.object_serializer_map[thing_id][objekt] = serializer

register_content_type_for_object classmethod

register_content_type_for_object(objekt: Any, content_type: str) -> None

Register content type for a property, action, event, or a Thing class to use a specific serializer.

If no serializer is found, content type could still be used as metadata.

Parameters:

Name Type Description Default

objekt

Any

the property, action or event. string is not accepted - use register_content_type_for_object_by_name() instead.

required

content_type

str

the content type for the value of the objekt or the serializer to be used

required

Raises:

Type Description
ValueError

if the object is not a Property, Action or Event

Source code in repo/hololinked/hololinked/injection.py
@classmethod
def register_content_type_for_object(cls, objekt: Any, content_type: str) -> None:
    """
    Register content type for a property, action, event, or a `Thing` class to use a specific serializer.

    If no serializer is found, content type could still be used as metadata.

    Parameters
    ----------
    objekt: Property | Action | Event | Thing
        the property, action or event. string is not accepted - use `register_content_type_for_object_by_name()` instead.
    content_type: str
        the content type for the value of the objekt or the serializer to be used

    Raises
    ------
    ValueError
        if the object is not a Property, Action or Event
    """
    from hololinked.core import Action, Event, Property, Thing

    if not isinstance(objekt, (Property, Action, Event)) and not issubklass(objekt, Thing):
        raise ValueError(f"object must be a Property, Action or Event, got : {type(objekt)}")
    if issubklass(objekt, Thing):
        owner = objekt.__name__
    elif not objekt.owner:
        raise ValueError(f"object owner cannot be determined, cannot register content type: {objekt}")
    else:
        owner = objekt.owner.__name__
    if owner not in cls.object_content_type_map:
        cls.object_content_type_map[owner] = dict()
    if issubklass(objekt, Thing):
        cls.object_content_type_map[owner][objekt.__name__] = content_type
        # its a redundant key, TODO - may be there is a better way to structure this map
    else:
        cls.object_content_type_map[owner][objekt.name] = content_type

register_content_type_for_thing_instance classmethod

register_content_type_for_thing_instance(thing_id: str, content_type: str) -> None

Register a content type for a specific Thing instance.

Parameters:

Name Type Description Default

thing_id

str

the id of the Thing

required

content_type

str

the content type to be used

required
Source code in repo/hololinked/hololinked/injection.py
@classmethod
def register_content_type_for_thing_instance(cls, thing_id: str, content_type: str) -> None:
    """
    Register a content type for a specific Thing instance.

    Parameters
    ----------
    thing_id: str
        the id of the Thing
    content_type: str
        the content type to be used
    """
    cls.object_content_type_map[thing_id][thing_id] = content_type

register_content_type_for_object_per_thing_instance classmethod

register_content_type_for_object_per_thing_instance(thing_id: str, objekt: str | Any, content_type: str) -> None

Register a content type for a property, action or event to use a specific serializer.

Other option is to register a serializer directly, the effects are similar. If no serializer is found, content type could still be used as metadata.

Parameters:

Name Type Description Default

thing_id

str

the id of the Thing that owns the property, action or event

required

objekt

str | Any

the name of the property, action or event

required

content_type

str

the content type to be used

required

Raises:

Type Description
ValueError

if the object is not a Property, Action or Event

Source code in repo/hololinked/hololinked/injection.py
@classmethod
def register_content_type_for_object_per_thing_instance(
    cls,
    thing_id: str,
    objekt: str | Any,
    content_type: str,
) -> None:
    """
    Register a content type for a property, action or event to use a specific serializer.

    Other option is to register a serializer directly, the effects are similar. If no serializer is found,
    content type could still be used as metadata.

    Parameters
    ----------
    thing_id: str
        the id of the Thing that owns the property, action or event
    objekt: str
        the name of the property, action or event
    content_type: str
        the content type to be used

    Raises
    ------
    ValueError
        if the object is not a Property, Action or Event
    """
    from hololinked.core import Action, Event, Property, Thing  # noqa

    if not isinstance(objekt, (Property, Action, Event, str)):
        raise ValueError(f"object must be a Property, Action or Event, got : {type(objekt)}")
    if not isinstance(objekt, str):
        objekt = objekt.name
    if thing_id not in cls.object_content_type_map:
        cls.object_content_type_map[thing_id] = dict()
    cls.object_content_type_map[thing_id][objekt] = content_type

get_content_type_for_object classmethod

get_content_type_for_object(thing_id: str, thing_cls: str, objekt: str) -> str

Retrieve a content type for a given property, action or event.

Parameters:

Name Type Description Default

thing_id

str

the id of the Thing or the Thing that owns the property, action or event

required

thing_cls

str

the class name of the Thing or the Thing that owns the property, action or event

required

objekt

str

the name of the property, action or event

required

Returns:

Type Description
str

the content type for the property, action or event. If no content type is found, the default content type is returned.

Source code in repo/hololinked/hololinked/injection.py
@classmethod
def get_content_type_for_object(self, thing_id: str, thing_cls: str, objekt: str) -> str:
    """
    Retrieve a content type for a given property, action or event.

    Parameters
    ----------
    thing_id: str | Any
        the id of the Thing or the Thing that owns the property, action or event
    thing_cls: str | Any
        the class name of the Thing or the Thing that owns the property, action or event
    objekt: str
        the name of the property, action or event

    Returns
    -------
    str
        the content type for the property, action or event. If no content type is found, the default content type is
        returned.
    """
    if len(self.object_serializer_map) == 0 and len(self.object_content_type_map) == 0:
        return self.default_content_type
    for thing in [thing_id, thing_cls]:  # first thing id, then thing cls
        if thing in self.object_content_type_map and objekt in self.object_content_type_map[thing]:
            return self.object_content_type_map[thing][objekt]
    return self.default_content_type  # JSON is default serializer

get_content_types

get_content_types() -> ContentTypeMap

Get the mapping of content type to serializer.

Returns:

Type Description
ContentTypeMap

a read-only mapping that imports a serializer only when one is looked up

Source code in repo/hololinked/hololinked/injection.py
@content_types.getter
def get_content_types(cls: type[Serializers]) -> ContentTypeMap:
    """
    Get the mapping of content type to serializer.

    Returns
    -------
    ContentTypeMap
        a read-only mapping that imports a serializer only when one is looked up
    """
    if cls._content_types is None:
        cls._content_types = ContentTypeMap(cls)
    return cls._content_types

get_allowed_content_types

get_allowed_content_types() -> list[str]

Get a list of all allowed content types for serialization.

Set global_config.ALLOW_PICKLE to True to allow pickle content type, which is not allowed by default for security reasons.

Returns:

Type Description
list[str]

a list of allowed content types

Source code in repo/hololinked/hololinked/injection.py
@allowed_content_types.getter
def get_allowed_content_types(cls) -> list[str]:
    """
    Get a list of all allowed content types for serialization.

    Set `global_config.ALLOW_PICKLE` to `True` to allow pickle content type,
    which is not allowed by default for security reasons.

    Returns
    -------
    list[str]
        a list of allowed content types
    """
    _allowed_content_types = list(cls.content_type_names.keys())
    for content_type, name in list(cls.content_type_names.items()):
        # the name is compared instead of the serializer, so that asking which content types are allowed
        # never imports the pickle serializer
        if name != "pickle":
            continue
        _allowed_content_types.remove(content_type)
        if global_config.ALLOW_PICKLE:
            _allowed_content_types.append(content_type)
    return _allowed_content_types

reset classmethod

reset() -> None

Reset the serializer registry.

Source code in repo/hololinked/hololinked/injection.py
@classmethod
def reset(cls) -> None:
    """Reset the serializer registry."""
    cls.object_content_type_map.clear()
    cls.object_serializer_map.clear()
    cls.protocol_serializer_map.clear()
    cls.forget_adapters()