triflix commited on
Commit
8a0a337
·
verified ·
1 Parent(s): f531709

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -37
app.py CHANGED
@@ -15,51 +15,68 @@ app = FastAPI()
15
  @app.post("/execute/")
16
  def install_and_execute(request: ExecutionRequest):
17
  """
18
- Installs a specified pip package and then executes a provided Python script.
19
 
20
- This endpoint first uses pip to install the package named in the `package_name`
21
- field. It then writes the `script_content` to a temporary file and
22
- executes it using the same Python interpreter that is running the FastAPI
23
- application.
 
 
24
 
25
- The output from both the pip installation and the script execution is
26
- captured and returned in the JSON response. Any errors during the process
27
- are also captured and returned.
28
  """
29
- pip_output = ""
30
- script_output = ""
31
- error = ""
 
 
32
 
33
- try:
34
- # Execute the pip install command
35
- pip_output = subprocess.check_output(
36
- [sys.executable, "-m", "pip", "install", request.package_name],
37
- stderr=subprocess.STDOUT,
38
- text=True
39
- )
 
 
 
 
 
 
 
 
 
 
 
40
 
41
- # Create a temporary file with a .py extension to save the script content
42
- with tempfile.NamedTemporaryFile(delete=False, suffix=".py", mode='w') as temp_script:
43
- temp_script.write(request.script_content)
44
- temp_script_path = temp_script.name
45
 
46
- try:
47
- # Execute the Python script
 
 
 
 
 
48
  script_output = subprocess.check_output(
49
- [sys.executable, temp_script_path],
50
  stderr=subprocess.STDOUT,
51
- text=True
 
52
  )
53
- finally:
54
- # Clean up the temporary file
55
- os.remove(temp_script_path)
56
 
57
- except subprocess.CalledProcessError as e:
58
- # If any command fails, capture the output as an error
59
- error = e.output
60
 
61
- return {
62
- "pip_install_output": pip_output,
63
- "script_execution_output": script_output,
64
- "error_output": error
65
- }
 
15
  @app.post("/execute/")
16
  def install_and_execute(request: ExecutionRequest):
17
  """
18
+ Installs a package to a temporary directory and executes a Python script.
19
 
20
+ This endpoint addresses permission errors in restricted environments like
21
+ Hugging Face Spaces by:
22
+ 1. Creating a temporary directory for the request.
23
+ 2. Installing the specified pip package into this temporary directory using `pip install --target`.
24
+ 3. Setting the PYTHONPATH environment variable to include this directory.
25
+ 4. Executing the provided script, which can now import the installed package.
26
 
27
+ The temporary directory and its contents are automatically removed after the
28
+ request is complete.
 
29
  """
30
+ # Use a temporary directory that will be automatically cleaned up
31
+ with tempfile.TemporaryDirectory() as temp_dir:
32
+ pip_output = ""
33
+ script_output = ""
34
+ error = ""
35
 
36
+ try:
37
+ # 1. Install the package to the temporary directory
38
+ install_path = os.path.join(temp_dir, "packages")
39
+ os.makedirs(install_path)
40
+
41
+ pip_output = subprocess.check_output(
42
+ [
43
+ sys.executable,
44
+ "-m",
45
+ "pip",
46
+ "install",
47
+ request.package_name,
48
+ "--target",
49
+ install_path, # Install here
50
+ ],
51
+ stderr=subprocess.STDOUT,
52
+ text=True
53
+ )
54
 
55
+ # 2. Create a temporary file for the user's script
56
+ script_path = os.path.join(temp_dir, "script.py")
57
+ with open(script_path, 'w') as temp_script:
58
+ temp_script.write(request.script_content)
59
 
60
+ # 3. Prepare the environment for the script execution
61
+ # This ensures the script can find the package in `install_path`
62
+ exec_env = os.environ.copy()
63
+ # Add the install path to the Python Path
64
+ exec_env["PYTHONPATH"] = install_path + os.pathsep + exec_env.get("PYTHONPATH", "")
65
+
66
+ # 4. Execute the Python script using the modified environment
67
  script_output = subprocess.check_output(
68
+ [sys.executable, script_path],
69
  stderr=subprocess.STDOUT,
70
+ text=True,
71
+ env=exec_env # Use the modified environment
72
  )
 
 
 
73
 
74
+ except subprocess.CalledProcessError as e:
75
+ # If any command fails, capture its output as an error
76
+ error = e.output
77
 
78
+ return {
79
+ "pip_install_output": pip_output,
80
+ "script_execution_output": script_output,
81
+ "error_output": error
82
+ }