Repository: rhayes777/PyAutoFit (python)

Issue:
Database building issue due to inheritance
The following script fails to build a database:

https://github.com/Jammy2211/autolens_workspace_test/blob/main/database/github_issue/build.py

The issue it raises is:

```
"^[[Dremove larTraceback (most recent call last):
  File "/mnt/c/Users/Jammy/Code/PyAuto/autolens_workspace_test/database/github_issue/build.py", line 50, in <module>
    agg.add_directory(directory=path.join("output", database_name))
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/database/aggregator/aggregator.py", line 419, in add_directory
    scraper.scrape()
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/database/aggregator/scrape.py", line 62, in scrape
    for fit in self._fits():
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/database/aggregator/scrape.py", line 89, in _fits
    model = item.model
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/aggregator/search_output.py", line 161, in model
    self.__model = AbstractPriorModel.from_dict(
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/model_object.py", line 243, in from_dict
    from_dict(
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoConf/autoconf/dictable.py", line 156, in from_dict
    return __parsers[type_](dictionary, **kwargs)
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/model_object.py", line 243, in from_dict
    from_dict(
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoConf/autoconf/dictable.py", line 156, in from_dict
    return __parsers[type_](dictionary, **kwargs)
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/model_object.py", line 243, in from_dict
    from_dict(
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoConf/autoconf/dictable.py", line 156, in from_dict
    return __parsers[type_](dictionary, **kwargs)
  File "/mnt/c/Users/Jammy/Code/PyAuto/PyAutoFit/autofit/mapper/model_object.py", line 213, in from_dict
    return cls_(
TypeError: Isothermal.__init__() got an unexpected keyword argument 'slope'
```

This will be related to how the `slope` parameter of an `Isothermal` is not in its `__init__` constructor:

```
class Isothermal(PowerLaw):
    def __init__(
        self,
        centre: Tuple[float, float] = (0.0, 0.0),
        ell_comps: Tuple[float, float] = (0.0, 0.0),
        einstein_radius: float = 1.0,
    ):
        """
        Represents an elliptical isothermal density distribution, which is equivalent to the elliptical power-law
        density distribution for the value slope: float = 2.0

        Parameters
        ----------
        centre
            The (y,x) arc-second coordinates of the profile centre.
        ell_comps
            The first and second ellipticity components of the elliptical coordinate system.
        einstein_radius
            The arc-second Einstein radius.
        """

        super().__init__(
            centre=centre,
            ell_comps=ell_comps,
            einstein_radius=einstein_radius,
            slope=2.0,
        )
```

Pull request description:
instantiate a SamplesPDF when scraping
All issues with script mentioned in #824 resolved except for covariance, which does not appear in the source code?

Also resolves #823

Patch:
diff --git a/autofit/database/aggregator/scrape.py b/autofit/database/aggregator/scrape.py
index 689686706..7a1334e56 100644
--- a/autofit/database/aggregator/scrape.py
+++ b/autofit/database/aggregator/scrape.py
@@ -10,7 +10,7 @@ import numpy as np
 
 from .. import model as m
 from ..sqlalchemy_ import sa
-from autofit.non_linear.samples.samples import Samples
+from autofit.non_linear.samples.pdf import SamplesPDF
 from ...mapper.model_object import Identifier
 from autofit.non_linear.samples.sample import samples_from_iterator
 
@@ -259,7 +259,7 @@ def _add_files(fit: m.Fit, files_path: Path):
         with open(samples_path) as f:
             sample_list = samples_from_iterator(csv.reader(f))
 
