thirdparty/google_appengine/lib/webob/docs/differences.txt
changeset 109 620f9b141567
equal deleted inserted replaced
108:261778de26ff 109:620f9b141567
       
     1 Differences Between WebOb and Other Systems
       
     2 +++++++++++++++++++++++++++++++++++++++++++
       
     3 
       
     4 This document points out some of the API differences between the
       
     5 Request and Response object, and the objects in other systems.
       
     6 
       
     7 .. contents::
       
     8 
       
     9 paste.wsgiwrappers and Pylons
       
    10 =============================
       
    11 
       
    12 The Pylons ``request`` and ``response`` object are based on
       
    13 ``paste.wsgiwrappers.WSGIRequest`` and ``WSGIResponse``
       
    14 
       
    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).
       
    20 
       
    21 Request
       
    22 -------
       
    23 
       
    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``
       
    28 
       
    29 ``languages()``:
       
    30     This is available through ``req.accept_language``, particularly
       
    31     ``req.accept_language.best_matches(fallback_language)``
       
    32 
       
    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)``
       
    37 
       
    38 ``errors``:
       
    39     This controls how unicode decode errors are handled; it is now
       
    40     named ``unicode_errors``
       
    41 
       
    42 There are also many extra methods and attributes on WebOb Request
       
    43 objects.
       
    44 
       
    45 Response
       
    46 --------
       
    47 
       
    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.
       
    51 
       
    52 ``determine_charset()``:
       
    53     Is now available as ``res.charset``
       
    54 
       
    55 ``has_header(header)``:
       
    56     Should be done with ``header in res.headers``
       
    57 
       
    58 ``get_content()`` and ``wsgi_response()``:
       
    59     These are gone; you should use ``res.body`` or ``res(environ,
       
    60     start_response)``
       
    61 
       
    62 ``write(content)``:
       
    63     Available in ``res.body_file.write(content)``.
       
    64 
       
    65 ``flush()`` and ``tell()``:
       
    66     Not available.
       
    67 
       
    68 There are also many extra methods and attributes on WebOb Response
       
    69 objects.
       
    70 
       
    71 Django
       
    72 ======
       
    73 
       
    74 This is a quick summary from reading `the Django documentation
       
    75 <http://www.djangoproject.com/documentation/request_response/>`_.
       
    76 
       
    77 Request
       
    78 -------
       
    79 
       
    80 ``encoding``:
       
    81     Is ``req.charset``
       
    82 
       
    83 ``REQUEST``:
       
    84     Is ``req.params``
       
    85 
       
    86 ``FILES``:
       
    87     File uploads are ``cgi.FieldStorage`` objects directly in
       
    88     ``res.POST``
       
    89 
       
    90 ``META``:
       
    91     Is ``req.environ``
       
    92 
       
    93 ``user``:
       
    94     No equivalent (too connected to application model for WebOb).
       
    95     There is ``req.remote_user``, which is only ever a string.
       
    96 
       
    97 ``session``:
       
    98     No equivalent
       
    99 
       
   100 ``raw_post_data``:
       
   101     Available with ``req.body``
       
   102 
       
   103 ``__getitem__(key)``:
       
   104     You have to use ``req.params``
       
   105 
       
   106 ``is_secure()``:
       
   107     No equivalent; you could use ``req.scheme == 'https'``.
       
   108 
       
   109 QueryDict
       
   110 ---------
       
   111 
       
   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.
       
   115 
       
   116 Mutability:
       
   117     WebOb dictionaries are sometimes mutable (req.GET is,
       
   118     req.params is not)
       
   119 
       
   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.
       
   124 
       
   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')]``
       
   130 
       
   131 ``getlist(key)``:
       
   132     Available as ``d.getall(key)``
       
   133 
       
   134 ``setlist(key)``:
       
   135     No direct equivalent
       
   136 
       
   137 ``appendlist(key, value)``:
       
   138     Available as ``d.add(key, value)``
       
   139 
       
   140 ``setlistdefault(key, default_list)``:
       
   141     No direct equivalent
       
   142 
       
   143 ``lists()``:
       
   144     Is ``d.dict_of_lists()``
       
   145  
       
   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.
       
   151 
       
   152 Response
       
   153 --------
       
   154 
       
   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
       
   159 
       
   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.
       
   164 
       
   165 ``has_header(header)``:
       
   166     Use ``header in res.headers``
       
   167 
       
   168 ``write(content)``:
       
   169     As ``res.body_file.write(content)``
       
   170 
       
   171 ``flush()``, ``tell()``:
       
   172     Not available
       
   173 
       
   174 ``content``:
       
   175     Use ``res.body`` for the ``str`` value, ``res.unicode_body`` for
       
   176     the ``unicode`` value
       
   177 
       
   178 Response Subclasses
       
   179 -------------------
       
   180 
       
   181 These are generally like ``webob.exc`` objects.
       
   182 ``HttpResponseNotModified`` is ``HTTPNotModified``; this naming
       
   183 translation generally works.
       
   184 
       
   185 CherryPy/TurboGears
       
   186 ===================
       
   187 
       
   188 The `CherryPy request object
       
   189 <http://www.cherrypy.org/wiki/RequestObject>`_ is also used by
       
   190 TurboGears 1.x.
       
   191 
       
   192 Request
       
   193 -------
       
   194 
       
   195 ``app``:
       
   196     No equivalent
       
   197 
       
   198 ``base``:
       
   199     ``req.application_url``
       
   200 
       
   201 ``close()``:
       
   202     No equivalent
       
   203 
       
   204 ``closed``:
       
   205     No equivalent
       
   206 
       
   207 ``config``:
       
   208     No equivalent
       
   209 
       
   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)
       
   214 
       
   215 ``dispatch``:
       
   216     No equivalent (this is the object dispatcher in CherryPy).
       
   217 
       
   218 ``error_page``, ``error_response``, ``handle_error``:
       
   219     No equivalent
       
   220 
       
   221 ``get_resource()``:
       
   222     Similar to ``req.get_response(app)``
       
   223 
       
   224 ``handler``:
       
   225     No equivalent
       
   226 
       
   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).
       
   230 
       
   231 ``hooks``:
       
   232     No equivalent
       
   233 
       
   234 ``local``:
       
   235     No equivalent
       
   236 
       
   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.
       
   241 
       
   242 ``namespaces``:
       
   243     No equivalent
       
   244 
       
   245 ``protocol``:
       
   246     As ``req.environ['SERVER_PROTOCOL']``
       
   247 
       
   248 ``query_string``:
       
   249     As ``req.query_string``
       
   250 
       
   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')``
       
   255 
       
   256 ``request_line``:
       
   257     No equivalent
       
   258 
       
   259 ``respond()``:
       
   260     A method that is somewhat similar to ``req.get_response()``.
       
   261 
       
   262 ``rfile``:
       
   263     ``req.body_file``
       
   264 
       
   265 ``run``:
       
   266     No equivalent
       
   267 
       
   268 ``server_protocol``:
       
   269     As ``req.environ['SERVER_PROTOCOL']``
       
   270 
       
   271 ``show_tracebacks``:
       
   272     No equivalent
       
   273 
       
   274 ``throw_errors``:
       
   275     No equivalent
       
   276 
       
   277 ``throws``:
       
   278     No equivalent
       
   279 
       
   280 ``toolmaps``:
       
   281     No equivalent
       
   282 
       
   283 ``wsgi_environ``:
       
   284     As ``req.environ``
       
   285 
       
   286 Response
       
   287 --------
       
   288 
       
   289 From information `from the wiki
       
   290 <http://www.cherrypy.org/wiki/ResponseObject>`_.
       
   291 
       
   292 ``body``:
       
   293     This is an iterable in CherryPy, a string in WebOb;
       
   294     ``res.app_iter`` gives an iterable in WebOb.
       
   295 
       
   296 ``check_timeout``:
       
   297     No equivalent
       
   298 
       
   299 ``collapse_body()``:
       
   300     This turns a stream/iterator body into a single string.  Accessing
       
   301     ``res.body`` will do this automatically.
       
   302 
       
   303 ``cookie``:
       
   304     Accessible through ``res.set_cookie(...)``, ``res.delete_cookie``,
       
   305     ``res.unset_cookie()``
       
   306 
       
   307 ``finalize()``:
       
   308     No equivalent
       
   309 
       
   310 ``header_list``:
       
   311     In ``res.headerlist``
       
   312 
       
   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.
       
   317 
       
   318 ``time``:
       
   319     No equivalent
       
   320 
       
   321 ``timed_out``:
       
   322     No equivalent
       
   323 
       
   324 Yaro
       
   325 ====
       
   326 
       
   327 `Yaro <http://lukearno.com/projects/yaro/>`_ is a small wrapper around
       
   328 the WSGI environment, much like WebOb in scope.
       
   329 
       
   330 The WebOb objects have many more methods and attributes.  The Yaro
       
   331 Response object is a much smaller subset of WebOb's Response.
       
   332 
       
   333 Request
       
   334 -------
       
   335 
       
   336 ``query``:
       
   337     As ``req.GET``
       
   338 
       
   339 ``form``:
       
   340     As ``req.POST``
       
   341 
       
   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)
       
   346 
       
   347 ``uri``:
       
   348     Returns a URI object, no equivalent (only string URIs available).
       
   349 
       
   350 ``redirect``:
       
   351     Not available (response-related).  ``webob.exc.HTTPFound()`` can
       
   352     be useful here.
       
   353 
       
   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.
       
   359 
       
   360 ``res``:
       
   361     The request object in WebOb *may* have a ``req.response``
       
   362     attribute.
       
   363 
       
   364 Werkzeug
       
   365 ========
       
   366 
       
   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.
       
   371 
       
   372 This is take from the `wrapper documentation
       
   373 <http://werkzeug.pocoo.org/documentation/wrappers>`_.
       
   374 
       
   375 Request
       
   376 -------
       
   377 
       
   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``
       
   390 
       
   391 Response
       
   392 --------
       
   393 
       
   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)``
       
   402 
       
   403 Zope 3
       
   404 ======
       
   405 
       
   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>`_.
       
   410 
       
   411 Request
       
   412 -------
       
   413 
       
   414 ``locale``, ``setupLocale()``:
       
   415     This is not fully calculated, but information is available in
       
   416     ``req.accept_languages``.
       
   417 
       
   418 ``principal``, ``setPrincipal(principal)``:
       
   419     ``req.remote_user`` gives the username, but there is no standard
       
   420     place for a user *object*.
       
   421 
       
   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.
       
   425 
       
   426 ``traverse(object)``, ``getTraversalStack()``, ``setTraversalStack()``:
       
   427     These all relate to traversal, which is part of the publishing
       
   428     system.
       
   429 
       
   430 ``processInputs()``, ``setPathSuffix(steps)``:
       
   431     Also associated with traversal and preparing the request.
       
   432 
       
   433 ``environment``:
       
   434     In ``req.environ``
       
   435 
       
   436 ``bodyStream``:
       
   437     In ``req.body_file``
       
   438 
       
   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.
       
   443 
       
   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']``.
       
   449 
       
   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()``.
       
   459 
       
   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``?
       
   464 
       
   465 ``retry()``, ``supportsRetry()``:
       
   466     Creates a new request that can be used to retry a request.
       
   467     Similar to ``req.copy()``.
       
   468 
       
   469 ``close()``, ``hold(obj)``: 
       
   470     This closes resources associated with the request, including any
       
   471     "held" objects.  There's nothing similar.
       
   472 
       
   473 Response
       
   474 --------
       
   475 
       
   476 ``authUser``:
       
   477     Not sure what this is or does.
       
   478 
       
   479 ``reset()``:
       
   480     No direct equivalent; you'd have to do ``res.headers = [];
       
   481     res.body = ''; res.status = 200``
       
   482 
       
   483 ``setCookie(name, value, **kw)``:
       
   484     Is ``res.set_cookie(...)``.
       
   485 
       
   486 ``getCookie(name)``:
       
   487     No equivalent.  Hm.
       
   488 
       
   489 ``expireCookie(name)``:
       
   490     Is ``res.delete_cookie(name)``.
       
   491 
       
   492 ``appendToCookie(name, value)``:
       
   493     This appends the value to any existing cookie (separating values
       
   494     with a colon).  WebOb does not do this.
       
   495 
       
   496 ``setStatus(status)``:
       
   497     Availble by setting ``res.status`` (can be set to an integer or a
       
   498     string of "code reason").
       
   499 
       
   500 ``getHeader(name, default=None)``:
       
   501     Is ``res.headers.get(name)``.
       
   502 
       
   503 ``getStatus()``:
       
   504     Is ``res.status_int`` (or ``res.status`` to include reason)
       
   505 
       
   506 ``addHeader(name, value)``:
       
   507     Is ``res.headers.add(name, value)`` (in Zope and WebOb, this does
       
   508     not clobber any previous value).
       
   509 
       
   510 ``getHeaders()``:
       
   511     Is ``res.headerlist``.
       
   512 
       
   513 ``setHeader(name, value)``:
       
   514     Is ``res.headers[name] = value``.
       
   515 
       
   516 ``getStatusString()``:
       
   517     Is ``res.status``.
       
   518 
       
   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``).
       
   523 
       
   524 ``internalError()``:
       
   525     This is available with ``webob.exc.HTTP*()``.
       
   526 
       
   527 ``handleException(exc_info)``:
       
   528     This is provided with a tool like ``paste.exceptions``.
       
   529 
       
   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.
       
   536 
       
   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.
       
   543 
       
   544     Like in Zope, WebOb updates Content-Length.  Unlike Zope, it does
       
   545     not automatically calculate a charset.
       
   546 
       
   547 
       
   548 mod_python
       
   549 ==========
       
   550 
       
   551 Some key attributes from the `mod_python
       
   552 <http://modpython.org/live/current/doc-html/pyapi-mprequest-mem.html>`_ 
       
   553 request object.
       
   554 
       
   555 Request
       
   556 -------
       
   557 
       
   558 ``req.uri``:
       
   559     In ``req.path``.
       
   560    
       
   561 ``req.user``:
       
   562     In ``req.remote_user``.
       
   563 
       
   564 ``req.get_remote_host()``:
       
   565     In ``req.environ['REMOTE_ADDR']`` or ``req.remote_addr``.
       
   566 
       
   567 ``req.headers_in.get('referer')``:
       
   568     In ``req.headers.get('referer')`` or ``req.referer`` (same pattern
       
   569     for other request headers, presumably).
       
   570 
       
   571 Response
       
   572 --------
       
   573 
       
   574 ``util.redirect`` or ``req.status = apache.HTTP_MOVED_TEMPORARILY``:
       
   575 
       
   576 .. code-block::
       
   577 
       
   578     from webob.exc import HTTPMovedTemporarily()
       
   579     exc = HTTPMovedTemporarily(location=url)
       
   580     return exc(environ, start_response)
       
   581 
       
   582 ``req.content_type = "application/x-csv"`` and 
       
   583 ``req.headers_out.add('Content-Disposition', 'attachment;filename=somefile.csv'):
       
   584 
       
   585 .. code-block::
       
   586 
       
   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)