Repository: openforcefield/openff-evaluator

Issue:
Allow AttributeClasses to be initialized with values
Currently all subclasses of AttributeClasses need their attributes to be set separately to instantiation, e.g.:

```
batch = Batch()
batch.id = ...
batch.force_field_id = ...
```

It'd be quite handy to be able to initialize attributes e.g. `Batch(id=..., force_field_id=...)`.

Some classes define `__init__` methods to allow this, so there may be a reason why this isn't more generally supported?

Discussion:

Patch:
diff --git a/openff/evaluator/attributes/attributes.py b/openff/evaluator/attributes/attributes.py
index b03dc1a..5fcbfb4 100644
--- a/openff/evaluator/attributes/attributes.py
+++ b/openff/evaluator/attributes/attributes.py
@@ -53,6 +53,11 @@ class AttributeClass(TypedBaseModel):
     attributes with additional metadata.
     """
 
+    def __init__(self, **kwargs):
+        super().__init__()
+        for k, v in kwargs.items():
+            setattr(self, k, v)
+
     def validate(self, attribute_type=None):
         """Validate the values of the attributes. If `attribute_type`
         is set, only attributes of that type will be validated.


Test patch:
diff --git a/openff/evaluator/_tests/test_attributes/test_attributes.py b/openff/evaluator/_tests/test_attributes/test_attributes.py
index 21fb2b4..2f6ba55 100644
--- a/openff/evaluator/_tests/test_attributes/test_attributes.py
+++ b/openff/evaluator/_tests/test_attributes/test_attributes.py
@@ -114,3 +114,22 @@ def test_nested_validation():
 
     nested_object.some_dict["x"].required_input = ""
     nested_object.validate()
+
+
+def test_initialize_with_attributes():
+    attribute_object = AttributeObject()
+    attribute_object.required_input = ""
+
+    nested_object = NestedAttributeObject(
+        some_value=attribute_object,
+        some_list=[
+            3,
+        ],
+        some_dict={"x": 4},
+    )
+    assert isinstance(nested_object.some_value, AttributeObject)
+    assert nested_object.some_value.required_input == ""
+    assert nested_object.some_list == [3]
+    assert nested_object.some_dict == {"x": 4}
+
+    nested_object.validate()