a b/dosma/utils/env.py
1
import logging
2
import os
3
from importlib import util
4
5
_SUPPORTED_PACKAGES = {}
6
7
_FILE_DIRECTORY = os.path.abspath(os.path.dirname(__file__))
8
9
__all__ = ["debug", "get_version", "package_available"]
10
11
12
def package_available(name: str):
13
    """Returns if package is available.
14
15
    Args:
16
        name (str): Name of the package.
17
18
    Returns:
19
        bool: Whether module exists in environment.
20
    """
21
    global _SUPPORTED_PACKAGES
22
    if name not in _SUPPORTED_PACKAGES:
23
        _SUPPORTED_PACKAGES[name] = util.find_spec(name) is not None
24
    return _SUPPORTED_PACKAGES[name]
25
26
27
def get_version(package_or_name) -> str:
28
    """Returns package version.
29
30
    Args:
31
        package_or_name (``module`` or ``str``): Module or name of module.
32
            This package must have the version accessible through ``<module>.__version__``.
33
34
    Returns:
35
        str: The package version.
36
37
    Examples:
38
        >>> get_version("numpy")
39
        "1.20.0"
40
    """
41
    if isinstance(package_or_name, str):
42
        if not package_available(package_or_name):
43
            raise ValueError(f"Package {package_or_name} not available")
44
        spec = util.find_spec(package_or_name)
45
        package_or_name = util.module_from_spec(spec)
46
        spec.loader.exec_module(package_or_name)
47
    version = package_or_name.__version__
48
    return version
49
50
51
def debug(value: bool = None) -> bool:
52
    """Return (and optionally set) debug mode.
53
54
    Args:
55
        value (bool, optional): If specified, sets the debug status.
56
            If not specified, debug mode is not set, only returned.
57
58
    Returns:
59
        bool: If ``True``, debug mode is active.
60
61
    Raises:
62
        ValueError: If ``value`` is not a supported value.
63
64
    Note:
65
        Changing the debug state changes the stream handler logging level
66
        for the default dosma logger. If debug state is turned off, logging
67
        level is set to ``logging.INFO``. If debug state is turned on,
68
        logging level is set to ``logging.DEBUG``.
69
70
    Examples:
71
        >>> debug()  # get debug status, defaults to False
72
        False
73
        >>> debug(True)  # turn on debug mode
74
        True
75
        >>> debug()  # get debug status
76
        True
77
    """
78
79
    def _is_debug():
80
        return os.environ.get("DOSMA_DEBUG", "") in ["True", "true"]
81
82
    def _toggle_debug(_old_value, _new_value):
83
        from dosma.defaults import preferences
84
85
        # TODO: Toggle dosma logging to debug mode.
86
        if _old_value == _new_value:
87
            return
88
89
        _dm_logger = logging.getLogger("dosma")
90
        if _new_value:
91
            preferences.set("nipype", value="stream", prefix="logging")
92
            _dm_logger.setLevel(logging.DEBUG)
93
            for h in _dm_logger.handlers:
94
                h.setLevel(logging.DEBUG)
95
        else:
96
            preferences.set("nipype", value="file_stderr", prefix="logging")
97
            _dm_logger.setLevel(logging.DEBUG)  # the root logger should always log at DEBUG level
98
            for h in _dm_logger.handlers:
99
                if isinstance(h, logging.StreamHandler):
100
                    h.setLevel(logging.INFO)
101
102
    if value is not None:
103
        old_value = _is_debug()
104
        if isinstance(value, bool):
105
            os.environ["DOSMA_DEBUG"] = str(value)
106
        elif isinstance(value, str) and value.lower() in ("true", "false", ""):
107
            os.environ["DOSMA_DEBUG"] = value
108
        else:
109
            raise ValueError(f"Unknown value for debug: '{value}'")
110
111
        _toggle_debug(old_value, _is_debug())
112
113
    return _is_debug()
114
115
116
def sitk_available():
117
    return package_available("SimpleITK")
118
119
120
def cupy_available():
121
    if "cupy" not in _SUPPORTED_PACKAGES:
122
        try:
123
            import cupy  # noqa
124
        except ImportError:
125
            _SUPPORTED_PACKAGES["cupy"] = False
126
    return package_available("cupy")
127
128
129
def sigpy_available():
130
    return package_available("sigpy")
131
132
133
def torch_available():
134
    return package_available("torch")
135
136
137
def resources_dir() -> str:
138
    return os.path.abspath(os.path.join(_FILE_DIRECTORY, "../resources"))
139
140
141
def output_dir() -> str:
142
    return os.path.abspath(os.path.join(_FILE_DIRECTORY, "../../.dosma"))
143
144
145
def temp_dir() -> str:
146
    return os.path.join(output_dir(), "temp")
147
148
149
def log_file_path() -> str:
150
    return os.path.join(output_dir(), "dosma.log")