Source code for lib.meta

"""
Functions/classes which make use of Python's dynamic nature to inspect a
program's internals.
"""

from functools import wraps
import inspect
from os.path import abspath, isfile, realpath
from pathlib import Path
import sys
from typing import Any, Callable
from warnings import warn


[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 = "".join(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 deprecated(func: Callable, wmsg: str) -> Callable: """ Used to deprecate @func after renaming it or moving it to a different module/package. """ @wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: warn(wmsg, category=BugyiDepreciationWarning, stacklevel=2) return func(*args, **kwargs) return wrapper
[docs]class BugyiDepreciationWarning(Warning): """DepreciationWarning that doesn't get ignored by default."""