Repository: rhayes777/PyAutoFit (python)

Issue:
Model Components With No Free Parameters In the Database
The following test script:

https://github.com/Jammy2211/autolens_workspace_test/blob/main/scripts/database/scrape/slam_pix.py

Gives the following error:

```
Traceback (most recent call last):
  File "/mnt/c/Users/Jammy/Results/slacs/paper/mge.py", line 63, in <module>
    ml_instances = [samps.max_log_likelihood() for samps in agg.values("samples")]
  File "/mnt/c/Users/Jammy/Results/slacs/paper/mge.py", line 63, in <listcomp>
    ml_instances = [samps.max_log_likelihood() for samps in agg.values("samples")]
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/non_linear/samples/interface.py", line 34, in wrapper
    return self._instance_from_vector(vector)
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/non_linear/samples/samples.py", line 64, in _instance_from_vector
    instance = super()._instance_from_vector(vector)
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/non_linear/samples/interface.py", line 217, in _instance_from_vector
    return self.model.instance_from_vector(vector=vector, ignore_prior_limits=True)
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/prior_model/abstract.py", line 776, in instance_from_vector
    return self.instance_for_arguments(
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/prior_model/abstract.py", line 1316, in instance_for_arguments
    return self._instance_for_arguments(
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/prior_model/collection.py", line 249, in _instance_for_arguments
    value = value.instance_for_arguments(arguments)
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/prior_model/abstract.py", line 1316, in instance_for_arguments
    return self._instance_for_arguments(
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/prior_model/collection.py", line 249, in _instance_for_arguments
    value = value.instance_for_arguments(arguments)
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/prior_model/abstract.py", line 1316, in instance_for_arguments
    return self._instance_for_arguments(
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/prior_model/prior_model.py", line 428, in _instance_for_arguments
    ] = prior_model.instance_for_arguments(
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/prior_model/abstract.py", line 1316, in instance_for_arguments
    return self._instance_for_arguments(
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/prior_model/prior_model.py", line 454, in _instance_for_arguments
    result = self.cls(**constructor_arguments)
TypeError: Pixelization.__init__() missing 1 required positional argument: 'mesh'
```

This is because I updated the model composition of a `Pixelization` to be as follows:

```
pixelization = af.Model(
    al.Pixelization,
    image_mesh=al.image_mesh.Overlay(shape=(30, 30)),
    mesh=al.mesh.Delaunay(),
    regularization=al.reg.Constant,
)
```

Notably, the `mesh` input and object does not have free parameters.

The code `mesh=al.mesh.Delaunay()` tells the code to use the delaunay functionality, but in this particular example it does not have any free parameters.

Can you update autofit database functionality to smoothly handle objects like this?

Pull request:
feature/unparamatised argument
Resolves #928


Patch:
diff --git a/autofit/database/model/model.py b/autofit/database/model/model.py
index 775098679..36cde5adb 100644
--- a/autofit/database/model/model.py
+++ b/autofit/database/model/model.py
@@ -6,8 +6,6 @@ import numpy as np
 
 from autoconf.class_path import get_class, get_class_path
 from ..sqlalchemy_ import sa, declarative
-from autofit.mapper.prior.arithmetic.assertion import ComparisonAssertion
-from autofit.mapper.prior.arithmetic.assertion import CompoundAssertion
 
 Base = declarative.declarative_base()
 
@@ -97,6 +95,7 @@ class Object(Base):
         elif isinstance(source, np.ndarray):
             from .array import Array
 
+            # noinspection PyArgumentList
             instance = Array(array=source)
         elif isinstance(source, Model):
             from .prior import Model
diff --git a/autofit/mapper/prior_model/abstract.py b/autofit/mapper/prior_model/abstract.py
index 7ef2546e8..7fb23ff7d 100644
--- a/autofit/mapper/prior_model/abstract.py
+++ b/autofit/mapper/prior_model/abstract.py
@@ -1178,12 +1178,11 @@ class AbstractPriorModel(AbstractModel):
         return result
 
     def items(self):
-        return (
-            self.direct_prior_tuples
-            + self.direct_instance_tuples
-            + self.direct_prior_model_tuples
-            + self.direct_tuple_priors
-        )
+        return [
+            (key, value)
+            for key, value in self.__dict__.items()
+            if not key.startswith("_") and key not in ("cls", "id")
+        ]
 
     @property
     @cast_collection(PriorNameValue)


Test patch:
diff --git a/test_autofit/database/test_regression.py b/test_autofit/database/test_regression.py
index 85ee87d8e..bae58d94e 100644
--- a/test_autofit/database/test_regression.py
+++ b/test_autofit/database/test_regression.py
@@ -21,3 +21,21 @@ def test_object_to_instance(model):
         db.Object.from_object(model)().instance_from_prior_medians(),
         af.Gaussian,
     )
+
+
+def test_model_with_parameterless_component():
+    child = af.Gaussian()
+    model = af.Model(
+        af.Gaussian,
+        centre=child,
+    )
+    assert ("centre", child) in model.items()
+
+    model = db.Object.from_object(model)()
+    instance = model.instance_from_prior_medians()
+    assert isinstance(instance.centre, af.Gaussian)
+
+
+def test_instance_in_collection():
+    collection = af.Collection(gaussian=af.Gaussian())
+    assert list(collection.items()) == [("gaussian", af.Gaussian())]