Add google appengine to repo
[frozenviper.git] / google_appengine / lib / webob / docs / differences.txt
blobdb7df6ae1360f667386347c75f3d56c4e479afe7
1 Differences Between WebOb and Other Systems
2 +++++++++++++++++++++++++++++++++++++++++++
4 This document points out some of the API differences between the
5 Request and Response object, and the objects in other systems.
7 .. contents::
9 paste.wsgiwrappers and Pylons
10 =============================
12 The Pylons ``request`` and ``response`` object are based on
13 ``paste.wsgiwrappers.WSGIRequest`` and ``WSGIResponse``
15 There is no concept of ``defaults`` in WebOb.  In Paste/Pylons these
16 serve as threadlocal settings that control certain policies on the
17 request and response object.  In WebOb you should make your own
18 subclasses to control policy (though in many ways simply being
19 explicit elsewhere removes the need for this policy).
21 Request
22 -------
24 ``body``:
25     This is a file-like object in WSGIRequest.  In WebOb it is a
26     string (to match Response.body) and the file-like object is
27     available through ``req.body_file``
29 ``languages()``:
30     This is available through ``req.accept_language``, particularly
31     ``req.accept_language.best_matches(fallback_language)``
33 ``match_accept(mimetypes)``:
34     This is available through ``req.accept.first_match(mimetypes)``;
35     or if you trust the client's quality ratings, you can use
36     ``req.accept.best_match(mimetypes)``
38 ``errors``:
39     This controls how unicode decode errors are handled; it is now
40     named ``unicode_errors``
42 There are also many extra methods and attributes on WebOb Request
43 objects.
45 Response
46 --------
48 default ``content_type``:
49     The base Response object has no default content_type or charset.
50     You can set ``default_content_type`` in a subclass.
52 ``determine_charset()``:
53     Is now available as ``res.charset``
55 ``has_header(header)``:
56     Should be done with ``header in res.headers``
58 ``get_content()`` and ``wsgi_response()``:
59     These are gone; you should use ``res.body`` or ``res(environ,
60     start_response)``
62 ``write(content)``:
63     Available in ``res.body_file.write(content)``.
65 ``flush()`` and ``tell()``:
66     Not available.
68 There are also many extra methods and attributes on WebOb Response
69 objects.
71 Django
72 ======
74 This is a quick summary from reading `the Django documentation
75 <http://www.djangoproject.com/documentation/request_response/>`_.
77 Request
78 -------
80 ``encoding``:
81     Is ``req.charset``
83 ``REQUEST``:
84     Is ``req.params``
86 ``FILES``:
87     File uploads are ``cgi.FieldStorage`` objects directly in
88     ``res.POST``
90 ``META``:
91     Is ``req.environ``
93 ``user``:
94     No equivalent (too connected to application model for WebOb).
95     There is ``req.remote_user``, which is only ever a string.
97 ``session``:
98     No equivalent
100 ``raw_post_data``:
101     Available with ``req.body``
103 ``__getitem__(key)``:
104     You have to use ``req.params``
106 ``is_secure()``:
107     No equivalent; you could use ``req.scheme == 'https'``.
109 QueryDict
110 ---------
112 QueryDict is the way Django represents the multi-key dictionary-like
113 objects that are request variables (query string and POST body
114 variables).  The equivalent in WebOb is MultiDict.
116 Mutability:
117     WebOb dictionaries are sometimes mutable (req.GET is,
118     req.params is not)
120 Ordering:
121     I believe Django does not order the keys fully; MultiDict is a
122     full ordering.  Methods that iterate over the parameters iterate
123     over keys in their order in the original request.
125 ``keys()``, ``items()``, ``values()`` (plus ``iter*``):
126     These return all values in MultiDict, but only the last value for
127     a QueryDict.  That is, given ``a=1&a=2`` with MultiDict
128     ``d.items()`` returns ``[('a', '1'), ('a', '2')]``, but QueryDict
129     returns ``[('a', '1')]``
131 ``getlist(key)``:
132     Available as ``d.getall(key)``
134 ``setlist(key)``:
135     No direct equivalent
137 ``appendlist(key, value)``:
138     Available as ``d.add(key, value)``
140 ``setlistdefault(key, default_list)``:
141     No direct equivalent
143 ``lists()``:
144     Is ``d.dict_of_lists()``
146 The MultiDict object has a ``d.getone(key)`` method, that raises
147 KeyError if there is not exactly one key.  There is a method
148 ``d.mixed()`` which returns a version where values are lists *if*
149 there are multiple values for a list.  This is similar to how many
150 cgi-based request forms are represented.
152 Response
153 --------
155 Constructor:
156     Totally different.  The WebOb Response object should probably be
157     subclassed for direct application use; in WebOb it does not
158     *prefer* HTML or anything normal web application conventions
160 dictionary-like:
161     The Django response object is somewhat dictionary-like, setting
162     headers.  The equivalent dictionary-like object is
163     ``res.headers``.  In WebOb this is a MultiDict.
165 ``has_header(header)``:
166     Use ``header in res.headers``
168 ``write(content)``:
169     As ``res.body_file.write(content)``
171 ``flush()``, ``tell()``:
172     Not available
174 ``content``:
175     Use ``res.body`` for the ``str`` value, ``res.unicode_body`` for
176     the ``unicode`` value
178 Response Subclasses
179 -------------------
181 These are generally like ``webob.exc`` objects.
182 ``HttpResponseNotModified`` is ``HTTPNotModified``; this naming
183 translation generally works.
185 CherryPy/TurboGears
186 ===================
188 The `CherryPy request object
189 <http://www.cherrypy.org/wiki/RequestObject>`_ is also used by
190 TurboGears 1.x.
192 Request
193 -------
195 ``app``:
196     No equivalent
198 ``base``:
199     ``req.application_url``
201 ``close()``:
202     No equivalent
204 ``closed``:
205     No equivalent
207 ``config``:
208     No equivalent
210 ``cookie``:
211     A ``SimpleCookie`` object in CherryPy; a dictionary in WebOb
212     (``SimpleCookie`` can represent cookie parameters, but cookie
213     parameters are only sent with responses not requests)
215 ``dispatch``:
216     No equivalent (this is the object dispatcher in CherryPy).
218 ``error_page``, ``error_response``, ``handle_error``:
219     No equivalent
221 ``get_resource()``:
222     Similar to ``req.get_response(app)``
224 ``handler``:
225     No equivalent
227 ``headers``, ``header_list``:
228     The WSGI environment represents headers as a dictionary, available
229     through ``req.headers`` (no list form is available in the request).
231 ``hooks``:
232     No equivalent
234 ``local``:
235     No equivalent
237 ``methods_with_bodies``:
238     This represents methods where CherryPy will automatically try to
239     read the request body.  WebOb lazily reads POST requests with the
240     correct content type, and no other bodies.
242 ``namespaces``:
243     No equivalent
245 ``protocol``:
246     As ``req.environ['SERVER_PROTOCOL']``
248 ``query_string``:
249     As ``req.query_string``
251 ``remote``:
252     ``remote.ip`` is like ``req.remote_addr``.  ``remote.port`` is not
253     available.  ``remote.name`` is in
254     ``req.environ.get('REMOTE_HOST')``
256 ``request_line``:
257     No equivalent
259 ``respond()``:
260     A method that is somewhat similar to ``req.get_response()``.
262 ``rfile``:
263     ``req.body_file``
265 ``run``:
266     No equivalent
268 ``server_protocol``:
269     As ``req.environ['SERVER_PROTOCOL']``
271 ``show_tracebacks``:
272     No equivalent
274 ``throw_errors``:
275     No equivalent
277 ``throws``:
278     No equivalent
280 ``toolmaps``:
281     No equivalent
283 ``wsgi_environ``:
284     As ``req.environ``
286 Response
287 --------
289 From information `from the wiki
290 <http://www.cherrypy.org/wiki/ResponseObject>`_.
292 ``body``:
293     This is an iterable in CherryPy, a string in WebOb;
294     ``res.app_iter`` gives an iterable in WebOb.
296 ``check_timeout``:
297     No equivalent
299 ``collapse_body()``:
300     This turns a stream/iterator body into a single string.  Accessing
301     ``res.body`` will do this automatically.
303 ``cookie``:
304     Accessible through ``res.set_cookie(...)``, ``res.delete_cookie``,
305     ``res.unset_cookie()``
307 ``finalize()``:
308     No equivalent
310 ``header_list``:
311     In ``res.headerlist``
313 ``stream``:
314     This can make CherryPy stream the response body out directory.
315     There is direct no equivalent; you can use a dynamically generated
316     iterator to do something similar.
318 ``time``:
319     No equivalent
321 ``timed_out``:
322     No equivalent
324 Yaro
325 ====
327 `Yaro <http://lukearno.com/projects/yaro/>`_ is a small wrapper around
328 the WSGI environment, much like WebOb in scope.
330 The WebOb objects have many more methods and attributes.  The Yaro
331 Response object is a much smaller subset of WebOb's Response.
333 Request
334 -------
336 ``query``:
337     As ``req.GET``
339 ``form``:
340     As ``req.POST``
342 ``cookie``:
343     A ``SimpleCookie`` object in Yaro; a dictionary in WebOb
344     (``SimpleCookie`` can represent cookie parameters, but cookie
345     parameters are only sent with responses not requests)
347 ``uri``:
348     Returns a URI object, no equivalent (only string URIs available).
350 ``redirect``:
351     Not available (response-related).  ``webob.exc.HTTPFound()`` can
352     be useful here.
354 ``forward(yaroapp)``, ``wsgi_forward(wsgiapp)``:
355     Available with ``req.get_response(app)`` and
356     ``req.call_application(app)``.  In both cases it is a WSGI
357     application in WebOb, there is no special kind of communication;
358     ``req.call_application()`` just returns a ``webob.Response`` object.
360 ``res``:
361     The request object in WebOb *may* have a ``req.response``
362     attribute.
364 Werkzeug
365 ========
367 Probably not that many people know about this library, which is a
368 offshoot of `Pocoo <http://pocoo.org>`_, and used to go by another
369 name (Columbrid?)  This library is based around WSGI, similar to Paste
370 and Yaro.
372 This is take from the `wrapper documentation
373 <http://werkzeug.pocoo.org/documentation/wrappers>`_.
375 Request
376 -------
378 path:
379     As ``req.path_info``
380 args:
381     As ``req.GET``
382 form:
383     As ``req.POST``
384 values:
385     As ``req.params``
386 files:
387     In ``req.POST`` (as FieldStorage objects)
388 data:
389     In ``req.body_file``
391 Response
392 --------
394 response:
395     In ``res.body`` (settable as ``res.body`` or ``res.app_iter``)
396 status:
397     In ``res.status_int``
398 mimetype:
399     In ``res.content_type``
400 write(data):
401     With ``res.body_file.write(data)``
403 Zope 3
404 ======
406 From the Zope 3 interfaces for the `Request
407 <http://apidoc.zope.org/++apidoc++/Interface/zope.publisher.interfaces.browser.IBrowserRequest/index.html>`_
408 and `Response
409 <http://apidoc.zope.org/++apidoc++/Interface/zope.publisher.interfaces.http.IHTTPResponse/index.html>`_.
411 Request
412 -------
414 ``locale``, ``setupLocale()``:
415     This is not fully calculated, but information is available in
416     ``req.accept_languages``.
418 ``principal``, ``setPrincipal(principal)``:
419     ``req.remote_user`` gives the username, but there is no standard
420     place for a user *object*.
422 ``publication``, ``setPublication()``, 
423     These are associated with the object publishing system in Zope.
424     This kind of publishing system is outside the scope of WebOb.
426 ``traverse(object)``, ``getTraversalStack()``, ``setTraversalStack()``:
427     These all relate to traversal, which is part of the publishing
428     system.
430 ``processInputs()``, ``setPathSuffix(steps)``:
431     Also associated with traversal and preparing the request.
433 ``environment``:
434     In ``req.environ``
436 ``bodyStream``:
437     In ``req.body_file``
439 ``interaction``:
440     This is the security context for the request; all the possible
441     participants or principals in the request.  There's no
442     equivalent.
444 ``annotations``:
445     Extra information associated with the request.  This would
446     generally go in custom keys of ``req.environ``, or if you set
447     attributes those attributes are stored in
448     ``req.environ['webob.adhoc_attrs']``.
450 ``debug``:
451     There is no standard debug flag for WebOb.
452     
453 ``__getitem__(key)``, ``get(key)``, etc:
454     These treat the request like a dictionary, which WebOb does not
455     do.  They seem to take values from the environment, not
456     parameters.  Also on the Zope request object is ``items()``,
457     ``__contains__(key)``, ``__iter__()``, ``keys()``, ``__len__()``,
458     ``values()``.
460 ``getPositionalArguments()``:
461     I'm not sure what the equivalent would be, as there are no
462     positional arguments during instantiation (it doesn't fit into
463     WSGI).  Maybe ``wsgiorg.urlvars``?
465 ``retry()``, ``supportsRetry()``:
466     Creates a new request that can be used to retry a request.
467     Similar to ``req.copy()``.
469 ``close()``, ``hold(obj)``: 
470     This closes resources associated with the request, including any
471     "held" objects.  There's nothing similar.
473 Response
474 --------
476 ``authUser``:
477     Not sure what this is or does.
479 ``reset()``:
480     No direct equivalent; you'd have to do ``res.headers = [];
481     res.body = ''; res.status = 200``
483 ``setCookie(name, value, **kw)``:
484     Is ``res.set_cookie(...)``.
486 ``getCookie(name)``:
487     No equivalent.  Hm.
489 ``expireCookie(name)``:
490     Is ``res.delete_cookie(name)``.
492 ``appendToCookie(name, value)``:
493     This appends the value to any existing cookie (separating values
494     with a colon).  WebOb does not do this.
496 ``setStatus(status)``:
497     Availble by setting ``res.status`` (can be set to an integer or a
498     string of "code reason").
500 ``getHeader(name, default=None)``:
501     Is ``res.headers.get(name)``.
503 ``getStatus()``:
504     Is ``res.status_int`` (or ``res.status`` to include reason)
506 ``addHeader(name, value)``:
507     Is ``res.headers.add(name, value)`` (in Zope and WebOb, this does
508     not clobber any previous value).
510 ``getHeaders()``:
511     Is ``res.headerlist``.
513 ``setHeader(name, value)``:
514     Is ``res.headers[name] = value``.
516 ``getStatusString()``:
517     Is ``res.status``.
519 ``consumeBody()``:
520     This consumes any non-string body to turn the body into a single
521     string.  Any access to ``res.body`` will do this (e.g., when you
522     have set the ``res.app_iter``).
524 ``internalError()``:
525     This is available with ``webob.exc.HTTP*()``.
527 ``handleException(exc_info)``:
528     This is provided with a tool like ``paste.exceptions``.
530 ``consumeBodyIter()``:
531     This returns the iterable for the body, even if the body was a
532     string.  Anytime you access ``res.app_iter`` you will get an
533     iterable.  ``res.body`` and ``res.app_iter`` can be interchanged
534     and accessed as many times as you want, unlike the Zope
535     equivalents.
537 ``setResult(result)``:
538     You can achieve the same thing through ``res.body = result``, or
539     ``res.app_iter = result``.  ``res.body`` accepts None, a unicode
540     string (*if* you have set a charset) or a normal string.
541     ``res.app_iter`` only accepts None and an interable.  You can't
542     update all of a response with one call.
544     Like in Zope, WebOb updates Content-Length.  Unlike Zope, it does
545     not automatically calculate a charset.
548 mod_python
549 ==========
551 Some key attributes from the `mod_python
552 <http://modpython.org/live/current/doc-html/pyapi-mprequest-mem.html>`_ 
553 request object.
555 Request
556 -------
558 ``req.uri``:
559     In ``req.path``.
560    
561 ``req.user``:
562     In ``req.remote_user``.
564 ``req.get_remote_host()``:
565     In ``req.environ['REMOTE_ADDR']`` or ``req.remote_addr``.
567 ``req.headers_in.get('referer')``:
568     In ``req.headers.get('referer')`` or ``req.referer`` (same pattern
569     for other request headers, presumably).
571 Response
572 --------
574 ``util.redirect`` or ``req.status = apache.HTTP_MOVED_TEMPORARILY``:
576 .. code-block::
578     from webob.exc import HTTPMovedTemporarily()
579     exc = HTTPMovedTemporarily(location=url)
580     return exc(environ, start_response)
582 ``req.content_type = "application/x-csv"`` and 
583 ``req.headers_out.add('Content-Disposition', 'attachment;filename=somefile.csv'):
585 .. code-block::
587     res = req.ResponseClass()
588     res.content_type = 'application/x-csv'
589     res.headers.add('Content-Disposition', 'attachment;filename=somefile.csv')
590     return res(environ, start_response)