Skip to content

Commit 4bc2d05

Browse files
authored
Merge pull request #262 from bobleesj/pytest-warning-zero-divide
Fix all remaining divide by zero pytest warnings
2 parents 9bd388d + 3287747 commit 4bc2d05

File tree

3 files changed

+157
-140
lines changed

3 files changed

+157
-140
lines changed

news/pytest-warning-divide-zero.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
**Added:**
2+
3+
* No news added: previous news created for catching divide by zero warnings in pytest
4+
5+
**Changed:**
6+
7+
* <news item>
8+
9+
**Deprecated:**
10+
11+
* <news item>
12+
13+
**Removed:**
14+
15+
* <news item>
16+
17+
**Fixed:**
18+
19+
* <news item>
20+
21+
**Security:**
22+
23+
* <news item>

tests/test_diffraction_objects.py

Lines changed: 99 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -373,15 +373,16 @@ def test_dump(tmp_path, mocker):
373373
x, y = np.linspace(0, 5, 6), np.linspace(0, 5, 6)
374374
directory = Path(tmp_path)
375375
file = directory / "testfile"
376-
do = DiffractionObject(
377-
wavelength=1.54,
378-
name="test",
379-
scat_quantity="x-ray",
380-
xarray=np.array(x),
381-
yarray=np.array(y),
382-
xtype="q",
383-
metadata={"thing1": 1, "thing2": "thing2", "package_info": {"package2": "3.4.5"}},
384-
)
376+
with pytest.warns(RuntimeWarning, match="divide by zero encountered in divide"):
377+
do = DiffractionObject(
378+
wavelength=1.54,
379+
name="test",
380+
scat_quantity="x-ray",
381+
xarray=np.array(x),
382+
yarray=np.array(y),
383+
xtype="q",
384+
metadata={"thing1": 1, "thing2": "thing2", "package_info": {"package2": "3.4.5"}},
385+
)
385386
mocker.patch("importlib.metadata.version", return_value="3.3.0")
386387
with freeze_time("2012-01-14"):
387388
do.dump(file, "q")
@@ -402,114 +403,107 @@ def test_dump(tmp_path, mocker):
402403
assert actual == expected
403404

404405

