Module multiformats.multicodec

Implementation of the multicodec spec.

The Multicodec dataclass provides a container for multicodec data:

>>> from multiformats import multicodec
>>> from multicodec import Multicodec
>>> Multicodec("identity", "multihash", 0x00, "permanent", "raw binary")
Multicodec(name='identity', tag='multihash', code=0,
           status='permanent', description='raw binary')

Core functionality is provided by the exists() and get() functions, which can be used to check whether a multicodec with given name or code is known, and if so to get the corresponding object:

>>> multicodec.exists("identity")
True
>>> multicodec.exists(0x01)
True
>>> multicodec.get("identity")
Multicodec(name='identity', tag='multihash', code=0,
           status='permanent', description='raw binary')
>>> multicodec.get(0x01)
Multicodec(name='cidv1', tag='ipld', code=1,
           status='permanent', description='CIDv1')

The table() function can be used to iterate through known multicodecs, optionally restricting to one or more tags and/or statuses:

>>> selected = multicodec.table(tag=["ipld", "multiaddr"], status="permanent")
>>> [m.code for m in selected]
[1, 4, 6, 41, 53, 54, 55, 56, 85, 112, 113, 114, 120,
 144, 145, 146, 147, 148, 149, 150, 151, 152, 176, 177,
 178, 192, 193, 290, 297, 400, 421, 460, 477, 478, 479]
Expand source code
"""
    Implementation of the [multicodec spec](https://github.com/multiformats/multicodec).

    The `Multicodec` dataclass provides a container for multicodec data:

    ```py
    >>> from multiformats import multicodec
    >>> from multicodec import Multicodec
    >>> Multicodec("identity", "multihash", 0x00, "permanent", "raw binary")
    Multicodec(name='identity', tag='multihash', code=0,
               status='permanent', description='raw binary')
    ```

    Core functionality is provided by the `exists` and `get` functions, which can be used to check
    whether a multicodec with given name or code is known, and if so to get the corresponding object:

    ```py
    >>> multicodec.exists("identity")
    True
    >>> multicodec.exists(0x01)
    True
    >>> multicodec.get("identity")
    Multicodec(name='identity', tag='multihash', code=0,
               status='permanent', description='raw binary')
    >>> multicodec.get(0x01)
    Multicodec(name='cidv1', tag='ipld', code=1,
               status='permanent', description='CIDv1')
    ```

    The `table` function can be used to iterate through known multicodecs, optionally restricting
    to one or more tags and/or statuses:

    ```py
    >>> selected = multicodec.table(tag=["ipld", "multiaddr"], status="permanent")
    >>> [m.code for m in selected]
    [1, 4, 6, 41, 53, 54, 55, 56, 85, 112, 113, 114, 120,
     144, 145, 146, 147, 148, 149, 150, 151, 152, 176, 177,
     178, 192, 193, 290, 297, 400, 421, 460, 477, 478, 479]
    ```

"""

import csv
from dataclasses import dataclass
from importlib import resources
import re
from typing import Collection, Dict, Iterable, Iterator, Mapping, Optional, Set, Tuple, Union


