# For convenience, import collection and numpy
# into the "pyradiomics" namespace
import collections # noqa: F401
import inspect
import logging
import os
import pkgutil
import sys
import traceback
import numpy # noqa: F401
from . import base, imageoperations
if sys.version_info < (2, 6, 0):
raise ImportError("pyradiomics > 0.9.7 requires python 2.6 or later")
[docs]def debug(debug_on=True):
"""
Control level of logger and stderr output of the toolbox. By default, this output reflects module hierarchy, as child
loggers are created by module. This is achieved by the following line in base.py:
``self.logger = logging.getLogger(self.__module__)``. To use same instance in each module, set
``self.logger=logging.getLogger('radiomics')``.
At command line, turn on debugging output to stderr for all pyradiomics functions with:
``import radiomics``\n
``radiomics.debug()``
This set the level of both the logger and the handler for output to stderr to level = DEBUG. If level of logger is
already at level "DEBUG" or "NOTSET", level of logger is not changed.
Turn off debugging with (only changes the level of the handler for output to stderr):
``radiomics.debug(False)``
By default, the radiomics logger is set to level "INFO" and the stderr handler to level "WARNING". Therefore a log
storing the extraction log messages from level "INFO" and up can be easily set up by adding an appropriate handler to
the radiomics logger.
"""
global logger, debugging
if debug_on:
setVerbosity(logging.DEBUG) # set the output to stderr to DEBUG
debugging = True
else:
setVerbosity(logging.WARNING) # set the output to stderr to WARNING
debugging = False
[docs]def setVerbosity(level):
"""
Assumes the handler added to the radiomics logger at initialization of the toolbox is not removed from the logger
handlers.
Using the ``level`` (Python defined logging levels) argument, determine how much PyRadiomics should print out to the
stderr, the following levels are possible:
- 60: Quiet mode, no messages are printed to the stderr
- 50: Only log messages of level "CRITICAL" are printed
- 40: Log messages of level "ERROR" and up are printed
- 30: Log messages of level "WARNING" and up are printed
- 20: Log messages of level "INFO" and up are printed
- 10: Log messages of level "DEBUG" and up are printed (i.e. all log messages)
**N.B. This does not affect the level of the logger itself (e.g. if verbosity level = 3, log messages with DEBUG level
can still be stored in a log file if an appropriate handler is added to the logger and the logging level of the logger
has been set to the correct level**
"""
global logger, handler
if level < 10: # Lowest level: DEBUG
level = 10
if level > 60: # Highest level = 50 (CRITICAL), level 60 results in a 'quiet' mode
level = 60
handler.setLevel(level)
if handler.level < logger.level: # reduce level of logger if necessary
logger.setLevel(level)
[docs]def enableCExtensions(enabled=True):
"""
By default, calculation of GLCM, GLRLM and GLSZM is done in C, using extension ``_cmatrices.py``
If an error occurs during loading of this extension, a warning is logged and the extension is disabled,
matrices are then calculated in python.
The C extension can be disabled by calling this function as ``enableCExtensions(False)``, which forces the calculation
of the matrices to full-python mode.
Re-enabling use of C implementation is also done by this function, but if the extension is not loaded correctly,
a warning is logged and matrix calculation is forced to full-python mode.
"""
global _cMatsState, logger
if enabled:
# If extensions are not yet enabled (_cMatsState == 2), check whether they are loaded (_cMatsState == 1) and if so,
# enable them. Otherwise, log a warning.
if _cMatsState == 1: # Extension loaded but not enabled
logger.info("Enabling C extensions")
_cMatsState = 2 # Enables matrix calculation in C
elif _cMatsState == 0: # _Extension not loaded correctly, do not enable matrix calculation in C and log warning
logger.warning("C Matrices not loaded correctly, cannot calculate matrices in C")
elif _cMatsState == 2: # enabled = False, _cMatsState = 2: extensions currently enabled, disable them
logger.info("Disabling C extensions")
_cMatsState = 1
[docs]def cMatsEnabled():
"""
Returns a boolean indicating whether or not the C extensions are enabled. This function is called by the feature
classes to switch between C-enhanced calculation and full python mode.
"""
return _cMatsState == 2
[docs]def getFeatureClasses():
"""
Iterates over all modules of the radiomics package using pkgutil and subsequently imports those modules.
Return a dictionary of all modules containing featureClasses, with modulename as key, abstract
class object of the featureClass as value. Assumes only one featureClass per module
This is achieved by inspect.getmembers. Modules are added if it contains a member that is a class,
with name starting with 'Radiomics' and is inherited from :py:class:`radiomics.base.RadiomicsFeaturesBase`.
This iteration only runs once (at initialization of toolbox), subsequent calls return the dictionary created by the
first call.
"""
global _featureClasses
if _featureClasses is None: # On first call, enumerate possible feature classes and import PyRadiomics modules
_featureClasses = {}
for _, mod, _ in pkgutil.iter_modules([os.path.dirname(base.__file__)]):
if str(mod).startswith('_'): # Skip loading of 'private' classes, these don't contain feature classes
continue
__import__('radiomics.' + mod)
module = sys.modules['radiomics.' + mod]
attributes = inspect.getmembers(module, inspect.isclass)
for a in attributes:
if a[0].startswith('Radiomics'):
if base.RadiomicsFeaturesBase in inspect.getmro(a[1])[1:]:
_featureClasses[mod] = a[1]
return _featureClasses
debugging = True
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO) # Set default level of logger to INFO to reflect most common setting for a log file
handler = logging.StreamHandler()
# formatter = logging.Formatter("%(asctime)s %(levelname)s: %(message)s", "%Y-%m-%d %H:%M")
formatter = logging.Formatter("%(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
debug(False) # force level=WARNING for stderr handler, in case logging default is set differently (issue 102)
_featureClasses = None
_inputImages = None
# Indicates status of C extensions: 0 = not loaded, 1 = loaded but not enabled, 2 = enabled
_cMatsState = 0
try:
from radiomics import _cmatrices as cMatrices
from radiomics import _cshape as cShape
_cMatsState = 1
enableCExtensions()
except Exception:
logger.warning("Error loading C extensions, switching to python calculation:\n%s", traceback.format_exc())
cMatrices = None # set cMatrices to None to prevent an import error in the feature classes.
cShape = None
from ._version import get_versions
__version__ = get_versions()['version']
del get_versions
getFeatureClasses()
getInputImageTypes()