Skip to content

Commit ec78bf2

Browse files
authored
Edge cases and error handling for the squeeze morph (#227)
* Edge cases and error handling * News * Tests now check message details
1 parent 3cb2c7c commit ec78bf2

File tree

4 files changed

+91
-10
lines changed

4 files changed

+91
-10
lines changed

news/squeeze_lims.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
**Added:**
2+
3+
* Error thrown when squeeze morph given improper inputs.
4+
5+
**Changed:**
6+
7+
* Squeeze morph now removes duplicate/repeated and trailing commas before parsing.
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>

src/diffpy/morph/morphapp.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ def custom_error(self, msg):
188188
"a0+a1*x+a2*x^2+...a_n*x^n."
189189
"n is dependent on the number of values in the "
190190
"user-inputted comma-separated list. "
191+
"Repeated and trailing commas are removed before parsing."
191192
"When this option is enabled, --hshift is disabled. "
192193
"When n>1, --stretch is disabled. "
193194
"See online documentation for more information."
@@ -522,6 +523,7 @@ def single_morph(
522523

523524
# Squeeze
524525
squeeze_poly_deg = -1
526+
squeeze_dict_in = {}
525527
if opts.squeeze is not None:
526528
# Handles both list and csv input
527529
if (
@@ -537,12 +539,19 @@ def single_morph(
537539
):
538540
opts.squeeze = opts.squeeze[1:-1]
539541
squeeze_coeffs = opts.squeeze.strip().split(",")
540-
squeeze_dict_in = {}
541-
for idx, coeff in enumerate(squeeze_coeffs):
542-
squeeze_dict_in.update({f"a{idx}": float(coeff)})
543-
squeeze_poly_deg = len(squeeze_coeffs) - 1
542+
idx = 0
543+
for _, coeff in enumerate(squeeze_coeffs):
544+
if coeff.strip() != "":
545+
try:
546+
squeeze_dict_in.update({f"a{idx}": float(coeff)})
547+
idx += 1
548+
except ValueError:
549+
parser.error(f"{coeff} could not be converted to float.")
550+
squeeze_poly_deg = len(squeeze_dict_in.keys())
544551
chain.append(morphs.MorphSqueeze())
545552
config["squeeze"] = squeeze_dict_in
553+
# config["extrap_index_low"] = None
554+
# config["extrap_index_high"] = None
546555
refpars.append("squeeze")
547556
# Scale
548557
if opts.scale is not None:
@@ -679,10 +688,7 @@ def single_morph(
679688
morph_inputs.update({"hshift": hshift_in, "vshift": vshift_in})
680689
# More complex input morph parameters are only displayed conditionally
681690
if opts.squeeze is not None:
682-
squeeze_coeffs = opts.squeeze.strip().split(",")
683-
squeeze_dict = {}
684-
for idx, coeff in enumerate(squeeze_coeffs):
685-
squeeze_dict.update({f"a{idx}": float(coeff)})
691+
squeeze_dict = squeeze_dict_in.copy()
686692
for idx, _ in enumerate(squeeze_dict):
687693
morph_inputs.update({f"squeeze a{idx}": squeeze_dict[f"a{idx}"]})
688694
if pymorphs is not None:

tests/test_morphapp.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,27 +105,43 @@ def test_parser_numerical(self, setup_parser):
105105
) # Check correct value parsed
106106
assert len(n_args) == 1 # Check one leftover
107107

108-
def test_parser_systemexits(self, setup_parser):
108+
def test_parser_systemexits(self, capsys, setup_parser):
109109
# ###Basic tests for any variety of morphing###
110110

111111
# Ensure only two pargs given for morphing
112112
(opts, pargs) = self.parser.parse_args(["toofewfiles"])
113113
with pytest.raises(SystemExit):
114114
single_morph(self.parser, opts, pargs, stdout_flag=False)
115+
_, err = capsys.readouterr()
116+
assert "You must supply FILE1 and FILE2." in err
115117
with pytest.raises(SystemExit):
116118
multiple_targets(self.parser, opts, pargs, stdout_flag=False)
119+
_, err = capsys.readouterr()
120+
assert "You must supply FILE and DIRECTORY." in err
117121
(opts, pargs) = self.parser.parse_args(["too", "many", "files"])
118122
with pytest.raises(SystemExit):
119123
single_morph(self.parser, opts, pargs, stdout_flag=False)
124+
_, err = capsys.readouterr()
125+
assert (
126+
"Too many arguments. Make sure you only supply FILE1 and FILE2."
127+
in err
128+
)
120129
with pytest.raises(SystemExit):
121130
multiple_targets(self.parser, opts, pargs, stdout_flag=False)
131+
_, err = capsys.readouterr()
132+
assert (
133+
"Too many arguments. You must only supply a FILE and a DIRECTORY."
134+
in err
135+
)
122136

123137
# Make sure rmax greater than rmin
124138
(opts, pargs) = self.parser.parse_args(
125139
[f"{nickel_PDF}", f"{nickel_PDF}", "--rmin", "10", "--rmax", "1"]
126140
)
127141
with pytest.raises(SystemExit):
128142
single_morph(self.parser, opts, pargs, stdout_flag=False)
143+
_, err = capsys.readouterr()
144+
assert "rmin must be less than rmax" in err
129145

130146
# ###Tests exclusive to multiple morphs###
131147
# Make sure we save to a directory that exists
@@ -140,8 +156,12 @@ def test_parser_systemexits(self, setup_parser):
140156
)
141157
with pytest.raises(SystemExit):
142158
single_morph(self.parser, opts, pargs, stdout_flag=False)
159+
_, err = capsys.readouterr()
160+
assert "Unable to save to designated location." in err
143161
with pytest.raises(SystemExit):
144162
multiple_targets(self.parser, opts, pargs, stdout_flag=False)
163+
_, err = capsys.readouterr()
164+
assert "is not a directory." in err
145165

146166
# Ensure first parg is a FILE and second parg is a DIRECTORY
147167
(opts, pargs) = self.parser.parse_args(
@@ -152,15 +172,21 @@ def test_parser_systemexits(self, setup_parser):
152172
(opts, pargs) = self.parser.parse_args(
153173
[f"{testsequence_dir}", f"{testsequence_dir}"]
154174
)
175+
_, err = capsys.readouterr()
176+
assert "is not a directory." in err
155177
with pytest.raises(SystemExit):
156178
multiple_targets(self.parser, opts, pargs, stdout_flag=False)
179+
_, err = capsys.readouterr()
180+
assert "is not a file." in err
157181

158182
# Try sorting by non-existing field
159183
(opts, pargs) = self.parser.parse_args(
160184
[f"{nickel_PDF}", f"{testsequence_dir}", "--sort-by", "fake_field"]
161185
)
162186
with pytest.raises(SystemExit):
163187
multiple_targets(self.parser, opts, pargs, stdout_flag=False)
188+
_, err = capsys.readouterr()
189+
assert "The requested field is missing from a PDF file header." in err
164190
(opts, pargs) = self.parser.parse_args(
165191
[
166192
f"{nickel_PDF}",
@@ -173,6 +199,8 @@ def test_parser_systemexits(self, setup_parser):
173199
)
174200
with pytest.raises(SystemExit):
175201
multiple_targets(self.parser, opts, pargs, stdout_flag=False)
202+
_, err = capsys.readouterr()
203+
assert "The requested field was not found in the metadata file." in err
176204

177205
# Try plotting an unknown parameter
178206
(opts, pargs) = self.parser.parse_args(
@@ -185,6 +213,8 @@ def test_parser_systemexits(self, setup_parser):
185213
)
186214
with pytest.raises(SystemExit):
187215
multiple_targets(self.parser, opts, pargs, stdout_flag=False)
216+
_, err = capsys.readouterr()
217+
assert "Cannot find specified plot parameter. No plot shown." in err
188218

189219
# Try plotting an unrefined parameter
190220
(opts, pargs) = self.parser.parse_args(
@@ -197,6 +227,26 @@ def test_parser_systemexits(self, setup_parser):
197227
)
198228
with pytest.raises(SystemExit):
199229
multiple_targets(self.parser, opts, pargs, stdout_flag=False)
230+
_, err = capsys.readouterr()
231+
assert (
232+
"The plot parameter is missing values for at "
233+
"least one morph and target pair. "
234+
"No plot shown." in err
235+
)
236+
237+
# Pass a non-float list to squeeze
238+
(opts, pargs) = self.parser.parse_args(
239+
[
240+
f"{nickel_PDF}",
241+
f"{nickel_PDF}",
242+
"--squeeze",
243+
"1,a,0",
244+
]
245+
)
246+
with pytest.raises(SystemExit):
247+
single_morph(self.parser, opts, pargs, stdout_flag=False)
248+
_, err = capsys.readouterr()
249+
assert "a could not be converted to float." in err
200250

201251
def test_morphsequence(self, setup_morphsequence):
202252
# Parse arguments sorting by field

tests/test_morphio.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ def test_morphsqueeze_outputs(self, setup, tmp_path):
163163
"--scale",
164164
"2",
165165
"--squeeze",
166-
"0,-0.001,-0.0001,0.0001",
166+
# Ignore duplicate commas and trailing commas
167+
# Handle spaces and non-spaces
168+
"0,, ,-0.001, -0.0001,0.0001,",
167169
"--stretch",
168170
"1",
169171
"--hshift",

0 commit comments

Comments
 (0)