diff --git a/docs/api/index.rst b/docs/api/index.rst index 5ec471c745..5ca53b0028 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -301,6 +301,7 @@ Print versions of packages that might influence numerical results. .. autosummary:: :toctree: . + logging.print_header logging.print_versions diff --git a/docs/release-latest.rst b/docs/release-latest.rst index 31d4e21c97..1199e465c5 100644 --- a/docs/release-latest.rst +++ b/docs/release-latest.rst @@ -41,6 +41,7 @@ This release includes an overhaul of :func:`~scanpy.pl.dotplot`, :func:`~scanpy. - Added `backup_url` param to :func:`~scanpy.read_10x_h5` :pr:`1296` :smaller:`A Gayoso` - Allow prefix for :func:`~scanpy.read_10x_mtx` :pr:`1250` :smaller:`G Sturm` - Optional tie correction for the `'wilcoxon'` method in :func:`~scanpy.tl.rank_genes_groups` :pr:`1330` :smaller:`S Rybakov` +- Use `sinfo` for :func:`~scanpy.logging.print_versions` and add :func:`~scanpy.logging.print_header` to do what it previously did. :pr:`1338` :smaller:`I Virshup` :pr:`1373` .. rubric:: Bug fixes diff --git a/scanpy/api/__init__.py b/scanpy/api/__init__.py index a781eb7838..b5fc06e6ac 100644 --- a/scanpy/api/__init__.py +++ b/scanpy/api/__init__.py @@ -276,6 +276,7 @@ .. autosummary:: + logging.print_header logging.print_versions diff --git a/scanpy/logging.py b/scanpy/logging.py index 2d0edc70e7..683e6237da 100644 --- a/scanpy/logging.py +++ b/scanpy/logging.py @@ -1,5 +1,6 @@ """Logging and Profiling """ +import io import logging import sys from functools import update_wrapper, partial @@ -112,17 +113,56 @@ def format(self, record: logging.LogRecord): get_memory_usage = anndata.logging.get_memory_usage +_DEPENDENCIES_NUMERICS = [ + 'anndata', # anndata actually shouldn't, but as long as it's in development + 'umap', + 'numpy', + 'scipy', + 'pandas', + ('sklearn', 'scikit-learn'), + 'statsmodels', + ('igraph', 'python-igraph'), + 'louvain', + 'leidenalg', +] + + +def _versions_dependencies(dependencies): + # this is not the same as the requirements! + for mod in dependencies: + mod_name, dist_name = mod if isinstance(mod, tuple) else (mod, mod) + try: + imp = __import__(mod_name) + yield dist_name, imp.__version__ + except (ImportError, AttributeError): + pass + + +def print_header(*, file=None): + """\ + Versions that might influence the numerical results. + Matplotlib and Seaborn are excluded from this. + """ + + modules = ['scanpy'] + _DEPENDENCIES_NUMERICS + print(' '.join( + f'{mod}=={ver}' + for mod, ver in _versions_dependencies(modules) + ), file=file or sys.stdout) + + def print_versions(*, file=None): """Print print versions of imported packages""" - if file is None: + if file is None: # Inform people about the behavior change + warning('If you miss a compact list, please try `print_header`!') + stdout = sys.stdout + try: + buf = sys.stdout = io.StringIO() sinfo(dependencies=True) - else: - stdout = sys.stdout - try: - sys.stdout = file - sinfo(dependencies=True) - finally: - sys.stdout = stdout + finally: + sys.stdout = stdout + output = buf.getvalue() + print(output, file=file) def print_version_and_date(*, file=None):