@dataclass(frozen=True)
class Multicodec:
    """
        Dataclass for a multicodec.

        Example usage:

        ```py
            >>> Multicodec.from_json({
            ...     'name': 'cidv1', 'tag': 'ipld', 'code': '0x01',
            ...     'status': 'permanent', 'description': 'CIDv1'})
            Multicodec(name='cidv1', tag='ipld', code=1,
                       status='permanent', description='CIDv1')
        ```

        Direct instantiation should be avoided: it is field-order dependent
        and might change without warning in the future.

    """

    name: str
    """
        Multicodec name. Must satisfy the following:

        ```py
        re.match(r"^[a-z][a-z0-9_-]+$", name)
        ```
    """

    tag: str
    """ Multicodec tag. """

    code: int
    """ Multicodec code. Must be a non-negative integer. """

    status: str
    """ Multicodec status. Must be 'draft' or 'permanent'."""

    description: str
    """ Multicodec description. """

    def __post_init__(self):
        if not re.match(r"^[a-z][a-z0-9_-]+$", self.name):
            raise ValueError(f"Invalid multicodec name {repr(self.name)}")
        if self.status not in ("draft", "permanent"):
            raise ValueError(f"Invalid multicodec status {repr(self.status)}.")
        if self.code < 0:
            raise ValueError(f"Invalid multicodec code {repr(self.code)}.")

    @property
    def hexcode(self) -> str:
        """
            Multicodec code as a hex string (with hex digits zero-padded to even length):

            Example usage:

            ```py
            >>> m = multicodec.get(1)
            >>> m.code
            1
            >>> m.hexcode
            '0x01'
            ```
        """
        code = hex(self.code)
        if len(code) % 2 != 0:
            code = "0x0"+code[2:]
        return code

    @property
    def is_private_use(self) -> bool:
        """
            Whether this multicodec code is reserved for private use,
            i.e. whether it is in `range(0x300000, 0x400000)`.
        """
        return self.code in range(0x300000, 0x400000)

    def to_json(self) -> Mapping[str, str]:
        """
            Returns a JSON dictionary representation of this multicodec object,
            compatible with the one from the table.csv found in the
            [multicodec spec](https://github.com/multiformats/multicodec).

            Example usage:

            ```py
            >>> m = multicodec.get(1)
            >>> m.to_json()
            {'name': 'cidv1', 'tag': 'ipld', 'code': '0x01',
             'status': 'permanent', 'description': 'CIDv1'}
            ```
        """
        return {
            "name": self.name,
            "tag": self.tag,
            "code": self.hexcode,
            "status": self.status,
            "description": self.description
        }

    @staticmethod
    def from_json(multicodec: Mapping[str, Union[str, int]]) -> "Multicodec":
        """
            Decodes a `Multicodec` object from a JSON dictionary representation
            compatible with the one from the table.csv found in the
            [multicodec spec](https://github.com/multiformats/multicodec).

            Example usage:

            ```py
            >>> m = Multicodec.from_json({
            ...     'name': 'cidv1', 'tag': 'ipld', 'code': '0x01',
            ...     'status': 'permanent', 'description': 'CIDv1'})
            >>> m == multicodec.get(1)
            True
            ```
        """
        name = multicodec["name"]
        tag = multicodec["tag"]
        code = multicodec["code"]
        status = multicodec["status"]
        description = multicodec["description"]
        if not isinstance(name, str):
            raise TypeError(f"Expected string, found {name = }.")
        if not isinstance(tag, str):
            raise TypeError(f"Expected string, found {tag = }.")
        if not isinstance(status, str):
            raise TypeError(f"Expected string, found {status = }.")
        if not isinstance(description, str):
            raise TypeError(f"Expected string, found {description = }.")
        if not isinstance(code, (str, int)):
            raise TypeError(f"Expected string or int, found {code = }")
        if isinstance(code, str):
            if code.startswith("0x"):
                code = code[2:]
            code = int(code, base=16)
        return Multicodec(name, tag, code, status, description)

    def __str__(self) -> str:
        return str(self.to_json())


def get(name_or_code: Union[str, int]) -> Multicodec:
    """
        Gets the multicodec with given name (if a string is passed) or code (if an int is passed).
        Raises `KeyError` if no such multicodec exists.

        Example usage:

        ```py
        >>> multicodec.get("identity")
        Multicodec(name='identity', tag='multihash', code=0,
                   status='permanent', description='raw binary')
        >>> multicodec.get(0x01)
        Multicodec(name='cidv1', tag='ipld', code=1,
                   status='permanent', description='CIDv1')
        ```
    """
    if isinstance(name_or_code, str):
        name: str = name_or_code
        if name not in _name_table:
            raise KeyError(f"No multicodec named {repr(name)}.")
        return _name_table[name]
    code: int = name_or_code
    if code not in _code_table:
        raise KeyError(f"No multicodec with code {repr(code)}.")
    return _code_table[code]


