Issue #1761 - Enable use of Tauthon instead of Python 2.7 at build

Make essential Tauthon's builtins and modules available in sandboxes, without
disrupting building with Python 2.7.

1. Allow new builtins and modules. "__build_class__" is for
building... new-style classes (to handle the new metaclass syntax imported from
3.x). "_oserror" is necessary because of internal changes to raise errors
deriving from OSError (which are reported as IOError if not caught).
2. Look for modules and packages in the right places.

This was tested on FreeBSD, and should work out of the box on Linux.
This commit is contained in:
Olivier Certner 2021-04-07 15:20:32 +02:00 • committed by roytam1
commit d094352ddf
4 changed files with 30 additions and 16 deletions

View file

@ -192,8 +192,9 @@ class ConfigureSandbox(dict):
b: __builtins__[b] b: __builtins__[b]
for b in ('None', 'False', 'True', 'int', 'bool', 'any', 'all', 'len', for b in ('None', 'False', 'True', 'int', 'bool', 'any', 'all', 'len',
'list', 'tuple', 'set', 'dict', 'isinstance', 'getattr', 'list', 'tuple', 'set', 'dict', 'isinstance', 'getattr',
'hasattr', 'enumerate', 'range', 'zip') 'hasattr', 'enumerate', 'range', 'zip', '__build_class__')
}, __import__=forbidden_import, str=unicode) if b in __builtins__},
__import__=forbidden_import, str=unicode)
# Expose a limited set of functions from os.path # Expose a limited set of functions from os.path
OS = ReadOnlyNamespace(path=ReadOnlyNamespace(**{ OS = ReadOnlyNamespace(path=ReadOnlyNamespace(**{

View file

@ -115,7 +115,10 @@ class Sandbox(dict):
def __init__(self, context, builtins=None, finder=default_finder): def __init__(self, context, builtins=None, finder=default_finder):
"""Initialize a Sandbox ready for execution. """Initialize a Sandbox ready for execution.
""" """
self._builtins = builtins or self.BUILTINS self._builtins = ReadOnlyDict(
(builtins or self.BUILTINS).viewitems() |
{b: __builtins__[b] for b in ('__build_class__',)
if b in __builtins__}.viewitems())
dict.__setitem__(self, '__builtins__', self._builtins) dict.__setitem__(self, '__builtins__', self._builtins)
assert isinstance(self._builtins, ReadOnlyDict) assert isinstance(self._builtins, ReadOnlyDict)

View file

@ -65,6 +65,7 @@ ImportError exception, it is silently ignored.
import sys import sys
import os import os
import platform
try: try:
import __builtin__ as builtins import __builtin__ as builtins
@ -85,11 +86,14 @@ USER_SITE = None
USER_BASE = None USER_BASE = None
_is_64bit = (getattr(sys, 'maxsize', None) or getattr(sys, 'maxint')) > 2**32 _is_64bit = (getattr(sys, 'maxsize', None) or getattr(sys, 'maxint')) > 2**32
_is_tauthon = platform.python_implementation() == "Tauthon"
_is_pypy = hasattr(sys, 'pypy_version_info') _is_pypy = hasattr(sys, 'pypy_version_info')
_is_jython = sys.platform[:4] == 'java' _is_jython = sys.platform[:4] == 'java'
if _is_jython: if _is_jython:
ModuleType = type(os) ModuleType = type(os)
_python_libdir = "tauthon" if _is_tauthon else "python"
def makepath(*paths): def makepath(*paths):
dir = os.path.join(*paths) dir = os.path.join(*paths)
if _is_jython and (dir == '__classpath__' or if _is_jython and (dir == '__classpath__' or
@ -228,16 +232,16 @@ def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_pre
else: # any other Python distros on OSX work this way else: # any other Python distros on OSX work this way
sitedirs = [os.path.join(prefix, "lib", sitedirs = [os.path.join(prefix, "lib",
"python" + sys.version[:3], "site-packages")] _python_libdir + sys.version[:3], "site-packages")]
elif os.sep == '/': elif os.sep == '/':
sitedirs = [os.path.join(prefix, sitedirs = [os.path.join(prefix,
"lib", "lib",
"python" + sys.version[:3], _python_libdir + sys.version[:3],
"site-packages"), "site-packages"),
os.path.join(prefix, "lib", "site-python"), os.path.join(prefix, "lib", "site-python"),
os.path.join(prefix, "python" + sys.version[:3], "lib-dynload")] os.path.join(prefix, _python_libdir + sys.version[:3], "lib-dynload")]
lib64_dir = os.path.join(prefix, "lib64", "python" + sys.version[:3], "site-packages") lib64_dir = os.path.join(prefix, "lib64", _python_libdir + sys.version[:3], "site-packages")
if (os.path.exists(lib64_dir) and if (os.path.exists(lib64_dir) and
os.path.realpath(lib64_dir) not in [os.path.realpath(p) for p in sitedirs]): os.path.realpath(lib64_dir) not in [os.path.realpath(p) for p in sitedirs]):
if _is_64bit: if _is_64bit:
@ -252,15 +256,15 @@ def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_pre
pass pass
# Debian-specific dist-packages directories: # Debian-specific dist-packages directories:
sitedirs.append(os.path.join(prefix, "local/lib", sitedirs.append(os.path.join(prefix, "local/lib",
"python" + sys.version[:3], _python_libdir + sys.version[:3],
"dist-packages")) "dist-packages"))
if sys.version[0] == '2': if sys.version[0] == '2':
sitedirs.append(os.path.join(prefix, "lib", sitedirs.append(os.path.join(prefix, "lib",
"python" + sys.version[:3], _python_libdir + sys.version[:3],
"dist-packages")) "dist-packages"))
else: else:
sitedirs.append(os.path.join(prefix, "lib", sitedirs.append(os.path.join(prefix, "lib",
"python" + sys.version[0], _python_libdir + sys.version[0],
"dist-packages")) "dist-packages"))
sitedirs.append(os.path.join(prefix, "lib", "dist-python")) sitedirs.append(os.path.join(prefix, "lib", "dist-python"))
else: else:
@ -583,9 +587,9 @@ def virtual_install_main_packages():
elif sys.platform == 'win32' and os.sep == '\\': elif sys.platform == 'win32' and os.sep == '\\':
paths = [os.path.join(sys.real_prefix, 'Lib'), os.path.join(sys.real_prefix, 'DLLs')] paths = [os.path.join(sys.real_prefix, 'Lib'), os.path.join(sys.real_prefix, 'DLLs')]
else: else:
paths = [os.path.join(sys.real_prefix, 'lib', 'python'+sys.version[:3])] paths = [os.path.join(sys.real_prefix, 'lib', _python_libdir + sys.version[:3])]
hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below
lib64_path = os.path.join(sys.real_prefix, 'lib64', 'python'+sys.version[:3]) lib64_path = os.path.join(sys.real_prefix, 'lib64', _python_libdir + sys.version[:3])
if os.path.exists(lib64_path): if os.path.exists(lib64_path):
if _is_64bit: if _is_64bit:
paths.insert(0, lib64_path) paths.insert(0, lib64_path)
@ -602,7 +606,7 @@ def virtual_install_main_packages():
# This is a non-multiarch aware Python. Fallback to the old way. # This is a non-multiarch aware Python. Fallback to the old way.
arch = sys.platform arch = sys.platform
plat_path = os.path.join(sys.real_prefix, 'lib', plat_path = os.path.join(sys.real_prefix, 'lib',
'python'+sys.version[:3], _python_libdir + sys.version[:3],
'plat-%s' % arch) 'plat-%s' % arch)
if os.path.exists(plat_path): if os.path.exists(plat_path):
paths.append(plat_path) paths.append(plat_path)

View file

@ -44,13 +44,14 @@ if sys.version_info < (2, 6):
print('ERROR: this script requires Python 2.6 or greater.') print('ERROR: this script requires Python 2.6 or greater.')
sys.exit(101) sys.exit(101)
import platform
try: try:
basestring basestring
except NameError: except NameError:
basestring = str basestring = str
py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1]) is_tauthon = platform.python_implementation() == "Tauthon"
is_jython = sys.platform.startswith('java') is_jython = sys.platform.startswith('java')
is_pypy = hasattr(sys, 'pypy_version_info') is_pypy = hasattr(sys, 'pypy_version_info')
is_win = (sys.platform == 'win32' and os.sep == '\\') is_win = (sys.platform == 'win32' and os.sep == '\\')
@ -59,6 +60,9 @@ is_msys2 = (sys.platform == 'win32' and os.sep == '/')
is_darwin = (sys.platform == 'darwin') is_darwin = (sys.platform == 'darwin')
abiflags = getattr(sys, 'abiflags', '') abiflags = getattr(sys, 'abiflags', '')
py_version = '%s%s.%s' % ("tauthon" if is_tauthon else "python",
sys.version_info[0], sys.version_info[1])
user_dir = os.path.expanduser('~') user_dir = os.path.expanduser('~')
if is_win: if is_win:
default_storage_dir = os.path.join(user_dir, 'virtualenv') default_storage_dir = os.path.join(user_dir, 'virtualenv')
@ -121,7 +125,7 @@ REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
'fnmatch', 'locale', 'encodings', 'codecs', 'fnmatch', 'locale', 'encodings', 'codecs',
'stat', 'UserDict', 'readline', 'copy_reg', 'types', 'stat', 'UserDict', 'readline', 'copy_reg', 'types',
're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile', 're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
'zlib'] 'zlib', 'platform', 'string']
REQUIRED_FILES = ['lib-dynload', 'config'] REQUIRED_FILES = ['lib-dynload', 'config']
@ -131,6 +135,8 @@ if majver == 2:
REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc']) REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
if minver >= 7: if minver >= 7:
REQUIRED_MODULES.extend(['_weakrefset']) REQUIRED_MODULES.extend(['_weakrefset'])
if is_tauthon:
REQUIRED_MODULES.extend(['_oserror'])
if is_msys2: if is_msys2:
REQUIRED_MODULES.extend(['functools']) REQUIRED_MODULES.extend(['functools'])
elif majver == 3: elif majver == 3: