Skip to content

Commit 4e67d23

Browse files
authored
Merge pull request kivy#1856 from JonasT/improve_syspython_find
Fix locating system python when it's not in $PATH (weird but happens, apparently)
2 parents 20d9258 + 6297c52 commit 4e67d23

File tree

1 file changed

+48
-5
lines changed

1 file changed

+48
-5
lines changed

pythonforandroid/pythonpackage.py

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535

3636
from io import open # needed for python 2
37+
import functools
3738
import os
3839
from pep517.envbuild import BuildEnvironment
3940
from pep517.wrappers import Pep517HookCaller
@@ -176,11 +177,23 @@ def _get_system_python_executable():
176177

177178
def python_binary_from_folder(path):
178179
def binary_is_usable(python_bin):
180+
""" Helper function to see if a given binary name refers
181+
to a usable python interpreter binary
182+
"""
183+
184+
# Abort if path isn't present at all or a directory:
185+
if not os.path.exists(
186+
os.path.join(path, python_bin)
187+
) or os.path.isdir(os.path.join(path, python_bin)):
188+
return
189+
# We should check file not found anyway trying to run it,
190+
# since it might be a dead symlink:
179191
try:
180192
filenotfounderror = FileNotFoundError
181193
except NameError: # Python 2
182194
filenotfounderror = OSError
183195
try:
196+
# Run it and see if version output works with no error:
184197
subprocess.check_output([
185198
os.path.join(path, python_bin), "--version"
186199
], stderr=subprocess.STDOUT)
@@ -206,19 +219,26 @@ def binary_is_usable(python_bin):
206219
bad_candidates = []
207220
good_candidates = []
208221
ever_had_nonvenv_path = False
222+
ever_had_path_starting_with_prefix = False
209223
for p in os.environ.get("PATH", "").split(":"):
210224
# Skip if not possibly the real system python:
211225
if not os.path.normpath(p).startswith(
212226
os.path.normpath(search_prefix)
213227
):
214228
continue
215229

230+
ever_had_path_starting_with_prefix = True
231+
216232
# First folders might be virtualenv/venv we want to avoid:
217233
if not ever_had_nonvenv_path:
218234
sep = os.path.sep
219-
if ("system32" not in p.lower() and "usr" not in p) or \
220-
{"home", ".tox"}.intersection(set(p.split(sep))) or \
221-
"users" in p.lower():
235+
if (
236+
("system32" not in p.lower() and
237+
"usr" not in p and
238+
not p.startswith("/opt/python")) or
239+
{"home", ".tox"}.intersection(set(p.split(sep))) or
240+
"users" in p.lower()
241+
):
222242
# Doesn't look like bog-standard system path.
223243
if (p.endswith(os.path.sep + "bin") or
224244
p.endswith(os.path.sep + "bin" + os.path.sep)):
@@ -230,14 +250,37 @@ def binary_is_usable(python_bin):
230250

231251
good_candidates.append(p)
232252

253+
# If we have a bad env with PATH not containing any reference to our
254+
# real python (travis, why would you do that to me?) then just guess
255+
# based from the search prefix location itself:
256+
if not ever_had_path_starting_with_prefix:
257+
# ... and yes we're scanning all the folders for that, it's dumb
258+
# but i'm not aware of a better way: (@JonasT)
259+
for root, dirs, files in os.walk(search_prefix, topdown=True):
260+
for name in dirs:
261+
bad_candidates.append(os.path.join(root, name))
262+
263+
# Sort candidates by length (to prefer shorter ones):
264+
def candidate_cmp(a, b):
265+
return len(a) - len(b)
266+
good_candidates = sorted(
267+
good_candidates, key=functools.cmp_to_key(candidate_cmp)
268+
)
269+
bad_candidates = sorted(
270+
bad_candidates, key=functools.cmp_to_key(candidate_cmp)
271+
)
272+
233273
# See if we can now actually find the system python:
234274
for p in good_candidates + bad_candidates:
235275
result = python_binary_from_folder(p)
236276
if result is not None:
237277
return result
238278

239-
raise RuntimeError("failed to locate system python in: " +
240-
sys.real_prefix)
279+
raise RuntimeError(
280+
"failed to locate system python in: {}"
281+
" - checked candidates were: {}, {}"
282+
.format(sys.real_prefix, good_candidates, bad_candidates)
283+
)
241284

242285

243286
def get_package_as_folder(dependency):

0 commit comments

Comments
 (0)