Changelog for Falcon 3.0.0

Changes to Supported Platforms

  • Python 3.8 and 3.9 are now fully supported.

  • Python 3.6+ is only required when using the new ASGI interface. WSGI is still supported on Python 3.5+.

  • Python 3.5 support is deprecated and may be removed in the next major release.

  • Python 3.4 is no longer supported.

  • The Falcon 2.x series was the last to support Python language version 2. As a result, support for CPython 2.7 and PyPy2.7 was removed in Falcon 3.0.

Breaking Changes

  • The class OptionalRepresentation and the attribute has_representation were deprecated. The default error serializer now generates a representation for every error type that derives from falcon.HTTPError. In addition, Falcon now ensures that any previously set response body is cleared before handling any raised exception. (#452)

  • The class NoRepresentation was deprecated. All subclasses of falcon.HTTPError now have a media type representation. (#777)

  • In order to reconcile differences between the framework’s support for WSGI vs. ASGI, the following breaking changes were made:

    • falcon.testing.create_environ() previously set a default User-Agent header, when one was not provided, to the value 'curl/7.24.0 (x86_64-apple-darwin12.0)'. As of Falcon 3.0, the default User-Agent string is now f'falcon-client/{falcon.__version__}'. This value can be overridden for the sake of backwards-compatibility by setting falcon.testing.helpers.DEFAULT_UA.

    • The falcon.testing.create_environ() function’s protocol keyword argument was renamed to http_version and now only includes the version number (the value is no longer prefixed with 'HTTP/').

    • The falcon.testing.create_environ() function’s app keyword argument was renamed to root_path.

    • The writeable property of BoundedStream was renamed to writable per the standard file-like I/O interface (the old name was a misspelling)

    • If an error handler raises an exception type other than falcon.HTTPStatus or falcon.HTTPError, remaining middleware process_response methods will no longer be executed before bubbling up the unhandled exception to the web server.

    • falcon.get_http_status() no longer accepts floats, and the method itself is deprecated.

    • falcon.api_helpers.prepare_middleware() no longer accepts a single object; the value that is passed must be an iterable.

    • falcon.Request.access_route now includes the value of the remote_addr property as the last element in the route, if not already present in one of the headers that are checked.

    • When the 'REMOTE_ADDR' field is not present in the WSGI environ, Falcon will assume '127.0.0.1' for the value, rather than simply returning None for falcon.Request.remote_addr.

    The changes above were implemented as part of the ASGI+HTTP work stream. (#1358)

  • Header-related methods of the Response class no longer coerce the passed header name to a string via str(). (#1497)

  • An unhandled exception will no longer be raised to the web server. Rather, the framework now installs a default error handler for the Exception type. This also means that middleware process_response methods will still be called in this case, rather than being skipped as previously. The new default error handler simply generates an HTTP 500 response. This behavior can be overridden by specifying your own error handler for Exception via add_error_handler(). (#1507)

  • Exceptions are now handled by the registered handler for the most specific matching exception class, rather than in reverse order of registration. “Specificity” is determined by the method resolution order of the raised exception type. (See add_error_handler() for more details.) (#1514)

  • The deprecated stream_len property was removed from the Response class. Please use set_stream() or content_length instead. (#1517)

  • If RequestOptions.strip_url_path_trailing_slash is enabled, routes should now be added without a trailing slash. Previously, the trailing slash was always removed as a side effect of a bug regardless of the strip_url_path_trailing_slash option value. See also: How does Falcon handle a trailing slash in the request path? (#1544)

  • Rename Response.body and HTTPStatus.body to text. The old name is deprecated, but still available. (#1578)

  • Referencing the class falcon.stream.BoundedStream through the falcon.request_helpers module is deprecated. It is now accessible from the module falcon.stream. (#1583)

  • General refactoring of internal media handler:

    • Deserializing an empty body with a handler that does not support it will raise falcon.MediaNotFoundError, and will be rendered as a 400 Bad Request response. This error may be suppressed by passing a default value to get_media to be used in case of empty body. See also Request.get_media() for details. Previously None was returned in all cases without calling the handler.

    • Exceptions raised by the handlers are wrapped as falcon.MediaMalformedError, and will be rendered as a 400 Bad Request response.

    • Subsequent calls to Request.get_media() or Request.media will re-raise the same exception, if the first call ended in an error, unless the exception was a falcon.MediaNotFoundError and a default value is passed to the default_when_empty attribute of the current invocation. Previously None was returned.

    External handlers should update their logic to align to the internal Falcon handlers. (#1589)

  • The falcon.Response.data property now just simply returns the same data object that it was set to, if any, rather than also checking and serializing the value of the falcon.Response.media property. Instead, a new render_body() method has been implemented, which can be used to obtain the HTTP response body for the request, taking into account the text, data, and media attributes. (#1679)

  • The params_csv parameter now defaults to False in falcon.testing.simulate_request(). The change was made to match the default value of the request option auto_parse_qs_csv (False since Falcon 2.0). (#1730)

  • The falcon.HTTPError.to_json() now returns bytes instead of str. Importing json from falcon.util is deprecated. (#1767)

New & Improved

Fixed

  • Previously, the default CompiledRouter was erroneously stripping trailing slashes from URI templates. This has been fixed so that it is now possible to add two different routes for a path with and without a trailing forward slash (see also: RequestOptions.strip_url_path_trailing_slash). (#1544)

  • falcon.uri.decode() and falcon.uri.parse_query_string() no longer explode quadratically for a large number of percent-encoded characters. The time complexity of these utility functions is now always close to O(n). (#1594)

  • When auto_parse_qs_csv is enabled, the framework now correctly parses all occurrences of the same parameter in the query string, rather than only splitting the values in the first occurrence. For example, whereas previously t=1,2&t=3,4 would become ['1', '2', '3,4'], now the resulting list will be ['1', '2', '3', '4'] (#1597)

  • The parse_query_string() utility function is now correctly parsing an empty string as {}. (#1600)

  • Previously, response serialization errors (such as in the case of a faulty custom media handler, or because an instance of HTTPUnsupportedMediaType was raised for an unsupported response content type) were unexpectedly bubbled up to the application server. This has been fixed, and these errors are now handled exactly the same way as other exceptions raised in a responder (see also: Error Handling). (#1607)

  • falcon.Request.forwarded_host now contains the port when proxy headers are not set, to make it possible to correctly reconstruct the URL when the application is not behind a proxy. (#1678)

  • The Response.downloadable_as property is now correctly encoding non-ASCII filenames as per RFC 6266 recommendations. (#1749)

  • The falcon.routing.CompiledRouter no longer mistakenly sets route parameters while exploring non matching routes. (#1779)

Misc

  • Deprecate the use of positional arguments for the optional kw args of the HTTPError subclasses (#777)

  • Setup towncrier to make CHANGES reporting much easier. (#1461)

  • Fix test errors on Windows (#1656)

  • A new method, get_media(), was added that can now be used instead of the falcon.Request.media property to make it more clear to app maintainers that getting the media object for a request involves a side-effect of consuming and deserializing the body stream. The original property remains available to ensure backwards-compatibility with existing apps. (#1679)

  • Falcon now uses the falcon.Response media handlers when serializing to JSON falcon.HTTPError and falcon.asgi.SSEvent. falcon.Request will use its defined media handler when loading a param as JSON with falcon.Request.get_param_as_json(). (#1767)

  • The add_link() method of the falcon.Request class was renamed to falcon.Request.append_link(). The old name is still available as a deprecated alias. (#1801)

Contributors to this Release

Many thanks to all of our talented and stylish contributors for this release!

Note

If we missed you below, don’t worry! We will capture the full list of contributors before the 3.0.0 final release.