feat(cli): propagate export options through JSON/paceENSDF flows
- main(argv) signature enables in-process CLI invocation and testing - parser defaults for --e-step/--neutrino-mass/--intensity-cutoff/ --csv-separator/--normalize-to-one now None = 'not provided' - JSON flow applies file values by default and CLI flags as overrides (previously these five options were silently discarded) - paceENSDF flow resolves None flags to literal defaults - new tests/integration/test_cli_flows.py: JSON propagation, degenerate-mode non-zero exit with no file (JSON + paceENSDF) - adapted two neutrino-mass default tests to None-parsing semantics
This commit is contained in:
+58
-25
@@ -81,14 +81,18 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
parser.add_argument(
|
||||
"--e-step",
|
||||
type=float,
|
||||
default=0.001,
|
||||
help="Energy step size in MeV (default: 0.001). All energies are in MeV throughout the toolkit.",
|
||||
default=None,
|
||||
help="Energy step size in MeV (default: 0.001 for nuclide input; "
|
||||
"for JSON input the file's e_step_MeV is used when the flag is "
|
||||
"omitted). All energies are in MeV throughout the toolkit.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--neutrino-mass",
|
||||
type=float,
|
||||
default=0.0,
|
||||
help="Neutrino mass in MeV (default: 0.0). Set to non-zero value to include neutrino mass effects in phase space calculation.",
|
||||
default=None,
|
||||
help="Neutrino mass in MeV (default: 0.0, or the JSON file's "
|
||||
"neutrino_mass_MeV when omitted). Set to non-zero value to include "
|
||||
"neutrino mass effects in phase space calculation.",
|
||||
)
|
||||
|
||||
# Output
|
||||
@@ -138,7 +142,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
log_group.add_argument(
|
||||
"--intensity-cutoff",
|
||||
type=float,
|
||||
default=0.0,
|
||||
default=None,
|
||||
metavar="FRAC",
|
||||
help="Minimum branch intensity fraction to include in the spectrum "
|
||||
"(default: 0.0 = include all branches). "
|
||||
@@ -154,12 +158,13 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
log_group.add_argument(
|
||||
"--csv-separator",
|
||||
type=str,
|
||||
default=",",
|
||||
default=None,
|
||||
help="CSV column separator (default: ','). Use 'tab' for tab separation.",
|
||||
)
|
||||
log_group.add_argument(
|
||||
"--normalize-to-one",
|
||||
action="store_true",
|
||||
default=None,
|
||||
help="Normalize each branch to 1, ignoring intensity. In this case, total spectrum will not be produced (only energy and branch-wise spectra).",
|
||||
)
|
||||
|
||||
@@ -230,6 +235,17 @@ def _run(args: argparse.Namespace) -> None:
|
||||
else:
|
||||
source_type = "paceENSDF"
|
||||
|
||||
# Resolve optional CLI flags: None means "not provided". For paceENSDF
|
||||
# they fall back to literal defaults; for JSON they let the file's own
|
||||
# values through unless explicitly overridden.
|
||||
e_step_MeV = 0.001 if args.e_step is None else float(args.e_step)
|
||||
neutrino_mass_MeV = 0.0 if args.neutrino_mass is None else float(args.neutrino_mass)
|
||||
intensity_cutoff = (
|
||||
0.0 if args.intensity_cutoff is None else float(args.intensity_cutoff)
|
||||
)
|
||||
csv_separator = "," if args.csv_separator is None else args.csv_separator
|
||||
normalize_to_one = bool(args.normalize_to_one)
|
||||
|
||||
# Build config
|
||||
config: SpectrumConfig
|
||||
if source_type == "paceENSDF":
|
||||
@@ -251,7 +267,7 @@ def _run(args: argparse.Namespace) -> None:
|
||||
intensity=b.intensity / total_intensity,
|
||||
)
|
||||
for b in decay_info.branches
|
||||
if b.intensity / total_intensity >= args.intensity_cutoff
|
||||
if b.intensity / total_intensity >= intensity_cutoff
|
||||
]
|
||||
config = SpectrumConfig(
|
||||
Z_parent=decay_info.Z_parent,
|
||||
@@ -259,37 +275,48 @@ def _run(args: argparse.Namespace) -> None:
|
||||
A_number=decay_info.A_number,
|
||||
endpoint_MeV=decay_info.endpoint_MeV,
|
||||
transition_type=decay_info.transition_type,
|
||||
e_step_MeV=args.e_step,
|
||||
neutrino_mass_MeV=args.neutrino_mass,
|
||||
e_step_MeV=e_step_MeV,
|
||||
neutrino_mass_MeV=neutrino_mass_MeV,
|
||||
branches=branches,
|
||||
intensity_cutoff=args.intensity_cutoff,
|
||||
csv_separator=args.csv_separator,
|
||||
normalize_to_one=args.normalize_to_one,
|
||||
intensity_cutoff=intensity_cutoff,
|
||||
csv_separator=csv_separator,
|
||||
normalize_to_one=normalize_to_one,
|
||||
)
|
||||
else:
|
||||
config = create_config_from_source(
|
||||
"paceENSDF",
|
||||
nuclide=source_value,
|
||||
e_step_MeV=args.e_step,
|
||||
intensity_cutoff=args.intensity_cutoff,
|
||||
neutrino_mass_MeV=args.neutrino_mass,
|
||||
csv_separator=args.csv_separator,
|
||||
normalize_to_one=args.normalize_to_one,
|
||||
e_step_MeV=e_step_MeV,
|
||||
intensity_cutoff=intensity_cutoff,
|
||||
neutrino_mass_MeV=neutrino_mass_MeV,
|
||||
csv_separator=csv_separator,
|
||||
normalize_to_one=normalize_to_one,
|
||||
)
|
||||
else:
|
||||
config = create_config_from_source(
|
||||
"paceENSDF",
|
||||
nuclide=source_value,
|
||||
e_step_MeV=args.e_step,
|
||||
intensity_cutoff=args.intensity_cutoff,
|
||||
neutrino_mass_MeV=args.neutrino_mass,
|
||||
csv_separator=args.csv_separator,
|
||||
normalize_to_one=args.normalize_to_one,
|
||||
e_step_MeV=e_step_MeV,
|
||||
intensity_cutoff=intensity_cutoff,
|
||||
neutrino_mass_MeV=neutrino_mass_MeV,
|
||||
csv_separator=csv_separator,
|
||||
normalize_to_one=normalize_to_one,
|
||||
)
|
||||
else:
|
||||
logger.info("Source: JSON file=%s", source_value)
|
||||
data = load_json_input(source_value)
|
||||
config = json_to_config(data)
|
||||
# CLI flags override the JSON file values only when explicitly
|
||||
# provided; unset flags keep the file's own values.
|
||||
if args.e_step is not None:
|
||||
config.e_step_MeV = e_step_MeV
|
||||
if args.neutrino_mass is not None:
|
||||
config.neutrino_mass_MeV = neutrino_mass_MeV
|
||||
if args.intensity_cutoff is not None:
|
||||
config.intensity_cutoff = intensity_cutoff
|
||||
if args.csv_separator is not None:
|
||||
config.csv_separator = csv_separator
|
||||
config.normalize_to_one = normalize_to_one
|
||||
|
||||
# Dry run: display resolved config and exit
|
||||
if args.dry_run:
|
||||
@@ -516,10 +543,16 @@ def _decay_notation(Z_parent: int, Z_daughter: int, A: int) -> str:
|
||||
return f"{_nuclide_symbol(Z_parent, A)} -> {_nuclide_symbol(Z_daughter, A)}"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Main entry point for the CLI."""
|
||||
def main(argv: list[str] | None = None) -> None:
|
||||
"""Main entry point for the CLI.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
argv : list[str], optional
|
||||
Explicit argument vector (for tests/embedding); None reads sys.argv.
|
||||
"""
|
||||
parser = _build_parser()
|
||||
args = parser.parse_args()
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
try:
|
||||
_run(args)
|
||||
|
||||
Reference in New Issue
Block a user