summaryrefslogtreecommitdiff
path: root/src/silx/test/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/silx/test/utils.py')
-rw-r--r--src/silx/test/utils.py199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/silx/test/utils.py b/src/silx/test/utils.py
new file mode 100644
index 0000000..72afdf1
--- /dev/null
+++ b/src/silx/test/utils.py
@@ -0,0 +1,199 @@
+# /*##########################################################################
+#
+# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Utilities for writing tests.
+
+- :func:`temp_dir` provides a with context to create/delete a temporary
+ directory.
+"""
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "03/01/2019"
+
+
+import sys
+import contextlib
+import os
+import numpy
+import shutil
+import tempfile
+from ..resources import ExternalResources
+
+
+utilstest = ExternalResources(
+ project="silx",
+ url_base="http://www.silx.org/pub/silx/",
+ env_key="SILX_DATA",
+ timeout=60,
+)
+"This is the instance to be used. Singleton-like feature provided by module"
+
+
+class _TestOptions(object):
+ def __init__(self):
+ self.WITH_QT_TEST = True
+ """Qt tests are included"""
+
+ self.WITH_QT_TEST_REASON = ""
+ """Reason for Qt tests are disabled if any"""
+
+ self.WITH_OPENCL_TEST = True
+ """OpenCL tests are included"""
+
+ self.WITH_OPENCL_TEST_REASON = ""
+ """Reason for OpenCL tests are disabled if any"""
+
+ self.WITH_GL_TEST = True
+ """OpenGL tests are included"""
+
+ self.WITH_GL_TEST_REASON = ""
+ """Reason for OpenGL tests are disabled if any"""
+
+ self.TEST_LOW_MEM = False
+ """Skip tests using too much memory"""
+
+ self.TEST_LOW_MEM_REASON = ""
+ """Reason for low_memory tests are disabled if any"""
+
+ def configure(self, parsed_options=None):
+ """Configure the TestOptions class from the command line arguments and the
+ environment variables
+ """
+ if parsed_options is not None and not parsed_options.gui:
+ self.WITH_QT_TEST = False
+ self.WITH_QT_TEST_REASON = "Skipped by command line"
+ elif os.environ.get("WITH_QT_TEST", "True") == "False":
+ self.WITH_QT_TEST = False
+ self.WITH_QT_TEST_REASON = "Skipped by WITH_QT_TEST env var"
+ elif sys.platform.startswith("linux") and not os.environ.get("DISPLAY", ""):
+ self.WITH_QT_TEST = False
+ self.WITH_QT_TEST_REASON = "DISPLAY env variable not set"
+
+ if parsed_options is not None and not parsed_options.opencl:
+ self.WITH_OPENCL_TEST_REASON = "Skipped by command line"
+ self.WITH_OPENCL_TEST = False
+ elif os.environ.get("SILX_OPENCL", "True") == "False":
+ self.WITH_OPENCL_TEST_REASON = "Skipped by SILX_OPENCL env var"
+ self.WITH_OPENCL_TEST = False
+
+ if not self.WITH_OPENCL_TEST:
+ # That's an easy way to skip OpenCL tests
+ # It disable the use of OpenCL on the full silx project
+ os.environ["SILX_OPENCL"] = "False"
+
+ if parsed_options is not None and not parsed_options.opengl:
+ self.WITH_GL_TEST = False
+ self.WITH_GL_TEST_REASON = "Skipped by command line"
+ elif os.environ.get("WITH_GL_TEST", "True") == "False":
+ self.WITH_GL_TEST = False
+ self.WITH_GL_TEST_REASON = "Skipped by WITH_GL_TEST env var"
+ elif sys.platform.startswith("linux") and not os.environ.get("DISPLAY", ""):
+ self.WITH_GL_TEST = False
+ self.WITH_GL_TEST_REASON = "DISPLAY env variable not set"
+ else:
+ try:
+ import OpenGL
+ except ImportError:
+ self.WITH_GL_TEST = False
+ self.WITH_GL_TEST_REASON = "OpenGL package not available"
+
+ if parsed_options is not None and parsed_options.low_mem:
+ self.TEST_LOW_MEM = True
+ self.TEST_LOW_MEM_REASON = "Skipped by command line"
+ elif os.environ.get("SILX_TEST_LOW_MEM", "True") == "False":
+ self.TEST_LOW_MEM = True
+ self.TEST_LOW_MEM_REASON = "Skipped by SILX_TEST_LOW_MEM env var"
+
+ if self.WITH_QT_TEST:
+ try:
+ from silx.gui import qt
+ except ImportError:
+ self.WITH_QT_TEST = False
+ self.WITH_QT_TEST_REASON = "Qt is not installed"
+ else:
+ if sys.platform == "win32" and qt.qVersion() == "5.9.2":
+ self.SKIP_TEST_FOR_ISSUE_936 = True
+
+
+# Temporary directory context #################################################
+
+
+@contextlib.contextmanager
+def temp_dir():
+ """with context providing a temporary directory.
+
+ >>> import os.path
+ >>> with temp_dir() as tmp:
+ ... print(os.path.isdir(tmp)) # Use tmp directory
+ """
+ tmp_dir = tempfile.mkdtemp()
+ try:
+ yield tmp_dir
+ finally:
+ shutil.rmtree(tmp_dir)
+
+
+# Synthetic data and random noise #############################################
+def add_gaussian_noise(y, stdev=1.0, mean=0.0):
+ """Add random gaussian noise to synthetic data.
+
+ :param ndarray y: Array of synthetic data
+ :param float mean: Mean of the gaussian distribution of noise.
+ :param float stdev: Standard deviation of the gaussian distribution of
+ noise.
+ :return: Array of data with noise added
+ """
+ noise = numpy.random.normal(mean, stdev, size=y.size)
+ noise.shape = y.shape
+ return y + noise
+
+
+def add_poisson_noise(y):
+ """Add random noise from a poisson distribution to synthetic data.
+
+ :param ndarray y: Array of synthetic data
+ :return: Array of data with noise added
+ """
+ yn = numpy.random.poisson(y)
+ yn.shape = y.shape
+ return yn
+
+
+def add_relative_noise(y, max_noise=5.0):
+ """Add relative random noise to synthetic data. The maximum noise level
+ is given in percents.
+
+ An array of noise in the interval [-max_noise, max_noise] (continuous
+ uniform distribution) is generated, and applied to the data the
+ following way:
+
+ :math:`yn = y * (1. + noise / 100.)`
+
+ :param ndarray y: Array of synthetic data
+ :param float max_noise: Maximum percentage of noise
+ :return: Array of data with noise added
+ """
+ noise = max_noise * (2 * numpy.random.random(size=y.size) - 1)
+ noise.shape = y.shape
+ return y * (1.0 + noise / 100.0)