blob: cc228fb3b54c9449fcb0a86b8ae12b882d68d09e [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
Victor Stinnerddd7c422019-01-08 01:27:27 +01009import warnings
Victor Stinnerb907abc2017-08-17 16:40:51 +020010
11
12def normalize_text(text):
13 if text is None:
14 return None
15 text = str(text)
16 text = re.sub(r'\s+', ' ', text)
17 return text.strip()
18
19
20class PythonInfo:
21 def __init__(self):
22 self.info = {}
23
24 def add(self, key, value):
25 if key in self.info:
26 raise ValueError("duplicate key: %r" % key)
27
Victor Stinnerad7eaed2017-08-18 12:08:47 +020028 if value is None:
29 return
30
31 if not isinstance(value, int):
32 if not isinstance(value, str):
33 # convert other objects like sys.flags to string
34 value = str(value)
35
Victor Stinnerb907abc2017-08-17 16:40:51 +020036 value = value.strip()
37 if not value:
38 return
Victor Stinnerb907abc2017-08-17 16:40:51 +020039
40 self.info[key] = value
41
42 def get_infos(self):
43 """
luzpaza5293b42017-11-05 07:37:50 -060044 Get information as a key:value dictionary where values are strings.
Victor Stinnerb907abc2017-08-17 16:40:51 +020045 """
46 return {key: str(value) for key, value in self.info.items()}
47
48
49def copy_attributes(info_add, obj, name_fmt, attributes, *, formatter=None):
50 for attr in attributes:
51 value = getattr(obj, attr, None)
52 if value is None:
53 continue
54 name = name_fmt % attr
55 if formatter is not None:
56 value = formatter(attr, value)
57 info_add(name, value)
58
59
Victor Stinner5d39e042017-11-29 17:20:38 +010060def copy_attr(info_add, name, mod, attr_name):
61 try:
62 value = getattr(mod, attr_name)
63 except AttributeError:
64 return
65 info_add(name, value)
66
67
Victor Stinnerad7eaed2017-08-18 12:08:47 +020068def call_func(info_add, name, mod, func_name, *, formatter=None):
69 try:
70 func = getattr(mod, func_name)
71 except AttributeError:
72 return
73 value = func()
74 if formatter is not None:
75 value = formatter(value)
76 info_add(name, value)
Victor Stinnerb907abc2017-08-17 16:40:51 +020077
Victor Stinnerad7eaed2017-08-18 12:08:47 +020078
79def collect_sys(info_add):
Victor Stinnerb907abc2017-08-17 16:40:51 +020080 attributes = (
81 '_framework',
Victor Stinnerad7eaed2017-08-18 12:08:47 +020082 'abiflags',
83 'api_version',
84 'builtin_module_names',
Victor Stinnerb907abc2017-08-17 16:40:51 +020085 'byteorder',
Victor Stinnerad7eaed2017-08-18 12:08:47 +020086 'dont_write_bytecode',
Victor Stinnerb907abc2017-08-17 16:40:51 +020087 'executable',
88 'flags',
Victor Stinnerad7eaed2017-08-18 12:08:47 +020089 'float_info',
90 'float_repr_style',
91 'hash_info',
92 'hexversion',
93 'implementation',
94 'int_info',
Victor Stinnerb907abc2017-08-17 16:40:51 +020095 'maxsize',
96 'maxunicode',
Victor Stinnerad7eaed2017-08-18 12:08:47 +020097 'path',
98 'platform',
99 'prefix',
100 'thread_info',
Victor Stinnerb907abc2017-08-17 16:40:51 +0200101 'version',
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200102 'version_info',
103 'winver',
Victor Stinnerb907abc2017-08-17 16:40:51 +0200104 )
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200105 copy_attributes(info_add, sys, 'sys.%s', attributes)
106
107 call_func(info_add, 'sys.androidapilevel', sys, 'getandroidapilevel')
108 call_func(info_add, 'sys.windowsversion', sys, 'getwindowsversion')
Victor Stinnerb907abc2017-08-17 16:40:51 +0200109
110 encoding = sys.getfilesystemencoding()
111 if hasattr(sys, 'getfilesystemencodeerrors'):
112 encoding = '%s/%s' % (encoding, sys.getfilesystemencodeerrors())
113 info_add('sys.filesystem_encoding', encoding)
114
115 for name in ('stdin', 'stdout', 'stderr'):
116 stream = getattr(sys, name)
117 if stream is None:
118 continue
119 encoding = getattr(stream, 'encoding', None)
120 if not encoding:
121 continue
122 errors = getattr(stream, 'errors', None)
123 if errors:
124 encoding = '%s/%s' % (encoding, errors)
125 info_add('sys.%s.encoding' % name, encoding)
126
Victor Stinnerafd055a2017-10-31 08:41:10 -0700127 # Were we compiled --with-pydebug or with #define Py_DEBUG?
128 Py_DEBUG = hasattr(sys, 'gettotalrefcount')
129 if Py_DEBUG:
130 text = 'Yes (sys.gettotalrefcount() present)'
131 else:
132 text = 'No (sys.gettotalrefcount() missing)'
133 info_add('Py_DEBUG', text)
134
Victor Stinnerb907abc2017-08-17 16:40:51 +0200135
136def collect_platform(info_add):
137 import platform
138
139 arch = platform.architecture()
140 arch = ' '.join(filter(bool, arch))
141 info_add('platform.architecture', arch)
142
143 info_add('platform.python_implementation',
144 platform.python_implementation())
145 info_add('platform.platform',
146 platform.platform(aliased=True))
147
Victor Stinner848acf72018-12-05 23:21:54 +0100148 libc_ver = ('%s %s' % platform.libc_ver()).strip()
149 if libc_ver:
150 info_add('platform.libc_ver', libc_ver)
151
Victor Stinnerb907abc2017-08-17 16:40:51 +0200152
153def collect_locale(info_add):
154 import locale
155
156 info_add('locale.encoding', locale.getpreferredencoding(False))
157
158
Victor Stinner98146972017-12-13 17:27:40 +0100159def collect_builtins(info_add):
160 info_add('builtins.float.float_format', float.__getformat__("float"))
161 info_add('builtins.float.double_format', float.__getformat__("double"))
162
163
Victor Stinner9cb27412019-06-25 13:37:27 +0200164def collect_urandom(info_add):
165 import os
166
167 if hasattr(os, 'getrandom'):
168 # PEP 524: Check if system urandom is initialized
169 try:
170 try:
171 os.getrandom(1, os.GRND_NONBLOCK)
172 state = 'ready (initialized)'
173 except BlockingIOError as exc:
174 state = 'not seeded yet (%s)' % exc
175 info_add('os.getrandom', state)
176 except OSError as exc:
177 # Python was compiled on a more recent Linux version
178 # than the current Linux kernel: ignore OSError(ENOSYS)
179 if exc.errno != errno.ENOSYS:
180 raise
181
182
Victor Stinnerb907abc2017-08-17 16:40:51 +0200183def collect_os(info_add):
184 import os
185
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200186 def format_attr(attr, value):
187 if attr in ('supports_follow_symlinks', 'supports_fd',
188 'supports_effective_ids'):
189 return str(sorted(func.__name__ for func in value))
190 else:
191 return value
192
193 attributes = (
194 'name',
195 'supports_bytes_environ',
196 'supports_effective_ids',
197 'supports_fd',
198 'supports_follow_symlinks',
199 )
200 copy_attributes(info_add, os, 'os.%s', attributes, formatter=format_attr)
Victor Stinnerb907abc2017-08-17 16:40:51 +0200201
Victor Stinner4a46adc2020-01-27 18:06:42 +0100202 for func in (
203 'cpu_count',
204 'getcwd',
205 'getegid',
206 'geteuid',
207 'getgid',
208 'getloadavg',
209 'getresgid',
210 'getresuid',
211 'getuid',
212 'uname',
213 ):
214 call_func(info_add, 'os.%s' % func, os, func)
Victor Stinnerb907abc2017-08-17 16:40:51 +0200215
Victor Stinner5d39e042017-11-29 17:20:38 +0100216 def format_groups(groups):
217 return ', '.join(map(str, groups))
218
Victor Stinner9cb27412019-06-25 13:37:27 +0200219 call_func(info_add, 'os.getgroups', os, 'getgroups', formatter=format_groups)
Victor Stinnerb907abc2017-08-17 16:40:51 +0200220
221 if hasattr(os, 'getlogin'):
222 try:
223 login = os.getlogin()
224 except OSError:
225 # getlogin() fails with "OSError: [Errno 25] Inappropriate ioctl
226 # for device" on Travis CI
227 pass
228 else:
229 info_add("os.login", login)
230
Victor Stinner282c03d2018-11-26 17:03:16 +0100231 # Environment variables used by the stdlib and tests. Don't log the full
232 # environment: filter to list to not leak sensitive information.
233 #
234 # HTTP_PROXY is not logged because it can contain a password.
235 ENV_VARS = frozenset((
236 "APPDATA",
237 "AR",
238 "ARCHFLAGS",
239 "ARFLAGS",
240 "AUDIODEV",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200241 "CC",
Victor Stinner282c03d2018-11-26 17:03:16 +0100242 "CFLAGS",
243 "COLUMNS",
244 "COMPUTERNAME",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200245 "COMSPEC",
Victor Stinner282c03d2018-11-26 17:03:16 +0100246 "CPP",
247 "CPPFLAGS",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200248 "DISPLAY",
Victor Stinner282c03d2018-11-26 17:03:16 +0100249 "DISTUTILS_DEBUG",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200250 "DISTUTILS_USE_SDK",
251 "DYLD_LIBRARY_PATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100252 "ENSUREPIP_OPTIONS",
253 "HISTORY_FILE",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200254 "HOME",
255 "HOMEDRIVE",
256 "HOMEPATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100257 "IDLESTARTUP",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200258 "LANG",
Victor Stinner282c03d2018-11-26 17:03:16 +0100259 "LDFLAGS",
260 "LDSHARED",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200261 "LD_LIBRARY_PATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100262 "LINES",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200263 "MACOSX_DEPLOYMENT_TARGET",
Victor Stinner282c03d2018-11-26 17:03:16 +0100264 "MAILCAPS",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200265 "MAKEFLAGS",
Victor Stinner282c03d2018-11-26 17:03:16 +0100266 "MIXERDEV",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200267 "MSSDK",
268 "PATH",
Victor Stinner282c03d2018-11-26 17:03:16 +0100269 "PATHEXT",
270 "PIP_CONFIG_FILE",
271 "PLAT",
272 "POSIXLY_CORRECT",
273 "PY_SAX_PARSER",
274 "ProgramFiles",
275 "ProgramFiles(x86)",
276 "RUNNING_ON_VALGRIND",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200277 "SDK_TOOLS_BIN",
Victor Stinner282c03d2018-11-26 17:03:16 +0100278 "SERVER_SOFTWARE",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200279 "SHELL",
Victor Stinner282c03d2018-11-26 17:03:16 +0100280 "SOURCE_DATE_EPOCH",
281 "SYSTEMROOT",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200282 "TEMP",
283 "TERM",
Victor Stinner282c03d2018-11-26 17:03:16 +0100284 "TILE_LIBRARY",
285 "TIX_LIBRARY",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200286 "TMP",
287 "TMPDIR",
Victor Stinnerc11b3b12018-12-05 01:58:31 +0100288 "TRAVIS",
Victor Stinner282c03d2018-11-26 17:03:16 +0100289 "TZ",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200290 "USERPROFILE",
Victor Stinner282c03d2018-11-26 17:03:16 +0100291 "VIRTUAL_ENV",
Victor Stinnerb907abc2017-08-17 16:40:51 +0200292 "WAYLAND_DISPLAY",
Victor Stinner282c03d2018-11-26 17:03:16 +0100293 "WINDIR",
294 "_PYTHON_HOST_PLATFORM",
295 "_PYTHON_PROJECT_BASE",
296 "_PYTHON_SYSCONFIGDATA_NAME",
297 "__PYVENV_LAUNCHER__",
298 ))
Victor Stinnerb907abc2017-08-17 16:40:51 +0200299 for name, value in os.environ.items():
300 uname = name.upper()
Victor Stinner5d39e042017-11-29 17:20:38 +0100301 if (uname in ENV_VARS
302 # Copy PYTHON* and LC_* variables
303 or uname.startswith(("PYTHON", "LC_"))
Victor Stinnerb907abc2017-08-17 16:40:51 +0200304 # Visual Studio: VS140COMNTOOLS
305 or (uname.startswith("VS") and uname.endswith("COMNTOOLS"))):
306 info_add('os.environ[%s]' % name, value)
307
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200308 if hasattr(os, 'umask'):
309 mask = os.umask(0)
310 os.umask(mask)
Victor Stinner4a46adc2020-01-27 18:06:42 +0100311 info_add("os.umask", '0o%03o' % mask)
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200312
Victor Stinner9cb27412019-06-25 13:37:27 +0200313
314def collect_pwd(info_add):
315 try:
316 import pwd
317 except ImportError:
318 return
319 import os
320
321 uid = os.getuid()
322 try:
323 entry = pwd.getpwuid(uid)
324 except KeyError:
325 entry = None
326
327 info_add('pwd.getpwuid(%s)'% uid,
328 entry if entry is not None else '<KeyError>')
329
330 if entry is None:
331 # there is nothing interesting to read if the current user identifier
332 # is not the password database
333 return
334
335 if hasattr(os, 'getgrouplist'):
336 groups = os.getgrouplist(entry.pw_name, entry.pw_gid)
337 groups = ', '.join(map(str, groups))
338 info_add('os.getgrouplist', groups)
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200339
Victor Stinnerb907abc2017-08-17 16:40:51 +0200340
341def collect_readline(info_add):
342 try:
343 import readline
344 except ImportError:
345 return
346
347 def format_attr(attr, value):
348 if isinstance(value, int):
349 return "%#x" % value
350 else:
351 return value
352
353 attributes = (
354 "_READLINE_VERSION",
355 "_READLINE_RUNTIME_VERSION",
356 "_READLINE_LIBRARY_VERSION",
357 )
358 copy_attributes(info_add, readline, 'readline.%s', attributes,
359 formatter=format_attr)
360
Victor Stinneref634b52018-06-01 11:04:29 +0200361 if not hasattr(readline, "_READLINE_LIBRARY_VERSION"):
362 # _READLINE_LIBRARY_VERSION has been added to CPython 3.7
363 doc = getattr(readline, '__doc__', '')
364 if 'libedit readline' in doc:
365 info_add('readline.library', 'libedit readline')
366 elif 'GNU readline' in doc:
367 info_add('readline.library', 'GNU readline')
368
Victor Stinnerb907abc2017-08-17 16:40:51 +0200369
370def collect_gdb(info_add):
371 import subprocess
372
373 try:
374 proc = subprocess.Popen(["gdb", "-nx", "--version"],
375 stdout=subprocess.PIPE,
376 stderr=subprocess.PIPE,
377 universal_newlines=True)
378 version = proc.communicate()[0]
Victor Stinnerec9bea42020-04-29 17:11:48 +0200379 if proc.returncode:
380 # ignore gdb failure: test_gdb will log the error
381 return
Victor Stinnerb907abc2017-08-17 16:40:51 +0200382 except OSError:
383 return
384
385 # Only keep the first line
386 version = version.splitlines()[0]
387 info_add('gdb_version', version)
388
389
390def collect_tkinter(info_add):
391 try:
392 import _tkinter
393 except ImportError:
394 pass
395 else:
396 attributes = ('TK_VERSION', 'TCL_VERSION')
397 copy_attributes(info_add, _tkinter, 'tkinter.%s', attributes)
398
399 try:
400 import tkinter
401 except ImportError:
402 pass
403 else:
404 tcl = tkinter.Tcl()
405 patchlevel = tcl.call('info', 'patchlevel')
406 info_add('tkinter.info_patchlevel', patchlevel)
407
408
409def collect_time(info_add):
410 import time
411
Victor Stinner7d91c022018-01-17 16:35:45 +0100412 info_add('time.time', time.time())
413
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200414 attributes = (
415 'altzone',
416 'daylight',
417 'timezone',
418 'tzname',
419 )
420 copy_attributes(info_add, time, 'time.%s', attributes)
421
Victor Stinner5d39e042017-11-29 17:20:38 +0100422 if hasattr(time, 'get_clock_info'):
Victor Stinnerddd7c422019-01-08 01:27:27 +0100423 for clock in ('clock', 'monotonic', 'perf_counter',
424 'process_time', 'thread_time', 'time'):
425 try:
426 # prevent DeprecatingWarning on get_clock_info('clock')
427 with warnings.catch_warnings(record=True):
428 clock_info = time.get_clock_info(clock)
429 except ValueError:
430 # missing clock like time.thread_time()
431 pass
432 else:
433 info_add('time.get_clock_info(%s)' % clock, clock_info)
Victor Stinner7d91c022018-01-17 16:35:45 +0100434
435
436def collect_datetime(info_add):
437 try:
438 import datetime
439 except ImportError:
440 return
441
442 info_add('datetime.datetime.now', datetime.datetime.now())
Victor Stinnerb907abc2017-08-17 16:40:51 +0200443
444
445def collect_sysconfig(info_add):
446 import sysconfig
447
448 for name in (
449 'ABIFLAGS',
450 'ANDROID_API_LEVEL',
451 'CC',
452 'CCSHARED',
453 'CFLAGS',
454 'CFLAGSFORSHARED',
Victor Stinnerb907abc2017-08-17 16:40:51 +0200455 'CONFIG_ARGS',
456 'HOST_GNU_TYPE',
457 'MACHDEP',
458 'MULTIARCH',
459 'OPT',
460 'PY_CFLAGS',
461 'PY_CFLAGS_NODIST',
stratakiscf10a752018-12-19 18:19:01 +0100462 'PY_CORE_LDFLAGS',
Victor Stinner5d39e042017-11-29 17:20:38 +0100463 'PY_LDFLAGS',
stratakiscf10a752018-12-19 18:19:01 +0100464 'PY_LDFLAGS_NODIST',
465 'PY_STDMODULE_CFLAGS',
Victor Stinnerb907abc2017-08-17 16:40:51 +0200466 'Py_DEBUG',
467 'Py_ENABLE_SHARED',
468 'SHELL',
469 'SOABI',
470 'prefix',
471 ):
472 value = sysconfig.get_config_var(name)
473 if name == 'ANDROID_API_LEVEL' and not value:
474 # skip ANDROID_API_LEVEL=0
475 continue
476 value = normalize_text(value)
477 info_add('sysconfig[%s]' % name, value)
478
479
480def collect_ssl(info_add):
Victor Stinnerb3e70452019-10-02 17:52:35 +0200481 import os
Victor Stinnerb907abc2017-08-17 16:40:51 +0200482 try:
483 import ssl
484 except ImportError:
485 return
Victor Stinnerb3e70452019-10-02 17:52:35 +0200486 try:
487 import _ssl
488 except ImportError:
489 _ssl = None
Victor Stinnerb907abc2017-08-17 16:40:51 +0200490
491 def format_attr(attr, value):
492 if attr.startswith('OP_'):
493 return '%#8x' % value
494 else:
Victor Stinnerad7eaed2017-08-18 12:08:47 +0200495 return value
Victor Stinnerb907abc2017-08-17 16:40:51 +0200496
497 attributes = (
498 'OPENSSL_VERSION',
499 'OPENSSL_VERSION_INFO',
500 'HAS_SNI',
501 'OP_ALL',
502 'OP_NO_TLSv1_1',
503 )
504 copy_attributes(info_add, ssl, 'ssl.%s', attributes, formatter=format_attr)
505
Victor Stinnerb3e70452019-10-02 17:52:35 +0200506 for name, ctx in (
507 ('SSLContext', ssl.SSLContext()),
508 ('default_https_context', ssl._create_default_https_context()),
509 ('stdlib_context', ssl._create_stdlib_context()),
510 ):
511 attributes = (
512 'minimum_version',
513 'maximum_version',
514 'protocol',
515 'options',
516 'verify_mode',
517 )
518 copy_attributes(info_add, ctx, f'ssl.{name}.%s', attributes)
519
520 env_names = ["OPENSSL_CONF", "SSLKEYLOGFILE"]
521 if _ssl is not None and hasattr(_ssl, 'get_default_verify_paths'):
522 parts = _ssl.get_default_verify_paths()
523 env_names.extend((parts[0], parts[2]))
524
525 for name in env_names:
526 try:
527 value = os.environ[name]
528 except KeyError:
529 continue
530 info_add('ssl.environ[%s]' % name, value)
531
Victor Stinnerb907abc2017-08-17 16:40:51 +0200532
533def collect_socket(info_add):
534 import socket
535
536 hostname = socket.gethostname()
537 info_add('socket.hostname', hostname)
538
539
540def collect_sqlite(info_add):
541 try:
542 import sqlite3
543 except ImportError:
544 return
545
546 attributes = ('version', 'sqlite_version')
547 copy_attributes(info_add, sqlite3, 'sqlite3.%s', attributes)
548
549
550def collect_zlib(info_add):
551 try:
552 import zlib
553 except ImportError:
554 return
555
556 attributes = ('ZLIB_VERSION', 'ZLIB_RUNTIME_VERSION')
557 copy_attributes(info_add, zlib, 'zlib.%s', attributes)
558
559
Victor Stinnerf6ebd832017-08-17 22:13:11 +0200560def collect_expat(info_add):
561 try:
562 from xml.parsers import expat
563 except ImportError:
564 return
565
566 attributes = ('EXPAT_VERSION',)
567 copy_attributes(info_add, expat, 'expat.%s', attributes)
568
569
570def collect_decimal(info_add):
571 try:
572 import _decimal
573 except ImportError:
574 return
575
576 attributes = ('__libmpdec_version__',)
577 copy_attributes(info_add, _decimal, '_decimal.%s', attributes)
578
579
Victor Stinner5d39e042017-11-29 17:20:38 +0100580def collect_testcapi(info_add):
581 try:
582 import _testcapi
583 except ImportError:
584 return
585
586 call_func(info_add, 'pymem.allocator', _testcapi, 'pymem_getallocatorsname')
587 copy_attr(info_add, 'pymem.with_pymalloc', _testcapi, 'WITH_PYMALLOC')
588
589
Victor Stinner98146972017-12-13 17:27:40 +0100590def collect_resource(info_add):
591 try:
592 import resource
593 except ImportError:
594 return
595
596 limits = [attr for attr in dir(resource) if attr.startswith('RLIMIT_')]
597 for name in limits:
598 key = getattr(resource, name)
599 value = resource.getrlimit(key)
600 info_add('resource.%s' % name, value)
601
Victor Stinnerb2385452019-01-21 10:24:12 +0100602 call_func(info_add, 'resource.pagesize', resource, 'getpagesize')
603
Victor Stinner98146972017-12-13 17:27:40 +0100604
605def collect_test_socket(info_add):
606 try:
607 from test import test_socket
608 except ImportError:
609 return
610
611 # all check attributes like HAVE_SOCKET_CAN
612 attributes = [name for name in dir(test_socket)
613 if name.startswith('HAVE_')]
614 copy_attributes(info_add, test_socket, 'test_socket.%s', attributes)
615
616
617def collect_test_support(info_add):
618 try:
619 from test import support
620 except ImportError:
621 return
622
623 attributes = ('IPV6_ENABLED',)
624 copy_attributes(info_add, support, 'test_support.%s', attributes)
625
626 call_func(info_add, 'test_support._is_gui_available', support, '_is_gui_available')
627 call_func(info_add, 'test_support.python_is_optimized', support, 'python_is_optimized')
628
629
Victor Stinner56013212018-06-01 00:33:03 +0200630def collect_cc(info_add):
631 import subprocess
632 import sysconfig
633
634 CC = sysconfig.get_config_var('CC')
635 if not CC:
636 return
637
638 try:
639 import shlex
640 args = shlex.split(CC)
641 except ImportError:
642 args = CC.split()
643 args.append('--version')
xdegayea86e0642019-04-29 14:53:30 +0200644 try:
645 proc = subprocess.Popen(args,
646 stdout=subprocess.PIPE,
647 stderr=subprocess.STDOUT,
648 universal_newlines=True)
649 except OSError:
650 # Cannot run the compiler, for example when Python has been
651 # cross-compiled and installed on the target platform where the
652 # compiler is missing.
653 return
654
Victor Stinner56013212018-06-01 00:33:03 +0200655 stdout = proc.communicate()[0]
656 if proc.returncode:
657 # CC --version failed: ignore error
658 return
659
660 text = stdout.splitlines()[0]
661 text = normalize_text(text)
662 info_add('CC.version', text)
663
664
Victor Stinner00f9edb2018-06-19 23:29:22 +0200665def collect_gdbm(info_add):
666 try:
Xiang Zhangb248e952018-06-20 21:23:30 +0800667 from _gdbm import _GDBM_VERSION
Victor Stinner00f9edb2018-06-19 23:29:22 +0200668 except ImportError:
669 return
670
Xiang Zhangb248e952018-06-20 21:23:30 +0800671 info_add('gdbm.GDBM_VERSION', '.'.join(map(str, _GDBM_VERSION)))
Victor Stinner00f9edb2018-06-19 23:29:22 +0200672
673
Victor Stinner00b137c2018-11-13 19:59:26 +0100674def collect_get_config(info_add):
Victor Stinner5f38b842019-05-01 02:30:12 +0200675 # Get global configuration variables, _PyPreConfig and _PyCoreConfig
Victor Stinner2094c2b2018-09-03 17:06:39 +0200676 try:
Victor Stinner23bace22019-04-18 11:37:26 +0200677 from _testinternalcapi import get_configs
Victor Stinner2094c2b2018-09-03 17:06:39 +0200678 except ImportError:
Victor Stinner7ddd56f2018-11-14 00:24:28 +0100679 return
Victor Stinner2094c2b2018-09-03 17:06:39 +0200680
Victor Stinner1075d162019-03-25 23:19:57 +0100681 all_configs = get_configs()
682 for config_type in sorted(all_configs):
683 config = all_configs[config_type]
Victor Stinner00b137c2018-11-13 19:59:26 +0100684 for key in sorted(config):
Victor Stinner1075d162019-03-25 23:19:57 +0100685 info_add('%s[%s]' % (config_type, key), repr(config[key]))
Victor Stinner2094c2b2018-09-03 17:06:39 +0200686
687
Victor Stinner9daecf32019-01-16 00:02:35 +0100688def collect_subprocess(info_add):
689 import subprocess
Victor Stinner8c349562019-01-16 23:38:06 +0100690 copy_attributes(info_add, subprocess, 'subprocess.%s', ('_USE_POSIX_SPAWN',))
Victor Stinner9daecf32019-01-16 00:02:35 +0100691
692
Victor Stinner64580da2019-06-28 18:05:05 +0200693def collect_windows(info_add):
694 try:
695 import ctypes
696 except ImportError:
697 return
698
699 if not hasattr(ctypes, 'WinDLL'):
700 return
701
702 ntdll = ctypes.WinDLL('ntdll')
703 BOOLEAN = ctypes.c_ubyte
704
705 try:
706 RtlAreLongPathsEnabled = ntdll.RtlAreLongPathsEnabled
707 except AttributeError:
708 res = '<function not available>'
709 else:
710 RtlAreLongPathsEnabled.restype = BOOLEAN
711 RtlAreLongPathsEnabled.argtypes = ()
712 res = bool(RtlAreLongPathsEnabled())
713 info_add('windows.RtlAreLongPathsEnabled', res)
714
Victor Stinner221fd842019-09-25 02:54:25 +0200715 try:
716 import _winapi
717 dll_path = _winapi.GetModuleFileName(sys.dllhandle)
718 info_add('windows.dll_path', dll_path)
719 except (ImportError, AttributeError):
720 pass
721
Victor Stinner64580da2019-06-28 18:05:05 +0200722
Victor Stinnere3dfb9b2020-04-29 18:04:22 +0200723def collect_fips(info_add):
724 try:
725 import _hashlib
726 except ImportError:
727 _hashlib = None
728
729 if _hashlib is not None:
730 call_func(info_add, 'fips.openssl_fips_mode', _hashlib, 'get_fips_mode')
731
732 try:
733 with open("/proc/sys/crypto/fips_enabled", encoding="utf-8") as fp:
734 line = fp.readline().rstrip()
735
736 if line:
737 info_add('fips.linux_crypto_fips_enabled', line)
738 except OSError:
739 pass
740
741
Victor Stinnerb907abc2017-08-17 16:40:51 +0200742def collect_info(info):
743 error = False
744 info_add = info.add
745
746 for collect_func in (
Victor Stinner9cb27412019-06-25 13:37:27 +0200747 # collect_urandom() must be the first, to check the getrandom() status.
748 # Other functions may block on os.urandom() indirectly and so change
749 # its state.
750 collect_urandom,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200751
Victor Stinner98146972017-12-13 17:27:40 +0100752 collect_builtins,
Victor Stinner9cb27412019-06-25 13:37:27 +0200753 collect_cc,
754 collect_datetime,
755 collect_decimal,
756 collect_expat,
Victor Stinnere3dfb9b2020-04-29 18:04:22 +0200757 collect_fips,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200758 collect_gdb,
Victor Stinner9cb27412019-06-25 13:37:27 +0200759 collect_gdbm,
760 collect_get_config,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200761 collect_locale,
Victor Stinner9cb27412019-06-25 13:37:27 +0200762 collect_os,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200763 collect_platform,
Victor Stinner9cb27412019-06-25 13:37:27 +0200764 collect_pwd,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200765 collect_readline,
Victor Stinner9cb27412019-06-25 13:37:27 +0200766 collect_resource,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200767 collect_socket,
768 collect_sqlite,
769 collect_ssl,
Victor Stinner9cb27412019-06-25 13:37:27 +0200770 collect_subprocess,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200771 collect_sys,
772 collect_sysconfig,
Victor Stinner9cb27412019-06-25 13:37:27 +0200773 collect_testcapi,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200774 collect_time,
775 collect_tkinter,
Victor Stinner64580da2019-06-28 18:05:05 +0200776 collect_windows,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200777 collect_zlib,
Victor Stinner98146972017-12-13 17:27:40 +0100778
779 # Collecting from tests should be last as they have side effects.
780 collect_test_socket,
781 collect_test_support,
Victor Stinnerb907abc2017-08-17 16:40:51 +0200782 ):
783 try:
784 collect_func(info_add)
Pablo Galindo293dd232019-11-19 21:34:03 +0000785 except Exception:
Victor Stinnerb907abc2017-08-17 16:40:51 +0200786 error = True
787 print("ERROR: %s() failed" % (collect_func.__name__),
788 file=sys.stderr)
789 traceback.print_exc(file=sys.stderr)
790 print(file=sys.stderr)
791 sys.stderr.flush()
792
793 return error
794
795
796def dump_info(info, file=None):
797 title = "Python debug information"
798 print(title)
799 print("=" * len(title))
800 print()
801
802 infos = info.get_infos()
803 infos = sorted(infos.items())
804 for key, value in infos:
805 value = value.replace("\n", " ")
806 print("%s: %s" % (key, value))
807 print()
808
809
810def main():
811 info = PythonInfo()
812 error = collect_info(info)
813 dump_info(info)
814
815 if error:
816 print("Collection failed: exit with error", file=sys.stderr)
817 sys.exit(1)
818
819
820if __name__ == "__main__":
821 main()