Re: a little wsgi framework
On Jul 7, 5:19 am, Bruno Desthuilliers bruno. 42.desthuilli...@websiteburo.invalid wrote: timmyt a écrit : i'm interested in getting opinions on a smallwsgiframework 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 -- thewsgiapp -- 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... thank you gentlemen i'm now looking for Redirect exceptions as well, and returning the appropriate response code (stole this idea from turbogears) i like doing the response codes and exceptions myself which is why i'm not using the webob response - i think it's more explicit and straightforward the conditional display of errors goes without say - that will be trivial to add the 'global config' line was an error - config is a module level variable set before the application definition i assume as long as i don't write to the config variable within the application it is thread-safe - is that correct the underlying assumption is the wsgi application setup does not have to be thread safe - this is only run once per process -- http://mail.python.org/mailman/listinfo/python-list
a little wsgi framework
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 -- the wsgi app -- def application(environ, start_response): path = environ.get('PATH_INFO', '').lstrip('/') for regex, callback in urls: match = re.search(regex, path) if match: environ['myapp.url_args'] = match.groups() request = webob.Request(environ) try: return callback(request, start_response) except Exception, ex: start_response('500 Internal Server Error', [('Content- Type', 'text/plain')]) return [traceback.format_exc()] start_response('404 Not Found', [('Content-Type', 'text/plain')]) return [Couldn't find the URL specified.] -- the controller decorator -- def web_decorator(filename, method='html'): def decorator(target): def wrapper(request, start_response): #genshi TemplateLoader template = loader.load(filename) global config try: return_dict = target(request, start_response) return_string = template.generate(**return_dict).render (method) config['database.Session'].commit() except: config['database.Session'].rollback() raise finally: config['database.Session'].remove() #TODO: alter 'Content-Type' per method being passed start_response('200 OK', [('Content-Type', 'text/html')]) return [return_string] return wrapper return decorator -- http://mail.python.org/mailman/listinfo/python-list
Standard CRUD
my buddy and i have created a Standard CRUD (SCRUD) spec that we'd like to use across projects and frameworks before we get totally dependent on the pattern, I want to make sure there's not some better solution out there, or some ideas that will improve the design below is the spec we came up with: SCRUD (Standard CRUD) = Overview --- Standard CRUD is a design pattern for: * displaying a single instance * displaying a filterable list of instances * displaying a form to create a new single instance * actually creating a new single instance * displaying a form to update a single instance * actually updating a single instance * displaying a form to delete a single instance * actually deleting a single instance * displaying a form to perform a bulk insert * actually performing a bulk insert * displaying a form to perform a bulk update * actually performing a bulk update * displaying a form to perform a bulk delete * actually performing a bulk delete The intention is that all methods supported by the model will have a consistent Class Method Interface - for example any model that supports bulk insert will have a standard class method to support this functionality. Important Considerations * SCRUD should work the same in an ajax context as well as in a traditional page submit * SCRUD state changing methods should be easily testable using selenium, twill or some other web testing tool in either an ajax or page submit context General Design A method performs one distinct action. For example the act of drawing an update form is different than the act of actually updating an object instance. This helps to enable testability and use in various contexts. Page Urls = Method URLWhat it does = GETmodel/ gets a list of model instances, using filters like ?key=value1key=value2 GETmodel/searchdisplays a search form GETmodel/iddisplays a readonly instance GETmodel/edit/id displays an edit form POST model/update/id updates an instance and redirects GETmodel/createdisplays an insert form POST model/insertinserts a new record and redirects POST model/delete/id deletes a record and redirects GETmodel/bulk/edit display a bulk edit ui POST model/bulk/update performs a bulk update and redirect GETmodel/bulk/create display a bulk insert form POST model/bulk/insert performs a bulk insert and redirect POST model/bulk/delete performs a bulk delete and redirect = -- http://mail.python.org/mailman/listinfo/python-list