Introduction Link to heading

I have been playing around with flask for few weeks now. It’s definitely leaner than Django but still there are some parts that look like black magic (I am looking at you, g).

So, Starting with…

Hello world Link to heading

This looks like a good to place to start. This is the smallest functional flask app, I guess.

Basically, there are two things happening here:

  • Route registration with @app.rount
  • Web Application with app.run()
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return "Hello, World!"

if __name__ == '__main__':
   app.run(debug = True)

Route registration Link to heading

Let’s start with app registration part.

@app.route defined in flask/app.py calls add_url_rule

 def route(self, rule, **options):
        def decorator(f):
            endpoint = options.pop("endpoint", None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f

        return decorator

and add_url_rule takes f as view_func and register rule that maps that route to view_func

    def add_url_rule(
        self,
        rule,
        endpoint=None,
        view_func=None,
        provide_automatic_options=None,
        **options
    ):

in the example above, endpoint is None, endpoint is set to __name__ of the view_func

        if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)
def _endpoint_from_view_func(view_func):
    assert view_func is not None, "expected view func if endpoint is not provided."
    return view_func.__name__

at this point we have rule as / and endpoint as index. Then, rule is used to create an object of Rule which takes options dict. and the newly created rule is added to url_map

To sum up, the following part registered url / to endpoint index

        options["endpoint"] = endpoint
      ...
      ...
        rule = self.url_rule_class(rule, methods=methods, **options)
        rule.provide_automatic_options = provide_automatic_options

        self.url_map.add(rule)

and eventually, endpoint index is linked to the actual function view_func using view_functions

            self.view_functions[endpoint] = view_func

Web Application Link to heading

For the second part, now that I know view_functions where the magic is, I can look for whoever doing lookup and start from there.

But we know that flask is WSGI application. So, we can start with __call__. If you haven’t heard about WSGI before, look into pep333. The important part:

The Application/Framework Side The application object is simply a callable object that accepts two arguments. The term “object” should not be misconstrued as requiring an actual object instance: a function, method, class, or instance with a call method are all acceptable for use as an application object. Application objects must be able to be invoked more than once, as virtually all servers/gateways (other than CGI) will make such repeated requests.

So, In flask/app.py, __call__ is defined as

    def __call__(self, environ, start_response):
        """The WSGI server calls the Flask application object as the
        WSGI application. This calls :meth:`wsgi_app` which can be
        wrapped to applying middleware."""
        return self.wsgi_app(environ, start_response)

In wsgi_app,

                response = self.full_dispatch_request()
   ...
   ...
            return response(environ, start_response)

in full_dispatch_request,

    def full_dispatch_request(self):

                rv = self.dispatch_request()

In dispatch_request, rule is extract from the request and rule.endpoint is used to lookup the registered view from, wait for it, view_functions

    def dispatch_request(self):

        return self.view_functions[rule.endpoint](**req.view_args)