def _compute_path(self, parent, path): graph = OrderedDict() print parent, path if hasattr(parent, "index"): graph[re.compile("^%s/$" % path) ] = parent.index for name in dir(parent): if name.startswith("_"): continue obj = getattr(parent, name) if isAction(obj): node_body = "%s/%s" % (path, name,) if isExposed(obj): graph[re.compile("^%s$" % node_body)] = obj elif isResource(obj): graph[re.compile("^%s/?(.*)" % node_body)] = obj elif obj: graph.update(self._compute_path(obj, "%s/%s" % (path, name,))) return graph
def routeRequest(self, request): action = None url_match = None for url_regex, candidate in self.object_graph.items(): url_match = url_regex.match(request.path) if url_match: action = candidate break if action is None: return NoResource() else: #Last step is to see what was found, if the target was a resource, we're done #For now, assuming only ^url/2/resource(.*)$ regexs are used for resources! if isResource(action): url_groups = url_match.groups() if url_groups: childPath = url_match.groups()[0].split("/") while childPath: action = action.getChild(childPath.pop(0), request) return action else: return OneTimeResource(action)
def routeRequest(self, request): """ Traverses from the root controller, down through its children and returns the first callable or Resource that matches the provided request.path If there is no match, it will return NoResource :param request is a twisted.web.request instance ex. Given a path like '/foo/test/x' it would match a OO graph of root.foo.test.x or the first callable in that line. so if root.root() has a method called test, then 'x' will be pushed into """ action = None #self.resource is the Root controller object provided to Site.__init__(resource) root = parent = self.resource """ defaultAction is a catch_all method that is set to intercept routing fallouts below the current parent. Example: Given a request path like "/foo/bar/something/something/ and a Graph like class Bar: pass class Foo: bar = Bar() class Root: def __default__(self, request): return "Root default handler" foo = Foo() Root.__default__ will end up being called if Foo had a __default__ method, it would be called instead if Bar had a __default__ method, then naturally it would be called The default action mechanism is the only planned means of supporting out of order routing like "/person/123/edit" where the desired action is to call Root.person.edit(<Request args={record_id:123} ) """ defaultAction = getattr(root, "__default__", None ) or NoResource() #crucial check because /foo/bar and /foo/bar/ should be treated as different ( former suggest Foo.<bound method bar> while the second Foo.<object instance bar>) endedWithSlash = request.path.endswith("/") path = request.path.strip("/").split("/") for i, element in enumerate(path): #For the first run through the loop, parent == root, but subsequent iterations parent will equal the Nth child of root parent = root root = getattr(root, element, None) request.prepath.append(element) if root is None: """ if root has nulled out, check to see if the last element in the path was a controller AND if so check for an index attribute that is callable or resource """ if endedWithSlash: if hasattr(parent, "index") and isAction(getattr(parent, "index")): action = getattr(parent, "index") break if hasattr(root, "__default__") and isAction(getattr(root, "__default__")): #Check for a catchall default action defaultAction = getattr(root, "__default__") if element.startswith("_"): #500 simplistic security check #There is already the exposed check, but this is a second security check to prevent calls to Root.__dict__ or such return ErrorPage(500, "Illegal characters", "URI segments cannot start with an underscore") break #pragma: no cover if isAction(root): action = root request.postpath = path[i+1:] if isResource(root): """ NOTE: For twisted.web a path like "/foo/bar/blah" translates to ["","foo","bar","blah"] while "/foo/bar/blah/" == ["","foo","bar","blah",""] which is how Str.split works. twisted.web's pathing logic depends on the prior result for Resource child delegation. txweb meanwhile, doesn't. """ if len( path[i+1:] ) > 0: childPath = request.postpath[:] while childPath: sub = childPath.pop(0) action = action.getChild(sub, request) elif endedWithSlash: #TODO need more unit-tests to clarify why I did this #given foo = File("somePath/") and a path like "/foo/", expected twisted behavior is File to be given path of "" action = action.getChild("", request) break if action is None: if endedWithSlash and hasattr(root, "index"): action = getattr(root, "index") #handles calls to child object attributes where they're at root.foo and url == "/foo" but should be "/foo/" elif not endedWithSlash and element in dir(parent) and element[0] != "_" and isinstance(getattr(parent, element), object): action = util.Redirect("%s/" % request.path) if action is None: action = defaultAction or NoResource() #Last step is to see what was found, if the target was a resource, we're done if isResource(action): return action #If action was a non-resource callable, bind the callable's parent to allow for pre/post filter logic in OneTimeResource elif parent is not None and isinstance(parent, object): return OneTimeResource(action, parent) else: #This isn't ideal but could be a result of Root having a __call__ method #Coverage in WebMud & PyProxy SSR both show this is never reached - placed on TODO as an Exception return OneTimeResource(action)