Source code for ska_sdp_piper.piper.configurations.doc_utils

# pragma: exclude from coverage
from types import NoneType, UnionType
from typing import (
    Annotated,
    Any,
    Iterable,
    Literal,
    Optional,
    Type,
    Union,
    get_args,
    get_origin,
)


[docs] def is_nullable(annotation) -> bool: if annotation is NoneType: return True if get_origin(annotation) in (Union, UnionType): return NoneType in get_args(annotation) return False
[docs] def get_allowed_values(annotation) -> list: if get_origin(annotation) is Literal: return list(get_args(annotation)) return []
[docs] def convert_description_to_line_string(desc: str) -> str: """ Converts the description of config param to a single line string suitable for sphinx node parsing Parameters ---------- desc Returns ------- Description converted to a single line, with any indents removed """ return " ".join(line.strip() for line in desc.splitlines() if line.strip())
[docs] def convert_allowed_values_to_string(values: Optional[Iterable[Any]]) -> str: """ Convert "allowed values" parameter of Config Param to a string. Parameters ---------- values Returns ------- String representation of allowed values """ if not values: # () or [] or None return "" s = str(values) # Remove outer brackets like () or [] # Always assumes that some outer brackets exist # In future, might need robust checks for edge cases return s[1:-1]
[docs] def get_resolved_path(tp: Type) -> str: """ Gets the fully qualified name of a type For builtins like int, str; the module name i.e. 'builtins' is not part of the output. Examples -------- >>> get_resolved_path(int) "int" >>> get_resolved_path(Any) "typing.Any" """ module = tp.__module__ if module == "builtins": return tp.__qualname__ return module + "." + tp.__qualname__
[docs] def convert_type_to_reST_string(tp: Type) -> str: """ Convert a type to string compatible for intersphinx mapping The input can be: 1. single type 2. an Annotated type — only the first arg (the actual type) is used 3. a union type (Union or UnionType) 4. a generic collection type (list, dict, set, etc.) — both the collection and its element types are linked For cases 3 and 4, the types are converted to sphinx compatible string and joined using a comma. Parameters ---------- tp type or tuple of type to convert to string Returns ------- String representation of type / tuple of type Examples -------- >>> convert_type_to_reST_string(int) ":py:class:`int`" >>> convert_type_to_reST_string(float, Any) ":py:class:`float`, :py:class:`typing.Any`" >>> convert_type_to_reST_string(float | int) ":py:class:`float` | :py:class:`int`" >>> convert_type_to_reST_string(list[int]) ":py:class:`~list`\\[:py:class:`~int`\\]" >>> convert_type_to_reST_string(Annotated[int, \"some metadata\"]) ":py:class:`~int`" """ origin = get_origin(tp) if origin is Annotated: return convert_type_to_reST_string( tp.__origin__ # pylint: disable=no-member ) if origin is Literal: return "" if origin in (Union, UnionType): return " | ".join(convert_type_to_reST_string(a) for a in get_args(tp)) # Handle generic collection types if origin is not None: origin_str = f":py:class:`~{get_resolved_path(origin)}`" args = get_args(tp) if args: args_str = ", ".join(convert_type_to_reST_string(a) for a in args) return f"{origin_str}\\[{args_str}\\]" return origin_str return f":py:class:`~{get_resolved_path(tp)}`"