News

1.1.1

  • Fix disconnect detection being incorrect in some cases (issue 21)
  • Fix exception when calling .accept.best_match(..) on a header containing ‘*’ (instead of ‘/‘)
  • Split Accept class into appropriate subclasses (AcceptCharset, AcceptLanguage)
  • Improve language matching code so that 'en' in AcceptLanguage('en-gb') (the app can now offer a generic ‘en’ and it will match any of the accepted dialects) and 'en_GB' in AcceptLanguage('en-gb') (normalization of the dash/underscode in language names).
  • Deprecate req.etag.weak_match(..)
  • Deprecate Response.request and Response.environ attrs.

1.1

  • Remove deprecation warnings for unicode_body and ubody.

1.1rc1

  • Deprecate Response.ubody / .unicode_body in favor of new .text attribute (the old names will be removed in 1.3 or even later).
  • Make Response.write much more efficient (issue 18)
  • Make sure copying responses does not reset Content-Length or Content-MD5 of the original (and that of future copies).
  • Change del res.body semantics so that it doesn’t make the response invalid, but only removes the response body.
  • Remove Response._body so the _app_iter is the only representation.

1.1b2

  • Add detection for browser / user-agent disconnects. If the client disconnected before sending the entire request body (POST / PUT), req.POST, req.body and other related properties and methods will raise an exception. Previously this caused the application get a truncated request with no indication that it is incomplete.
  • Make Response.body_file settable. This is now valid: Response(body_file=open('foo.bin'), content_type=...)
  • Revert the restriction on req.body not being settable for GET and some other requests. Such requests actually can have a body according to HTTP BIS (see also commit message)
  • Add support for file upload testing via Request.blank(POST=..). Patch contributed by Tim Perevezentsev. See also: ticket, changeset.
  • Deprecate req.str_GET, str_POST, str_params and str_cookies (warning).
  • Deprecate req.decode_param_names (warning).
  • Change req.decode_param_names default to True. This means that .POST, .GET, .params and .cookies keys are now unicode. This is necessary for WebOb to behave as close as possible on Python 2 and Python 3.

1.1b1

  • We have acquired the webob.org domain, docs are now hosted at docs.webob.org
  • Make accept.quality(..) return best match quality, not first match quality.
  • Fix Range.satisfiable(..) edge cases.
  • Make sure WSGIHTTPException instances return the same headers for HEAD and GET requests.
  • Drop Python 2.4 support
  • Deprecate HTTPException.exception (warning on use).
  • Deprecate accept.first_match(..) (warning on use). Use .best_match(..) instead.
  • Complete deprecation of req.[str_]{post|query}vars properties (exception on use).
  • Remove FakeCGIBody.seek hack (no longer necessary).

1.0.8

  • Escape commas in cookie values (see also: stdlib Cookie bug)
  • Change cookie serialization to more closely match how cookies usually are serialized (unquoted expires, semicolon separators even between morsels)
  • Fix some rare cases in cookie parsing
  • Enhance the req.is_body_readable to always guess GET, HEAD, DELETE and TRACE as unreadable and PUT and POST as readable (issue 12)
  • Deny setting req.body or req.body_file to non-empty values for GET, HEAD and other bodiless requests
  • Fix running nosetests with arguments on UNIX systems (issue 11)

1.0.7

  • Fix Accept header matching for items with zero-quality (issue 10)
  • Hide password values in MultiDict.__repr__

1.0.6

  • Use environ['wsgi.input'].read() instead of .read(-1) because the former is explicitly mentioned in PEP-3333 and CherryPy server does not support the latter.
  • Add new environ['webob.is_body_readable'] flag which specifies if the input stream is readable even if the CONTENT_LENGTH is not set. WebOb now only ever reads the input stream if the content-length is known or this flag is set.
  • The two changes above fix a hangup with CherryPy and wsgiref servers (issue 6)
  • req.body_file is now safer to read directly. For GET and other similar requests it returns an empty StringIO or BytesIO object even if the server passed in something else.
  • Setting req.body_file to a string now produces a PendingDeprecationWarning. It will produce DeprecationWarning in 1.1 and raise an error in 1.2. Either set req.body_file to a file-like object or set req.body to a string value.
  • Fix .pop() and .setdefault(..) methods of req/resp.cache_control
  • Thanks to the participants of Pyramid sprint at the PyCon US 2011 WebOb now has 100% test coverage.