def exists(name_or_code: Union[str, int]) -> bool:
    """
        Checks whether there is a multicodec with the given name (if a string is passed)
        or code (if an int is passed).

        Example usage:

        ```py
        >>> multicodec.exists("identity")
        True
        >>> multicodec.exists(0x01)
        True
        ```
    """
    if isinstance(name_or_code, str):
        name: str = name_or_code
        return name in _name_table
    code: int = name_or_code
    return code in _code_table


def register(m: Multicodec, overwrite: bool = False) -> None:
    """
        Registers a given multicodec. The optional keyword argument `overwrite` (default: `False`)
        can be used to overwrite a multicodec with existing code.

        Raises `ValueError` if a multicodec with the same name exists, or if a multicodec with the
        same code exists and `overwrite` is `False`.

        Example usage:

        ```py
            >>> m = Multicodec("my-multicodec", "my-tag", 0x300001, "draft", "...")
            >>> multicodec.register(m)
            >>> multicodec.exists(0x300001)
            True
            >>> multicodec.get(0x300001).name
            'my-multicodec'
            >>> multicodec.get(0x300001).is_private_use
            True
        ```
    """
    if not overwrite and m.code in _code_table:
        raise ValueError(f"Multicodec with code {repr(m.code)} already exists: {_code_table[m.code]}")
    if m.name in _name_table:
        raise ValueError(f"Multicodec with name {repr(m.name)} already exists: {_name_table[m.name]}")
    _code_table[m.code] = m
    _name_table[m.name] = m


def unregister(name_or_code: Union[str, int]) -> None:
    """
        Unregisters the multicodec with given name (if a string is passed) or code (if an int is passed).
        Raises `KeyError` if no such multicodec exists.

        Example usage:

        ```py
        >>> multicodec.unregister(0x01) # cidv1
        >>> multicodec.exists(0x01)
        False
        ```
    """
    m = get(name_or_code)
    del _code_table[m.code]
    del _name_table[m.name]


def table(tag: Union[None, str, Collection[str]] = None, status: Union[None, str, Collection[str]] = None) -> Iterator[Multicodec]:
    """
        Iterates through the registered multicodecs, in order of ascending code.
        The optional keyword arguments `tag` and `status` can be used to restrict the iterator
        to multicodecs with a given `tag` or `status` respectively.

        Example usage:


        ```py
        >>> selected = multicodec.table(tag=["ipld", "multiaddr"], status="permanent")
        >>> [m.code for m in selected]
        [1, 4, 6, 41, 53, 54, 55, 56, 85, 112, 113, 114, 120,
         144, 145, 146, 147, 148, 149, 150, 151, 152, 176, 177,
         178, 192, 193, 290, 297, 400, 421, 460, 477, 478, 479]
        ```
    """
    tags: Optional[Collection[str]]
    if tag is None:
        tags = None
    elif isinstance(tag, str):
        tags = [tag]
    else:
        tags = tag
    statuses: Optional[Collection[str]]
    if status is None:
        statuses = None
    elif isinstance(status, str):
        statuses = [status]
    else:
        statuses = status
    for code in sorted(_code_table.keys()):
        m = _code_table[code]
        if tags is not None and m.tag not in tags:
            continue
        if statuses is not None and m.status not in statuses:
            continue
        yield m


