From 22763cce3b24194f3401a67133a6e2ff36f44081 Mon Sep 17 00:00:00 2001 From: John Stilley Date: Wed, 19 Nov 2025 13:35:50 -0800 Subject: [PATCH] Formatting code in docstrings --- armi/bookkeeping/historyTracker.py | 6 +- armi/cases/__init__.py | 29 +- armi/cases/inputModifiers/inputModifiers.py | 4 +- armi/cases/suiteBuilder.py | 20 +- armi/interfaces.py | 79 ++- armi/nucDirectory/__init__.py | 10 +- armi/nucDirectory/elements.py | 8 +- armi/nucDirectory/nucDir.py | 18 +- armi/nucDirectory/nuclideBases.py | 19 +- armi/nuclearDataIO/cccc/compxs.py | 6 +- armi/nuclearDataIO/cccc/geodst.py | 2 +- armi/nuclearDataIO/cccc/isotxs.py | 10 +- armi/nuclearDataIO/xsLibraries.py | 6 +- armi/physics/fuelCycle/fuelHandlers.py | 8 +- .../fuelCycle/hexAssemblyFuelMgmtUtils.py | 8 +- .../lumpedFissionProduct.py | 2 +- armi/plugins.py | 457 ++++++++---------- armi/reactor/assemblies.py | 4 +- armi/reactor/blocks.py | 2 +- armi/reactor/composites.py | 3 +- armi/reactor/converters/geometryConverters.py | 4 +- armi/reactor/grids/cartesian.py | 10 +- armi/reactor/grids/locations.py | 4 +- armi/reactor/grids/structuredGrid.py | 2 +- .../parameters/parameterDefinitions.py | 1 + armi/utils/flags.py | 4 +- armi/utils/iterables.py | 23 +- armi/utils/outputCache.py | 4 +- armi/utils/plotting.py | 6 +- armi/utils/properties.py | 11 +- armi/utils/tabulate.py | 24 +- armi/utils/textProcessors.py | 16 +- pyproject.toml | 4 + 33 files changed, 361 insertions(+), 453 deletions(-) diff --git a/armi/bookkeeping/historyTracker.py b/armi/bookkeeping/historyTracker.py index 23d114ba9e..cf96d79aa9 100644 --- a/armi/bookkeeping/historyTracker.py +++ b/armi/bookkeeping/historyTracker.py @@ -46,12 +46,12 @@ become available. For example:: def getHistoryParams(self): - return ['flux', 'percentBu'] + return ["flux", "percentBu"] When you'd like to access history information, you need to grab the history interface. The history interfaces is present by default in your interface stack. To get it, just call:: - history = self.getInterface('history') + history = self.getInterface("history") Now you can do a few things, such as:: @@ -60,7 +60,7 @@ def getHistoryParams(self): timeStepsAvailable = history.getTimeIndices() # now go out and get some time-dependent block params: - fluxAtTimeStep3 = history.getBlockHistoryVal('B1003A', 'flux', 3) + fluxAtTimeStep3 = history.getBlockHistoryVal("B1003A", "flux", 3) Specifying blocks and assemblies to track ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/armi/cases/__init__.py b/armi/cases/__init__.py index 3c0c3b0b0a..678cb9aba8 100644 --- a/armi/cases/__init__.py +++ b/armi/cases/__init__.py @@ -15,18 +15,14 @@ """ Case and CaseSuite objects for running and analyzing ARMI cases. -A ``Case`` is a collection of inputs that represents one particular run. -Cases have special knowledge about dependencies and can perform useful -operations like compare, clone, and run. +A ``Case`` is a collection of inputs that represents one particular run. Cases have special knowledge about dependencies +and can perform useful operations like compare, clone, and run. -A ``CaseSuite`` is a set of (often related) Cases. These are fundamental to -parameter sweeps and test suites. +A ``CaseSuite`` is a set of (often related) Cases. These are fundamental to parameter sweeps and test suites. See Also -------- -armi.cli : Entry points that build Cases and/or CaseSuites and send them off to - do work - +armi.cli : Entry points that build Cases and/or CaseSuites and send them off to do work armi.operators : Operations that ARMI will perform on a reactor model. Generally these are made by an individual Case. @@ -34,29 +30,28 @@ -------- Create a Case and run it:: - case = Case(settings.Settings('path-to-settings.yaml')) + case = Case(settings.Settings("path-to-settings.yaml")) case.run() # do something with output database Create a case suite from existing files, and run the suite:: - cs = settings.Settings() # default settings - suite = CaseSuite(settings.Settings()) # default settings - suite.discover('my-cases*.yaml', recursive=True) + cs = settings.Settings() # default settings + suite = CaseSuite(settings.Settings()) # default settings + suite.discover("my-cases*.yaml", recursive=True) suite.run() .. warning:: Suite running may not work yet if the cases have interdependencies. Create a ``burnStep`` sensitivity study from some base CS:: - baseCase = Case(settings.Settings('base-settings.yaml')) # default settings - suite = CaseSuite(baseCase.cs) # basically just sets armiLocation + baseCase = Case(settings.Settings("base-settings.yaml")) # default settings + suite = CaseSuite(baseCase.cs) # basically just sets armiLocation for numSteps in range(3, 11): - with ForcedCreationDirectoryChanger('{}steps'.format(numSteps)): - case = baseCase.clone(title=baseCase.title + '-with{}steps'.format(numSteps), - settings={'burnSteps': numSteps}) + with ForcedCreationDirectoryChanger("{}steps".format(numSteps)): + case = baseCase.clone(title=baseCase.title + f"-with{numSteps}steps", settings={"burnSteps": numSteps}) suite.add(case) suite.writeInputs() diff --git a/armi/cases/inputModifiers/inputModifiers.py b/armi/cases/inputModifiers/inputModifiers.py index 95768b3448..4aabfd001d 100644 --- a/armi/cases/inputModifiers/inputModifiers.py +++ b/armi/cases/inputModifiers/inputModifiers.py @@ -135,9 +135,7 @@ class MultiSettingModifier(InputModifier): Examples -------- - >>> inputModifiers.MultiSettingModifier( - ... {CONF_NEUTRONICS_TYPE: "both", CONF_COARSE_MESH_REBALANCE: -1} - ... ) + >>> inputModifiers.MultiSettingModifier({CONF_NEUTRONICS_TYPE: "both", CONF_COARSE_MESH_REBALANCE: -1}) """ diff --git a/armi/cases/suiteBuilder.py b/armi/cases/suiteBuilder.py index ec0863856d..2126bfb1b7 100644 --- a/armi/cases/suiteBuilder.py +++ b/armi/cases/suiteBuilder.py @@ -198,7 +198,6 @@ def addDegreeOfFreedom(self, inputModifiers): For example:: class SettingModifier(InputModifier): - def __init__(self, settingName, value): self.settingName = settingName self.value = value @@ -207,9 +206,10 @@ def __call__(self, cs, bp): cs = cs.modified(newSettings={self.settingName: self.value}) return cs, bp + builder = FullFactorialSuiteBuilder(someCase) - builder.addDegreeOfFreedom(SettingModifier('settingName1', value) for value in (1,2)) - builder.addDegreeOfFreedom(SettingModifier('settingName2', value) for value in (3,4,5)) + builder.addDegreeOfFreedom(SettingModifier("settingName1", value) for value in (1, 2)) + builder.addDegreeOfFreedom(SettingModifier("settingName2", value) for value in (3, 4, 5)) would result in 6 cases: @@ -289,7 +289,6 @@ def addDegreeOfFreedom(self, inputModifiers): For example:: class SettingModifier(InputModifier): - def __init__(self, settingName, value): self.settingName = settingName self.value = value @@ -298,9 +297,10 @@ def __call__(self, cs, bp): cs = cs.modified(newSettings={self.settignName: self.value}) return cs, bp + builder = SeparateEffectsSuiteBuilder(someCase) - builder.addDegreeOfFreedom(SettingModifier('settingName1', value) for value in (1,2)) - builder.addDegreeOfFreedom(SettingModifier('settingName2', value) for value in (3,4,5)) + builder.addDegreeOfFreedom(SettingModifier("settingName1", value) for value in (1, 2)) + builder.addDegreeOfFreedom(SettingModifier("settingName2", value) for value in (3, 4, 5)) would result in 5 cases: @@ -356,17 +356,15 @@ def addDegreeOfFreedom(self, inputModifiers): For example:: class InputParameterModifier(SamplingInputModifier): - def __init__( self, name: str, - pararmType: str, # either 'continuous' or 'discrete' - bounds: Optional[Tuple, List] + pararmType: str, # either 'continuous' or 'discrete' + bounds: Optional[Tuple, List], ): super().__init__(name, paramType, bounds) - def __call__(self, cs, bp): - ... + def __call__(self, cs, bp): ... If the modifier is discrete then bounds specifies a list of options the values can take. If continuous, then bounds specifies a range of values. diff --git a/armi/interfaces.py b/armi/interfaces.py index a4c85e6d2b..dfe5c9b7a4 100644 --- a/armi/interfaces.py +++ b/armi/interfaces.py @@ -13,8 +13,8 @@ # limitations under the License. """ -Interfaces are objects of code that interact with ARMI. They read information off the state, -perform calculations (or run external codes), and then store the results back in the state. +Interfaces are objects of code that interact with ARMI. They read information off the state, perform calculations (or\ +run external codes), and then store the results back in the state. Learn all about interfaces in :doc:`/developer/guide` @@ -39,8 +39,8 @@ class STACK_ORDER: # noqa: N801 """ Constants that help determine the order of modules in the interface stack. - Each module defines an ``ORDER`` constant that specifies where in this order it should be placed - in the Interface Stack. + Each module defines an ``ORDER`` constant that specifies where in this order it should be placed in the Interface + Stack. .. impl:: Define an ordered list of interfaces. :id: I_ARMI_OPERATOR_INTERFACES0 @@ -155,8 +155,7 @@ def storePreviousIterationValue(self, val: _SUPPORTED_TYPES): def isConverged(self, val: _SUPPORTED_TYPES) -> bool: """ - Return boolean indicating if the convergence criteria between the current and previous - iteration values are met. + Return boolean indicating if the convergence criteria between the current and previous iteration values are met. Parameters ---------- @@ -182,15 +181,15 @@ def isConverged(self, val: _SUPPORTED_TYPES) -> bool: Raises ------ ValueError - If the previous iteration value has not been assigned. The - ``storePreviousIterationValue`` method must be called first. + If the previous iteration value has not been assigned. The ``storePreviousIterationValue`` method must be + called first. RuntimeError Only support calculating norms for up to 2D arrays. """ if self._previousIterationValue is None: raise ValueError( - f"Cannot check convergence of {self} with no previous iteration value set. " - "Set using `storePreviousIterationValue` first." + f"Cannot check convergence of {self} with no previous iteration value set. Set using " + "`storePreviousIterationValue` first." ) previous = self._previousIterationValue @@ -219,8 +218,8 @@ def isConverged(self, val: _SUPPORTED_TYPES) -> bool: self._numIters += 1 if self._numIters == self.maxIters: runLog.warning( - f"Maximum number of iterations for {self.parameter} reached without convergence!" - f"Prescribed convergence criteria is {self.tolerance}." + f"Maximum number of iterations for {self.parameter} reached without convergence! Prescribed " + f"convergence criteria is {self.tolerance}." ) self._numIters = 0 @@ -358,7 +357,7 @@ def preDistributeState(self): Examples -------- - >>> return {'neutronsPerFission',self.neutronsPerFission} + >>> return {"neutronsPerFission", self.neutronsPerFission} """ return {} @@ -386,20 +385,17 @@ def attachReactor(self, o, r): self.o = o def detachReactor(self): - """Delete the callbacks to reactor or operator. Useful when pickling, MPI sending, etc. to - save memory. - """ + """Delete the callbacks to reactor or operator. Useful when pickling, MPI sending, etc. to save memory.""" self.o = None self.r = None self.cs = None def duplicate(self): """ - Duplicate this interface without duplicating some of the large attributes (like the entire - reactor). + Duplicate this interface without duplicating some of the large attributes (like the entire reactor). - Makes a copy of interface with detached reactor/operator/settings so that it can be attached - to an operator at a later point in time. + Makes a copy of interface with detached reactor/operator/settings so that it can be attached to an operator at a + later point in time. Returns ------- @@ -502,13 +498,11 @@ def interactDistributeState(self): def interactRestart(self, startNode: Tuple[int, int], previousNode: Tuple[int, int]): """Perform any actions prior to simulating a restart. - Interfaces may want to restore some state that would have existed at the start of - ``startNode`` prior to calling :meth:`interactBOL` for the desired start point. - The database interface will be used prior to any interfaces calling this method, - so you can assume the reactor state has been correctly loaded from the database - from the ``previousNode``. This helps ensure that interfaces restart at e.g., - ``(cycle, node)=(4, 3)`` would see the same data compared to the nominal simulation - without a restart. + Interfaces may want to restore some state that would have existed at the start of ``startNode`` prior to calling + :meth:`interactBOL` for the desired start point. The database interface will be used prior to any interfaces + calling this method, so you can assume the reactor state has been correctly loaded from the database from the + ``previousNode``. This helps ensure that interfaces restart at e.g., ``(cycle, node)=(4, 3)`` would see the same + data compared to the nominal simulation without a restart. Parameters ---------- @@ -688,13 +682,11 @@ class OutputReader: Attributes ---------- success : bool - False by default, set to True if the run is considered - to have completed without error. + False by default, set to True if the run is considered to have completed without error. Notes ----- - Should ideally not require r, eci, and fname arguments and would rather just have an - apply(reactor) method. + Should ideally not require r, eci, and fname arguments and would rather just have an apply(reactor) method. """ def __init__(self, r=None, externalCodeInterface=None, fName=None, cs=None): @@ -723,10 +715,9 @@ def apply(self, reactor): """ Apply the output back to a reactor state. - This provides a generic interface for the output data of anything - to be applied to a reactor state. The application could involve - reading text or binary output or simply parameters to appropriate - values in some other data structure. + This provides a generic interface for the output data of anything to be applied to a reactor state. The + application could involve reading text or binary output or simply parameters to appropriate values in some other + data structure. """ raise NotImplementedError() @@ -739,10 +730,9 @@ def _setTightCouplerByInterfaceFunction(interfaceClass, cs): ---------- interfaceClass : Interface Interface class that a ``TightCoupler`` object will be added to. - cs : Settings - Case settings that are parsed to determine if tight coupling is enabled - globally and if both a target parameter and convergence criteria defined. + Case settings that are parsed to determine if tight coupling is enabled globally and if both a target parameter + and convergence criteria defined. """ # No tight coupling if there is no function for the Interface defined. if interfaceClass.function is None: @@ -762,12 +752,10 @@ def getActiveInterfaceInfo(cs): """ Return a list containing information for all of the Interface classes that are present. - This creates a list of tuples, each containing an Interface subclass and appropriate - kwargs for adding them to an Operator stack, given case settings. There should be - entries for all Interface classes that are returned from implementations of the - describeInterfaces() function in modules present in the passed list of packages. The - list is sorted by the ORDER specified by the module in which the specific Interfaces - are described. + This creates a list of tuples, each containing an Interface subclass and appropriate kwargs for adding them to an + Operator stack, given case settings. There should be entries for all Interface classes that are returned from + implementations of the describeInterfaces() function in modules present in the passed list of packages. The list is + sorted by the ORDER specified by the module in which the specific Interfaces are described. Parameters ---------- @@ -794,8 +782,7 @@ class InterfaceInfo(NamedTuple): Notes ----- - If kwargs is an empty dictionary, defaults from - ``armi.operators.operator.Operator.addInterface`` will be applied. + If kwargs is an empty dictionary, defaults from ``armi.operators.operator.Operator.addInterface`` will be applied. See Also -------- diff --git a/armi/nucDirectory/__init__.py b/armi/nucDirectory/__init__.py index 0204a94f5b..5576cc2902 100644 --- a/armi/nucDirectory/__init__.py +++ b/armi/nucDirectory/__init__.py @@ -120,16 +120,16 @@ may be extended as needed by end-users as needs arise. >>> r = Reactor("testReactor", bp) - >>> pu239 = r.nuclideBases.byName['PU239'] + >>> pu239 = r.nuclideBases.byName["PU239"] >>> pu239.z 94 Just like with elements, the item retrieved from the various dictionaries are the same object. - >>> tinFromName = r.nuclideBases.byName['SN112'] - >>> tinFromLabel = r.nuclideBases.byLabel['SN112'] - >>> tinFromMcc2Id = r.nuclideBases.byName['SN1125'] - >>> tinFromMcc3Id = r.nuclideBases.byLabel['SN1127'] + >>> tinFromName = r.nuclideBases.byName["SN112"] + >>> tinFromLabel = r.nuclideBases.byLabel["SN112"] + >>> tinFromMcc2Id = r.nuclideBases.byName["SN1125"] + >>> tinFromMcc3Id = r.nuclideBases.byLabel["SN1127"] >>> tinFromName == tinFromLabel == tinFromMcc2Id == tinFromMcc3Id True >>> id(tinFromName) == id(tinFromLabel) == id(tinFromMcc2Id) == id(tinFromMcc3Id) diff --git a/armi/nucDirectory/elements.py b/armi/nucDirectory/elements.py index 796de46639..e92cf11d81 100644 --- a/armi/nucDirectory/elements.py +++ b/armi/nucDirectory/elements.py @@ -451,7 +451,7 @@ def getName(self, z: int = None, symbol: str = None) -> str: -------- >>> elements.getName(10) 'Neon' - >>> elements.getName(symbol='Ne') + >>> elements.getName(symbol="Ne") 'Neon' """ element = None @@ -477,7 +477,7 @@ def getSymbol(self, z: int = None, name: str = None) -> str: -------- >>> elements.getSymbol(10) 'Ne' - >>> elements.getSymbol(name='Neon') + >>> elements.getSymbol(name="Neon") 'Ne' """ @@ -502,9 +502,9 @@ def getElementZ(self, symbol: str = None, name: str = None) -> int: Examples -------- - >>> elements.getZ('Zr') + >>> elements.getZ("Zr") 40 - >>> elements.getZ(name='Zirconium') + >>> elements.getZ(name="Zirconium") 40 Notes diff --git a/armi/nucDirectory/nucDir.py b/armi/nucDirectory/nucDir.py index 499df2989c..5d882c4d9e 100644 --- a/armi/nucDirectory/nucDir.py +++ b/armi/nucDirectory/nucDir.py @@ -132,13 +132,13 @@ def getMc2Label(name): Examples -------- - >>> nucDir.getMc2Label('U235') + >>> nucDir.getMc2Label("U235") 'U235' >> nucDir.getMc2Label('FE') 'FE' - >>> nucDir.getMc2Label('IRON') + >>> nucDir.getMc2Label("IRON") 'FE' - >>> nucDir.getMc2Label('AM242') + >>> nucDir.getMc2Label("AM242") A242 """ @@ -162,7 +162,7 @@ def getElementName(z=None, symbol=None): -------- >>> nucDir.getElementName(10) 'Neon' - >>> nucDir.getElementName(symbol='Zr') + >>> nucDir.getElementName(symbol="Zr") 'Neon' """ @@ -189,7 +189,7 @@ def getElementSymbol(z=None, name=None): -------- >>> nucDir.getElementSymbol(10) 'Ne' - >>> nucDir.getElementSymbol(name='Neon') + >>> nucDir.getElementSymbol(name="Neon") 'Ne' """ @@ -290,16 +290,16 @@ def getAtomicWeight(lab=None, z=None, a=None): Examples -------- >>> from armi.nucDirectory import nucDir - >>> nucDir.getAtomicWeight('U235') + >>> nucDir.getAtomicWeight("U235") 235.0439299 - >>> nucDir.getAtomicWeight('U239') + >>> nucDir.getAtomicWeight("U239") 239 - >>> nucDir.getAtomicWeight('U238') + >>> nucDir.getAtomicWeight("U238") 238.0507882 - >>> nucDir.getAtomicWeight(z=94,a=239) + >>> nucDir.getAtomicWeight(z=94, a=239) 239.0521634 """ if lab: diff --git a/armi/nucDirectory/nuclideBases.py b/armi/nucDirectory/nuclideBases.py index 1018754f57..5d31e0362c 100644 --- a/armi/nucDirectory/nuclideBases.py +++ b/armi/nucDirectory/nuclideBases.py @@ -60,30 +60,30 @@ Examples -------- >>> r = Reactor("ExampleReactor", bp) ->>> r.nuclideBases.byName['U235'] +>>> r.nuclideBases.byName["U235"] , HL:2.22160758861e+16, Abund:7.204000e-03> ->>> r.nuclideBases.byLabel['U235'] +>>> r.nuclideBases.byLabel["U235"] , HL:2.22160758861e+16, Abund:7.204000e-03> Retrieve U-235 by the MC2-2 ID: ->>> r.nuclideBases.byMcc2Id['U-2355'] +>>> r.nuclideBases.byMcc2Id["U-2355"] , HL:2.22160758861e+16, Abund:7.204000e-03> Retrieve U-235 by the MC2-3 ID: ->>> r.nuclideBases.byMcc3IdEndfVII0['U235_7'] +>>> r.nuclideBases.byMcc3IdEndfVII0["U235_7"] , HL:2.22160758861e+16, Abund:7.204000e-03> Retrieve U-235 by the MCNP ID: ->>> r.nuclideBases.byMcnpId['92235'] +>>> r.nuclideBases.byMcnpId["92235"] , HL:2.22160758861e+16, Abund:7.204000e-03> Retrieve U-235 by the AAAZZZS ID: ->>> r.nuclideBases.byAAAZZZSId['2350920'] +>>> r.nuclideBases.byAAAZZZSId["2350920"] , HL:2.22160758861e+16, Abund:7.204000e-03> Notes @@ -1320,13 +1320,14 @@ def where(self, predicate): -------- >>> from armi.nucDirectory.nuclideBases import NuclideBases >>> nuclideBases = NuclideBases() - >>> [nn.name for nn in nuclideBases.where(lambda nb: 'Z' in nb.name)] + >>> [nn.name for nn in nuclideBases.where(lambda nb: "Z" in nb.name)] ['ZN64', 'ZN66', 'ZN67', 'ZN68', 'ZN70', 'ZR90', 'ZR91', 'ZR92', 'ZR94', 'ZR96', 'ZR93', 'ZR95', 'ZR'] >>> # in order to get length, convert to list >>> isomers90 = list(nuclideBases.where(lambda nb: nb.a == 95)) >>> len(isomers90) 3 - >>> for iso in isomers: print(iso) + >>> for iso in isomers: + ... print(iso) @@ -1344,7 +1345,7 @@ def single(self, predicate): Examples -------- >>> from armi.nucDirectory import nuclideBases - >>> nuclideBases.single(lambda nb: nb.name == 'C') + >>> nuclideBases.single(lambda nb: nb.name == "C") >>> nuclideBases.single(lambda nb: nb.z == 95 and nb.a == 242 and nb.state == 1) diff --git a/armi/nuclearDataIO/cccc/compxs.py b/armi/nuclearDataIO/cccc/compxs.py index 78a1b7025b..8903679fd2 100644 --- a/armi/nuclearDataIO/cccc/compxs.py +++ b/armi/nuclearDataIO/cccc/compxs.py @@ -47,14 +47,14 @@ Examples -------- >>> from armi.nuclearDataIO import compxs - >>> lib = compxs.readBinary('COMPXS') + >>> lib = compxs.readBinary("COMPXS") >>> r0 = lib.regions[0] >>> r0.macros.fission # returns fission XS for this region >>> r0.macros.higherOrderScatter[1] # returns P1 scattering matrix >>> r0.macros.higherOrderScatter[5] *= 0 # zero out P5 scattering matrix - >>> compxs.writeBinary(lib, 'COMPXS2') + >>> compxs.writeBinary(lib, "COMPXS2") Notes ----- @@ -449,7 +449,7 @@ class CompxsRegion: Examples -------- - >>> lib = compxs.readBinary('COMPXS') + >>> lib = compxs.readBinary("COMPXS") >>> lib.regions diff --git a/armi/nuclearDataIO/cccc/geodst.py b/armi/nuclearDataIO/cccc/geodst.py index 3d465bc96e..b26d2fe6e6 100644 --- a/armi/nuclearDataIO/cccc/geodst.py +++ b/armi/nuclearDataIO/cccc/geodst.py @@ -24,7 +24,7 @@ -------- >>> geo = geodst.readBinary("GEODST") >>> print(geo.xmesh) ->>> geo.zmesh[-1]*=2 # make a modification to data +>>> geo.zmesh[-1] *= 2 # make a modification to data >>> geodst.writeBinary(geo, "GEODST2") """ diff --git a/armi/nuclearDataIO/cccc/isotxs.py b/armi/nuclearDataIO/cccc/isotxs.py index fc6bb96ea0..64272201f1 100644 --- a/armi/nuclearDataIO/cccc/isotxs.py +++ b/armi/nuclearDataIO/cccc/isotxs.py @@ -27,13 +27,13 @@ Examples -------- >>> from armi.nuclearDataIO.cccc import isotxs ->>> myLib = isotxs.readBinary('ISOTXS-ref') ->>> nuc = myLib.getNuclide('U235','AA') +>>> myLib = isotxs.readBinary("ISOTXS-ref") +>>> nuc = myLib.getNuclide("U235", "AA") >>> fis5 = nuc.micros.fission[5] ->>> scat = nuc.micros.scatter[(0, 5, 6, 1)] # 1st order elastic scatter from group 5->6 ->>> nuc.micros.fission[7] = fis5*1.01 # you can modify the isotxs too. +>>> scat = nuc.micros.scatter[(0, 5, 6, 1)] # 1st order elastic scatter from group 5->6 +>>> nuc.micros.fission[7] = fis5 * 1.01 # you can modify the isotxs too. >>> captureEnergy = nuc.isotxsMetadata["ecapt"] ->>> isotxs.writeBinary(myLib, 'ISOTXS-modified') +>>> isotxs.writeBinary(myLib, "ISOTXS-modified") """ diff --git a/armi/nuclearDataIO/xsLibraries.py b/armi/nuclearDataIO/xsLibraries.py index 9d46440fae..8128051299 100644 --- a/armi/nuclearDataIO/xsLibraries.py +++ b/armi/nuclearDataIO/xsLibraries.py @@ -332,9 +332,9 @@ class IsotxsLibrary(_XSLibrary): -------- >>> lib = xsLibraries.IsotxsLibrary() >>> # this doesn't have any information yet, we can read ISOTXS information - >>> libIsotxs = isotxs.readBinary('ISOAA') + >>> libIsotxs = isotxs.readBinary("ISOAA") >>> # any number of XSLibraries can be merged - >>> lib.merge(libIsotxs) # now the `lib` contains the ISOAA information. + >>> lib.merge(libIsotxs) # now the `lib` contains the ISOAA information. """ def __init__(self): @@ -600,7 +600,7 @@ class CompxsLibrary(_XSLibrary): Examples -------- - >>> lib = compxs.readBinary('COMPXS') + >>> lib = compxs.readBinary("COMPXS") >>> lib.regions """ diff --git a/armi/physics/fuelCycle/fuelHandlers.py b/armi/physics/fuelCycle/fuelHandlers.py index 931b14a98e..b4c9a98225 100644 --- a/armi/physics/fuelCycle/fuelHandlers.py +++ b/armi/physics/fuelCycle/fuelHandlers.py @@ -430,11 +430,9 @@ def findAssembly( This returns the feed fuel assembly in ring 4 that has a burnup closest to 100% (the highest burnup assembly):: - feed = self.findAssembly(targetRing=4, - width=(0,0), - param='maxPercentBu', - compareTo=100, - typeSpec=Flags.FEED | Flags.FUEL) + feed = self.findAssembly( + targetRing=4, width=(0, 0), param="maxPercentBu", compareTo=100, typeSpec=Flags.FEED | Flags.FUEL + ) """ # list for storing multiple results if findMany is true. diff --git a/armi/physics/fuelCycle/hexAssemblyFuelMgmtUtils.py b/armi/physics/fuelCycle/hexAssemblyFuelMgmtUtils.py index bfed454d54..ca5e1dd085 100644 --- a/armi/physics/fuelCycle/hexAssemblyFuelMgmtUtils.py +++ b/armi/physics/fuelCycle/hexAssemblyFuelMgmtUtils.py @@ -147,17 +147,17 @@ def buildRingSchedule( Jump ring behavior can be generalized by first building a base ring list where assemblies get charged to H and discharge from A:: - [A,B,C,D,E,F,G,H] + [A, B, C, D, E, F, G, H] If a jump should be placed where it jumps from ring G to C, reversed back to F, and then discharges from A, we simply reverse the sublist [C,D,E,F], leaving us with:: - [A,B,F,E,D,C,G,H] + [A, B, F, E, D, C, G, H] A less-complex, more standard convergent-divergent scheme is a subcase of this, where the sublist [A,B,C,D,E] or so is reversed, leaving:: - [E,D,C,B,A,F,G,H] + [E, D, C, B, A, F, G, H] So the task of this function is simply to determine what subsection, if any, to reverse of the baselist. @@ -193,7 +193,7 @@ def buildRingSchedule( Examples -------- - >>> f.buildRingSchedule(17,1,jumpRingFrom=14) + >>> f.buildRingSchedule(17, 1, jumpRingFrom=14) ([13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, 15, 16, 17], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) """ diff --git a/armi/physics/neutronics/fissionProductModel/lumpedFissionProduct.py b/armi/physics/neutronics/fissionProductModel/lumpedFissionProduct.py index bd67bb1b63..24f663e8c6 100644 --- a/armi/physics/neutronics/fissionProductModel/lumpedFissionProduct.py +++ b/armi/physics/neutronics/fissionProductModel/lumpedFissionProduct.py @@ -45,7 +45,7 @@ class LumpedFissionProduct: Examples -------- >>> fpd = FissionProductDefinitionFile(stream) - >>> lfp = fpd.createSingleLFPFromFile('LFP39') + >>> lfp = fpd.createSingleLFPFromFile("LFP39") >>> lfp[] 2.9773e-05 diff --git a/armi/plugins.py b/armi/plugins.py index e6e4a6ff37..543e917dd4 100644 --- a/armi/plugins.py +++ b/armi/plugins.py @@ -15,34 +15,28 @@ r""" Plugins allow various built-in or external functionality to be brought into the ARMI ecosystem. -This module defines the hooks that may be defined within plugins. Plugins are ultimately -incorporated into a :py:class:`armi.pluginManager.ArmiPluginManager`, which live inside -of a :py:class:`armi.apps.App` object. - -The ``ArmiPluginManager`` is derived from the ``PluginManager`` class provided by the -``pluggy`` package, which provides a registry of known plugins. Rather than create one -directly, we use the :py:func:`armi.plugins.getNewPluginManager()` function, which -handles some of the setup for us. - -From a high-altitude perspective, the plugins provide numerous "hooks", which allow for -ARMI to be extended in various ways. Some of these extensions are subtle and play a part -in how certain ARMI components are initialized or defined. As such, it is necessary to -register most plugins before some parts of ARMI are imported or exercised in a -meaningful way. These requirements are in flux, and will ultimately constitute part of -the specification of the ARMI plugin architecture. For now, to be safe, plugins should -be registered as soon as possible. - -After forming the ``PluginManager``, the plugin hooks can be accessed through the -``hook`` attribute. E.g.:: +This module defines the hooks that may be defined within plugins. Plugins are ultimately incorporated into a +:py:class:`armi.pluginManager.ArmiPluginManager`, which live inside of a :py:class:`armi.apps.App` object. + +The ``ArmiPluginManager`` is derived from the ``PluginManager`` class provided by the ``pluggy`` package, which provides +a registry of known plugins. Rather than create one directly, we use the :py:func:`armi.plugins.getNewPluginManager()` +function, which handles some of the setup for us. + +From a high-altitude perspective, the plugins provide numerous "hooks", which allow for ARMI to be extended in various +ways. Some of these extensions are subtle and play a part in how certain ARMI components are initialized or defined. As +such, it is necessary to register most plugins before some parts of ARMI are imported or exercised in a meaningful way. +These requirements are in flux, and will ultimately constitute part of the specification of the ARMI plugin +architecture. For now, to be safe, plugins should be registered as soon as possible. + +After forming the ``PluginManager``, the plugin hooks can be accessed through the ``hook`` attribute. E.g.:: >>> armi.getPluginManagerOrFail().hook.exposeInterfaces(cs=cs) -Don't forget to use the keyword argument form for all arguments to hooks; ``pluggy`` -requires them to enforce hook specifications. +Don't forget to use the keyword argument form for all arguments to hooks; ``pluggy`` requires them to enforce hook +specifications. -The :py:class:`armi.apps.App` class serves as the primary storage location of the -PluginManager, and also provides some methods to get data out of the plugins more -ergonomically than through the hooks themselves. +The :py:class:`armi.apps.App` class serves as the primary storage location of the PluginManager, and also provides some +methods to get data out of the plugins more ergonomically than through the hooks themselves. Some things you may want to bring in via a plugin includes: @@ -58,64 +52,53 @@ Warning ------- -The plugin system was developed to support improved collaboration. It is new and should -be considered under development. The API is subject to change as the version of the ARMI -framework approaches 1.0. +The plugin system was developed to support improved collaboration. It is new and should be considered under +development. The API is subject to change as the version of the ARMI framework approaches 1.0. Notes ----- -Due to the nature of some of these components, there are a couple of restrictions on -the order in which things can be imported (lest we endeavor to redesign them -considerably). Examples: - - - Parameters: All parameter definitions must be present before any ``ArmiObject`` - objects are instantiated. This is mostly by choice, but also makes the most sense, - because the ``ParameterCollection`` s are instance attributes of an ``ArmiObject``, - which in turn use ``Parameter`` objects as *class* attributes. We should know - what class attributes we have before making instances. - - - Blueprints: Since blueprints should be extendable with new sections, we must also - be able to provide new *class* attributes to extend their behavior. This is - because blueprints use the yamlize package, which uses class attributes to define - much of the class's behavior through metaclassing. Therefore, we need to be able - to import all plugins *before* importing blueprints. - -Plugins are currently stateless. They do not have ``__init__()`` methods, and when they are -registered with the PluginMagager, the PluginManager gets the Plugin's class object -rather than an instance of that class. Also notice that all of the hooks are -``@staticmethod``\ s. As a result, they can be called directly off of the class object, -and only have access to the state passed into them to perform their function. This is a -deliberate design choice to keep the plugin system simple and to preclude a large class -of potential bugs. At some point it may make sense to revisit this. +Due to the nature of some of these components, there are a couple of restrictions on the order in which things can be +imported (lest we endeavor to redesign them considerably). Examples: + + - Parameters: All parameter definitions must be present before any ``ArmiObject`` objects are instantiated. This is + mostly by choice, but also makes the most sense, because the ``ParameterCollection`` s are instance attributes of an + ``ArmiObject``, which in turn use ``Parameter`` objects as *class* attributes. We should know what class attributes + we have before making instances. + + - Blueprints: Since blueprints should be extendable with new sections, we must also be able to provide new *class* + attributes to extend their behavior. This is because blueprints use the yamlize package, which uses class attributes + to define much of the class's behavior through metaclassing. Therefore, we need to be able to import all plugins + *before* importing blueprints. + +Plugins are currently stateless. They do not have ``__init__()`` methods, and when they are registered with the +PluginMagager, the PluginManager gets the Plugin's class object rather than an instance of that class. Also notice that +all of the hooks are ``@staticmethod``\ s. As a result, they can be called directly off of the class object, and only +have access to the state passed into them to perform their function. This is a deliberate design choice to keep the +plugin system simple and to preclude a large class of potential bugs. At some point it may make sense to revisit this. **Other customization points** -While the Plugin API is the main place for ARMI framework customization, there are -several other areas where ARMI may be extended or customized. These typically pre-dated -the Plugin-based architecture, and as the need arise may be migrated to here. - - - Component types: Component types are registered dynamically through some metaclass - magic, found in :py:class:`armi.reactor.components.component.ComponentType` and - :py:class:`armi.reactor.composites.CompositeModelType`. Simply defining a new - Component subclass should register it with the appropriate ARMI systems. While this - is convenient, it does lead to potential issues, as the behavior of ARMI becomes - sensitive to module import order and the like; the containing module needs to be - imported before the registration occurs, which can be surprising. - - - Interface input files: Interfaces used to be discovered dynamically, rather than - explicitly as they are now in the :py:meth:`armi.plugins.ArmiPlugin.exposeInterfaces` - plugin hook. Essentially they functioned as ersatz plugins. One of the ways that they - would customize ARMI behavior is through the - :py:meth:`armi.physics.interface.Interface.specifyInputs` static method, which is - still used to determine inter-Case dependencies and support cloning and hashing Case - inputs. Going forward, this approach will likely be deprecated in favor of a plugin - hook. - - - Fuel handler logic: The - :py:class:`armi.physics.fuelCycle.fuelHandlers.FuelHandlerInterface` supports - customization through the dynamic loading of fuel handler logic modules, based on - user settings. This also predated the plugin infrastructure, and may one day be - replaced with plugin-based fuel handler logic. +While the Plugin API is the main place for ARMI framework customization, there are several other areas where ARMI may be +extended or customized. These typically pre-dated the Plugin-based architecture, and as the need arise may be migrated +to here. + + - Component types: Component types are registered dynamically through some metaclass magic, found in + :py:class:`armi.reactor.components.component.ComponentType` and + :py:class:`armi.reactor.composites.CompositeModelType`. Simply defining a new Component subclass should register + it with the appropriate ARMI systems. While this is convenient, it does lead to potential issues, as the behavior + of ARMI becomes sensitive to module import order and the like; the containing module needs to be imported before + the registration occurs, which can be surprising. + + - Interface input files: Interfaces used to be discovered dynamically, rather than explicitly as they are now in the + :py:meth:`armi.plugins.ArmiPlugin.exposeInterfaces` plugin hook. Essentially they functioned as ersatz plugins. + One of the ways that they would customize ARMI behavior is through the + :py:meth:`armi.physics.interface.Interface.specifyInputs` static method, which is still used to determine inter- + Case dependencies and support cloning and hashing Case inputs. Going forward, this approach will likely be + deprecated in favor of a plugin hook. + + - Fuel handler logic: The :py:class:`armi.physics.fuelCycle.fuelHandlers.FuelHandlerInterface` supports + customization through the dynamic loading of fuel handler logic modules, based on user settings. This also + predated the plugin infrastructure, and may one day be replaced with plugin-based fuel handler logic. """ @@ -137,22 +120,19 @@ class ArmiPlugin: """ - An ArmiPlugin exposes a collection of hooks that allow users to add a - variety of things to their ARMI application: Interfaces, parameters, - settings, flags, and much more. + An ArmiPlugin exposes a collection of hooks that allow users to add a variety of things to their ARMI application: + Interfaces, parameters, settings, flags, and much more. .. impl:: Plugins add code to the application through interfaces. :id: I_ARMI_PLUGIN :implements: R_ARMI_PLUGIN - Each plugin has the option of implementing the ``exposeInterfaces`` method, and - this will be used as a plugin hook to add one or more Interfaces to the ARMI - Application. Interfaces can wrap external executables with nuclear modeling - codes in them, or directly implement their logic in Python. But because - Interfaces are Python code, they have direct access to read and write from - ARMI's reactor data model. This Plugin to multiple Interfaces to reactor data - model connection is the primary way that developers add code to an ARMI - application and simulation. + Each plugin has the option of implementing the ``exposeInterfaces`` method, and this will be used as a plugin + hook to add one or more Interfaces to the ARMI Application. Interfaces can wrap external executables with + nuclear modeling codes in them, or directly implement their logic in Python. But because Interfaces are Python + code, they have direct access to read and write from ARMI's reactor data model. This Plugin to multiple + Interfaces to reactor data model connection is the primary way that developers add code to an ARMI application + and simulation. """ @staticmethod @@ -165,9 +145,8 @@ def exposeInterfaces(cs) -> List: :id: I_ARMI_PLUGIN_INTERFACES :implements: R_ARMI_PLUGIN_INTERFACES - This method takes in a Settings object and returns a list of Interfaces, - the position of each Interface in the Interface stack, and a list of - arguments to pass to the Interface when initializing it later. These + This method takes in a Settings object and returns a list of Interfaces, the position of each Interface in + the Interface stack, and a list of arguments to pass to the Interface when initializing it later. These Interfaces can then be used to add code to a simulation. Returns @@ -177,11 +156,9 @@ def exposeInterfaces(cs) -> List: - The insertion order to use when building an interface stack, - an implementation of the Interface class - - a dictionary of kwargs to pass to an Operator when adding an instance of - the interface class + - a dictionary of kwargs to pass to an Operator when adding an instance of the interface class - If no Interfaces should be active given the passed case settings, this should - return an empty list. + If no Interfaces should be active given the passed case settings, this should return an empty list. """ @staticmethod @@ -194,30 +171,27 @@ def defineParameters() -> Dict: :id: I_ARMI_PLUGIN_PARAMS :implements: R_ARMI_PLUGIN_PARAMS - Through this method, plugin developers can create new Parameters. A - parameter can represent any physical property an analyst might want to - track. And they can be added at any level of the reactor data model. - Through this, the developers can extend ARMI and what physical properties - of the reactor they want to calculate, track, and store to the database. + Through this method, plugin developers can create new Parameters. A parameter can represent any physical + property an analyst might want to track. And they can be added at any level of the reactor data model. + Through this, the developers can extend ARMI and what physical properties of the reactor they want to + calculate, track, and store to the database. .. impl:: Define an arbitrary physical parameter. :id: I_ARMI_PARAM0 :implements: R_ARMI_PARAM - Through this method, plugin developers can create new Parameters. A - parameter can represent any physical property an analyst might want to - track. For example, through this method, a plugin developer can add a new - thermodynamic property that adds a thermodynamic parameter to every block - in the reactor. Or they could add a neutronics parameter to every fuel - assembly. A parameter is quite generic. But these parameters will be - tracked in the reactor data model, extend what developers can do with ARMI, - and will be saved to the output database. + Through this method, plugin developers can create new Parameters. A parameter can represent any physical + property an analyst might want to track. For example, through this method, a plugin developer can add a new + thermodynamic property that adds a thermodynamic parameter to every block in the reactor. Or they could add + a neutronics parameter to every fuel assembly. A parameter is quite generic. But these parameters will be + tracked in the reactor data model, extend what developers can do with ARMI, and will be saved to the output + database. Returns ------- dict - Keys should be subclasses of ArmiObject, values being a ParameterDefinitionCollection - should be added to the key's parameter definitions. + Keys should be subclasses of ArmiObject, values being a ParameterDefinitionCollection should be added to the + key's parameter definitions. Example ------- @@ -225,16 +199,11 @@ def defineParameters() -> Dict: >>> with pluginBlockParams.createBuilder() as pb: ... pb.defParam("plugBlkP1", ...) ... # ... - ... >>> pluginAssemParams = parameters.ParameterDefinitionCollection() >>> with pluginAssemParams.createBuilder() as pb: ... pb.defParam("plugAsmP1", ...) ... # ... - ... - >>> return { - ... blocks.Block: pluginBlockParams, - ... assemblies.Assembly: pluginAssemParams - ... } + >>> return {blocks.Block: pluginBlockParams, assemblies.Assembly: pluginAssemParams} """ @staticmethod @@ -245,10 +214,8 @@ def afterConstructionOfAssemblies(assemblies, cs) -> None: This hook can be used to: - - Verify that all assemblies satisfy constraints imposed by active interfaces - and plugins - - Apply modifications to Assemblies based on modeling options and active - interfaces + - Verify that all assemblies satisfy constraints imposed by active interfaces and plugins + - Apply modifications to Assemblies based on modeling options and active interfaces Implementers may alter the state of the passed Assembly objects. @@ -263,8 +230,8 @@ def onProcessCoreLoading(core, cs, dbLoad) -> None: """ Function to call whenever a Core object is newly built. - This is usually used to set initial parameter values from inputs, either after - constructing a Core from Blueprints, or after loading it from a database. + This is usually used to set initial parameter values from inputs, either after constructing a Core from + Blueprints, or after loading it from a database. """ @staticmethod @@ -282,11 +249,9 @@ def defineFlags() -> Dict[str, Union[int, flags.auto]]: :id: I_ARMI_FLAG_EXTEND1 :implements: R_ARMI_FLAG_EXTEND - This method allows a plugin developers to provide novel values for - the Flags system. This method returns a dictionary mapping flag names - to their desired numerical values. In most cases, no specific value - is needed, one can be automatically generated using - :py:class:`armi.utils.flags.auto`. (For more information, see + This method allows a plugin developers to provide novel values for the Flags system. This method returns a + dictionary mapping flag names to their desired numerical values. In most cases, no specific value is needed, + one can be automatically generated using :py:class:`armi.utils.flags.auto`. (For more information, see :py:mod:`armi.reactor.flags`.) See Also @@ -296,9 +261,7 @@ def defineFlags() -> Dict[str, Union[int, flags.auto]]: Example ------- >>> def defineFlags(): - ... return { - ... "FANCY": armi.utils.flags.auto() - ... } + ... return {"FANCY": armi.utils.flags.auto()} """ @staticmethod @@ -307,10 +270,9 @@ def defineBlockTypes() -> List: """ Function for providing novel Block types from a plugin. - This should return a list of tuples containing ``(compType, blockType)``, where - ``blockType`` is a new ``Block`` subclass to register, and ``compType`` is the - corresponding ``Component`` type that should activate it. For instance a - ``HexBlock`` would be created when the largest component is a ``Hexagon``:: + This should return a list of tuples containing ``(compType, blockType)``, where ``blockType`` is a new ``Block`` + subclass to register, and ``compType`` is the corresponding ``Component`` type that should activate it. For + instance a ``HexBlock`` would be created when the largest component is a ``Hexagon``:: [(Hexagon, HexBlock)] @@ -326,10 +288,9 @@ def defineAssemblyTypes() -> List: """ Function for providing novel Assembly types from a plugin. - This should return a list of tuples containing ``(blockType, assemType)``, where - ``assemType`` is a new ``Assembly`` subclass to register, and ``blockType`` is - the corresponding ``Block`` subclass that, if present in the assembly, should - trigger it to be of the corresponding ``assemType``. + This should return a list of tuples containing ``(blockType, assemType)``, where ``assemType`` is a new + ``Assembly`` subclass to register, and ``blockType`` is the corresponding ``Block`` subclass that, if present in + the assembly, should trigger it to be of the corresponding ``assemType``. Warning ------- @@ -364,25 +325,21 @@ def defineBlueprintsSections() -> List: list (name, section, resolutionMethod) tuples, where: - - name : The name of the attribute to add to the Blueprints class; this - should be a valid Python identifier. + - name : The name of the attribute to add to the Blueprints class; this should be a valid Python identifier. - - section : An instance of ``yaml.Attribute`` defining the data that is - described by the Blueprints section. + - section : An instance of ``yaml.Attribute`` defining the data that is described by the Blueprints section. - - resolutionMethod : A callable that takes a Blueprints object and case - settings as arguments. This will be called like an unbound instance - method on the passed Blueprints object to initialize the state of the new + - resolutionMethod : A callable that takes a Blueprints object and case settings as arguments. This will be + called like an unbound instance method on the passed Blueprints object to initialize the state of the new Blueprints section. Notes ----- - Most of the sections that a plugin would want to add may be better served as - settings, rather than blueprints sections. These sections were added to the - blueprints mainly because the schema is more flexible, allowing namespaces and - hierarchical collections of settings. Perhaps in the near future it would make - sense to enhance the settings system to support these features, moving the - blueprints extensions out into settings. This is discussed in more detail in T1671. + Most of the sections that a plugin would want to add may be better served as settings, rather than blueprints + sections. These sections were added to the blueprints mainly because the schema is more flexible, allowing + namespaces and hierarchical collections of settings. Perhaps in the near future it would make sense to enhance + the settings system to support these features, moving the blueprints extensions out into settings. This is + discussed in more detail in T1671. """ @staticmethod @@ -391,8 +348,8 @@ def defineEntryPoints() -> List: """ Return new entry points for the ARMI CLI. - This hook allows plugins to provide their own ARMI entry points, which each - serve as a command in the command-line interface. + This hook allows plugins to provide their own ARMI entry points, which each serve as a command in the command- + line interface. Returns ------- @@ -410,17 +367,13 @@ def defineSettings() -> List: :id: I_ARMI_PLUGIN_SETTINGS :implements: R_ARMI_PLUGIN_SETTINGS - This hook allows plugin developers to provide their own configuration - settings, which can participate in the - :py:class:`armi.settings.caseSettings.Settings`. Plugins may provide - entirely new settings to what are already provided by ARMI, as well as - new options or default values for existing settings. For instance, the - framework provides a ``neutronicsKernel`` setting for selecting which - global physics solver to use. Since we wish to enforce that the user - specify a valid kernel, the settings validator will check to make sure - that the user's requested kernel is among the available options. If a - plugin were to provide a new neutronics kernel (let's say MCNP), it - should also define a new option to tell the settings system that + This hook allows plugin developers to provide their own configuration settings, which can participate in the + :py:class:`armi.settings.caseSettings.Settings`. Plugins may provide entirely new settings to what are + already provided by ARMI, as well as new options or default values for existing settings. For instance, the + framework provides a ``neutronicsKernel`` setting for selecting which global physics solver to use. Since we + wish to enforce that the user specify a valid kernel, the settings validator will check to make sure + that the user's requested kernel is among the available options. If a plugin were to provide a new + neutronics kernel (let's say MCNP), it should also define a new option to tell the settings system that ``"MCNP"`` is a valid option. Returns @@ -450,13 +403,11 @@ def defineSettingsValidators(inspector) -> List: Notes ----- - These are higher-level than the input-level SCHEMA defined - in :py:meth:`defineSettings` and are intended to be used for more - complex cross-plugin info. + These are higher-level than the input-level SCHEMA defined in :py:meth:`defineSettings` and are intended to be + used for more complex cross-plugin info. - We'd prefer to not manipulate objects passed in directly, but - rather have the inspection happen in a measurable hook. This - would help find misbehaving plugins. + We would prefer to not manipulate objects passed in directly, but rather have the inspection happen in a + measurable hook. This would help find misbehaving plugins. See Also -------- @@ -475,11 +426,10 @@ def defineCaseDependencies(case, suite): r""" Function for defining case dependencies. - Some Cases depend on the results of other ``Case``\ s in the same ``CaseSuite``. - Which dependencies exist, and how they are discovered depends entirely on the - type of analysis and active interfaces, etc. This function allows a plugin to - inspect settings and declare dependencies between the passed ``case`` and any - other cases in the passed ``suite``. + Some Cases depend on the results of other ``Case``\ s in the same ``CaseSuite``. Which dependencies exist, and + how they are discovered depends entirely on the type of analysis and active interfaces, etc. This function + allows a plugin to inspect settings and declare dependencies between the passed ``case`` and any other cases in + the passed ``suite``. Parameters ---------- @@ -491,9 +441,8 @@ def defineCaseDependencies(case, suite): Returns ------- dependencies : set of Cases - This should return a set containing ``Case`` objects that are considered - dependencies of the passed ``case``. They should be members of the passed - ``suite``. + This should return a set containing ``Case`` objects that are considered dependencies of the passed + ``case``. They should be members of the passed ``suite``. """ @staticmethod @@ -502,16 +451,14 @@ def defineGuiWidgets() -> List: """ Define which settings should go in the GUI. - Rather than making widgets here, this simply returns metadata - as a nested dictionary saying which tab to put which settings on, - and a little bit about how to group them. + Rather than making widgets here, this simply returns metadata as a nested dictionary saying which tab to put + which settings on, and a little bit about how to group them. Returns ------- widgetData : list of dict - Each dict is nested. First level contains the tab name (e.g. 'Global Flux'). - Second level contains a box name. Third level contains help and a - list of setting names + Each dict is nested. First level contains the tab name (e.g. 'Global Flux'). Second level contains a box + name. Third level contains help and a list of setting names See Also -------- @@ -543,42 +490,35 @@ def defineParameterRenames() -> Dict: """ Return a mapping from old parameter names to new parameter names. - Occasionally, it may become necessary to alter the name of an existing - parameter. This can lead to frustration when attempting to load from old - database files that use the previous name. This hook allows a plugin to define - mappings from the old name to the new name, allowing the old database to be read - in and translated to the new parameter name. + Occasionally, it may become necessary to alter the name of an existing parameter. This can lead to frustration + when attempting to load from old database files that use the previous name. This hook allows a plugin to define + mappings from the old name to the new name, allowing the old database to be read in and translated to the new + parameter name. The following rules are followed when applying these renames: - * When state is loaded from a database, if the parameter name in the database - file is found in the rename dictionary, it will be mapped to that renamed - parameter. - * If the renamed parameter is found in the renames, then it will be mapped again - to new parameter name. This process is repeated until there are no more - renames left. This allows for parameters to be renamed multiple times, and for - a database from several generations prior to still be readable, so long as the - history of renames is intact. - * If at the end of the above process, the parameter name is not a defined - parameter for the appropriate ``ArmiObject`` type, an exception is raised. - * If any of the ``renames`` keys match any currently-defined parameters, an - exception is raised. - * If any of the ``renames`` collide with another plugin's ``renames``, an - exception is raised. + * When state is loaded from a database, if the parameter name in the database file is found in the rename + dictionary, it will be mapped to that renamed parameter. + * If the renamed parameter is found in the renames, then it will be mapped again to new parameter name. This + process is repeated until there are no more renames left. This allows for parameters to be renamed multiple + times, and for a database from several generations prior to still be readable, so long as the history of + renames is intact. + * If at the end of the above process, the parameter name is not a defined parameter for the appropriate + ``ArmiObject`` type, an exception is raised. + * If any of the ``renames`` keys match any currently-defined parameters, an exception is raised. + * If any of the ``renames`` collide with another plugin's ``renames``, an exception is raised. Returns ------- renames : dict - Keys should be an old parameter name, where the corresponding values are - the new parameter name. + Keys should be an old parameter name, where the corresponding values are the new parameter name. Example ------- - The following would allow databases with values for either ``superOldParam`` or - ``oldParam`` to be read into ``currentParam``:: + The following would allow databases with values for either ``superOldParam`` or ``oldParam`` to be read into + ``currentParam``:: - return {"superOldParam": "oldParam", - "oldParam": "currentParam"} + return {"superOldParam": "oldParam", "oldParam": "currentParam"} """ @staticmethod @@ -587,10 +527,9 @@ def mpiActionRequiresReset(cmd) -> bool: """ Flag indicating when a reactor reset is required. - Commands are sent through operators either as strings (old) or as MpiActions (newer). - After some are sent, the reactor must be reset. This hook says when to reset. The - reset operation is a (arguably suboptimal) response to some memory issues in - very large and long-running cases. + Commands are sent through operators either as strings (old) or as MpiActions (newer). After some are sent, the + reactor must be reset. This hook says when to reset. The reset operation is a (arguably suboptimal) response to + some memory issues in very large and long-running cases. Parameters ---------- @@ -615,16 +554,11 @@ def getReportContents(r, cs, report, stage, blueprint) -> None: Parameters ---------- r : Reactor - cs : Settings - report : ReportContent Report object to add contents to - stage : ReportStage - begin/standard/or end (stage of the report for when inserting BOL vs. EOL - content) - + begin/standard/or end (stage of the report for when inserting BOL vs. EOL content) blueprint : Blueprint, optional for a reactor (if None, only partial contents created) """ @@ -656,8 +590,8 @@ def defineSystemBuilders() -> Dict[str, Callable[[str], "Composite"]]: Notes ----- - The default :class:`~armi.reactor.ReactorPlugin` defines a ``"core"`` lookup - and a ``"sfp"`` lookup, triggered to run after all other hooks have been run. + The default :class:`~armi.reactor.ReactorPlugin` defines a ``"core"`` lookup and a ``"sfp"`` lookup, triggered + to run after all other hooks have been run. """ @staticmethod @@ -665,14 +599,11 @@ def defineSystemBuilders() -> Dict[str, Callable[[str], "Composite"]]: def getAxialExpansionChanger() -> type["AxialExpansionChanger"]: """Produce the class responsible for performing axial expansion. - Plugins can provide this hook to override or negate axial expansion. - Will be used during initial construction of the core and assemblies, and - can be a class to perform custom axial expansion routines. + Plugins can provide this hook to override or negate axial expansion. Will be used during initial construction of + the core and assemblies, and can be a class to perform custom axial expansion routines. - The first object returned that is not ``None`` will be used. - Plugins are encouraged to add the ``tryfirst=True`` arguments to their - ``HOOKIMPL`` invocations to make sure their specific are earlier in the - hook call sequence. + The first object returned that is not ``None`` will be used. Plugins are encouraged to add the ``tryfirst=True`` + arguments to their ``HOOKIMPL`` invocations to make sure their specific are earlier in the hook call sequence. Returns ------- @@ -680,12 +611,12 @@ def getAxialExpansionChanger() -> type["AxialExpansionChanger"]: Notes ----- - This hook **should not** provide an instance of the class. The construction - of the changer will be handled by applications and plugins that need it. + This hook **should not** provide an instance of the class. The construction of the changer will be handled by + applications and plugins that need it. - This hook should only be provided by one additional plugin in your application. Otherwise - the `order of hook execution `_ - may not provide the behavior you expect. + This hook should only be provided by one additional plugin in your application. Otherwise the `order of hook + execution `_ may not provide the behavior + you expect. Examples -------- @@ -704,14 +635,14 @@ class UserPlugin(ArmiPlugin): """ A variation on the ArmiPlugin meant to be created at runtime, from the ``userPlugins`` setting. - This is obviously a more limited use-case than the usual ArmiPlugin, as those are meant - to be defined at import time, instead of run time. As such, this class has some built-in - tooling to limit how these run-time plugins are used. They are meant to be more limited. + This is obviously a more limited use-case than the usual ArmiPlugin, as those are meant to be defined at import + time, instead of run time. As such, this class has some built-in tooling to limit how these run-time plugins are + used. They are meant to be more limited. Notes ----- - The usual ArmiPlugin is much more flexible, if the UserPlugin does not support what - you want to do, just use an ArmiPlugin. + The usual ArmiPlugin is much more flexible, if the UserPlugin does not support what you want to do, just use an + ArmiPlugin. """ def __init__(self, *args, **kwargs): @@ -722,9 +653,8 @@ def __enforceLimitations(self): """ This method enforces that UserPlugins are more limited than regular ArmiPlugins. - UserPlugins are different from regular plugins in that they can be defined during - a run, and as such, we want to limit how flexible they are, so we can correctly - corral their side effects during a run. + UserPlugins are different from regular plugins in that they can be defined during a run, and as such, we want to + limit how flexible they are, so we can correctly corral their side effects during a run. """ if issubclass(self.__class__, UserPlugin): assert len(self.__class__.defineParameters()) == 0, ( @@ -736,8 +666,8 @@ def __enforceLimitations(self): assert len(self.__class__.defineSettings()) == 0, ( "UserPlugins cannot define new Settings, consider using an ArmiPlugin." ) - # NOTE: These are the methods that we are staunchly _not_ allowing people - # to change in this class. If you need these, please use a regular ArmiPlugin. + # NOTE: These are the methods that we are staunchly _not_ allowing people to change in this class. If you + # need these, please use a regular ArmiPlugin. self.defineParameterRenames = lambda: {} self.defineSettings = lambda: [] self.defineSettingsValidators = lambda: [] @@ -752,10 +682,9 @@ def defineParameters(): Notes ----- - It is a designed limitation of user plugins that they not define parameters. - Parameters are defined when the App() is read in, which is LONG before the settings - file has been read. So the parameters are defined before we discover the user plugin. - If this is a feature you need, just use an ArmiPlugin. + It is a designed limitation of user plugins that they not define parameters. Parameters are defined when the + App() is read in, which is LONG before the settings file has been read. So the parameters are defined before we + discover the user plugin. If this is a feature you need, just use an ArmiPlugin. """ return {} @@ -765,14 +694,15 @@ def defineParameterRenames(): """ Prevents parameter renames. - .. warning:: This is not overridable. + Warning + ------- + This is not overridable. Notes ----- - It is a designed limitation of user plugins that they not generate parameter renames, - Parameters are defined when the App() is read in, which is LONG before the settings - file has been read. So the parameters are defined before we discover the user plugin. - If this is a feature you need, just use a normal Plugin. + It is a designed limitation of user plugins that they not generate parameter renames, Parameters are defined + when the App() is read in, which is LONG before the settings file has been read. So the parameters are defined + before we discover the user plugin. If this is a feature you need, just use a normal Plugin. """ return {} @@ -782,12 +712,14 @@ def defineSettings(): """ Prevents new settings. - .. warning:: This is not overridable. + Warning + ------- + This is not overridable. Notes ----- - It is a designed limitation of user plugins that they not define new settings, - so that they are able to be added to the plugin stack during run time. + It is a designed limitation of user plugins that they not define new settings, so that they are able to be added + to the plugin stack during run time. """ return [] @@ -801,8 +733,8 @@ def defineSettingsValidators(inspector): Notes ----- - It is a designed limitation of user plugins that they not define new settings, - so that they are able to be added to the plugin stack during run time. + It is a designed limitation of user plugins that they not define new settings, so that they are able to be added + to the plugin stack during run time. """ return [] @@ -818,10 +750,9 @@ def collectInterfaceDescriptions(mod, cs): """ Adapt old-style ``describeInterfaces`` to the new plugin interface. - Old describeInterfaces implementations would return an interface class and kwargs - for adding to an operator. Now we expect an ORDER as well. This takes a module and - case settings and staples the module's ORDER attribute to the tuple and checks to - make sure that a None is replaced by an empty list. + Old describeInterfaces implementations would return an interface class and kwargs for adding to an operator. Now we + expect an ORDER as well. This takes a module and case settings and staples the module's ORDER attribute to the tuple + and checks to make sure that a None is replaced by an empty list. """ from armi import interfaces @@ -840,10 +771,8 @@ class PluginError(RuntimeError): """ Special exception class for use when a plugin appears to be non-conformant. - These should always come from some form of programmer error, and indicates - conditions such as: + These should always come from some form of programmer error, and indicates conditions such as: - A plugin improperly implementing a hook, when possible to detect. - - A collision between components provided by plugins (e.g. two plugins providing - the same Blueprints section) + - A collision between components provided by plugins (e.g. two plugins providing the same Blueprints section) """ diff --git a/armi/reactor/assemblies.py b/armi/reactor/assemblies.py index da581de663..4db9c92576 100644 --- a/armi/reactor/assemblies.py +++ b/armi/reactor/assemblies.py @@ -969,10 +969,10 @@ def getBlocksBetweenElevations(self, zLower, zUpper, eps=1e-10): Then, - >>> a.getBlocksBetweenElevations(0,50) + >>> a.getBlocksBetweenElevations(0, 50) [(Block1, 25.0), (Block2, 25.0)] - >>> a.getBlocksBetweenElevations(0,30) + >>> a.getBlocksBetweenElevations(0, 30) [(Block1, 25.0), (Block2, 5.0)] """ diff --git a/armi/reactor/blocks.py b/armi/reactor/blocks.py index d8f35c212f..e043de6779 100644 --- a/armi/reactor/blocks.py +++ b/armi/reactor/blocks.py @@ -1098,7 +1098,7 @@ def getDim(self, typeSpec, dimName): Examples -------- - >>> getDim(Flags.WIRE,'od') + >>> getDim(Flags.WIRE, "od") 0.01 """ for c in self: diff --git a/armi/reactor/composites.py b/armi/reactor/composites.py index 99039456f1..8eb42b89f7 100644 --- a/armi/reactor/composites.py +++ b/armi/reactor/composites.py @@ -757,8 +757,7 @@ def hasFlags(self, typeID: TypeSpec, exact=False): >>> obj.hasFlags(Flags.INNER | Flags.FUEL, exact=True) False - >>> obj.hasFlags([Flags.INNER | Flags.DRIVER | Flags.FUEL, - ... Flags.OUTER | Flags.DRIVER | Flags.FUEL], exact=True) + >>> obj.hasFlags([Flags.INNER | Flags.DRIVER | Flags.FUEL, Flags.OUTER | Flags.DRIVER | Flags.FUEL], exact=True) False """ diff --git a/armi/reactor/converters/geometryConverters.py b/armi/reactor/converters/geometryConverters.py index 2c718e2ca2..2133f1248b 100644 --- a/armi/reactor/converters/geometryConverters.py +++ b/armi/reactor/converters/geometryConverters.py @@ -112,9 +112,9 @@ class GeometryConverter(GeometryChanger): >>> HexToRZConverter(useMostCommonXsId=False, expandReactor=False) >>> geomConv.convert(r) >>> newR = geomConv.convReactor - >>> dif3d = dif3dInterface.Dif3dInterface('dif3dRZ', newR) + >>> dif3d = dif3dInterface.Dif3dInterface("dif3dRZ", newR) >>> dif3d.o = self.o - >>> dif3d.writeInput('rzGeom_actual.inp') + >>> dif3d.writeInput("rzGeom_actual.inp") """ def __init__(self, cs=None): diff --git a/armi/reactor/grids/cartesian.py b/armi/reactor/grids/cartesian.py index 94ee18a265..0678973831 100644 --- a/armi/reactor/grids/cartesian.py +++ b/armi/reactor/grids/cartesian.py @@ -33,9 +33,9 @@ class CartesianGrid(StructuredGrid): In Cartesian, (i, j, k) indices map to (x, y, z) coordinates. In an axial plane (i, j) are as follows:: - (-1, 1) ( 0, 1) ( 1, 1) - (-1, 0) ( 0, 0) ( 1, 0) - (-1,-1) ( 0,-1) ( 1,-1) + (-1, 1)(0, 1)(1, 1) + (-1, 0)(0, 0)(1, 0) + (-1, -1)(0, -1)(1, -1) The concepts of ring and position are a bit tricker in Cartesian grids than in Hex, because unlike in the Hex case, there is no guaranteed center location. For example, @@ -135,10 +135,10 @@ def getRingPos(self, indices): This is needed to support GUI, but should not often be used. i, j (0-based) indices are much more useful. For example: - >>> locator = core.spatialGrid[i, j, 0] # 3rd index is 0 for assembly + >>> locator = core.spatialGrid[i, j, 0] # 3rd index is 0 for assembly >>> a = core.childrenByLocator[locator] - >>> a = core.childrenByLocator[core.spatialGrid[i, j, 0]] # one liner + >>> a = core.childrenByLocator[core.spatialGrid[i, j, 0]] # one liner """ i, j = indices[0:2] split = self._isThroughCenter() diff --git a/armi/reactor/grids/locations.py b/armi/reactor/grids/locations.py index 220c30d61c..f6a5a73d9b 100644 --- a/armi/reactor/grids/locations.py +++ b/armi/reactor/grids/locations.py @@ -97,9 +97,9 @@ def __lt__(self, that: "LocationBase") -> bool: Examples -------- >>> grid = grids.HexGrid.fromPitch(1.0) - >>> grid[0, 0, 0] < grid[2, 3, 4] # the "radius" is less + >>> grid[0, 0, 0] < grid[2, 3, 4] # the "radius" is less True - >>> grid[2, 3, 4] < grid[2, 3, 4] # they are equal + >>> grid[2, 3, 4] < grid[2, 3, 4] # they are equal False >>> grid[2, 3, 4] < grid[-2, 3, 4] # 2 is greater than -2 False diff --git a/armi/reactor/grids/structuredGrid.py b/armi/reactor/grids/structuredGrid.py index f11233032a..403d7468d8 100644 --- a/armi/reactor/grids/structuredGrid.py +++ b/armi/reactor/grids/structuredGrid.py @@ -84,7 +84,7 @@ class StructuredGrid(Grid): -------- A 2D a rectangular grid with width (x) 2 and height (y) 3 would be:: - >>> grid = Grid(unitSteps=((2, 0, 0), (0, 3, 0),(0, 0, 0))) + >>> grid = Grid(unitSteps=((2, 0, 0), (0, 3, 0), (0, 0, 0))) A regular hex grid with pitch 1 is:: diff --git a/armi/reactor/parameters/parameterDefinitions.py b/armi/reactor/parameters/parameterDefinitions.py index b5c6567e6b..cea7203041 100644 --- a/armi/reactor/parameters/parameterDefinitions.py +++ b/armi/reactor/parameters/parameterDefinitions.py @@ -383,6 +383,7 @@ def setter(self, setter): -------- >>> class MyParameterCollection(parameters.ParameterCollection): ... mass = parameters.Parameter(...) + ... ... @mass.setter ... def mass(self, value): ... if value < 0: diff --git a/armi/utils/flags.py b/armi/utils/flags.py index 0acaa0f787..bfa72cfc7e 100644 --- a/armi/utils/flags.py +++ b/armi/utils/flags.py @@ -239,9 +239,7 @@ def extend(cls, fields: Dict[str, Union[int, auto]]): ... FOO = auto() ... BAR = 1 ... BAZ = auto() - >>> MyFlags.extend({ - ... "SUPER": auto() - ... }) + >>> MyFlags.extend({"SUPER": auto()}) >>> print(MyFlags.SUPER) """ diff --git a/armi/utils/iterables.py b/armi/utils/iterables.py index 8d3ad5e0ae..15d6ae1f78 100644 --- a/armi/utils/iterables.py +++ b/armi/utils/iterables.py @@ -25,7 +25,7 @@ def flatten(lst): Examples -------- - >>> flatten([[1,2,3,4],[5,6,7,8],[9,10]]) + >>> flatten([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]) [1,2,3,4,5,6,7,8,9,10] """ return [item for sublist in lst for item in sublist] @@ -39,7 +39,7 @@ def chunk(lst, n): Examples -------- - >>> list(chunk([1,2,3,4,5,6,7,8,9,10], 4)) + >>> list(chunk([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 4)) [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]] """ for i in range(0, len(lst), n): @@ -70,10 +70,10 @@ def split(a, n, padWith=()): Examples -------- - >>> split([1,2,3,4,5,6,7,8,9,10],4) + >>> split([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 4) [[1, 2, 3], [4, 5, 6], [7, 8], [9, 10]] - >>> split([0,1,2], 5, padWith=None) + >>> split([0, 1, 2], 5, padWith=None) [[0], [1], [2], None, None] """ a = list(a) # in case `a` is not list-like @@ -129,7 +129,7 @@ class Sequence: e.g. >>> s = Sequence(range(1000000)) - >>> tuple(s.drop(lambda i: i%2 == 0).select(lambda i: i < 20).transform(lambda i: i*10)) + >>> tuple(s.drop(lambda i: i % 2 == 0).select(lambda i: i < 20).transform(lambda i: i * 10)) (10, 30, 50, 70, 90, 110, 130, 150, 170, 190) This starts with a Sequence over 1 million elements (not stored in memory), @@ -141,11 +141,11 @@ class Sequence: drop, select, and transform act in-place, so the following is equivalent to the chained expression given above: >>> s = Sequence(range(1000000)) - >>> s.drop(lambda i: i%2 == 0) + >>> s.drop(lambda i: i % 2 == 0) >>> s.select(lambda i: i < 20) - >>> s.transform(lambda i: i*10) + >>> s.transform(lambda i: i * 10) >>> tuple(s) (10, 30, 50, 70, 90, 110, 130, 150, 170, 190) @@ -154,11 +154,10 @@ class Sequence: to use with infinite generators. For instance, the following will not work: >>> def counter(): - ... i = 0 - ... while True: - ... yield i - ... i += 1 - ... + ... i = 0 + ... while True: + ... yield i + ... i += 1 >>> s = Sequence(counter()).select(lambda i: i < 10) >>> tuple(s) # DON'T DO THIS! diff --git a/armi/utils/outputCache.py b/armi/utils/outputCache.py index 09ef72de0d..389a47ee41 100644 --- a/armi/utils/outputCache.py +++ b/armi/utils/outputCache.py @@ -24,8 +24,8 @@ --------- Getting a cached file:: - exe = 'MC2-2018-blah.exe' - inpFiles = ['mccAA.inp', 'rmzflx'] + exe = "MC2-2018-blah.exe" + inpFiles = ["mccAA.inp", "rmzflx"] outputFound = crc.retrieveOutput(exe, inp, output) if not outputFound: mc2.run(exe, inp, output) diff --git a/armi/utils/plotting.py b/armi/utils/plotting.py index 4bffce3605..38357b5ad9 100644 --- a/armi/utils/plotting.py +++ b/armi/utils/plotting.py @@ -1452,11 +1452,11 @@ def plotNucXs(isotxs, nucNames, xsNames, fName=None, label=None, noShow=False, t Examples -------- >>> l = ISOTXS() - >>> plotNucXs(l, 'U238NA','fission') + >>> plotNucXs(l, "U238NA", "fission") >>> # Plot n,g for all xenon and krypton isotopes - >>> f = lambda name: 'XE' in name or 'KR' in name - >>> plotNucXs(l, sorted(filter(f,l.nuclides.keys())),itertools.repeat('nGamma')) + >>> f = lambda name: "XE" in name or "KR" in name + >>> plotNucXs(l, sorted(filter(f, l.nuclides.keys())), itertools.repeat("nGamma")) See Also -------- diff --git a/armi/utils/properties.py b/armi/utils/properties.py index e6469162ca..008cead4dc 100644 --- a/armi/utils/properties.py +++ b/armi/utils/properties.py @@ -65,7 +65,8 @@ def createImmutableProperty(name, dependencyAction, doc): The following example is essentially exactly how this should be used. >>> class SomeClass: - ... myNum = createImmutableProperty('myNum', 'You must invoke the initialize() method', 'My random number') + ... myNum = createImmutableProperty("myNum", "You must invoke the initialize() method", "My random number") + ... ... def initialize(self, val): ... unlockImmutableProperties(self) ... try: @@ -75,15 +76,15 @@ def createImmutableProperty(name, dependencyAction, doc): >>> sc = SomeClass() >>> sc.myNum.__doc__ My Random Number - >>> sc.myNum # raises error, because it hasn't been assigned + >>> sc.myNum # raises error, because it hasn't been assigned ImmutablePropertyError >>> sc.myNum = 42.1 >>> sc.myNum 42.1 - >>> sc.myNum = 21.05 * 2 # raises error, because the value cannot change after it has been assigned. + >>> sc.myNum = 21.05 * 2 # raises error, because the value cannot change after it has been assigned. ImmutablePropertyError - >>> sc.initialize(42.1) # this works, because the values are the same. - >>> sc.initialize(100) # this fails, because the value cannot change + >>> sc.initialize(42.1) # this works, because the values are the same. + >>> sc.initialize(100) # this fails, because the value cannot change ImmutablePropertyError """ privateName = "_" + name diff --git a/armi/utils/tabulate.py b/armi/utils/tabulate.py index 2a4c7199c0..bd78b15815 100644 --- a/armi/utils/tabulate.py +++ b/armi/utils/tabulate.py @@ -579,9 +579,9 @@ def _type(string, hasInvisible=True, numparse=True): True >>> _type("1") is type(1) True - >>> _type('\x1b[31m42\x1b[0m') is type(42) + >>> _type("\x1b[31m42\x1b[0m") is type(42) True - >>> _type('\x1b[31m42\x1b[0m') is type(42) + >>> _type("\x1b[31m42\x1b[0m") is type(42) True """ @@ -639,7 +639,7 @@ def _afterpoint(string): def _padleft(width, s): r"""Flush right. - >>> _padleft(6, '\u044f\u0439\u0446\u0430') == ' \u044f\u0439\u0446\u0430' + >>> _padleft(6, "\u044f\u0439\u0446\u0430") == " \u044f\u0439\u0446\u0430" True """ @@ -650,7 +650,7 @@ def _padleft(width, s): def _padright(width, s): r"""Flush left. - >>> _padright(6, '\u044f\u0439\u0446\u0430') == '\u044f\u0439\u0446\u0430 ' + >>> _padright(6, "\u044f\u0439\u0446\u0430") == "\u044f\u0439\u0446\u0430 " True """ @@ -661,7 +661,7 @@ def _padright(width, s): def _padboth(width, s): r"""Center string. - >>> _padboth(6, '\u044f\u0439\u0446\u0430') == ' \u044f\u0439\u0446\u0430 ' + >>> _padboth(6, "\u044f\u0439\u0446\u0430") == " \u044f\u0439\u0446\u0430 " True """ @@ -679,10 +679,10 @@ def _stripAnsi(s): CSI sequences are simply removed from the output, while OSC hyperlinks are replaced with the link text. Note: it may be desirable to show the URI instead but this is not supported. - >>> repr(_stripAnsi('\x1B]8;;https://example.com\x1B\\This is a link\x1B]8;;\x1B\\')) + >>> repr(_stripAnsi("\x1b]8;;https://example.com\x1b\\This is a link\x1b]8;;\x1b\\")) "'This is a link'" - >>> repr(_stripAnsi('\x1b[31mred\x1b[0m text')) + >>> repr(_stripAnsi("\x1b[31mred\x1b[0m text")) "'red text'" """ @@ -695,7 +695,7 @@ def _stripAnsi(s): def _visibleWidth(s): r"""Visible width of a printed string. - >>> _visibleWidth('\x1b[31mhello\x1b[0m'), _visibleWidth("world") + >>> _visibleWidth("\x1b[31mhello\x1b[0m"), _visibleWidth("world") (5, 5) """ @@ -855,14 +855,14 @@ def _columnType(strings, hasInvisible=True, numparse=True): True >>> _columnType(["1", "2.3", "four"]) is str True - >>> _columnType(["four", '\u043f\u044f\u0442\u044c']) is str + >>> _columnType(["four", "\u043f\u044f\u0442\u044c"]) is str True >>> _columnType([None, "brux"]) is str True >>> _columnType([1, 2, None]) is int True >>> import datetime as dt - >>> _columnType([dt.datetime(1991,2,19), dt.time(17,35)]) is str + >>> _columnType([dt.datetime(1991, 2, 19), dt.time(17, 35)]) is str True """ @@ -1146,10 +1146,10 @@ def _toStr(s, encoding="utf8", errors="ignore"): 2. decode() is called for the given parameter and assumes utf8 encoding, but the default error behavior is changed from 'strict' to 'ignore' - >>> repr(_toStr(b'foo')) + >>> repr(_toStr(b"foo")) "'foo'" - >>> repr(_toStr('foo')) + >>> repr(_toStr("foo")) "'foo'" >>> repr(_toStr(42)) diff --git a/armi/utils/textProcessors.py b/armi/utils/textProcessors.py index 7fd27d5c3d..add4ca58be 100644 --- a/armi/utils/textProcessors.py +++ b/armi/utils/textProcessors.py @@ -269,12 +269,12 @@ class SequentialReader: always started with the same text followed by information, you could do something like this: - >>> with SequentialReader('somefile') as sr: + >>> with SequentialReader("somefile") as sr: ... data = [] - ... while sr.searchForText('start of data chunk'): + ... while sr.searchForText("start of data chunk"): ... # this needs to repeat for as many chunks as there are. - ... if sr.searchForPatternOnNextLine('some-(?P\w+)-pattern'): - ... data.append(sr.match['data']) + ... if sr.searchForPatternOnNextLine("some-(?P\w+)-pattern"): + ... data.append(sr.match["data"]) """ def __init__(self, filePath): @@ -488,12 +488,12 @@ class SequentialStringIOReader(SequentialReader): always started with the same text followed by information, you could do something like this: - >>> with SequentialReader('somefile') as sr: + >>> with SequentialReader("somefile") as sr: ... data = [] - ... while sr.searchForText('start of data chunk'): + ... while sr.searchForText("start of data chunk"): ... # this needs to repeat for as many chunks as there are. - ... if sr.searchForPatternOnNextLine('some-(?P\\w+)-pattern'): - ... data.append(sr.match['data']) + ... if sr.searchForPatternOnNextLine("some-(?P\\w+)-pattern"): + ... data.append(sr.match["data"]) """ def __init__(self, stringIO): diff --git a/pyproject.toml b/pyproject.toml index bc2467faea..b033ec3aad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -216,6 +216,10 @@ ban-relative-imports = "all" [tool.ruff.lint.pydocstyle] convention = "numpy" +[tool.ruff.format] +docstring-code-format = true +docstring-code-line-length = 120 + ####################################################################### # PYTEST CONFIG #