summaryrefslogtreecommitdiff
path: root/src/silx/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/silx/test')
-rw-r--r--src/silx/test/__init__.py53
-rw-r--r--src/silx/test/test_resources.py187
-rw-r--r--src/silx/test/test_sx.py265
-rw-r--r--src/silx/test/test_version.py38
-rw-r--r--src/silx/test/utils.py198
5 files changed, 741 insertions, 0 deletions
diff --git a/src/silx/test/__init__.py b/src/silx/test/__init__.py
new file mode 100644
index 0000000..d9d3e42
--- /dev/null
+++ b/src/silx/test/__init__.py
@@ -0,0 +1,53 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2015-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.
+#
+# ###########################################################################*/
+"""This package provides test of the root modules
+"""
+
+import logging
+
+
+try:
+ import pytest
+except ImportError:
+ logging.getLogger(__name__).error(
+ "pytest is required to run the tests, please install it.")
+ raise
+
+def run_tests(module: str='silx', verbosity: int=0, args=()):
+ """Run tests
+
+ :param module: Name of the silx module to test (default: 'silx')
+ :param verbosity: Requested level of verbosity
+ :param args: List of extra arguments to pass to `pytest`
+ """
+ return pytest.main([
+ '--pyargs',
+ module,
+ '--verbosity',
+ str(verbosity),
+ '-o python_files=["test/test*.py","test/Test*.py"]',
+ '-o python_classes=["Test"]',
+ '-o python_functions=["Test"]',
+ ] + list(args))
diff --git a/src/silx/test/test_resources.py b/src/silx/test/test_resources.py
new file mode 100644
index 0000000..4030271
--- /dev/null
+++ b/src/silx/test/test_resources.py
@@ -0,0 +1,187 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016-2018 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.
+#
+# ###########################################################################*/
+"""Test for resource files management."""
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "08/03/2019"
+
+
+import os
+import unittest
+import shutil
+import tempfile
+
+import silx.resources
+
+
+class TestResources(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestResources, cls).setUpClass()
+
+ cls.tmpDirectory = tempfile.mkdtemp(prefix="resource_")
+ os.mkdir(os.path.join(cls.tmpDirectory, "gui"))
+ destination_dir = os.path.join(cls.tmpDirectory, "gui", "icons")
+ os.mkdir(destination_dir)
+ source = silx.resources.resource_filename("gui/icons/zoom-in.png")
+ destination = os.path.join(destination_dir, "foo.png")
+ shutil.copy(source, destination)
+ source = silx.resources.resource_filename("gui/icons/zoom-out.svg")
+ destination = os.path.join(destination_dir, "close.png")
+ shutil.copy(source, destination)
+
+ @classmethod
+ def tearDownClass(cls):
+ super(TestResources, cls).tearDownClass()
+ shutil.rmtree(cls.tmpDirectory)
+
+ def setUp(self):
+ # Store the original configuration
+ self._oldResources = dict(silx.resources._RESOURCE_DIRECTORIES)
+ unittest.TestCase.setUp(self)
+
+ def tearDown(self):
+ unittest.TestCase.tearDown(self)
+ # Restiture the original configuration
+ silx.resources._RESOURCE_DIRECTORIES = self._oldResources
+
+ def test_resource_dir(self):
+ """Get a resource directory"""
+ icons_dirname = silx.resources.resource_filename('gui/icons/')
+ self.assertTrue(os.path.isdir(icons_dirname))
+
+ def test_resource_file(self):
+ """Get a resource file name"""
+ filename = silx.resources.resource_filename('gui/icons/colormap.png')
+ self.assertTrue(os.path.isfile(filename))
+
+ def test_resource_nonexistent(self):
+ """Get a non existent resource"""
+ filename = silx.resources.resource_filename('non_existent_file.txt')
+ self.assertFalse(os.path.exists(filename))
+
+ def test_isdir(self):
+ self.assertTrue(silx.resources.is_dir('gui/icons'))
+
+ def test_not_isdir(self):
+ self.assertFalse(silx.resources.is_dir('gui/icons/colormap.png'))
+
+ def test_list_dir(self):
+ result = silx.resources.list_dir('gui/icons')
+ self.assertTrue(len(result) > 10)
+
+ # With prefixed resources
+
+ def test_resource_dir_with_prefix(self):
+ """Get a resource directory"""
+ icons_dirname = silx.resources.resource_filename('silx:gui/icons/')
+ self.assertTrue(os.path.isdir(icons_dirname))
+
+ def test_resource_file_with_prefix(self):
+ """Get a resource file name"""
+ filename = silx.resources.resource_filename('silx:gui/icons/colormap.png')
+ self.assertTrue(os.path.isfile(filename))
+
+ def test_resource_nonexistent_with_prefix(self):
+ """Get a non existent resource"""
+ filename = silx.resources.resource_filename('silx:non_existent_file.txt')
+ self.assertFalse(os.path.exists(filename))
+
+ def test_isdir_with_prefix(self):
+ self.assertTrue(silx.resources.is_dir('silx:gui/icons'))
+
+ def test_not_isdir_with_prefix(self):
+ self.assertFalse(silx.resources.is_dir('silx:gui/icons/colormap.png'))
+
+ def test_list_dir_with_prefix(self):
+ result = silx.resources.list_dir('silx:gui/icons')
+ self.assertTrue(len(result) > 10)
+
+ # Test new repository
+
+ def test_repository_not_exists(self):
+ """The resource from 'test' is available"""
+ self.assertRaises(ValueError, silx.resources.resource_filename, 'test:foo.png')
+
+ def test_adding_test_directory(self):
+ """The resource from 'test' is available"""
+ silx.resources.register_resource_directory("test", "silx.test.resources", forced_path=self.tmpDirectory)
+ path = silx.resources.resource_filename('test:gui/icons/foo.png')
+ self.assertTrue(os.path.exists(path))
+
+ def test_adding_test_directory_no_override(self):
+ """The resource from 'silx' is still available"""
+ silx.resources.register_resource_directory("test", "silx.test.resources", forced_path=self.tmpDirectory)
+ filename1 = silx.resources.resource_filename('gui/icons/close.png')
+ filename2 = silx.resources.resource_filename('silx:gui/icons/close.png')
+ filename3 = silx.resources.resource_filename('test:gui/icons/close.png')
+ self.assertTrue(os.path.isfile(filename1))
+ self.assertTrue(os.path.isfile(filename2))
+ self.assertTrue(os.path.isfile(filename3))
+ self.assertEqual(filename1, filename2)
+ self.assertNotEqual(filename1, filename3)
+
+ def test_adding_test_directory_non_existing(self):
+ """A resource while not exists in test is not available anyway it exists
+ in silx"""
+ silx.resources.register_resource_directory("test", "silx.test.resources", forced_path=self.tmpDirectory)
+ resource_name = "gui/icons/colormap.png"
+ path = silx.resources.resource_filename('test:' + resource_name)
+ path2 = silx.resources.resource_filename('silx:' + resource_name)
+ self.assertFalse(os.path.exists(path))
+ self.assertTrue(os.path.exists(path2))
+
+
+class TestResourcesWithoutPkgResources(TestResources):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestResourcesWithoutPkgResources, cls).setUpClass()
+ cls._old = silx.resources.pkg_resources
+ silx.resources.pkg_resources = None
+
+ @classmethod
+ def tearDownClass(cls):
+ silx.resources.pkg_resources = cls._old
+ del cls._old
+ super(TestResourcesWithoutPkgResources, cls).tearDownClass()
+
+
+class TestResourcesWithCustomDirectory(TestResources):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestResourcesWithCustomDirectory, cls).setUpClass()
+ cls._old = silx.resources._RESOURCES_DIR
+ base = os.path.dirname(silx.resources.__file__)
+ silx.resources._RESOURCES_DIR = base
+
+ @classmethod
+ def tearDownClass(cls):
+ silx.resources._RESOURCES_DIR = cls._old
+ del cls._old
+ super(TestResourcesWithCustomDirectory, cls).tearDownClass()
diff --git a/src/silx/test/test_sx.py b/src/silx/test/test_sx.py
new file mode 100644
index 0000000..9836285
--- /dev/null
+++ b/src/silx/test/test_sx.py
@@ -0,0 +1,265 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016-2019 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.
+#
+# ###########################################################################*/
+__authors__ = ["T. Vincent", "P. Knobel"]
+__license__ = "MIT"
+__date__ = "06/11/2018"
+
+
+import numpy
+import pytest
+
+from silx.gui import qt
+from silx.gui.colors import rgba
+from silx.gui.colors import Colormap
+
+
+@pytest.fixture(scope="module")
+def sx(qapp):
+ """Lazy loading to avoid it to create QApplication before qapp fixture"""
+ from silx import sx
+ if sx._IS_NOTEBOOK:
+ pytest.skip("notebook context")
+ if sx._NO_DISPLAY:
+ pytest.skip("no DISPLAY specified")
+ yield sx
+
+
+def test_plot(sx, qapp_utils):
+ """Test plot function"""
+ y = numpy.random.random(100)
+ x = numpy.arange(len(y)) * 0.5
+
+ # Nothing
+ plt = sx.plot()
+ qapp_utils.exposeAndClose(plt)
+
+ # y
+ plt = sx.plot(y, title='y')
+ qapp_utils.exposeAndClose(plt)
+
+ # y, style
+ plt = sx.plot(y, 'blued ', title='y, "blued "')
+ qapp_utils.exposeAndClose(plt)
+
+ # x, y
+ plt = sx.plot(x, y, title='x, y')
+ qapp_utils.exposeAndClose(plt)
+
+ # x, y, style
+ plt = sx.plot(x, y, 'ro-', xlabel='x', title='x, y, "ro-"')
+ qapp_utils.exposeAndClose(plt)
+
+ # x, y, style, y
+ plt = sx.plot(x, y, 'ro-', y ** 2, xlabel='x', ylabel='y',
+ title='x, y, "ro-", y ** 2')
+ qapp_utils.exposeAndClose(plt)
+
+ # x, y, style, y, style
+ plt = sx.plot(x, y, 'ro-', y ** 2, 'b--',
+ title='x, y, "ro-", y ** 2, "b--"')
+ qapp_utils.exposeAndClose(plt)
+
+ # x, y, style, x, y, style
+ plt = sx.plot(x, y, 'ro-', x, y ** 2, 'b--',
+ title='x, y, "ro-", x, y ** 2, "b--"')
+ qapp_utils.exposeAndClose(plt)
+
+ # x, y, x, y
+ plt = sx.plot(x, y, x, y ** 2, title='x, y, x, y ** 2')
+ qapp_utils.exposeAndClose(plt)
+
+
+def test_imshow(sx, qapp_utils):
+ """Test imshow function"""
+ img = numpy.arange(100.).reshape(10, 10) + 1
+
+ # Nothing
+ plt = sx.imshow()
+ qapp_utils.exposeAndClose(plt)
+
+ # image
+ plt = sx.imshow(img)
+ qapp_utils.exposeAndClose(plt)
+
+ # image, named cmap
+ plt = sx.imshow(img, cmap='jet', title='jet cmap')
+ qapp_utils.exposeAndClose(plt)
+
+ # image, custom colormap
+ plt = sx.imshow(img, cmap=Colormap(), title='custom colormap')
+ qapp_utils.exposeAndClose(plt)
+
+ # image, log cmap
+ plt = sx.imshow(img, norm='log', title='log cmap')
+ qapp_utils.exposeAndClose(plt)
+
+ # image, fixed range
+ plt = sx.imshow(img, vmin=10, vmax=20,
+ title='[10,20] cmap')
+ qapp_utils.exposeAndClose(plt)
+
+ # image, keep ratio
+ plt = sx.imshow(img, aspect=True,
+ title='keep ratio')
+ qapp_utils.exposeAndClose(plt)
+
+ # image, change origin and scale
+ plt = sx.imshow(img, origin=(10, 10), scale=(2, 2),
+ title='origin=(10, 10), scale=(2, 2)')
+ qapp_utils.exposeAndClose(plt)
+
+ # image, origin='lower'
+ plt = sx.imshow(img, origin='upper', title='origin="lower"')
+ qapp_utils.exposeAndClose(plt)
+
+
+def test_scatter(sx, qapp_utils):
+ """Test scatter function"""
+ x = numpy.arange(100)
+ y = numpy.arange(100)
+ values = numpy.arange(100)
+
+ # simple scatter
+ plt = sx.scatter(x, y, values)
+ qapp_utils.exposeAndClose(plt)
+
+ # No value
+ plt = sx.scatter(x, y, values)
+ qapp_utils.exposeAndClose(plt)
+
+ # single value
+ plt = sx.scatter(x, y, 10.)
+ qapp_utils.exposeAndClose(plt)
+
+ # set size
+ plt = sx.scatter(x, y, values, size=20)
+ qapp_utils.exposeAndClose(plt)
+
+ # set colormap
+ plt = sx.scatter(x, y, values, cmap='jet')
+ qapp_utils.exposeAndClose(plt)
+
+ # set colormap range
+ plt = sx.scatter(x, y, values, vmin=2, vmax=50)
+ qapp_utils.exposeAndClose(plt)
+
+ # set colormap normalisation
+ plt = sx.scatter(x, y, values, norm='log')
+ qapp_utils.exposeAndClose(plt)
+
+
+@pytest.mark.parametrize("plot_kind", ["plot", "imshow", "scatter"])
+def test_ginput(sx, qapp, qapp_utils, plot_kind):
+ """Test ginput function
+
+ This does NOT perform interactive tests
+ """
+ create_plot = getattr(sx, plot_kind)
+ plt = create_plot()
+ qapp_utils.qWaitForWindowExposed(plt)
+ qapp.processEvents()
+
+ result = sx.ginput(1, timeout=0.1)
+ assert len(result) == 0
+
+ plt.setAttribute(qt.Qt.WA_DeleteOnClose)
+ plt.close()
+
+
+@pytest.mark.usefixtures("use_opengl")
+def test_contour3d(sx, qapp_utils):
+ """Test contour3d function"""
+ coords = numpy.linspace(-10, 10, 64)
+ z = coords.reshape(-1, 1, 1)
+ y = coords.reshape(1, -1, 1)
+ x = coords.reshape(1, 1, -1)
+ data = numpy.sin(x * y * z) / (x * y * z)
+
+ # Just data
+ window = sx.contour3d(data)
+
+ isosurfaces = window.getIsosurfaces()
+ assert len(isosurfaces) == 1
+
+ if not window.getPlot3DWidget().isValid():
+ del window, isosurfaces # Release widget reference
+ pytest.skip("OpenGL context is not valid")
+
+ # N contours + color
+ colors = ['red', 'green', 'blue']
+ window = sx.contour3d(data, copy=False, contours=len(colors),
+ color=colors)
+
+ isosurfaces = window.getIsosurfaces()
+ assert len(isosurfaces) == len(colors)
+ for iso, color in zip(isosurfaces, colors):
+ assert rgba(iso.getColor()) == rgba(color)
+
+ # by isolevel, single color
+ contours = 0.2, 0.5
+ window = sx.contour3d(data, copy=False, contours=contours,
+ color='yellow')
+
+ isosurfaces = window.getIsosurfaces()
+ assert len(isosurfaces) == len(contours)
+ for iso, level in zip(isosurfaces, contours):
+ assert iso.getLevel() == level
+ assert rgba(iso.getColor()) == rgba('yellow')
+
+ # Single isolevel, colormap
+ window = sx.contour3d(data, copy=False, contours=0.5,
+ colormap='gray', vmin=0.6, opacity=0.4)
+
+ isosurfaces = window.getIsosurfaces()
+ assert len(isosurfaces) == 1
+ assert isosurfaces[0].getLevel() == 0.5
+ assert rgba(isosurfaces[0].getColor()) == (0., 0., 0., 0.4)
+
+
+@pytest.mark.usefixtures("use_opengl")
+def test_points3d(sx, qapp_utils):
+ """Test points3d function"""
+ x = numpy.random.random(1024)
+ y = numpy.random.random(1024)
+ z = numpy.random.random(1024)
+ values = numpy.random.random(1024)
+
+ # 3D positions, no value
+ window = sx.points3d(x, y, z)
+
+ if not window.getSceneWidget().isValid():
+ del window # Release widget reference
+ pytest.skip("OpenGL context is not valid")
+
+ # 3D positions, values
+ window = sx.points3d(x, y, z, values, mode='2dsquare',
+ colormap='magma', vmin=0.4, vmax=0.5)
+
+ # 2D positions, no value
+ window = sx.points3d(x, y)
+
+ # 2D positions, values
+ window = sx.points3d(x, y, values=values, mode=',',
+ colormap='magma', vmin=0.4, vmax=0.5)
diff --git a/src/silx/test/test_version.py b/src/silx/test/test_version.py
new file mode 100644
index 0000000..80084f9
--- /dev/null
+++ b/src/silx/test/test_version.py
@@ -0,0 +1,38 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2015-2016 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.
+#
+# ###########################################################################*/
+"""Basic test of top-level package import and existence of version info."""
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "26/02/2016"
+
+import unittest
+
+import silx
+
+
+class TestVersion(unittest.TestCase):
+ def test_version(self):
+ self.assertTrue(isinstance(silx.version, str))
diff --git a/src/silx/test/utils.py b/src/silx/test/utils.py
new file mode 100644
index 0000000..0c2d5bf
--- /dev/null
+++ b/src/silx/test/utils.py
@@ -0,0 +1,198 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# 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., mean=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.):
+ """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. + noise / 100.)