debug Flask server inside Jupyter Notebook

后端 未结 2 769
没有蜡笔的小新
没有蜡笔的小新 2021-02-04 11:45

I want to debug small flask server inside jupyter notebook for demo.

I created virtualenv on latest Ubuntu and Python2 (on Mac with Python3 this error occurs as well), p

相关标签:
2条回答
  • 2021-02-04 12:24

    The trick is to run the Flask server in a separate thread. This code allows registering data providers. The key features are

    • Find a free port for the server. If you run multiple instances of the server in different notebooks they would compete for the same port.

    • The register_data function returns the URL of the server so you can use it for whatever you need.

    • The server is started on-demand (when the first data provider is registered)

    • Note: I added the @cross_origin() decorator from the flask-cors package. Else you cannot call the API form within the notebook.

    • Note: there is no way to stop the server in this code...

    • Note: The code uses typing and python 3.

    • Note: There is no good error handling at the moment

    import socket
    import threading
    import uuid
    from typing import Any, Callable, cast, Optional
    
    from flask import Flask, abort, jsonify
    from flask_cors import cross_origin
    from werkzeug.serving import run_simple
    
    app = Flask('DataServer')
    
    
    @app.route('/data/<id>')
    @cross_origin()
    def data(id: str) -> Any:
        func = _data.get(id)
        if not func:
            abort(400)
        return jsonify(func())
    
    
    _data = {}
    
    _port: int = 0
    
    
    def register_data(f: Callable[[], Any], id: Optional[str] = None) -> str:
        """Sets a callback for data and returns a URL"""
        _start_sever()
        id = id or str(uuid.uuid4())
        _data[id] = f
        return f'http://localhost:{_port}/data/{id}'
    
    
    def _init_port() -> int:
        """Creates a random free port."""
        # see https://stackoverflow.com/a/5089963/2297345
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('localhost', 0))
    
        port = sock.getsockname()[1]
        sock.close()
        return cast(int, port)
    
    
    def _start_sever() -> None:
        """Starts a flask server in the background."""
        global _port
        if _port:
            return
        _port = _init_port()
        thread = threading.Thread(target=lambda: run_simple('localhost', _port, app))
        thread.start()
    
    0 讨论(0)
  • 2021-02-04 12:39

    I installed Jupyter and Flask and your original code works.


    The flask.Flask object is a WSGI application, not a server. Flask uses Werkzeug's development server as a WSGI server when you call python -m flask run in your shell. It creates a new WSGI server and then passes your app as paremeter to werkzeug.serving.run_simple. Maybe you can try doing that manually:

    from werkzeug.wrappers import Request, Response
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route("/")
    def hello():
        return "Hello World!"
    
    if __name__ == '__main__':
        from werkzeug.serving import run_simple
        run_simple('localhost', 9000, app)
    

    Flask.run() calls run_simple() internally, so there should be no difference here.

    0 讨论(0)
提交回复
热议问题