Skip to content

Commit 283c2d3

Browse files
Merge branch 'main' into wavelength-config
2 parents cf3b37e + bd71eda commit 283c2d3

File tree

4 files changed

+135
-59
lines changed

4 files changed

+135
-59
lines changed

news/muD-options.rst

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
**Added:**
2+
3+
* <news item>
4+
5+
**Changed:**
6+
7+
* Made muD an optional argument and provided different options (manually entry / z-scan file path) for users to specify muD
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/labpdfproc/labpdfprocapp.py

+28-15
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,8 @@
1313
from diffpy.utils.parsers.loaddata import loadData
1414

1515

16-
def define_arguments():
16+
def _define_arguments():
1717
args = [
18-
{
19-
"name": ["mud"],
20-
"help": "Value of mu*D for your sample. Required.",
21-
"type": float,
22-
},
2318
{
2419
"name": ["input"],
2520
"help": (
@@ -150,20 +145,37 @@ def define_arguments():
150145
),
151146
"default": None,
152147
},
153-
{
154-
"name": ["-z", "--z-scan-file"],
155-
"help": "Path to the z-scan file to be loaded "
156-
"to determine the mu*D value.",
157-
"default": None,
158-
"widget": "FileChooser",
159-
},
160148
]
161149
return args
162150

163151

152+
def _add_mud_selection_group(p, is_gui=False):
153+
"""Current Options:
154+
1. Manually enter muD (`--mud`).
155+
2. Estimate muD from a z-scan file (`-z` or `--z-scan-file`).
156+
"""
157+
g = p.add_argument_group("Options for setting mu*D value (Required)")
158+
g = g.add_mutually_exclusive_group(required=True)
159+
g.add_argument(
160+
"--mud",
161+
type=float,
162+
help="Enter the mu*D value manually.",
163+
**({"widget": "DecimalField"} if is_gui else {}),
164+
)
165+
g.add_argument(
166+
"-z",
167+
"--z-scan-file",
168+
help="Provide the path to the z-scan file to be loaded "
169+
"to determine the mu*D value.",
170+
**({"widget": "FileChooser"} if is_gui else {}),
171+
)
172+
return p
173+
174+
164175
def get_args(override_cli_inputs=None):
165176
p = ArgumentParser()
166-
for arg in define_arguments():
177+
p = _add_mud_selection_group(p, is_gui=False)
178+
for arg in _define_arguments():
167179
kwargs = {
168180
key: value
169181
for key, value in arg.items()
@@ -177,7 +189,8 @@ def get_args(override_cli_inputs=None):
177189
@Gooey(required_cols=1, optional_cols=1, program_name="Labpdfproc GUI")
178190
def gooey_parser():
179191
p = GooeyParser()
180-
for arg in define_arguments():
192+
p = _add_mud_selection_group(p, is_gui=True)
193+
for arg in _define_arguments():
181194
kwargs = {key: value for key, value in arg.items() if key != "name"}
182195
p.add_argument(*arg["name"], **kwargs)
183196
args = p.parse_args()

src/diffpy/labpdfproc/tools.py

+29-10
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,34 @@ def set_xtype(args):
298298
return args
299299

300300

301+
def _estimate_mud_from_zscan(args):
302+
"""Compute mu*D based on the given z-scan file.
303+
304+
Parameters
305+
----------
306+
args : argparse.Namespace
307+
The arguments from the parser.
308+
309+
Returns
310+
-------
311+
args : argparse.Namespace
312+
The updated arguments with mu*D.
313+
"""
314+
filepath = Path(args.z_scan_file).resolve()
315+
if not filepath.is_file():
316+
raise FileNotFoundError(
317+
f"Cannot find {args.z_scan_file}. "
318+
f"Please specify a valid file path."
319+
)
320+
args.z_scan_file = str(filepath)
321+
args.mud = compute_mud(filepath)
322+
return args
323+
324+
301325
def set_mud(args):
302-
"""Compute mu*D based on the given z-scan file, if provided.
326+
"""Compute and set mu*D based on different options.
327+
Current options include manually entering a value,
328+
or estimating from a z-scan file.
303329
304330
Parameters
305331
----------
@@ -312,14 +338,7 @@ def set_mud(args):
312338
The updated arguments with mu*D.
313339
"""
314340
if args.z_scan_file:
315-
filepath = Path(args.z_scan_file).resolve()
316-
if not filepath.is_file():
317-
raise FileNotFoundError(
318-
f"Cannot find {args.z_scan_file}. "
319-
f"Please specify a valid file path."
320-
)
321-
args.z_scan_file = str(filepath)
322-
args.mud = compute_mud(filepath)
341+
return _estimate_mud_from_zscan(args)
323342
return args
324343

325344

@@ -437,13 +456,13 @@ def preprocessing_args(args):
437456
args : argparse.Namespace
438457
The updated argparse Namespace with arguments preprocessed.
439458
"""
459+
args = set_mud(args)
440460
args = load_package_info(args)
441461
args = load_user_info(args)
442462
args = set_input_lists(args)
443463
args = set_output_directory(args)
444464
args = set_wavelength(args)
445465
args = set_xtype(args)
446-
args = set_mud(args)
447466
args = load_user_metadata(args)
448467
return args
449468

tests/test_tools.py

+55-34
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def test_set_input_lists(inputs, expected, user_filesystem):
115115
base_dir.resolve() / expected_path for expected_path in expected
116116
]
117117

