Repository: larq/zookeeper

Issue:
ComponentFields passed through the CLI don't get their Fields resolved
### Describe the bug
In the code below, let's say it's called `script.py`, `child.some_attribute` should be inherited from the `Parent` class. This works just fine if you execute this with `python script.py`, but if you instead excute `python script.py child=Child`, it will throw the following error:
```
  File "script.py", line 16, in run
    print(f"child attribute: {self.child.some_attribute}")
   ...
  File "<local_path>/zookeeper/core/field.py", line 144, in get_default
    raise AttributeError(
AttributeError: Field 'some_attribute' has no default or configured value.
```
So the `Child` is correctly resolved, but its `Field` never obtains the value from the parent class.

### To Reproduce
```python
from zookeeper import ComponentField, Field, cli, component, task


@component
class Child:
    some_attribute: bool = Field()  # inherited from parent


@task
class Parent:
    some_attribute: bool = Field(False)
    child: Child = ComponentField(Child)

    def run(self):
        print(f"Own attribute: {self.some_attribute}")
        print(f"child attribute: {self.child.some_attribute}")


if __name__ == "__main__":
    cli()

```

### Environment

TensorFlow version: 2.2.1
Zookeeper version: 1.1.0


Discussion:

Patch:
diff --git a/zookeeper/core/component.py b/zookeeper/core/component.py
index e3fde1f..63b0ee6 100644
--- a/zookeeper/core/component.py
+++ b/zookeeper/core/component.py
@@ -484,6 +484,14 @@ def configure_component_instance(
                             conf_field_value = subclass()
                             break
 
+            # If this isn't the case, then it's a user type error, but we don't
+            # throw here and instead let the run-time type-checking take care of
+            # it (which will provide a better error message).
+            if utils.is_component_instance(conf_field_value):
+                # Set the component parent so that field value inheritence will
+                # work correctly.
+                conf_field_value.__component_parent__ = instance
+
             # Set the value on the instance.
             instance.__component_configured_field_values__[
                 field.name


Test patch:
diff --git a/zookeeper/core/component_test.py b/zookeeper/core/component_test.py
index 1caf4fb..120557a 100644
--- a/zookeeper/core/component_test.py
+++ b/zookeeper/core/component_test.py
@@ -809,3 +809,21 @@ def test_base_hasattr():
 
     assert not hasattr(instance, "missing_attribute")
     assert base_hasattr(instance, "missing_attribute")
+
+
+def test_component_configure_component_passed_as_config():
+    @component
+    class Child:
+        x: int = Field()  # Inherited from parent
+
+    @component
+    class Parent:
+        x: int = Field(7)
+        child: Child = ComponentField(Child)
+
+    instance = Parent()
+    new_child_instance = Child()
+    configure(instance, {"child": new_child_instance})
+    assert instance.child is new_child_instance
+    assert instance.child.__component_parent__ is instance
+    assert instance.child.x == 7  # This value should be correctly inherited.