1.0.5

  • Restore Python 2.4 compatibility.

1.0.4

  • The field names escaping bug semi-fixed in 1.0.3 and originally blamed on cgi module was in fact a webob.request._encode_multipart bug (also in Google Chrome) and was lurking in webob code for quite some time – 1.0.2 just made it trigger more often. Now it is fixed properly.
  • Make sure that req.url and related properties do not unnecessarily escape some chars (:@&+$) in the URI path (issue 5)
  • Revert some changes from 1.0.3 that have broken backwards compatibility for some apps. Getting req.body_file does not make input stream seekable, but there’s a new property req.body_file_seekable that does.
  • Request.get_response and Request.call_application seek the input body to start before calling the app (if possible).
  • Accessing req.body ‘rewinds’ the input stream back to pos 0 as well.
  • When accessing req.POST we now avoid making the body seekable as the input stream data are preserved in FakeCGIBody anyway.
  • Add new method Request.from_string.
  • Make sure Request.as_string() uses CRLF to separate headers.
  • Improve parity between Request.as_string() and .from_file/.from_string methods, so that the latter can parse output of the former and create a similar request object which wasn’t always the case previously.

1.0.3

  • Correct a caching issue introduced in WebOb 1.0.2 that was causing unnecessary reparsing of POST requests.
  • Fix a bug regarding field names escaping for forms submitted as multipart/form-data. For more infromation see the bug report and discussion and 1.0.4 notes for further fix.
  • Add req.http_version attribute.

1.0.2

  • Primary maintainer is now Sergey Schetinin.
  • Issue tracker moved from Trac to bitbucket’s issue tracker
  • WebOb 1.0.1 changed the behavior of MultiDict.update to be more in line with other dict-like objects. We now also issue a warning when we detect that the client code seems to expect the old, extending semantics.
  • Make Response.set_cookie(key, None) set the ‘delete-cookie’ (same as .delete_cookie(key))
  • Make req.upath_info and req.uscript_name settable
  • Add :meth:Request.as_string() method
  • Add a req.is_body_seekable property
  • Support for the deflate method with resp.decode_content()
  • To better conform to WSGI spec we no longer attempt to use seek on wsgi.input file instead we assume it is not seekable unless env['webob.is_body_seekable'] is set. When making the body seekable we set that flag.
  • A call to req.make_body_seekable() now guarantees that the body is seekable, is at 0 position and that a correct req.content_length is present.
  • req.body_file is always seekable. To access env['wsgi.input'] without any processing, use req.body_file_raw. (Partially reverted in 1.0.4)
  • Fix responses to HEAD requests with Range.
  • Fix del resp.content_type, del req.body, del req.cache_control
  • Fix resp.merge_cookies() when called with an argument that is not a Response instance.
  • Fix resp.content_body = None (was removing Cache-Control instead)
  • Fix req.body_file = f setting CONTENT_LENGTH to -1 (now removes from environ)
  • Fix: make sure req.copy() leaves the original with seekable body
  • Fix handling of WSGI environs with missing SCRIPT_NAME
  • A lot of tests were added by Mariano Mara and Danny Navarro.

1.0.1

  • As WebOb requires Python 2.4 or later, drop some compatibility modules and update the code to use the decorator syntax.
  • Implement optional on-the-fly response compression (resp.encode_content(lazy=True))
  • Drop util.safezip module and make util a module instead of a subpackage. Merge statusreasons into it.
  • Instead of using stdlib Cookie with monkeypatching, add a derived but thoroughly rewritten, cleaner, safer and faster webob.cookies module.
  • Fix: Response.merge_cookies now copies the headers before modification instead of doing it in-place.
  • Fix: setting request header attribute to None deletes that header. (Bug only affected the 1.0 release).
  • Use io.BytesIO for the request body file on Python 2.7 and newer.
  • If a UnicodeMultiDict was used as the multi argument of another UnicodeMultiDict, and a cgi.FieldStorage with a filename with high-order characters was present in the underlying UnicodeMultiDict, a UnicodeEncodeError would be raised when any helper method caused the _decode_value method to be called, because the method would try to decode an already decoded string.
  • Fix tests to pass under Python 2.4.
  • Add descriptive docstrings to each exception in webob.exc.
  • Change the behaviour of MultiDict.update to overwrite existing header values instead of adding new headers. The extending semantics are now available via the extend method.
  • Fix a bug in webob.exc.WSGIHTTPException.__init__. If a list of headers was passed as a sequence which contained duplicate keys (for example, multiple Set-Cookie headers), all but one of those headers would be lost, because the list was effectively flattened into a dictionary as the result of calling self.headers.update. Fixed via calling self.headers.extend instead.

