6
6
7
7
import atexit
8
8
import json
9
+ import multiprocessing
9
10
import os
10
11
import os .path as op
11
12
import platform
15
16
import sys
16
17
import tempfile
17
18
from functools import partial
19
+ from importlib import import_module
18
20
from pathlib import Path
19
21
20
22
from .check import (_validate_type , _check_qt_version , _check_option ,
@@ -500,56 +502,26 @@ def _get_gpu_info():
500
502
return out
501
503
502
504
503
- def sys_info (fid = None , show_paths = False , * , dependencies = 'user' ):
504
- """Print the system information for debugging .
505
+ def sys_info (fid = None , show_paths = False , * , dependencies = 'user' , unicode = True ):
506
+ """Print system information.
505
507
506
- This function is useful for printing system information
507
- to help triage bugs.
508
+ This function prints system information useful when triaging bugs.
508
509
509
510
Parameters
510
511
----------
511
512
fid : file-like | None
512
- The file to write to. Will be passed to :func:`print()`.
513
- Can be None to use :data:`sys.stdout`.
513
+ The file to write to. Will be passed to :func:`print()`. Can be None to
514
+ use :data:`sys.stdout`.
514
515
show_paths : bool
515
516
If True, print paths for each module.
516
517
dependencies : 'user' | 'developer'
517
518
Show dependencies relevant for users (default) or for developers
518
519
(i.e., output includes additional dependencies).
520
+ unicode : bool
521
+ Include Unicode symbols in output.
519
522
520
523
.. versionadded:: 0.24
521
-
522
- Examples
523
- --------
524
- Running this function with no arguments prints an output that is
525
- useful when submitting bug reports::
526
-
527
- >>> import mne
528
- >>> mne.sys_info() # doctest: +SKIP
529
- Platform: Linux-4.15.0-1067-aws-x86_64-with-glibc2.2.5
530
- Python: 3.8.1 (default, Feb 2 2020, 08:37:37) [GCC 8.3.0]
531
- Executable: /usr/local/bin/python
532
- CPU: : 36 cores
533
- Memory: 68.7 GB
534
-
535
- mne: 0.21.dev0
536
- numpy: 1.19.0 {blas=openblas, lapack=openblas}
537
- scipy: 1.5.1
538
- matplotlib: 3.2.2 {backend=Qt5Agg}
539
-
540
- sklearn: 0.23.1
541
- numba: 0.50.1
542
- nibabel: 3.1.1
543
- nilearn: 0.7.0
544
- dipy: 1.1.1
545
- cupy: Not found
546
- pandas: 1.0.5
547
- pyvista: 0.25.3 {pyvistaqt=0.1.1, OpenGL 3.3 (Core Profile) Mesa 18.3.6 via llvmpipe (LLVM 7.0, 256 bits)}
548
- vtk: 9.0.1
549
- qtpy: 2.0.1 {PySide6=6.2.4}
550
- pyqtgraph: 0.12.4
551
- pooch: v1.5.1
552
- """ # noqa: E501
524
+ """
553
525
_validate_type (dependencies , str )
554
526
_check_option ('dependencies' , dependencies , ('user' , 'developer' ))
555
527
ljust = 21 if dependencies == 'developer' else 18
@@ -569,14 +541,8 @@ def sys_info(fid=None, show_paths=False, *, dependencies='user'):
569
541
out ('Platform:' .ljust (ljust ) + platform_str + '\n ' )
570
542
out ('Python:' .ljust (ljust ) + str (sys .version ).replace ('\n ' , ' ' ) + '\n ' )
571
543
out ('Executable:' .ljust (ljust ) + sys .executable + '\n ' )
572
- out ('CPU:' .ljust (ljust ) + f'{ platform .processor ()} : ' )
573
- try :
574
- import multiprocessing
575
- except ImportError :
576
- out ('number of processors unavailable '
577
- '(requires "multiprocessing" package)\n ' )
578
- else :
579
- out (f'{ multiprocessing .cpu_count ()} cores\n ' )
544
+ out ('CPU:' .ljust (ljust ) + f'{ platform .processor ()} ' )
545
+ out (f'({ multiprocessing .cpu_count ()} cores)\n ' )
580
546
out ('Memory:' .ljust (ljust ))
581
547
try :
582
548
import psutil
@@ -586,26 +552,63 @@ def sys_info(fid=None, show_paths=False, *, dependencies='user'):
586
552
out (f'{ psutil .virtual_memory ().total / float (2 ** 30 ):0.1f} GB\n ' )
587
553
out ('\n ' )
588
554
libs = _get_numpy_libs ()
589
- use_mod_names = ('mne' , 'numpy' , 'scipy' , 'matplotlib' , '' , 'sklearn' ,
590
- 'numba' , 'nibabel' , 'nilearn' , 'dipy' , 'openmeeg' , 'cupy' ,
591
- 'pandas' , 'pyvista' , 'pyvistaqt' , 'ipyvtklink' , 'vtk' ,
592
- 'qtpy' , 'ipympl' , 'pyqtgraph' , 'pooch' , '' , 'mne_bids' ,
593
- 'mne_nirs' , 'mne_features' , 'mne_qt_browser' ,
594
- 'mne_connectivity' , 'mne_icalabel' )
555
+ unavailable = []
556
+ use_mod_names = (
557
+ '# Core' ,
558
+ 'mne' , 'numpy' , 'scipy' , 'matplotlib' , 'pooch' , 'jinja2' ,
559
+ '' ,
560
+ '# Numerical (optional)' ,
561
+ 'sklearn' , 'numba' , 'nibabel' , 'nilearn' , 'dipy' , 'openmeeg' , 'cupy' ,
562
+ 'pandas' ,
563
+ '' ,
564
+ '# Visualization (optional)' ,
565
+ 'pyvista' , 'pyvistaqt' , 'ipyvtklink' , 'vtk' , 'qtpy' , 'ipympl' ,
566
+ 'pyqtgraph' , 'mne-qt-browser' ,
567
+ '' ,
568
+ '# Ecosystem (optional)' ,
569
+ 'mne_bids' , 'mne_nirs' , 'mne_features' , 'mne_connectivity' ,
570
+ 'mne_icalabel' ,
571
+ ''
572
+ )
595
573
if dependencies == 'developer' :
596
574
use_mod_names += (
597
- '' , 'sphinx' , 'sphinx_gallery' , 'numpydoc' , 'pydata_sphinx_theme' ,
598
- 'pytest' , 'nbclient' )
599
- for mod_name in use_mod_names :
600
- if mod_name == '' :
601
- out ('\n ' )
575
+ '# Testing' ,
576
+ 'pytest' , 'nbclient' , 'numpydoc' , 'flake8' , 'pydocstyle' ,
577
+ '' ,
578
+ '# Documentation' ,
579
+ 'sphinx' , 'sphinx_gallery' , 'pydata_sphinx_theme' ,
580
+ '' ,
581
+ )
582
+ try :
583
+ unicode = unicode and (sys .stdout .encoding .lower ().startswith ('utf' ))
584
+ except Exception : # in case someone overrides sys.stdout in an unsafe way
585
+ unicode = False
586
+ for mi , mod_name in enumerate (use_mod_names ):
587
+ # upcoming break
588
+ if mod_name == '' : # break
589
+ if unavailable :
590
+ out ('└☐ ' if unicode else ' - ' )
591
+ out ('unavailable:' .ljust (ljust ))
592
+ out (f"{ ', ' .join (unavailable )} \n " )
593
+ unavailable = []
594
+ if mi != len (use_mod_names ) - 1 :
595
+ out ('\n ' )
596
+ continue
597
+ elif mod_name .startswith ('# ' ): # header
598
+ mod_name = mod_name .replace ('# ' , '' )
599
+ out (f'{ mod_name } \n ' )
602
600
continue
603
- out (f'{ mod_name } :' .ljust (ljust ))
601
+ pre = '├'
602
+ last = use_mod_names [mi + 1 ] == '' and not unavailable
603
+ if last :
604
+ pre = '└'
604
605
try :
605
- mod = __import__ (mod_name )
606
+ mod = import_module (mod_name )
606
607
except Exception :
607
- out ( 'Not found \n ' )
608
+ unavailable . append ( mod_name )
608
609
else :
610
+ out (f'{ pre } ☑ ' if unicode else ' + ' )
611
+ out (f'{ mod_name } :' .ljust (ljust ))
609
612
if mod_name == 'vtk' :
610
613
vtk_version = mod .vtkVersion ()
611
614
# 9.0 dev has VersionFull but 9.0 doesn't
@@ -618,20 +621,26 @@ def sys_info(fid=None, show_paths=False, *, dependencies='user'):
618
621
else :
619
622
out ('unknown' )
620
623
else :
621
- out (mod .__version__ )
624
+ out (mod .__version__ . lstrip ( "v" ) )
622
625
if mod_name == 'numpy' :
623
- out (f' {{ { libs } }} ' )
626
+ out (f' ( { libs } ) ' )
624
627
elif mod_name == 'qtpy' :
625
628
version , api = _check_qt_version (return_api = True )
626
- out (f' {{ { api } ={ version } }} ' )
629
+ out (f' ( { api } ={ version } ) ' )
627
630
elif mod_name == 'matplotlib' :
628
- out (f' {{ backend={ mod .get_backend ()} }} ' )
631
+ out (f' ( backend={ mod .get_backend ()} ) ' )
629
632
elif mod_name == 'pyvista' :
630
633
version , renderer = _get_gpu_info ()
631
634
if version is None :
632
- out (' { OpenGL could not be initialized} ' )
635
+ out (' ( OpenGL unavailable) ' )
633
636
else :
634
- out (f' {{ OpenGL { version } via { renderer } }} ' )
637
+ out (f' ( OpenGL { version } via { renderer } ) ' )
635
638
if show_paths :
636
- out (f'\n { " " * ljust } •{ op .dirname (mod .__file__ )} ' )
639
+ if last :
640
+ pre = ' '
641
+ elif unicode :
642
+ pre = '│ '
643
+ else :
644
+ pre = ' | '
645
+ out (f'\n { pre } { " " * ljust } { op .dirname (mod .__file__ )} ' )
637
646
out ('\n ' )
0 commit comments