Skip to content

typelib

The top-level API for typelib.

Typical Usage

>>> import dataclasses
>>> import typelib
>>>
>>> @dataclasses.dataclass
... class Data:
...     attr: int
...     key: str
...
>>>
>>> typelib.unmarshal(Data, '{"key":"string","attr":"1"}')
Data(attr=1, key='string')
>>> typelib.marshal(Data(attr=1, key='string'))
{'attr': 1, 'key': 'string'}
>>> codec = typelib.codec(Data)
>>> codec.encode(Data(attr=1, key='string'))
b'{"attr":1,"key":"string"}'
>>> codec.decode(b'{"key":"string","attr":1}')
Data(attr=1, key='string')

AbstractMarshaller

AbstractMarshaller(t: type[T], context: ContextT, *, var: str | None = None)

Bases: ABC, Generic[T]

Abstract base class defining the common interface for marshallers.

Marshallers are custom callables which maintain type-specific information. They use this information to provide robust, performant logic reducing Python objects into their primitive representations for over-the-wire encoding.

Marshallers support contextual serialization, which enables the marshalling of nested types.

Attributes:

  • t (type[T]) –

    The root type of this marshaller.

  • origin (type[T]) –

    If t is a generic, this will be an actionable runtime type related to t, otherwise it is the same as t.

  • context (ContextT) –

    The complete type context for this unmarshaller.

  • var (str | None) –

    If this unmarshaller is used in a nested context, this will reference the field/parameter/index at which this unmarshaller should be used.

Parameters:

  • t (type[T]) –

    The root type of this marshaller.

  • context (ContextT) –

    The complete type context for this marshaller.

  • var (str | None, default: None ) –

    The associated field or parameter name for this unmarshaller (optional).

Source code in src/typelib/marshals/routines.py
def __init__(self, t: type[T], context: ContextT, *, var: str | None = None):
    """Construct a marshaller instance.

    Args:
        t: The root type of this marshaller.
        context: The complete type context for this marshaller.
        var: The associated field or parameter name for this unmarshaller (optional).
    """
    self.t = t
    self.origin = inspection.origin(self.t)
    self.context = context
    self.var = var

AbstractUnmarshaller

AbstractUnmarshaller(t: type[T], context: ContextT, *, var: str | None = None)

Bases: ABC, Generic[T]

Abstract base class defining the common interface for unmarshallers.

Unmarshallers are custom callables which maintain type-specific information. They use this information to provide robust, performant logic for decoding and converting primtive Python objects or JSON-endcoded data into their target type.

Unmarshallers support contextual deserialization, which enables the unmarshalling of nested types.

Attributes:

  • t (type[T]) –

    The root type of this unmarshaller.

  • origin (type[T]) –

    If t is a generic, this will be an actionable runtime type related to t, otherwise it is the same as t.

  • context (ContextT) –

    The complete type context for this unmarshaller.

  • var (str | None) –

    If this unmarshaller is used in a nested context, this will reference the field/parameter/index at which this unmarshaller should be used.

Parameters:

  • t (type[T]) –

    The root type of this unmarshaller.

  • context (ContextT) –

    The complete type context for this unmarshaller.

  • var (str | None, default: None ) –

    The associated field or parameter name for this unmarshaller (optional).

Source code in src/typelib/unmarshals/routines.py
def __init__(self, t: type[T], context: ContextT, *, var: str | None = None):
    """Construct an unmarshaller instance.

    Args:
        t: The root type of this unmarshaller.
        context: The complete type context for this unmarshaller.
        var: The associated field or parameter name for this unmarshaller (optional).
    """
    self.t = t
    self.origin = inspection.origin(self.t)
    self.context = context
    self.var = var

__call__ abstractmethod

__call__(val: Any) -> T

Unmarshall a Python object into its target type.

Not implemented for the abstract base class.

Source code in src/typelib/unmarshals/routines.py
@abc.abstractmethod
def __call__(self, val: tp.Any) -> T:
    """Unmarshall a Python object into its target type.

    Not implemented for the abstract base class.
    """

Codec dataclass

Codec(marshal: AbstractMarshaller[T], unmarshal: AbstractUnmarshaller[T], encoder: EncoderT, decoder: DecoderT)

