Any Ideas For Running Python Code on the Web?

Question:
So, I’m working on a thing that allows you to run git repos on the web by inputing a URL, but if I put an input() into the python repo file, it waits for me to input something into the Replit IDE console, and I’m not sure how to make it do so on the web. Any ideas?
Repl link:
Repl is private, here’s code:

import os
import subprocess
import shutil
from flask import Flask, render_template, request
from multiprocessing import Process, Queue

app = Flask(__name__)

def run_code_in_isolation(q, github_repo, base_env_dir, persistent_dir):
    repo_name = github_repo.split('/')[-1]
    repo_url = f'{github_repo}.git'
    env_dir = os.path.join(persistent_dir, f'env_{repo_name}')
    repo_env_bin = os.path.join(env_dir, 'bin')
    repo_dir = os.path.join(persistent_dir, repo_name)

    # Clean up if the directory already exists
    if os.path.exists(env_dir):
        shutil.rmtree(env_dir)
    if os.path.exists(repo_dir):
        shutil.rmtree(repo_dir)

    try:
        # Clone the git repository with a timeout
        subprocess.run(['git', 'clone', '-v', repo_url, repo_dir], check=True, timeout=300)
        print(f'Cloned repository {repo_name} to {repo_dir}')
        
        # Copy the base virtual environment for the repo
        shutil.copytree(base_env_dir, env_dir)
        print(f'Copied base virtual environment for {repo_name} to {env_dir}')

        pip_executable = os.path.join(repo_env_bin, 'pip')
        python_executable = os.path.join(repo_env_bin, 'python')

        # Change to the repository directory
        os.chdir(repo_dir)

        # Install requirements if requirements.txt exists in the repo
        if os.path.exists('requirements.txt'):
            subprocess.run([pip_executable, 'install', '-r', 'requirements.txt'], check=True, timeout=300)
            print(f'Installed requirements for {repo_name}')

        # Assume the main script is named 'main.py'
        main_py_path = os.path.join(repo_dir, 'main.py')
        print(f"Running python file at {main_py_path}...")
        process = subprocess.run([python_executable, main_py_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=300)
        output = process.stdout
        error = process.stderr
        return_code = process.returncode
        print("Process finished with return code:", return_code)
    except subprocess.CalledProcessError as e:
        print(f"Git clone failed with the following error:\n{e.stderr}")
        q.put(("Failed to clone the repository.", "", e.returncode))
        return
    except subprocess.TimeoutExpired as e:
        print("The operation timed out. Error: " + str(e))
        q.put(("The operation timed out. Error: " + str(e), "", 1))
        return
    except Exception as e:
        print(f"An exception occurred: {str(e)}")
        q.put((f"An exception occurred: {str(e)}", "", 1))
        return

    q.put((output, error, return_code))

@app.route('/run', methods=['POST'])
def run_code():
    # GitHub repo form input
    github_repo = request.form['github_repo']

    # Set the base environment directory
    base_env_dir = os.path.abspath('base_env')

    # Define the persistent directory
    persistent_dir = os.path.abspath('persistent_workspace')

    # Make sure the persistent directory exists
    os.makedirs(persistent_dir, exist_ok=True)

    # Create a Multiprocessing queue
    q = Queue()

    # Start a new Process for running the code
    p = Process(target=run_code_in_isolation, args=(q, github_repo, base_env_dir, persistent_dir))
    p.start()

    # Wait for the process to finish
    p.join()
    output, error, return_code = q.get()

    # Return the output to the client
    if return_code != 0:
        return render_template('output.html', output=f"An error occurred: {error}")
    return render_template('output.html', output=output)

@app.route('/')
def index():
    return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=False, host='0.0.0.0', port=8080)

Here’s index.html:

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>GitHub Code Runner</title>
</head>
<body>
    <h1>GitHub Code Runner</h1>
    <form action="/run" method="post">
        <label for="github_repo">GitHub Repository:</label>
        <input type="text" id="github_repo" name="github_repo" required>
        <button type="submit">Run Code</button>
    </form>
</body>
</html>

Here’s output.html:

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>GitHub Code Runner</title>
</head>
<body>
  <h1>GitHub Code Runner</h1>
	{{ output }}
</body>
</html>

I think you could just do

def input(stdin): # Redefine input function
  return "Hello, world"

But I want the user to be able to input to the web console, not just redefine it.

Sandboxed app:

import requests
def input(stdin): # Redefine input function
  requests.get("localhost:8080/startinput")
  while True:
    v = requests.get("localhost:8080/input").text
    if v == "":
      continue
    else:
      return v

And then you could add this code to the flask app:

currentInput = ""
@app.route('/giveinput')
def giveinput():
   global currentInput
   currentInput = request.args.get("text")
  return "done"
   
@app.route('/input')
def getinput():
  global currentInput
  if currentInput == "":
    return ""
  else:
    v = currentInput
    currentInput = ""
    return v

In output.html, you could add:

<input id="stdin" placeholder="Type input here">
<button onclick='send()'>Send input</button>
<script>
async function send() {
var v = document.getElementById("stdin").value
await fetch("/giveinput?text=" + v)
}
</script>

Hope this helps!

1 Like