Skip to content

xnano.symbols

xnano.symbols

xnano.symbols

Names for values: register a picture, a note, a pixel or a sound once and use it by name.

A symbol is a name, not a class. symbol='wall' on a value registers it here, and a function that takes a str where such a value fits looks the name up, so Pixel('wall') or play('kick') uses what was registered. The registry is shared by the whole program.

Functions:

  • register –

    Register value under name, so that functions that take a name can use it.

  • lookup –

    Return the value registered under name.

  • names –

    Return the registered names, in alphabetical order.

  • remove –

    Forget the value registered under name. Removing a name that is not there does nothing.

register

register(name: str, value: object) -> None

Register value under name, so that functions that take a name can use it.

Registering a name again with a value of the same kind keeps the newer value, so code that builds the same symbol twice (a function called again, a notebook cell run again) keeps working. A name already taken by another kind of value is refused, so a lookup that worked before can never silently change.

Parameters:

  • name (str) –

    The name, two characters or more, without spaces. It may not be the name of a pixel preset, a note name such as 'C4', 'rest' or a number.

  • value (object) –

    The value to register.

Raises:

  • ValueError –

    The name cannot be a symbol, or another kind of value already has it.

  • TypeError –

    The name is not a string.

Examples:

import xnano

xnano.symbols.register('logo', xnano.Color('#336699'))
assert xnano.symbols.lookup('logo') == xnano.Color('#336699')
xnano.symbols.remove('logo')
Source code in xnano/symbols.py
def register(name: str, value: object, /) -> None:
    """
    Register ``value`` under ``name``, so that functions that take a name can use it.

    Registering a name again with a value of the same kind keeps the newer value, so code
    that builds the same symbol twice (a function called again, a notebook
    cell run again) keeps working. A name already taken by another kind of value is
    refused, so a lookup that worked before can never silently change.

    Args:
        name: The name, two characters or more, without spaces. It may not be the name of a
            pixel preset, a note name such as ``'C4'``, ``'rest'`` or a number.
        value: The value to register.

    Raises:
        ValueError: The name cannot be a symbol, or another kind of value already has it.
        TypeError: The name is not a string.

    Examples:
        ```python
        import xnano

        xnano.symbols.register('logo', xnano.Color('#336699'))
        assert xnano.symbols.lookup('logo') == xnano.Color('#336699')
        xnano.symbols.remove('logo')
        ```
    """
    _check_name(name)
    with _lock:
        existing = _registry.get(name)
        if existing is not None and type(existing) is not type(value):
            raise ValueError(
                f'The symbol {name!r} is already {_article(_kind_name(existing))}, so it '
                f'cannot also name {_article(_kind_name(value))}. Call '
                f'xnano.symbols.remove({name!r}) first, or pick another name.'
            )
        _registry[name] = value

lookup

lookup(name: str) -> object
lookup(name: str, /, *, kind: type[ValueT]) -> ValueT
lookup(name: str, /, *, kind: type[ValueT] | None = None) -> ValueT | object

Return the value registered under name.

Parameters:

  • name (str) –

    The registered name.

  • kind (type[ValueT] | None, default: None ) –

    The class the value must be an instance of, such as xnano.Image; None accepts any kind.

Raises:

  • ValueError –

    Nothing of that kind is registered under the name. The message names the closest registered names first, then every known one.

Examples:

import xnano

xnano.symbols.register('accent', xnano.Color('#ff8800'))
assert xnano.symbols.lookup('accent', kind=xnano.Color).to_rgb() == (255, 136, 0)
xnano.symbols.remove('accent')
Source code in xnano/symbols.py
def lookup(name: str, /, *, kind: type[ValueT] | None = None) -> ValueT | object:
    """
    Return the value registered under ``name``.

    Args:
        name: The registered name.
        kind: The class the value must be an instance of, such as ``xnano.Image``; ``None``
            accepts any kind.

    Raises:
        ValueError: Nothing of that kind is registered under the name. The message names the
            closest registered names first, then every known one.

    Examples:
        ```python
        import xnano

        xnano.symbols.register('accent', xnano.Color('#ff8800'))
        assert xnano.symbols.lookup('accent', kind=xnano.Color).to_rgb() == (255, 136, 0)
        xnano.symbols.remove('accent')
        ```
    """
    with _lock:
        value = _registry.get(name)
        known = sorted(
            registered
            for registered, item in _registry.items()
            if kind is None or isinstance(item, kind)
        )
    if value is not None and (kind is None or isinstance(value, kind)):
        return value
    what = 'symbol' if kind is None else f'{kind.__name__} symbol'
    if value is not None and kind is not None:
        raise ValueError(
            f'{name!r} is {_article(_kind_name(value))} symbol, not {_article(what)}. Use a '
            f'name registered for {_article(kind.__name__)}, or register one with '
            f'symbol={name!r} when you create it.'
        )
    close = difflib.get_close_matches(name, known, n=3)
    hint = f' Did you mean {" or ".join(repr(item) for item in close)}?' if close else ''
    listed = ', '.join(repr(item) for item in known) if known else 'none yet'
    raise ValueError(
        f'{name!r} is not a known {what}.{hint} Known {what}s: {listed}. Register one with '
        f'symbol={name!r} when you create it.'
    )

names

names(*, kind: type | None = None) -> tuple[str, ...]

Return the registered names, in alphabetical order.

Parameters:

  • kind (type | None, default: None ) –

    Only the names of values that are instances of this class; None for all.

Examples:

import xnano

xnano.symbols.register('sky', xnano.Color('#88ccff'))
assert 'sky' in xnano.symbols.names(kind=xnano.Color)
xnano.symbols.remove('sky')
Source code in xnano/symbols.py
def names(*, kind: type | None = None) -> tuple[str, ...]:
    """
    Return the registered names, in alphabetical order.

    Args:
        kind: Only the names of values that are instances of this class; ``None`` for all.

    Examples:
        ```python
        import xnano

        xnano.symbols.register('sky', xnano.Color('#88ccff'))
        assert 'sky' in xnano.symbols.names(kind=xnano.Color)
        xnano.symbols.remove('sky')
        ```
    """
    with _lock:
        return tuple(
            sorted(
                registered
                for registered, item in _registry.items()
                if kind is None or isinstance(item, kind)
            )
        )

remove

remove(name: str) -> None

Forget the value registered under name. Removing a name that is not there does nothing.

Parameters:

  • name (str) –

    The registered name.

Source code in xnano/symbols.py
def remove(name: str, /) -> None:
    """
    Forget the value registered under ``name``. Removing a name that is not there does nothing.

    Args:
        name: The registered name.
    """
    with _lock:
        _registry.pop(name, None)