librelist archives

« back to archive

debug + relative imports == fail?

debug + relative imports == fail?

From:
Ben Beuchler
Date:
2014-01-23 @ 16:24
I'm working on a project with several moving parts including a REST
API, which I'm writing in Flask. It uses absolute_imports and one
relative import with the '..' notation.  If debug=True, it throws
"ValueError: Attempted relative import in non-package."  If
debug=False, it works just fine.  Phira in #pocoo suspects the
reloader, which seems plausible. My setup / code is below, but I've
reduced it to a minimal example that results in the same error:

http://paste.ubuntu.com/6799011/

Any idea what I'm doing wrong?  Or is this a bug / incompatibility in
the reloader?

-Ben



adminbot/
|+celery/
|~web/
| |+static/
| |+templates/
| |-__init__.py
| `-api.py
`-__init__.py

adminbot/web/api.py is my Flask application.  It starts with the
following imports:

----------
from __future__ import absolute_import

import flask
import celery

from flask.ext import restful
from flask.ext.restful import reqparse

from ..celery import tasks
----------

And starts the app like so:

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

And this is what happens when I run it:

$ python -m adminbot.web.api
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader
Traceback (most recent call last):
  File "/home/insyte/adminbot/adminbot/web/api.py", line 9, in <module>
    from ..celery import tasks
ValueError: Attempted relative import in non-package

Re: [flask] debug + relative imports == fail?

From:
Emanuil Tolev
Date:
2014-01-23 @ 16:51
In case this does turn out to be a reloader incompatibility (or even if it
doesn't?) - why use absolute imports? I.e. are they somehow helpful to
achieving your goal with the app?

For example, for celery tasks, I'd just put them inside the package that
houses the flask app.

A more concrete example can be found in this repo:
https://github.com/CottageLabs/OpenArticleGauge/
The web app is in the openarticlegauge.app module, i.e. I would do "python
openarticlegauge/app.py" to run it.
The celery tasks are in the openarticlegauge.workflow module. It defines
various other things, and they're defined as functions at the bottom.

Then you just tell celery to import the tasks from your module! E.g. the
app I'm referring to has an openarticlegauge.slavedriver module, which
imports openarticlegauge.celeryconfig, which in turn, defines the celery
imports:

CELERY_IMPORTS = ('openarticlegauge.workflow', 'openarticlegauge.models')

Then I can always run
celery multi start 4 -A openarticlegauge.slavedriver -l info
--pidfile=%%n.pid --logfile=%%n.log -Q:1-2 some_queue -Q:3-4
some_other_queue

in the web app's directory (the root of the repo you're seeing).

Doesn't even matter whether it's started or not. But the idea here really
is: I can give celery normal package-level imports, the same I use
everywhere else in the web app itself. I understand the desire to separate
them, but they (app and celery tasks) are surely going to end up sharing
code soon enough.

Greetings,
Emanuil


On 23 January 2014 16:24, Ben Beuchler <insyte@gmail.com> wrote:

> I'm working on a project with several moving parts including a REST
> API, which I'm writing in Flask. It uses absolute_imports and one
> relative import with the '..' notation.  If debug=True, it throws
> "ValueError: Attempted relative import in non-package."  If
> debug=False, it works just fine.  Phira in #pocoo suspects the
> reloader, which seems plausible. My setup / code is below, but I've
> reduced it to a minimal example that results in the same error:
>
> http://paste.ubuntu.com/6799011/
>
> Any idea what I'm doing wrong?  Or is this a bug / incompatibility in
> the reloader?
>
> -Ben
>
>
>
> adminbot/
> |+celery/
> |~web/
> | |+static/
> | |+templates/
> | |-__init__.py
> | `-api.py
> `-__init__.py
>
> adminbot/web/api.py is my Flask application.  It starts with the
> following imports:
>
> ----------
> from __future__ import absolute_import
>
> import flask
> import celery
>
> from flask.ext import restful
> from flask.ext.restful import reqparse
>
> from ..celery import tasks
> ----------
>
> And starts the app like so:
>
> ----------
> if __name__ == '__main__':
>      app.run(debug=True)
> ----------
>
> And this is what happens when I run it:
>
> $ python -m adminbot.web.api
>  * Running on http://127.0.0.1:5000/
>  * Restarting with reloader
> Traceback (most recent call last):
>   File "/home/insyte/adminbot/adminbot/web/api.py", line 9, in <module>
>     from ..celery import tasks
> ValueError: Attempted relative import in non-package
>

Re: [flask] debug + relative imports == fail?

From:
Ben Beuchler
Date:
2014-01-23 @ 19:06
On Thu, Jan 23, 2014 at 10:51 AM, Emanuil Tolev <emanuil@cottagelabs.com> wrote:
> In case this does turn out to be a reloader incompatibility (or even if it
> doesn't?) - why use absolute imports? I.e. are they somehow helpful to
> achieving your goal with the app?

No, absolute imports are not specifically important to my application.
 I went with them for two main reasons:

1. The Celery examples I used as templates all used absolute imports,
so I stuck with it.
2. My understanding is absolute imports are considered the One True
Way by the BDFL and will be the only way in Python 3, so I figured I
might as well start learning how to work with it.

> Doesn't even matter whether it's started or not. But the idea here really
> is: I can give celery normal package-level imports, the same I use
> everywhere else in the web app itself.

I must be missing something here.  Another reason I like the absolute
imports approach is it means my application doesn't need to be
installed in a sys.path directory in order for me to import parts of
it, making interactive development easier.  With relative imports
(import ..celery.app) I can edit and run directly from my working
directory without going through an install step. Are you able to
accomplish something similar with the approach you describe?

-Ben