Skip to content

Commit

Permalink
Merge 2eca648 into c2d6c76
Browse files Browse the repository at this point in the history
  • Loading branch information
john-science authored Jul 26, 2022
2 parents c2d6c76 + 2eca648 commit 2e56b41
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 73 deletions.
21 changes: 6 additions & 15 deletions armi/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
from typing import Dict, Optional, Tuple, List
import collections
import importlib
import os
import sys

from armi import context, plugins, pluginManager, meta, settings
Expand Down Expand Up @@ -263,7 +262,7 @@ def registerUserPlugins(self, pluginPaths):
self.__initNewPlugins()

for pluginPath in pluginPaths:
if os.sep in pluginPath:
if ".py:" in pluginPath:
# The path is of the form: /path/to/why.py:MyPlugin
self.__registerUserPluginsAbsPath(pluginPath)
else:
Expand All @@ -274,19 +273,11 @@ def __registerUserPluginsAbsPath(self, pluginPath):
"""Helper method to register a single UserPlugin where
the given path is of the form: /path/to/why.py:MyPlugin
"""
# determine if this is a Windows system
isWindows = False
if os.name == "nt":
isWindows = True

# handle the minor variations on Windows file pathing
if isWindows:
assert pluginPath.count(":") == 2, f"Invalid plugin path: {pluginPath}"
drive, filePath, className = pluginPath.split(":")
filePath = drive + ":" + filePath
else:
assert pluginPath.count(":") == 1, f"Invalid plugin path: {pluginPath}"
filePath, className = pluginPath.split(":")
assert pluginPath.count(".py:") == 1, f"Invalid plugin path: {pluginPath}"

# split the settings string into file path and class name
filePath, className = pluginPath.split(".py:")
filePath += ".py"

spec = importlib.util.spec_from_file_location(className, filePath)
mod = importlib.util.module_from_spec(spec)
Expand Down
38 changes: 9 additions & 29 deletions armi/bookkeeping/tests/test_historyTracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
a valid HDF5 file to load from as a test fixtures. Thus they take a little longer
than usual.
"""
# pylint: disable=missing-function-docstring,missing-class-docstring,protected-access
import os
import pathlib
import shutil
import unittest

from armi import init as armi_init
from armi import settings
from armi import utils
from armi.bookkeeping import historyTracker
Expand All @@ -35,14 +35,15 @@
from armi.reactor import grids
from armi.reactor.flags import Flags
from armi.tests import ArmiTestHelper
from armi.utils import directoryChangers
from armi.utils.directoryChangers import TemporaryDirectoryChanger

CASE_TITLE = "anl-afci-177"
THIS_DIR = os.path.dirname(__file__) # b/c tests don't run in this folder
TUTORIAL_DIR = os.path.join(ROOT, "tests", "tutorials")


def runTutorialNotebook():
# pylint: disable=import-outside-toplevel
import nbformat
from nbconvert.preprocessors import ExecutePreprocessor

Expand All @@ -57,35 +58,14 @@ class TestHistoryTracker(ArmiTestHelper):

@classmethod
def setUpClass(cls):
# Not using a directory changer since it isn't important that we go back in the
# first place, and we don't want to get tangled with the directory change below.
# We need to be in the TUTORIAL_DIR in the first place so that for `filesToMove`
# to work right.
# We need to be in the TUTORIAL_DIR so that for `filesToMove` to work right.
os.chdir(TUTORIAL_DIR)

# Make sure to do this work in a temporary directory to avoid race conditions
# when running tests in parallel with xdist.
cls.dirChanger = directoryChangers.TemporaryDirectoryChanger(
filesToMove=TUTORIAL_FILES
)
# Do this work in a temp dir, to avoid race conditions.
cls.dirChanger = TemporaryDirectoryChanger(filesToMove=TUTORIAL_FILES)
cls.dirChanger.__enter__()
runTutorialNotebook()

reloadCs = settings.Settings(f"{CASE_TITLE}.yaml")

newSettings = {}
newSettings["db"] = True
newSettings["reloadDBName"] = pathlib.Path(f"{CASE_TITLE}.h5").absolute()
newSettings["runType"] = "Snapshots"
newSettings["loadStyle"] = "fromDB"
newSettings["detailAssemLocationsBOL"] = ["001-001"]

reloadCs = reloadCs.modified(newSettings=newSettings)
reloadCs.caseTitle = "armiRun"

o = armi_init(cs=reloadCs)
cls.o = o

@classmethod
def tearDownClass(cls):
cls.dirChanger.__exit__(None, None, None)
Expand All @@ -94,13 +74,13 @@ def setUp(self):
cs = settings.Settings(f"{CASE_TITLE}.yaml")
newSettings = {}
newSettings["db"] = True
newSettings["reloadDBName"] = pathlib.Path(f"{CASE_TITLE}.h5").absolute()
newSettings["loadStyle"] = "fromDB"
newSettings["detailAssemLocationsBOL"] = ["001-001"]
newSettings["loadStyle"] = "fromDB"
newSettings["reloadDBName"] = pathlib.Path(f"{CASE_TITLE}.h5").absolute()
newSettings["startNode"] = 1
cs = cs.modified(newSettings=newSettings)

self.td = directoryChangers.TemporaryDirectoryChanger()
self.td = TemporaryDirectoryChanger()
self.td.__enter__()

c = case.Case(cs)
Expand Down
2 changes: 1 addition & 1 deletion armi/operators/tests/test_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def test_interfaceIsActive(self):
self.assertTrue(o.interfaceIsActive("main"))
self.assertFalse(o.interfaceIsActive("Fake-o"))

def test_loadState(self):
def test_loadStateError(self):
"""The loadTestReactor() test tool does not have any history in the DB to load from"""
o, _r = test_reactors.loadTestReactor()

Expand Down
5 changes: 3 additions & 2 deletions armi/tests/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ def test_exposeInterfaces(self):
"""Make sure that the exposeInterfaces hook is properly implemented"""
if self.plugin is None:
return
if not hasattr(self.plugin, "exposeInterfaces"):
return

cs = settings.getMasterCs()
results = self.plugin.exposeInterfaces(cs)
if results is None or not results:
return

# each plugin should return a list
self.assertIsInstance(results, list)
for result in results:
Expand Down
17 changes: 13 additions & 4 deletions armi/tests/test_user_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,29 @@
from armi.utils import directoryChangers


HOOKSPEC = pluggy.HookspecMarker("armi")


class UserPluginFlags(plugins.UserPlugin):
"""Simple UserPlugin that defines a single, new flag."""

@staticmethod
@plugins.HOOKIMPL
def defineFlags():
return {"SPECIAL": utils.flags.auto()}


class UserPluginFlags2(plugins.UserPlugin):
"""Simple UserPlugin that defines a single, new flag."""

@staticmethod
@plugins.HOOKIMPL
def defineFlags():
return {"FLAG2": utils.flags.auto()}


class UserPluginFlags3(plugins.UserPlugin):
"""Simple UserPlugin that defines a single, new flag."""

@staticmethod
@plugins.HOOKIMPL
def defineFlags():
return {"FLAG3": utils.flags.auto()}

Expand All @@ -64,6 +67,8 @@ def defineFlags():
from armi import utils
class UserPluginFlags4(plugins.UserPlugin):
@staticmethod
@plugins.HOOKIMPL
def defineFlags():
return {"FLAG4": utils.flags.auto()}
"""
Expand All @@ -72,13 +77,17 @@ def defineFlags():
class UserPluginBadDefinesSettings(plugins.UserPlugin):
"""This is invalid/bad because it implements defineSettings()"""

