blob: 30e6f21c2b483f9df8c75f7e0b589bd1bfb53cd3 [file] [log] [blame]
Victor Stinnerb907abc2017-08-17 16:40:51 +02001"""
luzpaza5293b42017-11-05 07:37:50 -06002Collect various information about Python to help debugging test failures.
Victor Stinnerb907abc2017-08-17 16:40:51 +02003"""
4from __future__ import print_function
Victor Stinnera92941f2017-09-19 07:37:24 -07005import errno
Victor Stinnerb907abc2017-08-17 16:40:51 +02006import re
7import sys
8import traceback
9
10
11def normalize_text(text):
12 if text is None:
13 return None
14 text = str(text)
15 text = re.sub(r'\s+', ' ', text)
16 return text.strip()
17
18
19class PythonInfo:
20 def __init__(self):
21 self.info = {}
22
23 def add(self, key, value):
24 if key in self.info:
25 raise ValueError("duplicate key: %r" % key)
26
Victor Stinnerad7eaed2017-08-18 12:08:47 +020027 if value is None:
28 return
29
30 if not isinstance(value, int):
31 if not isinstance(value, str):
32 # convert other objects like sys.flags to string
33 value = str(value)
34
Victor Stinnerb907abc2017-08-17 16:40:51 +020035 value = value.strip()
36 if not value:
37 return
Victor Stinnerb907abc2017-08-17 16:40:51 +020038
39 self.info[key] = value
40
41 def get_infos(self):
42 """
luzpaza5293b42017-11-05 07:37:50 -060043 Get information as a key:value dictionary where values are strings.
Victor Stinnerb907abc2017-08-17 16:40:51 +020044 """
45 return {key: str(value) for key, value in self.info.items()}
46
47
48def copy_attributes(info_add, obj, name_fmt, attributes, *, formatter=None):
49 for attr in attributes:
50 value = getattr(obj, attr, None)
51 if value is None:
52 continue
53 name = name_fmt % attr
54 if formatter is not None:
55 value = formatter(attr, value)
56 info_add(name, value)
57
58
Victor Stinner5d39e042017-11-29 17:20:38 +010059def copy_attr(info_add, name, mod, attr_name):
60 try:
61 value = getattr(mod, attr_name)
62 except AttributeError:
63 return
64 info_add(name, value)
65
66
Victor Stinnerad7eaed2017-08-18 12:08:47 +020067def call_func(info_add, name, mod, func_name, *, formatter=None):
68 try:
69 func = getattr(mod, func_name)
70 except AttributeError:
71 return
72 value = func()
73 if formatter is not None:
74 value = formatter(value)
75 info_add(name, value)
Victor Stinnerb907abc2017-08-17 16:40:51 +020076
Victor Stinnerad7eaed2017-08-18 12:08:47 +020077
78def collect_sys(info_add):
Victor Stinnerb907abc2017-08-17 16:40:51 +020079 attributes = (
80 '_framework',
Victor Stinnerad7eaed2017-08-18 12:08:47 +020081 'abiflags',
82 'api_version',
83 'builtin_module_names',
Victor Stinnerb907abc2017-08-17 16:40:51 +020084 'byteorder',
Victor Stinnerad7eaed2017-08-18 12:08:47 +020085 'dont_write_bytecode',
Victor Stinnerb907abc2017-08-17 16:40:51 +020086 'executable',
87 'flags',
Victor Stinnerad7eaed2017-08-18 12:08:47 +020088 'float_info',
89 'float_repr_style',
90 'hash_info',
91 'hexversion',
92 'implementation',
93 'int_info',
Victor Stinnerb907abc2017-08-17 16:40:51 +020094 'maxsize',
95 'maxunicode',
Victor Stinnerad7eaed2017-08-18 12:08:47 +020096 'path',
97 'platform',
98 'prefix',
99 'thread_info',
Victor Stinnerb907abc2017-08-17 16:40:51 +0200100 'version',
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200101 'version_info',
102 'winver',
Victor Stinnerb907abc2017-08-17 16:40:51 +0200103 )
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200104 copy_attributes(info_add, sys, 'sys.%s', attributes)
105
106 call_func(info_add, 'sys.androidapilevel', sys, 'getandroidapilevel')
107 call_func(info_add, 'sys.windowsversion', sys, 'getwindowsversion')
Victor Stinnerb907abc2017-08-17 16:40:51 +0200108
109 encoding = sys.getfilesystemencoding()
110 if hasattr(sys, 'getfilesystemencodeerrors'):
111 encoding = '%s/%s' % (encoding, sys.getfilesystemencodeerrors())
112 info_add('sys.filesystem_encoding', encoding)
113
114 for name in ('stdin', 'stdout', 'stderr'):
115 stream = getattr(sys, name)
116 if stream is None:
117 continue
118 encoding = getattr(stream, 'encoding', None)
119 if not encoding:
120 continue
121 errors = getattr(stream, 'errors', None)
122 if errors:
123 encoding = '%s/%s' % (encoding, errors)
124 info_add('sys.%s.encoding' % name, encoding)
125
Victor Stinnerafd055a2017-10-31 08:41:10 -0700126 # Were we compiled --with-pydebug or with #define Py_DEBUG?
127 Py_DEBUG = hasattr(sys, 'gettotalrefcount')
128 if Py_DEBUG:
129 text = 'Yes (sys.gettotalrefcount() present)'
130 else:
131 text = 'No (sys.gettotalrefcount() missing)'
132 info_add('Py_DEBUG', text)
133
Victor Stinnerb907abc2017-08-17 16:40:51 +0200134
135def collect_platform(info_add):
136 import platform
137
138 arch = platform.architecture()
139 arch = ' '.join(filter(bool, arch))
140 info_add('platform.architecture', arch)
141
142 info_add('platform.python_implementation',
143 platform.python_implementation())
144 info_add('platform.platform',
145 platform.platform(aliased=True))
146
147
148def collect_locale(info_add):
149 import locale
150
151 info_add('locale.encoding', locale.getpreferredencoding(False))
152
153
Victor Stinner98146972017-12-13 17:27:40 +0100154def collect_builtins(info_add):
155 info_add('builtins.float.float_format', float.__getformat__("float"))
156 info_add('builtins.float.double_format', float.__getformat__("double"))
157
158
Victor Stinnerb907abc2017-08-17 16:40:51 +0200159def collect_os(info_add):
160 import os
161
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200162 def format_attr(attr, value):
163 if attr in ('supports_follow_symlinks', 'supports_fd',
164 'supports_effective_ids'):
165 return str(sorted(func.__name__ for func in value))
166 else:
167 return value
168
169 attributes = (
170 'name',
171 'supports_bytes_environ',
172 'supports_effective_ids',
173 'supports_fd',
174 'supports_follow_symlinks',
175 )
176 copy_attributes(info_add, os, 'os.%s', attributes, formatter=format_attr)
Victor Stinnerb907abc2017-08-17 16:40:51 +0200177
Victor Stinner98146972017-12-13 17:27:40 +0100178 call_func(info_add, 'os.cwd', os, 'getcwd')
Victor Stinnerb907abc2017-08-17 16:40:51 +0200179
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200180 call_func(info_add, 'os.uid', os, 'getuid')
181 call_func(info_add, 'os.gid', os, 'getgid')
182 call_func(info_add, 'os.uname', os, 'uname')
Victor Stinnerb907abc2017-08-17 16:40:51 +0200183
Victor Stinner5d39e042017-11-29 17:20:38 +0100184 def format_groups(groups):
185 return ', '.join(map(str, groups))
186
187 call_func(info_add, 'os.groups', os, 'getgroups', formatter=format_groups)
Victor Stinnerb907abc2017-08-17 16:40:51 +0200188
189 if hasattr(os, 'getlogin'):
190 try:
191 login = os.getlogin()
192 except OSError:
193 # getlogin() fails with "OSError: [Errno 25] Inappropriate ioctl
194 # for device" on Travis CI
195 pass
196 else:
197 info_add("os.login", login)
198
Victor Stinner5d39e042017-11-29 17:20:38 +0100199 call_func(info_add, 'os.cpu_count', os, 'cpu_count')
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200200 call_func(info_add, 'os.loadavg', os, 'getloadavg')
Victor Stinnerb907abc2017-08-17 16:40:51 +0200201
Victor Stinner282c03d2018-11-26 17:03:16 +0100202 # Environment variables used by the stdlib and tests. Don't log the full
203 # environment: filter to list to not leak sensitive information.
204 #
205 # HTTP_PROXY is not logged because it can contain a password.
206 ENV_VARS = frozenset((
207 "APPDATA",
208 "AR",
209 "ARCHFLAGS",
210 "ARFLAGS",
211 "AUDIODEV",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200212 "CC",
Victor Stinner282c03d2018-11-26 17:03:16 +0100213 "CFLAGS",
214 "COLUMNS",
215 "COMPUTERNAME",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200216 "COMSPEC",
Victor Stinner282c03d2018-11-26 17:03:16 +0100217 "CPP",
218 "CPPFLAGS",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200219 "DISPLAY",
Victor Stinner282c03d2018-11-26 17:03:16 +0100220 "DISTUTILS_DEBUG",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200221 "DISTUTILS_USE_SDK",
222 "DYLD_LIBRARY_PATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100223 "ENSUREPIP_OPTIONS",
224 "HISTORY_FILE",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200225 "HOME",
226 "HOMEDRIVE",
227 "HOMEPATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100228 "IDLESTARTUP",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200229 "LANG",
Victor Stinner282c03d2018-11-26 17:03:16 +0100230 "LDFLAGS",
231 "LDSHARED",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200232 "LD_LIBRARY_PATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100233 "LINES",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200234 "MACOSX_DEPLOYMENT_TARGET",
Victor Stinner282c03d2018-11-26 17:03:16 +0100235 "MAILCAPS",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200236 "MAKEFLAGS",
Victor Stinner282c03d2018-11-26 17:03:16 +0100237 "MIXERDEV",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200238 "MSSDK",
239 "PATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100240 "PATHEXT",
241 "PIP_CONFIG_FILE",
242 "PLAT",
243 "POSIXLY_CORRECT",
244 "PY_SAX_PARSER",
245 "ProgramFiles",
246 "ProgramFiles(x86)",
247 "RUNNING_ON_VALGRIND",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200248 "SDK_TOOLS_BIN",
Victor Stinner282c03d2018-11-26 17:03:16 +0100249 "SERVER_SOFTWARE",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200250 "SHELL",
Victor Stinner282c03d2018-11-26 17:03:16 +0100251 "SOURCE_DATE_EPOCH",
252 "SYSTEMROOT",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200253 "TEMP",
254 "TERM",
Victor Stinner282c03d2018-11-26 17:03:16 +0100255 "TILE_LIBRARY",
256 "TIX_LIBRARY",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200257 "TMP",
258 "TMPDIR",
Victor Stinner282c03d2018-11-26 17:03:16 +0100259 "TZ",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200260 "USERPROFILE",
Victor Stinner282c03d2018-11-26 17:03:16 +0100261 "VIRTUAL_ENV",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200262 "WAYLAND_DISPLAY",
Victor Stinner282c03d2018-11-26 17:03:16 +0100263 "WINDIR",
264 "_PYTHON_HOST_PLATFORM",
265 "_PYTHON_PROJECT_BASE",
266 "_PYTHON_SYSCONFIGDATA_NAME",
267 "__PYVENV_LAUNCHER__",
268 ))
Victor Stinnerb907abc2017-08-17 16:40:51 +0200269 for name, value in os.environ.items():
270 uname = name.upper()
Victor Stinner5d39e042017-11-29 17:20:38 +0100271 if (uname in ENV_VARS
272 # Copy PYTHON* and LC_* variables
273 or uname.startswith(("PYTHON", "LC_"))
Victor Stinnerb907abc2017-08-17 16:40:51 +0200274 # Visual Studio: VS140COMNTOOLS
275 or (uname.startswith("VS") and uname.endswith("COMNTOOLS"))):
276 info_add('os.environ[%s]' % name, value)
277
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200278 if hasattr(os, 'umask'):
279 mask = os.umask(0)
280 os.umask(mask)
281 info_add("os.umask", '%03o' % mask)
282
283 if hasattr(os, 'getrandom'):
284 # PEP 524: Check if system urandom is initialized
285 try:
Victor Stinnera92941f2017-09-19 07:37:24 -0700286 try:
287 os.getrandom(1, os.GRND_NONBLOCK)
288 state = 'ready (initialized)'
289 except BlockingIOError as exc:
290 state = 'not seeded yet (%s)' % exc
291 info_add('os.getrandom', state)
292 except OSError as exc:
293 # Python was compiled on a more recent Linux version
294 # than the current Linux kernel: ignore OSError(ENOSYS)
295 if exc.errno != errno.ENOSYS:
296 raise
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200297
Victor Stinnerb907abc2017-08-17 16:40:51 +0200298
299def collect_readline(info_add):
300 try:
301 import readline
302 except ImportError:
303 return
304
305 def format_attr(attr, value):
306 if isinstance(value, int):
307 return "%#x" % value
308 else:
309 return value
310
311 attributes = (
312 "_READLINE_VERSION",
313 "_READLINE_RUNTIME_VERSION",
314 "_READLINE_LIBRARY_VERSION",
315 )
316 copy_attributes(info_add, readline, 'readline.%s', attributes,
317 formatter=format_attr)
318
Victor Stinneref634b52018-06-01 11:04:29 +0200319 if not hasattr(readline, "_READLINE_LIBRARY_VERSION"):
320 # _READLINE_LIBRARY_VERSION has been added to CPython 3.7
321 doc = getattr(readline, '__doc__', '')
322 if 'libedit readline' in doc:
323 info_add('readline.library', 'libedit readline')
324 elif 'GNU readline' in doc:
325 info_add('readline.library', 'GNU readline')
326
Victor Stinnerb907abc2017-08-17 16:40:51 +0200327
328def collect_gdb(info_add):
329 import subprocess
330
331 try:
332 proc = subprocess.Popen(["gdb", "-nx", "--version"],
333 stdout=subprocess.PIPE,
334 stderr=subprocess.PIPE,
335 universal_newlines=True)
336 version = proc.communicate()[0]
337 except OSError:
338 return
339
340 # Only keep the first line
341 version = version.splitlines()[0]
342 info_add('gdb_version', version)
343
344
345def collect_tkinter(info_add):
346 try:
347 import _tkinter
348 except ImportError:
349 pass
350 else:
351 attributes = ('TK_VERSION', 'TCL_VERSION')
352 copy_attributes(info_add, _tkinter, 'tkinter.%s', attributes)
353
354 try:
355 import tkinter
356 except ImportError:
357 pass
358 else:
359 tcl = tkinter.Tcl()
360 patchlevel = tcl.call('info', 'patchlevel')
361 info_add('tkinter.info_patchlevel', patchlevel)
362
363
364def collect_time(info_add):
365 import time
366
Victor Stinner7d91c022018-01-17 16:35:45 +0100367 info_add('time.time', time.time())
368
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200369 attributes = (
370 'altzone',
371 'daylight',
372 'timezone',
373 'tzname',
374 )
375 copy_attributes(info_add, time, 'time.%s', attributes)
376
Victor Stinner5d39e042017-11-29 17:20:38 +0100377 if hasattr(time, 'get_clock_info'):
378 for clock in ('time', 'perf_counter'):
379 tinfo = time.get_clock_info(clock)
Victor Stinner7d91c022018-01-17 16:35:45 +0100380 info_add('time.get_clock_info(%s)' % clock, tinfo)
381
382
383def collect_datetime(info_add):
384 try:
385 import datetime
386 except ImportError:
387 return
388
389 info_add('datetime.datetime.now', datetime.datetime.now())
Victor Stinnerb907abc2017-08-17 16:40:51 +0200390
391
392def collect_sysconfig(info_add):
393 import sysconfig
394
395 for name in (
396 'ABIFLAGS',
397 'ANDROID_API_LEVEL',
398 'CC',
399 'CCSHARED',
400 'CFLAGS',
401 'CFLAGSFORSHARED',
Victor Stinnerb907abc2017-08-17 16:40:51 +0200402 'CONFIG_ARGS',
403 'HOST_GNU_TYPE',
404 'MACHDEP',
405 'MULTIARCH',
406 'OPT',
407 'PY_CFLAGS',
408 'PY_CFLAGS_NODIST',
Victor Stinner5d39e042017-11-29 17:20:38 +0100409 'PY_LDFLAGS',
Victor Stinnerb907abc2017-08-17 16:40:51 +0200410 'Py_DEBUG',
411 'Py_ENABLE_SHARED',
412 'SHELL',
413 'SOABI',
414 'prefix',
415 ):
416 value = sysconfig.get_config_var(name)
417 if name == 'ANDROID_API_LEVEL' and not value:
418 # skip ANDROID_API_LEVEL=0
419 continue
420 value = normalize_text(value)
421 info_add('sysconfig[%s]' % name, value)
422
423
424def collect_ssl(info_add):
425 try:
426 import ssl
427 except ImportError:
428 return
429
430 def format_attr(attr, value):
431 if attr.startswith('OP_'):
432 return '%#8x' % value
433 else:
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200434 return value
Victor Stinnerb907abc2017-08-17 16:40:51 +0200435
436 attributes = (
437 'OPENSSL_VERSION',
438 'OPENSSL_VERSION_INFO',
439 'HAS_SNI',
440 'OP_ALL',
441 'OP_NO_TLSv1_1',
442 )
443 copy_attributes(info_add, ssl, 'ssl.%s', attributes, formatter=format_attr)
444
445
446def collect_socket(info_add):
447 import socket
448
449 hostname = socket.gethostname()
450 info_add('socket.hostname', hostname)
451
452
453def collect_sqlite(info_add):
454 try:
455 import sqlite3
456 except ImportError:
457 return
458
459 attributes = ('version', 'sqlite_version')
460 copy_attributes(info_add, sqlite3, 'sqlite3.%s', attributes)
461
462
463def collect_zlib(info_add):
464 try:
465 import zlib
466 except ImportError:
467 return
468
469 attributes = ('ZLIB_VERSION', 'ZLIB_RUNTIME_VERSION')
470 copy_attributes(info_add, zlib, 'zlib.%s', attributes)
471
472
Victor Stinnerf6ebd832017-08-17 22:13:11 +0200473def collect_expat(info_add):
474 try:
475 from xml.parsers import expat
476 except ImportError:
477 return
478
479 attributes = ('EXPAT_VERSION',)
480 copy_attributes(info_add, expat, 'expat.%s', attributes)
481
482
483def collect_decimal(info_add):
484 try:
485 import _decimal
486 except ImportError:
487 return
488
489 attributes = ('__libmpdec_version__',)
490 copy_attributes(info_add, _decimal, '_decimal.%s', attributes)
491
492
Victor Stinner5d39e042017-11-29 17:20:38 +0100493def collect_testcapi(info_add):
494 try:
495 import _testcapi
496 except ImportError:
497 return
498
499 call_func(info_add, 'pymem.allocator', _testcapi, 'pymem_getallocatorsname')
500 copy_attr(info_add, 'pymem.with_pymalloc', _testcapi, 'WITH_PYMALLOC')
501
502
Victor Stinner98146972017-12-13 17:27:40 +0100503def collect_resource(info_add):
504 try:
505 import resource
506 except ImportError:
507 return
508
509 limits = [attr for attr in dir(resource) if attr.startswith('RLIMIT_')]
510 for name in limits:
511 key = getattr(resource, name)
512 value = resource.getrlimit(key)
513 info_add('resource.%s' % name, value)
514
515
516def collect_test_socket(info_add):
517 try:
518 from test import test_socket
519 except ImportError:
520 return
521
522 # all check attributes like HAVE_SOCKET_CAN
523 attributes = [name for name in dir(test_socket)
524 if name.startswith('HAVE_')]
525 copy_attributes(info_add, test_socket, 'test_socket.%s', attributes)
526
527
528def collect_test_support(info_add):
529 try:
530 from test import support
531 except ImportError:
532 return
533
534 attributes = ('IPV6_ENABLED',)
535 copy_attributes(info_add, support, 'test_support.%s', attributes)
536
537 call_func(info_add, 'test_support._is_gui_available', support, '_is_gui_available')
538 call_func(info_add, 'test_support.python_is_optimized', support, 'python_is_optimized')
539
540
Victor Stinner56013212018-06-01 00:33:03 +0200541def collect_cc(info_add):
542 import subprocess
543 import sysconfig
544
545 CC = sysconfig.get_config_var('CC')
546 if not CC:
547 return
548
549 try:
550 import shlex
551 args = shlex.split(CC)
552 except ImportError:
553 args = CC.split()
554 args.append('--version')
555 proc = subprocess.Popen(args,
556 stdout=subprocess.PIPE,
557 stderr=subprocess.STDOUT,
558 universal_newlines=True)
559 stdout = proc.communicate()[0]
560 if proc.returncode:
561 # CC --version failed: ignore error
562 return
563
564 text = stdout.splitlines()[0]
565 text = normalize_text(text)
566 info_add('CC.version', text)
567
568
Victor Stinner00f9edb2018-06-19 23:29:22 +0200569def collect_gdbm(info_add):
570 try:
Xiang Zhangb248e952018-06-20 21:23:30 +0800571 from _gdbm import _GDBM_VERSION
Victor Stinner00f9edb2018-06-19 23:29:22 +0200572 except ImportError:
573 return
574
Xiang Zhangb248e952018-06-20 21:23:30 +0800575 info_add('gdbm.GDBM_VERSION', '.'.join(map(str, _GDBM_VERSION)))
Victor Stinner00f9edb2018-06-19 23:29:22 +0200576
577
Victor Stinner00b137c2018-11-13 19:59:26 +0100578def collect_get_config(info_add):
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100579 # Dump global configuration variables, _PyCoreConfig
580 # and _PyMainInterpreterConfig
Victor Stinner2094c2b2018-09-03 17:06:39 +0200581 try:
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100582 from _testcapi import get_global_config, get_core_config, get_main_config
Victor Stinner2094c2b2018-09-03 17:06:39 +0200583 except ImportError:
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100584 return
Victor Stinner2094c2b2018-09-03 17:06:39 +0200585
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100586 for prefix, get_config_func in (
587 ('global_config', get_global_config),
588 ('core_config', get_core_config),
589 ('main_config', get_main_config),
590 ):
591 config = get_config_func()
Victor Stinner00b137c2018-11-13 19:59:26 +0100592 for key in sorted(config):
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100593 info_add('%s[%s]' % (prefix, key), repr(config[key]))
Victor Stinner2094c2b2018-09-03 17:06:39 +0200594
595
Victor Stinnerb907abc2017-08-17 16:40:51 +0200596def collect_info(info):
597 error = False
598 info_add = info.add
599
600 for collect_func in (
601 # collect_os() should be the first, to check the getrandom() status
602 collect_os,
603
Victor Stinner98146972017-12-13 17:27:40 +0100604 collect_builtins,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200605 collect_gdb,
606 collect_locale,
607 collect_platform,
608 collect_readline,
609 collect_socket,
610 collect_sqlite,
611 collect_ssl,
612 collect_sys,
613 collect_sysconfig,
614 collect_time,
Victor Stinner7d91c022018-01-17 16:35:45 +0100615 collect_datetime,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200616 collect_tkinter,
617 collect_zlib,
Victor Stinnerf6ebd832017-08-17 22:13:11 +0200618 collect_expat,
619 collect_decimal,
Victor Stinner5d39e042017-11-29 17:20:38 +0100620 collect_testcapi,
Victor Stinner98146972017-12-13 17:27:40 +0100621 collect_resource,
Victor Stinner56013212018-06-01 00:33:03 +0200622 collect_cc,
Victor Stinner00f9edb2018-06-19 23:29:22 +0200623 collect_gdbm,
Victor Stinner00b137c2018-11-13 19:59:26 +0100624 collect_get_config,
Victor Stinner98146972017-12-13 17:27:40 +0100625
626 # Collecting from tests should be last as they have side effects.
627 collect_test_socket,
628 collect_test_support,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200629 ):
630 try:
631 collect_func(info_add)
632 except Exception as exc:
633 error = True
634 print("ERROR: %s() failed" % (collect_func.__name__),
635 file=sys.stderr)
636 traceback.print_exc(file=sys.stderr)
637 print(file=sys.stderr)
638 sys.stderr.flush()
639
640 return error
641
642
643def dump_info(info, file=None):
644 title = "Python debug information"
645 print(title)
646 print("=" * len(title))
647 print()
648
649 infos = info.get_infos()
650 infos = sorted(infos.items())
651 for key, value in infos:
652 value = value.replace("\n", " ")
653 print("%s: %s" % (key, value))
654 print()
655
656
657def main():
658 info = PythonInfo()
659 error = collect_info(info)
660 dump_info(info)
661
662 if error:
663 print("Collection failed: exit with error", file=sys.stderr)
664 sys.exit(1)
665
666
667if __name__ == "__main__":
668 main()