Source code for esrf_pathlib._schemas.fields.base

from enum import Enum
from typing import Any
from typing import Callable
from typing import List
from typing import Optional
from typing import Tuple
from typing import Type
from typing import Union
from typing import get_type_hints

from ..identifier import SchemaIdentifier


[docs] class Field: def __init__( self, name: str, description: str, schema_identifier: SchemaIdentifier, value_generator: Union[Callable[..., Any], Type[Any]], value_serializer: Union[Callable[..., Any], Type[Any], None] = None, examples: Optional[List[str]] = None, ) -> None: self._name = name self._description = description self._examples = examples self._schema_identifier = schema_identifier self._value_generator = value_generator self._value_serializer = value_serializer def __repr__(self) -> str: return f"<{type(self).__name__} {self._name!r} schema={str(self._schema_identifier)!r}>" @property def name(self) -> str: return self._name @property def description(self) -> str: return self._description @property def docstring(self) -> str: description = self._description or "Path concept" description = _ensure_sentence(description) category, values = self.value_info() if category is None: return description return f"{description}\n\n{category}: ``{', '.join(values)}``" @property def schema_identifier(self) -> SchemaIdentifier: return self._schema_identifier
[docs] def annotation(self) -> Any: """More specific type annotation of the return value of ``deserialize``.""" return _get_return_annotation(self._value_generator)
[docs] def value_info(self) -> Tuple[Optional[str], Optional[str]]: enum_values = self._enum_values() if enum_values: return "Enumeration", enum_values if self._examples: return "Examples", list(map(repr, self._examples)) return None, None
def _enum_values(self) -> List[str]: enum_type = None if isinstance(self._value_generator, Enum): enum_type = self._value_generator else: return_type = self.annotation() if isinstance(return_type, type) and issubclass(return_type, Enum): enum_type = return_type if enum_type is None or self._value_serializer is None: return [] values = [] for field in enum_type: try: value = repr(self._value_serializer(field)) except Exception: continue values.append(value) return values
def _get_return_annotation(obj: Union[Callable[..., Any], Type[Any]]) -> Any: """Extract the return annotation of a function or a type.""" if isinstance(obj, type): return obj if callable(obj): hints = get_type_hints(obj) return hints.get("return", None) raise TypeError(f"{obj!r} must be a type or callable") def _ensure_sentence(text: str) -> str: text = text.strip() if not text: return "" if text[0].isalpha(): text = text[0].upper() + text[1:] if text[-1] not in ".!?": text += "." return text