@staticmethod
@plugins.HOOKIMPL
def defineSettings():
return [1, 2, 3]


class UserPluginBadDefineParameterRenames(plugins.UserPlugin):
"""This is invalid/bad because it implements defineParameterRenames()"""

@staticmethod
@plugins.HOOKIMPL
def defineParameterRenames():
return {"oldType": "type"}

Expand All @@ -91,7 +100,7 @@ class UserPluginOnProcessCoreLoading(plugins.UserPlugin):
"""

@staticmethod
@HOOKSPEC
@plugins.HOOKIMPL
def onProcessCoreLoading(core, cs):
blocks = core.getBlocks(Flags.FUEL)
for b in blocks:
Expand Down
15 changes: 1 addition & 14 deletions armi/utils/pathTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,7 @@ def isAccessible(path):
path : str
a directory or file
"""
if os.path.exists(path):
# This can potentially return a false positive in Python 2 if the path
# exists but the user does not have access. As a workaround, we attempt
# to list the contents of the containing directory, which will throw an
# OSError if the user doesn't have access.
try:
if not os.path.isdir(path):
path = os.path.dirname(path)
os.listdir(path)
return True
except OSError:
return False
else:
return False
return os.path.exists(path)


def separateModuleAndAttribute(pathAttr):
Expand Down
24 changes: 24 additions & 0 deletions armi/utils/tests/test_pathTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"""
# pylint: disable=missing-function-docstring,missing-class-docstring,abstract-method,protected-access,no-member,disallowed-name,invalid-name
import os
import time
import types
import unittest

Expand Down Expand Up @@ -120,6 +121,29 @@ def test_cleanPathNoMpi(self):
context.waitAll()
self.assertFalse(os.path.exists(dir3))

def test_isFilePathNewer(self):
with TemporaryDirectoryChanger():
path1 = "test_isFilePathNewer1.txt"
with open(path1, "w") as f1:
f1.write("test1")

time.sleep(1)

path2 = "test_isFilePathNewer2.txt"
with open(path2, "w") as f2:
f2.write("test2")

self.assertFalse(pathTools.isFilePathNewer(path1, path2))
self.assertTrue(pathTools.isFilePathNewer(path2, path1))

def test_isAccessible(self):
with TemporaryDirectoryChanger():
path1 = "test_isAccessible.txt"
with open(path1, "w") as f1:
f1.write("test")

self.assertTrue(pathTools.isAccessible(path1))


if __name__ == "__main__":
unittest.main()
14 changes: 6 additions & 8 deletions doc/tutorials/making_your_first_app.rst
Original file line number Diff line number Diff line change
Expand Up @@ -392,17 +392,15 @@ This can be done by sublassing :py:class:`armi.plugins.UserPlugin`:
class UserPluginExample(plugins.UserPlugin):
"""
This plugin flex-tests the onProcessCoreLoading() hook,
and arbitrarily adds "1" to the height of every block,
after the DB is loaded.
This plugin flex-tests the onProcessCoreLoading() hook, and
arbitrarily adds "1" to the power ever each fuel block.
"""
@staticmethod
@HOOKSPEC
@plugins.HOOKIMPL
def onProcessCoreLoading(core, cs):
blocks = core.getBlocks(Flags.FUEL)
for b in blocks:
b.p.height += 1.0
for b in core.getBlocks(Flags.FUEL):
b.p.power += 1.0
In most ways, ``UserPluginExample`` above is just a normal
:py:class:`ArmiPlugin <armi.plugins.ArmiPlugin>`. You can implement any of the normal
Expand All @@ -424,7 +422,7 @@ file:

.. code-block::
userPlugins::
userPlugins:
- armi.tests.test_user_plugins.UserPlugin0
- //path/to/my/pluginz.py:UserPlugin1
- C:\\path\to\my\pluginZ.py:UserPlugin2
Expand Down

0 comments on commit 2e56b41

Please sign in to comment.