-        fit.samples = Samples.from_list_info_and_model(
+        fit.samples = SamplesPDF.from_list_info_and_model(
             sample_list=sample_list,
             samples_info=info_json,
             model=fit.model,
diff --git a/autofit/mapper/model_object.py b/autofit/mapper/model_object.py
index b7a7f6c96..8b26f6ddd 100644
--- a/autofit/mapper/model_object.py
+++ b/autofit/mapper/model_object.py
@@ -4,7 +4,7 @@ from typing import Type, Union, Tuple, Optional, Dict
 import logging
 
 from autoconf.class_path import get_class
-from autoconf.dictable import from_dict
+from autoconf.dictable import from_dict, to_dict
 from .identifier import Identifier
 
 logger = logging.getLogger(__name__)
@@ -299,9 +299,7 @@ class ModelObject:
 
         for key, value in self._dict.items():
             try:
-                if not isinstance(value, ModelObject):
-                    value = AbstractPriorModel.from_instance(value)
-                value = value.dict()
+                value = to_dict(value)
             except AttributeError:
                 pass
             except TypeError:
diff --git a/autofit/non_linear/paths/database.py b/autofit/non_linear/paths/database.py
index 29012672b..fd097b71e 100644
--- a/autofit/non_linear/paths/database.py
+++ b/autofit/non_linear/paths/database.py
@@ -121,7 +121,7 @@ class DatabasePaths(AbstractPaths):
         del d["session"]
         return d
 
-    def save_json(self, name, object_dict: Union[dict, list], prefix : str = ""):
+    def save_json(self, name, object_dict: Union[dict, list], prefix: str = ""):
         """
         Save a dictionary as a json file in the database
 
@@ -134,7 +134,7 @@ class DatabasePaths(AbstractPaths):
         """
         self.fit.set_json(name, object_dict)
 
-    def load_json(self, name: str, prefix : str = "") -> Union[dict, list]:
+    def load_json(self, name: str, prefix: str = "") -> Union[dict, list]:
         """
         Load a json file from the database
 
@@ -177,7 +177,7 @@ class DatabasePaths(AbstractPaths):
         """
         return self.fit.get_array(name)
 
-    def save_fits(self, name: str, hdu, prefix : str = ""):
+    def save_fits(self, name: str, hdu, prefix: str = ""):
         """
         Save a fits file in the database
 
@@ -190,7 +190,7 @@ class DatabasePaths(AbstractPaths):
         """
         self.fit.set_hdu(name, hdu)
 
-    def load_fits(self, name: str, prefix : str = ""):
+    def load_fits(self, name: str, prefix: str = ""):
         """
         Load a fits file from the database
 
@@ -205,10 +205,10 @@ class DatabasePaths(AbstractPaths):
         """
         return self.fit.get_hdu(name)
 
-    def save_object(self, name: str, obj: object, prefix : str = ""):
+    def save_object(self, name: str, obj: object, prefix: str = ""):
         self.fit[name] = obj
 
-    def load_object(self, name: str, prefix : str = ""):
+    def load_object(self, name: str, prefix: str = ""):
         return self.fit[name]
 
     def remove_object(self, name: str):
@@ -279,12 +279,11 @@ class DatabasePaths(AbstractPaths):
         return self._load_samples().samples_info
 
     def save_all(self, info, *_, **kwargs):
-
         self.fit.info = info
         self.fit.model = self.model
         if info:
             self.save_json("info", info)
         self.save_json("search", to_dict(self.search))
-        self.save_json("model", self.model.dict())
+        self.save_json("model", to_dict(self.model))
 
         self.session.commit()
diff --git a/autofit/non_linear/paths/directory.py b/autofit/non_linear/paths/directory.py
index 817467d73..961e4e9dc 100644
--- a/autofit/non_linear/paths/directory.py
+++ b/autofit/non_linear/paths/directory.py
@@ -234,7 +234,6 @@ class DirectoryPaths(AbstractPaths):
             return json.load(infile)
 
     def save_all(self, search_config_dict=None, info=None):
-        search_config_dict = search_config_dict or {}
         info = info or {}
 
         self.save_identifier()
@@ -244,7 +243,7 @@ class DirectoryPaths(AbstractPaths):
         if info:
             self.save_json("info", info)
         self.save_json("search", to_dict(self.search))
-        self.save_json("model", self.model.dict())
+        self.save_json("model", to_dict(self.model))
         self._save_metadata(search_name=type(self.search).__name__.lower())
 
     @AbstractPaths.parent.setter


Test patch:
diff --git a/test_autofit/serialise/test_regression.py b/test_autofit/serialise/test_regression.py
index bbc891fe3..642fd710c 100644
--- a/test_autofit/serialise/test_regression.py
+++ b/test_autofit/serialise/test_regression.py
@@ -1,5 +1,6 @@
 import json
 
+from autoconf.dictable import to_dict, from_dict
 from autofit.mapper.mock.mock_model import MockClassx2Tuple
 import autofit as af
 
@@ -7,3 +8,15 @@ import autofit as af
 def test_tuple():
     model = af.Model(MockClassx2Tuple)
     json.dumps(model.dict())
+
+
+class AttributeNotInInit:
+    def __init__(self):
+        self.attribute = 1
+
+
+def test_embedded():
+    model = af.Collection(instance=AttributeNotInInit())
+
+    print(to_dict(model))
+    from_dict(to_dict(model))