Bases: Generic[T]

A standard wire protocol (codec).

This codec enables you to directly encode and decode your data model into your wire protocol.

decoder instance-attribute

decoder: DecoderT

The decoder used to deserialize a bytes-like object into a Python data structure for marshalling into T.

encoder instance-attribute

encoder: EncoderT

The encoder used to serialize a marshalled T into bytes.

marshal instance-attribute

marshal: AbstractMarshaller[T]

The marshaller used to convert an instance of T to a serializable object.

unmarshal instance-attribute

unmarshal: AbstractUnmarshaller[T]

The unmarshaller used to convert a deserialized object into an instance of T.

decode

decode(value: bytes) -> T

Decode an instance of T from bytes.

We will first decode the data from bytes using the decoder, then unmarshal the data into an instance of T using unmarshal.

Parameters:

  • value (bytes) –

    The bytes to decode.

Source code in src/typelib/codecs.py
def decode(self, value: bytes) -> T:
    """Decode an instance of `T` from bytes.

    We will first decode the data from bytes using the
    [`decoder`][typelib.Codec.decoder], then unmarshal the data into an
    instance of `T` using [`unmarshal`][typelib.Codec.unmarshal].

    Args:
        value: The bytes to decode.
    """
    decoded = self.decoder(value)
    unmarshalled = self.unmarshal(decoded)
    return unmarshalled

encode

encode(value: T) -> bytes

Encode an instance of T to bytes.

We will first marshal the given instance using the marshal, then encode the marshalled data into bytes using the encoder.

Parameters:

  • value (T) –

    The instance to encode.

Source code in src/typelib/codecs.py
def encode(self, value: T) -> bytes:
    """Encode an instance of `T` to bytes.

    We will first marshal the given instance using the
    [`marshal`][typelib.Codec.marshal], then encode the marshalled data
    into bytes using the [`encoder`][typelib.Codec.encoder].

    Args:
        value: The instance to encode.
    """
    marshalled = self.marshal(value)
    encoded = self.encoder(marshalled)
    return encoded

codec

codec(t: type[T], *, marshaller: AbstractMarshaller[T] | None = None, unmarshaller: AbstractUnmarshaller[T] | None = None, encoder: EncoderT = compat.json.dumps, decoder: DecoderT = compat.json.loads, codec_cls: type[CodecT[T]] | None = None) -> CodecT[T]

Factory function for creating a Codec instance.

Note

In the simplest case, all that needs be provided is the first parameter (t). We will generate a marshaller, unmarshaller and build a codec. However, we provide ample means for customization:

  • You can pass in a subclass of Codec to codec_cls.
  • You may supply custom marshaller or unmarshaller callables - we will generate one using the high-level APIs from marshals and unmarshals if not supplied.
  • The encoder and decoder default to JSON, using either stdlib json or orjson if available. You may provide custom encoder and decoder callables, the only requirement is they ser/des to/from bytes.

Tip

If you installed the json extra when you installed this library, then you have installed orjson.

Parameters:

  • t (type[T]) –

    The type to create the interchange protocol for.

  • marshaller (AbstractMarshaller[T] | None, default: None ) –

    The marshaller used to marshal inputs into the associated type. (optional)

  • unmarshaller (AbstractUnmarshaller[T] | None, default: None ) –

    The unmarshaller used to unmarshal inputs into the associated type. (optional)

  • encoder (EncoderT, default: dumps ) –

    The encoder for encoding data for over-the-wire (defaults to JSON).

  • decoder (DecoderT, default: loads ) –

    The decoder for decoding data from over-the-wire (defaults to JSON).

  • codec_cls (type[CodecT[T]] | None, default: None ) –

    The codec class definition, if overloading (optional).