118-
cli_inputs = ["2.5"] + inputs
118+
cli_inputs = inputs + ["--mud", "2.5"]
119119
actual_args = get_args(cli_inputs)
120120
actual_args = set_input_lists(actual_args)
121121
assert sorted(actual_args.input_paths) == sorted(expected_paths)
@@ -161,7 +161,7 @@ def test_set_input_lists(inputs, expected, user_filesystem):
161161
def test_set_input_files_bad(inputs, expected_error_msg, user_filesystem):
162162
base_dir = Path(user_filesystem)
163163
os.chdir(base_dir)
164-
cli_inputs = ["2.5"] + inputs
164+
cli_inputs = inputs + ["--mud", "2.5"]
165165
actual_args = get_args(cli_inputs)
166166
with pytest.raises(FileNotFoundError, match=re.escape(expected_error_msg)):
167167
actual_args = set_input_lists(actual_args)
@@ -179,7 +179,7 @@ def test_set_input_files_bad(inputs, expected_error_msg, user_filesystem):
179179
def test_set_output_directory(inputs, expected, user_filesystem):
180180
os.chdir(user_filesystem)
181181
expected_output_directory = Path(user_filesystem) / expected[0]
182-
cli_inputs = ["2.5", "data.xy"] + inputs
182+
cli_inputs = ["data.xy", "--mud", "2.5"] + inputs
183183
actual_args = get_args(cli_inputs)
184184
actual_args = set_output_directory(actual_args)
185185
assert actual_args.output_directory == expected_output_directory
@@ -189,7 +189,13 @@ def test_set_output_directory(inputs, expected, user_filesystem):
189189

190190
def test_set_output_directory_bad(user_filesystem):
191191
os.chdir(user_filesystem)
192-
cli_inputs = ["2.5", "data.xy", "--output-directory", "good_data.chi"]
192+
cli_inputs = [
193+
"data.xy",
194+
"--mud",
195+
"2.5",
196+
"--output-directory",
197+
"good_data.chi",
198+
]
193199
actual_args = get_args(cli_inputs)
194200
with pytest.raises(FileExistsError):
195201
actual_args = set_output_directory(actual_args)
@@ -374,7 +380,7 @@ def test_load_wavelength_from_config_file_without_conf_files(
374380
],
375381
)
376382
def test_set_wavelength(inputs, expected):
377-
cli_inputs = ["2.5", "data.xy"] + inputs
383+
cli_inputs = ["data.xy", "--mud", "2.5"] + inputs
378384
actual_args = get_args(cli_inputs)
379385
actual_args = set_wavelength(actual_args)
380386
assert actual_args.wavelength == expected["wavelength"]
@@ -413,7 +419,7 @@ def test_set_wavelength(inputs, expected):
413419
],
414420
)
415421
def test_set_wavelength_bad(inputs, expected_error_msg):
416-
cli_inputs = ["2.5", "data.xy"] + inputs
422+
cli_inputs = ["data.xy", "--mud", "2.5"] + inputs
417423
actual_args = get_args(cli_inputs)
418424
with pytest.raises(ValueError, match=re.escape(expected_error_msg)):
419425
actual_args = set_wavelength(actual_args)
@@ -429,50 +435,63 @@ def test_set_wavelength_bad(inputs, expected_error_msg):
429435
],
430436
)
431437
def test_set_xtype(inputs, expected_xtype):
432-
cli_inputs = ["2.5", "data.xy"] + inputs
438+
cli_inputs = ["data.xy", "--mud", "2.5"] + inputs
433439
actual_args = get_args(cli_inputs)
434440
actual_args = set_xtype(actual_args)
435441
assert actual_args.xtype == expected_xtype
436442

437443

438444
def test_set_xtype_bad():
439-
cli_inputs = ["2.5", "data.xy", "--xtype", "invalid"]
445+
cli_inputs = ["data.xy", "--mud", "2.5", "--xtype", "invalid"]
440446
actual_args = get_args(cli_inputs)
441447
with pytest.raises(
442448
ValueError,
443449
match=re.escape(
444-
f"Unknown xtype: invalid. " f"Allowed xtypes are {*XQUANTITIES, }."
450+
f"Unknown xtype: invalid. Allowed xtypes are {*XQUANTITIES, }."
445451
),
446452
):
447453
actual_args = set_xtype(actual_args)
448454

449455

