storen
storen

Reputation: 1035

How to understand the first parameter in Flask instance init?

When create a Flask instance , we always use __name__ as the first arguments, but why?

class flask.Flask(import_name, static_path=None, static_url_path=None,static_folder='static', template_folder='templates', instance_path=None, instance_relative_config=False)

The official document says that first parameter is used to find resource,how?

Upvotes: 6

Views: 2267

Answers (3)

user4322779
user4322779

Reputation:

__name__ should not always be used as the first argument particularly if the application is in a package instead of a single module, then its 'usually recommended to hardcode the package name' in order to simplify debugging with the Flask-SQLAlchemy extension for example. For reference see the section on 'About the First Parameter' in http://flask.pocoo.org/docs/0.10/api/.

In the case when using a package there is a way to avoid hardcoding the package name with a special configuration which forces __name__ to resolve to the package name as desribed in Larger Applications. First, note that a Python package is not simply a directory containing modules which are Python source files; it must also contain an __init__.py file (except for Python3 namespace packages). One function of __init__.py files is to prevent unintentional namespace conflicts as mentioned in An Introduction to Python: Section 6.4. In the case of flask, its convenient to define a flask app in a package's __init__.py in order to enable use of __name__ since in that case it resolves to the package name which is identical to the package's base directory name and has a file attribute with which its absolute pathname can be determined. A working flask/Python3 project demonstrating this configuration is available at flaskdemo.

Regarding understanding the first parameter in flask instance initialization, first of all if its missing and there are no remaining arguments, then when attempting to run the flask app it immediately fails with "TypeError: __init__() missing 1 required positional argument: 'import_name'". Second, if a nonexistent pathname is provided for it, then the application's and its resources root is set to the cwd (current working directory) and attempts to access resources would fail unless they are in the cwd which is not necessarily always the case and a limitation anyway.

Further details can be obtained by examining the flask sources, particularly app.py as well as helpers.py. In an Anaconda3 installation they are located in Lib\site-packages\flask. From a brief review, what I found is that class Flask is defined in app.py and its __init__ method begins with:

def __init__(self, import_name, static_path=None, static_url_path=None,
                 static_folder='static', template_folder='templates',
                 instance_path=None, instance_relative_config=False):
    _PackageBoundObject.__init__(self, import_name, template_folder=template_folder)
...

class _PackageBoundObject is defined in helpers.py and it has an open_resource() function that returns open(os.path.join(self.root_path, resource), mode) where

self.root_path = get_root_path(self.import_name)

The root in root_path refers to 'the path of a package or the folder that contains a module'. get_root_path goes though a series of attempts to resolve it starting with the module name if its available and has a file attribute. In all cases absent exceptions it returns an absolute pathname which defaults to cwd if it has not been already been resolved with a module name whenpkgutil.get_loader(import_name) == None or import_name == '__main__', which happens when running a flask app interactively instead of from a file.

Upvotes: 1

Sean Vieira
Sean Vieira

Reputation: 159935

The import name is used to resolve the directory where the Flask application is installed (see the get_root_path function in flask/helpers.py). This makes it possible for things like render_template, send_static_file, and relative file paths in config to resolve to files in the application's folder without needing a file path to be provided.

Consider an extremely simple Python app without this functionality:

simple_app.py

print("Running simple_app")

with open('the-folder/simple.file', 'r') as f:
    for line in f:
        print(f)

simple.file

Hello
World!

And a directory structure looking like this:

some-path/
    simple-app/
        simple_app.py
        the-folder/
            simple.file

If we start Python while our current working directory is simple-app/ everything will work just fine:

simple-app$ python simple_app.py
Running simple_app
Hello
World!

But if we move up one folder and try again:

some-path$ python simple-app/simple_app.py
Traceback (most recent call last):
IOError: [Errno 2] No such file or directory: 'the-folder/simple.file'

The same thing happens when we move down one folder. However, if we could get the location of simple_app.py on the file system, we could then os.join the directory in which simple_app.py was installed with the-folder/simple.file

with open(os.join(SIMPLE_APP_DIR, 'the-folder/simple.file', 'r') as f:

And our working directory wouldn't matter, since we would always be dealing with an absolute path. This is what Flask does, and this is why it needs the __name__ passed in.

Upvotes: 10

user4999841
user4999841

Reputation:

It is explained in the Quick Start section of docs.

http://flask.readthedocs.org/en/latest/quickstart/#a-minimal-application

Quoting from the docs

The first argument is the name of the application’s module or package. If you are using a single module (as in this example), you should use __name__ because depending on if it’s started as application or imported as module the name will be different (__main__ versus the actual import name). This is needed so that Flask knows where to look for templates, static files, and so on.

Upvotes: 0

Related Questions