Source code in src/typelib/codecs.py
@compat.cache
def codec(
    t: type[T],
    *,
    marshaller: marshals.AbstractMarshaller[T] | None = None,
    unmarshaller: unmarshals.AbstractUnmarshaller[T] | None = None,
    encoder: EncoderT = compat.json.dumps,
    decoder: DecoderT = compat.json.loads,
    codec_cls: type[CodecT[T]] | None = None,
) -> CodecT[T]:
    """Factory function for creating a [`Codec`][typelib.Codec] instance.

    Note:
        In the simplest case, all that needs be provided is the first parameter (`t`). We will
        generate a marshaller, unmarshaller and build a codec. However, we provide ample
        means for customization:

        - You can pass in a subclass of [`Codec`][typelib.codecs.Codec] to `codec_cls`.
        - You may supply custom `marshaller` or `unmarshaller` callables - we will generate
          one using the high-level APIs from [`marshals`][typelib.marshals] and
          [`unmarshals`][typelib.unmarshals] if not supplied.
        - The `encoder` and `decoder` default to JSON, using either
          stdlib [`json`][] or [`orjson`](https://github.com/ijl/orjson){.external}
          if available. You may provide custom `encoder` and `decoder` callables, the only
          requirement is they ser/des to/from `bytes`.

        /// tip
        If you installed the `json` extra when you installed this library, then you have
        installed [`orjson`](https://github.com/ijl/orjson){.external}.
        ///

    Args:
        t: The type to create the interchange protocol for.
        marshaller: The marshaller used to marshal inputs into the associated type. (optional)
        unmarshaller: The unmarshaller used to unmarshal inputs into the associated type. (optional)
        encoder: The encoder for encoding data for over-the-wire (defaults to JSON).
        decoder: The decoder for decoding data from over-the-wire (defaults to JSON).
        codec_cls: The codec class definition, if overloading (optional).

    """
    marshal = marshaller or marshals.marshaller(t=t)
    unmarshal = unmarshaller or unmarshals.unmarshaller(t=t)
    cls = codec_cls or Codec
    if inspection.isbytestype(t):
        cdc = cls(
            marshal=marshal,
            unmarshal=unmarshal,
            encoder=lambda v: v,  # type: ignore[arg-type,return-value]
            decoder=lambda v: v,  # type: ignore[arg-type,return-value]
        )
        return cdc
    cdc = cls(
        marshal=marshal,
        unmarshal=unmarshal,
        encoder=encoder,
        decoder=decoder,
    )
    return cdc

decode

decode(t: type[T] | ForwardRef | str, value: bytes, *, decoder: DecoderT = compat.json.loads) -> T

Decode a bytes object into an instance of t.

Parameters:

  • t (type[T] | ForwardRef | str) –

    A type hint for resolving the unmarshaller.

  • value (bytes) –

    The value to decode.

  • decoder (DecoderT, default: loads ) –

    A callable that takes a bytes object and returns a Python value.

Source code in src/typelib/api.py
def decode(
    t: type[T] | refs.ForwardRef | str,
    value: bytes,
    *,
    decoder: DecoderT = compat.json.loads,
) -> T:
    """Decode a bytes object into an instance of `t`.

    Args:
        t: A type hint for resolving the unmarshaller.
        value: The value to decode.
        decoder: A callable that takes a bytes object and returns a Python value.
    """
    decoded = decoder(value)
    unmarshalled = unmarshal(t=t, value=decoded)
    return unmarshalled

encode

encode(value: T, *, t: type[T] | ForwardRef | str | None = None, encoder: EncoderT = compat.json.dumps) -> bytes

Encode a value into a bytes object.

Parameters:

  • value (T) –

    The value to encode.

  • t (type[T] | ForwardRef | str | None, default: None ) –

    A type hint for resolving the marshaller.

  • encoder (EncoderT, default: dumps ) –

    A callable that takes a value and returns a bytes object.

Source code in src/typelib/api.py
def encode(
    value: T,
    *,
    t: type[T] | refs.ForwardRef | str | None = None,
    encoder: EncoderT = compat.json.dumps,
) -> bytes:
    """Encode a value into a bytes object.

    Args:
        value: The value to encode.
        t: A type hint for resolving the marshaller.
        encoder: A callable that takes a value and returns a bytes object.
    """
    marshalled = marshal(value=value, t=t)
    encoded = encoder(marshalled)
    return encoded

marshal

marshal(value: Any, *, t: type[T] | ForwardRef | str | None = None) -> MarshalledValueT