1.0

  • 1.0, yay!
  • Pull in werkzeug Cookie fix for malformed cookie bug.
  • Implement Request.from_file() and Response.from_file() which are kind of the inversion of str(req) and str(resp)
  • Add optional pattern argument to Request.path_info_pop() that requires the path_info segment to match the passed regexp to get popped and returned.
  • Rewrite most of descriptor implementations for speed.
  • Reorder descriptor declarations to group them by their semantics.
  • Move code around so that there are fewer compat modules.
  • Change :meth:HTTPError.__str__ to better conform to PEP 352.
  • Make Request.cache_control a view on the headers.
  • Correct Accept-Language and Accept-Charset matching to fully conform to the HTTP spec.
  • Expose parts of Request.blank() as environ_from_url() and environ_add_POST()
  • Fix Authorization header parsing for some corner cases.
  • Fix an error generated if the user-agent sends a ‘Content_Length’ header (note the underscore).
  • Kill Request.default_charset. Request charset defaults to UTF-8. This ensures that all values in req.GET, req.POST and req.params are always unicode.
  • Fix the headerlist and content_type constructor arguments priorities for HTTPError and subclasses.
  • Add support for weak etags to conditional Response objects.
  • Fix locale-dependence for some cookie dates strings.
  • Improve overall test coverage.
  • Rename class webob.datastruct.EnvironHeaders to webob.headers.EnvironHeaders
  • Rename class webob.headerdict.HeaderDict to webob.headers.ResponseHeaders
  • Rename class webob.updatedict.UpdateDict to webob.cachecontrol.UpdateDict

0.9.8

  • Fix issue with WSGIHTTPException inadvertently generating unicode body and failing to encode it
  • WWW-Authenticate response header is accessible as response.www_authenticate
  • response.www_authenticate and request.authorization hold None or tuple (auth_method, params) where params is a dictionary (or a string when auth_method is not one of known auth schemes and for Authenticate: Basic ...)
  • Don’t share response headers when getting a response like resp = req.get_response(some_app); this can avoid some funny errors with modifying headers and reusing Response objects.
  • Add overwrite argument to Response.set_cookie() that make the new value overwrite the previously set. False by default.
  • Add strict argument to Response.unset_cookie() that controls if an exception should be raised in case there are no cookies to unset. True by default.
  • Fix req.GET.copy()
  • Make sure that 304 Not Modified responses generated by Response.conditional_response_app() exclude Content-{Length/Type} headers
  • Fix Response.copy() not being an independent copy
  • When the requested range is not satisfiable, return a 416 error (was returning entire body)
  • Truncate response for range requests that go beyond the end of body (was treating as invalid).

0.9.7.1

  • Fix an import problem with Pylons

