Skip to content

Commit 6297c52

Browse files
author
Jonas Thiem
committed
Fix for locating system python when it's not in $PATH for some reason
1 parent e409aeb commit 6297c52

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
@@ -172,11 +173,23 @@ def _get_system_python_executable():
172173

173174
def python_binary_from_folder(path):
174175
def binary_is_usable(python_bin):
176+
""" Helper function to see if a given binary name refers
177+
to a usable python interpreter binary
178+
"""
179+
180+
# Abort if path isn't present at all or a directory:
181+
if not os.path.exists(
182+
os.path.join(path, python_bin)
183+
) or os.path.isdir(os.path.join(path, python_bin)):
184+
return
185+
# We should check file not found anyway trying to run it,
186+
# since it might be a dead symlink:
175187
try:
176188
filenotfounderror = FileNotFoundError
177189
except NameError: # Python 2
178190
filenotfounderror = OSError
179191
try:
192+
# Run it and see if version output works with no error:
180193
subprocess.check_output([
181194
os.path.join(path, python_bin), "--version"
182195
], stderr=subprocess.STDOUT)
@@ -202,19 +215,26 @@ def binary_is_usable(python_bin):
202215
bad_candidates = []
203216
good_candidates = []
204217
ever_had_nonvenv_path = False
218+
ever_had_path_starting_with_prefix = False
205219
for p in os.environ.get("PATH", "").split(":"):
206220
# Skip if not possibly the real system python:
207221
if not os.path.normpath(p).startswith(
208222
os.path.normpath(search_prefix)
209223
):
210224
continue
211225

226+
ever_had_path_starting_with_prefix = True
227+
212228
# First folders might be virtualenv/venv we want to avoid:
213229
if not ever_had_nonvenv_path:
214230
sep = os.path.sep
215-
if ("system32" not in p.lower() and "usr" not in p) or \
216-
{"home", ".tox"}.intersection(set(p.split(sep))) or \
217-
"users" in p.lower():
231+
if (
232+
("system32" not in p.lower() and
233+
"usr" not in p and
234+
not p.startswith("/opt/python")) or
235+
{"home", ".tox"}.intersection(set(p.split(sep))) or
236+
"users" in p.lower()
237+
):
218238
# Doesn't look like bog-standard system path.
219239
if (p.endswith(os.path.sep + "bin") or
220240
p.endswith(os.path.sep + "bin" + os.path.sep)):
@@ -226,14 +246,37 @@ def binary_is_usable(python_bin):
226246

227247
good_candidates.append(p)
228248

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

235-
raise RuntimeError("failed to locate system python in: " +
236-
sys.real_prefix)
275+
raise RuntimeError(
276+
"failed to locate system python in: {}"
277+
" - checked candidates were: {}, {}"
278+
.format(sys.real_prefix, good_candidates, bad_candidates)
279+
)
237280

238281

239282
def get_package_as_folder(dependency):

0 commit comments

Comments
 (0)