On 2011-01-14 22:53:03 -0800, Rob Miller said:

Object dispatch is a TurboGears concept, not Pylons.

I've retrofitted it to almost every web framework I've ever used from WebPy and CherryPy through to Pylons. Routes are an inherently limiting thing to me (one app I worked on actually exceeded the ~55KiB limit on regular expressions!) and I think the Pyramid folks generally agree with me. ;)

While I think a "Pyramid for TG users" guide would be a valuable resource, I think it'd be a bit confusing to put such a reference in a "Pyramid for Pylons users" document.

I guess so; Pyramid's dispatch seems to be one of the most misunderstood parts of how it works, and as an up-front intelligence cost some may give up before fully grasping it. Don't get me wrong, I like it. I also like the separation of view and the powerful cross-package collaboration it gives.

The rest of this e-mail assumes that second-stage view lookup doesn't exist; I find this to be an interesting discussion and don't mean to imply or give the impression that I think "Pyramid sucks" or "traversal sucks" or "view lookup sucks" and would like to concentrate on just traversal for discussion purposes.

From what I've seen in blog posts—overriding the dictionary lookup method—it seems a little too close to object dispatch

too close? too close for what? this sounds a bit pejorative, but i'm not quite understanding what you're getting at...

Read on.  :)

where you have straight-up attribute lookup—allowing override using __getattr__ and usually some combination of __default__ (effectively __getattr__ with extra arguments) and __lookup__ (redirecting the dispatch by returning a new object to inspect).

I'm not intimately familiar w/ TG's object dispatch, so I can't really comprehensively address the differences btween object dispatch and resource traversal.

https://github.com/GothAlice/WebCore/blob/master/web/core/dialects/common.py#L14-50

The above is the "simplest possible" (I'm sure it can be made simpler, but not by much) object dispatch function. It is simple enough to be easily groked by almost anyone. It is used in WebCore for XML-RPC and AMF dispatch. The following is the core object dispatch used for standard controllers in WebCore and is well commented:

https://github.com/GothAlice/WebCore/blob/master/web/core/dialects/core.py#L34-108

It adds redirection via __lookup__ and __default__ and correct use of HTTP status codes, but is two and a half times larger than the former version.

In my mind, though, there's a pretty big difference between URLs being constructed based on object attributes vs. URLs being constructed by traversing nested dictionaries.

An attribute is a value in the __dict__ of the object, either added by superclasses (standard or mix-in) or at runtime. Considering that, they're very similar. :)

I think of object attributes as primarily a code construct; I would expect two instances of the same class to have the same attributes, for instance.

Correct. The result is that you get a declarative-style definition of path elements to callables a la the difference between SA and Declarative SA.

Generating URL paths via object attributes makes me wary that the URL structure of my application is going to be tightly coupled with my code choices, such that refactoring my application would change the URLs in use.

Not necessarily true; there is already de-coupling in most frameworks that use object dispatch between the 'controller' and 'view', where the object dispatch 'controller' determines the 'view' to utilize. Within the context of the mismatched-for-HTTP MVC, the controller shouldn't really be doing much work at all, just passing relevant model back and forth with the view.

I could refactor the functionality of those objects [dicts] to my heart's content, but as long as the dictionary lookup API still worked, I wouldn't need to worry about the impact it had on my URL paths.

In terms of raw lookup, I'm not entirely sure how dicts and base objects differ; each provides a mechanism for determining a callable based on (in a frictionless universe, recursive) lookups.

I can see how the two might seem more similar when you look at some of the traversal examples in the Pyramid docs, since they show trivial implementations where the dictionary keys and values are hard-coded in Python.

No, I was thinking about the complicated / dynamic aspect of this as well. Dicts provide __getitem__, objects provide __getattr__; same basic idea. My core dispatch provides two additional methods for reasons I describe below.

In practice, however, this is rarely the case; traversal resources usually provide dynamic __getitem__ implementations that fetch their contents from some data source. Changing the URL structure of your site might involve a database migration, but it usually wouldn't involve any code changes.

As above, __getattr__ provides the same dynamism as __getitem__. Both of these suffer one problem: the need to use superglobals (thread-local proxies) or functional thread locals (function calls to look up objects from a registry) to have truly dynamic behaviour.

The dispatch used in WebCore includes two additional methods, one which replicates the behaviour of the end-methods, the other being passed remaining path elements as *args and GET+POST as **kw:

:: __default__ returns like any other WebCore method call, returning a view and data for the view; this is a "catch-all".

:: __lookup__ returns another object and a list of remaining path elements to evaluate via dispatch.

The latter I use /everywhere/ to affect dynamic behaviour based on remaining path elements. Recursive (or non-recursive, whatever) querying of __getattr__ will get you a single level deeper each loop, but I have one application (a MongoDB-based CMS) that optimizes using __lookup__:

https://github.com/GothAlice/Contentment/blob/master/web/extras/contentment/components/core.py#L91-139

It's
hard to describe.  :/

It takes the remaining path elements (on the first call) and computes all intermediary paths. E.g. it creates a list of ['/', '/foo', '/foo/bar'] from the path "/foo/bar", then looks up all of those paths in the DB. If the data structure is correct, that will give the deepest element. (If not, that's OK, too, instead of returning the asset controller and view, it returns the nearest asset controller and the unhandled path elements.)

On subsequent calls (e.g. deep lookup fails) it reverts to lookups based on the names of child nodes from the DB.

Anyway, that's an _extreme_ use case… in 48 lines of code.  ;)

Using __lookup__ you can model the following quite easily:

:: /
:: /action
:: /users/
:: /users/27
:: /users/27/method (e.g. delete)

The above is done like this:

https://gist.github.com/780774

As you would expect (and as demonstrated in the CMS), this can be based entirely on a database-modelled path structure.

It comes down to traversal being dict-based, and object dispatch being dict-based with benefits. ;)

In Pyramid /is/ it possible to optimize traversal for the consumption of multiple path elements?

of course, URL matching is more flexible in this regard than either other options. change the matching pattern, and the URLs have changed. no muss, no fuss.

It's more flexible in terms of centralized path reconfiguration, I'll give it that. Flexible in other terms is a more difficult claim to back up. ;) (Performance-wise, executing a 54KiB regular expression on each request is pure insanity… and what Routes actually does on one project.)

        — Alice.


--
You received this message because you are subscribed to the Google Groups 
"pylons-devel" group.
To post to this group, send email to pylons-devel@googlegroups.com.
To unsubscribe from this group, send email to 
pylons-devel+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/pylons-devel?hl=en.

Reply via email to