pythoninfo: sync with master (#4843)
diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py
index 8b02933..4ce06e0 100644
--- a/Lib/test/pythoninfo.py
+++ b/Lib/test/pythoninfo.py
@@ -1,7 +1,8 @@
"""
-Collect various informations about Python to help debugging test failures.
+Collect various information about Python to help debugging test failures.
"""
from __future__ import print_function
+import errno
import re
import sys
import traceback
@@ -26,8 +27,8 @@
if value is None:
return
- if not isinstance(value, (int, long)):
- if not isinstance(value, basestring):
+ if not isinstance(value, int):
+ if not isinstance(value, str):
# convert other objects like sys.flags to string
value = str(value)
@@ -39,7 +40,7 @@
def get_infos(self):
"""
- Get informations as a key:value dictionary where values are strings.
+ Get information as a key:value dictionary where values are strings.
"""
return {key: str(value) for key, value in self.info.items()}
@@ -55,6 +56,14 @@
info_add(name, value)
+def copy_attr(info_add, name, mod, attr_name):
+ try:
+ value = getattr(mod, attr_name)
+ except AttributeError:
+ return
+ info_add(name, value)
+
+
def call_func(info_add, name, mod, func_name, formatter=None):
try:
func = getattr(mod, func_name)
@@ -68,6 +77,8 @@
def collect_sys(info_add):
attributes = (
+ '_framework',
+ 'abiflags',
'api_version',
'builtin_module_names',
'byteorder',
@@ -76,20 +87,28 @@
'flags',
'float_info',
'float_repr_style',
+ 'hash_info',
'hexversion',
- 'maxint',
+ 'implementation',
+ 'int_info',
'maxsize',
'maxunicode',
'path',
'platform',
'prefix',
+ 'thread_info',
'version',
'version_info',
'winver',
)
copy_attributes(info_add, sys, 'sys.%s', attributes)
+ call_func(info_add, 'sys.androidapilevel', sys, 'getandroidapilevel')
+ call_func(info_add, 'sys.windowsversion', sys, 'getwindowsversion')
+
encoding = sys.getfilesystemencoding()
+ if hasattr(sys, 'getfilesystemencodeerrors'):
+ encoding = '%s/%s' % (encoding, sys.getfilesystemencodeerrors())
info_add('sys.filesystem_encoding', encoding)
for name in ('stdin', 'stdout', 'stderr'):
@@ -129,26 +148,43 @@
def collect_locale(info_add):
import locale
- info_add('locale.encoding', locale.getpreferredencoding(True))
+ info_add('locale.encoding', locale.getpreferredencoding(False))
+
+
+def collect_builtins(info_add):
+ info_add('builtins.float.float_format', float.__getformat__("float"))
+ info_add('builtins.float.double_format', float.__getformat__("double"))
def collect_os(info_add):
import os
- attributes = ('name',)
- copy_attributes(info_add, os, 'os.%s', attributes)
+ def format_attr(attr, value):
+ if attr in ('supports_follow_symlinks', 'supports_fd',
+ 'supports_effective_ids'):
+ return str(sorted(func.__name__ for func in value))
+ else:
+ return value
- info_add("os.cwd", os.getcwd())
+ attributes = (
+ 'name',
+ 'supports_bytes_environ',
+ 'supports_effective_ids',
+ 'supports_fd',
+ 'supports_follow_symlinks',
+ )
+ copy_attributes(info_add, os, 'os.%s', attributes, formatter=format_attr)
+
+ call_func(info_add, 'os.cwd', os, 'getcwd')
call_func(info_add, 'os.uid', os, 'getuid')
call_func(info_add, 'os.gid', os, 'getgid')
call_func(info_add, 'os.uname', os, 'uname')
- if hasattr(os, 'getgroups'):
- groups = os.getgroups()
- groups = map(str, groups)
- groups = ', '.join(groups)
- info_add("os.groups", groups)
+ def format_groups(groups):
+ return ', '.join(map(str, groups))
+
+ call_func(info_add, 'os.groups', os, 'getgroups', formatter=format_groups)
if hasattr(os, 'getlogin'):
try:
@@ -160,6 +196,7 @@
else:
info_add("os.login", login)
+ call_func(info_add, 'os.cpu_count', os, 'cpu_count')
call_func(info_add, 'os.loadavg', os, 'getloadavg')
# Get environment variables: filter to list
@@ -190,7 +227,9 @@
)
for name, value in os.environ.items():
uname = name.upper()
- if (uname in ENV_VARS or uname.startswith(("PYTHON", "LC_"))
+ if (uname in ENV_VARS
+ # Copy PYTHON* and LC_* variables
+ or uname.startswith(("PYTHON", "LC_"))
# Visual Studio: VS140COMNTOOLS
or (uname.startswith("VS") and uname.endswith("COMNTOOLS"))):
info_add('os.environ[%s]' % name, value)
@@ -200,13 +239,20 @@
os.umask(mask)
info_add("os.umask", '%03o' % mask)
- try:
- cpu_count = os.sysconf('SC_NPROCESSORS_ONLN')
- except (AttributeError, ValueError):
- pass
- else:
- if cpu_count:
- info_add('os.sysconf(SC_NPROCESSORS_ONLN)', cpu_count)
+ if hasattr(os, 'getrandom'):
+ # PEP 524: Check if system urandom is initialized
+ try:
+ try:
+ os.getrandom(1, os.GRND_NONBLOCK)
+ state = 'ready (initialized)'
+ except BlockingIOError as exc:
+ state = 'not seeded yet (%s)' % exc
+ info_add('os.getrandom', state)
+ except OSError as exc:
+ # Python was compiled on a more recent Linux version
+ # than the current Linux kernel: ignore OSError(ENOSYS)
+ if exc.errno != errno.ENOSYS:
+ raise
def collect_readline(info_add):
@@ -216,7 +262,7 @@
return
def format_attr(attr, value):
- if isinstance(value, (int, long)):
+ if isinstance(value, int):
return "%#x" % value
else:
return value
@@ -224,6 +270,7 @@
attributes = (
"_READLINE_VERSION",
"_READLINE_RUNTIME_VERSION",
+ "_READLINE_LIBRARY_VERSION",
)
copy_attributes(info_add, readline, 'readline.%s', attributes,
formatter=format_attr)
@@ -256,11 +303,11 @@
copy_attributes(info_add, _tkinter, 'tkinter.%s', attributes)
try:
- import Tkinter
+ import tkinter
except ImportError:
pass
else:
- tcl = Tkinter.Tcl()
+ tcl = tkinter.Tcl()
patchlevel = tcl.call('info', 'patchlevel')
info_add('tkinter.info_patchlevel', patchlevel)
@@ -276,6 +323,11 @@
)
copy_attributes(info_add, time, 'time.%s', attributes)
+ if hasattr(time, 'get_clock_info'):
+ for clock in ('time', 'perf_counter'):
+ tinfo = time.get_clock_info(clock)
+ info_add('time.%s' % clock, tinfo)
+
def collect_sysconfig(info_add):
import sysconfig
@@ -287,7 +339,6 @@
'CCSHARED',
'CFLAGS',
'CFLAGSFORSHARED',
- 'PY_LDFLAGS',
'CONFIG_ARGS',
'HOST_GNU_TYPE',
'MACHDEP',
@@ -295,6 +346,7 @@
'OPT',
'PY_CFLAGS',
'PY_CFLAGS_NODIST',
+ 'PY_LDFLAGS',
'Py_DEBUG',
'Py_ENABLE_SHARED',
'SHELL',
@@ -368,15 +420,62 @@
copy_attributes(info_add, expat, 'expat.%s', attributes)
-def collect_multiprocessing(info_add):
+def collect_decimal(info_add):
try:
- import multiprocessing
+ import _decimal
except ImportError:
return
- cpu_count = multiprocessing.cpu_count()
- if cpu_count:
- info_add('multiprocessing.cpu_count', cpu_count)
+ attributes = ('__libmpdec_version__',)
+ copy_attributes(info_add, _decimal, '_decimal.%s', attributes)
+
+
+def collect_testcapi(info_add):
+ try:
+ import _testcapi
+ except ImportError:
+ return
+
+ call_func(info_add, 'pymem.allocator', _testcapi, 'pymem_getallocatorsname')
+ copy_attr(info_add, 'pymem.with_pymalloc', _testcapi, 'WITH_PYMALLOC')
+
+
+def collect_resource(info_add):
+ try:
+ import resource
+ except ImportError:
+ return
+
+ limits = [attr for attr in dir(resource) if attr.startswith('RLIMIT_')]
+ for name in limits:
+ key = getattr(resource, name)
+ value = resource.getrlimit(key)
+ info_add('resource.%s' % name, value)
+
+
+def collect_test_socket(info_add):
+ try:
+ from test import test_socket
+ except ImportError:
+ return
+
+ # all check attributes like HAVE_SOCKET_CAN
+ attributes = [name for name in dir(test_socket)
+ if name.startswith('HAVE_')]
+ copy_attributes(info_add, test_socket, 'test_socket.%s', attributes)
+
+
+def collect_test_support(info_add):
+ try:
+ from test import support
+ except ImportError:
+ return
+
+ attributes = ('IPV6_ENABLED',)
+ copy_attributes(info_add, support, 'test_support.%s', attributes)
+
+ call_func(info_add, 'test_support._is_gui_available', support, '_is_gui_available')
+ call_func(info_add, 'test_support.python_is_optimized', support, 'python_is_optimized')
def collect_info(info):
@@ -384,10 +483,12 @@
info_add = info.add
for collect_func in (
- collect_expat,
+ # collect_os() should be the first, to check the getrandom() status
+ collect_os,
+
+ collect_builtins,
collect_gdb,
collect_locale,
- collect_os,
collect_platform,
collect_readline,
collect_socket,
@@ -398,7 +499,14 @@
collect_time,
collect_tkinter,
collect_zlib,
- collect_multiprocessing,
+ collect_expat,
+ collect_decimal,
+ collect_testcapi,
+ collect_resource,
+
+ # Collecting from tests should be last as they have side effects.
+ collect_test_socket,
+ collect_test_support,
):
try:
collect_func(info_add)