def build_multicodec_tables(multicodecs: Iterable[Multicodec], *,
                            allow_private_use: bool = False) -> Tuple[Dict[int, Multicodec], Dict[str, Multicodec]]:
    """
        Creates code->multicodec and name->multicodec mappings from a finite iterable of multicodecs,
        returning the mappings.
        The keyword argument `allow_private_use` (default: `False`) can be used to allow multicodec entries
        with private use codes in `range(0x300000, 0x400000)`: if set to `False`, a `ValueError` is raised
        if one such private use code is encountered.

        Raises `ValueError` if the same multicodec code is encountered multiple times, unless exactly one
        of the multicodecs has permanent status (in which case that codec is the one inserted in the table).
        Raises `ValueError` if the same name is encountered multiple times.

        Example usage:

        ```py
            code_table, name_table = build_multicodec_tables(multicodecs)
        ```
    """
    code_table: Dict[int, Multicodec] = {}
    name_table: Dict[str, Multicodec] = {}
    overwritten_draft_codes: Set[int] = set()
    for m in multicodecs:
        if not allow_private_use and m.is_private_use:
            raise ValueError(f"Private use multicodec not allowed: {m}")
        if m.code in code_table:
            if code_table[m.code].status == "permanent":
                if m.status == "draft":
                    # this draft code has been superseded by a permanent one, skip it
                    continue
                raise ValueError(f"Multicodec code {m.hexcode} appears multiple times in table.")
            if m.code != "permanent":
                # overwriting draft code with another draft code: dodgy, need to check at the end
                overwritten_draft_codes.add(m.code)
        code_table[m.code] = m
        if m.name in name_table:
            raise ValueError(f"Multicodec name {m.name} appears multiple times in table.")
        name_table[m.name] = m
    for code in overwritten_draft_codes:
        m = code_table[code]
        if m.status != "permanent":
            raise ValueError(f"Code {m.code} appears multiple times in table, "
                              "but none of the associated multicodecs is permanent.")
    return code_table, name_table

# Create the global code->multicodec and name->multicodec mappings.
# _code_table: Dict[str, Encoding] = {}
# _name_table: Dict[str, Encoding] = {}
with resources.open_text("multiformats", "multicodec-table.csv") as csv_table:
    reader = csv.DictReader(csv_table)
    multicodecs = (Multicodec.from_json({k.strip(): v.strip() for k, v in _row.items()})
                   for _row in reader)
    _code_table, _name_table = build_multicodec_tables(multicodecs)

Functions

def build_multicodec_tables(multicodecs: Iterable[Multicodec], *, allow_private_use: bool = False) ‑> Tuple[Dict[int, Multicodec], Dict[str, Multicodec]]

Creates code->multicodec and name->multicodec mappings from a finite iterable of multicodecs, returning the mappings. The keyword argument allow_private_use (default: False) can be used to allow multicodec entries with private use codes in range(0x300000, 0x400000): if set to False, a ValueError is raised if one such private use code is encountered.

Raises ValueError if the same multicodec code is encountered multiple times, unless exactly one of the multicodecs has permanent status (in which case that codec is the one inserted in the table). Raises ValueError if the same name is encountered multiple times.

Example usage:

    code_table, name_table = build_multicodec_tables(multicodecs)
Expand source code
def build_multicodec_tables(multicodecs: Iterable[Multicodec], *,
                            allow_private_use: bool = False) -> Tuple[Dict[int, Multicodec], Dict[str, Multicodec]]:
    """
        Creates code->multicodec and name->multicodec mappings from a finite iterable of multicodecs,
        returning the mappings.
        The keyword argument `allow_private_use` (default: `False`) can be used to allow multicodec entries
        with private use codes in `range(0x300000, 0x400000)`: if set to `False`, a `ValueError` is raised
        if one such private use code is encountered.

        Raises `ValueError` if the same multicodec code is encountered multiple times, unless exactly one
        of the multicodecs has permanent status (in which case that codec is the one inserted in the table).
        Raises `ValueError` if the same name is encountered multiple times.

        Example usage:

        ```py
            code_table, name_table = build_multicodec_tables(multicodecs)
        ```
    """
    code_table: Dict[int, Multicodec] = {}
    name_table: Dict[str, Multicodec] = {}
    overwritten_draft_codes: Set[int] = set()
    for m in multicodecs:
        if not allow_private_use and m.is_private_use:
            raise ValueError(f"Private use multicodec not allowed: {m}")
        if m.code in code_table:
            if code_table[m.code].status == "permanent":
                if m.status == "draft":
                    # this draft code has been superseded by a permanent one, skip it
                    continue
                raise ValueError(f"Multicodec code {m.hexcode} appears multiple times in table.")
            if m.code != "permanent":
                # overwriting draft code with another draft code: dodgy, need to check at the end
                overwritten_draft_codes.add(m.code)
        code_table[m.code] = m
        if m.name in name_table:
            raise ValueError(f"Multicodec name {m.name} appears multiple times in table.")
        name_table[m.name] = m
    for code in overwritten_draft_codes:
        m = code_table[code]
        if m.status != "permanent":
            raise ValueError(f"Code {m.code} appears multiple times in table, "
                              "but none of the associated multicodecs is permanent.")
    return code_table, name_table
