a little wsgi framework

Bruno Desthuilliers bruno.42.desthuilliers at websiteburo.invalid
Tue Jul 7 05:19:46 EDT 2009


timmyt a écrit :
> i'm interested in getting opinions on a small wsgi framework i
> assembled from webob, sqlalchemy, genshi, and various code fragments i
> found on the inter-tubes
> 
> here is the interesting glue - any comments / suggestions would be
> much appreciated

<meta>
Well... My first comment would be about the usefulness of yet another 
Python web framework, but let's not worry about this...
</meta>

> ------------------
> the wsgi app
> ------------------
> def application(environ, start_response):
>     path = environ.get('PATH_INFO', '').lstrip('/')
> 
>     for regex, callback in urls:
>         match = re.search(regex, path)


I don't know where these "urls" come from. But anyway : if they live in 
some sort of long-running process, you may want to precompile them.

>         if match:
>             environ['myapp.url_args'] = match.groups()
>             request = webob.Request(environ)
> 
>             try:
>                 return callback(request, start_response)
>             except Exception, ex:

How are redirect etc handled ?

>                 start_response('500 Internal Server Error', [('Content-
> Type', 'text/plain')])
>                 return [traceback.format_exc()]

A configuration option controlling the display of the traceback would be 
fine - I surely don't want the traceback being displayed to anyone when 
  the app goes into production.

Also, logging the error and traceback might be useful.


>     start_response('404 Not Found', [('Content-Type', 'text/plain')])
>     return ["Couldn't find the URL specified."]
> 

And in both cases, having the ability to use "custom" 500 and 404 pages 
might be nice too.


> ----------------------------------
> the controller decorator
> ----------------------------------
> def web_decorator(filename, method='html'):
 >
>     def decorator(target):

May I suggest some renaming here ?

filename => path (or 'template_path' ?)
method   => content_type
target   => controller or function or callback or....

>         def wrapper(request, start_response):
> 
>             #genshi TemplateLoader
>             template = loader.load(filename)
> 
>             global config

Probably not thread-safe....

>             try:
>                 return_dict = target(request, start_response)
>                 return_string = template.generate(**return_dict).render
> (method)


Renaming again:
return_dict => context
return_string => data or text or ???

>                 config['database.Session'].commit()
>             except:
>                 config['database.Session'].rollback()
>                 raise
>             finally:
>                 config['database.Session'].remove()

This doesn't leave much control on transactions... Sometimes you want to 
handle it manually one way or another.

>             #TODO: alter 'Content-Type' per method being passed
>             start_response('200 OK', [('Content-Type', 'text/html')])
>             return [return_string]

Ok, so here again, I don't understand how redirects can work. Also, if 
you do use start_response here, I don't get why you still pass it to the 
callback function.

>         return wrapper
> 
>     return decorator

slightly OT, but preserving infos on the decorated function might help 
too (introspection, debugging etc).


My 2 cents...



More information about the Python-list mailing list