Source code for metaman._core

"""The metaman package's catch-all module.

You should only add code to this module when you are unable to find ANY other
module to add it to.
"""

from __future__ import annotations

import inspect
from os.path import abspath, isfile, realpath
from pathlib import Path
import sys
from typing import Callable, MutableSequence, TypeVar


T = TypeVar("T")


[docs]def cname(obj: object) -> str: """Helper function for getting an object's class name as a string.""" return obj.__class__.__name__
[docs]class Inspector: """ Helper class for python introspection (e.g. What line number is this?) """ def __init__(self, *, up: int = 0) -> None: frame = inspect.stack()[up + 1] self.module_name = _path_to_module(frame[1]) self.file_name = frame[1] self.line_number = frame[2] self.function_name = frame[3] self.lines = frame[4] or []
def _path_to_module(path: str) -> str: P = path # HACK: Improves the (still broken) output in some weird cases where # python gets confused about paths. real_abs_P = realpath(abspath(P)) if isfile(real_abs_P): P = real_abs_P if P.endswith((".py", ".px")): P = P[:-3] sorted_pypaths = sorted(sys.path, key=lambda path: -len(str(path))) for pypath in sorted_pypaths: pypath = realpath(pypath) P = P.replace(pypath + "/", "") P = P.replace("/", ".") return P
[docs]def scriptname(*, up: int = 0) -> str: """Returns the name of the current script / module. Args: up: How far should we crawl up the stack? """ frame = inspect.stack()[up + 1] return Path(frame.filename).stem
[docs]def register_function_factory( mut_registry: MutableSequence[T], ) -> Callable[[T], T]: """Factory for decorators used to register a function. We append all decorated functions to the `mut_registry` list. """ def register_function(spell: T) -> T: mut_registry.append(spell) return spell return register_function