Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect and display error for duplicate reaction names (keys) - Issue #235 #241

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions src/acom_music_box/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ def main():
myBox = MusicBox()
logger.debug(f"Configuration file = {musicBoxConfigFile}")
myBox.readConditionsFromJson(musicBoxConfigFile)
myBox.check_config(os.path.join(os.getcwd(), musicBoxConfigFile))
carl-drews marked this conversation as resolved.
Show resolved Hide resolved

# Create solver and solve
config_path = os.path.join(
Expand Down
41 changes: 41 additions & 0 deletions src/acom_music_box/music_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,47 @@ def create_solver(
solver_type,
number_of_grid_cells)

def check_config(self, boxConfigPath):
"""
Verifies correct configuration of the MusicBox object.
There is intentionally no check for the presence of a solver;
this test function is for the loaded configuration only.

Args:
boxConfigPath = filename and path of MusicBox configuration file
This filename is supplied only for the error message;
the configuration should already be loaded.

Returns:
True if all checks passed
Throws error for the first check failed.
"""

# look for duplicate reaction names
if (self.initial_conditions):
if (self.initial_conditions.reaction_rates):
reactionNames = []
for rate in self.initial_conditions.reaction_rates:
# watch out for Nones in here
if not rate.reaction:
continue
if not rate.reaction.name:
continue
reactionNames.append(rate.reaction.name)

# look for name already seen
seen = set()
dupNames = [name for name in reactionNames if name in seen or seen.add(name)]

if (len(dupNames) > 0):
# inform user of the error and its remedy
errString = ("Error: Duplicate reaction names specified within {}: {}."
.format(boxConfigPath, dupNames))
errString += " Please remove or rename the duplicates."
raise Exception(errString)

return(True)

def solve(self, output_path=None, callback=None):
"""
Solves the box model simulation and optionally writes the output to a file.
Expand Down
42 changes: 42 additions & 0 deletions tests/integration/test_duplicate_reactions.py
carl-drews marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from acom_music_box import MusicBox, Reaction, ReactionRate, Conditions
from acom_music_box.reaction_list import ReactionList

import os
import csv
import math
carl-drews marked this conversation as resolved.
Show resolved Hide resolved


class TestDuplicateReactions:
def test_run(self):
# set up dummy reactions
abc123 = ReactionRate(Reaction("abc"), 12.3)
def456 = ReactionRate(Reaction("def"), 45.6)
abc789 = ReactionRate(Reaction("abc"), 78.9)

# Pass: unique reaction names
pass_reactions = [abc123, def456]
pass_conditions = Conditions(reaction_rates=pass_reactions)
box_model = MusicBox(initial_conditions=pass_conditions)
box_model.check_config("Loaded from string.")

# Pass test should throw an error above if it fails
assert True, f"All is good." # example of assertion
carl-drews marked this conversation as resolved.
Show resolved Hide resolved

# Fail: duplicate reaction names
fail_reactions = reactions=[abc123, abc789]
fail_conditions = Conditions(reaction_rates=fail_reactions)
box_model = MusicBox(initial_conditions=fail_conditions) # new instance

# catching the exception is a Pass for the duplicate case
caughtExcept = False
try:
box_model.check_config("Loaded from string.")
except Exception as myExcept:
caughtExcept = True
assert caughtExcept, f"Failed to detect duplicate reaction names."
carl-drews marked this conversation as resolved.
Show resolved Hide resolved


if __name__ == "__main__":
test = TestDuplicateReactions()
test.test_run()