Python: flask app can't find dependencies

I’m trying to set up a nix-shell to develop a Flask application, and I set up a minimal example that depends on flask and flask-restful. The relevant import statements are:

# nix_flask/
from flask import Flask
from flask_restful import Resource, Api

My shell.nix is:

with (import (builtins.fetchTarball {
  url = "";
}) { });

( python37.withPackages (ps: with ps; [ flask flask-restful ]) ).env

If I start the app with python directly, it works:

# server
FLASK_APP=nix_flask/ FLASK_ENV=development \
    python nix_flask/
# client
$ curl localhost:5000
{"hello": "world"}

But if I start it with flask run, it’s unable to find flask-restful:

# server
FLASK_APP=nix_flask/ FLASK_ENV=development \
    flask run
# client
$ curl localhost:5000
Traceback (most recent call last):
  File "/nix/store/...-python3.7-Flask-1.0.3/lib/python3.7/site-packages/flask/", line 236, in locate_app
  File "/path/to/nix-flask/nix_flask/", line 2, in <module>
    from flask_restful import Resource, Api
ModuleNotFoundError: No module named 'flask_restful'

My Nix knowledge outweighs my Python knowledge, and I’m not sure what I need to change to fix this (PYTHONPATH?). Does anyone know what I’m doing wrong?

Huh, can’t reproduce

$ nix-shell -E 'with (import (builtins.fetchTarball {
  url = "";
}) { }); (python37.withPackages(p: [ p.flask p.flask-restful ])).env' --run 'FLASK_APP=/tmp/ flask run'
 * Serving Flask app "/tmp/"
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on (Press CTRL+C to quit) - - [23/Mar/2020 21:02:00] "GET / HTTP/1.1" 200 -

Do you reproduce this with nix-shell --pure?

Ooh, interesting. It happens if you set FLASK_ENV=development but not otherwise.

  • when you set development flask env, it enabled debug and reloader
  • reloader is a stuff from werkzeug, which enables python files reloading. It assumes sys.argv[0] is python script
  • however, in Nix $out/bin/flask is a wrapper over python script, so it fails to reload Bash script as a python script
  • read here about why was that done for Nix: nixpkgs/wrap-python.nix at 83c0498f70066868fb2db2d839a48a30c58aceb8 · NixOS/nixpkgs · GitHub
  • the hotfix is to replace sys.argv[0] with path to python script in your Add a header:
    import sys
    import os.path
    sys.argv[0] = os.path.dirname(sys.argv[0]) + '/.flask-wrapped'

cc @FRidh, is this best we can do?

1 Like

This seems different from the argv[0] issue, since I’m not getting a SyntaxError (from trying to interpret a shell script as Python, as described in this issue), but rather an ImportError.

I tried the hotfix you suggested, but the problem remained the same.

1 Like

which means, my Nixpkgs is quite old… But now I can reproduce your issue (with your nixpkgs revision), and it works with my revision (and argv hack):

$ nix-shell -E '
with (import (builtins.fetchTarball {
  url = "";
}) { }); (python37.withPackages(p: [ p.flask p.flask-restful ])).env' --run 'FLASK_APP=/tmp/ FLASK_ENV=development flask run'

Maybe you can bisect git revisions from bea1a232c61 to 8746c77a383f5c and find out which one breaks reloader.

1 Like

This thread just got mentioned on Flask patch reversion causing breakage in development mode · Issue #72345 · NixOS/nixpkgs · GitHub which may be of interest.

1 Like