import contextlib
import os
import platform
import subprocess
import sys
from importlib.metadata import PackageNotFoundError, version
import napari
OS_RELEASE_PATH = '/etc/os-release'
def _linux_sys_name() -> str:
"""
Try to discover linux system name base on /etc/os-release file or lsb_release command output
https://www.freedesktop.org/software/systemd/man/os-release.html
"""
if os.path.exists(OS_RELEASE_PATH):
with open(OS_RELEASE_PATH) as f_p:
data = {}
for line in f_p:
field, value = line.split('=')
data[field.strip()] = value.strip().strip('"')
if 'PRETTY_NAME' in data:
return data['PRETTY_NAME']
if 'NAME' in data:
if 'VERSION' in data:
return f'{data["NAME"]} {data["VERSION"]}'
if 'VERSION_ID' in data:
return f'{data["NAME"]} {data["VERSION_ID"]}'
return f'{data["NAME"]} (no version)'
return _linux_sys_name_lsb_release()
def _linux_sys_name_lsb_release() -> str:
"""
Try to discover linux system name base on lsb_release command output
"""
with contextlib.suppress(subprocess.CalledProcessError):
res = subprocess.run(
['lsb_release', '-d', '-r'], check=True, capture_output=True
)
text = res.stdout.decode()
data = {}
for line in text.split('\n'):
key, val = line.split(':')
data[key.strip()] = val.strip()
version_str = data['Description']
if not version_str.endswith(data['Release']):
version_str += ' ' + data['Release']
return version_str
return ''
def _sys_name() -> str:
"""
Discover MacOS or Linux Human readable information. For Linux provide information about distribution.
"""
with contextlib.suppress(Exception):
if sys.platform == 'linux':
return _linux_sys_name()
if sys.platform == 'darwin':
with contextlib.suppress(subprocess.CalledProcessError):
res = subprocess.run(
['sw_vers', '-productVersion'],
check=True,
capture_output=True,
)
return f'MacOS {res.stdout.decode().strip()}'
return ''
[docs]
def sys_info(as_html: bool = False) -> str:
"""Gathers relevant module versions for troubleshooting purposes.
Parameters
----------
as_html : bool
if True, info will be returned as HTML, suitable for a QTextEdit widget
"""
sys_version = sys.version.replace('\n', ' ')
text = (
f'<b>napari</b>: {napari.__version__}<br>'
f'<b>Platform</b>: {platform.platform()}<br>'
)
__sys_name = _sys_name()
if __sys_name:
text += f'<b>System</b>: {__sys_name}<br>'
text += f'<b>Python</b>: {sys_version}<br>'
try:
from qtpy import API_NAME, PYQT_VERSION, PYSIDE_VERSION, QtCore
if API_NAME == 'PySide2':
API_VERSION = PYSIDE_VERSION
elif API_NAME == 'PyQt5':
API_VERSION = PYQT_VERSION
else:
API_VERSION = ''
text += (
f'<b>Qt</b>: {QtCore.__version__}<br>'
f'<b>{API_NAME}</b>: {API_VERSION}<br>'
)
except Exception as e: # noqa BLE001
text += f'<b>Qt</b>: Import failed ({e})<br>'
modules = (
('numpy', 'NumPy'),
('scipy', 'SciPy'),
('dask', 'Dask'),
('vispy', 'VisPy'),
('magicgui', 'magicgui'),
('superqt', 'superqt'),
('in_n_out', 'in-n-out'),
('app_model', 'app-model'),
('psygnal', 'psygnal'),
('npe2', 'npe2'),
('pydantic', 'pydantic'),
)
loaded = {}
for module, name in modules:
try:
loaded[module] = __import__(module)
text += f'<b>{name}</b>: {version(module)}<br>'
except PackageNotFoundError:
text += f'<b>{name}</b>: Import failed<br>'
text += '<br><b>OpenGL:</b><br>'
if loaded.get('vispy', False):
from napari._vispy.utils.gl import get_max_texture_sizes
sys_info_text = (
'<br>'.join(
[
loaded['vispy'].sys_info().split('\n')[index]
for index in [-4, -3]
]
)
.replace("'", '')
.replace('<br>', '<br> - ')
)
text += f' - {sys_info_text}<br>'
_, max_3d_texture_size = get_max_texture_sizes()
text += f' - GL_MAX_3D_TEXTURE_SIZE: {max_3d_texture_size}<br>'
else:
text += ' - failed to load vispy'
text += '<br><b>Screens:</b><br>'
try:
from qtpy.QtGui import QGuiApplication
screen_list = QGuiApplication.screens()
for i, screen in enumerate(screen_list, start=1):
text += f' - screen {i}: resolution {screen.geometry().width()}x{screen.geometry().height()}, scale {screen.devicePixelRatio()}<br>'
except Exception as e: # noqa BLE001
text += f' - failed to load screen information {e}'
text += '<br><b>Optional:</b><br>'
optional_modules = (
('numba', 'numba'),
('triangle', 'triangle'),
('napari_plugin_manager', 'napari-plugin-manager'),
)
for module, name in optional_modules:
try:
text += f' - <b>{name}</b>: {version(module)}<br>'
except PackageNotFoundError:
text += f' - {name} not installed<br>'
text += '<br><b>Settings path:</b><br>'
try:
from napari.settings import get_settings
text += f' - {get_settings().config_path}'
except ValueError:
from napari.utils._appdirs import user_config_dir
text += f" - {os.getenv('NAPARI_CONFIG', user_config_dir())}"
if not as_html:
text = (
text.replace('<br>', '\n').replace('<b>', '').replace('</b>', '')
)
return text
citation_text = (
'napari contributors (2019). napari: a '
'multi-dimensional image viewer for python. '
'doi:10.5281/zenodo.3555620'
)