diff --git a/src/skore/__init__.py b/src/skore/__init__.py index 3b01c1474..3315055f6 100644 --- a/src/skore/__init__.py +++ b/src/skore/__init__.py @@ -1,4 +1,4 @@ -"""Provide the Store class for managing information in a data science project.""" +"""Configure logging and global settings.""" import logging @@ -6,8 +6,11 @@ from skore.project import Project, load +from .utils._show_versions import show_versions + __all__ = [ "load", + "show_versions", "Project", ] diff --git a/src/skore/utils/__init__.py b/src/skore/utils/__init__.py new file mode 100644 index 000000000..3ee290a4d --- /dev/null +++ b/src/skore/utils/__init__.py @@ -0,0 +1 @@ +"""Various utilities to help with development.""" diff --git a/src/skore/utils/_show_versions.py b/src/skore/utils/_show_versions.py new file mode 100644 index 000000000..bfac99942 --- /dev/null +++ b/src/skore/utils/_show_versions.py @@ -0,0 +1,81 @@ +""" +Utility methods to print system info for debugging. + +adapted from :func:`sklearn.show_versions` +""" + +import importlib +import platform +import sys + + +def _get_sys_info(): + """System information. + + Returns + ------- + sys_info : dict + system and Python version information + + """ + python = sys.version.replace("\n", " ") + + blob = [ + ("python", python), + ("executable", sys.executable), + ("machine", platform.platform()), + ] + + return dict(blob) + + +def _get_deps_info(): + """Overview of the installed version of main dependencies. + + This function does not import the modules to collect the version numbers + but instead relies on standard Python package metadata. + + Returns + ------- + deps_info: dict + version information on relevant Python libraries + + """ + from importlib.metadata import PackageNotFoundError, version + + deps = ["pip", "setuptools"] + + requirements = importlib.metadata.requires("skore") + for requirement in filter(lambda r: "; extra" not in r, requirements): + deps.append(requirement) + + deps_info = { + "skore": version("skore"), + } + + for modname in deps: + try: + deps_info[modname] = version(modname) + except PackageNotFoundError: + deps_info[modname] = None + return deps_info + + +def show_versions(): + """Print useful debugging information. + + Examples + -------- + >>> from skore import show_versions + >>> show_versions() # doctest: +SKIP + """ + sys_info = _get_sys_info() + deps_info = _get_deps_info() + + print("\nSystem:") # noqa: T201 + for k, stat in sys_info.items(): + print(f"{k:>10}: {stat}") # noqa: T201 + + print("\nPython dependencies:") # noqa: T201 + for k, stat in deps_info.items(): + print(f"{k:>13}: {stat}") # noqa: T201 diff --git a/tests/unit/utils/test_show_versions.py b/tests/unit/utils/test_show_versions.py new file mode 100644 index 000000000..13ed68889 --- /dev/null +++ b/tests/unit/utils/test_show_versions.py @@ -0,0 +1,46 @@ +import os +import tempfile + +from skore.utils._show_versions import _get_deps_info, _get_sys_info, show_versions + + +def test_get_sys_info(): + sys_info = _get_sys_info() + assert isinstance(sys_info, dict) + assert "python" in sys_info + assert "executable" in sys_info + assert "machine" in sys_info + + +def test_get_deps_info(): + deps_info = _get_deps_info() + assert isinstance(deps_info, dict) + assert "pip" in deps_info + assert "setuptools" in deps_info + assert "skore" in deps_info + + +def test_show_versions(capfd): + show_versions() + captured = capfd.readouterr() + assert "python" in captured.out + assert "executable" in captured.out + assert "machine" in captured.out + assert "pip" in captured.out + assert "setuptools" in captured.out + assert "skore" in captured.out + + +def test_get_deps_in_any_working_directory(capfd): + cwd = os.getcwd() + with tempfile.TemporaryDirectory() as temp_dir: + os.chdir(temp_dir) + show_versions() + captured = capfd.readouterr() + assert "python" in captured.out + assert "executable" in captured.out + assert "machine" in captured.out + assert "pip" in captured.out + assert "setuptools" in captured.out + assert "skore" in captured.out + os.chdir(cwd)