2

For the program I am making, I need to be able to send POST requests to the local server in order to control the game. I am using Flask to run all of this.

The app.py contains the Flask code that sets up the server and receives requests. When the app.py is outside any folders and simply in my Desktop it works just fine. When in the folders, the organization of which is shown below, the page does not work, and gives the 404 error. And when I go to the localhost address it tells me the URL cannot be found.

I outline the problem in more detail below. I included the folder organization, errors I receive in terminal and the server, how I run the code, and what code I have written in each file. I am not sure what is causing the problem.

  1. My files are organized as follows:
game/
  game.py
  app/
    __init__.py
    app.py
  1. When I run the program in the terminal, I cd into the app folder, and I enter the following commands in the command line:

    • export FLASK_APP=game.py
    • flask run
  2. This is what is printed in the terminal when I go to the localhost which the app.py is supposed to create. I bolded where it says that it does not exist:

     * Debug mode: off
     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    127.0.0.1 - - [26/Dec/2019 23:29:28] "GET / HTTP/1.1" 404 -
    
  3. On the localhost webpage, I get the following error:

    "Not Found The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again."

  4. File content:

    • game.py
    from app import app
    
    • __init__.py
    from flask import Flask
    
    app = Flask(__name__)
    
    • app.py
    from flask import Flask, request 
    
    app = Flask(__name__) #create the Flask app
    
    @app.route('/', methods=['POST','GET'])
    def form():
        if request.method == 'POST':
            concentrated = request.form.get('concentrated')
            return '''The person is concentrated? {}'''.format(concentrated)
    
         return '''<form method="POST">
            Concentrated <input type="text" name="concentrated">
            <input type="submit">
            </form>'''
    
    
    if __name__ == '__main__':
        app.run(debug=True, port=5000)
    

I looked at this question, however it does not seem to help in my situation: Why does localhost:5000 not work in Flask?

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
lna21
  • 79
  • 1
  • 9
  • You seem to have duplicate instantiations of a Flask app, one in `__init__.py` and one in app.py. You only need one, the one in app.py. Also, you don't need the `app.run` in app.py if you are using the `flask` CLI tool. – Gino Mempin Dec 27 '19 at 05:11
  • @GinoMempin could I just delete the __init__.py file or leave it empty then? – lna21 Dec 27 '19 at 05:14
  • Try leaving it empty. You need it to exist so that app (the folder) gets treated as a package. But leave it blank like the default way of creating Python packages. I think the app in `__init.py__` is shadowing the app in app.py, and that one has no definition of a root (/) route, which is why you get the error. – Gino Mempin Dec 27 '19 at 05:18
  • Please don't edit the code as you're solving it. Potential helpers and future readers should be able to reproduce the same problem, so that comments and answers will make sense. If you solved it, and no one posted an answer yet, post it as an answer instead. – Gino Mempin Dec 27 '19 at 05:21

2 Answers2

3

It looks like the accepted answer has already solved your problem, but I wanted to explain the cause of the original problem and offer my own solution that does not use import * (see Why is “import *” bad? and the PEP8 guidelines on imports that says "Wildcard imports (from <module> import *) should be avoided, as they make it unclear which names are present in the namespace, confusing both readers and many automated tools.").

The Problem

Given this:

game
├── app
│   ├── __init__.py  # instantiates app = Flask(__name__)
│   └── app.py       # also instantiates app = Flask(__name__) 
└── game.py

The app folder here is treated as a package because of the __init__.py file (see the Packages section of the Python docs). The __init__.py can just be empty but if you put some initialization code in there (like the instantiation of the app Flask instance), it will be used when Python imports the app package.

You can try it by hacking into the Flask config and adding a "whoami" attribute:

app/__init__.py

app = Flask(__name__)
app.config.update({"whoami": "In app/__init__.py"})

app/app.py

app = Flask(__name__)  
app.config.update({"whoami": "In app/app.py"})

# rest of your code

game.py

from app import app

print(app.config["whoami"])

run

(running it from the game folder)

game$ export FLASK_APP=game.py
game$ flask run
 * Serving Flask app "game.py"
...
In app/__init__.py
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Notice that the imported app is the one from __init__.py and it does not contain the method form, which should have defined the route for the / URL. That is why when you try to access http://127.0.0.1:5000/, Flask will raise an error that the requested URL (/) was not found.

This behavior is similar to what is called "shadowing", where the app in __init__.py hides the app in app.py. In fact, the app in app.py is never used here.

The Solution

As I mentioned in the comments, just keep the __init__.py file empty. Its main purpose (for your case) is just to tell Python that the app folder is actually a package, to allow importing like from app import app.

app/init.py

# leave this empty

app/app.py

from flask import Flask, request

app = Flask(__name__)  #create the Flask app
app.config.update({"whoami": "In app/app.py"})

@app.route('/', methods=['POST', 'GET'])
def form():
    if request.method == 'POST':
        concentrated = request.form.get('concentrated')
        return '''The person is concentrated? {}'''.format(concentrated)
    elif request.method == 'GET':
        return '''<form method="POST">
        Concentrated <input type="text" name="concentrated">
        <input type="submit">
        </form>'''

if __name__ == '__main__':
    app.run(debug=True, port=5000)

game.py

from app.app import app

print(app.config["whoami"])

run

(running it from the game folder)

game$ export FLASK_APP=game.py
game$ flask run
 * Serving Flask app "game.py"
...
In app/app.py
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [28/Dec/2019 09:23:05] "GET / HTTP/1.1" 200 -

Notice four things here.

  1. The app/__init__.py is now empty.
  2. The import statement in game.py is changed. It now reads as "from the app module of the app package, import the app instance". The app folder is the "app package", the app.py file is the "app module", and the app = Flask(__name__) is the "app instance". This is a typical way of importing stuff in Python: from package.module import something. If you get confused with all the "app", you might want to rename some of them.
  3. Printing the "whoami" attribute now correctly shows that the app instance is the one from app/app.py, which is the one with your actual route methods.
  4. I changed the two return statements in your form method into one for the GET request and one for the POST request, just to make it explicit.

Now when you go to http://127.0.0.1:5000/, it should correct work now for the / URL.

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
0

In app/__init__.py:

from flask import Flask

app = Flask(__name__)

from .app import *

In app.py:

from flask import Flask, request 

from app import app

@app.route('/', methods=['POST','GET'])
def form():
  if request.method == 'POST':
      concentrated = request.form.get('concentrated')
      return '''The person is concentrated? {}'''.format(concentrated)

     return '''<form method="POST">
      Concentrated <input type="text" name="concentrated">
      <input type="submit">
      </form>'''

In game.py, it should be:

from app import app

if __name__ == '__main__':
    app.run(debug=True, port=5000)

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
aman kumar
  • 3,086
  • 1
  • 17
  • 24
  • While this works, using `import *` is unnecessary and isn't good practice. See [Why is "import *" bad?](https://stackoverflow.com/q/2386714/2745495) and the [PEP8 guidelines on imports](https://www.python.org/dev/peps/pep-0008/#imports) that says "_Wildcard imports (`from import *)` should be avoided, as they make it unclear which names are present in the namespace, confusing both readers and many automated tools._"). – Gino Mempin Dec 28 '19 at 01:41