2020-12-15T12:06:14Z

Why do we pass __name__ to the Flask class?

When you learn Flask, you are told to create your Flask application instances by passing __name__ as the first argument to the Flask class. Most developers do this without thinking, and without knowing what it achieves.

In this article we are going to look at Flask(__name__) in depth. By the end you will not only have a full understanding of this pattern, but you will also know when to deviate from it and pass other values.

What is __name__?

Python sets the __name__ variable to the module name, so the value of this variable will vary depending on the Python source file in which you use it.

For example, in a module named test.py that is located in the top-level directory of the application, the value of __name__ is test. If the test.py module is located inside a Python package called my_package, then the value of __name__ is my_package.test.

There are two special exceptions with regards to the value of __name__:

  • Inside a __init__.py package constructor module, the value of __name__ is the package name, without __init__. For example, in my_package/__init__.py, the value of __name__ is just my_package.
  • In the main module of the application (the file you run the Python interpreter on) the value of __name__ has the special value of __main__.

Flask Documentation on __name__

If you read the Flask documentation, the first argument to the Flask class is called import_name. It is described as "the name of the application package". The documentation suggests that you "usually" create the Flask instance by passing __name__ for this argument, without going into any details on why.

In the sub-section titled "About the First Parameter" there is a little more information about the purpose of the import_name argument, with a list of three different purposes for it:

  • Find resources on the filesystem
  • Used by extensions to improve debugging information
  • A lot more (???)

Very confusing, right? Let's look at these one by one.

Finding Resources

This is actually easier to understand that it may seem initially. The term "resources" in this context refers to additional files needed by the application, such as static and template files. Did you ever stop to think about how Flask knows where to look for these files?

The way it works is as follows. Flask takes the argument passed as import_name, which is the name of an imported package, and tries to use it to figure out what the root path of the application is by looking for the module object with that name. Once it knows this path, it appends the static and template directory names and that is where it goes to get those files.

There is a function in the flask/helpers.py module called get_root_path() that Flask uses to obtain the root directory of the application. This function does all the dirty work of navigating the Python import system to locate the module with the name that was given as the import_name argument.

Let's take a quick look at the get_root_path() function. For the following test I'm going to use the microblog application featured in my Flask Mega-Tutorial. With this application correctly installed, I'm going to start a Python session and call the get_root_path() function with a few different values to see what the results are:

>>> from flask.helpers import get_root_path

# the app package
>>> get_root_path('app')
'/home/miguel/microblog/app'

# the flask package
>>> get_root_path('flask')
'/home/miguel/microblog/venv/lib/python3.8/site-packages/flask'

# the threading package
>>> get_root_path('threading')
'/home/miguel/.pyenv/versions/3.8.6/lib/python3.8'

# the config.py module
>>> get_root_path('config')
'/Users/mgrinberg/Documents/dev/python/microblog'

# the app/models.py module
>>> get_root_path('app.models')
'/Users/mgrinberg/Documents/dev/python/microblog/app'

# the app.api package
>>> get_root_path('app.api')
'/Users/mgrinberg/Documents/dev/python/microblog/app/api'

# the app.api.auth.py module
>>> get_root_path('app.api.auth')
'/Users/mgrinberg/Documents/dev/python/microblog/app/api'

From these examples we can derive the rules that Flask uses to determine the root path:

  • If you call Flask() passing the name of a package as an argument, then the root path of the application is the directory where the package is located.
  • If you call Flask() passing the name of a module as an argument, then the root path of the application is the directory of the package in which the module is located.

There is a second usage of the import_name argument. Flask has an obscure feature called instance folders, which are special folders where configuration files that are not under source control can be stored. The method to determine the location of the instance folder for an application is the same, the import_name is used to find a root path, and then an instance subdirectory is added to it.

I should note that both the default root and instance paths can be overriden in the Flask constructor with the root_path and instance_path arguments.

Improving Debugging Information In Flask Extensions

This one was very tricky to figure out. The only Flask extension I have found that uses the import_name argument is Flask-SQLAlchemy. The extension has a get_debug_queries() function that collects and logs all the queries that are issued during the life of a request. One of the attributes that are logged is the place in the application source code where the query was issued. Obtaining this information is actually quite hard, Flask-SQLAlchemy walks up the call stack at the time the query completes until it finds a source location that matches the import name of the application.

While this is a very cool technique, it is also very magical and obscure. I have not seen it used in any other Flask extensions.

A Lot More

I scanned the Flask source code for other usages of the import_name parameter and found two more cases that are worth mentioning.

One is the Blueprint class, which takes the blueprint name as first argument, and import_name as second. The usage of the argument in blueprints is related to finding blueprint specific resources, and it works in the same way as in the application instance.

The other interesting place where the import_name argument is used is in giving the application instance a name. The name of the application appears when you print the application instance:

>>> from flask import Flask
>>> app = Flask('foo')
>>> app
<Flask 'foo'>

This name is assigned to the main group of the Click command-line interface. If you were to attach the Flask CLI of your project as a group into a parent CLI, then this name would be the group name that you would use to access the Flask application commands.

Conclusion

I hope you now have a better understanding of the common practice of calling Flask(__name__). If you have any remaining questions regarding this topic, feel free to ask me below in the comments section!

4 comments

  • #1 Paul said 2020-12-22T07:55:15Z

    That last one does it mean one would say: "foo run" instead of "flask run" in the cli

  • #2 Miguel Grinberg said 2020-12-22T21:08:39Z

    @Paul: No. The flask in flask run refers to the flask executable that is installed in the virtual environment. The name of your application is independent of that. The use within the CLI is only when the CLI of your application is included as a sub-command in a bigger CLI.

  • #3 Jack said 2021-02-21T21:19:56Z

    So in the context of the Microblog application, __name__ (in app/__init__.py) is getting its value when the statement from app import app executes in microblog.py?

  • #4 Miguel Grinberg said 2021-02-22T10:08:37Z

    @Jack: the __name__ variable is somewhat magical, in that Python sets its value automatically, and it is different depending on the file from where you use it.

Leave a Comment