Archives for: June 2006

06/28/06

Permalink 09:25:43 am, by admin Email , 365 words   English (US)
Categories: IT, Python, Dejavu

The Fourth Way

Ted Neward has written a good discussion of Object-Relational Mapper concerns. I'd like to react to, and associate, a couple of points he makes, seemingly unrelatedly:

...we typically end up with one of Query-By-Example (QBE), Query-By-API (QBA), or Query-By-Language (QBL) approaches.

A QBE approach states that you fill out an object template of the type of object you're looking for...
a "Query-By-API" approach, in which queries are constructed by Query objects...
a "Query-By-Language" approach, in which a new language, similar to SQL but "better" somehow, is written...

and

Several possible solutions present themselves...

5. Integration of relational concepts into the languages. Developers simply accept that this is a problem that should be solved by the language, not by a library or framework...bring relational concepts (which, at heart, are set-based) into mainstream programming languages, making it easier to bridge the gap between "sets" and "objects"...[such as] direct integration into traditional O-O languages, such as the LINQ project from Microsoft...

I propose (and implemented in Dejavu) a fourth approach from QBE, QBA, and QBL. Rather than build a DSL on top of a programming language (as QBL does), use the language instead. Rather than change the programming language by introducing relational syntax (as LINQ does), use the language instead. In Dejavu, you write plain old Python functions which take an object and return True or False. Iterate over a collection of objects and it works as a filter. Pass it to the storage backend and it is translated into SQL for you. Most commonly, you pass it to the library and it does both for you: iterates over its in-memory cache of objects and merges in new objects, queried from storage. Let's call it... "query". It's not "by" anything. It has an infinitesimal learning curve. LINQ is, in essence, shoehorning higher-order functions into its various target languages in a very limited domain. Why not use a programming language that has real HOF's?

06/25/06

Permalink 01:47:16 pm, by fumanchu Email , 15 words   English (US)
Categories: General

Apologies to you blogspot users

I've decided it's easier to just ban blogspot.com comments. Sorry if that includes you.

06/15/06

Permalink 01:23:24 am, by admin Email , 753 words   English (US)
Categories: Python, CherryPy

How CherryPy processes a request

Inspired by James Bennett, here's a little treatise on how CherryPy processes a request. A couple of differences, though. First, Django is a "full-stack" web framework, with an ORM, built-in templating, etcetera, whereas CherryPy focuses on HTTP. Second, I'll be showing the process for CherryPy 2.2 (the current stable branch), but I'll try to point out along the way where CherryPy 3 (now in alpha) differs.

HTTP Server

Something must actually sit on a listening socket and receive requests from HTTP clients. CherryPy provides an HTTP server (_cpwsgiserver.py), or you can use Apache, lighttpd, or others.

Bridge from HTTP Server to CherryPy

The Web Server Gateway Interface spec came into being to connect various HTTP servers to various web frameworks (and gateways and middleware and...). If you want to use it to connect an HTTP server with CherryPy, feel free. CherryPy provides a "WSGI application callable" in _cpwsgi.py. Otherwise, you need a specific adapter at this stage to connect the two.

The CherryPy Engine

Whether you use WSGI or not for the Bridge, it calls Engine.request(), which creates the all-important objects cherrypy.request and cherrypy.response, returning the former. The Bridge then calls request.run(), passing it the incoming message stream.

The CherryPy Request

Several steps occur here to convert the incoming stream to more usable data structures, pass the request to the appropriate user code, and then convert outbound data. In-between the standard processing steps, users can define extra code to be run via filters (CP 2.2) or hooks (CP 3). Here's how CherryPy 2 does it:

  1. Request.processRequestLine() analyzes the first line of the request, turning "GET /path/to/resource?key=val HTTP/1.1" into a request method, path, query string, and version.
  2. Any on_start_resource filters are run.
  3. Request.processHeaders() turns the incoming HTTP request headers into a dictionary, and separates Cookie information.
  4. Any before_request_body filters are run.
  5. Request.processBody() turns the incoming HTTP request body into a dictionary if possible, otherwise, it's passed onward as a file-like object.
  6. Any before_main filters are run.
  7. The user-supplied page handler is looked up (see below).
  8. The user-supplied page handler is invoked. Its return value, which can be a string, a list, a file, or a generator object, will be used for the response body.
  9. Any before_finalize filters will be run.
  10. Response.finalize() checks for HTTP correctness of the response, and transforms user-friendly data structures into HTTP-server-friendly structures.
  11. Any on_end_resource filters are run.

CherryPy 3 performs the same steps as above, but in the order: 1, 3, 7, 2, 4, 5, 6, 8, 9, 10, 11. That is, it determines which bit of user code will respond to the request much earlier in the process. This also means that internal redirects can "start over" much earlier. In addition, CP 3 can collect configuration data once (at the same time that it looks up the page handler); CP 2 recollected config data every time it was used.

Page handlers

As mentioned (steps 7 and 8, above), CherryPy users write "page handlers", functions which receive the request parameters as arguments, and return the response body. CherryPy makes clever use of threadlocals, so all other data a developer needs is available in the global cherrypy.request and cherrypy.response objects (the parameters are as well, but it's awfully convenient to receive them as arguments to the page handler, and to return the body rather than setting it).

The URL is mapped to a page handler by traversing a tree of such handlers, so that the handler for "/a/b/c" is most likely root.a.b.c(). I say "most likely", because you can also define index() handlers and default() handlers.

The CherryPy Response

When the call to Request.run() returns, the Bridge uses the Response attributes status, header_list, and body to construct the outbound stream, and pass it to the HTTP server that made the request. CherryPy works hard to support both buffered and streaming output, so the body may be a generator object that is only iterated over at this point.

Exceptional circumstances

The page handler, or any of the filters/hooks, can decide that the response is complete, and that processing should be stopped. Most often, this is accomplished by raising an HTTPRedirect (3xx) exception, or an HTTPError (4xx or 5xx; NotFound (404) is so common it has its own subclass). Unanticipated errors are automatically converted into HTTPError(500). Users have some facility for modifying the actual error output with additional error filters/hooks.

That's it!

June 2006
Sun Mon Tue Wed Thu Fri Sat
 << < Current> >>
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  

Search

The requested Blog doesn't exist any more!

XML Feeds

powered by b2evolution