Skip to content

sob.meta

Meta

Bases: sob.abc.Meta

This is a base class for sob.ObjectMeta, sob.ArrayMeta, and sob.DictionaryMeta, and implements methods common to these three classes.

ObjectMeta

ObjectMeta(
    properties: (
        collections.abc.Mapping[str, sob.abc.Property]
        | collections.abc.Iterable[
            tuple[str, sob.abc.Property]
        ]
        | sob.abc.Properties
        | None
    ) = None,
)

Bases: sob.meta.Meta, sob.abc.ObjectMeta

This class holds metadata for a sub-class or instance of sob.Object.

Attributes:

  • properties (sob.abc.Properties | None) –

    This is a dictionary-like object mapping property names to a corresponding instance (or sub-class instance) of sob.Property for a sub-class or sub-class instance of sob.Object . Attempting to set values for a property which do not correspond to the property metadata will raise a TypeError. Deserializing data with dictionary keys not corresponding to a defined property will not raise an error on deserializing, but will raise an sob.ValidationError when/if the instance is validated using sob.validate .

Source code in sob/meta.py
138
139
140
141
142
143
144
145
146
def __init__(
    self,
    properties: Mapping[str, abc.Property]
    | Iterable[tuple[str, abc.Property]]
    | abc.Properties
    | None = None,
) -> None:
    self._properties: abc.Properties | None = None
    self.properties = properties  # type: ignore

DictionaryMeta

DictionaryMeta(
    value_types: (
        collections.abc.Iterable[sob.abc.Property | type]
        | sob.abc.Types
        | None
        | sob.abc.Property
        | type
    ) = None,
)

Bases: sob.meta.Meta, sob.abc.DictionaryMeta

This class holds metadata for a sub-class or instance of sob.Dictionary.

Attributes:

  • value_types (sob.abc.Types | None) –

    This is a sequence of types and/or instances of sob.Property or one of its sub-classes determining the types of values which can be stored in a sub-class or sub-class instance of sob.Dictionary . Attempting to set values of a type not described by the dictionary value types will raise a TypeError.

Source code in sob/meta.py
190
191
192
193
194
195
196
197
198
199
def __init__(
    self,
    value_types: Iterable[abc.Property | type]
    | abc.Types
    | None
    | abc.Property
    | type = None,
) -> None:
    self._value_types: abc.Types | None = None
    self.value_types = value_types  # type: ignore

ArrayMeta

ArrayMeta(
    item_types: (
        collections.abc.Iterable[sob.abc.Property | type]
        | sob.abc.Types
        | None
        | sob.abc.Property
        | type
    ) = None,
)

Bases: sob.meta.Meta, sob.abc.ArrayMeta

This class holds metadata for a sub-class or instance of sob.Array.

Attributes:

  • item_types (sob.abc.Types | None) –

    This is a sequence of types and/or instances of sob.Property or one of its sub-classes determining the types of items which can be stored in a sub-class or sub-class instance of sob.Array . Attempting to insert or append items of a type not described by the array item types will raise a TypeError.

Source code in sob/meta.py
246
247
248
249
250
251
252
253
254
255
def __init__(
    self,
    item_types: Iterable[abc.Property | type]
    | abc.Types
    | None
    | abc.Property
    | type = None,
):
    self._item_types: abc.Types | None = None
    self.item_types = item_types  # type: ignore

Properties

Properties(
    items: (
        collections.abc.Mapping[str, sob.abc.Property]
        | collections.abc.Iterable[
            tuple[str, sob.abc.Property]
        ]
        | sob.abc.Properties
        | None
    ) = None,
)

Bases: sob.abc.Properties

Instances of this class are dictionary-like objects mapping property names to a corresponding instance (or sub-class instance) of sob.Property .

Source code in sob/meta.py
291
292
293
294
295
296
297
298
299
300
def __init__(
    self,
    items: Mapping[str, abc.Property]
    | Iterable[tuple[str, abc.Property]]
    | abc.Properties
    | None = None,
) -> None:
    self._dict: dict[str, abc.Property] = {}
    if items is not None:
        self.update(items)

