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

Add function to output ParameterNode as YAML #295

Draft
wants to merge 15 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog_entry.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- bump: minor
changes:
added:
- write_yaml function to output ParameterNode data to a YAML file
- test_write_yaml test to produce a sample output
29 changes: 29 additions & 0 deletions policyengine_core/parameters/at_instant_like.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,32 @@ def get_at_instant(self, instant: Instant) -> Any:

@abc.abstractmethod
def _get_at_instant(self, instant): ...

def get_attr_dict(self) -> dict:
attr_dict = {}
attr_list = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the best practice here would be to keep this method as simple as possible, then do a bit more work with it where we actually use it. What I would do here is:

  1. Programmatically loop over all attributes and feed into a relevant data structure
  2. Return said structure

I wouldn't recurse downward here, either. I think we can do that inside our custom ParameterNode method, where we're more broadly defining what we're doing.

"name",
"description",
"documentation",
"file_path",
"metadata",
"trace",
"tracer",
"branch_name",
"modified",
"values_list",
]
for attr in attr_list:
if hasattr(self, attr):
attr_dict[attr] = getattr(self, attr)
if hasattr(self, "children"):
for child_name, child in self.children.items():
attr_dict[child_name] = child.get_attr_dict()
if hasattr(self, "values_list"):
value_dict = {}
attr_dict["values_list"] = value_dict
for value_at_instant in self.values_list:
value_dict[value_at_instant.instant_str] = (
value_at_instant.value
)
return attr_dict
18 changes: 14 additions & 4 deletions policyengine_core/parameters/parameter_node.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import copy
import os
import typing
from typing import Iterable, List, Type, Union
from pathlib import Path
from typing import Iterable, Union

import yaml

from policyengine_core import commons, parameters, tools
from policyengine_core.data_structures import Reference
from policyengine_core.periods.instant_ import Instant
from policyengine_core.tracers import TracingParameterNodeAtInstant

from .at_instant_like import AtInstantLike
from .parameter import Parameter
from .parameter_node_at_instant import ParameterNodeAtInstant
from .config import COMMON_KEYS, FILE_EXTENSIONS
from .helpers import (
load_parameter_file,
Expand All @@ -19,6 +19,8 @@
_parse_child,
_load_yaml_file,
)
from .parameter import Parameter
from .parameter_node_at_instant import ParameterNodeAtInstant

EXCLUDED_PARAMETER_CHILD_NAMES = ["reference", "__pycache__"]

Expand Down Expand Up @@ -274,3 +276,11 @@ def get_child(self, path: str) -> "ParameterNode":
f"Could not find the parameter (failed at {name})."
)
return node

def write_yaml(self, file_path: Path) -> yaml:
data = self.get_attr_dict()
anth-volk marked this conversation as resolved.
Show resolved Hide resolved
try:
with open(file_path, "w") as f:
yaml.dump(data, f, sort_keys=True)
except Exception as e:
print(f"Error when writing YAML file: {e}")
26 changes: 26 additions & 0 deletions tests/core/test_parameters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import tempfile
from pathlib import Path

import pytest

Expand Down Expand Up @@ -141,3 +142,28 @@ def test_name():
}
parameter = ParameterNode("root", data=parameter_data)
assert parameter.children["2010"].name == "root.2010"


def test_write_yaml():
parameter_data = {
"amount": {
"values": {
"2015-01-01": {"value": 550},
"2016-01-01": {"value": 600},
},
"description": "The amount of the basic income",
"documentation": None,
"modified": False,
},
"min_age": {
"values": {
"2015-01-01": {"value": 25},
"2016-01-01": {"value": 18},
},
"description": "The minimum age to receive the basic income",
"documentation": None,
"modified": True,
},
}
parameter = ParameterNode("root", data=parameter_data)
parameter.write_yaml(Path("output.yaml"))
Loading