405-
test_init_valid_params = [
406-
( # instantiate just array attributes
407-
{
408-
"xarray": np.array([0.0, 90.0, 180.0]),
409-
"yarray": np.array([1.0, 2.0, 3.0]),
410-
"xtype": "tth",
411-
"wavelength": 4.0 * np.pi,
412-
},
413-
{
414-
"_all_arrays": np.array(
415-
[
416-
[1.0, 0.0, 0.0, np.float64(np.inf)],
417-
[2.0, 1.0 / np.sqrt(2), 90.0, np.sqrt(2) * 2 * np.pi],
418-
[3.0, 1.0, 180.0, 1.0 * 2 * np.pi],
419-
]
420-
),
421-
"metadata": {},
422-
"_input_xtype": "tth",
423-
"name": "",
424-
"scat_quantity": "",
425-
"qmin": np.float64(0.0),
426-
"qmax": np.float64(1.0),
427-
"tthmin": np.float64(0.0),
428-
"tthmax": np.float64(180.0),
429-
"dmin": np.float64(2 * np.pi),
430-
"dmax": np.float64(np.inf),
431-
"wavelength": 4.0 * np.pi,
432-
},
433-
),
434-
( # instantiate just array attributes
435-
{
436-
"xarray": np.array([np.inf, 2 * np.sqrt(2) * np.pi, 2 * np.pi]),
437-
"yarray": np.array([1.0, 2.0, 3.0]),
438-
"xtype": "d",
439-
"wavelength": 4.0 * np.pi,
440-
"scat_quantity": "x-ray",
441-
},
442-
{
443-
"_all_arrays": np.array(
444-
[
445-
[1.0, 0.0, 0.0, np.float64(np.inf)],
446-
[2.0, 1.0 / np.sqrt(2), 90.0, np.sqrt(2) * 2 * np.pi],
447-
[3.0, 1.0, 180.0, 1.0 * 2 * np.pi],
448-
]
449-
),
450-
"metadata": {},
451-
"_input_xtype": "d",
452-
"name": "",
453-
"scat_quantity": "x-ray",
454-
"qmin": np.float64(0.0),
455-
"qmax": np.float64(1.0),
456-
"tthmin": np.float64(0.0),
457-
"tthmax": np.float64(180.0),
458-
"dmin": np.float64(2 * np.pi),
459-
"dmax": np.float64(np.inf),
460-
"wavelength": 4.0 * np.pi,
461-
},
462-
),
463-
]
464-
465-
466406
@pytest.mark.parametrize(
467-
"init_args, expected_do_dict",
468-
test_init_valid_params,
407+
"do_init_args, expected_do_dict, divide_by_zero_warning_expected",
408+
[
409+
( # instantiate just array attributes
410+
{
411+
"xarray": np.array([0.0, 90.0, 180.0]),
412+
"yarray": np.array([1.0, 2.0, 3.0]),
413+
"xtype": "tth",
414+
"wavelength": 4.0 * np.pi,
415+
},
416+
{
417+
"_all_arrays": np.array(
418+
[
419+
[1.0, 0.0, 0.0, np.float64(np.inf)],
420+
[2.0, 1.0 / np.sqrt(2), 90.0, np.sqrt(2) * 2 * np.pi],
421+
[3.0, 1.0, 180.0, 1.0 * 2 * np.pi],
422+
]
423+
),
424+
"metadata": {},
425+
"_input_xtype": "tth",
426+
"name": "",
427+
"scat_quantity": "",
428+
"qmin": np.float64(0.0),
429+
"qmax": np.float64(1.0),
430+
"tthmin": np.float64(0.0),
431+
"tthmax": np.float64(180.0),
432+
"dmin": np.float64(2 * np.pi),
433+
"dmax": np.float64(np.inf),
434+
"wavelength": 4.0 * np.pi,
435+
},
436+
True,
437+
),
438+
( # instantiate just array attributes
439+
{
440+
"xarray": np.array([np.inf, 2 * np.sqrt(2) * np.pi, 2 * np.pi]),
441+
"yarray": np.array([1.0, 2.0, 3.0]),
442+
"xtype": "d",
443+
"wavelength": 4.0 * np.pi,
444+
"scat_quantity": "x-ray",
445+
},
446+
{
447+
"_all_arrays": np.array(
448+
[
449+
[1.0, 0.0, 0.0, np.float64(np.inf)],
450+
[2.0, 1.0 / np.sqrt(2), 90.0, np.sqrt(2) * 2 * np.pi],
451+
[3.0, 1.0, 180.0, 1.0 * 2 * np.pi],
452+
]
453+
),
454+
"metadata": {},
455+
"_input_xtype": "d",
456+
"name": "",
457+
"scat_quantity": "x-ray",
458+
"qmin": np.float64(0.0),
459+
"qmax": np.float64(1.0),
460+
"tthmin": np.float64(0.0),
461+
"tthmax": np.float64(180.0),
462+
"dmin": np.float64(2 * np.pi),
463+
"dmax": np.float64(np.inf),
464+
"wavelength": 4.0 * np.pi,
465+
},
466+
False,
467+
),
468+
],
469469
)
470-
def test_init_valid(init_args, expected_do_dict):
471-
actual_do_dict = DiffractionObject(**init_args).__dict__
470+
def test_init_valid(do_init_args, expected_do_dict, divide_by_zero_warning_expected):
471+
if divide_by_zero_warning_expected:
472+
with pytest.warns(RuntimeWarning, match="divide by zero encountered in divide"):
473+
actual_do_dict = DiffractionObject(**do_init_args).__dict__
474+
else:
475+
actual_do_dict = DiffractionObject(**do_init_args).__dict__
472476
diff = DeepDiff(
473477
actual_do_dict, expected_do_dict, ignore_order=True, significant_digits=13, exclude_paths="root['_id']"
474478
)
475479
assert diff == {}
476480

477481

478-
test_init_invalid_params = [
479-
( # UC1: no arguments provided
480-
{},
481-
"missing 3 required positional arguments: 'xarray', 'yarray', and 'xtype'",
482-
),
483-
( # UC2: only xarray and yarray provided
484-
{"xarray": np.array([0.0, 90.0]), "yarray": np.array([0.0, 90.0])},
485-
"missing 1 required positional argument: 'xtype'",
486-
),
487-
]
488-
489-
490-
@pytest.mark.parametrize("init_args, expected_error_msg", test_init_invalid_params)
482+
@pytest.mark.parametrize(
483+
"do_init_args, expected_error_msg",
484+
[
485+
( # Case 1: no arguments provided
486+
{},
487+
"missing 3 required positional arguments: 'xarray', 'yarray', and 'xtype'",
488+
),
489+
( # Case 2: only xarray and yarray provided
490+
{"xarray": np.array([0.0, 90.0]), "yarray": np.array([0.0, 90.0])},
491+
"missing 1 required positional argument: 'xtype'",
492+
),
493+
],
494+
)
491495
def test_init_invalid_args(
492-
init_args,
496+
do_init_args,
493497
expected_error_msg,
494498
):
495499
with pytest.raises(TypeError, match=expected_error_msg):
496-
DiffractionObject(**init_args)
500+
DiffractionObject(**do_init_args)
497501

