1import ctypes 2import json 3import locale 4import multiprocessing 5import os 6import platform 7import textwrap 8import sys 9from contextlib import redirect_stdout 10from datetime import datetime 11from io import StringIO 12from subprocess import check_output, PIPE, CalledProcessError 13import llvmlite.binding as llvmbind 14from numba import cuda as cu 15from numba import roc 16from numba.roc.hlc import hlc, libhlc 17from numba.cuda import cudadrv 18from numba.cuda.cudadrv.driver import driver as cudriver 19from numba.core import config 20 21_psutil_import = False 22try: 23 import psutil 24except ImportError: 25 pass 26else: 27 _psutil_import = True 28 29__all__ = ['get_sysinfo', 'display_sysinfo'] 30 31# Keys of a `sysinfo` dictionary 32 33# Time info 34_start, _start_utc, _runtime = 'Start', 'Start UTC', 'Runtime' 35# Hardware info 36_machine = 'Machine' 37_cpu_name, _cpu_count = 'CPU Name', 'CPU Count' 38_cpus_allowed, _cpus_list = 'CPUs Allowed', 'List CPUs Allowed' 39_cpu_features = 'CPU Features' 40_cfs_quota, _cfs_period = 'CFS Quota', 'CFS Period', 41_cfs_restrict = 'CFS Restriction' 42_mem_total, _mem_available = 'Mem Total', 'Mem Available' 43# OS info 44_platform_name, _platform_release = 'Platform Name', 'Platform Release' 45_os_name, _os_version = 'OS Name', 'OS Version' 46_os_spec_version = 'OS Specific Version' 47_libc_version = 'Libc Version' 48# Python info 49_python_comp = 'Python Compiler' 50_python_impl = 'Python Implementation' 51_python_version = 'Python Version' 52_python_locale = 'Python Locale' 53# LLVM info 54_llvm_version = 'LLVM Version' 55# CUDA info 56_cu_dev_init = 'CUDA Device Init' 57_cu_drv_ver = 'CUDA Driver Version' 58_cu_detect_out, _cu_lib_test = 'CUDA Detect Output', 'CUDA Lib Test' 59# ROC information 60_roc_available, _roc_toolchains = 'ROC Available', 'ROC Toolchains' 61_hsa_agents_count, _hsa_agents = 'HSA Agents Count', 'HSA Agents' 62_hsa_gpus_count, _hsa_gpus = 'HSA Discrete GPUs Count', 'HSA Discrete GPUs' 63# SVML info 64_svml_state, _svml_loaded = 'SVML State', 'SVML Lib Loaded' 65_llvm_svml_patched = 'LLVM SVML Patched' 66_svml_operational = 'SVML Operational' 67# Threading layer info 68_tbb_thread, _tbb_error = 'TBB Threading', 'TBB Threading Error' 69_openmp_thread, _openmp_error = 'OpenMP Threading', 'OpenMP Threading Error' 70_openmp_vendor = 'OpenMP vendor' 71_wkq_thread, _wkq_error = 'Workqueue Threading', 'Workqueue Threading Error' 72# Numba info 73_numba_env_vars = 'Numba Env Vars' 74# Conda info 75_conda_build_ver, _conda_env_ver = 'Conda Build', 'Conda Env' 76_conda_platform, _conda_python_ver = 'Conda Platform', 'Conda Python Version' 77_conda_root_writable = 'Conda Root Writable' 78# Packages info 79_inst_pkg = 'Installed Packages' 80# Psutil info 81_psutil = 'Psutil Available' 82# Errors and warnings 83_errors = 'Errors' 84_warnings = 'Warnings' 85 86# Error and warning log 87_error_log = [] 88_warning_log = [] 89 90 91def get_os_spec_info(os_name): 92 # Linux man page for `/proc`: 93 # http://man7.org/linux/man-pages/man5/proc.5.html 94 95 # Windows documentation for `wmic OS`: 96 # https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/cim-operatingsystem 97 98 # MacOS man page for `sysctl`: 99 # https://www.unix.com/man-page/osx/3/sysctl/ 100 # MacOS man page for `vm_stat`: 101 # https://www.unix.com/man-page/osx/1/vm_stat/ 102 103 class CmdBufferOut(tuple): 104 buffer_output_flag = True 105 106 class CmdReadFile(tuple): 107 read_file_flag = True 108 109 shell_params = { 110 'Linux': { 111 'cmd': ( 112 CmdReadFile(('/sys/fs/cgroup/cpuacct/cpu.cfs_quota_us',)), 113 CmdReadFile(('/sys/fs/cgroup/cpuacct/cpu.cfs_period_us',)), 114 ), 115 'cmd_optional': ( 116 CmdReadFile(('/proc/meminfo',)), 117 CmdReadFile(('/proc/self/status',)), 118 ), 119 'kwds': { 120 # output string fragment -> result dict key 121 'MemTotal:': _mem_total, 122 'MemAvailable:': _mem_available, 123 'Cpus_allowed:': _cpus_allowed, 124 'Cpus_allowed_list:': _cpus_list, 125 '/sys/fs/cgroup/cpuacct/cpu.cfs_quota_us': _cfs_quota, 126 '/sys/fs/cgroup/cpuacct/cpu.cfs_period_us': _cfs_period, 127 }, 128 }, 129 'Windows': { 130 'cmd': (), 131 'cmd_optional': ( 132 CmdBufferOut(('wmic', 'OS', 'get', 'TotalVirtualMemorySize')), 133 CmdBufferOut(('wmic', 'OS', 'get', 'FreeVirtualMemory')), 134 ), 135 'kwds': { 136 # output string fragment -> result dict key 137 'TotalVirtualMemorySize': _mem_total, 138 'FreeVirtualMemory': _mem_available, 139 }, 140 }, 141 'Darwin': { 142 'cmd': (), 143 'cmd_optional': ( 144 ('sysctl', 'hw.memsize'), 145 ('vm_stat'), 146 ), 147 'kwds': { 148 # output string fragment -> result dict key 149 'hw.memsize:': _mem_total, 150 'free:': _mem_available, 151 }, 152 'units': { 153 _mem_total: 1, # Size is given in bytes. 154 _mem_available: 4096, # Size is given in 4kB pages. 155 }, 156 }, 157 } 158 159 os_spec_info = {} 160 params = shell_params.get(os_name, {}) 161 cmd_selected = params.get('cmd', ()) 162 163 if _psutil_import: 164 vm = psutil.virtual_memory() 165 os_spec_info.update({ 166 _mem_total: vm.total, 167 _mem_available: vm.available, 168 }) 169 p = psutil.Process() 170 cpus_allowed = p.cpu_affinity() if hasattr(p, 'cpu_affinity') else [] 171 if cpus_allowed: 172 os_spec_info[_cpus_allowed] = len(cpus_allowed) 173 os_spec_info[_cpus_list] = ' '.join(str(n) for n in cpus_allowed) 174 175 else: 176 _warning_log.append( 177 "Warning (psutil): psutil cannot be imported. " 178 "For more accuracy, consider installing it.") 179 # Fallback to internal heuristics 180 cmd_selected += params.get('cmd_optional', ()) 181 182 # Assuming the shell cmd returns a unique (k, v) pair per line 183 # or a unique (k, v) pair spread over several lines: 184 # Gather output in a list of strings containing a keyword and some value. 185 output = [] 186 for cmd in cmd_selected: 187 if hasattr(cmd, 'read_file_flag'): 188 # Open file within Python 189 if os.path.exists(cmd[0]): 190 try: 191 with open(cmd[0], 'r') as f: 192 out = f.readlines() 193 if out: 194 out[0] = ' '.join((cmd[0], out[0])) 195 output.extend(out) 196 except OSError as e: 197 _error_log.append(f'Error (file read): {e}') 198 continue 199 else: 200 _warning_log.append('Warning (no file): {}'.format(cmd[0])) 201 continue 202 else: 203 # Spawn a subprocess 204 try: 205 out = check_output(cmd, stderr=PIPE) 206 except (OSError, CalledProcessError) as e: 207 _error_log.append(f'Error (subprocess): {e}') 208 continue 209 if hasattr(cmd, 'buffer_output_flag'): 210 out = b' '.join(line for line in out.splitlines()) + b'\n' 211 output.extend(out.decode().splitlines()) 212 213 # Extract (k, output) pairs by searching for keywords in output 214 kwds = params.get('kwds', {}) 215 for line in output: 216 match = kwds.keys() & line.split() 217 if match and len(match) == 1: 218 k = kwds[match.pop()] 219 os_spec_info[k] = line 220 elif len(match) > 1: 221 print(f'Ambiguous output: {line}') 222 223 # Try to extract something meaningful from output string 224 def format(): 225 # CFS restrictions 226 split = os_spec_info.get(_cfs_quota, '').split() 227 if split: 228 os_spec_info[_cfs_quota] = float(split[-1]) 229 split = os_spec_info.get(_cfs_period, '').split() 230 if split: 231 os_spec_info[_cfs_period] = float(split[-1]) 232 if os_spec_info.get(_cfs_quota, -1) != -1: 233 cfs_quota = os_spec_info.get(_cfs_quota, '') 234 cfs_period = os_spec_info.get(_cfs_period, '') 235 runtime_amount = cfs_quota / cfs_period 236 os_spec_info[_cfs_restrict] = runtime_amount 237 238 def format_optional(): 239 # Memory 240 units = {_mem_total: 1024, _mem_available: 1024} 241 units.update(params.get('units', {})) 242 for k in (_mem_total, _mem_available): 243 digits = ''.join(d for d in os_spec_info.get(k, '') if d.isdigit()) 244 os_spec_info[k] = int(digits or 0) * units[k] 245 # Accessible CPUs 246 split = os_spec_info.get(_cpus_allowed, '').split() 247 if split: 248 n = split[-1] 249 n = n.split(',')[-1] 250 os_spec_info[_cpus_allowed] = str(bin(int(n or 0, 16))).count('1') 251 split = os_spec_info.get(_cpus_list, '').split() 252 if split: 253 os_spec_info[_cpus_list] = split[-1] 254 255 try: 256 format() 257 if not _psutil_import: 258 format_optional() 259 except Exception as e: 260 _error_log.append(f'Error (format shell output): {e}') 261 262 # Call OS specific functions 263 os_specific_funcs = { 264 'Linux': { 265 _libc_version: lambda: ' '.join(platform.libc_ver()) 266 }, 267 'Windows': { 268 _os_spec_version: lambda: ' '.join( 269 s for s in platform.win32_ver()), 270 }, 271 'Darwin': { 272 _os_spec_version: lambda: ''.join( 273 i or ' ' for s in tuple(platform.mac_ver()) for i in s), 274 }, 275 } 276 key_func = os_specific_funcs.get(os_name, {}) 277 os_spec_info.update({k: f() for k, f in key_func.items()}) 278 return os_spec_info 279 280 281def get_sysinfo(): 282 283 # Gather the information that shouldn't raise exceptions 284 sys_info = { 285 _start: datetime.now(), 286 _start_utc: datetime.utcnow(), 287 _machine: platform.machine(), 288 _cpu_name: llvmbind.get_host_cpu_name(), 289 _cpu_count: multiprocessing.cpu_count(), 290 _platform_name: platform.platform(aliased=True), 291 _platform_release: platform.release(), 292 _os_name: platform.system(), 293 _os_version: platform.version(), 294 _python_comp: platform.python_compiler(), 295 _python_impl: platform.python_implementation(), 296 _python_version: platform.python_version(), 297 _numba_env_vars: {k: v for (k, v) in os.environ.items() 298 if k.startswith('NUMBA_')}, 299 _llvm_version: '.'.join(str(i) for i in llvmbind.llvm_version_info), 300 _roc_available: roc.is_available(), 301 _psutil: _psutil_import, 302 } 303 304 # CPU features 305 try: 306 feature_map = llvmbind.get_host_cpu_features() 307 except RuntimeError as e: 308 _error_log.append(f'Error (CPU features): {e}') 309 else: 310 features = sorted([key for key, value in feature_map.items() if value]) 311 sys_info[_cpu_features] = ' '.join(features) 312 313 # Python locale 314 # On MacOSX, getdefaultlocale can raise. Check again if Py > 3.7.5 315 try: 316 # If $LANG is unset, getdefaultlocale() can return (None, None), make 317 # sure we can encode this as strings by casting explicitly. 318 sys_info[_python_locale] = '.'.join([str(i) for i in 319 locale.getdefaultlocale()]) 320 except Exception as e: 321 _error_log.append(f'Error (locale): {e}') 322 323 # CUDA information 324 try: 325 cu.list_devices()[0] # will a device initialise? 326 except Exception as e: 327 sys_info[_cu_dev_init] = False 328 msg_not_found = "CUDA driver library cannot be found" 329 msg_disabled_by_user = "CUDA is disabled" 330 msg_end = " or no CUDA enabled devices are present." 331 msg_generic_problem = "CUDA device intialisation problem." 332 msg = getattr(e, 'msg', None) 333 if msg is not None: 334 if msg_not_found in msg: 335 err_msg = msg_not_found + msg_end 336 elif msg_disabled_by_user in msg: 337 err_msg = msg_disabled_by_user + msg_end 338 else: 339 err_msg = msg_generic_problem + " Message:" + msg 340 else: 341 err_msg = msg_generic_problem + " " + str(e) 342 # Best effort error report 343 _warning_log.append("Warning (cuda): %s\nException class: %s" % 344 (err_msg, str(type(e)))) 345 else: 346 try: 347 sys_info[_cu_dev_init] = True 348 349 output = StringIO() 350 with redirect_stdout(output): 351 cu.detect() 352 sys_info[_cu_detect_out] = output.getvalue() 353 output.close() 354 355 dv = ctypes.c_int(0) 356 cudriver.cuDriverGetVersion(ctypes.byref(dv)) 357 sys_info[_cu_drv_ver] = dv.value 358 359 output = StringIO() 360 with redirect_stdout(output): 361 cudadrv.libs.test(sys.platform, print_paths=False) 362 sys_info[_cu_lib_test] = output.getvalue() 363 output.close() 364 except Exception as e: 365 _warning_log.append( 366 "Warning (cuda): Probing CUDA failed " 367 "(device and driver present, runtime problem?)\n" 368 f"(cuda) {type(e)}: {e}") 369 370 # ROC information 371 # If no ROC try and report why 372 if not sys_info[_roc_available]: 373 from numba.roc.hsadrv.driver import hsa 374 try: 375 hsa.is_available 376 except Exception as e: 377 msg = str(e) 378 else: 379 msg = 'No ROC toolchains found.' 380 _warning_log.append(f"Warning (roc): Error initialising ROC: {msg}") 381 382 toolchains = [] 383 try: 384 libhlc.HLC() 385 toolchains.append('librocmlite library') 386 except Exception: 387 pass 388 try: 389 cmd = hlc.CmdLine().check_tooling() 390 toolchains.append('ROC command line tools') 391 except Exception: 392 pass 393 sys_info[_roc_toolchains] = toolchains 394 395 try: 396 # ROC might not be available due to lack of tool chain, but HSA 397 # agents may be listed 398 from numba.roc.hsadrv.driver import hsa, dgpu_count 399 400 def decode(x): 401 return x.decode('utf-8') if isinstance(x, bytes) else x 402 403 sys_info[_hsa_agents_count] = len(hsa.agents) 404 agents = [] 405 for i, agent in enumerate(hsa.agents): 406 agents.append({ 407 'Agent id': i, 408 'Vendor': decode(agent.vendor_name), 409 'Name': decode(agent.name), 410 'Type': agent.device, 411 }) 412 sys_info[_hsa_agents] = agents 413 414 _dgpus = [] 415 for a in hsa.agents: 416 if a.is_component and a.device == 'GPU': 417 _dgpus.append(decode(a.name)) 418 sys_info[_hsa_gpus_count] = dgpu_count() 419 sys_info[_hsa_gpus] = ', '.join(_dgpus) 420 except Exception as e: 421 _warning_log.append( 422 "Warning (roc): No HSA Agents found, " 423 f"encountered exception when searching: {e}") 424 425 # SVML information 426 # Replicate some SVML detection logic from numba.__init__ here. 427 # If SVML load fails in numba.__init__ the splitting of the logic 428 # here will help diagnosing the underlying issue. 429 svml_lib_loaded = True 430 try: 431 if sys.platform.startswith('linux'): 432 llvmbind.load_library_permanently("libsvml.so") 433 elif sys.platform.startswith('darwin'): 434 llvmbind.load_library_permanently("libsvml.dylib") 435 elif sys.platform.startswith('win'): 436 llvmbind.load_library_permanently("svml_dispmd") 437 else: 438 svml_lib_loaded = False 439 except Exception: 440 svml_lib_loaded = False 441 func = getattr(llvmbind.targets, "has_svml", None) 442 sys_info[_llvm_svml_patched] = func() if func else False 443 sys_info[_svml_state] = config.USING_SVML 444 sys_info[_svml_loaded] = svml_lib_loaded 445 sys_info[_svml_operational] = all(( 446 sys_info[_svml_state], 447 sys_info[_svml_loaded], 448 sys_info[_llvm_svml_patched], 449 )) 450 451 # Check which threading backends are available. 452 def parse_error(e, backend): 453 # parses a linux based error message, this is to provide feedback 454 # and hide user paths etc 455 try: 456 path, problem, symbol = [x.strip() for x in e.msg.split(':')] 457 extn_dso = os.path.split(path)[1] 458 if backend in extn_dso: 459 return "%s: %s" % (problem, symbol) 460 except Exception: 461 pass 462 return "Unknown import problem." 463 464 try: 465 from numba.np.ufunc import tbbpool # NOQA 466 sys_info[_tbb_thread] = True 467 except ImportError as e: 468 # might be a missing symbol due to e.g. tbb libraries missing 469 sys_info[_tbb_thread] = False 470 sys_info[_tbb_error] = parse_error(e, 'tbbpool') 471 472 try: 473 from numba.np.ufunc import omppool 474 sys_info[_openmp_thread] = True 475 sys_info[_openmp_vendor] = omppool.openmp_vendor 476 except ImportError as e: 477 sys_info[_openmp_thread] = False 478 sys_info[_openmp_error] = parse_error(e, 'omppool') 479 480 try: 481 from numba.np.ufunc import workqueue # NOQA 482 sys_info[_wkq_thread] = True 483 except ImportError as e: 484 sys_info[_wkq_thread] = True 485 sys_info[_wkq_error] = parse_error(e, 'workqueue') 486 487 # Look for conda and installed packages information 488 cmd = ('conda', 'info', '--json') 489 try: 490 conda_out = check_output(cmd) 491 except Exception as e: 492 _warning_log.append(f'Warning: Conda not available.\n Error was {e}\n') 493 # Conda is not available, try pip list to list installed packages 494 cmd = (sys.executable, '-m', 'pip', 'list') 495 try: 496 reqs = check_output(cmd) 497 except Exception as e: 498 _error_log.append(f'Error (pip): {e}') 499 else: 500 sys_info[_inst_pkg] = reqs.decode().splitlines() 501 502 else: 503 jsond = json.loads(conda_out.decode()) 504 keys = { 505 'conda_build_version': _conda_build_ver, 506 'conda_env_version': _conda_env_ver, 507 'platform': _conda_platform, 508 'python_version': _conda_python_ver, 509 'root_writable': _conda_root_writable, 510 } 511 for conda_k, sysinfo_k in keys.items(): 512 sys_info[sysinfo_k] = jsond.get(conda_k, 'N/A') 513 514 # Get info about packages in current environment 515 cmd = ('conda', 'list') 516 try: 517 conda_out = check_output(cmd) 518 except CalledProcessError as e: 519 _error_log.append(f'Error (conda): {e}') 520 else: 521 data = conda_out.decode().splitlines() 522 sys_info[_inst_pkg] = [l for l in data if not l.startswith('#')] 523 524 sys_info.update(get_os_spec_info(sys_info[_os_name])) 525 sys_info[_errors] = _error_log 526 sys_info[_warnings] = _warning_log 527 sys_info[_runtime] = (datetime.now() - sys_info[_start]).total_seconds() 528 return sys_info 529 530 531def display_sysinfo(info=None, sep_pos=45): 532 class DisplayMap(dict): 533 display_map_flag = True 534 535 class DisplaySeq(tuple): 536 display_seq_flag = True 537 538 class DisplaySeqMaps(tuple): 539 display_seqmaps_flag = True 540 541 if info is None: 542 info = get_sysinfo() 543 544 fmt = f'%-{sep_pos}s : %-s' 545 MB = 1024**2 546 template = ( 547 ("-" * 80,), 548 ("__Time Stamp__",), 549 ("Report started (local time)", info.get(_start, '?')), 550 ("UTC start time", info.get(_start_utc, '?')), 551 ("Running time (s)", info.get(_runtime, '?')), 552 ("",), 553 ("__Hardware Information__",), 554 ("Machine", info.get(_machine, '?')), 555 ("CPU Name", info.get(_cpu_name, '?')), 556 ("CPU Count", info.get(_cpu_count, '?')), 557 ("Number of accessible CPUs", info.get(_cpus_allowed, '?')), 558 ("List of accessible CPUs cores", info.get(_cpus_list, '?')), 559 ("CFS Restrictions (CPUs worth of runtime)", 560 info.get(_cfs_restrict, 'None')), 561 ("",), 562 ("CPU Features", '\n'.join( 563 ' ' * (sep_pos + 3) + l if i else l 564 for i, l in enumerate( 565 textwrap.wrap( 566 info.get(_cpu_features, '?'), 567 width=79 - sep_pos 568 ) 569 ) 570 )), 571 ("",), 572 ("Memory Total (MB)", info.get(_mem_total, 0) // MB or '?'), 573 ("Memory Available (MB)" 574 if info.get(_os_name, '') != 'Darwin' or info.get(_psutil, False) 575 else "Free Memory (MB)", info.get(_mem_available, 0) // MB or '?'), 576 ("",), 577 ("__OS Information__",), 578 ("Platform Name", info.get(_platform_name, '?')), 579 ("Platform Release", info.get(_platform_release, '?')), 580 ("OS Name", info.get(_os_name, '?')), 581 ("OS Version", info.get(_os_version, '?')), 582 ("OS Specific Version", info.get(_os_spec_version, '?')), 583 ("Libc Version", info.get(_libc_version, '?')), 584 ("",), 585 ("__Python Information__",), 586 DisplayMap({k: v for k, v in info.items() if k.startswith('Python')}), 587 ("",), 588 ("__LLVM Information__",), 589 ("LLVM Version", info.get(_llvm_version, '?')), 590 ("",), 591 ("__CUDA Information__",), 592 ("CUDA Device Initialized", info.get(_cu_dev_init, '?')), 593 ("CUDA Driver Version", info.get(_cu_drv_ver, '?')), 594 ("CUDA Detect Output:",), 595 (info.get(_cu_detect_out, "None"),), 596 ("CUDA Librairies Test Output:",), 597 (info.get(_cu_lib_test, "None"),), 598 ("",), 599 ("__ROC information__",), 600 ("ROC Available", info.get(_roc_available, '?')), 601 ("ROC Toolchains", info.get(_roc_toolchains, []) or 'None'), 602 ("HSA Agents Count", info.get(_hsa_agents_count, 0)), 603 ("HSA Agents:",), 604 (DisplaySeqMaps(info.get(_hsa_agents, {})) or ('None',)), 605 ('HSA Discrete GPUs Count', info.get(_hsa_gpus_count, 0)), 606 ('HSA Discrete GPUs', info.get(_hsa_gpus, 'None')), 607 ("",), 608 ("__SVML Information__",), 609 ("SVML State, config.USING_SVML", info.get(_svml_state, '?')), 610 ("SVML Library Loaded", info.get(_svml_loaded, '?')), 611 ("llvmlite Using SVML Patched LLVM", info.get(_llvm_svml_patched, '?')), 612 ("SVML Operational", info.get(_svml_operational, '?')), 613 ("",), 614 ("__Threading Layer Information__",), 615 ("TBB Threading Layer Available", info.get(_tbb_thread, '?')), 616 ("+-->TBB imported successfully." if info.get(_tbb_thread, '?') 617 else f"+--> Disabled due to {info.get(_tbb_error, '?')}",), 618 ("OpenMP Threading Layer Available", info.get(_openmp_thread, '?')), 619 (f"+-->Vendor: {info.get(_openmp_vendor, '?')}" 620 if info.get(_openmp_thread, False) 621 else f"+--> Disabled due to {info.get(_openmp_error, '?')}",), 622 ("Workqueue Threading Layer Available", info.get(_wkq_thread, '?')), 623 ("+-->Workqueue imported successfully." if info.get(_wkq_thread, False) 624 else f"+--> Disabled due to {info.get(_wkq_error, '?')}",), 625 ("",), 626 ("__Numba Environment Variable Information__",), 627 (DisplayMap(info.get(_numba_env_vars, {})) or ('None found.',)), 628 ("",), 629 ("__Conda Information__",), 630 (DisplayMap({k: v for k, v in info.items() 631 if k.startswith('Conda')}) or ("Conda not available.",)), 632 ("",), 633 ("__Installed Packages__",), 634 DisplaySeq(info.get(_inst_pkg, ("Couldn't retrieve packages info.",))), 635 ("",), 636 ("__Error log__" if info.get(_errors, []) 637 else "No errors reported.",), 638 DisplaySeq(info.get(_errors, [])), 639 ("",), 640 ("__Warning log__" if info.get(_warnings, []) 641 else "No warnings reported.",), 642 DisplaySeq(info.get(_warnings, [])), 643 ("-" * 80,), 644 ("If requested, please copy and paste the information between\n" 645 "the dashed (----) lines, or from a given specific section as\n" 646 "appropriate.\n\n" 647 "=============================================================\n" 648 "IMPORTANT: Please ensure that you are happy with sharing the\n" 649 "contents of the information present, any information that you\n" 650 "wish to keep private you should remove before sharing.\n" 651 "=============================================================\n",), 652 ) 653 for t in template: 654 if hasattr(t, 'display_seq_flag'): 655 print(*t, sep='\n') 656 elif hasattr(t, 'display_map_flag'): 657 print(*tuple(fmt % (k, v) for (k, v) in t.items()), sep='\n') 658 elif hasattr(t, 'display_seqmaps_flag'): 659 for d in t: 660 print(*tuple(fmt % ('\t' + k, v) for (k, v) in d.items()), 661 sep='\n', end='\n') 662 elif len(t) == 2: 663 print(fmt % t) 664 else: 665 print(*t) 666 667 668if __name__ == '__main__': 669 display_sysinfo() 670