read_model_meta

read_model_meta(
    model: type | sob.abc.Model,
) -> sob.abc.Meta | None

Read the metadata associated with a sub-class or instance of sob.Model, or return None if no metadata is defined.

Please note that the returned metadata may be inherited, and therefore should not be modified. Use get_writable_model_meta to retrieve an instance of this metadata suitable for modification.

Source code in sob/meta.py
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
def read_model_meta(model: type | abc.Model) -> abc.Meta | None:
    """
    Read the metadata associated with a sub-class or instance of `sob.Model`,
    or return `None` if no metadata is defined.

    Please note that the returned metadata may be inherited,
    and therefore should not be modified. Use `get_writable_model_meta` to
    retrieve an instance of this metadata suitable for modification.
    """
    message: str
    if isinstance(model, abc.Model):
        return getattr(model, "_instance_meta", None) or read_model_meta(
            type(model)
        )
    if isinstance(model, type) and issubclass(model, abc.Model):
        base: type | None
        try:
            return next(
                getattr(base, "_class_meta", None)
                for base in filter(
                    lambda base: issubclass(base, abc.Model),
                    model.__mro__,
                )
            )
        except StopIteration:
            return None
    repr_model: str = represent(model)
    message = (
        "{} requires a parameter which is an instance or sub-class of "
        "`{}`, not{}".format(
            get_calling_function_qualified_name(),
            get_qualified_name(abc.Model),
            (f":\n{repr_model}" if "\n" in repr_model else f" `{repr_model}`"),
        )
    )
    raise TypeError(message)

read_object_meta

read_object_meta(
    model: type | sob.abc.Object,
) -> sob.abc.ObjectMeta | None

Read the metadata associated with a sub-class or instance of sob.Object, or return None if no metadata is defined.

Please note that the returned metadata may be inherited, and therefore should not be modified. Use get_writable_object_meta to retrieve an instance of this metadata suitable for modification.

Source code in sob/meta.py
505
506
507
508
509
510
511
512
513
514
def read_object_meta(model: type | abc.Object) -> abc.ObjectMeta | None:
    """
    Read the metadata associated with a sub-class or instance of `sob.Object`,
    or return `None` if no metadata is defined.

    Please note that the returned metadata may be inherited,
    and therefore should not be modified. Use `get_writable_object_meta` to
    retrieve an instance of this metadata suitable for modification.
    """
    return read_model_meta(model)  # type: ignore

read_array_meta

read_array_meta(
    model: type | sob.abc.Array,
) -> sob.abc.ArrayMeta | None

Read the metadata associated with a sub-class or instance of sob.Array, or return None if no metadata is defined.

Please note that the returned metadata may be inherited, and therefore should not be modified. Use get_writable_array_meta to retrieve an instance of this metadata suitable for modification.

Source code in sob/meta.py
523
524
525
526
527
528
529
530
531
532
def read_array_meta(model: type | abc.Array) -> abc.ArrayMeta | None:
    """
    Read the metadata associated with a sub-class or instance of `sob.Array`,
    or return `None` if no metadata is defined.

    Please note that the returned metadata may be inherited,
    and therefore should not be modified. Use `get_writable_array_meta` to
    retrieve an instance of this metadata suitable for modification.
    """
    return read_model_meta(model)  # type: ignore

read_dictionary_meta

read_dictionary_meta(
    model: type[sob.abc.Dictionary] | sob.abc.Dictionary,
) -> sob.abc.DictionaryMeta | None

Read metadata from a sub-class or instance of sob.Dictionary.

Please note that the returned metadata may be inherited, and therefore should not be modified. Use get_writable_dictionary_hooks to retrieve an instance of this metadata suitable for modification.

