Skip to content

Commit 417a9c4

Browse files
cbrnrlarsoner
andauthored
Slightly rework mne.sys_info() (mne-tools#11568)
Co-authored-by: Eric Larson <[email protected]>
1 parent 6384a89 commit 417a9c4

File tree

4 files changed

+90
-74
lines changed

4 files changed

+90
-74
lines changed

azure-pipelines.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ stages:
123123
- bash: |
124124
set -e
125125
mne sys_info -pd
126-
mne sys_info -pd | grep "qtpy: .*{PySide6=.*}$"
126+
mne sys_info -pd | grep "qtpy: .*(PySide6=.*)$"
127127
displayName: Print config
128128
# Uncomment if "xcb not found" Qt errors/segfaults come up again
129129
# - bash: |
@@ -198,23 +198,23 @@ stages:
198198
- bash: |
199199
set -e
200200
mne sys_info -pd
201-
mne sys_info -pd | grep "qtpy: .*{PySide6=.*}$"
201+
mne sys_info -pd | grep "qtpy: .* (PySide6=.*)$"
202202
pytest -m "not slowtest" ${TEST_OPTIONS}
203203
python -m pip uninstall -yq PySide6
204204
displayName: 'PySide6'
205205
- bash: |
206206
set -e
207207
python -m pip install PyQt6
208208
mne sys_info -pd
209-
mne sys_info -pd | grep "^qtpy: .*{PyQt6=.*}$"
209+
mne sys_info -pd | grep "qtpy: .* (PyQt6=.*)$"
210210
pytest -m "not slowtest" ${TEST_OPTIONS}
211211
python -m pip uninstall -yq PyQt6 PyQt6-sip PyQt6-Qt6
212212
displayName: 'PyQt6'
213213
- bash: |
214214
set -e
215215
python -m pip install PySide2
216216
mne sys_info -pd
217-
mne sys_info -pd | grep "^qtpy: .*{PySide2=.*}$"
217+
mne sys_info -pd | grep "qtpy: .* (PySide2=.*)$"
218218
pytest -m "not slowtest" ${TEST_OPTIONS}
219219
python -m pip uninstall -yq PySide2
220220
displayName: 'PySide2'
@@ -223,7 +223,7 @@ stages:
223223
set -e
224224
python -m pip install PyQt5
225225
mne sys_info -pd
226-
mne sys_info -pd | grep "^qtpy: .*{PyQt5=.*}$"
226+
mne sys_info -pd | grep "qtpy: .* (PyQt5=.*)$"
227227
pytest -m "not slowtest" ${TEST_OPTIONS}
228228
python -m pip uninstall -yq PyQt5 PyQt5-sip PyQt5-Qt5
229229
displayName: 'PyQt5'

mne/commands/mne_sys_info.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,20 @@ def run():
2323
parser.add_option('-d', '--developer', dest='developer',
2424
help='Show additional developer module information',
2525
action='store_true')
26+
parser.add_option('-a', '--ascii', dest='unicode',
27+
help='Use ASCII instead of unicode symbols',
28+
action='store_false', default=True)
2629
options, args = parser.parse_args()
2730
dependencies = 'developer' if options.developer else 'user'
2831
if len(args) != 0:
2932
parser.print_help()
3033
sys.exit(1)
3134

32-
mne.sys_info(show_paths=options.show_paths, dependencies=dependencies)
35+
mne.sys_info(
36+
show_paths=options.show_paths,
37+
dependencies=dependencies,
38+
unicode=options.unicode
39+
)
3340

3441

3542
mne.utils.run_command_if_main()

mne/utils/config.py

Lines changed: 76 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import atexit
88
import json
9+
import multiprocessing
910
import os
1011
import os.path as op
1112
import platform
@@ -15,6 +16,7 @@
1516
import sys
1617
import tempfile
1718
from functools import partial
19+
from importlib import import_module
1820
from pathlib import Path
1921

2022
from .check import (_validate_type, _check_qt_version, _check_option,
@@ -500,56 +502,26 @@ def _get_gpu_info():
500502
return out
501503

502504

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.
505507
506-
This function is useful for printing system information
507-
to help triage bugs.
508+
This function prints system information useful when triaging bugs.
508509
509510
Parameters
510511
----------
511512
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`.
514515
show_paths : bool
515516
If True, print paths for each module.
516517
dependencies : 'user' | 'developer'
517518
Show dependencies relevant for users (default) or for developers
518519
(i.e., output includes additional dependencies).
520+
unicode : bool
521+
Include Unicode symbols in output.
519522
520523
.. 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+
"""
553525
_validate_type(dependencies, str)
554526
_check_option('dependencies', dependencies, ('user', 'developer'))
555527
ljust = 21 if dependencies == 'developer' else 18
@@ -569,14 +541,8 @@ def sys_info(fid=None, show_paths=False, *, dependencies='user'):
569541
out('Platform:'.ljust(ljust) + platform_str + '\n')
570542
out('Python:'.ljust(ljust) + str(sys.version).replace('\n', ' ') + '\n')
571543
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')
580546
out('Memory:'.ljust(ljust))
581547
try:
582548
import psutil
@@ -586,26 +552,63 @@ def sys_info(fid=None, show_paths=False, *, dependencies='user'):
586552
out(f'{psutil.virtual_memory().total / float(2 ** 30):0.1f} GB\n')
587553
out('\n')
588554
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+
)
595573
if dependencies == 'developer':
596574
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')
602600
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 = '└'
604605
try:
605-
mod = __import__(mod_name)
606+
mod = import_module(mod_name)
606607
except Exception:
607-
out('Not found\n')
608+
unavailable.append(mod_name)
608609
else:
610+
out(f'{pre}☑ ' if unicode else ' + ')
611+
out(f'{mod_name}:'.ljust(ljust))
609612
if mod_name == 'vtk':
610613
vtk_version = mod.vtkVersion()
611614
# 9.0 dev has VersionFull but 9.0 doesn't
@@ -618,20 +621,26 @@ def sys_info(fid=None, show_paths=False, *, dependencies='user'):
618621
else:
619622
out('unknown')
620623
else:
621-
out(mod.__version__)
624+
out(mod.__version__.lstrip("v"))
622625
if mod_name == 'numpy':
623-
out(f' {{{libs}}}')
626+
out(f' ({libs})')
624627
elif mod_name == 'qtpy':
625628
version, api = _check_qt_version(return_api=True)
626-
out(f' {{{api}={version}}}')
629+
out(f' ({api}={version})')
627630
elif mod_name == 'matplotlib':
628-
out(f' {{backend={mod.get_backend()}}}')
631+
out(f' (backend={mod.get_backend()})')
629632
elif mod_name == 'pyvista':
630633
version, renderer = _get_gpu_info()
631634
if version is None:
632-
out(' {OpenGL could not be initialized}')
635+
out(' (OpenGL unavailable)')
633636
else:
634-
out(f' {{OpenGL {version} via {renderer}}}')
637+
out(f' (OpenGL {version} via {renderer})')
635638
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__)}')
637646
out('\n')

requirements_base.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ pooch>=1.5
77
decorator
88
packaging
99
jinja2
10-
importlib_resources>=5.10.2
10+
importlib_resources>=5.10.2; python_version<'3.9'

0 commit comments

Comments
 (0)