Skip to content

Commit

Permalink
Merge pull request #7 from pmslavin/sk_fixes
Browse files Browse the repository at this point in the history
Functions to manage reference recorders and inline recorders.
  • Loading branch information
pmslavin authored Mar 18, 2024
2 parents 2c30b60 + d0f4fdf commit 985b9d3
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 1 deletion.
2 changes: 1 addition & 1 deletion pywrparser/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def configure_args(args):


def handle_args(args):

filename = args.filename
raise_error = args.raise_on_error
raise_warning = args.raise_on_warning
Expand Down Expand Up @@ -171,7 +172,6 @@ def handle_args(args):
network.add_recorder_references()
network.promote_inline_parameters()
network.attach_reference_parameters()
network.detach_parameters()
if args.terse_report:
report = network.report()
console.print(report)
Expand Down
62 changes: 62 additions & 0 deletions pywrparser/types/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,31 @@ def promote_inline_parameters(self):
param = PywrParameter(param_name, value)
node.data[attr] = param

def promote_inline_recorders(self):
"""
Promotes inline recorder definitions to instances of
:class:`PywrRecorder`.
Any values of attrs in a node which can be interpreted as
an inline (i.e. dict) recorder definition are instantiated
as recorders and the attr value replaced with the instance.
"""
exclude = ("name", "type")
for node in self.nodes.values():
for attr, value in node.data.items():
if isinstance(value, dict):
type_key = value.get("type")
if not type_key or "parameter" in type_key.lower():
continue
rec_name = value.get("name")
if not rec_name or rec_name in self.recorders:
rec_name = canonical_name(node.name, attr)
log.debug(f"Creating inline recorder: {rec_name}")
if rec_name in self.recorders:
# Node inline recorder has same name as global recorder
raise ValueError("inline dups global recorder")
recorder = PywrRecorder(rec_name, value)
node.data[attr] = recorder

def attach_reference_parameters(self):
"""
Expand All @@ -225,6 +250,7 @@ def attach_reference_parameters(self):
are replaced with the instance of that parameter.
"""
exclude = ("name", "type")
attached_parameters = []
for node in self.nodes.values():
for attr, value in node.data.items():
if attr.lower() in exclude:
Expand All @@ -239,6 +265,39 @@ def attach_reference_parameters(self):
continue
log.debug(f"Attaching global param ref: {value}")
node.data[attr] = param
attached_parameters.append(value)

for attached_parameter in attached_parameters:
del(self.parameters[attached_parameter])

def attach_reference_recorders(self):
"""
Promotes strings which reference recorders to instances of
:class:`PywrRecorder`.
Any values of attrs in a node which resolve to a global recorder
are replaced with the instance of that recorder.
"""
exclude = ("name", "type")
attached_recorders = []
for node in self.nodes.values():
for attr, value in node.data.items():
if attr.lower() in exclude:
"""
A recorder could exist with the same name as a node,
leading to node["name"] = recorder
"""
continue
if isinstance(value, str):
recorder = self.recorders.get(value)
if not recorder:
continue
log.debug(f"Attaching global recorder ref: {value}")
node.data[attr] = recorder
attached_recorders.append(value)

for attached_recorder in attached_recorders:
del(self.recorders[attached_recorder])


def __add_component_references(self, component=None):
Expand Down Expand Up @@ -417,4 +476,7 @@ def url_references(self):
for p in (param for param in self.parameters.values() if "url" in param.data):
url_map[p.data["url"]].append(p)

for t in (table for table in self.tables.values() if "url" in table.data):
url_map[t.data["url"]].append(t)

return url_map
7 changes: 7 additions & 0 deletions tests/test_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,10 @@ def test_network_add_recorder_references(valid_network_file):
assert "recorder" not in node.data
network.add_recorder_references()
assert "recorder" in node.data

def test_network_promote_inline_recorders(valid_network_file):
network, errors, warnings = PywrNetwork.from_file(valid_network_file)
node = network.nodes["Node_1"]
assert not isinstance(node.data["max_flow"], PywrRecorder)
network.promote_inline_recorders()
assert isinstance(node.data["max_flow"], PywrRecorder)

0 comments on commit 985b9d3

Please sign in to comment.