pallets / flask

The Python micro framework for building web applications.
https://flask.palletsprojects.com
BSD 3-Clause "New" or "Revised" License
67.5k stars 16.14k forks source link

Document behaviour of __init__ in cli.prepare_import() #5512

Closed Visgean closed 2 months ago

Visgean commented 2 months ago

The code in cli is a bit confusing: if you have an init file in the project it causes the cli to step out of the directory and import it from outside the directory.

E.h. I was working in directory /Users/visgean/p/social-flask/chapter2/models_app and the flask run command tried to import the app as chapter2.models_app.app, which did not work:

Error: While importing 'chapter2.models_app.app', an ImportError was raised:

I had to dig into the code to see that the solution is to delete the init file, apparently i am not the only one: https://stackoverflow.com/questions/70835630/while-importing-myapp-app-an-import-error-was-raised

I think this feature is a bit undcomented and to be honest I am not sure what the goal is. If I run flask run in a directory I dont want it to work at all with the parent directory. E.g. flask should only be aware of the current directory.

Proposed fixes:

davidism commented 2 months ago

I'm not sure why this is unexpected. If you're in the middle of a package, and were to start python, your imports in your modules would break as the python path would be incorrect. Instead, you'd need to get to the folder containing your package, because all your imports are rooted there. Flask does this for you. If we removed this, people would still get errors if they created incorrect init files or were in the wrong directory.

Visgean commented 2 months ago

Generally in Unix you want the command line to work only with the folder you are in or the children, you dont want the programs to randomly go up the folder tree.

Instead, you'd need to get to the folder containing your package, because all your imports are rooted there

That depends on the package. My imports were for example not rooted at the package that flask thinks is a root, it worked with normal python way of running python but not with CLI.

In other words if I run a python script in directory X I expect the directory to be there in sys.path which is currently not happening.

davidism commented 2 months ago

Generally in Unix you want the command line to work only with the folder you are in or the children, you dont want the programs to randomly go up the folder tree.

Plenty of tools search up the tree to try to find the root. For example, git, poetry, and tox.

I'd need to see your package then, it does not sound like a standard layout for a Python project. It sounds like you're describing the following:

top/
  project/
    __init__.py
    app/  # current directory
      __init__.py  # app defined here (or somewhere under here)

In that case, you'd import your app like from project.app import app or similar; flask -A project.app run, etc. If somehow from app import app works directly, then the layout doesn't make sense, why is the app subpackage inside the project package if it can't import anything from project? Or if it can, that suggests you're directly messing with sys.path, which is an antipattern. Either app is under package and should be imported as such, or it's not actually part of package and should be separate.

You're welcome to post what your layout actually is, it sounds like you're following a book or tutorial, but I have a strong feeling something is non-standard about it even if it's not exactly what I guessed.

Visgean commented 2 months ago

Overall I agree with you that the project layout that I had did not make sense (it was a result of moving some files around without moving the init files). But I think having an explicit message that this is happening would be better.