Why do we pass __name__ to the Flask class?
Posted by
on underWhen 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 justmy_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!
-
#1 Paul said
That last one does it mean one would say: "foo run" instead of "flask run" in the cli
-
#2 Miguel Grinberg said
@Paul: No. The
flask
inflask run
refers to theflask
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
So in the context of the Microblog application,
__name__
(inapp/__init__.py
) is getting its value when the statementfrom app import app
executes in microblog.py? -
#4 Miguel Grinberg said
@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. -
#5 Dayle said
This is a bit off topic - not sure where to post the question. Bought your Mega Tutorial book and its my bible on all things Flask. I've recently ran in to a situation where I need to access a PostgreSQL database both from a Flask and non-Flask application. The solution seems to be to replace flask_sqlalchemy with sqlachemy and rebuild my database and Flask app. You touched on it here: https://stackoverflow.com/questions/22698478/what-is-the-difference-between-the-declarative-base-and-db-model
Any thoughts or just bite the bullet and redo it?
Thanks once again -
#6 Miguel Grinberg said
@Dayle: in my opinion Flask-SQLAlchemy has some advantages over plain SQLAlchemy. Enough that when I'm in situation similar to the one you describe, I continue to use Flask-SQLAlchemy and for the non-Flask app I just create a dummy Flask app instance to be able to continue to use Flask-SQLAlchemy.
-
#7 Jürgen Gmach said
Thank you, Miguel! This was an interesting read :-)
-
#8 narges said
it was wonderful thanks.you help me alot
-
#9 ziglub said
If you have only one module, wouldn't name return main and not give a valid path for flask to identify?
-
#10 Miguel Grinberg said
@ziglub: The argument that you pass is the module name, not the path. You can find the module in the
sys.modules
dictionary. The expressionsys.modules['__main__']
is valid and returns the correct module for Flask to use in determining the location of the application.