The API Reference

This part of the documentation covers wask’s Python interfaces.

Adapters

These classes are for adapting webapp2 code to run on flask.

class wask.adapters.WaskApp[source]

Adapter for writting code that expects access to the active webapp2.WSGIApplication instance and makes it work with flask.current_app.

flask.current_app is a proxy to the application handling the current request. It is only available during requests.

See the following documentation for more details:

https://flask.palletsprojects.com/en/1.1.x/api/#flask.current_app https://flask.palletsprojects.com/en/1.1.x/appcontext/

class wask.adapters.WaskMethodView(*args, **kwargs)[source]

Adapter for writing webapp2 request handlers that work with flask.

Methods not implemented:

error: Not used anywhere in mainapp. url_for: Not used anywhere in mainapp.

Differences between flask and webapp2 that influence how this class is implemented and how it should be used:

Flask: - By default, the allowed methods for a request where the handler is an instance

of MethodView is determined as follows:
  • Any HTTP method functions (e.g. get, post, etc.) defined for a MethodView subclass.

  • If no method functions are defined, “GET” is included by default.

  • “HEAD” is automatically added if get is present. MethodView calls get if request.method == “HEAD” and there’s no head method.

  • “OPTIONS” is added and handled by flask automatically.

  • The above rules mean allowed methods will always include “OPTIONS”, and will always include “HEAD” if the handler has a get method.

  • If a request method is not in the allowed methods, flask won’t dispatch the request to the handler and automatically responds with a 405 status code and populates the “Allow” HTTP header with the allowed methods.

  • For reference, see:

    https://flask.palletsprojects.com/en/1.1.x/quickstart/#http-methods

Webapp2: - By default, webapp2 allows all HTTP methods (except for “PATCH”), and thus

dispatches requests with (almost) any HTTP method to a handler.

  • It’s up to the handler to call the right function to handle the request method (e.g. with getattr(self, method_name)) or respond with a 405 status code if it can’t handle the request method.

  • RequestHandler sets the “Allow” header on 405 responses to the list of HTTP method functions implemented by the class (e.g. get, post, etc.).

  • Webapp2 doesn’t automatically handle “OPTIONS” or “HEAD”.

To make flask’s request routing and dispatching work more like webapp2, the following must be done: - Disable automatic handling of “OPTIONS” for any subclass of WaskMethodView by setting

provide_automatic_options = False

  • Use wask.adapters.add_route to register a route with the application that has automatic support for the “HEAD” method disabled.

As a result, wask.adapters.add_route should always be used to register a route with the app that uses an instance of WaskMethodView as the route’s handler. E.g.

add_route(app, “/”, view_func=Handler.as_view(“endpoint-name”))

class wask.adapters.WaskResponse(*args, **kwargs)[source]

For allowing you to write webapp2 code that works with flask.

Methods not implemented:
body: This is only used once in mainapp and seems like an improper

use of webapp2.Response

status_message: Used for setting the text portion of the status

e.g. The “OK” in “200 OK”. This is also only used once and is likely unnecessary

headers:

The header member variable is actually a different class in webapp2 than it is in flask. Both implement complex custom classes to handle headers.

Luckily they appear to have exactly the same interface, so we have not made any changes here to attempt to adapt them.

In mainapp we only use self.response.header in the following ways:
  • Setting a header directly as if the header was a dictionary

  • using the header.add(key, value) method

  • using the header.add_header(key, value) method, which appears to be functionally the same as header.add(key, value)

out:

In webapp1 (yes 1), you would access the write function through ` self.response.out.write, in webapp2 they changed it to self.response.write however they maintained the out property for backwards compatibility.

Because we have the old pattern all over the place in our code we have to support it as well.

class wask.adapters.WaskRequest[source]

Datastructures

These datastructures are used throughout wask. Based on werkzeug’s datastructures and adapting them to fit webapp2 style interfaces.

class wask.datastructures.WaskCombinedMultiDict(dicts=None)[source]

In webapp2 they use webob.multidict.NestedMultiDic, which operates almost identically to werkzeug.datastructures.CombinedMultiDict.

The only difference is that in NestedMultiDic.items() by default it returns duplicate values, whereas in CombinedMultiDict.items() by default it doesn’t

e.g. for GET /?foo=bar&foo=baz

webob.multidict.NestedMultiDic.items() returns [(“foo”, “bar”), (“foo”, “baz”)] werkzeug.datastructures.CombinedMultiDict.items() returns [(“foo”, “bar”)]

class wask.datastructures.WaskImmutableMultiDict(mapping=None)[source]

In webapp2 they use webob.multidict.GetDict, which operates almost identically to werkzeug.datastructures.ImmutableMultiDict.

The only difference is that in GetDict.items() by default it returns duplicate values, whereas in ImmutableMultiDict.items() by default it doesn’t

e.g. for GET /?foo=bar&foo=baz

webob.multidict.GetDict.items() returns [(“foo”, “bar”), (“foo”, “baz”)] werkzeug.datastructures.ImmutableMultiDict.items() returns [(“foo”, “bar”)]

Routing

These tools are for adapting webapp2 routing to run on flask. A lot of it is temporary scaffolding for migrating mainapp.

wask.routing.uri_for(name, *args, **kwargs)[source]

Adapts webapp2.uri_for to flask.url_for

Documentation references: - webapp2: https://github.com/GoogleCloudPlatform/webapp2/blob/2.5.2/docs/guide/routing.rst#building-uris - flask: https://flask.palletsprojects.com/en/1.1.x/api/#flask.url_for

Differences from webapp2: - Query params are not sorted (Python 3 only) - If _scheme is not None and _full (_external in flask) is not True, ValueError is raised - _request argument is not supported, it will be ignored

Return type:

str

wask.routing.add_webapp2_routes_to_flask_app(app, route_config)[source]

Takes a webapp2 routing configuration and adds the same URLs to a flask app, while skipping any with matching endpoint names.

This should be done after you add all the migrated routes from webapp2.

The endpoint for each of these endpoints will return 501 Not Implemented.

These endpoints should never be called directly.

Return type:

None

Justification:

During the migration process we will need to have every routable URI from webapp2 available in Flask.

All that matters is that we are able to build the URIs from flasks url_for and webapp2s uri_for at the same time.

Once the migration is complete this file can be removed

See:

https://flask.palletsprojects.com/en/1.1.x/api/#url-route-registrations https://webapp2.readthedocs.io/en/latest/guide/routing.html#the-url-template

Differences between webapp2 and flask routes:
  • webapp2 routes can have regular expressions, flask routes cannot

  • webapp2 routes can have unnamed templates, flask routes cannot Since we don’t have unnamed templates in mainapp, we are not supporting them

wask.routing.convert_webapp2_route_to_flask_route(webapp2_route)[source]
Return type:

str

wask.routing.add_route(app, *args, **kwargs)[source]
Return type:

None

wask.routing.add_routes(app, wask_routes)[source]
Return type:

None

class wask.routing.WaskRedirectRoute(path, name, redirect_to='', redirect_to_name='', **kwargs)[source]

Provides similar functionality as webapp2.RedirectRoute

Differences: - webapp2.RedirectRoute allows both redirect_to and redirect_to_name to be absent

whereas WaskRedirectRoute requires one or the other. Like webapp2.RedirectRoute, WaskRedirectRoute does not allow both at the same time.