|
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) |