blob: 81fca10eaeb1b8507cae5c245b61485816ad58f2 [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
Victor Stinner848acf72018-12-05 23:21:54 +0100147 libc_ver = ('%s %s' % platform.libc_ver()).strip()
148 if libc_ver:
149 info_add('platform.libc_ver', libc_ver)
150
Victor Stinnerb907abc2017-08-17 16:40:51 +0200151
152def collect_locale(info_add):
153 import locale
154
155 info_add('locale.encoding', locale.getpreferredencoding(False))
156
157
Victor Stinner98146972017-12-13 17:27:40 +0100158def collect_builtins(info_add):
159 info_add('builtins.float.float_format', float.__getformat__("float"))
160 info_add('builtins.float.double_format', float.__getformat__("double"))
161
162
Victor Stinnerb907abc2017-08-17 16:40:51 +0200163def collect_os(info_add):
164 import os
165
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200166 def format_attr(attr, value):
167 if attr in ('supports_follow_symlinks', 'supports_fd',
168 'supports_effective_ids'):
169 return str(sorted(func.__name__ for func in value))
170 else:
171 return value
172
173 attributes = (
174 'name',
175 'supports_bytes_environ',
176 'supports_effective_ids',
177 'supports_fd',
178 'supports_follow_symlinks',
179 )
180 copy_attributes(info_add, os, 'os.%s', attributes, formatter=format_attr)
Victor Stinnerb907abc2017-08-17 16:40:51 +0200181
Victor Stinner98146972017-12-13 17:27:40 +0100182 call_func(info_add, 'os.cwd', os, 'getcwd')
Victor Stinnerb907abc2017-08-17 16:40:51 +0200183
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200184 call_func(info_add, 'os.uid', os, 'getuid')
185 call_func(info_add, 'os.gid', os, 'getgid')
186 call_func(info_add, 'os.uname', os, 'uname')
Victor Stinnerb907abc2017-08-17 16:40:51 +0200187
Victor Stinner5d39e042017-11-29 17:20:38 +0100188 def format_groups(groups):
189 return ', '.join(map(str, groups))
190
191 call_func(info_add, 'os.groups', os, 'getgroups', formatter=format_groups)
Victor Stinnerb907abc2017-08-17 16:40:51 +0200192
193 if hasattr(os, 'getlogin'):
194 try:
195 login = os.getlogin()
196 except OSError:
197 # getlogin() fails with "OSError: [Errno 25] Inappropriate ioctl
198 # for device" on Travis CI
199 pass
200 else:
201 info_add("os.login", login)
202
Victor Stinner5d39e042017-11-29 17:20:38 +0100203 call_func(info_add, 'os.cpu_count', os, 'cpu_count')
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200204 call_func(info_add, 'os.loadavg', os, 'getloadavg')
Victor Stinnerb907abc2017-08-17 16:40:51 +0200205
Victor Stinner282c03d2018-11-26 17:03:16 +0100206 # Environment variables used by the stdlib and tests. Don't log the full
207 # environment: filter to list to not leak sensitive information.
208 #
209 # HTTP_PROXY is not logged because it can contain a password.
210 ENV_VARS = frozenset((
211 "APPDATA",
212 "AR",
213 "ARCHFLAGS",
214 "ARFLAGS",
215 "AUDIODEV",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200216 "CC",
Victor Stinner282c03d2018-11-26 17:03:16 +0100217 "CFLAGS",
218 "COLUMNS",
219 "COMPUTERNAME",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200220 "COMSPEC",
Victor Stinner282c03d2018-11-26 17:03:16 +0100221 "CPP",
222 "CPPFLAGS",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200223 "DISPLAY",
Victor Stinner282c03d2018-11-26 17:03:16 +0100224 "DISTUTILS_DEBUG",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200225 "DISTUTILS_USE_SDK",
226 "DYLD_LIBRARY_PATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100227 "ENSUREPIP_OPTIONS",
228 "HISTORY_FILE",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200229 "HOME",
230 "HOMEDRIVE",
231 "HOMEPATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100232 "IDLESTARTUP",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200233 "LANG",
Victor Stinner282c03d2018-11-26 17:03:16 +0100234 "LDFLAGS",
235 "LDSHARED",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200236 "LD_LIBRARY_PATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100237 "LINES",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200238 "MACOSX_DEPLOYMENT_TARGET",
Victor Stinner282c03d2018-11-26 17:03:16 +0100239 "MAILCAPS",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200240 "MAKEFLAGS",
Victor Stinner282c03d2018-11-26 17:03:16 +0100241 "MIXERDEV",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200242 "MSSDK",
243 "PATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100244 "PATHEXT",
245 "PIP_CONFIG_FILE",
246 "PLAT",
247 "POSIXLY_CORRECT",
248 "PY_SAX_PARSER",
249 "ProgramFiles",
250 "ProgramFiles(x86)",
251 "RUNNING_ON_VALGRIND",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200252 "SDK_TOOLS_BIN",
Victor Stinner282c03d2018-11-26 17:03:16 +0100253 "SERVER_SOFTWARE",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200254 "SHELL",
Victor Stinner282c03d2018-11-26 17:03:16 +0100255 "SOURCE_DATE_EPOCH",
256 "SYSTEMROOT",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200257 "TEMP",
258 "TERM",
Victor Stinner282c03d2018-11-26 17:03:16 +0100259 "TILE_LIBRARY",
260 "TIX_LIBRARY",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200261 "TMP",
262 "TMPDIR",
Victor Stinnerc11b3b12018-12-05 01:58:31 +0100263 "TRAVIS",
Victor Stinner282c03d2018-11-26 17:03:16 +0100264 "TZ",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200265 "USERPROFILE",
Victor Stinner282c03d2018-11-26 17:03:16 +0100266 "VIRTUAL_ENV",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200267 "WAYLAND_DISPLAY",
Victor Stinner282c03d2018-11-26 17:03:16 +0100268 "WINDIR",
269 "_PYTHON_HOST_PLATFORM",
270 "_PYTHON_PROJECT_BASE",
271 "_PYTHON_SYSCONFIGDATA_NAME",
272 "__PYVENV_LAUNCHER__",
273 ))
Victor Stinnerb907abc2017-08-17 16:40:51 +0200274 for name, value in os.environ.items():
275 uname = name.upper()
Victor Stinner5d39e042017-11-29 17:20:38 +0100276 if (uname in ENV_VARS
277 # Copy PYTHON* and LC_* variables
278 or uname.startswith(("PYTHON", "LC_"))
Victor Stinnerb907abc2017-08-17 16:40:51 +0200279 # Visual Studio: VS140COMNTOOLS
280 or (uname.startswith("VS") and uname.endswith("COMNTOOLS"))):
281 info_add('os.environ[%s]' % name, value)
282
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200283 if hasattr(os, 'umask'):
284 mask = os.umask(0)
285 os.umask(mask)
286 info_add("os.umask", '%03o' % mask)
287
288 if hasattr(os, 'getrandom'):
289 # PEP 524: Check if system urandom is initialized
290 try:
Victor Stinnera92941f2017-09-19 07:37:24 -0700291 try:
292 os.getrandom(1, os.GRND_NONBLOCK)
293 state = 'ready (initialized)'
294 except BlockingIOError as exc:
295 state = 'not seeded yet (%s)' % exc
296 info_add('os.getrandom', state)
297 except OSError as exc:
298 # Python was compiled on a more recent Linux version
299 # than the current Linux kernel: ignore OSError(ENOSYS)
300 if exc.errno != errno.ENOSYS:
301 raise
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200302
Victor Stinnerb907abc2017-08-17 16:40:51 +0200303
304def collect_readline(info_add):
305 try:
306 import readline
307 except ImportError:
308 return
309
310 def format_attr(attr, value):
311 if isinstance(value, int):
312 return "%#x" % value
313 else:
314 return value
315
316 attributes = (
317 "_READLINE_VERSION",
318 "_READLINE_RUNTIME_VERSION",
319 "_READLINE_LIBRARY_VERSION",
320 )
321 copy_attributes(info_add, readline, 'readline.%s', attributes,
322 formatter=format_attr)
323
Victor Stinneref634b52018-06-01 11:04:29 +0200324 if not hasattr(readline, "_READLINE_LIBRARY_VERSION"):
325 # _READLINE_LIBRARY_VERSION has been added to CPython 3.7
326 doc = getattr(readline, '__doc__', '')
327 if 'libedit readline' in doc:
328 info_add('readline.library', 'libedit readline')
329 elif 'GNU readline' in doc:
330 info_add('readline.library', 'GNU readline')
331
Victor Stinnerb907abc2017-08-17 16:40:51 +0200332
333def collect_gdb(info_add):
334 import subprocess
335
336 try:
337 proc = subprocess.Popen(["gdb", "-nx", "--version"],
338 stdout=subprocess.PIPE,
339 stderr=subprocess.PIPE,
340 universal_newlines=True)
341 version = proc.communicate()[0]
342 except OSError:
343 return
344
345 # Only keep the first line
346 version = version.splitlines()[0]
347 info_add('gdb_version', version)
348
349
350def collect_tkinter(info_add):
351 try:
352 import _tkinter
353 except ImportError:
354 pass
355 else:
356 attributes = ('TK_VERSION', 'TCL_VERSION')
357 copy_attributes(info_add, _tkinter, 'tkinter.%s', attributes)
358
359 try:
360 import tkinter
361 except ImportError:
362 pass
363 else:
364 tcl = tkinter.Tcl()
365 patchlevel = tcl.call('info', 'patchlevel')
366 info_add('tkinter.info_patchlevel', patchlevel)
367
368
369def collect_time(info_add):
370 import time
371
Victor Stinner7d91c022018-01-17 16:35:45 +0100372 info_add('time.time', time.time())
373
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200374 attributes = (
375 'altzone',
376 'daylight',
377 'timezone',
378 'tzname',
379 )
380 copy_attributes(info_add, time, 'time.%s', attributes)
381
Victor Stinner5d39e042017-11-29 17:20:38 +0100382 if hasattr(time, 'get_clock_info'):
383 for clock in ('time', 'perf_counter'):
384 tinfo = time.get_clock_info(clock)
Victor Stinner7d91c022018-01-17 16:35:45 +0100385 info_add('time.get_clock_info(%s)' % clock, tinfo)
386
387
388def collect_datetime(info_add):
389 try:
390 import datetime
391 except ImportError:
392 return
393
394 info_add('datetime.datetime.now', datetime.datetime.now())
Victor Stinnerb907abc2017-08-17 16:40:51 +0200395
396
397def collect_sysconfig(info_add):
398 import sysconfig
399
400 for name in (
401 'ABIFLAGS',
402 'ANDROID_API_LEVEL',
403 'CC',
404 'CCSHARED',
405 'CFLAGS',
406 'CFLAGSFORSHARED',
Victor Stinnerb907abc2017-08-17 16:40:51 +0200407 'CONFIG_ARGS',
408 'HOST_GNU_TYPE',
409 'MACHDEP',
410 'MULTIARCH',
411 'OPT',
412 'PY_CFLAGS',
413 'PY_CFLAGS_NODIST',
Victor Stinner5d39e042017-11-29 17:20:38 +0100414 'PY_LDFLAGS',
Victor Stinnerb907abc2017-08-17 16:40:51 +0200415 'Py_DEBUG',
416 'Py_ENABLE_SHARED',
417 'SHELL',
418 'SOABI',
419 'prefix',
420 ):
421 value = sysconfig.get_config_var(name)
422 if name == 'ANDROID_API_LEVEL' and not value:
423 # skip ANDROID_API_LEVEL=0
424 continue
425 value = normalize_text(value)
426 info_add('sysconfig[%s]' % name, value)
427
428
429def collect_ssl(info_add):
430 try:
431 import ssl
432 except ImportError:
433 return
434
435 def format_attr(attr, value):
436 if attr.startswith('OP_'):
437 return '%#8x' % value
438 else:
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200439 return value
Victor Stinnerb907abc2017-08-17 16:40:51 +0200440
441 attributes = (
442 'OPENSSL_VERSION',
443 'OPENSSL_VERSION_INFO',
444 'HAS_SNI',
445 'OP_ALL',
446 'OP_NO_TLSv1_1',
447 )
448 copy_attributes(info_add, ssl, 'ssl.%s', attributes, formatter=format_attr)
449
450
451def collect_socket(info_add):
452 import socket
453
454 hostname = socket.gethostname()
455 info_add('socket.hostname', hostname)
456
457
458def collect_sqlite(info_add):
459 try:
460 import sqlite3
461 except ImportError:
462 return
463
464 attributes = ('version', 'sqlite_version')
465 copy_attributes(info_add, sqlite3, 'sqlite3.%s', attributes)
466
467
468def collect_zlib(info_add):
469 try:
470 import zlib
471 except ImportError:
472 return
473
474 attributes = ('ZLIB_VERSION', 'ZLIB_RUNTIME_VERSION')
475 copy_attributes(info_add, zlib, 'zlib.%s', attributes)
476
477
Victor Stinnerf6ebd832017-08-17 22:13:11 +0200478def collect_expat(info_add):
479 try:
480 from xml.parsers import expat
481 except ImportError:
482 return
483
484 attributes = ('EXPAT_VERSION',)
485 copy_attributes(info_add, expat, 'expat.%s', attributes)
486
487
488def collect_decimal(info_add):
489 try:
490 import _decimal
491 except ImportError:
492 return
493
494 attributes = ('__libmpdec_version__',)
495 copy_attributes(info_add, _decimal, '_decimal.%s', attributes)
496
497
Victor Stinner5d39e042017-11-29 17:20:38 +0100498def collect_testcapi(info_add):
499 try:
500 import _testcapi
501 except ImportError:
502 return
503
504 call_func(info_add, 'pymem.allocator', _testcapi, 'pymem_getallocatorsname')
505 copy_attr(info_add, 'pymem.with_pymalloc', _testcapi, 'WITH_PYMALLOC')
506
507
Victor Stinner98146972017-12-13 17:27:40 +0100508def collect_resource(info_add):
509 try:
510 import resource
511 except ImportError:
512 return
513
514 limits = [attr for attr in dir(resource) if attr.startswith('RLIMIT_')]
515 for name in limits:
516 key = getattr(resource, name)
517 value = resource.getrlimit(key)
518 info_add('resource.%s' % name, value)
519
520
521def collect_test_socket(info_add):
522 try:
523 from test import test_socket
524 except ImportError:
525 return
526
527 # all check attributes like HAVE_SOCKET_CAN
528 attributes = [name for name in dir(test_socket)
529 if name.startswith('HAVE_')]
530 copy_attributes(info_add, test_socket, 'test_socket.%s', attributes)
531
532
533def collect_test_support(info_add):
534 try:
535 from test import support
536 except ImportError:
537 return
538
539 attributes = ('IPV6_ENABLED',)
540 copy_attributes(info_add, support, 'test_support.%s', attributes)
541
542 call_func(info_add, 'test_support._is_gui_available', support, '_is_gui_available')
543 call_func(info_add, 'test_support.python_is_optimized', support, 'python_is_optimized')
544
545
Victor Stinner56013212018-06-01 00:33:03 +0200546def collect_cc(info_add):
547 import subprocess
548 import sysconfig
549
550 CC = sysconfig.get_config_var('CC')
551 if not CC:
552 return
553
554 try:
555 import shlex
556 args = shlex.split(CC)
557 except ImportError:
558 args = CC.split()
559 args.append('--version')
560 proc = subprocess.Popen(args,
561 stdout=subprocess.PIPE,
562 stderr=subprocess.STDOUT,
563 universal_newlines=True)
564 stdout = proc.communicate()[0]
565 if proc.returncode:
566 # CC --version failed: ignore error
567 return
568
569 text = stdout.splitlines()[0]
570 text = normalize_text(text)
571 info_add('CC.version', text)
572
573
Victor Stinner00f9edb2018-06-19 23:29:22 +0200574def collect_gdbm(info_add):
575 try:
Xiang Zhangb248e952018-06-20 21:23:30 +0800576 from _gdbm import _GDBM_VERSION
Victor Stinner00f9edb2018-06-19 23:29:22 +0200577 except ImportError:
578 return
579
Xiang Zhangb248e952018-06-20 21:23:30 +0800580 info_add('gdbm.GDBM_VERSION', '.'.join(map(str, _GDBM_VERSION)))
Victor Stinner00f9edb2018-06-19 23:29:22 +0200581
582
Victor Stinner00b137c2018-11-13 19:59:26 +0100583def collect_get_config(info_add):
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100584 # Dump global configuration variables, _PyCoreConfig
585 # and _PyMainInterpreterConfig
Victor Stinner2094c2b2018-09-03 17:06:39 +0200586 try:
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100587 from _testcapi import get_global_config, get_core_config, get_main_config
Victor Stinner2094c2b2018-09-03 17:06:39 +0200588 except ImportError:
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100589 return
Victor Stinner2094c2b2018-09-03 17:06:39 +0200590
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100591 for prefix, get_config_func in (
592 ('global_config', get_global_config),
593 ('core_config', get_core_config),
594 ('main_config', get_main_config),
595 ):
596 config = get_config_func()
Victor Stinner00b137c2018-11-13 19:59:26 +0100597 for key in sorted(config):
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100598 info_add('%s[%s]' % (prefix, key), repr(config[key]))
Victor Stinner2094c2b2018-09-03 17:06:39 +0200599
600
Victor Stinnerb907abc2017-08-17 16:40:51 +0200601def collect_info(info):
602 error = False
603 info_add = info.add
604
605 for collect_func in (
606 # collect_os() should be the first, to check the getrandom() status
607 collect_os,
608
Victor Stinner98146972017-12-13 17:27:40 +0100609 collect_builtins,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200610 collect_gdb,
611 collect_locale,
612 collect_platform,
613 collect_readline,
614 collect_socket,
615 collect_sqlite,
616 collect_ssl,
617 collect_sys,
618 collect_sysconfig,
619 collect_time,
Victor Stinner7d91c022018-01-17 16:35:45 +0100620 collect_datetime,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200621 collect_tkinter,
622 collect_zlib,
Victor Stinnerf6ebd832017-08-17 22:13:11 +0200623 collect_expat,
624 collect_decimal,
Victor Stinner5d39e042017-11-29 17:20:38 +0100625 collect_testcapi,
Victor Stinner98146972017-12-13 17:27:40 +0100626 collect_resource,
Victor Stinner56013212018-06-01 00:33:03 +0200627 collect_cc,
Victor Stinner00f9edb2018-06-19 23:29:22 +0200628 collect_gdbm,
Victor Stinner00b137c2018-11-13 19:59:26 +0100629 collect_get_config,
Victor Stinner98146972017-12-13 17:27:40 +0100630
631 # Collecting from tests should be last as they have side effects.
632 collect_test_socket,
633 collect_test_support,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200634 ):
635 try:
636 collect_func(info_add)
637 except Exception as exc:
638 error = True
639 print("ERROR: %s() failed" % (collect_func.__name__),
640 file=sys.stderr)
641 traceback.print_exc(file=sys.stderr)
642 print(file=sys.stderr)
643 sys.stderr.flush()
644
645 return error
646
647
648def dump_info(info, file=None):
649 title = "Python debug information"
650 print(title)
651 print("=" * len(title))
652 print()
653
654 infos = info.get_infos()
655 infos = sorted(infos.items())
656 for key, value in infos:
657 value = value.replace("\n", " ")
658 print("%s: %s" % (key, value))
659 print()
660
661
662def main():
663 info = PythonInfo()
664 error = collect_info(info)
665 dump_info(info)
666
667 if error:
668 print("Collection failed: exit with error", file=sys.stderr)
669 sys.exit(1)
670
671
672if __name__ == "__main__":
673 main()