498502

499-
def test_all_array_getter():
500-
actual_do = DiffractionObject(
501-
xarray=np.array([0.0, 90.0, 180.0]),
502-
yarray=np.array([1.0, 2.0, 3.0]),
503-
xtype="tth",
504-
wavelength=4.0 * np.pi,
505-
)
506-
expected_all_arrays = np.array(
507-
[
508-
[1.0, 0.0, 0.0, np.float64(np.inf)],
509-
[2.0, 1.0 / np.sqrt(2), 90.0, np.sqrt(2) * 2 * np.pi],
510-
[3.0, 1.0, 180.0, 1.0 * 2 * np.pi],
511-
]
512-
)
503+
def test_all_array_getter(do_minimal_tth):
504+
actual_do = do_minimal_tth
505+
print(actual_do.all_arrays)
506+
expected_all_arrays = [[1, 0.51763809, 30, 12.13818192], [2, 1, 60, 6.28318531]]
513507
assert np.allclose(actual_do.all_arrays, expected_all_arrays)
514508

515509

@@ -574,14 +568,8 @@ def test_input_xtype_setter_error(do_minimal):
574568
do.input_xtype = "q"
575569

576570

577-
def test_copy_object():
578-
do = DiffractionObject(
579-
name="test",
580-
wavelength=4.0 * np.pi,
581-
xarray=np.array([0.0, 90.0, 180.0]),
582-
yarray=np.array([1.0, 2.0, 3.0]),
583-
xtype="tth",
584-
)
571+
def test_copy_object(do_minimal):
572+
do = do_minimal
585573
do_copy = do.copy()
586574
assert do == do_copy
587575
assert id(do) != id(do_copy)

tests/test_transforms.py

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -146,50 +146,55 @@ def test_q_to_d(q, expected_d, warning_expected):
146146

147147

148148
@pytest.mark.parametrize(
149-
"d, expected_q",
149+
"d, expected_q, zero_divide_error_expected",
150150
[
151151
# UC1: User specified empty d values
152-
(np.array([]), np.array([])),
152+
(np.array([]), np.array([]), False),
153153
# UC2: User specified valid d values
154154
(
155155
np.array([5 * np.pi, 4 * np.pi, 3 * np.pi, 2 * np.pi, np.pi, 0]),
156156
np.array([0.4, 0.5, 0.66667, 1, 2, np.inf]),
157+
True,
157158
),
158159
],
159160
)
160-
def test_d_to_q(d, expected_q):
161-
actual_q = d_to_q(d)
161+
def test_d_to_q(d, expected_q, zero_divide_error_expected):
162+
if zero_divide_error_expected:
163+
with pytest.warns(RuntimeWarning, match="divide by zero encountered in divide"):
164+
actual_q = d_to_q(d)
165+
else:
166+
actual_q = d_to_q(d)
162167
assert np.allclose(actual_q, expected_q)
163168

164169

