Skip to content

topmark.core.typing_guards

topmark / core / typing_guards

Generic type guards and normalization helpers for TopMark.

This module provides TypeGuard-based predicates that help Pyright narrow runtime values coming from weakly typed objects, e.g. values stored in the Click context.

It also includes small, side-effect-free normalization helpers such as as_object_dict, plus permissive generic mapping-extraction helpers used by runtime/config payload shaping. These helpers are meant for already-normalized Python mappings, not TOML-schema validation.

See Also: - topmark.toml.typing_guards: type guards and normalization helpers for TOML parsing.

is_mapping

is_mapping(obj)

Type guard for a Mapping value.

Checks only that the value is a Mapping; does not validate item types.

Parameters:

Name Type Description Default
obj object

Value to test.

required

Returns:

Type Description
TypeGuard[Mapping[object, object]]

True if obj is a Mapping.

Source code in src/topmark/core/typing_guards.py
def is_mapping(obj: object) -> TypeGuard[Mapping[object, object]]:
    """Type guard for a Mapping value.

    Checks only that the value is a ``Mapping``; does not validate item types.

    Args:
        obj: Value to test.

    Returns:
        True if obj is a Mapping.
    """
    return isinstance(obj, Mapping)

is_any_list

is_any_list(obj)

Type guard for a generic list value.

Checks only that the value is a list; does not validate item types.

Parameters:

Name Type Description Default
obj object

Value to test.

required

Returns:

Type Description
TypeGuard[list[object]]

True if obj is a list.

Source code in src/topmark/core/typing_guards.py
def is_any_list(obj: object) -> TypeGuard[list[object]]:
    """Type guard for a generic list value.

    Checks only that the value is a ``list``; does not validate item types.

    Args:
        obj: Value to test.

    Returns:
        True if obj is a list.
    """
    return isinstance(obj, list)

is_str_list

is_str_list(obj)

Type guard for a string list value.

Checks that the value is a list[str].

Parameters:

Name Type Description Default
obj object

Value to test.

required

Returns:

Type Description
TypeGuard[list[str]]

True if obj is a list[str].

Source code in src/topmark/core/typing_guards.py
def is_str_list(obj: object) -> TypeGuard[list[str]]:
    """Type guard for a string list value.

    Checks that the value is a ``list[str]``.

    Args:
        obj: Value to test.

    Returns:
        True if obj is a list[str].
    """
    return is_any_list(obj) and all(isinstance(x, str) for x in obj)

as_object_dict

as_object_dict(value)

Return value as a shallow dict[str, object] when possible.

This helper is intentionally permissive and is meant for post-normalization payload shaping, not TOML-schema validation. Non-dictionary inputs yield an empty dictionary. Dictionary keys are stringified to provide a stable dict[str, object] result for downstream machine-payload builders.

Parameters:

Name Type Description Default
value object

Arbitrary runtime value.

required

Returns:

Type Description
dict[str, object]

A shallow dictionary with string keys when value is a plain dict;

dict[str, object]

otherwise {}.

Source code in src/topmark/core/typing_guards.py
def as_object_dict(value: object) -> dict[str, object]:
    """Return `value` as a shallow `dict[str, object]` when possible.

    This helper is intentionally permissive and is meant for post-normalization
    payload shaping, not TOML-schema validation. Non-dictionary inputs yield an
    empty dictionary. Dictionary keys are stringified to provide a stable
    ``dict[str, object]`` result for downstream machine-payload builders.

    Args:
        value: Arbitrary runtime value.

    Returns:
        A shallow dictionary with string keys when `value` is a plain `dict`;
        otherwise ``{}``.
    """
    if not isinstance(value, dict):
        return {}

    items: Mapping[object, object] = cast("Mapping[object, object]", value)
    return {str(key): item for key, item in items.items()}

get_object_dict_value

get_object_dict_value(mapping, key)

Return a shallow dict[str, object] value for key when present.

This helper is intentionally permissive and is meant for generic mapping extraction from already-normalized runtime/config payloads. It is not a TOML schema-validation helper.

Parameters:

Name Type Description Default
mapping Mapping[str, object]

Mapping to inspect.

required
key str

Key to extract.

required

Returns:

Type Description
dict[str, object]

A shallow dictionary with stringified keys when the value at key is a

dict[str, object]

plain dict; otherwise {}.

Source code in src/topmark/core/typing_guards.py
def get_object_dict_value(mapping: Mapping[str, object], key: str) -> dict[str, object]:
    """Return a shallow `dict[str, object]` value for `key` when present.

    This helper is intentionally permissive and is meant for generic mapping
    extraction from already-normalized runtime/config payloads. It is not a TOML
    schema-validation helper.

    Args:
        mapping: Mapping to inspect.
        key: Key to extract.

    Returns:
        A shallow dictionary with stringified keys when the value at `key` is a
        plain `dict`; otherwise ``{}``.
    """
    value: object = mapping.get(key)
    return as_object_dict(value)

get_string_dict_value

get_string_dict_value(mapping, key)

Return a dict[str, str] value for key, filtering invalid items.

Parameters:

Name Type Description Default
mapping Mapping[str, object]

Mapping to inspect.

required
key str

Key to extract.

required

Returns:

Type Description
dict[str, str]

A dictionary containing only str -> str entries from the value stored

dict[str, str]

at key, or {} when the value is absent or not a plain dict.

Source code in src/topmark/core/typing_guards.py
def get_string_dict_value(mapping: Mapping[str, object], key: str) -> dict[str, str]:
    """Return a `dict[str, str]` value for `key`, filtering invalid items.

    Args:
        mapping: Mapping to inspect.
        key: Key to extract.

    Returns:
        A dictionary containing only `str -> str` entries from the value stored
        at `key`, or ``{}`` when the value is absent or not a plain `dict`.
    """
    value: object = mapping.get(key)
    if not isinstance(value, dict):
        return {}

    # Tell Pyright this is a dict, treat the keys/values as base objects:
    items = cast("Mapping[object, object]", value)

    result: dict[str, str] = {}
    for item_key, item_value in items.items():
        if isinstance(item_key, str) and isinstance(item_value, str):
            result[item_key] = item_value
    return result

get_string_list_dict_value

get_string_list_dict_value(mapping, key)

Return a dict[str, list[str]] value for key, filtering invalid items.

Parameters:

Name Type Description Default
mapping Mapping[str, object]

Mapping to inspect.

required
key str

Key to extract.

required

Returns:

Type Description
dict[str, list[str]]

A dictionary containing only str -> list[str] entries from the value

dict[str, list[str]]

stored at key, or {} when the value is absent or not a plain

dict[str, list[str]]

dict.

Source code in src/topmark/core/typing_guards.py
def get_string_list_dict_value(mapping: Mapping[str, object], key: str) -> dict[str, list[str]]:
    """Return a `dict[str, list[str]]` value for `key`, filtering invalid items.

    Args:
        mapping: Mapping to inspect.
        key: Key to extract.

    Returns:
        A dictionary containing only `str -> list[str]` entries from the value
        stored at `key`, or ``{}`` when the value is absent or not a plain
        `dict`.
    """
    value: object = mapping.get(key)
    if not isinstance(value, dict):
        return {}

    # Tell Pyright this is a dict, treat the keys/values as base objects:
    items = cast("Mapping[object, object]", value)

    result: dict[str, list[str]] = {}
    for item_key, item_value in items.items():
        if not isinstance(item_key, str) or not is_str_list(item_value):
            continue
        result[item_key] = list(item_value)
    return result