"""Logic for traversing directory objects and generating output. """ import quixote from quixote.errors import TraversalError class Directory(object): """ Instance attributes: none """ # A list containing strings or 2-tuples of strings that map external # names to internal names. Note that the empty string will be # implicitly mapped to '_q_index'. _q_exports = [] def _q_translate(self, component): """(component : string) -> string | None Translate a path component into a Python identifier. Returning None signifies that the component does not exist. """ if component in self._q_exports: if component == '': return '_q_index' # implicit mapping else: return component else: # check for an explicit external to internal mapping for value in self._q_exports: if isinstance(value, tuple): if value[0] == component: return value[1] else: return None def _q_lookup(self, component): """(component : string) -> object Lookup a path component and return the corresponding object (usually a Directory, a method or a string). Returning None signals that the component does not exist. """ return None def _q_traverse(self, path): """(path: [string]) -> object Traverse a path and return the result. """ assert len(path) > 0 component = path[0] path = path[1:] name = self._q_translate(component) if name is not None: obj = getattr(self, name) else: obj = self._q_lookup(component) if obj is None: raise TraversalError(private_msg=('directory %r has no component ' '%r' % (self, component))) if path: if hasattr(obj, '_q_traverse'): return obj._q_traverse(path) else: raise TraversalError elif callable(obj): return obj() else: return obj def __call__(self): if "" in self._q_exports and not quixote.get_request().form: # Fix missing trailing slash. path = quixote.get_path() print "Adding slash to: %r " % path return quixote.redirect(path + "/", permanent=True) else: raise TraversalError(private_msg=('directory %r is not ' 'callable' % self)) class AccessControlled(object): """ A mix-in class that calls the _q_access() method before traversing into the directory. """ def _q_access(self): pass def _q_traverse(self, path): self._q_access() return super(AccessControlled, self)._q_traverse(path) class Resolving(object): """ A mix-in class that provides the _q_resolve() method. _q_resolve() is called if a component name appears in the _q_exports list but is not an instance attribute. _q_resolve is expected to return the component object. """ def _q_resolve(self, name): return None def _q_translate(self, component): name = super(Resolving, self)._q_translate(component) if name is not None and not hasattr(self, name): obj = self._q_resolve(name) setattr(self, name, obj) return name