0.9.7

  • Moved repository from svn location to http://bitbucket.org/ianb/webob/
  • Arguments to Accept.best_match() must be specific types, not wildcards. The server should know a list of specic types it can offer and use best_match to select a specific one.
  • With req.accept.best_match([types]) prefer the first type in the list (previously it preferred later types).
  • Also, make sure that if the user-agent accepts multiple types and there are multiple matches to the types that the application offers, req.accept.best_match([..]) returns the most specific match. So if the server can satisfy either image/* or text/plain types, the latter will be picked independent from the order the accepted or offered types are listed (given they have the same quality rating).
  • Fix Range, Content-Range and AppIter support all of which were broken in many ways, incorrectly parsing ranges, reporting incorrect content-ranges, failing to generate the correct body to satisfy the range from app_iter etc.
  • Fix assumption that presense of a seek method means that the stream is seekable.
  • Add ubody alias for Response.unicode_body
  • Add Unicode versions of Request.script_name and path_info: uscript_name and upath_info.
  • Split __init__.py into four modules: request, response, descriptors and datetime_utils.
  • Fix Response.body access resetting Content-Length to zero for HEAD responses.
  • Support passing Unicode bodies to WSGIHTTPException constructors.
  • Make bool(req.accept) return False for requests with missing Accept header.
  • Add HTTP version to Request.__str__() output.
  • Resolve deprecation warnings for parse_qsl on Python 2.6 and newer.
  • Fix Response.md5_etag() setting Content-MD5 in incorrect format.
  • Add Request.authorization property for Authorization header.
  • Make sure ETag value is always quoted (required by RFC)
  • Moved most Request behavior into a new class named BaseRequest. The Request class is now a superclass for BaseRequest and a simple mixin which manages environ['webob.adhoc_attrs'] when __setitem__, __delitem__ and __getitem__ are called. This allows framework developers who do not want the environ['webob.adhoc_attrs'] mutation behavior from __setattr__. (chrism)
  • Added response attribute response.content_disposition for its associated header.
  • Changed how charset is determined on webob.Request objects. Now the charset parameter is read on the Content-Type header, if it is present. Otherwise a default_charset parameter is read, or the charset argument to the Request constructor. This is more similar to how webob.Response handles the charset.
  • Made the case of the Content-Type header consistent (note: this might break some doctests).
  • Make req.GET settable, such that req.environ['QUERY_STRING'] is updated.
  • Fix problem with req.POST causing a re-parse of the body when you instantiate multiple Request objects over the same environ (e.g., when using middleware that looks at req.POST).
  • Recreate the request body properly when a POST includes file uploads.
  • When req.POST is updated, the generated body will include the new values.
  • Added a POST parameter to webob.Request.blank(); when given this will create a request body for the POST parameters (list of two-tuples or dictionary-like object). Note: this does not handle unicode or file uploads.
  • Added method webob.Response.merge_cookies(), which takes the Set-Cookie headers from a Response, and merges them with another response or WSGI application. (This is useful for flash messages.)
  • Fix a problem with creating exceptions like webob.exc.HTTPNotFound(body='<notfound/>', content_type='application/xml') (i.e., non-HTML exceptions).
  • When a Location header is not absolute in a Response, it will be made absolute when the Response is called as a WSGI application. This makes the response less bound to a specific request.
  • Added webob.dec, a decorator for making WSGI applications from functions with the signature resp = app(req).

0.9.6.1

  • Fixed Response.__init__(), which for some content types would raise an exception.
  • The req.body property will not recreate a StringIO object unnecessarily when rereading the body.

0.9.6

  • Removed environ_getter from webob.Request. This largely-unused option allowed a Request object to be instantiated with a dynamic underlying environ. Since it wasn’t used much, and might have been ill-advised from the beginning, and affected performance, it has been removed (from Chris McDonough).
  • Speed ups for webob.Response.__init__() and webob.Request.__init__()
  • Fix defaulting of CONTENT_TYPE instead of CONTENT_LENGTH to 0 in Request.str_POST.
  • Added webob.Response.copy()

0.9.5

  • Fix Request.blank('/').copy() raising an exception.
  • Fix a potential memory leak with HEAD requests and 304 responses.
  • Make webob.html_escape() respect the .__html__() magic method, which allows you to use HTML in :class`webob.exc.HTTPException` instances.
  • Handle unicode values for resp.location.
  • Allow arbitrary keyword arguments to exc.HTTP* (the same keywords you can send to webob.Response).
  • Allow setting webob.Response.cache_expires() (usually it is called as a method). This is primarily to allow Response(cache_expires=True).

0.9.4

  • Quiet Python 2.6 deprecation warnings.
  • Added an attribute unicode_errors to webob.Response – if set to something like unicode_errors='replace' it will decode resp.body appropriately. The default is strict (which was the former un-overridable behavior).

0.9.3

  • Make sure that if changing the body the Content-MD5 header is removed. (Otherwise a lot of middleware would accidentally corrupt responses).
  • Fixed Response.encode_content('identity') case (was a no-op even for encoded bodies).
  • Fixed Request.remove_conditional_headers() that was removing If-Match header instead of If-None-Match.
  • Fixed resp.set_cookie(max_age=timedelta(...))
  • request.POST now supports PUT requests with the appropriate Content-Type.

0.9.2

  • Add more arguments to Request.remove_conditional_headers() for more fine-grained control: remove_encoding, remove_range, remove_match, remove_modified. All of them are True by default.
  • Add an set_content_md5 argument to Response.md5_etag() that calculates and sets Content-MD5 reponse header from current body.
  • Change formatting of cookie expires, to use the more traditional format Wed, 5-May-2001 15:34:10 GMT (dashes instead of spaces). Browsers should deal with either format, but some other code expects dashes.
  • Added in sorted function for backward compatibility with Python 2.3.
  • Allow keyword arguments to webob.Request, which assign attributes (possibly overwriting values in the environment).
  • Added methods webob.Request.make_body_seekable() and webob.Request.copy_body(), which make it easier to share a request body among different consuming applications, doing something like req.make_body_seekable(); req.body_file.seek(0)

0.9.1

  • request.params.copy() now returns a writable MultiDict (before it returned an unwritable object).
  • There were several things broken with UnicodeMultiDict when decode_param_names is turned on (when the dictionary keys are unicode).
  • You can pass keyword arguments to Request.blank() that will be used to construct Request (e.g., Request.blank('/', decode_param_names=True)).
  • If you set headers like response.etag to a unicode value, they will be encoded as ISO-8859-1 (however, they will remain encoded, and response.etag will not be a unicode value).
  • When parsing, interpret times with no timezone as UTC (previously they would be interpreted as local time).
  • Set the Expires property on cookies when using response.set_cookie(). This is inherited from max_age.
  • Support Unicode cookie values

0.9

  • Added req.urlarg, which represents positional arguments in environ['wsgiorg.routing_args'].
  • For Python 2.4, added attribute get/set proxies on exception objects from, for example, webob.exc.HTTPNotFound().exception, so that they act more like normal response objects (despite not being new-style classes or webob.Response objects). In Python 2.5 the exceptions are webob.Response objects.

Backward Incompatible Changes

  • The Response constructor has changed: it is now Response([body], [status], ...) (before it was Response([status], [body], ...)). Body may be str or unicode.
  • The Response class defaults to text/html for the Content-Type, and utf8 for the charset (charset is only set on text/* and application/*+xml responses).

Bugfixes and Small Changes

  • Use BaseCookie instead of SimpleCookie for parsing cookies.
  • Added resp.write(text) method, which is equivalent to resp.body += text or resp.unicode_body += text, depending on the type of text.
  • The decode_param_names argument (used like Request(decode_param_names=True)) was being ignored.
  • Unicode decoding of file uploads and file upload filenames were causing errors when decoding non-file-upload fields (both fixes from Ryan Barrett).

0.8.5

  • Added response methods resp.encode_content() and resp.decode_content() to gzip or ungzip content.
  • Response(status=404) now works (before you would have to use status="404 Not Found").
  • Bugfix (typo) with reusing POST body.
  • Added 226 IM Used response status.
  • Backport of string.Template included for Python 2.3 compatibility.

0.8.4

  • __setattr__ would keep Request subclasses from having properly settable environ proxies (like req.path_info).

0.8.3

  • request.POST was giving FieldStorage objects for every attribute, not just file uploads. This is fixed now.
  • Added request attributes req.server_name and req.server_port for the environ keys SERVER_NAME and SERVER_PORT.
  • Avoid exceptions in req.content_length, even if environ['CONTENT_LENGTH'] is somehow invalid.

0.8.2

  • Python 2.3 compatibility: backport of reversed(seq)
  • Made separate .exception attribute on webob.exc objects, since new-style classes can’t be raised as exceptions.
  • Deprecate req.postvars and req.queryvars, instead using the sole names req.GET and req.POST (also req.str_GET and req.str_POST). The old names give a warning; will give an error in next release, and be completely gone in the following release.
  • req.user_agent is now just a simple string (parsing the User-Agent header was just too volatile, and required too much knowledge about current browsers). Similarly, req.referer_search_query() is gone.
  • Added parameters version and comment to Response.set_cookie(), per William Dode’s suggestion.
  • Was accidentally consuming file uploads, instead of putting the FieldStorage object directly in the parameters.

0.8.1

  • Added res.set_cookie(..., httponly=True) to set the HttpOnly attribute on the cookie, which keeps Javascript from reading the cookie.
  • Added some WebDAV-related responses to webob.exc
  • Set default Last-Modified when using response.cache_expire() (fixes issue with Opera)
  • Generally fix .cache_control

0.8

First release. Nothing is new, or everything is new, depending on how you think about it.