Source code for pygada_runtime.typing

"""Package containing the builtin Gada types."""
from __future__ import annotations

__all__ = [
    "Type",
    "AnyType",
    "BoolType",
    "IntType",
    "FloatType",
    "StringType",
    "ListType",
    "VariableType",
    "TupleType",
    "UnionType",
    "isinstance",
    "typeof",
]
import builtins
from dataclasses import dataclass
from typing import Any, Optional, Union, Iterator
from abc import ABC, abstractmethod


_isinstance = builtins.isinstance


[docs]class Type(ABC): """Base for Gada types.""" @abstractmethod def _match(self, o: Any, /) -> bool: raise NotImplementedError()
[docs]@dataclass class AnyType(Type): r"""Represent any type. .. code-block:: python >>> t = AnyType() >>> repr(t) 'AnyType()' >>> str(t) 'any' >>> """ def __repr__(self) -> str: return f"{self.__class__.__name__}()" def __str__(self) -> str: return "any" def _match(self, o: Any, /) -> bool: return True
[docs]@dataclass class BoolType(Type): r"""Wrap the Python **bool** type. .. code-block:: python >>> t = BoolType() >>> repr(t) 'BoolType()' >>> str(t) 'bool' >>> """ def __repr__(self) -> str: return f"{self.__class__.__name__}()" def __str__(self) -> str: return "bool" def _match(self, o: Any, /) -> bool: return _isinstance(o, bool)
[docs]@dataclass class IntType(Type): r"""Wrap the Python **int** type. .. code-block:: python >>> t = IntType() >>> repr(t) 'IntType()' >>> str(t) 'int' >>> """ def __repr__(self) -> str: return f"{self.__class__.__name__}()" def __str__(self) -> str: return "int" def _match(self, o: Any, /) -> bool: return _isinstance(o, int)
[docs]@dataclass class FloatType(Type): r"""Wrap the Python **float** type. .. code-block:: python >>> t = FloatType() >>> repr(t) 'FloatType()' >>> str(t) 'float' >>> """ def __repr__(self) -> str: return f"{self.__class__.__name__}()" def __str__(self) -> str: return "float" def _match(self, o: Any, /) -> bool: return _isinstance(o, float)
[docs]@dataclass class StringType(Type): r"""Wrap the Python **str** type. .. code-block:: python >>> t = StringType() >>> repr(t) 'StringType()' >>> str(t) 'str' >>> """ def __repr__(self) -> str: return f"{self.__class__.__name__}()" def __str__(self) -> str: return "str" def _match(self, o: Any, /) -> bool: return _isinstance(o, str)
[docs]@dataclass class ListType(Type): r"""Wrap the Python **list** type. .. code-block:: python >>> t = ListType(IntType()) >>> repr(t) 'ListType(IntType())' >>> str(t) '[int]' >>> :param item_type: type of list items """ __slot__ = "_item_type" def __init__(self, item_type: Optional[Type], /) -> None: self._item_type = item_type def __repr__(self) -> str: return f"{self.__class__.__name__}({repr(self._item_type)})" def __str__(self) -> str: return f"[{self._item_type}]" def _match(self, o: Any, /) -> bool: if not _isinstance(o, list): return False if not self._item_type or not o: return True return self._item_type._match(o[0])
[docs]@dataclass class VariableType(Type): r"""Represent one or multiple values of the same type. .. code-block:: python >>> t = VariableType(IntType()) >>> repr(t) 'VariableType(IntType())' >>> str(t) '*int' >>> :param item_type: type of items """ __slot__ = "_item_type" def __init__(self, item_type: Type, /) -> None: self._item_type = item_type def __repr__(self) -> str: return f"{self.__class__.__name__}({repr(self._item_type)})" def __str__(self) -> str: return f"*{self._item_type}" def _match(self, o: Any, /) -> bool: if _isinstance(o, list): return self._item_type._match(o[0]) if o else True return self._item_type._match(o[0])
[docs]@dataclass class TupleType(Type): r"""Wrap the Python **tuple** type. .. code-block:: python >>> t = TupleType([IntType(), StringType()]) >>> repr(t) 'TupleType([IntType(), StringType()])' >>> str(t) '(int, str)' >>> :param items_types: types of tuple items """ __slot__ = "_items_types" def __init__( self, items_types: Union[list[Type], Iterator[Type]], / ) -> None: self._items_types = list(items_types) if items_types is not None else [] def __repr__(self) -> str: return f"{self.__class__.__name__}({repr(self._items_types)})" def __str__(self) -> str: return f"({', '.join(map(str, self._items_types))})" def _match(self, o: Any, /) -> bool: if not _isinstance(o, tuple): return False if len(self._items_types) != len(o): return False return all((t._match(v) for t, v in zip(self._items_types, o)))
[docs]@dataclass class UnionType(Type): r"""Represent an union of multiple types. .. code-block:: python >>> t = UnionType([IntType(), StringType()]) >>> repr(t) 'UnionType([IntType(), StringType()])' >>> str(t) 'int | str' >>> :param items_types: possible types """ __slot__ = "_items_types" def __init__(self, items_types: list[Type], /) -> None: self._items_types = list(items_types) if items_types is not None else [] def __repr__(self) -> str: return f"{self.__class__.__name__}({repr(self._items_types)})" def __str__(self) -> str: return " | ".join(map(str, self._items_types)) def _match(self, o: Any, /) -> bool: if not _isinstance(o, tuple): return False if len(self._items_types) != len(o): return False return all((t._match(v) for t, v in zip(self._items_types, o)))
[docs]def isinstance(value: Any, type: Type, /) -> bool: r"""Check if a Python object is an instance of a Gada type. .. code-block:: python >>> from pygada_runtime import typing >>> >>> typing.isinstance(1, IntType()) True >>> typing.isinstance("hello", IntType()) False >>> :param value: Python object :param type: type to check :return: if **value** is an instance of **type** """ return type._match(value)
[docs]def typeof(value: Any, /) -> Type: r"""Get the Gada type of a Python object. .. code-block:: python >>> from pygada_runtime import typing >>> >>> typing.typeof(True) BoolType() >>> typing.typeof(1) IntType() >>> typing.typeof("hello") StringType() >>> typing.typeof([[1]]) ListType(ListType(IntType())) >>> typing.typeof((1, "hello")) TupleType([IntType(), StringType()]) >>> :param value: Python object :return: type of **value** """ if _isinstance(value, bool): return BoolType() if _isinstance(value, int): return IntType() if _isinstance(value, float): return FloatType() if _isinstance(value, str): return StringType() if _isinstance(value, list): return ListType(typeof(value[0]) if value else None) if _isinstance(value, tuple): return TupleType(map(typeof, value)) raise Exception(f"unsupported type {type(value)}")