def exists(name_or_code: Union[str, int]) ‑> bool

Checks whether there is a multicodec with the given name (if a string is passed) or code (if an int is passed).

Example usage:

>>> multicodec.exists("identity")
True
>>> multicodec.exists(0x01)
True
Expand source code
def exists(name_or_code: Union[str, int]) -> bool:
    """
        Checks whether there is a multicodec with the given name (if a string is passed)
        or code (if an int is passed).

        Example usage:

        ```py
        >>> multicodec.exists("identity")
        True
        >>> multicodec.exists(0x01)
        True
        ```
    """
    if isinstance(name_or_code, str):
        name: str = name_or_code
        return name in _name_table
    code: int = name_or_code
    return code in _code_table
def get(name_or_code: Union[str, int]) ‑> Multicodec

Gets the multicodec with given name (if a string is passed) or code (if an int is passed). Raises KeyError if no such multicodec exists.

Example usage:

>>> multicodec.get("identity")
Multicodec(name='identity', tag='multihash', code=0,
           status='permanent', description='raw binary')
>>> multicodec.get(0x01)
Multicodec(name='cidv1', tag='ipld', code=1,
           status='permanent', description='CIDv1')
Expand source code
def get(name_or_code: Union[str, int]) -> Multicodec:
    """
        Gets the multicodec with given name (if a string is passed) or code (if an int is passed).
        Raises `KeyError` if no such multicodec exists.

        Example usage:

        ```py
        >>> multicodec.get("identity")
        Multicodec(name='identity', tag='multihash', code=0,
                   status='permanent', description='raw binary')
        >>> multicodec.get(0x01)
        Multicodec(name='cidv1', tag='ipld', code=1,
                   status='permanent', description='CIDv1')
        ```
    """
    if isinstance(name_or_code, str):
        name: str = name_or_code
        if name not in _name_table:
            raise KeyError(f"No multicodec named {repr(name)}.")
        return _name_table[name]
    code: int = name_or_code
    if code not in _code_table:
        raise KeyError(f"No multicodec with code {repr(code)}.")
    return _code_table[code]
def register(m: Multicodec, overwrite: bool = False) ‑> None

Registers a given multicodec. The optional keyword argument overwrite (default: False) can be used to overwrite a multicodec with existing code.

Raises ValueError if a multicodec with the same name exists, or if a multicodec with the same code exists and overwrite is False.

Example usage:

    >>> m = Multicodec("my-multicodec", "my-tag", 0x300001, "draft", "...")
    >>> multicodec.register(m)
    >>> multicodec.exists(0x300001)
    True
    >>> multicodec.get(0x300001).name
    'my-multicodec'
    >>> multicodec.get(0x300001).is_private_use
    True
Expand source code
def register(m: Multicodec, overwrite: bool = False) -> None:
    """
        Registers a given multicodec. The optional keyword argument `overwrite` (default: `False`)
        can be used to overwrite a multicodec with existing code.

        Raises `ValueError` if a multicodec with the same name exists, or if a multicodec with the
        same code exists and `overwrite` is `False`.

        Example usage:

        ```py
            >>> m = Multicodec("my-multicodec", "my-tag", 0x300001, "draft", "...")
            >>> multicodec.register(m)
            >>> multicodec.exists(0x300001)
            True
            >>> multicodec.get(0x300001).name
            'my-multicodec'
            >>> multicodec.get(0x300001).is_private_use
            True
        ```
    """
    if not overwrite and m.code in _code_table:
        raise ValueError(f"Multicodec with code {repr(m.code)} already exists: {_code_table[m.code]}")
    if m.name in _name_table:
        raise ValueError(f"Multicodec with name {repr(m.name)} already exists: {_name_table[m.name]}")
    _code_table[m.code] = m
    _name_table[m.name] = m