450-
def test_set_mud(user_filesystem):
451-
cli_inputs = ["2.5", "data.xy"]
452-
actual_args = get_args(cli_inputs)
453-
actual_args = set_mud(actual_args)
454-
assert actual_args.mud == pytest.approx(2.5, rel=1e-4, abs=0.1)
455-
assert actual_args.z_scan_file is None
456-
456+
@pytest.mark.parametrize(
457+
"inputs, expected_mud",
458+
[
459+
# C1: user enters muD manually, expect to return the same value
460+
(["--mud", "2.5"], 2.5),
461+
# C2: user provides a z-scan file, expect to estimate through the file
462+
(["--z-scan-file", "test_dir/testfile.xy"], 3),
463+
],
464+
)
465+
def test_set_mud(user_filesystem, inputs, expected_mud):
457466
cwd = Path(user_filesystem)
458-
test_dir = cwd / "test_dir"
459467
os.chdir(cwd)
460-
inputs = ["--z-scan-file", "test_dir/testfile.xy"]
461-
expected = [3, str(test_dir / "testfile.xy")]
462-
cli_inputs = ["2.5", "data.xy"] + inputs
468+
cli_inputs = ["data.xy"] + inputs
463469
actual_args = get_args(cli_inputs)
464470
actual_args = set_mud(actual_args)
465-
assert actual_args.mud == pytest.approx(expected[0], rel=1e-4, abs=0.1)
466-
assert actual_args.z_scan_file == expected[1]
471+
assert actual_args.mud == pytest.approx(expected_mud, rel=1e-4, abs=0.1)
467472

468473

469-
def test_set_mud_bad():
470-
cli_inputs = ["2.5", "data.xy", "--z-scan-file", "invalid file"]
474+
@pytest.mark.parametrize(
475+
"inputs, expected",
476+
[
477+
# C1: user provides an invalid z-scan file,
478+
# expect FileNotFoundError and message to specify a valid file path
479+
(
480+
["--z-scan-file", "invalid file"],
481+
[
482+
FileNotFoundError,
483+
"Cannot find invalid file. Please specify a valid file path.",
484+
],
485+
),
486+
],
487+
)
488+
def test_set_mud_bad(user_filesystem, inputs, expected):
489+
expected_error, expected_error_msg = expected
490+
cwd = Path(user_filesystem)
491+
os.chdir(cwd)
492+
cli_inputs = ["data.xy"] + inputs
471493
actual_args = get_args(cli_inputs)
472-
with pytest.raises(
473-
FileNotFoundError,
474-
match="Cannot find invalid file. " "Please specify a valid file path.",
475-
):
494+
with pytest.raises(expected_error, match=expected_error_msg):
476495
actual_args = set_mud(actual_args)
477496

478497

@@ -497,12 +516,12 @@ def test_set_mud_bad():
497516
],
498517
)
499518
def test_load_user_metadata(inputs, expected):
500-
expected_args = get_args(["2.5", "data.xy"])
519+
expected_args = get_args(["data.xy", "--mud", "2.5"])
501520
for expected_pair in expected:
502521
setattr(expected_args, expected_pair[0], expected_pair[1])
503522
delattr(expected_args, "user_metadata")
504523

505-
cli_inputs = ["2.5", "data.xy"] + inputs
524+
cli_inputs = ["data.xy", "--mud", "2.5"] + inputs
506525
actual_args = get_args(cli_inputs)
507526
actual_args = load_user_metadata(actual_args)
508527
assert actual_args == expected_args
@@ -538,7 +557,7 @@ def test_load_user_metadata(inputs, expected):
538557
],
539558
)
540559
def test_load_user_metadata_bad(inputs, expected_error_msg):
541-
cli_inputs = ["2.5", "data.xy"] + inputs
560+
cli_inputs = ["data.xy", "--mud", "2.5"] + inputs
542561
actual_args = get_args(cli_inputs)
543562
with pytest.raises(ValueError, match=re.escape(expected_error_msg)):
544563
actual_args = load_user_metadata(actual_args)
@@ -601,8 +620,9 @@ def test_load_user_info(monkeypatch, inputs, expected, user_filesystem):
601620
os.chdir(cwd)
602621

603622
cli_inputs = [
604-
"2.5",
605623
"data.xy",
624+
"--mud",
625+
"2.5",
606626
"--username",
607627
inputs["username"],
608628
"--email",
@@ -624,7 +644,7 @@ def test_load_package_info(mocker):
624644
"3.3.0" if package_name == "diffpy.utils" else "1.2.3"
625645
),
626646
)
627-
cli_inputs = ["2.5", "data.xy"]
647+
cli_inputs = ["data.xy", "--mud", "2.5"]
628648
actual_args = get_args(cli_inputs)
629649
actual_args = load_package_info(actual_args)
630650
assert actual_args.package_info == {
@@ -650,8 +670,9 @@ def test_load_metadata(mocker, user_filesystem):
650670
),
651671
)
652672
cli_inputs = [
653-
"2.5",
654673
".",
674+
"--mud",
675+
"2.5",
655676
"--anode-type",
656677
"Mo",
657678
"--user-metadata",

0 commit comments

Comments
 (0)