Source code in sob/meta.py
541
542
543
544
545
546
547
548
549
550
551
def read_dictionary_meta(
    model: type[abc.Dictionary] | abc.Dictionary,
) -> abc.DictionaryMeta | None:
    """
    Read metadata from a sub-class or instance of `sob.Dictionary`.

    Please note that the returned metadata may be inherited,
    and therefore should not be modified. Use `get_writable_dictionary_hooks`
    to retrieve an instance of this metadata suitable for modification.
    """
    return read_model_meta(model)  # type: ignore

get_writable_model_meta

get_writable_model_meta(
    model: type | sob.abc.Model,
) -> sob.abc.Meta

Retrieve an instance of sob.Meta which is associated directly with the model class or instance, and therefore suitable for modifying.

If model is an instance of an sob.Model sub-class, and the instance does not have any metadata associated, the class hooks will be copied to the instance and returned

If model is a sub-class of sob.Model, but does not have any metadata associated, hooks will be copied from the first parent class which has metadata attributed, and the copy will be returned.

If neither the model class or instance, nor any parent classes, have any metadata associated—a new instance of sob.Meta will be created, attributed to model, and returned.

Source code in sob/meta.py
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
def get_writable_model_meta(model: type | abc.Model) -> abc.Meta:
    """
    Retrieve an instance of `sob.Meta` which is associated directly with the
    `model` class or instance, and therefore suitable for modifying.

    If `model` is an instance of an `sob.Model` sub-class, and the instance
    does not have any metadata associated, the class hooks will be
    copied to the instance and returned

    If `model` is a sub-class of `sob.Model`, but does not have any metadata
    associated, hooks will be copied from the first parent class which
    has metadata attributed, and the copy will be returned.

    If neither the `model` class or instance, nor any parent classes,
    have any metadata associated—a new instance of `sob.Meta` will be
    created, attributed to `model`, and returned.
    """
    if not _is_model(model):
        raise TypeError(model)
    if isinstance(model, abc.Model):
        if model._instance_meta is None:  # noqa: SLF001
            model._instance_meta = deepcopy(  # noqa: SLF001
                read_model_meta(type(model))
            )
        if model._instance_meta is None:  # noqa: SLF001
            model._instance_meta = (  # noqa: SLF001
                ObjectMeta()
                if isinstance(model, abc.Object)
                else ArrayMeta()
                if isinstance(model, abc.Array)
                else DictionaryMeta()
            )
        return model._instance_meta  # noqa: SLF001
    if isinstance(model, type) and issubclass(model, abc.Model):
        if model._class_meta is None:  # noqa: SLF001
            model._class_meta = deepcopy(  # noqa: SLF001
                read_model_meta(model)
            )
        if model._class_meta is None:  # noqa: SLF001
            model._class_meta = (  # noqa: SLF001
                ObjectMeta()
                if issubclass(model, abc.Object)
                else ArrayMeta()
                if issubclass(model, abc.Array)
                else DictionaryMeta()
            )
        return model._class_meta  # noqa: SLF001
    repr_model: str = represent(model)
    message: str = (
        "{} requires a parameter which is an instance or sub-class of "
        "`{}`, not{}".format(
            get_calling_function_qualified_name(),
            get_qualified_name(abc.Model),
            (":\n" + repr_model if "\n" in repr_model else f" `{repr_model}`"),
        )
    )
    raise TypeError(message)

get_writable_object_meta

get_writable_object_meta(
    object_: type[sob.abc.Object] | sob.abc.Object,
) -> sob.abc.ObjectMeta

Retrieve an instance of sob.ObjectMeta which is associated directly with the model class or instance, and therefore suitable for modifying.

If model is an instance of an sob.Object sub-class, and the instance does not have any metadata associated, the class metadata will be copied to the instance and returned.

If model is a sub-class of sob.Object, but does not have any metadata associated, metadata will be copied from the first parent class which has metadata attributed, and the copy will be returned.

If neither the model class or instance, nor any parent classes, have any metadata associated—a new instance of sob.ObjectMeta will be created, attributed to model, and returned.