def table(tag: Union[ForwardRef(None), str, Collection[str]] = None, status: Union[ForwardRef(None), str, Collection[str]] = None) ‑> Iterator[Multicodec]

Iterates through the registered multicodecs, in order of ascending code. The optional keyword arguments tag and status can be used to restrict the iterator to multicodecs with a given tag or status respectively.

Example usage:

>>> selected = multicodec.table(tag=["ipld", "multiaddr"], status="permanent")
>>> [m.code for m in selected]
[1, 4, 6, 41, 53, 54, 55, 56, 85, 112, 113, 114, 120,
 144, 145, 146, 147, 148, 149, 150, 151, 152, 176, 177,
 178, 192, 193, 290, 297, 400, 421, 460, 477, 478, 479]
Expand source code
def table(tag: Union[None, str, Collection[str]] = None, status: Union[None, str, Collection[str]] = None) -> Iterator[Multicodec]:
    """
        Iterates through the registered multicodecs, in order of ascending code.
        The optional keyword arguments `tag` and `status` can be used to restrict the iterator
        to multicodecs with a given `tag` or `status` respectively.

        Example usage:


        ```py
        >>> selected = multicodec.table(tag=["ipld", "multiaddr"], status="permanent")
        >>> [m.code for m in selected]
        [1, 4, 6, 41, 53, 54, 55, 56, 85, 112, 113, 114, 120,
         144, 145, 146, 147, 148, 149, 150, 151, 152, 176, 177,
         178, 192, 193, 290, 297, 400, 421, 460, 477, 478, 479]
        ```
    """
    tags: Optional[Collection[str]]
    if tag is None:
        tags = None
    elif isinstance(tag, str):
        tags = [tag]
    else:
        tags = tag
    statuses: Optional[Collection[str]]
    if status is None:
        statuses = None
    elif isinstance(status, str):
        statuses = [status]
    else:
        statuses = status
    for code in sorted(_code_table.keys()):
        m = _code_table[code]
        if tags is not None and m.tag not in tags:
            continue
        if statuses is not None and m.status not in statuses:
            continue
        yield m
def unregister(name_or_code: Union[str, int]) ‑> None

Unregisters the multicodec with given name (if a string is passed) or code (if an int is passed). Raises KeyError if no such multicodec exists.

Example usage:

>>> multicodec.unregister(0x01) # cidv1
>>> multicodec.exists(0x01)
False
Expand source code
def unregister(name_or_code: Union[str, int]) -> None:
    """
        Unregisters the multicodec with given name (if a string is passed) or code (if an int is passed).
        Raises `KeyError` if no such multicodec exists.

        Example usage:

        ```py
        >>> multicodec.unregister(0x01) # cidv1
        >>> multicodec.exists(0x01)
        False
        ```
    """
    m = get(name_or_code)
    del _code_table[m.code]
    del _name_table[m.name]

Classes

class Multicodec (name: str, tag: str, code: int, status: str, description: str)

Dataclass for a multicodec.

Example usage:

    >>> Multicodec.from_json({
    ...     'name': 'cidv1', 'tag': 'ipld', 'code': '0x01',
    ...     'status': 'permanent', 'description': 'CIDv1'})
    Multicodec(name='cidv1', tag='ipld', code=1,
               status='permanent', description='CIDv1')

Direct instantiation should be avoided: it is field-order dependent and might change without warning in the future.

