Skip to content

Commit 8e55ff7

Browse files
ethanwharrislexierule
authored andcommitted
[App] Fix environment check with command redirection (#16883)
1 parent d4c5ff3 commit 8e55ff7

File tree

3 files changed

+74
-8
lines changed

3 files changed

+74
-8
lines changed

src/lightning_app/cli/lightning_cli.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,21 @@ def main() -> None:
7676
# Check environment and versions if not in the cloud and not testing
7777
is_testing = bool(int(os.getenv("LIGHTING_TESTING", "0")))
7878
if not is_testing and "LIGHTNING_APP_STATE_URL" not in os.environ:
79-
# Enforce running in PATH Python
80-
_check_environment_and_redirect()
81-
82-
# Check for newer versions and upgrade
83-
_check_version_and_upgrade()
79+
try:
80+
# Enforce running in PATH Python
81+
_check_environment_and_redirect()
82+
83+
# Check for newer versions and upgrade
84+
_check_version_and_upgrade()
85+
except SystemExit:
86+
raise
87+
except Exception:
88+
# Note: We intentionally ignore all exceptions here so that we never panic if one of the above calls fails.
89+
# If they fail for some reason users should still be able to continue with their command.
90+
click.echo(
91+
"We encountered an unexpected problem while checking your environment."
92+
"We will still proceed with the command, however, there is a chance that errors may occur."
93+
)
8494

8595
# 1: Handle connection to a Lightning App.
8696
if len(sys.argv) > 1 and sys.argv[1] in ("connect", "disconnect", "logout"):

src/lightning_app/utilities/cli_helpers.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import json
1717
import os
1818
import re
19-
import shutil
2019
import subprocess
2120
import sys
2221
from typing import Dict, Optional
@@ -323,7 +322,14 @@ def _check_environment_and_redirect():
323322
If not, this utility tries to redirect the ``lightning`` call to the environment executable (prompting the user to
324323
install lightning for them there if needed).
325324
"""
326-
env_executable = os.path.realpath(shutil.which("python"))
325+
process = subprocess.run(
326+
["python", "-c", "import sys; print(sys.executable)"],
327+
capture_output=True,
328+
env=os.environ,
329+
check=True,
330+
)
331+
332+
env_executable = os.path.realpath(process.stdout.decode().strip())
327333
sys_executable = os.path.realpath(sys.executable)
328334

329335
# on windows, the extension might be different, where one uses `.EXE` and the other `.exe`

tests/tests_app/utilities/test_cli_helpers.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1+
import os
2+
import sys
13
from unittest.mock import Mock, patch
24

35
import arrow
46
import pytest
57

68
import lightning_app
7-
from lightning_app.utilities.cli_helpers import _arrow_time_callback, _format_input_env_variables, _get_newer_version
9+
from lightning_app.utilities.cli_helpers import (
10+
_arrow_time_callback,
11+
_check_environment_and_redirect,
12+
_format_input_env_variables,
13+
_get_newer_version,
14+
)
815

916

1017
def test_format_input_env_variables():
@@ -111,3 +118,46 @@ def test_get_newer_version(mock_requests, releases, current_version, newer_versi
111118

112119
_get_newer_version.cache_clear()
113120
assert _get_newer_version() == newer_version
121+
122+
123+
@patch("lightning_app.utilities.cli_helpers._redirect_command")
124+
def test_check_environment_and_redirect(mock_redirect_command, tmpdir, monkeypatch):
125+
# Ensure that the test fails if it tries to redirect
126+
mock_redirect_command.side_effect = RuntimeError
127+
128+
# Test normal executable on the path
129+
# Ensure current executable is on the path
130+
monkeypatch.setenv("PATH", f"{os.path.dirname(sys.executable)}")
131+
132+
assert _check_environment_and_redirect() is None
133+
134+
# Test executable on the path with redirect
135+
fake_python_path = os.path.join(tmpdir, "python")
136+
137+
os.symlink(sys.executable, fake_python_path)
138+
139+
monkeypatch.setenv("PATH", f"{tmpdir}")
140+
assert _check_environment_and_redirect() is None
141+
142+
os.remove(fake_python_path)
143+
144+
descriptor = os.open(
145+
fake_python_path,
146+
flags=(
147+
os.O_WRONLY # access mode: write only
148+
| os.O_CREAT # create if not exists
149+
| os.O_TRUNC # truncate the file to zero
150+
),
151+
mode=0o777,
152+
)
153+
154+
with open(descriptor, "w") as f:
155+
f.writelines(
156+
[
157+
"#!/bin/bash\n",
158+
f'{sys.executable} "$@"',
159+
]
160+
)
161+
162+
monkeypatch.setenv("PATH", f"{tmpdir}")
163+
assert _check_environment_and_redirect() is None

0 commit comments

Comments
 (0)