def __init__(self, node_name: valid_node_name, cage_name: valid_cage_name, cage_directory: os_path.isdir, log: callable, log_priority: int): self._node_name, self._cage_name = node_name, cage_name self._log, self._log_priority = log, log_priority self._cage_directory = cage_directory self._module_locator = ModuleLocator(self._cage_directory) self._lock, self._modules, self._loggers = Lock(), {}, {}
class ModuleLoader: @typecheck def __init__(self, node_name: valid_node_name, cage_name: valid_cage_name, cage_directory: os_path.isdir, log: callable, log_priority: int): self._node_name, self._cage_name = node_name, cage_name self._log, self._log_priority = log, log_priority self._cage_directory = cage_directory self._module_locator = ModuleLocator(self._cage_directory) self._lock, self._modules, self._loggers = Lock(), {}, {} ################################### class _Logger: def __init__(self, log, log_priority, src_module): self._log, self._log_priority = log, log_priority self._src_module = src_module def __call__(self, s, priority = None): try: if priority is None: return self(s, priority = 4) elif priority <= self._log_priority: while not isinstance(s, str): try: s = str(s) except: s = str(s.__class__) request = getattr(current_thread(), "_request", None) req_desc = request.description if request else "" req_desc = " by {0:s}".format(req_desc) if req_desc else "" if self._src_module: line, func = extract_stack(None, 3)[-3][1:3] s += " # {0:s}.py:{1:d} in {2:s}(){3:s}".\ format(self._src_module, line, func, req_desc) elif req_desc: s += " #{0:s}".format(req_desc) self._log(s, priority = priority) except: pass # do nothing error = lambda self, s: self(s, priority = 1) message = lambda self, s: self(s, priority = 2) warning = lambda self, s: self(s, priority = 3) info = lambda self, s: self(s, priority = 5) debug = lambda self, s: self(s, priority = 6) def set_log_priority(self, log_priority): with self._lock: if self._log_priority != log_priority: self._log_priority = log_priority self._loggers.clear() ################################### def __getattr__(self, module_name, src_module = None): # special case #1: pmnc.log[.error|.message|.warning|.info|.debug](s) # I prefer to cache logger instances created for each module for two # reasons: (1) runtime exception safety and (2) performance if module_name == "log": with self._lock: logger = self._loggers.get(src_module) if logger is None: logger = ModuleLoader._Logger(self._log, self._log_priority, src_module) self._loggers[src_module] = logger return logger # special case #2: pmnc.request request = current_thread()._request if module_name == "request": return request # reserve a private namespace for modules if module_name.startswith("_"): raise InvalidModuleNameError("module name cannot start with underscore") # locate the file containing the required module module_filename = \ self._module_locator.locate("{0:s}.py".format(module_name)) or \ self._module_locator.locate("{0:s}.pyc".format(module_name)) if module_filename is None: raise ModuleNotFoundError("file {0:s}.py was not found".format(module_name)) # see if such module has already been loaded, create an empty object if it hasn't with self._lock: module = self._modules.get(module_name) if not module: module = Module(module_name, self) self._modules[module_name] = module # reload the module if necessary and return the proxy object return module.reload(module_filename, request, src_module)