Search code examples
pythonpython-3.xheroku

Heroku won't deploy my Python code, failure to obtain "temp/build" file


I am trying to deploy a test application. My current code is a single file named setup.py and contains the following:

from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread

clients = {}
addresses = {}

HOST = ''
PORT = 3300
BUFFSIZ = 1024
ADDR = (HOST, PORT)
SERVER = socket(AF_INET, SOCK_STREAM)
SERVER.bind(ADDR)

def accept_incoming_connections():
    while True:
        client, client_address = SERVER.accept()
        print("%s:%s has connected." % client_address)
        client.send(bytes("Greetings! type your name and press enter!", "utf8"))
        addresses[client] = client_address
        Thread(target = handle_client, args=(client,)).start()
def handle_client(client):  # Takes client socket as argument.
    """Handles a single client connection."""
    name = client.recv(BUFFSIZ).decode("utf8")
    welcome = 'Welcome %s! If you ever want to quit, type {quit} to exit.' % name
    client.send(bytes(welcome, "utf8"))
    msg = "%s has joined the chat!" % name
    broadcast(bytes(msg, "utf8"))
    clients[client] = name
    while True:
        msg = client.recv(BUFFSIZ)
        if msg != bytes("{quit}", "utf8"):
            broadcast(msg, name+": ")
        else:
            client.send(bytes("{quit}", "utf8"))
            client.close()
            del clients[client]
            broadcast(bytes("%s has left the chat." % name, "utf8"))
            break

def broadcast(msg, prefix=""):
    """Broadcasts a message to all the clients."""
    for sock in clients:
        sock.send(bytes(prefix, "utf8")+msg)
if __name__ == "__main__":
    SERVER.listen(5)  # Listens for 5 connections at max.
    print("Waiting for connection...")
    ACCEPT_THREAD = Thread(target=accept_incoming_connections)
    ACCEPT_THREAD.start()  # Starts the infinite loop.
    ACCEPT_THREAD.join()
    SERVER.close()

It is 99% test code from a page I found online for making a simple chat application, it will later be modified much more if I can get it to work on Heroku. The commands I have run are as follows:

> heroku login
> git init
> git add .
> git commit -m "initial commit"
> heroku create
> heroku git:remote -a myProjectName
> git push heroku master

The build log shows the following:

-----> Building on the Heroku-20 stack
-----> Using buildpack: heroku/python
-----> Python app detected
-----> No Python version was specified. Using the buildpack default: python-3.9.6
       To use a different version, see: https://devcenter.heroku.com/articles/python-runtimes
cp: cannot stat '/tmp/build_7a00c31d/requirements.txt': No such file or directory
-----> Installing python-3.9.6
-----> Installing pip 20.2.4, setuptools 47.1.1 and wheel 0.36.2
-----> Installing SQLite3
-----> Installing requirements with pip
       Obtaining file:///tmp/build_7a00c31d (from -r /tmp/build_7a00c31d/requirements.txt (line 1))

After that line it hangs infinitely or times out and gives me "build failed, see more information at the build log" with a link that directs me to that file.


Solution

  • There are a few issues here.

    The immediate issue is that setup.py means something very specific in the Python ecosystem and Heroku assumes that it can do pip install -e . if this file is present and there is no requirements.txt or Pipfile.

    Rename your file to anything else (e.g. server.py), add a requirements.txt or Pipfile and Pipfile.lock or compliant setup.py defining your dependencies, and commit.

    You will probably also need a Procfile. Since you are expecting incoming requests you'll need to define a web process (they're the only ones that can receive traffic from the Internet), e.g. something like this if your new file is called server.py:

    web: python server.py
    

    You will also need to stop hard-coding the port you listen on and instead use the value Heroku provides via the PORT environment variable, e.g. something like this:

    import os
    
    PORT = os.getenv("PORT", default=3300)
    

    Heroku will route traffic coming in on ports 80 or 443 to your application automatically.