Expand source code
@dataclass(frozen=True)
class Multicodec:
    """
        Dataclass for a multicodec.

        Example usage:

        ```py
            >>> Multicodec.from_json({
            ...     'name': 'cidv1', 'tag': 'ipld', 'code': '0x01',
            ...     'status': 'permanent', 'description': 'CIDv1'})
            Multicodec(name='cidv1', tag='ipld', code=1,
                       status='permanent', description='CIDv1')
        ```

        Direct instantiation should be avoided: it is field-order dependent
        and might change without warning in the future.

    """

    name: str
    """
        Multicodec name. Must satisfy the following:

        ```py
        re.match(r"^[a-z][a-z0-9_-]+$", name)
        ```
    """

    tag: str
    """ Multicodec tag. """

    code: int
    """ Multicodec code. Must be a non-negative integer. """

    status: str
    """ Multicodec status. Must be 'draft' or 'permanent'."""

    description: str
    """ Multicodec description. """

    def __post_init__(self):
        if not re.match(r"^[a-z][a-z0-9_-]+$", self.name):
            raise ValueError(f"Invalid multicodec name {repr(self.name)}")
        if self.status not in ("draft", "permanent"):
            raise ValueError(f"Invalid multicodec status {repr(self.status)}.")
        if self.code < 0:
            raise ValueError(f"Invalid multicodec code {repr(self.code)}.")

    @property
    def hexcode(self) -> str:
        """
            Multicodec code as a hex string (with hex digits zero-padded to even length):

            Example usage:

            ```py
            >>> m = multicodec.get(1)
            >>> m.code
            1
            >>> m.hexcode
            '0x01'
            ```
        """
        code = hex(self.code)
        if len(code) % 2 != 0:
            code = "0x0"+code[2:]
        return code

    @property
    def is_private_use(self) -> bool:
        """
            Whether this multicodec code is reserved for private use,
            i.e. whether it is in `range(0x300000, 0x400000)`.
        """
        return self.code in range(0x300000, 0x400000)

    def to_json(self) -> Mapping[str, str]:
        """
            Returns a JSON dictionary representation of this multicodec object,
            compatible with the one from the table.csv found in the
            [multicodec spec](https://github.com/multiformats/multicodec).

            Example usage:

            ```py
            >>> m = multicodec.get(1)
            >>> m.to_json()
            {'name': 'cidv1', 'tag': 'ipld', 'code': '0x01',
             'status': 'permanent', 'description': 'CIDv1'}
            ```
        """
        return {
            "name": self.name,
            "tag": self.tag,
            "code": self.hexcode,
            "status": self.status,
            "description": self.description
        }

    @staticmethod
    def from_json(multicodec: Mapping[str, Union[str, int]]) -> "Multicodec":
        """
            Decodes a `Multicodec` object from a JSON dictionary representation
            compatible with the one from the table.csv found in the
            [multicodec spec](https://github.com/multiformats/multicodec).

            Example usage:

            ```py
            >>> m = Multicodec.from_json({
            ...     'name': 'cidv1', 'tag': 'ipld', 'code': '0x01',
            ...     'status': 'permanent', 'description': 'CIDv1'})
            >>> m == multicodec.get(1)
            True
            ```
        """
        name = multicodec["name"]
        tag = multicodec["tag"]
        code = multicodec["code"]
        status = multicodec["status"]
        description = multicodec["description"]
        if not isinstance(name, str):
            raise TypeError(f"Expected string, found {name = }.")
        if not isinstance(tag, str):
            raise TypeError(f"Expected string, found {tag = }.")
        if not isinstance(status, str):
            raise TypeError(f"Expected string, found {status = }.")
        if not isinstance(description, str):
            raise TypeError(f"Expected string, found {description = }.")
        if not isinstance(code, (str, int)):
            raise TypeError(f"Expected string or int, found {code = }")
        if isinstance(code, str):
            if code.startswith("0x"):
                code = code[2:]
            code = int(code, base=16)
        return Multicodec(name, tag, code, status, description)

    def __str__(self) -> str:
        return str(self.to_json())

Class variables

var code : int

Multicodec code. Must be a non-negative integer.

var description : str

Multicodec description.

var name : str

Multicodec name. Must satisfy the following:

re.match(r"^[a-z][a-z0-9_-]+$", name)
var status : str

