""" Improve the standard Python REPL. This module attempts to emulate the workflow of ghci or lisp repls. It uses importlib to load a namespace from the given path. It then binds 'r()' to a function that reloads the same namespace. """ import importlib import logging import sys from Biz import Log def use(ns: str, path: str) -> None: """ Load or reload the module named 'ns' from 'path'. Like `use` in the Guile Scheme repl. """ logging.info("loading %s from %s", ns, path) spec = importlib.util.spec_from_file_location(ns, path) module = importlib.util.module_from_spec(spec) # delete module and its imported names if its already loaded if ns in sys.modules: del sys.modules[ns] for name in module.__dict__: if name in globals(): del globals()[name] sys.modules[ns] = module spec.loader.exec_module(module) names = list(module.__dict__) globals().update({k: getattr(module, k) for k in names}) if __name__ == "__main__": Log.setup() NS = sys.argv[1] PATH = sys.argv[2] use(NS, PATH) logging.info("use reload() or _r() after making changes") sys.ps1 = f"{NS}> " sys.ps2 = f"{NS}| " def reload() -> None: """Reload the namespace.""" return use(NS, PATH) def _r() -> None: """Shorthand: Reload the namespace.""" return use(NS, PATH)