diff --git a/armi/physics/fuelCycle/__init__.py b/armi/physics/fuelCycle/__init__.py index fbfed6e9e..cce46b7e0 100644 --- a/armi/physics/fuelCycle/__init__.py +++ b/armi/physics/fuelCycle/__init__.py @@ -173,6 +173,17 @@ def defineSettingsValidators(inspector): Implementation of settings inspections for fuel cycle settings. """ queries = [] + + queries.append(settingsValidation.Query( + lambda: bool(inspector.cs["shuffleLogic"]) ^ + bool(inspector.cs["fuelHandlerName"]), + "A value was provided for `fuelHandlerName` or `shuffleLogic`, but not " + "the other. Either both `fuelHandlerName` and `shuffleLogic` should be " + "defined, or neither of them.", + "", + inspector.NO_ACTION, + )) + # Check for code fixes for input code on the fuel shuffling outside the version control of ARMI # These are basically auto-migrations for untracked code using # the ARMI API. (This may make sense at a higher level) diff --git a/armi/physics/fuelCycle/fuelHandlers.py b/armi/physics/fuelCycle/fuelHandlers.py index ac614ba7f..b6130e9af 100644 --- a/armi/physics/fuelCycle/fuelHandlers.py +++ b/armi/physics/fuelCycle/fuelHandlers.py @@ -224,7 +224,7 @@ def fuelHandlerFactory(operator): # User did request a custom fuel handler. We must go find and import it # from the input directory. - with directoryChangers.DirectoryChanger(cs.inputDirectory): + with directoryChangers.DirectoryChanger(cs.inputDirectory, dumpOnException=False): try: module = pathTools.importCustomPyModule(fuelHandlerModulePath) diff --git a/armi/utils/pathTools.py b/armi/utils/pathTools.py index 8a2d2b5da..32ac00d9b 100644 --- a/armi/utils/pathTools.py +++ b/armi/utils/pathTools.py @@ -163,18 +163,18 @@ def getModAndClassFromPath(path): def separateModuleAndAttribute(pathAttr): """ Return True of the specified python module, and attribute of the module exist. - - + + Parameters ---------- pathAttr : str Path to a python module followed by the desired attribute. e.g.: `/path/to/my/thing.py:MyClass` - + Notes ----- The attribute of the module could be a class, function, variable, etc. - + Raises ------ ValueError: @@ -190,17 +190,20 @@ def separateModuleAndAttribute(pathAttr): def importCustomPyModule(modulePath): """ Dynamically import a custom module. - + Parameters ---------- modulePath : str Path to a python module. - + Returns ------- userSpecifiedModule : module The imported python module. """ + modulePath = pathlib.Path(modulePath) + if not modulePath.exists() or not modulePath.is_file(): + raise IOError(r"Cannot import module from the given path: `{modulePath}`") _dir, moduleName = os.path.split(modulePath) moduleName = os.path.splitext(moduleName)[0] # take off the extension spec = importlib.util.spec_from_file_location(moduleName, modulePath) @@ -212,19 +215,19 @@ def importCustomPyModule(modulePath): def moduleAndAttributeExist(pathAttr): """ Return True if the specified python module, and attribute of the module exist. - - + + Parameters ---------- pathAttr : str Path to a python module followed by the desired attribute. e.g.: `/path/to/my/thing.py:MyClass` - - Returns + + Returns ------- - bool + bool True if the specified python module, and attribute of the module exist. - + Notes ----- The attribute of the module could be a class, function, variable, etc.