[Twisted-Python] A new & improved IResource

Glyph Lefkowitz glyph at twistedmatrix.com
Tue Jun 14 12:58:56 EDT 2011


On Jun 13, 2011, at 6:30 PM, Laurens Van Houtven wrote:

> On Mon, Jun 13, 2011 at 3:38 PM, <exarkun at twistedmatrix.com> wrote:
> Another thing we want is something closer to locateChild as Nevow and
> web2 had.  The key feature is being able to consume multiple path
> segments (or none at all) at a time if desired.
> 
> Jean-Paul
> 
> I added it to the ticket.
> 
> Someone on IRC mentioned that locateChild isn't exactly perfect either -- how does it differ from the idealized API? 
> 
> For the people who hadn't seen locateChild before (much like myself) -- the main difference is that instead of just taking the *next* segment, it takes all of the remaining ones, and instead of returning a single child, it returns a child and the remaining segments. A possible problem with this is that people might get the impression they should mess with the segments... Comments welcome.

Yeah, messing with segments is an issue.  There's a thing that some Nevow applications would do which, while I'm not entirely sure it was a terrible idea, definitely exposed a weakness in this model.  We called it an "internal redirect".  The basic idea is that your resource gets called with "request, [a, b, c]" and you return "resource, [d, e, f]".  The problem with allowing this is that it decouples the resource from any sane way to identify its URL based on the request.  It's handy to have something like the 'prepath' attribute to assist in generating absolute URIs that can be passed to external systems, but you can't make that consistent in the face of code that arbitrarily manipulates the segments list.

Also, you can internally redirect this way based on path-based dispatch but you can't redirect based on hostname or other features of the request without mutating it.  So it seemed like a lopsided half-feature.

One off-the-cuff idea to address this would be to have a 'path' object with an API of its own; something like this:

def locateDescendant(self, request, path):
    year, month, day = path.consume(3)
    rsrc = self.resourceFromDate(year, month, day)
    return rsrc

.consume(integer) is something of a strawman here; you'd probably need a way to say stuff like "consume all of the path segments" or "consume everything up to a segment with the value 'x'", so that we didn't lose the (legitimate) flexibility of having a list.  We could of course just pass in a mutable list and not return it, but that provides a little more flexibility than I'd like, because it would allow you to do all the same stuff as returning your own arbitrary sequence.

Really this 'path' is actually cursor over the URI inside the request.  It would be nice if the state associated with traversal were encapsulated entirely in that object, so that the request itself didn't get mutated as it traveled down the path.

> I'm also not sure if it should be allowed to return an IResource (and basically use the IResource getChild behavior whenever you see an IResource...) or if it should only return the new things.

One return-type signature is a good idea.  Convenience APIs are better.  That said, if we do go with 2-tuple as the return type, good error reporting is crucial; it's very easy to accidentally return a resource.

> Perhaps there could be an adapter: if entity.locateChild([a, b, c]) returns a (resource, [b, c]), the resource is adapted to IEntity (working title for I2NewResource2), and the adapter's .locateChild([b, c]) call gets translated into self.wrappedResource.getChild(b).getChild(c), or something.

That seems sensible.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://twistedmatrix.com/pipermail/twisted-python/attachments/20110614/56689e74/attachment.htm 


More information about the Twisted-Python mailing list