-1

enter image description here

I'm working to modify a cookiecutter Flask app. I'm currently trying to add a datepicker to a page. I've found https://eonasdan.github.io/bootstrap-datetimepicker/. This cookiecutter uses flask-assets to manage the project assets.

Following https://adambard.com/blog/fresh-flask-setup/ I've modified my assets.py file :

from flask_assets import Bundle, Environment
import os

css = Bundle(
    "libs/bootstrap/dist/css/spacelab/bootstrap.css",
    "bower_components/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.css",
    "css/style.css",
    "css/home.css",
    # "css/style.css",
    filters="cssmin",
    output="public/css/common.css"
)

js = Bundle(
    "libs/jQuery/dist/jquery.js",
    "libs/bootstrap/dist/js/bootstrap.js",
    "bower_components/moment/moment.js",
    "bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js",
    "js/plugins.js",
    filters='jsmin',
    output="public/js/common.js"
)

# Tell flask-assets where to look for our coffeescript and sass files.
assets = Environment()
assets.load_path = [os.path.join(os.path.dirname(__file__), 'myflaskapp/static/bower_components')]

assets.register("js_all", js)
assets.register("css_all", css)

When I do this I get:

Traceback (most recent call last):
  File "C:/envs/r2/myproject/manage.py", line 8, in <module>
    from myflaskapp.app import create_app
  File "C:\envs\r2\myproject\myflaskapp\app.py", line 8, in <module>
    from myflaskapp.assets import assets
  File "C:\envs\r2\myproject\myflaskapp\assets.py", line 41, in <module>
    assets.load_path = [os.path.join(os.path.dirname(__file__), 'myflaskapp/static/bower_components')]
  File "C:\envs\virtalenvs\flask_myproject\lib\site-packages\webassets\env.py", line 639, in _set_load_path
    self._storage['load_path'] = load_path
  File "C:\envs\virtalenvs\flask_myproject\lib\site-packages\flask_assets.py", line 104, in __setitem__
    self.env._app.config[self._transform_key(key)] = value
  File "C:\envs\virtalenvs\flask_myproject\lib\site-packages\flask_assets.py", line 292, in _app
    'and no application in current context')
RuntimeError: assets instance not bound to an application, and no application in current context

What am I doing wrong?

edit: app.py initializes the assets:

from flask import Flask, render_template
from myflaskapp.assets import assets

    :param config_object: The configuration object to use.
    """
    app = Flask(__name__)
    app.config.from_object(config_object)
    register_extensions(app)
    register_blueprints(app)
    register_errorhandlers(app)
    return app

def register_extensions(app):
    assets.init_app(app)

def register_blueprints(app):
    app.register_blueprint(public.blueprint)
    app.register_blueprint(user.blueprint)
user1592380
  • 34,265
  • 92
  • 284
  • 515
  • Where's your app? It tells you in the stack trace. See the docs for flask_asset (https://flask-assets.readthedocs.org/en/latest/), you need to give Environment an app, `Environment(app)` or initialise it at some point `assets.init_app(app)` before you register something. – jonnybazookatone Mar 18 '16 at 00:51
  • Hi jonny, please see edit above as well as https://github.com/wdm0006/cookiecutter-flask/blob/master/%7B%7Bcookiecutter.app_name%7D%7D/%7B%7Bcookiecutter.app_name%7D%7D/assets.py – user1592380 Mar 18 '16 at 01:42

1 Answers1

2

As I noted in my comment, you have to a Flask app bound to the object, as it notes in the traceback:

>>> RuntimeError: assets instance not bound to an application, and no 
    application in current context

This will fix your problem, whether or not it's relevant for you use case...:

def register_extensions(app):
    assets.init_app(app)
    with app.app_context():
         assets.load_path = ['static']

or you could re-write your create app to have

def create_assets(app):
    assets = Environment(app)
    ....
    assets.load_path ['static']
    return assets

def create_app():
    app = Flask()
    ....
    assets = create_assets(app)
    return app

The whole reason for your errors is your call to load_path. This tries to set the attribute in webassets, which you can see here: https://github.com/miracle2k/webassets/blob/95dff0ad6dcc25b81790a1585c67f5393e7d32af/src/webassets/env.py#L656

def _set_load_path(self, load_path):
    self._storage['load_path'] = load_path

In turn, this now activates the attribute of _storage on your flask-asset object, which results in it trying to do this: https://github.com/miracle2k/flask-assets/blob/eb7f1905410828689086b80eb19be9331041ac52/src/flask_assets.py#L102

def __setitem__(self, key, value):
    if not self._set_deprecated(key, value):
        self.env._app.config[self._transform_key(key)] = value

As you see, it needs access to an app, and as you haven't given one when you used load_path it will complain to you, as it explains so nicely in the Traceback. I found a discussion about this on the flask-asset page: https://github.com/miracle2k/flask-assets/issues/35

You may, quite rightly, think that as you called init_app() that everything should be fine, but that's not the case, init_app() does not give any reference of the app to Environment: https://github.com/miracle2k/flask-assets/blob/eb7f1905410828689086b80eb19be9331041ac52/src/flask_assets.py#L338

def init_app(self, app):
    app.jinja_env.add_extension('webassets.ext.jinja2.AssetsExtension')
    app.jinja_env.assets_environment = self

I don't use flask-assets at all, and so I'm not particularly sure why they haven't referenced the app with the Environment().init_app, so if someone else knows, shout out.

jonnybazookatone
  • 2,188
  • 15
  • 21
  • Thanks jonny, with your help I got it working after changing with app.app_context(): assets.load_path = ['static'] to assets.load_path= [os.path.join(os.path.dirname(__file__), 'static')]. Unfortunately when I push to heroku the output files are not being put in the static directory, please see http://stackoverflow.com/questions/36086581/flask-assets-working-locally-but-not-on-heroku – user1592380 Mar 19 '16 at 17:43