Multicodec status. Must be 'draft' or 'permanent'.

var tag : str

Multicodec tag.

Static methods

def from_json(multicodec: Mapping[str, Union[str, int]]) ‑> Multicodec

Decodes a Multicodec object from a JSON dictionary representation compatible with the one from the table.csv found in the multicodec spec.

Example usage:

>>> m = Multicodec.from_json({
...     'name': 'cidv1', 'tag': 'ipld', 'code': '0x01',
...     'status': 'permanent', 'description': 'CIDv1'})
>>> m == multicodec.get(1)
True
Expand source code
@staticmethod
def from_json(multicodec: Mapping[str, Union[str, int]]) -> "Multicodec":
    """
        Decodes a `Multicodec` object from a JSON dictionary representation
        compatible with the one from the table.csv found in the
        [multicodec spec](https://github.com/multiformats/multicodec).

        Example usage:

        ```py
        >>> m = Multicodec.from_json({
        ...     'name': 'cidv1', 'tag': 'ipld', 'code': '0x01',
        ...     'status': 'permanent', 'description': 'CIDv1'})
        >>> m == multicodec.get(1)
        True
        ```
    """
    name = multicodec["name"]
    tag = multicodec["tag"]
    code = multicodec["code"]
    status = multicodec["status"]
    description = multicodec["description"]
    if not isinstance(name, str):
        raise TypeError(f"Expected string, found {name = }.")
    if not isinstance(tag, str):
        raise TypeError(f"Expected string, found {tag = }.")
    if not isinstance(status, str):
        raise TypeError(f"Expected string, found {status = }.")
    if not isinstance(description, str):
        raise TypeError(f"Expected string, found {description = }.")
    if not isinstance(code, (str, int)):
        raise TypeError(f"Expected string or int, found {code = }")
    if isinstance(code, str):
        if code.startswith("0x"):
            code = code[2:]
        code = int(code, base=16)
    return Multicodec(name, tag, code, status, description)

Instance variables

var hexcode : str

Multicodec code as a hex string (with hex digits zero-padded to even length):

Example usage:

>>> m = multicodec.get(1)
>>> m.code
1
>>> m.hexcode
'0x01'
Expand source code
@property
def hexcode(self) -> str:
    """
        Multicodec code as a hex string (with hex digits zero-padded to even length):

        Example usage:

        ```py
        >>> m = multicodec.get(1)
        >>> m.code
        1
        >>> m.hexcode
        '0x01'
        ```
    """
    code = hex(self.code)
    if len(code) % 2 != 0:
        code = "0x0"+code[2:]
    return code
var is_private_use : bool

Whether this multicodec code is reserved for private use, i.e. whether it is in range(0x300000, 0x400000).

Expand source code
@property
def is_private_use(self) -> bool:
    """
        Whether this multicodec code is reserved for private use,
        i.e. whether it is in `range(0x300000, 0x400000)`.
    """
    return self.code in range(0x300000, 0x400000)

Methods

def to_json(self) ‑> Mapping[str, str]

Returns a JSON dictionary representation of this multicodec object, compatible with the one from the table.csv found in the multicodec spec.

Example usage:

>>> m = multicodec.get(1)
>>> m.to_json()
{'name': 'cidv1', 'tag': 'ipld', 'code': '0x01',
 'status': 'permanent', 'description': 'CIDv1'}
Expand source code
def to_json(self) -> Mapping[str, str]:
    """
        Returns a JSON dictionary representation of this multicodec object,
        compatible with the one from the table.csv found in the
        [multicodec spec](https://github.com/multiformats/multicodec).

        Example usage:

        ```py
        >>> m = multicodec.get(1)
        >>> m.to_json()
        {'name': 'cidv1', 'tag': 'ipld', 'code': '0x01',
         'status': 'permanent', 'description': 'CIDv1'}
        ```
    """
    return {
        "name": self.name,
        "tag": self.tag,
        "code": self.hexcode,
        "status": self.status,
        "description": self.description
    }