Marshal value from typ into MarshalledValueT.

Parameters:

  • value (Any) –

    The value to reduce to a simple, encode-able type.

  • t (type[T] | ForwardRef | str | None, default: None ) –

    The type to use for building the marshaller (optional). If not provided, we'll default to the type of the input value.

Source code in src/typelib/marshals/api.py
def marshal(
    value: tp.Any, *, t: type[T] | refs.ForwardRef | str | None = None
) -> serdes.MarshalledValueT:
    """Marshal `value` from `typ` into [`MarshalledValueT`][typelib.serdes.MarshalledValueT].

    Args:
        value: The value to reduce to a simple, encode-able type.
        t:
            The type to use for building the marshaller (optional).
            If not provided, we'll default to the type of the input value.
    """
    typ = value.__class__ if t is None else t
    routine: routines.AbstractMarshaller[T] = marshaller(typ)
    unmarshalled = routine(value)
    return unmarshalled

marshaller

marshaller(t: type[T] | ForwardRef | TypeAliasType | str) -> AbstractMarshaller[T]

Get a marshaller routine for a given type.

Parameters:

  • t (type[T] | ForwardRef | TypeAliasType | str) –

    The type annotation to generate a marshaller for. Can be a type, type alias, typing.ForwardRef, or string reference.

Source code in src/typelib/marshals/api.py
@compat.cache
def marshaller(
    t: type[T] | refs.ForwardRef | compat.TypeAliasType | str,
) -> routines.AbstractMarshaller[T]:
    """Get a marshaller routine for a given type.

    Args:
        t:
            The type annotation to generate a marshaller for. Can be a type, type alias,
            [`typing.ForwardRef`][], or string reference.
    """
    nodes = graph.static_order(t)
    context: ctx.TypeContext[routines.AbstractMarshaller] = ctx.TypeContext()
    if not nodes:
        return routines.NoOpMarshaller(t=t, context=context, var=None)  # type: ignore[arg-type]

    # "root" type will always be the final node in the sequence.
    root = nodes[-1]
    for node in nodes:
        context[node.type] = _get_unmarshaller(node, context=context)
        context[node.unwrapped] = context[node.type]

    return context[root.type]

unmarshal

unmarshal(t: type[T] | ForwardRef | str, value: Any) -> T

Unmarshal value into typ.

Parameters:

  • t (type[T] | ForwardRef | str) –

    The type annotation or reference to unmarshal into.

  • value (Any) –

    The value to unmarshal.

Source code in src/typelib/unmarshals/api.py
def unmarshal(t: type[T] | refs.ForwardRef | str, value: tp.Any) -> T:
    """Unmarshal `value` into `typ`.

    Args:
        t: The type annotation or reference to unmarshal into.
        value: The value to unmarshal.
    """
    routine = unmarshaller(t)
    unmarshalled = routine(value)
    return unmarshalled

unmarshaller

unmarshaller(t: type[T] | ForwardRef | TypeAliasType | str) -> AbstractUnmarshaller[T]

Get an un-marshaller routine for a given type.

Parameters:

  • t (type[T] | ForwardRef | TypeAliasType | str) –

    The type annotation to generate an unmarshaller for. May be a type, type alias, typing.ForwardRef, or string reference.

Source code in src/typelib/unmarshals/api.py
@compat.cache
def unmarshaller(
    t: type[T] | refs.ForwardRef | compat.TypeAliasType | str,
) -> routines.AbstractUnmarshaller[T]:
    """Get an un-marshaller routine for a given type.

    Args:
        t: The type annotation to generate an unmarshaller for.
             May be a type, type alias, [`typing.ForwardRef`][], or string reference.
    """
    nodes = graph.static_order(t)
    context: ctx.TypeContext[routines.AbstractUnmarshaller] = ctx.TypeContext()
    if not nodes:
        return routines.NoOpUnmarshaller(t=t, context=context, var=None)  # type: ignore[arg-type]

    # "root" type will always be the final node in the sequence.
    root = nodes[-1]
    for node in nodes:
        context[node.type] = _get_unmarshaller(node, context=context)
        context[node.unwrapped] = context[node.type]

    return context[root.type]