Source code for bookbuilderpy.types

"""Some basic type handling routines."""
from typing import Any, Final, Iterable


[docs]def type_name(tpe: type) -> str: """ Convert a type to a string. :param tpe: the type :returns: the string >>> type_name(type(None)) 'None' >>> type_name(int) 'int' >>> from bookbuilderpy.path import Path >>> type_name(Path) 'bookbuilderpy.path.Path' """ c1: str = str(tpe) if c1.startswith("<class '"): c1 = c1[8:-2] if c1 == "NoneType": return "None" if hasattr(tpe, "__qualname__"): c2: str = tpe.__qualname__ if hasattr(tpe, "__module__"): module = tpe.__module__ if (module is not None) and (module != "builtins"): c2 = f"{module}.{c2}" if len(c2) > len(c1): return c2 return c1
[docs]def type_name_of(obj) -> str: """ Get the fully-qualified class name of an object. :param obj: the object :returns: the fully-qualified class name of the object >>> from bookbuilderpy.path import Path >>> type_name_of(Path.path("/tmp")) 'bookbuilderpy.path.Path' """ if obj is None: return "None" c1: Final[str] = type_name(type(obj)) if hasattr(obj, "__class__"): cls: Final[type] = obj.__class__ c2: str = type_name(cls) if hasattr(cls, "__qualname__"): c3: str = cls.__qualname__ if hasattr(obj, "__module__"): module = obj.__module__ if (module is not None) and (module != "builtins"): c3 = f"{module}.{c3}" if len(c3) > len(c2): c2 = c3 if len(c2) > len(c1): return c2 return c1
[docs]def type_error(obj: Any, name: str, expected: None | type | Iterable[type] = None, call: bool = False) -> ValueError | TypeError: """ Create an error to raise if a type did not fit. :param obj: the object that is of the wrong type :param name: the name of the object :param expected: the expected types (or `None`) :param call: the object should have been callable? :returns: a :class:`TypeError` with a descriptive information >>> type_error(1.3, "var", int) TypeError("var should be an instance of int but is float, namely '1.3'.") >>> type_error("x", "z", (int, float)).args[0] "z should be an instance of any in {float, int} but is str, namely 'x'." >>> type_error("f", "q", call=True).args[0] "q should be a callable but is str, namely 'f'." >>> type_error("1", "2", bool, call=True).args[0] "2 should be an instance of bool or a callable but is str, namely '1'." >>> type_error(None, "x", str) TypeError('x should be an instance of str but is None.') """ exp: str = "" if isinstance(expected, Iterable): exp = ", ".join(sorted([type_name(e) for e in expected])) exp = f"an instance of any in {{{exp}}}" elif expected is not None: exp = f"an instance of {type_name(expected)}" if call: exp = f"{exp} or a callable" if exp else "a callable" if obj is None: return TypeError(f"{name} should be {exp} but is None.") return TypeError(f"{name} should be {exp} but is " f"{type_name_of(obj)}, namely '{obj}'.")