Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delayed initialization — init_app() not working #203

Closed
RealJTG opened this issue Feb 26, 2014 · 5 comments
Closed

Delayed initialization — init_app() not working #203

RealJTG opened this issue Feb 26, 2014 · 5 comments
Labels

Comments

@RealJTG
Copy link

RealJTG commented Feb 26, 2014

Regression.
Flask 0.10.1, Flask-RESTful 0.2.11 (from PyPI)

from flask import Flask
from flask.ext.restful import reqparse, abort, Api, Resource

class Test(Resource):
    def get(self):        
        return {'foo': 'bar'}

app = Flask(__name__)

# This one returns 404
api = Api()
api.init_app(app)

# This works okay
# api = Api(app)

api.add_resource(Test, '/test/')

if __name__ == '__main__':
    app.run(debug=True)
> curl http://127.0.0.1:5000/test/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server.  If you entered the URL manually please check your spelling and try again.</p>

Here: a1d59b7#diff-2d0ae3f4d6c2de850684766cfb7c5a6bR83

@yunlzheng
Copy link

you should add_resource first, then init_app .

api = Api()
api.add_resource(Test, '/test/')
api.init_app(app)

@RealJTG
Copy link
Author

RealJTG commented Feb 27, 2014

That's a bit weird and need some refactoring.

  1. http://flask-restful.readthedocs.org/en/latest/api.html?highlight=init_app#flask.ext.restful.Api.init_app
  2. Factory actually worked before factory-fix :)
  3. Inexplicit initialization with _init_app() and dead code if app is not None: next to self.app = None
  4. If you're using factory pattern then brobably all app-related stuff are initialized before main logic, views etc.

Flask-kit:

def get_app(self, app_module_name, **kwargs):
    self.app = Flask(app_module_name, **kwargs)
    self.app.config.from_object(self.app_config)

    self._generate_db_mapping()
    self._bind_extensions()
    self._register_blueprints()
    self._register_context_processors()

My other app written with some boilerplate:

def app_factory(config, app_name=None, blueprints=None):
    app_name = app_name or __name__
    app = Flask(app_name)

    config = config_str_to_obj(config)
    configure_app(app, config)
    configure_database(app)
    configure_cache(app)
    configure_blueprints(app, blueprints or config.BLUEPRINTS)
    configure_error_handlers(app)
    configure_extensions(app)
    configure_context_processors(app)
    configure_template_filters(app)
    configure_before_request(app)
    configure_views(app)
    return app

@dougblack dougblack added the bug label Mar 10, 2014
@celestianx
Copy link

Had the same issue. What is misleading are the explanations:

Initialize this class with the given :class:`flask.Flask`
        application or :class:`flask.Blueprint` object.
        :param app: the Flask application or blueprint object
        :type app: flask.Flask
        :type app: flask.Blueprint
        Examples::
            api = Api()
            api.init_app(app)
            api.add_resource(...)

If you look at the code of the add_ressource function:

        if self.app is not None:
            self._register_view(self.app, resource, *urls, **kwargs)
        else:
            self.resources.append((resource, urls, kwargs))

adding a ressource is self.app is not defined add it to a list-like object and when you call init_app, you get

  try:
            app.record(self._deferred_blueprint_init)
        # Flask.Blueprint has a 'record' attribute, Flask.Api does not
        except AttributeError:
            self._init_app(app)
        else:
            self.blueprint = app

While I don't know what the app.record does, there's a call to the self._init_app(app) which register the views:

    if len(self.resources) > 0:
            for resource, urls, kwargs in self.resources:
                self._register_view(app, resource, *urls, **kwargs)

So basically, for it to works, you have to do the following

api = Api()
api.add_resource(...)
api.init_app(app)

Which does make sense somehow as you delay the initialization but can register api views within the views itself at imports time and not only, exclusively in a separate function when you create you app objects. So, it's not really a bug in my opinion but rather a documentation issue :)

@dougblack
Copy link
Contributor

Sorry about this guys. I've updated the documentation to match working behavior:

api = Api()
api.add_resource(...)
api.init_app(app)

@dougblack
Copy link
Contributor

Based on the discussion here that sounds like the correct fix so I'm going to go ahead and close this out. If you still feel this isn't fixed, feel free to reopen and we can talk about solutions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants