diff --git a/deerlab/utils.py b/deerlab/utils.py index 8e121908..46b139dc 100644 --- a/deerlab/utils.py +++ b/deerlab/utils.py @@ -955,3 +955,90 @@ def choleskycovmat(Q,cholfactors): return Σ # ---------------------------------------------------------------------------------- + + +def _config(): + import importlib + import sys + import os + import platform + config = {} + + # Versions + config['python_version'] = sys.version.split()[0] + module = importlib.import_module('deerlab') + version = getattr(module,'__version__', 'unknown') + config['deerlab_version'] = version + + cpu_cores = os.process_cpu_count() if hasattr(os, 'process_cpu_count') else os.cpu_count() + operating_system = sys.platform + + config['cpu_cores'] = cpu_cores + config['operating_system'] = operating_system + config['operating_system_version'] = platform.release() + config['platform'] = platform.machine() + + # NNLS backendss + nnls_backends ={} + for nnls_backend in ['numpy','scipy','cvxopt','quadprog']: + print(f'Testing backend: {nnls_backend}') + state = importlib.util.find_spec(nnls_backend) is not None + if state: + module = importlib.import_module(nnls_backend) + version = getattr(module,'__version__', 'unknown') + nnls_backends[nnls_backend] = (True, version) + else: + nnls_backends[nnls_backend] = (False, None) + config['nnls_backends'] = nnls_backends + + ## BLAS linking + import numpy as np + config['numpy'] = {'version': np.__version__} + blas_info = np.__config__.CONFIG['Build Dependencies']['blas'] + lapack_info = np.__config__.CONFIG['Build Dependencies']['lapack'] + config['numpy']['BLAS'] = blas_info['name'] + config['numpy']['LAPACK'] = lapack_info['name'] + + import scipy + config['scipy'] = {'version': scipy.__version__} + scipy_blas_info = scipy.__config__.CONFIG['Build Dependencies']['blas'] + scipy_lapack_info = scipy.__config__.CONFIG['Build Dependencies']['lapack'] + config['scipy']['BLAS'] = scipy_blas_info['name'] + config['scipy']['LAPACK'] = scipy_lapack_info['name'] + + return config + +def show_config(mode='stdout'): + """ + Shows the current configuration of DeerLab, including the current machine infomation and the libaries that DeerLab is built upon. + + Notes + ----- + On Python < 3.13, the CPU core count is estimated using `os.cpu_count()`, which may not always be accurate. On Python >= 3.13, `os.process_cpu_count()` is used for a more accurate count. + + Parameters + ---------- + mode : str, optional + Indicates how to display the config information. ‘stdout’ prints to console, ‘dicts’ returns a dictionary of the configuration. + + Returns + ------- + config : dict, optional + If `mode` is set to 'dicts', returns a dictionary containing the configuration information. + """ + CONFIG = _config() + if mode == 'stdout': + try: # Non-standard library, check import + import yaml + + print(yaml.dump(CONFIG)) + except ModuleNotFoundError: + import warnings + import json + + warnings.warn("Install `pyyaml` for better output", stacklevel=1) + print(json.dumps(CONFIG, indent=2)) + elif mode == 'dicts': + return CONFIG + else: + raise ValueError("Invalid mode. Use 'stdout' or 'dicts'.") diff --git a/docsrc/source/reference.rst b/docsrc/source/reference.rst index afda906d..652289e6 100644 --- a/docsrc/source/reference.rst +++ b/docsrc/source/reference.rst @@ -83,3 +83,4 @@ Reference Index ovl der_snr formatted_table + show_config diff --git a/test/test_utils.py b/test/test_utils.py index f111e009..93025d9c 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -35,3 +35,23 @@ def test_sophegrid(): assert np.allclose(phi, np.array([0]),rtol=1e-4) assert np.allclose(theta, np.array([0]),rtol=1e-4) assert np.allclose(weights*4*np.pi, np.array([12.5664]),rtol=1e-4) + +def test_config(): + from deerlab.utils import show_config + + config_dict = show_config(mode='dicts') + + assert 'python_version' in config_dict + assert 'deerlab_version' in config_dict + assert 'cpu_cores' in config_dict + assert 'operating_system' in config_dict + assert 'operating_system_version' in config_dict + + assert 'version' in config_dict['numpy'] + assert 'BLAS' in config_dict['numpy'] + assert 'LAPACK' in config_dict['numpy'] + assert 'version' in config_dict['scipy'] + assert 'BLAS' in config_dict['scipy'] + assert 'LAPACK' in config_dict['scipy'] + + show_config()