Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/terrapower/armi into main
Browse files Browse the repository at this point in the history
  • Loading branch information
AidanMcDonald committed Feb 6, 2024
2 parents 06bb2e3 + 571e4f5 commit 75b3700
Show file tree
Hide file tree
Showing 269 changed files with 9,995 additions and 5,094 deletions.
12 changes: 5 additions & 7 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,18 @@
<!-- MANDATORY: Explain why the change is necessary -->
<!-- Optional: Link to any related GitHub Issues -->



---

## Checklist

<!--
You (the pull requester) should put an `x` in the boxes below you have completed.
If you're unsure about any of them, don't hesitate to ask. We're here to help!
Learn what a "good PR" looks like here:
https://terrapower.github.io/armi/developer/tooling.html#good-pull-requests
(If a checkbox requires no action for this PR, put an `x` in the box.)
-->

- [ ] This PR has only one purpose or idea.
- [ ] Tests have been added/updated to verify that the new/changed code works.
- [ ] This PR has only [one purpose or idea](https://terrapower.github.io/armi/developer/tooling.html#one-idea-one-pr).
- [ ] [Tests](https://terrapower.github.io/armi/developer/tooling.html#test-it) have been added/updated to verify that the new/changed code works.

<!-- Check the code quality -->

Expand All @@ -31,5 +28,6 @@
<!-- Check the project-level cruft -->

- [ ] The [release notes](https://terrapower.github.io/armi/release/index.html) (location `doc/release/0.X.rst`) are up-to-date with any important changes.
- [ ] The documentation is still up-to-date in the `doc` folder.
- [ ] The [documentation](https://terrapower.github.io/armi/developer/tooling.html#document-it) is still up-to-date in the `doc` folder.
- [ ] If any [requirements](https://terrapower.github.io/armi/developer/tooling.html#watch-for-requirements) were affected, mention it in the [release notes](https://terrapower.github.io/armi/release/index.html).
- [ ] The dependencies are still up-to-date in `pyproject.toml`.
8 changes: 6 additions & 2 deletions .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ on:
push:
branches:
- main
paths-ignore:
- 'doc/**'
pull_request:
paths-ignore:
- 'doc/**'

jobs:
build:
Expand All @@ -25,9 +29,9 @@ jobs:
- name: Install Tox and any other packages
run: pip install tox
- name: Run Coverage Part 1
run: tox -e cov1 || true
run: tox -e cov1
- name: Run Coverage Part 2
run: tox -e cov2
run: tox -e cov2 || true
- name: Publish to coveralls.io
uses: coverallsapp/[email protected]
with:
Expand Down
53 changes: 53 additions & 0 deletions .github/workflows/find_test_crumbs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright 2024 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This script exists so we can determine if new tests in CI are leaving crumbs."""

import subprocess

# A list of objects we expect during a run, and don't mind (like pycache dirs).
IGNORED_OBJECTS = [
".pytest_cache",
".tox",
"__pycache__",
"armi.egg-info",
"armi/logs/ARMI.armiRun.",
"armi/logs/armiRun.mpi.log",
"armi/tests/tutorials/case-suite/",
"armi/tests/tutorials/logs/",
]


def main():
# use "git clean" to find all non-tracked files
proc = subprocess.Popen(["git", "clean", "-xnd"], stdout=subprocess.PIPE)
lines = proc.communicate()[0].decode("utf-8").split("\n")

# clean up the whitespace
lines = [ln.strip() for ln in lines if len(ln.strip())]

# ignore certain untracked object, like __pycache__ dirs
for ignore in IGNORED_OBJECTS:
lines = [ln for ln in lines if ignore not in ln]

# fail hard if there are still untracked files
if len(lines):
for line in lines:
print(line)

raise ValueError("The workspace is dirty; the tests are leaving crumbs!")


if __name__ == "__main__":
main()
1 change: 0 additions & 1 deletion .github/workflows/linting.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,4 @@ jobs:
- name: Install Tox and any other packages
run: pip install tox
- name: Run Linter
continue-on-error: true
run: tox -e lint
8 changes: 7 additions & 1 deletion .github/workflows/unittests.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
name: ARMI unit tests

on: [push, pull_request]
on:
push:
paths-ignore:
- 'doc/**'
pull_request:
paths-ignore:
- 'doc/**'

jobs:
build:
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/wintests.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
name: ARMI Windows tests

on: [push, pull_request]
on:
push:
paths-ignore:
- 'doc/**'
pull_request:
paths-ignore:
- 'doc/**'

jobs:
build:
Expand All @@ -19,3 +25,5 @@ jobs:
run: python -m pip install tox tox-gh-actions
- name: Run Tox
run: tox -e test
- name: Find Test Crumbs
run: python .github/workflows/find_test_crumbs.py
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pytestdebug.log
dump-temp-*
dump-tests*
.vim-bookmarks
armi-venv/*
venv*/
.mypy_cache/
**/__pycache__
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ The ARMI system is licensed as follows:

.. code-block:: none
Copyright 2009-2023 TerraPower, LLC
Copyright 2009-2024 TerraPower, LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
27 changes: 20 additions & 7 deletions armi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2009-2019 TerraPower, LLC
# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -118,22 +118,35 @@ def init(choice=None, fName=None, cs=None):
"""
Scan a directory for armi inputs and load one to interact with.
.. impl:: Settings are used to define an ARMI run.
:id: I_ARMI_SETTING1
:implements: R_ARMI_SETTING
This method initializes an ARMI run, and if successful returns an Operator.
That operator is designed to drive the reactor simulation through time steps to
simulate its operation. This method takes in a settings file or object to
initialize the operator. Whether a settings file or object is supplied, the
operator will be built based on the those settings. Because the total
collection of settings can be modified by developers of ARMI applications,
providing these settings allow ARMI end-users to define their simulation as
granularly as they need.
Parameters
----------
choice : int, optional
Automatically run with this item out of the menu
that would be produced of existing xml files.
Automatically run with this item out of the menu that would be produced by the
existing YAML files.
fName : str, optional
An actual case name to load. e.g. ntTwr1.xml
The path to a settings file to load: my_case.yaml
cs : object, optional
If supplied, supercede the other case input methods and use the object directly
cs : Settings, optional
If supplied, this CS object will supercede the other case input methods and use
the object directly.
Examples
--------
>>> o = armi.init()
"""
from armi import cases
from armi import settings
Expand Down
15 changes: 5 additions & 10 deletions armi/_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Collection of code that needs to be executed before most ARMI components are safe to
import.
"""
"""Code that needs to be executed before most ARMI components are safe to import."""

import sys
import tabulate

# This needs to happen pretty darn early, as one of it's purposes is to provide a better
# python version warning than "invalid syntax". Maybe this is enough of a crutch that we
# should get rid of it...
# This is a courtesy, to help people who accidently run ARMI with an old version of Python.
if (
sys.version_info.major < 3
or sys.version_info.major == 3
and sys.version_info.minor < 6
and sys.version_info.minor < 7
):
raise RuntimeError(
"ARMI highly recommends using Python 3.7. Are you sure you are using the correct "
"interpreter?\nUsing: {}".format(sys.executable)
"ARMI highly recommends using Python 3.9 or 3.11. Are you sure you are using the "
f"correct interpreter?\nYou are using: {sys.executable}"
)


Expand Down
65 changes: 43 additions & 22 deletions armi/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
Framework for a specific application. An ``App`` implements a simple interface for
customizing much of the Framework's behavior.
.. admonition:: Historical Fun Fact
This pattern is used by many frameworks as a way of encapsulating what would
otherwise be global state. The ARMI Framework has historically made heavy use of
global state (e.g., :py:mod:`armi.nucDirectory.nuclideBases`), and it will take
quite a bit of effort to refactor the code to access such things through an App
object. We are planning to do this, but for now this App class is somewhat
rudimentary.
Notes
-----
Historical Fun Fact
This pattern is used by many frameworks as a way of encapsulating what would otherwise be global
state. The ARMI Framework has historically made heavy use of global state (e.g.,
:py:mod:`armi.nucDirectory.nuclideBases`), and it will take quite a bit of effort to refactor the
code to access such things through an App object.
"""
# ruff: noqa: E402
from typing import Dict, Optional, Tuple, List
Expand All @@ -43,19 +43,23 @@

class App:
"""
The main point of customization for the ARMI Framework.
The App class is intended to be subclassed in order to customize the functionality
and look-and-feel of the ARMI Framework for a specific use case. An App contains a
plugin manager, which should be populated in ``__init__()`` with a collection of
plugins that are deemed suitable for a given application, as well as other methods
which provide further customization.
The base App class is also a good place to expose some more convenient ways to get
data out of the Plugin API; calling the ``pluggy`` hooks directly can sometimes be a
pain, as the results returned by the individual plugins may need to be merged and/or
checked for errors. Adding that logic here reduces boilerplate throughout the rest
of the code.
The highest-level of abstraction for defining what happens during an ARMI run.
.. impl:: An App has a plugin manager.
:id: I_ARMI_APP_PLUGINS
:implements: R_ARMI_APP_PLUGINS
The App class is intended to be subclassed in order to customize the functionality
and look-and-feel of the ARMI Framework for a specific use case. An App contains a
plugin manager, which should be populated in ``__init__()`` with a collection of
plugins that are deemed suitable for a given application, as well as other methods
which provide further customization.
The base App class is also a good place to expose some more convenient ways to get
data out of the Plugin API; calling the ``pluggy`` hooks directly can sometimes be a
pain, as the results returned by the individual plugins may need to be merged and/or
checked for errors. Adding that logic here reduces boilerplate throughout the rest
of the code.
"""

name = "armi"
Expand Down Expand Up @@ -121,7 +125,24 @@ def pluginManager(self) -> pluginManager.ArmiPluginManager:
return self._pm

def getSettings(self) -> Dict[str, Setting]:
"""Return a dictionary containing all Settings defined by the framework and all plugins."""
"""
Return a dictionary containing all Settings defined by the framework and all plugins.
.. impl:: Applications will not allow duplicate settings.
:id: I_ARMI_SETTINGS_UNIQUE
:implements: R_ARMI_SETTINGS_UNIQUE
Each ARMI application includes a collection of Plugins. Among other
things, these plugins can register new settings in addition to
the default settings that come with ARMI. This feature provides a
lot of utility, so application developers can easily configure
their ARMI appliction in customizable ways.
However, it would get confusing if two different plugins registered
a setting with the same name string. Or if a plugin registered a
setting with the same name as an ARMI default setting. So this
method throws an error if such a situation arises.
"""
# Start with framework settings
settingDefs = {
setting.name: setting for setting in fwSettings.getFrameworkSettings()
Expand Down
Loading

0 comments on commit 75b3700

Please sign in to comment.