-
Notifications
You must be signed in to change notification settings - Fork 21
Fix all remaining divide by zero pytest warnings #262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b7ad810
25cb875
9c8fd95
102310b
efb0585
3287747
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
**Added:** | ||
|
||
* No news added: previous news created for catching divide by zero warnings in pytest | ||
|
||
**Changed:** | ||
|
||
* <news item> | ||
|
||
**Deprecated:** | ||
|
||
* <news item> | ||
|
||
**Removed:** | ||
|
||
* <news item> | ||
|
||
**Fixed:** | ||
|
||
* <news item> | ||
|
||
**Security:** | ||
|
||
* <news item> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -373,15 +373,16 @@ def test_dump(tmp_path, mocker): | |
x, y = np.linspace(0, 5, 6), np.linspace(0, 5, 6) | ||
directory = Path(tmp_path) | ||
file = directory / "testfile" | ||
do = DiffractionObject( | ||
wavelength=1.54, | ||
name="test", | ||
scat_quantity="x-ray", | ||
xarray=np.array(x), | ||
yarray=np.array(y), | ||
xtype="q", | ||
metadata={"thing1": 1, "thing2": "thing2", "package_info": {"package2": "3.4.5"}}, | ||
) | ||
with pytest.warns(RuntimeWarning, match="divide by zero encountered in divide"): | ||
do = DiffractionObject( | ||
wavelength=1.54, | ||
name="test", | ||
scat_quantity="x-ray", | ||
xarray=np.array(x), | ||
yarray=np.array(y), | ||
xtype="q", | ||
metadata={"thing1": 1, "thing2": "thing2", "package_info": {"package2": "3.4.5"}}, | ||
) | ||
mocker.patch("importlib.metadata.version", return_value="3.3.0") | ||
with freeze_time("2012-01-14"): | ||
do.dump(file, "q") | ||
|
@@ -402,114 +403,107 @@ def test_dump(tmp_path, mocker): | |
assert actual == expected | ||
|
||
|
||
test_init_valid_params = [ | ||
( # instantiate just array attributes | ||
{ | ||
"xarray": np.array([0.0, 90.0, 180.0]), | ||
"yarray": np.array([1.0, 2.0, 3.0]), | ||
"xtype": "tth", | ||
"wavelength": 4.0 * np.pi, | ||
}, | ||
{ | ||
"_all_arrays": np.array( | ||
[ | ||
[1.0, 0.0, 0.0, np.float64(np.inf)], | ||
[2.0, 1.0 / np.sqrt(2), 90.0, np.sqrt(2) * 2 * np.pi], | ||
[3.0, 1.0, 180.0, 1.0 * 2 * np.pi], | ||
] | ||
), | ||
"metadata": {}, | ||
"_input_xtype": "tth", | ||
"name": "", | ||
"scat_quantity": "", | ||
"qmin": np.float64(0.0), | ||
"qmax": np.float64(1.0), | ||
"tthmin": np.float64(0.0), | ||
"tthmax": np.float64(180.0), | ||
"dmin": np.float64(2 * np.pi), | ||
"dmax": np.float64(np.inf), | ||
"wavelength": 4.0 * np.pi, | ||
}, | ||
), | ||
( # instantiate just array attributes | ||
{ | ||
"xarray": np.array([np.inf, 2 * np.sqrt(2) * np.pi, 2 * np.pi]), | ||
"yarray": np.array([1.0, 2.0, 3.0]), | ||
"xtype": "d", | ||
"wavelength": 4.0 * np.pi, | ||
"scat_quantity": "x-ray", | ||
}, | ||
{ | ||
"_all_arrays": np.array( | ||
[ | ||
[1.0, 0.0, 0.0, np.float64(np.inf)], | ||
[2.0, 1.0 / np.sqrt(2), 90.0, np.sqrt(2) * 2 * np.pi], | ||
[3.0, 1.0, 180.0, 1.0 * 2 * np.pi], | ||
] | ||
), | ||
"metadata": {}, | ||
"_input_xtype": "d", | ||
"name": "", | ||
"scat_quantity": "x-ray", | ||
"qmin": np.float64(0.0), | ||
"qmax": np.float64(1.0), | ||
"tthmin": np.float64(0.0), | ||
"tthmax": np.float64(180.0), | ||
"dmin": np.float64(2 * np.pi), | ||
"dmax": np.float64(np.inf), | ||
"wavelength": 4.0 * np.pi, | ||
}, | ||
), | ||
] | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"init_args, expected_do_dict", | ||
test_init_valid_params, | ||
"do_init_args, expected_do_dict, divide_by_zero_warning_expected", | ||
[ | ||
( # instantiate just array attributes | ||
{ | ||
"xarray": np.array([0.0, 90.0, 180.0]), | ||
"yarray": np.array([1.0, 2.0, 3.0]), | ||
"xtype": "tth", | ||
"wavelength": 4.0 * np.pi, | ||
}, | ||
{ | ||
"_all_arrays": np.array( | ||
[ | ||
[1.0, 0.0, 0.0, np.float64(np.inf)], | ||
[2.0, 1.0 / np.sqrt(2), 90.0, np.sqrt(2) * 2 * np.pi], | ||
[3.0, 1.0, 180.0, 1.0 * 2 * np.pi], | ||
] | ||
), | ||
"metadata": {}, | ||
"_input_xtype": "tth", | ||
"name": "", | ||
"scat_quantity": "", | ||
"qmin": np.float64(0.0), | ||
"qmax": np.float64(1.0), | ||
"tthmin": np.float64(0.0), | ||
"tthmax": np.float64(180.0), | ||
"dmin": np.float64(2 * np.pi), | ||
"dmax": np.float64(np.inf), | ||
"wavelength": 4.0 * np.pi, | ||
}, | ||
True, | ||
), | ||
( # instantiate just array attributes | ||
{ | ||
"xarray": np.array([np.inf, 2 * np.sqrt(2) * np.pi, 2 * np.pi]), | ||
"yarray": np.array([1.0, 2.0, 3.0]), | ||
"xtype": "d", | ||
"wavelength": 4.0 * np.pi, | ||
"scat_quantity": "x-ray", | ||
}, | ||
{ | ||
"_all_arrays": np.array( | ||
[ | ||
[1.0, 0.0, 0.0, np.float64(np.inf)], | ||
[2.0, 1.0 / np.sqrt(2), 90.0, np.sqrt(2) * 2 * np.pi], | ||
[3.0, 1.0, 180.0, 1.0 * 2 * np.pi], | ||
] | ||
), | ||
"metadata": {}, | ||
"_input_xtype": "d", | ||
"name": "", | ||
"scat_quantity": "x-ray", | ||
"qmin": np.float64(0.0), | ||
"qmax": np.float64(1.0), | ||
"tthmin": np.float64(0.0), | ||
"tthmax": np.float64(180.0), | ||
"dmin": np.float64(2 * np.pi), | ||
"dmax": np.float64(np.inf), | ||
"wavelength": 4.0 * np.pi, | ||
}, | ||
False, | ||
), | ||
], | ||
) | ||
def test_init_valid(init_args, expected_do_dict): | ||
actual_do_dict = DiffractionObject(**init_args).__dict__ | ||
def test_init_valid(do_init_args, expected_do_dict, divide_by_zero_warning_expected): | ||
if divide_by_zero_warning_expected: | ||
with pytest.warns(RuntimeWarning, match="divide by zero encountered in divide"): | ||
actual_do_dict = DiffractionObject(**do_init_args).__dict__ | ||
else: | ||
actual_do_dict = DiffractionObject(**do_init_args).__dict__ | ||
diff = DeepDiff( | ||
actual_do_dict, expected_do_dict, ignore_order=True, significant_digits=13, exclude_paths="root['_id']" | ||
) | ||
assert diff == {} | ||
|
||
|
||
test_init_invalid_params = [ | ||
( # UC1: no arguments provided | ||
{}, | ||
"missing 3 required positional arguments: 'xarray', 'yarray', and 'xtype'", | ||
), | ||
( # UC2: only xarray and yarray provided | ||
{"xarray": np.array([0.0, 90.0]), "yarray": np.array([0.0, 90.0])}, | ||
"missing 1 required positional argument: 'xtype'", | ||
), | ||
] | ||
|
||
|
||
@pytest.mark.parametrize("init_args, expected_error_msg", test_init_invalid_params) | ||
@pytest.mark.parametrize( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will further refine these comments with higher level commets, etc. in the following PRs (issues have been created for these) |
||
"do_init_args, expected_error_msg", | ||
[ | ||
( # Case 1: no arguments provided | ||
{}, | ||
"missing 3 required positional arguments: 'xarray', 'yarray', and 'xtype'", | ||
), | ||
( # Case 2: only xarray and yarray provided | ||
{"xarray": np.array([0.0, 90.0]), "yarray": np.array([0.0, 90.0])}, | ||
"missing 1 required positional argument: 'xtype'", | ||
), | ||
], | ||
) | ||
def test_init_invalid_args( | ||
init_args, | ||
do_init_args, | ||
expected_error_msg, | ||
): | ||
with pytest.raises(TypeError, match=expected_error_msg): | ||
DiffractionObject(**init_args) | ||
DiffractionObject(**do_init_args) | ||
|
||
|
||
def test_all_array_getter(): | ||
actual_do = DiffractionObject( | ||
xarray=np.array([0.0, 90.0, 180.0]), | ||
yarray=np.array([1.0, 2.0, 3.0]), | ||
xtype="tth", | ||
wavelength=4.0 * np.pi, | ||
) | ||
expected_all_arrays = np.array( | ||
[ | ||
[1.0, 0.0, 0.0, np.float64(np.inf)], | ||
[2.0, 1.0 / np.sqrt(2), 90.0, np.sqrt(2) * 2 * np.pi], | ||
[3.0, 1.0, 180.0, 1.0 * 2 * np.pi], | ||
] | ||
) | ||
def test_all_array_getter(do_minimal_tth): | ||
actual_do = do_minimal_tth | ||
print(actual_do.all_arrays) | ||
expected_all_arrays = [[1, 0.51763809, 30, 12.13818192], [2, 1, 60, 6.28318531]] | ||
assert np.allclose(actual_do.all_arrays, expected_all_arrays) | ||
|
||
|
||
|
@@ -574,14 +568,8 @@ def test_input_xtype_setter_error(do_minimal): | |
do.input_xtype = "q" | ||
|
||
|
||
def test_copy_object(): | ||
do = DiffractionObject( | ||
name="test", | ||
wavelength=4.0 * np.pi, | ||
xarray=np.array([0.0, 90.0, 180.0]), | ||
yarray=np.array([1.0, 2.0, 3.0]), | ||
xtype="tth", | ||
) | ||
def test_copy_object(do_minimal): | ||
do = do_minimal | ||
do_copy = do.copy() | ||
assert do == do_copy | ||
assert id(do) != id(do_copy) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -146,50 +146,55 @@ def test_q_to_d(q, expected_d, warning_expected): | |
|
||
|
||
@pytest.mark.parametrize( | ||
"d, expected_q", | ||
"d, expected_q, zero_divide_error_expected", | ||
[ | ||
# UC1: User specified empty d values | ||
(np.array([]), np.array([])), | ||
(np.array([]), np.array([]), False), | ||
# UC2: User specified valid d values | ||
( | ||
np.array([5 * np.pi, 4 * np.pi, 3 * np.pi, 2 * np.pi, np.pi, 0]), | ||
np.array([0.4, 0.5, 0.66667, 1, 2, np.inf]), | ||
True, | ||
), | ||
], | ||
) | ||
def test_d_to_q(d, expected_q): | ||
actual_q = d_to_q(d) | ||
def test_d_to_q(d, expected_q, zero_divide_error_expected): | ||
if zero_divide_error_expected: | ||
with pytest.warns(RuntimeWarning, match="divide by zero encountered in divide"): | ||
actual_q = d_to_q(d) | ||
else: | ||
actual_q = d_to_q(d) | ||
assert np.allclose(actual_q, expected_q) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"wavelength, tth, expected_d", | ||
"wavelength, tth, expected_d, divide_by_zero_warning_expected", | ||
[ | ||
# UC0: User specified empty tth values (without wavelength) | ||
(None, np.array([]), np.array([])), | ||
# UC1: User specified empty tth values (with wavelength) | ||
(4 * np.pi, np.array([]), np.array([])), | ||
# UC2: User specified valid tth values between 0-180 degrees (without wavelength) | ||
( | ||
None, | ||
np.array([0, 30, 60, 90, 120, 180]), | ||
np.array([0, 1, 2, 3, 4, 5]), | ||
), | ||
# UC3: User specified valid tth values between 0-180 degrees (with wavelength) | ||
# Test conversion of q to d with valid values | ||
# Case 1: empty tth values, no, expect empty d values | ||
(None, np.array([]), np.array([]), False), | ||
# Case 2: empty tth values, wavelength provided, expect empty d values | ||
(4 * np.pi, np.array([]), np.array([]), False), | ||
# Case 3: User specified valid tth values between 0-180 degrees (without wavelength) | ||
(None, np.array([0, 30, 60, 90, 120, 180]), np.array([0, 1, 2, 3, 4, 5]), False), | ||
# Case 4: User specified valid tth values between 0-180 degrees (with wavelength) | ||
( | ||
4 * np.pi, | ||
np.array([0, 30.0, 60.0, 90.0, 120.0, 180.0]), | ||
np.array([np.inf, 24.27636, 12.56637, 8.88577, 7.25520, 6.28319]), | ||
True, | ||
), | ||
], | ||
) | ||
def test_tth_to_d(wavelength, tth, expected_d, wavelength_warning_msg): | ||
def test_tth_to_d(wavelength, tth, expected_d, divide_by_zero_warning_expected, wavelength_warning_msg): | ||
if wavelength is None: | ||
with pytest.warns(UserWarning, match=re.escape(wavelength_warning_msg)): | ||
actual_d = tth_to_d(tth, wavelength) | ||
elif divide_by_zero_warning_expected: | ||
with pytest.warns(RuntimeWarning, match="divide by zero encountered in divide"): | ||
actual_d = tth_to_d(tth, wavelength) | ||
else: | ||
actual_d = tth_to_d(tth, wavelength) | ||
|
||
assert np.allclose(actual_d, expected_d) | ||
|
||
|
||
|
@@ -218,30 +223,31 @@ def test_tth_to_d_invalid(wavelength, tth, expected_error_type, expected_error_m | |
|
||
|
||
@pytest.mark.parametrize( | ||
"wavelength, d, expected_tth", | ||
"wavelength, d, expected_tth, divide_by_zero_warning_expected", | ||
[ | ||
# UC1: Empty d values, no wavelength, return empty arrays | ||
(None, np.empty((0)), np.empty((0))), | ||
(None, np.empty((0)), np.empty((0)), False), | ||
# UC2: Empty d values, wavelength specified, return empty arrays | ||
(4 * np.pi, np.empty((0)), np.empty(0)), | ||
(4 * np.pi, np.empty((0)), np.empty(0), False), | ||
# UC3: User specified valid d values, no wavelength, return empty arrays | ||
( | ||
None, | ||
np.array([1, 0.8, 0.6, 0.4, 0.2, 0]), | ||
np.array([0, 1, 2, 3, 4, 5]), | ||
), | ||
(None, np.array([1, 0.8, 0.6, 0.4, 0.2, 0]), np.array([0, 1, 2, 3, 4, 5]), True), | ||
# UC4: User specified valid d values (with wavelength) | ||
( | ||
4 * np.pi, | ||
np.array([4 * np.pi, 4 / np.sqrt(2) * np.pi, 4 / np.sqrt(3) * np.pi]), | ||
np.array([60.0, 90.0, 120.0]), | ||
False, | ||
), | ||
], | ||
) | ||
def test_d_to_tth(wavelength, d, expected_tth, wavelength_warning_msg): | ||
if wavelength is None: | ||
def test_d_to_tth(wavelength, d, expected_tth, divide_by_zero_warning_expected, wavelength_warning_msg): | ||
if wavelength is None and not divide_by_zero_warning_expected: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am thinking we could make a reusable test util function under |
||
with pytest.warns(UserWarning, match=re.escape(wavelength_warning_msg)): | ||
actual_tth = d_to_tth(d, wavelength) | ||
elif wavelength is None and divide_by_zero_warning_expected: | ||
with pytest.warns(UserWarning, match=re.escape(wavelength_warning_msg)): | ||
with pytest.warns(RuntimeWarning, match="divide by zero encountered in divide"): | ||
actual_tth = d_to_tth(d, wavelength) | ||
else: | ||
actual_tth = d_to_tth(d, wavelength) | ||
|
||
|
@@ -254,7 +260,7 @@ def test_d_to_tth(wavelength, d, expected_tth, wavelength_warning_msg): | |
# UC1: user specified invalid d values that result in tth > 180 degrees | ||
(4 * np.pi, np.array([1.2, 1, 0.8, 0.6, 0.4, 0.2]), ValueError), | ||
# UC2: user specified a wrong wavelength that result in tth > 180 degrees | ||
(100, np.array([1, 0.8, 0.6, 0.4, 0.2, 0]), ValueError), | ||
(100, np.array([1.2, 1, 0.8, 0.6, 0.4, 0.2]), ValueError), | ||
], | ||
) | ||
def test_d_to_tth_bad(wavelength, d, expected_error_type, invalid_q_or_d_or_wavelength_error_msg): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just moving them under
@pytest.mark.parametrize
- no numbers have been modified.