forked from AmbaPant/mantid
-
Notifications
You must be signed in to change notification settings - Fork 1
/
__init__.py
269 lines (238 loc) · 10.6 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source,
# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 +
"""Defines a set of helpers wrapped around the C++ TestHelpers package that
are for use in unit tests only!
"""
from distutils.version import LooseVersion
# Import mantid to set MANTIDPATH for any ConfigService call that may be done
import mantid # noqa
import numpy
# Define some pure-Python functions to add to the mix
def run_algorithm(name, **kwargs):
"""Run a named algorithm and return the
algorithm handle
Parameters:
name - The name of the algorithm
kwargs - A dictionary of property name:value pairs
"""
alg = create_algorithm(name, **kwargs)
alg.execute()
return alg
def create_algorithm(name, **kwargs):
"""Create a named algorithm, set the properties given by the keywords and return the
algorithm handle WITHOUT executing the algorithm
Useful keywords:
- child: Makes algorithm a child algorithm
- rethrow: Causes exceptions to be rethrown on execution
Parameters:
name - The name of the algorithm
kwargs - A dictionary of property name:value pairs
@returns The algorithm handle
"""
# Initialize the whole framework
import mantid.simpleapi # noqa
if 'Version' in kwargs:
alg = mantid.api.AlgorithmManager.createUnmanaged(name, kwargs['Version'])
del kwargs['Version']
else:
alg = mantid.api.AlgorithmManager.createUnmanaged(name)
alg.initialize()
# Avoid problem that Load needs to set Filename first if it exists
if name == 'Load' and 'Filename' in kwargs:
alg.setPropertyValue('Filename', kwargs['Filename'])
del kwargs['Filename']
if 'child'in kwargs:
alg.setChild(True)
del kwargs['child']
if 'OutputWorkspace' in alg:
alg.setPropertyValue("OutputWorkspace","UNUSED_NAME_FOR_CHILD")
if 'rethrow' in kwargs:
alg.setRethrows(True)
del kwargs['rethrow']
alg.setProperties(kwargs)
return alg
# Case difference is to be consistent with the unittest module
def assertRaisesNothing(testobj, callable, *args, **kwargs):
"""
unittest does not have an assertRaisesNothing. This
provides that functionality
Parameters:
testobj - A unittest object
callable - A callable object
*args - Positional arguments passed to the callable as they are
**kwargs - Keyword arguments, passed on as they are
"""
try:
return callable(*args, **kwargs)
except Exception as exc:
testobj.fail("Assertion error. An exception was caught where none was expected in %s. Message: %s"
% (callable.__name__, str(exc)))
def assert_called_with_partial(_mock_self, *args, **kwargs):
"""This is similar to assert_called_with but passes if the function is called with provided arguments and keywords,
which can be a subset of the full list of arguments passed.
Credit: https://stackoverflow.com/questions/52647476/python-unit-test-assert-called-with-partial
"""
self = _mock_self
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
raise AssertionError('Expected call: %s\nNot called' % (expected,))
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher((args, kwargs))
expected_args, expected_kwargs = expected
actual_args, actual_kwargs = self._call_matcher(self.call_args)
if actual_args[:len(expected_args)] != expected_args or not (expected_kwargs.items() <= actual_kwargs.items()):
cause = expected if isinstance(expected, Exception) else None
raise AssertionError(_error_message()) from cause
def assert_any_call_partial(_mock_self, *args, **kwargs):
"""This is similar to assert_any_call but passes if the function is called with provided arguments and keywords,
which can be a subset of the full list of arguments passed.
Adapted from: https://stackoverflow.com/questions/52647476/python-unit-test-assert-called-with-partial and the
unittest assert_any_call function
"""
self = _mock_self
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
raise AssertionError('Expected call: %s\nNot called' % (expected,))
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher((args, kwargs))
actual = [self._call_matcher(c) for c in self.call_args_list]
expected_args, expected_kwargs = expected
for actual_args, actual_kwargs in actual:
if actual_args[:len(expected_args)] == expected_args and (expected_kwargs.items() <= actual_kwargs.items()):
return
cause = expected if isinstance(expected, Exception) else None
raise AssertionError(_error_message()) from cause
def can_be_instantiated(cls):
"""The Python unittest assertRaises does not
seem to catch the assertion raised by being unable
to instantiate a class (or maybe it's just the boost
python stuff).
In any case this little function tests for it and returns
a boolean
"""
try:
cls()
result = True
except RuntimeError:
result = False
return result
# Work around for slow testhelpers.assert_almost_equal that was fixed in 1.9.0:
# - https://github.com/numpy/numpy/commit/79d3a94f41b7e3c661eceed2f26ba6cce362ba4f
# Running assert_almost_equal in a tight loop with v<1.9.0 causes major slows (read minutes)
if LooseVersion(numpy.__version__) >= LooseVersion("1.9.0"):
assert_almost_equal = numpy.testing.assert_almost_equal
else:
def assert_almost_equal(actual,desired,decimal=7,err_msg='',verbose=True):
"""
Raises an AssertionError if two items are not equal up to desired
precision.
.. note:: It is recommended to use one of `assert_allclose`,
`assert_array_almost_equal_nulp` or `assert_array_max_ulp`
instead of this function for more consistent floating point
comparisons.
The test is equivalent to ``abs(desired-actual) < 0.5 * 10**(-decimal)``.
Given two objects (numbers or ndarrays), check that all elements of these
objects are almost equal. An exception is raised at conflicting values.
For ndarrays this delegates to assert_array_almost_equal
Parameters
----------
actual : array_like
The object to check.
desired : array_like
The expected object.
decimal : int, optional
Desired precision, default is 7.
err_msg : str, optional
The error message to be printed in case of failure.
verbose : bool, optional
If True, the conflicting values are appended to the error message.
Raises
------
AssertionError
If actual and desired are not equal up to specified precision.
See Also
--------
assert_allclose: Compare two array_like objects for equality with desired
relative and/or absolute precision.
assert_array_almost_equal_nulp, assert_array_max_ulp, assert_equal
Examples
--------
>>> import numpy.testing as npt
>>> npt.assert_almost_equal(2.3333333333333, 2.33333334)
>>> npt.assert_almost_equal(2.3333333333333, 2.33333334, decimal=10)
...
<type 'exceptions.AssertionError'>:
Items are not equal:
ACTUAL: 2.3333333333333002
DESIRED: 2.3333333399999998
>>> npt.assert_almost_equal(np.array([1.0,2.3333333333333]),
... np.array([1.0,2.33333334]), decimal=9)
...
<type 'exceptions.AssertionError'>:
Arrays are not almost equal
<BLANKLINE>
(mismatch 50.0%)
x: array([ 1. , 2.33333333])
y: array([ 1. , 2.33333334])
"""
__tracebackhide__ = True # Hide traceback for py.test
from numpy.core import ndarray
from numpy.lib import iscomplexobj, real, imag
from numpy.testing.utils import (assert_array_almost_equal, build_err_msg,
gisfinite, gisnan)
# Handle complex numbers: separate into real/imag to handle
# nan/inf/negative zero correctly
# XXX: catch ValueError for subclasses of ndarray where iscomplex fail
try:
usecomplex = iscomplexobj(actual) or iscomplexobj(desired)
except ValueError:
usecomplex = False
def _build_err_msg():
header = ('Arrays are not almost equal to %d decimals' % decimal)
return build_err_msg([actual, desired], err_msg, verbose=verbose,
header=header)
if usecomplex:
if iscomplexobj(actual):
actualr = real(actual)
actuali = imag(actual)
else:
actualr = actual
actuali = 0
if iscomplexobj(desired):
desiredr = real(desired)
desiredi = imag(desired)
else:
desiredr = desired
desiredi = 0
try:
assert_almost_equal(actualr, desiredr, decimal=decimal)
assert_almost_equal(actuali, desiredi, decimal=decimal)
except AssertionError:
raise AssertionError(_build_err_msg())
if isinstance(actual, (ndarray, tuple, list)) \
or isinstance(desired, (ndarray, tuple, list)):
return assert_array_almost_equal(actual, desired, decimal, err_msg)
try:
# If one of desired/actual is not finite, handle it specially here:
# check that both are nan if any is a nan, and test for equality
# otherwise
if not (gisfinite(desired) and gisfinite(actual)):
if gisnan(desired) or gisnan(actual):
if not (gisnan(desired) and gisnan(actual)):
raise AssertionError(_build_err_msg())
else:
if not desired == actual:
raise AssertionError(_build_err_msg())
return
except (NotImplementedError, TypeError):
pass
if round(abs(desired - actual), decimal) != 0:
raise AssertionError(_build_err_msg())