165170
@pytest.mark.parametrize(
166-
"wavelength, tth, expected_d",
171+
"wavelength, tth, expected_d, divide_by_zero_warning_expected",
167172
[
168-
# UC0: User specified empty tth values (without wavelength)
169-
(None, np.array([]), np.array([])),
170-
# UC1: User specified empty tth values (with wavelength)
171-
(4 * np.pi, np.array([]), np.array([])),
172-
# UC2: User specified valid tth values between 0-180 degrees (without wavelength)
173-
(
174-
None,
175-
np.array([0, 30, 60, 90, 120, 180]),
176-
np.array([0, 1, 2, 3, 4, 5]),
177-
),
178-
# UC3: User specified valid tth values between 0-180 degrees (with wavelength)
173+
# Test conversion of q to d with valid values
174+
# Case 1: empty tth values, no, expect empty d values
175+
(None, np.array([]), np.array([]), False),
176+
# Case 2: empty tth values, wavelength provided, expect empty d values
177+
(4 * np.pi, np.array([]), np.array([]), False),
178+
# Case 3: User specified valid tth values between 0-180 degrees (without wavelength)
179+
(None, np.array([0, 30, 60, 90, 120, 180]), np.array([0, 1, 2, 3, 4, 5]), False),
180+
# Case 4: User specified valid tth values between 0-180 degrees (with wavelength)
179181
(
180182
4 * np.pi,
181183
np.array([0, 30.0, 60.0, 90.0, 120.0, 180.0]),
182184
np.array([np.inf, 24.27636, 12.56637, 8.88577, 7.25520, 6.28319]),
185+
True,
183186
),
184187
],
185188
)
186-
def test_tth_to_d(wavelength, tth, expected_d, wavelength_warning_msg):
189+
def test_tth_to_d(wavelength, tth, expected_d, divide_by_zero_warning_expected, wavelength_warning_msg):
187190
if wavelength is None:
188191
with pytest.warns(UserWarning, match=re.escape(wavelength_warning_msg)):
189192
actual_d = tth_to_d(tth, wavelength)
193+
elif divide_by_zero_warning_expected:
194+
with pytest.warns(RuntimeWarning, match="divide by zero encountered in divide"):
195+
actual_d = tth_to_d(tth, wavelength)
190196
else:
191197
actual_d = tth_to_d(tth, wavelength)
192-
193198
assert np.allclose(actual_d, expected_d)
194199

195200

@@ -218,30 +223,31 @@ def test_tth_to_d_invalid(wavelength, tth, expected_error_type, expected_error_m
218223

219224

220225
@pytest.mark.parametrize(
221-
"wavelength, d, expected_tth",
226+
"wavelength, d, expected_tth, divide_by_zero_warning_expected",
222227
[
223228
# UC1: Empty d values, no wavelength, return empty arrays
224-
(None, np.empty((0)), np.empty((0))),
229+
(None, np.empty((0)), np.empty((0)), False),
225230
# UC2: Empty d values, wavelength specified, return empty arrays
226-
(4 * np.pi, np.empty((0)), np.empty(0)),
231+
(4 * np.pi, np.empty((0)), np.empty(0), False),
227232
# UC3: User specified valid d values, no wavelength, return empty arrays
228-
(
229-
None,
230-
np.array([1, 0.8, 0.6, 0.4, 0.2, 0]),
231-
np.array([0, 1, 2, 3, 4, 5]),
232-
),
233+
(None, np.array([1, 0.8, 0.6, 0.4, 0.2, 0]), np.array([0, 1, 2, 3, 4, 5]), True),
233234
# UC4: User specified valid d values (with wavelength)
234235
(
235236
4 * np.pi,
236237
np.array([4 * np.pi, 4 / np.sqrt(2) * np.pi, 4 / np.sqrt(3) * np.pi]),
237238
np.array([60.0, 90.0, 120.0]),
239+
False,
238240
),
239241
],
240242
)
241-
def test_d_to_tth(wavelength, d, expected_tth, wavelength_warning_msg):
242-
if wavelength is None:
243+
def test_d_to_tth(wavelength, d, expected_tth, divide_by_zero_warning_expected, wavelength_warning_msg):
244+
if wavelength is None and not divide_by_zero_warning_expected:
243245
with pytest.warns(UserWarning, match=re.escape(wavelength_warning_msg)):
244246
actual_tth = d_to_tth(d, wavelength)
247+
elif wavelength is None and divide_by_zero_warning_expected:
248+
with pytest.warns(UserWarning, match=re.escape(wavelength_warning_msg)):
249+
with pytest.warns(RuntimeWarning, match="divide by zero encountered in divide"):
250+
actual_tth = d_to_tth(d, wavelength)
245251
else:
246252
actual_tth = d_to_tth(d, wavelength)
247253

@@ -254,7 +260,7 @@ def test_d_to_tth(wavelength, d, expected_tth, wavelength_warning_msg):
254260
# UC1: user specified invalid d values that result in tth > 180 degrees
255261
(4 * np.pi, np.array([1.2, 1, 0.8, 0.6, 0.4, 0.2]), ValueError),
256262
# UC2: user specified a wrong wavelength that result in tth > 180 degrees
257-
(100, np.array([1, 0.8, 0.6, 0.4, 0.2, 0]), ValueError),
263+
(100, np.array([1.2, 1, 0.8, 0.6, 0.4, 0.2]), ValueError),
258264
],
259265
)
260266
def test_d_to_tth_bad(wavelength, d, expected_error_type, invalid_q_or_d_or_wavelength_error_msg):

0 commit comments

Comments
 (0)