pex: Pex does not play nicely with Flask's `debug=True`

Given app.py:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

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

Run pex flask -o flask.pex, then ./flask.pex app.py:

❯ ./flask.pex app.py
 * Serving Flask app "__main__" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
Traceback (most recent call last):
  File "/Users/eric/.pyenv/versions/3.9.1/lib/python3.9/runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/Users/eric/.pyenv/versions/3.9.1/lib/python3.9/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/Users/eric/code/debug/pex-flask-debug/app.py", line 1, in <module>
    from flask import Flask
ModuleNotFoundError: No module named 'flask'

But if setting debug=False, then it works like normal. Here, it’s complaining about flask, but in all reported cases of Pants users, the issue was instead their first party code.

A user found last week that with Dash—a wrapper around Flask—they could set debug=True, use_reloader=False and things would work. So, we can be fairly confident the file reloader is what causes issues. Why is this?

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 16 (12 by maintainers)

Most upvoted comments

OK - reproed via docker python:3.9. Thabnks @Eric-Arellano and @gshuflin. It turns out my box has requests installed in the underlying interpreter, so when Flask restarts and busts out of the PEX it sees the underlying interpreter’s requests installation.

I debugged with a slightly modified app.py:

import os
import sys
print(f">>> sys.path:\n{os.linesep.join(sys.path)}")

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

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

In the python:3.9 image I repro:

$ docker run --rm -it python:3.9 bash -c '
python -mvenv issues_1172
source issues_1172/bin/activate
pip -q install -U pip
pip -q install pex
pex --version
pex flask -o flask.pex --unzip
cat << EOF > app.py
import os
import sys
print(f">>> sys.path:\n{os.linesep.join(sys.path)}")

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run(debug=True)
EOF
./flask.pex app.py
'
2.1.24
>>> sys.path:
/root/.pex/unzipped_pexes/d81d3df451933800a53109cc2eaa92a397b5541c
/usr/local/lib/python39.zip
/usr/local/lib/python3.9
/usr/local/lib/python3.9/lib-dynload
/root/.pex/unzipped_pexes/d81d3df451933800a53109cc2eaa92a397b5541c/.deps/Flask-1.1.2-py2.py3-none-any.whl
/root/.pex/unzipped_pexes/d81d3df451933800a53109cc2eaa92a397b5541c/.deps/Werkzeug-1.0.1-py2.py3-none-any.whl
/root/.pex/unzipped_pexes/d81d3df451933800a53109cc2eaa92a397b5541c/.deps/click-7.1.2-py2.py3-none-any.whl
/root/.pex/unzipped_pexes/d81d3df451933800a53109cc2eaa92a397b5541c/.deps/Jinja2-2.11.2-py2.py3-none-any.whl
/root/.pex/unzipped_pexes/d81d3df451933800a53109cc2eaa92a397b5541c/.deps/itsdangerous-1.1.0-py2.py3-none-any.whl
/root/.pex/unzipped_pexes/d81d3df451933800a53109cc2eaa92a397b5541c/.deps/MarkupSafe-1.1.1-cp39-cp39-linux_x86_64.whl
/root/.pex/unzipped_pexes/d81d3df451933800a53109cc2eaa92a397b5541c/.bootstrap
 * Serving Flask app "__main__" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
>>> sys.path:
/
/usr/local/lib/python39.zip
/usr/local/lib/python3.9
/usr/local/lib/python3.9/lib-dynload
/usr/local/lib/python3.9/site-packages
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/local/lib/python3.9/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/app.py", line 5, in <module>
    from flask import Flask
ModuleNotFoundError: No module named 'flask'

This is fixed though by the --venv mode on master that will be released in 2.1.25:

$ python -mpex flask --venv -o /tmp/pex/issues/1172/flask-venv-mode.pex
^jsirois@gill /tmp/pex/issues/1172 $ ./flask-venv-mode.pex app.py 
>>> sys.path:
/home/jsirois/.pex/venvs/c346ae1bc73407d55bd9b575bba834b9050f4231/b4f78fd45edb740f0c5a41aa48be01f1e4e7090f
/usr/lib/python39.zip
/usr/lib/python3.9
/usr/lib/python3.9/lib-dynload
/home/jsirois/.pex/venvs/c346ae1bc73407d55bd9b575bba834b9050f4231/b4f78fd45edb740f0c5a41aa48be01f1e4e7090f/lib/python3.9/site-packages

 * Serving Flask app "pex" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
>>> sys.path:
/tmp/pex/issues/1172
/usr/lib/python39.zip
/usr/lib/python3.9
/usr/lib/python3.9/lib-dynload
/home/jsirois/.pex/venvs/c346ae1bc73407d55bd9b575bba834b9050f4231/b4f78fd45edb740f0c5a41aa48be01f1e4e7090f/lib/python3.9/site-packages
 * Debugger is active!
 * Debugger PIN: 876-963-074
^C^jsirois@gill /tmp/pex/issues/1172 $

So … I’m going to keep this as question / answered and closed. It’s still the case that no zipapp works with Flask but Pex (upon next release) provides a workaround.

I’m going to close this issue as answered since Pex fails just like a standard zipapp but also gives you a workaround with --unzip.