librelist archives

« back to archive

Bigger projects and "import_name" troubles

Bigger projects and "import_name" troubles

From:
Mitchell Hashimoto
Date:
2012-04-26 @ 04:47
Hello all,

So I'm working on a bigger-than-usual Flask project, which is nicely
split into many blueprints. It also has a "shared" package which
contains things like business logic, models, etc.

One of the shared models is "shared.app" which contains the "app" (an
instance of Flask). The issue I run into is initializing with the
proper import_name. The problem I have is this:

* When I run the web app using gunicorn, the import name actually
needs to be "app" which is a root app.py that imports "shared.app" and
runs it. This is because the templates and so on are all at the root
level.
* When I run the web app directly with "python app.py", the import
name is "__main__"
* When I run workers with "python worker/do_something.py" which needs
to import the app, the import name is "app" again.

The import name at the end of the day is a huge annoyance. What I'd
like to do is just say "HERE is the root path, don't try to use some
import name magic."

Can I do this? Looking at the source I can see there is an
instance_path but some things like Jinja loading appear to still use
the root_path, which is auto-magicked from the import name.

Or maybe I'm just using the Flask app wrong? How do I share it across
many modules properly?

Best,
Mitchell

Re: [flask] Bigger projects and "import_name" troubles

From:
Ron DuPlain
Date:
2012-04-26 @ 13:06
Hi Mitchell,

On Thu, Apr 26, 2012 at 12:47 AM, Mitchell Hashimoto
<mitchell.hashimoto@gmail.com> wrote:
> So I'm working on a bigger-than-usual Flask project, which is nicely
> split into many blueprints. It also has a "shared" package which
> contains things like business logic, models, etc.
>
> One of the shared models is "shared.app" which contains the "app" (an
> instance of Flask). The issue I run into is initializing with the
> proper import_name. The problem I have is this:
>
> * When I run the web app using gunicorn, the import name actually
> needs to be "app" which is a root app.py that imports "shared.app" and
> runs it. This is because the templates and so on are all at the root
> level.
> * When I run the web app directly with "python app.py", the import
> name is "__main__"
> * When I run workers with "python worker/do_something.py" which needs
> to import the app, the import name is "app" again.
>
> The import name at the end of the day is a huge annoyance. What I'd
> like to do is just say "HERE is the root path, don't try to use some
> import name magic."
>
> Can I do this? Looking at the source I can see there is an
> instance_path but some things like Jinja loading appear to still use
> the root_path, which is auto-magicked from the import name.
>
> Or maybe I'm just using the Flask app wrong? How do I share it across
> many modules properly?

The Flask class doc should hopefully clarify this.
http://flask.pocoo.org/docs/api/#application-object

If your resources are in the root folder of the package, you should
provide the package name as the import name.  If you have specific
paths, you can pass static_folder, template_folder, and instance_path
explicitly.

-Ron

Re: [flask] Bigger projects and "import_name" troubles

From:
Mitchell Hashimoto
Date:
2012-04-26 @ 17:52
Ron,

On Thu, Apr 26, 2012 at 6:06 AM, Ron DuPlain <ron.duplain@gmail.com> wrote:
> Hi Mitchell,
>
> On Thu, Apr 26, 2012 at 12:47 AM, Mitchell Hashimoto
> <mitchell.hashimoto@gmail.com> wrote:
>> So I'm working on a bigger-than-usual Flask project, which is nicely
>> split into many blueprints. It also has a "shared" package which
>> contains things like business logic, models, etc.
>>
>> One of the shared models is "shared.app" which contains the "app" (an
>> instance of Flask). The issue I run into is initializing with the
>> proper import_name. The problem I have is this:
>>
>> * When I run the web app using gunicorn, the import name actually
>> needs to be "app" which is a root app.py that imports "shared.app" and
>> runs it. This is because the templates and so on are all at the root
>> level.
>> * When I run the web app directly with "python app.py", the import
>> name is "__main__"
>> * When I run workers with "python worker/do_something.py" which needs
>> to import the app, the import name is "app" again.
>>
>> The import name at the end of the day is a huge annoyance. What I'd
>> like to do is just say "HERE is the root path, don't try to use some
>> import name magic."
>>
>> Can I do this? Looking at the source I can see there is an
>> instance_path but some things like Jinja loading appear to still use
>> the root_path, which is auto-magicked from the import name.
>>
>> Or maybe I'm just using the Flask app wrong? How do I share it across
>> many modules properly?
>
> The Flask class doc should hopefully clarify this.
> http://flask.pocoo.org/docs/api/#application-object
>
> If your resources are in the root folder of the package, you should
> provide the package name as the import name.  If you have specific
> paths, you can pass static_folder, template_folder, and instance_path
> explicitly.

Thanks, so I did this and it appears to work, but this still seems
incredibly complex for what I'm trying to achieve. My "shared/app.py"
now looks like this towards the top:

```
from flask import Flask

# The instance path has to be absolute so figure it out
my_directory = os.path.dirname(__file__)
root_directory = os.path.abspath(os.path.join(my_directory, ".."))

# Create the app and configure
app = Flask(__name__,
        static_folder="../static",
        template_folder="../templates",
        instance_path=root_directory,
        instance_relative_config=True)
```

However, all of this would be made much simpler if I could just do this:

```
Flask(__name__, root_path="..")
```

I couldn't figure out from the docs or implementation why so much
hoop-jumping is necessary to do the above. Doesn't this make more
sense as an easy API for new users? The current approach requires a
pretty high amount of understanding of Python as well as really deeply
reading the App documentation.

Best,
Mitchell

>
> -Ron

Re: [flask] Bigger projects and "import_name" troubles

From:
David Shawley
Date:
2012-04-27 @ 12:20
On Thu, Apr 26, 2012 at 1:52 PM, Mitchell Hashimoto
<mitchell.hashimoto@gmail.com> wrote:
> ```
> from flask import Flask
>
> # The instance path has to be absolute so figure it out
> my_directory = os.path.dirname(__file__)
> root_directory = os.path.abspath(os.path.join(my_directory, ".."))
>
> # Create the app and configure
> app = Flask(__name__,
>        static_folder="../static",
>        template_folder="../templates",
>        instance_path=root_directory,
>        instance_relative_config=True)
> ```
>
> However, all of this would be made much simpler if I could just do this:
>
> ```
> Flask(__name__, root_path="..")
> ```
>

The easiest thing to do is to subclass Flask and implement root_path
to your liking:

    class RootedApplication(flask.Flask):
        def __init__(self, name, *args, **kwds):
            root = kwds.pop('root_path', None)
            if root:
                kwds.setdefault('static_folder', os.path.join(root, 'static'))
                kwds.setdefault('template_folder', os.path.join(root,
'templates'))
                kwds.setdefault('instance_path', root)
                kwds['instance_relative_config'] = True
            super(RootedApplication, self).__init__(name, *args, **kwds)

I've used this pattern to solve a few similar problems in the past.  I
rarely use a raw flask.Flask instance any more for my application.
There is always something that I want to add in.  This feature isn't
there because it is relatively easy to implement and it is a special
case.  It might be worth writing this up as a Flask snippet on
http://flask.pocoo.org/snippets/

Enjoy, dave.
--