class CommandModule(object): _log = log_.get_log("module") def __init__(self, path): self._path = os.path.abspath(path) self._namespace = None self._loaded = False def __str__(self): return "%s(%r)" % (self.__class__.__name__, os.path.basename( self._path)) def load(self): self._log.error("%s: Loading module: %r" % (self, self._path)) # Prepare namespace in which to execute the namespace = {} namespace["__file__"] = self._path # Attempt to execute the module; handle any exceptions. try: execfile(self._path, namespace) except Exception, e: self._log.error("%s: Error loading module: %s" % (self, e)) self._loaded = False return self._loaded = True self._namespace = namespace
class CommandModuleDirectory(object): _log = log_.get_log("directory") def __init__(self, path, excludes=None): self._path = os.path.abspath(path) self._excludes = excludes self._modules = {} def load(self): valid_paths = self._get_valid_paths() # Remove any deleted modules. for path, module in self._modules.items(): if path not in valid_paths: del self._modules[path] module.unload() # Add any new modules. for path in valid_paths: if path not in self._modules: module = CommandModule(path) module.load() self._modules[path] = module else: module = self._modules[path] module.check_freshness() def _get_valid_paths(self): valid_paths = [] for filename in os.listdir(self._path): path = os.path.abspath(join(self._path, filename)) if not os.path.isfile(path): continue if not os.path.splitext(path)[1] == ".py": continue if path in self._excludes: continue valid_paths.append(path) self._log.error("valid paths: %r" % valid_paths) return valid_paths
class Config(object): """ Configuration class for storing program settings. Constructor argument: - *name* (*str*) -- the name of this configuration object. This class can contain zero or more :class:`Section` instances, each of which can contain zero or more :class:`Item` instances. It is these items which store the actual configuration settings. The sections merely divide the items up into groups, so that different configuration topics can be split for easy readability. """ _configs_by_name = {} _log = log_.get_log("config") #----------------------------------------------------------------------- @classmethod def get_by_name(cls, name): try: return cls._configs_by_name[name] except KeyError: return None @classmethod def get_instances(cls): instances = cls._configs_by_name.items() instances.sort() return [instance for name, instance in instances] #----------------------------------------------------------------------- def __init__(self, name): set_ = object.__setattr__ set_(self, "name", name) set_(self, "_sections", {}) set_(self, "_sections_list", []) set_(self, "_mode", _init) set_(self, "module_path", None) set_(self, "config_path", None) Config._configs_by_name[name] = self def _set_mode(self, mode): object.__setattr__(self, "_mode", mode) for n, s in self._sections_list: s._set_mode(mode) def __getattr__(self, name): if name in self._sections: return self._sections[name] else: raise AttributeError(name) def __setattr__(self, name, value): if self._mode == _init: if isinstance(value, Section): self._sections[name] = value self._sections_list.append((name, value)) else: raise TypeError("Invalid type %s, expecting Section." % type(value)) else: raise AttributeError(name) def load(self, path=None): """ Load the configuration file at the given *path*, or look for a configuration file associated with the calling module. - *path* (*str*, default: *None*) -- path to the configuration file to load. If *None*, then a path is generated from the calling module's file name by replacing its extension with ".txt". If the *path* is a file, it is loaded. On the other hand, if it does not exist or is not a file, nothing is loaded and this configuration's defaults remain in place. """ self._set_mode(_load) if not path: caller_frame = inspect.currentframe().f_back caller_file = caller_frame.f_globals["__file__"] module_base, module_ext = os.path.splitext(caller_file) path = module_base + ".txt" if module_ext in (".pyc", ".pyo"): module_ext = ".py" object.__setattr__(self, "module_path", module_base + module_ext) object.__setattr__(self, "config_path", path) if os.path.exists(path): namespace = self.load_from_file(path) else: namespace = None self._set_mode(_done) return namespace def load_from_file(self, path): namespace = dict(self._sections) for name, section in self._sections_list: section.update_namespace(namespace) try: execfile(path, namespace) # except ConfigError, e: except Exception, e: print "exception:", e t, v, tb = sys.exc_info() frames = traceback.extract_tb(tb) relevant_frames = [] error_line = "<unknown>" include_all = False for frame in frames: filename, line, function, text = frame print "frame:", frame if not include_all: file1 = os.path.basename(filename) file2 = os.path.basename(path) if file1 == file2: include_all = True error_line = line if include_all: relevant_frames.append(frame) self._log.error("An error occurred in the %s file at line %s." % (path, error_line)) self._log.error("The error message was: %s" % e) formatted = traceback.format_list(relevant_frames) lines = "\n".join(formatted).splitlines() for line in lines: self._log.error(" " + line) return namespace
class Compound(elements_.Alternative): _log = log_.get_log("compound.parse") _parser = parser_.Parser(stuff, _log) def __init__(self, spec, extras=None, actions=None, name=None, value=None, value_func=None, elements=None): self._spec = spec self._value = value self._value_func = value_func if extras is None: extras = {} if actions is None: actions = {} if elements is None: elements = {} # Convert extras argument from sequence to mapping. if isinstance(extras, (tuple, list)): mapping = {} for element in extras: if not isinstance(element, elements_.ElementBase): self._log.error("Invalid extras item: %s" % element) raise TypeError("Invalid extras item: %s" % element) if not element.name: self._log.error("Extras item does not have a name: %s" % element) raise TypeError("Extras item does not have a name: %s" % element) if element.name in mapping: self._log.warning( "Multiple extras items with the same name: %s" % element) mapping[element.name] = element extras = mapping elif not isinstance(extras, dict): self._log.error("Invalid extras argument: %s" % extras) raise TypeError("Invalid extras argument: %s" % extras) # Temporary transition code so that both "elements" and "extras" # are supported as keyword arguments. if extras and elements: extras = dict(extras) extras.update(elements) elif elements: extras = elements self._extras = extras # This solution is non-ideal as "stuff" is a global instance. stuff.set_elements(extras) stuff.set_actions(actions) element = self._parser.parse(spec) if not element: self._log.error("Invalid compound spec: %r" % spec) raise SyntaxError("Invalid compound spec: %r" % spec) elements_.Alternative.__init__(self, (element, ), name=name) def __str__(self): arguments = ["%r" % self._spec] if self.name: arguments.append("name=%r" % self.name) arguments = ", ".join(arguments) return "%s(%s)" % (self.__class__.__name__, arguments) def value(self, node): if self._value_func is not None: extras = {} for name, element in self._extras.iteritems(): extra_node = node.get_child_by_name(name, shallow=True) if not extra_node: continue extras[name] = extra_node.value() try: value = self._value_func(node, extras) except Exception, e: self._log.warning("Exception from value_func: %s" % e) raise return value elif self._value is not None: return self._value
class CompilerBase(object): _log = log_.get_log("engine.compiler") element_compilers = [ (elements_.Sequence, lambda s, e, *a, **k: s._compile_sequence(e, *a, **k)), (elements_.Alternative, lambda s, e, *a, **k: s._compile_alternative(e, *a, **k)), (elements_.Optional, lambda s, e, *a, **k: s._compile_optional(e, *a, **k)), (elements_.Literal, lambda s, e, *a, **k: s._compile_literal(e, *a, **k)), (elements_.RuleRef, lambda s, e, *a, **k: s._compile_rule_ref(e, *a, **k)), (elements_.ListRef, lambda s, e, *a, **k: s._compile_list_ref(e, *a, **k)), (elements_.Dictation, lambda s, e, *a, **k: s._compile_dictation(e, *a, **k)), (elements_.Impossible, lambda s, e, *a, **k: s._compile_impossible(e, *a, **k)), ] #----------------------------------------------------------------------- def __str__(self): return "%s()" % self.__class__.__name__ #----------------------------------------------------------------------- # Methods for compiling grammars. def compile_grammar(self, grammar, *args, **kwargs): raise NotImplementedError("Compiler %s not implemented." % self) #----------------------------------------------------------------------- # Methods for compiling elements. def compile_element(self, element, *args, **kwargs): # Look for a compiler method to handle the given element. for element_type, compiler in self.element_compilers: if isinstance(element, element_type): compiler(self, element, *args, **kwargs) return # Didn't find a compiler method for this element type. raise NotImplementedError("Compiler %s not implemented" " for element type %s." % (self, element)) #----------------------------------------------------------------------- def _compile_unknown_element(self, element, *args, **kwargs): raise NotImplementedError("Compiler %s not implemented" " for element type %s." % (self, element)) _compile_sequence = _compile_unknown_element _compile_alternative = _compile_unknown_element _compile_optional = _compile_unknown_element _compile_literal = _compile_unknown_element _compile_rule_ref = _compile_unknown_element _compile_list_ref = _compile_unknown_element _compile_dictation = _compile_unknown_element _compile_impossible = _compile_unknown_element