Skip to content

Commit 06b839e

Browse files
authored
Add writer style option to SettingsWriter pt2 : Propagate to additional methods (#932)
* Add settingsWriteStyle arg to case and suite cloning CLI/modules * WIP add unit tests * Docstring fixes * Fix for using clone with medium write style The medium write style requires clone to pass in knowledge about the "from" location, not just the "to" location, so that the original settings can be read in. * Add a test for clone * Adding a little more to writeInputs test * Release notes * Missed a commit in interactive rebase...this fixes what was missing * Address reviewer comment: add comments to explain expected test results * Address reviewer comments: More descriptive docstrings, and moving a line under the if statement it pertains to
1 parent f4bb14b commit 06b839e

File tree

7 files changed

+167
-23
lines changed

7 files changed

+167
-23
lines changed

armi/cases/case.py

+26-11
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,13 @@ def buildCommand(self, python="python"):
601601

602602
return command
603603

604-
def clone(self, additionalFiles=None, title=None, modifiedSettings=None):
604+
def clone(
605+
self,
606+
additionalFiles=None,
607+
title=None,
608+
modifiedSettings=None,
609+
writeStyle="short",
610+
):
605611
"""
606612
Clone existing ARMI inputs to current directory with optional settings modifications.
607613
@@ -616,6 +622,9 @@ def clone(self, additionalFiles=None, title=None, modifiedSettings=None):
616622
title of new case
617623
modifiedSettings : dict (optional)
618624
settings to set/modify before creating the cloned case
625+
writeStyle : str (optional)
626+
Writing style for which settings get written back to the settings files
627+
(short, medium, or full).
619628
620629
Raises
621630
------
@@ -644,7 +653,7 @@ def clone(self, additionalFiles=None, title=None, modifiedSettings=None):
644653
clone.cs = newCs
645654

646655
runLog.important("writing settings file {}".format(clone.cs.path))
647-
clone.cs.writeToYamlFile(clone.cs.path)
656+
clone.cs.writeToYamlFile(clone.cs.path, style=writeStyle, fromFile=self.cs.path)
648657
runLog.important("finished writing {}".format(clone.cs))
649658

650659
fromPath = lambda fname: pathTools.armiAbsPath(self.cs.inputDirectory, fname)
@@ -732,7 +741,9 @@ def compare(
732741

733742
return code
734743

735-
def writeInputs(self, sourceDir: Optional[str] = None):
744+
def writeInputs(
745+
self, sourceDir: Optional[str] = None, writeStyle: Optional[str] = "short"
746+
):
736747
"""
737748
Write the inputs to disk.
738749
@@ -742,9 +753,12 @@ def writeInputs(self, sourceDir: Optional[str] = None):
742753
743754
Parameters
744755
----------
745-
sourceDir : str, optional
756+
sourceDir : str (optional)
746757
The path to copy inputs from (if different from the cs.path). Needed
747758
in SuiteBuilder cases to find the baseline inputs from plugins (e.g. shuffleLogic)
759+
writeStyle : str (optional)
760+
Writing style for which settings get written back to the settings files
761+
(short, medium, or full).
748762
749763
Notes
750764
-----
@@ -789,7 +803,13 @@ def writeInputs(self, sourceDir: Optional[str] = None):
789803
newSettings[settingName] = value
790804

791805
self.cs = self.cs.modified(newSettings=newSettings)
792-
self.cs.writeToYamlFile(self.title + ".yaml")
806+
if sourceDir:
807+
fromPath = os.path.join(sourceDir, self.title + ".yaml")
808+
else:
809+
fromPath = self.cs.path
810+
self.cs.writeToYamlFile(
811+
self.title + ".yaml", style=writeStyle, fromFile=fromPath
812+
)
793813

794814

795815
def _copyInputsHelper(
@@ -807,13 +827,10 @@ def _copyInputsHelper(
807827
----------
808828
fileDescription : str
809829
A file description for the copyOrWarn method
810-
811830
sourcePath : str
812831
The absolute file path of the file to copy
813-
814832
destPath : str
815833
The target directory to copy input files to
816-
817834
origFile : str
818835
File path as defined in the original settings file
819836
@@ -857,11 +874,9 @@ def copyInterfaceInputs(
857874
----------
858875
cs : CaseSettings
859876
The source case settings to find input files
860-
861877
destination : str
862878
The target directory to copy input files to
863-
864-
sourceDir : str, optional
879+
sourceDir : str (optional)
865880
The directory from which to copy files. Defaults to cs.inputDirectory
866881
867882
Returns

armi/cases/suite.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def echoConfiguration(self):
146146
)
147147
)
148148

149-
def clone(self, oldRoot=None):
149+
def clone(self, oldRoot=None, writeStyle="short"):
150150
"""
151151
Clone a CaseSuite to a new place.
152152
@@ -160,6 +160,9 @@ def clone(self, oldRoot=None):
160160
oldRoot : str (optional)
161161
root directory of original case suite used to help filter when a suite
162162
contains one or more cases with the same case title.
163+
writeStyle : str (optional)
164+
Writing style for which settings get written back to the settings files
165+
(short, medium, or full).
163166
164167
Notes
165168
-----
@@ -185,7 +188,9 @@ def clone(self, oldRoot=None):
185188
with directoryChangers.ForcedCreationDirectoryChanger(
186189
newDir, dumpOnException=False
187190
):
188-
clone.add(case.clone(modifiedSettings=modifiedSettings))
191+
clone.add(
192+
case.clone(modifiedSettings=modifiedSettings, writeStyle=writeStyle)
193+
)
189194
return clone
190195

191196
def run(self):
@@ -266,17 +271,21 @@ def compare(
266271

267272
return nIssues
268273

269-
def writeInputs(self):
274+
def writeInputs(self, writeStyle="short"):
270275
"""
271276
Write inputs for all cases in the suite.
272277
278+
writeStyle : str (optional)
279+
Writing style for which settings get written back to the settings files
280+
(short, medium, or full).
281+
273282
See Also
274283
--------
275284
clone
276285
Similar to this but doesn't let you write out new geometry or blueprints objects.
277286
"""
278287
for case in self:
279-
case.writeInputs(sourceDir=self.cs.inputDirectory)
288+
case.writeInputs(sourceDir=self.cs.inputDirectory, writeStyle=writeStyle)
280289

281290
@staticmethod
282291
def writeTable(tableResults):

armi/cases/tests/test_cases.py

+51
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,44 @@ def test_run(self):
212212
self.assertIn("xsGroups", mock._outputStream)
213213
self.assertIn("Completed EveryNode - cycle 0", mock._outputStream)
214214

215+
def test_clone(self):
216+
testTitle = "CLONE_TEST"
217+
# test the short write style
218+
with directoryChangers.TemporaryDirectoryChanger():
219+
cs = settings.Settings(ARMI_RUN_PATH)
220+
setMasterCs(cs)
221+
case = cases.Case(cs)
222+
shortCase = case.clone(
223+
additionalFiles=["ISOAA"],
224+
title=testTitle,
225+
modifiedSettings={"verbosity": "important"},
226+
)
227+
# Check additional files made it
228+
self.assertTrue(os.path.exists("ISOAA"))
229+
# Check title change made it
230+
clonedYaml = testTitle + ".yaml"
231+
self.assertTrue(os.path.exists(clonedYaml))
232+
self.assertTrue(shortCase.title, testTitle)
233+
# Check on some expected settings
234+
# Availability factor is in the original settings file but since it is a
235+
# default value, gets removed for the write-out
236+
txt = open(clonedYaml, "r").read()
237+
self.assertNotIn("availabilityFactor", txt)
238+
self.assertIn("verbosity: important", txt)
239+
240+
# test the medium write style
241+
with directoryChangers.TemporaryDirectoryChanger():
242+
cs = settings.Settings(ARMI_RUN_PATH)
243+
setMasterCs(cs)
244+
case = cases.Case(cs)
245+
case.clone(writeStyle="medium")
246+
clonedYaml = "armiRun.yaml"
247+
self.assertTrue(os.path.exists(clonedYaml))
248+
# Availability factor is in the original settings file and it is a default
249+
# value. While "short" (default writing style) removes, "medium" should not
250+
txt = open(clonedYaml, "r").read()
251+
self.assertIn("availabilityFactor", txt)
252+
215253

216254
class TestCaseSuiteDependencies(unittest.TestCase):
217255
"""CaseSuite tests"""
@@ -370,6 +408,19 @@ def test_writeInput(self):
370408
case = baseCase.clone()
371409
case.writeInputs()
372410
self.assertTrue(os.path.exists(cs["shuffleLogic"]))
411+
# Availability factor is in the original settings file but since it is a
412+
# default value, gets removed for the write-out
413+
txt = open("armiRun.yaml", "r").read()
414+
self.assertNotIn("availabilityFactor", txt)
415+
self.assertIn("armiRun-blueprints.yaml", txt)
416+
417+
with directoryChangers.TemporaryDirectoryChanger():
418+
case = baseCase.clone(writeStyle="medium")
419+
case.writeInputs(writeStyle="medium")
420+
# Availability factor is in the original settings file and it is a default
421+
# value. While "short" (default writing style) removes, "medium" should not
422+
txt = open("armiRun.yaml", "r").read()
423+
self.assertIn("availabilityFactor", txt)
373424

374425

375426
class MultiFilesInterfaces(interfaces.Interface):

armi/cli/clone.py

+21-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ def addOptions(self):
3434
default=[],
3535
help="Additional files from the source directory to copy into the target directory",
3636
)
37+
self.parser.add_argument(
38+
"--settingsWriteStyle",
39+
type=str,
40+
default="short",
41+
help="Writing style for which settings get written back to the settings files.",
42+
choices=["short", "medium", "full"],
43+
)
3744
# somehow running `armi clone-batch -h` on the command line requires this to
3845
# not be first?
3946
for settingName in self.cs.keys():
@@ -44,7 +51,10 @@ def invoke(self):
4451
from armi import cases
4552

4653
inputCase = cases.Case(cs=self.cs)
47-
inputCase.clone(additionalFiles=self.args.additional_files)
54+
inputCase.clone(
55+
additionalFiles=self.args.additional_files,
56+
writeStyle=self.args.settingsWriteStyle,
57+
)
4858

4959

5060
class CloneArmiRunCommandInteractive(CloneArmiRunCommandBatch):
@@ -95,6 +105,13 @@ def addOptions(self):
95105
default=False,
96106
help="Just list the settings files found, don't actually submit them.",
97107
)
108+
self.parser.add_argument(
109+
"--settingsWriteStyle",
110+
type=str,
111+
default="short",
112+
help="Writing style for which settings get written back to the settings files.",
113+
choices=["short", "medium", "full"],
114+
)
98115

99116
def invoke(self):
100117
from armi import cases
@@ -105,4 +122,6 @@ def invoke(self):
105122
rootDir=self.args.directory,
106123
ignorePatterns=self.args.ignore,
107124
)
108-
suite.clone(oldRoot=self.args.directory)
125+
suite.clone(
126+
oldRoot=self.args.directory, writeStyle=self.args.settingsWriteStyle
127+
)

armi/cli/tests/test_runEntryPoint.py

+46-2
Original file line numberDiff line numberDiff line change
@@ -97,21 +97,65 @@ class TestCloneArmiRunCommandBatch(unittest.TestCase):
9797
def test_cloneArmiRunCommandBatchBasics(self):
9898
ca = CloneArmiRunCommandBatch()
9999
ca.addOptions()
100-
ca.parse_args([ARMI_RUN_PATH, "--additional-files", "test"])
100+
ca.parse_args(
101+
[
102+
ARMI_RUN_PATH,
103+
"--additional-files",
104+
"test",
105+
"--settingsWriteStyle",
106+
"full",
107+
]
108+
)
101109

102110
self.assertEqual(ca.name, "clone-batch")
103111
self.assertEqual(ca.settingsArgument, "required")
104112
self.assertEqual(ca.args.additional_files, ["test"])
113+
self.assertEqual(ca.args.settingsWriteStyle, "full")
114+
115+
def test_cloneArmiRunCommandBatchInvokeShort(self):
116+
# Test short write style
117+
ca = CloneArmiRunCommandBatch()
118+
ca.addOptions()
119+
ca.parse_args([ARMI_RUN_PATH])
120+
121+
with TemporaryDirectoryChanger():
122+
ca.invoke()
123+
124+
self.assertEqual(ca.settingsArgument, "required")
125+
self.assertEqual(ca.args.settingsWriteStyle, "short")
126+
clonedYaml = "armiRun.yaml"
127+
self.assertTrue(os.path.exists(clonedYaml))
128+
# validate a setting that has a default value was removed
129+
txt = open(clonedYaml, "r").read()
130+
self.assertNotIn("availabilityFactor", txt)
131+
132+
def test_cloneArmiRunCommandBatchInvokeMedium(self):
133+
# Test medium write style
134+
ca = CloneArmiRunCommandBatch()
135+
ca.addOptions()
136+
ca.parse_args([ARMI_RUN_PATH, "--settingsWriteStyle", "medium"])
137+
138+
with TemporaryDirectoryChanger():
139+
ca.invoke()
140+
141+
self.assertEqual(ca.settingsArgument, "required")
142+
self.assertEqual(ca.args.settingsWriteStyle, "medium")
143+
clonedYaml = "armiRun.yaml"
144+
self.assertTrue(os.path.exists(clonedYaml))
145+
# validate a setting that has a default value is still there
146+
txt = open(clonedYaml, "r").read()
147+
self.assertIn("availabilityFactor", txt)
105148

106149

107150
class TestCloneSuiteCommand(unittest.TestCase):
108151
def test_cloneSuiteCommandBasics(self):
109152
cs = CloneSuiteCommand()
110153
cs.addOptions()
111-
cs.parse_args(["-d", "test"])
154+
cs.parse_args(["-d", "test", "--settingsWriteStyle", "medium"])
112155

113156
self.assertEqual(cs.name, "clone-suite")
114157
self.assertEqual(cs.args.directory, "test")
158+
self.assertEqual(cs.args.settingsWriteStyle, "medium")
115159

116160

117161
class TestCompareCases(unittest.TestCase):

armi/settings/caseSettings.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def initLogVerbosity(self):
352352

353353
self.setModuleVerbosities(force=True)
354354

355-
def writeToYamlFile(self, fName, style="short"):
355+
def writeToYamlFile(self, fName, style="short", fromFile=None):
356356
"""
357357
Write settings to a yaml file.
358358
@@ -366,11 +366,17 @@ def writeToYamlFile(self, fName, style="short"):
366366
the file to write to
367367
style : str (optional)
368368
the method of output to be used when creating the file for the current
369-
state of settings
369+
state of settings (short, medium, or full)
370+
fromFile : str (optional)
371+
if the source file and destination file are different (i.e. for cloning)
372+
and the style argument is ``medium``, then this arg is used
370373
"""
371374
self.path = pathTools.armiAbsPath(fName)
372375
if style == "medium":
373-
settingsSetByUser = self.getSettingsSetByUser(self.path)
376+
getSettingsPath = (
377+
self.path if fromFile is None else pathTools.armiAbsPath(fromFile)
378+
)
379+
settingsSetByUser = self.getSettingsSetByUser(getSettingsPath)
374380
else:
375381
settingsSetByUser = []
376382
with open(self.path, "w") as stream:

doc/release/0.2.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ What's new in ARMI
1111

1212
#. TBD
1313
#. Cleanup of stale ``coveragerc`` file (`PR#923 <https://github.com/terrapower/armi/pull/923>`_)
14-
#. Added writer style option to ``SettingsWriter`` and added it as arg to modify CLI (`PR#924 <https://github.com/terrapower/armi/pull/924>`_)
14+
#. Added `medium` writer style option to ``SettingsWriter``. Added it as arg to modify CLI (`PR#924 <https://github.com/terrapower/armi/pull/924>`_), and to clone CLI (`PR#932 <https://github.com/terrapower/armi/pull/932>`_).
1515
#. Update the EntryPoint class to provide user feedback on required positional arguments (`PR#922 <https://github.com/terrapower/armi/pull/922>`_)
1616

1717
Bug fixes

0 commit comments

Comments
 (0)