Source code in sob/meta.py
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
def get_writable_object_meta(
    object_: type[abc.Object] | abc.Object,
) -> abc.ObjectMeta:
    """
    Retrieve an instance of `sob.ObjectMeta` which is associated directly with
    the `model` class or instance, and therefore suitable for modifying.

    If `model` is an instance of an `sob.Object` sub-class, and the instance
    does not have any metadata associated, the class metadata will be
    copied to the instance and returned.

    If `model` is a sub-class of `sob.Object`, but does not have any metadata
    associated, metadata will be copied from the first parent class which
    has metadata attributed, and the copy will be returned.

    If neither the `model` class or instance, nor any parent classes,
    have any metadata associated—a new instance of `sob.ObjectMeta` will be
    created, attributed to `model`, and returned.
    """
    return get_writable_model_meta(object_)  # type: ignore

get_writable_array_meta

get_writable_array_meta(
    model: type | sob.abc.Array,
) -> sob.abc.ArrayMeta

Retrieve an instance of sob.ArrayMeta which is associated directly with the model class or instance, and therefore suitable for modifying.

If model is an instance of an sob.Array sub-class, and the instance does not have any metadata associated, the class metadata will be copied to the instance and returned.

If model is a sub-class of sob.Array, but does not have any metadata associated, metadata will be copied from the first parent class which has metadata attributed, and the copy will be returned.

If neither the model class or instance, nor any parent classes, have any metadata associated—a new instance of sob.ArrayMeta will be created, attributed to model, and returned.

Source code in sob/meta.py
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
def get_writable_array_meta(model: type | abc.Array) -> abc.ArrayMeta:
    """
    Retrieve an instance of `sob.ArrayMeta` which is associated directly with
    the `model` class or instance, and therefore suitable for modifying.

    If `model` is an instance of an `sob.Array` sub-class, and the instance
    does not have any metadata associated, the class metadata will be
    copied to the instance and returned.

    If `model` is a sub-class of `sob.Array`, but does not have any metadata
    associated, metadata will be copied from the first parent class which
    has metadata attributed, and the copy will be returned.

    If neither the `model` class or instance, nor any parent classes,
    have any metadata associated—a new instance of `sob.ArrayMeta` will be
    created, attributed to `model`, and returned.
    """
    return get_writable_model_meta(model)  # type: ignore

get_writable_dictionary_meta

get_writable_dictionary_meta(
    model: type | sob.abc.Dictionary,
) -> sob.abc.DictionaryMeta

Retrieve an instance of sob.DictionaryMeta which is associated directly with the model class or instance, and therefore suitable for writing metadata to.

If model is an instance of an sob.Dictionary sub-class, and the instance does not have any metadata associated, the parent class metadata will be copied to the instance and returned.

If model is a sub-class of sob.Dictionary, but does not have any metadata associated, metadata will be copied from the first parent class which does have metadata attributed.

If neither the model class or instance, nor any parent classes, have any metadata associated—a new instance of sob.DictionaryMeta will be created, attributed to model, and returned.

Source code in sob/meta.py
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
def get_writable_dictionary_meta(
    model: type | abc.Dictionary,
) -> abc.DictionaryMeta:
    """
    Retrieve an instance of `sob.DictionaryMeta` which is associated directly
    with the `model` class or instance, and therefore suitable for writing
    metadata to.

    If `model` is an instance of an `sob.Dictionary` sub-class, and the
    instance does not have any metadata associated, the parent class metadata
    will be copied to the instance and returned.

    If `model` is a sub-class of `sob.Dictionary`, but does not have any
    metadata associated, metadata will be copied from the first parent class
    which does have metadata attributed.

    If neither the `model` class or instance, nor any parent classes,
    have any metadata associated—a new instance of `sob.DictionaryMeta` will be
    created, attributed to `model`, and returned.
    """
    return get_writable_model_meta(model)  # type: ignore

get_model_meta_type

get_model_meta_type(model: type | sob.abc.Model) -> type

Determine the type of metadata required for the specified model class or instance.

