AlexLordThorsen
AlexLordThorsen

Reputation: 8498

Run code before an IPython Notebook cell runs

I'm writing a bunch of examples of how to use Flask and currently I want to be able to just write

@app.route("/")
def redirectora():
    redirect("redirected")

@app.route("/targeta", methods=["GET", "POST"])
def redirecteda():
    return "Redirected!"

app.run(host="0.0.0.0", port=5000)

in my cells but I have to include

app = Flask("the_flask_module")

in every cell (otherwise if I run the cell twice I get an assertion error about trying to add a route twice).

I would really like to be able to run code before the cell is run (so I don't have to write app = 60 times) but I'm not finding any signals or hooks for notebooks.

Does anyone know how run code before any cell is run?

Upvotes: 1

Views: 886

Answers (2)

George Mauer
George Mauer

Reputation: 122232

The answer given by shad is the right one for the scenario outlined but the wrong one for the question as phrased (and what I was searching for when landing here). For anyone else who is looking for the right way to run code before a cell runs in ipython, check out the events api.

For example how the autoreload extension works

def load_ipython_extension(ip):
    """Load the extension in IPython."""
    auto_reload = AutoreloadMagics(ip)
    ip.register_magics(auto_reload)
    ip.events.register("pre_run_cell", auto_reload.pre_run_cell)
    ip.events.register("post_execute", auto_reload.post_execute_hook)

Upvotes: 1

shad
shad

Reputation: 1820

Every time you make a call to app = Flask('the_flask_module'), you're creating a new Flask app instance. If you had this at the top of every cell, then every time you execute a cell, you would wipe out the previous Flask app instance that you had. For example, if you did this:

app = Flask('my_app')

@app.route('/targeta')
def targeta():
    return 'targeta'

app = Flask('my_app')

@app.route('/targetb')
def targeta():
    return 'targetb'

app.run(host="0.0.0.0", port=5000)

/targeta would return a 404.

If this is the behaviour you want, i.e. that every cell should be an independent Flask endpoint, then you could achieve this by creating your own decorator that creates a new app object for whatever function you decorate, as follows:

class route(object):
    def __init__(self, path, **kwargs):
        self.path = path
        self.kwargs = kwargs

    def __call__(self, func):
        app = Flask('my_flask_app')
        app.add_url_rule(self.path, func.func_name, func, **self.kwargs)
        app.run(host="0.0.0.0", port=5000)

If the behaviour you're looking for is to be allowed to use @app.route more than once without receiving an assertion error, you could create your own decorator that calls add_url_rule and swallows the exception:

class route(object):
    def __init__(self, path, **kwargs):
        self.path = path
        self.kwargs = kwargs

    def __call__(self, func):
        try:
            app.add_url_rule(self.path, func.func_name, func, **self.kwargs)
        except AssertionError, e:
            pass

In both cases, you would decorate your function as follows:

@route('/targeta')
def targeta():
    return 'targeta'

Assuming that you're doing this for tutorial or presentation purposes, you'll want to put the decorator code in a setup section of your notebook so that it is transparent why you've done this.

Upvotes: 1

Related Questions