Source code in sob/meta.py
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
def get_model_meta_type(model: type | abc.Model) -> type:
    """
    Determine the type of metadata required for the specified `model`
    class or instance.
    """
    meta_type: type | None
    if not isinstance(model, (type, abc.Object, abc.Dictionary, abc.Array)):
        raise TypeError(model)
    if isinstance(model, type):
        if not issubclass(model, (abc.Object, abc.Dictionary, abc.Array)):
            raise TypeError(model)
        meta_type = (
            ObjectMeta
            if issubclass(model, abc.Object)
            else ArrayMeta
            if issubclass(model, abc.Array)
            else DictionaryMeta
        )
    else:
        meta_type = (
            ObjectMeta
            if isinstance(model, abc.Object)
            else ArrayMeta
            if isinstance(model, abc.Array)
            else DictionaryMeta
        )
    return meta_type

write_model_meta

write_model_meta(
    model: type[sob.abc.Model] | sob.abc.Model,
    meta: sob.abc.Meta | None,
) -> None

Write metadata to a sub-class or instance of sob.Model.

Source code in sob/meta.py
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
def write_model_meta(
    model: type[abc.Model] | abc.Model, meta: abc.Meta | None
) -> None:
    """
    Write metadata to a sub-class or instance of `sob.Model`.
    """
    if meta is not None:
        # Verify that the metadata is of the correct type
        meta_type: type[abc.Meta] = get_model_meta_type(model)
        if not isinstance(meta, meta_type):
            message: str = (
                f"Metadata assigned to `{get_qualified_name(type(model))}` "
                f"must be of type `{get_qualified_name(meta_type)}`"
            )
            raise ValueError(message)
    if isinstance(model, abc.Model):
        model._instance_meta = meta  # noqa: SLF001
    else:
        if not issubclass(model, abc.Model):
            raise TypeError(model)
        model._class_meta = meta  # noqa: SLF001

get_model_pointer

get_model_pointer(model: sob.abc.Model) -> str | None

Get the JSON pointer associated with this model. Please note that this will typically only be available for models which have been deserialized from JSON data, otherwise, this function will return None (unless explicitly set using set_model_pointer on this instance, or a parent).

Source code in sob/meta.py
762
763
764
765
766
767
768
769
def get_model_pointer(model: abc.Model) -> str | None:
    """
    Get the JSON pointer associated with this model. Please note that this
    will typically only be available for models which have been deserialized
    from JSON data, otherwise, this function will return `None` (unless
    explicitly set using `set_model_pointer` on this instance, or a parent).
    """
    return model._pointer  # noqa: SLF001

set_model_pointer

set_model_pointer(
    model: sob.abc.Model, pointer_: str | None
) -> None

Set the JSON pointer associated with this model, and all models assigned to object properties, array items, or dictionary values of this model.

Source code in sob/meta.py
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
def set_model_pointer(model: abc.Model, pointer_: str | None) -> None:
    """
    Set the JSON pointer associated with this model, and all models
    assigned to object properties, array items, or dictionary values
    of this model.
    """
    key: str
    value: Any
    model._pointer = pointer_  # noqa: SLF001
    if isinstance(model, abc.Dictionary):
        for key, value in model.items():
            if isinstance(
                value,
                (abc.Object, abc.Dictionary, abc.Array),
            ):
                set_model_pointer(
                    value,
                    "{}/{}".format(
                        pointer_,
                        (
                            escape_reference_token(key)
                            if isinstance(key, str)
                            else str(key)
                        ),
                    ),
                )
    elif isinstance(model, abc.Object):
        property_name: str
        property_: abc.Property
        for property_name, property_ in _read_object_properties(model) or ():
            key = property_.name or property_name
            value = getattr(model, property_name)
            if isinstance(
                value,
                (abc.Object, abc.Dictionary, abc.Array),
            ):
                set_model_pointer(
                    value,
                    "{}/{}".format(
                        pointer_,
                        (
                            escape_reference_token(key)
                            if isinstance(key, str)
                            else str(key)
                        ),
                    ),
                )
    elif isinstance(model, abc.Array):
        index: int
        for index in range(len(model)):
            value = model[index]
            if isinstance(
                value,
                (abc.Object, abc.Dictionary, abc.Array),
            ):
                set_model_pointer(value, f"{pointer_}/{index!s}")

pointer

pointer(
    model: sob.abc.Model, pointer_: str | None = None
) -> str | None

Get or set a model's pointer

Source code in sob/meta.py
871
872
873
874
875
876
877
878
879
880
881
882
883
884
@deprecated(
    "`sob.meta.pointer` is deprecated and will be removed in sob 3. "
    "Use `sob.get_model_pointer` and `sob.set_model_pointer` "
    "instead.",
)
def pointer(model: abc.Model, pointer_: str | None = None) -> str | None:
    """
    Get or set a model's pointer
    """
    if not isinstance(model, (abc.Object, abc.Dictionary, abc.Array)):
        raise TypeError(model)
    if pointer_ is not None:
        set_model_pointer(model, pointer_)
    return get_model_pointer(model)

set_model_url

set_model_url(
    model_instance: sob.abc.Model, source_url: str | None
) -> None

Set a source URL to be associated with this model, and all models assigned to object properties, array items, or dictionary values of this model.

Source code in sob/meta.py
918
919
920
921
922
923
924
925
926
927
928
929
930
931
def set_model_url(model_instance: abc.Model, source_url: str | None) -> None:
    """
    Set a source URL to be associated with this model, and all models
    assigned to object properties, array items, or dictionary values
    of this model.
    """
    if not isinstance(model_instance, (abc.Object, abc.Dictionary, abc.Array)):
        raise TypeError(model_instance)
    if (source_url is not None) and not isinstance(source_url, str):
        raise TypeError(source_url)
    model_instance._url = source_url  # noqa: SLF001
    child_model: abc.Model
    for child_model in _traverse_models(model_instance):
        set_model_url(child_model, source_url)

get_model_url

get_model_url(model: sob.abc.Model) -> str | None

Get the source URL from which this model was deserialized.

Source code in sob/meta.py
940
941
942
943
944
def get_model_url(model: abc.Model) -> str | None:
    """
    Get the source URL from which this model was deserialized.
    """
    return model._url  # noqa: SLF001

version_model

version_model(
    data: sob.abc.Model,
    specification: str,
    version_number: (
        str | int | collections.abc.Sequence[int]
    ),
) -> None

Recursively alters model class or instance metadata based on version number metadata associated with an object's properties. This allows one data model to represent multiple versions of a specification and dynamically change based on the version of a specification represented.

Parameters:

  • data (sob.model.Model)
  • specification (str): The specification to which the version_number argument applies.
  • version_number (str|int|[int]): A version number represented as text (in the form of integers separated by periods), an integer, or a sequence of integers.
Source code in sob/meta.py
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
def version_model(
    data: abc.Model,
    specification: str,
    version_number: str | int | Sequence[int],
) -> None:
    """
    Recursively alters model class or instance metadata based on version number
    metadata associated with an object's properties. This allows one data model
    to represent multiple versions of a specification and dynamically change
    based on the version of a specification represented.

    Parameters:

    - data ([sob.model.Model](#Model))
    - specification (str): The specification to which the `version_number`
      argument applies.
    - version_number (str|int|[int]): A version number represented as text
      (in the form of integers separated by periods), an integer, or a
      sequence of integers.
    """
    if not (
        isinstance(version_number, (str, float))
        or (
            isinstance(version_number, Sequence)
            and isinstance(next(iter(version_number)), int)
        )
    ):
        raise TypeError(version_number)
    if not isinstance(data, abc.Model):
        raise TypeError(data)
    if isinstance(data, abc.Object):
        _version_object(data, specification, version_number)
    elif isinstance(data, abc.Dictionary):
        _version_dictionary(data, specification, version_number)
    elif isinstance(data, abc.Array):
        _version_array(data, specification, version_number)