Repository: gammapy/gammapy

Issue:
Management of metadata for `Models`

**Description**
This pull request aims to deal with metadata for `Models`. 

For the moment, models metadata are not kept in a dedicated metadata class. They are just written in file, and read when a basic check of the Gammapy version.




Discussion:
## [Codecov](https://app.codecov.io/gh/gammapy/gammapy/pull/4819?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gammapy) Report
> Merging [#4819](https://app.codecov.io/gh/gammapy/gammapy/pull/4819?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gammapy) (da2243b) into [main](https://app.codecov.io/gh/gammapy/gammapy/commit/7287b3048f7cb6b33ccea7f4eda91670345568f5?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gammapy) (7287b30) will **increase** coverage by `0.04%`.
> Report is 15 commits behind head on main.
> The diff coverage is `88.88%`.

> :exclamation: Current head da2243b differs from pull request most recent head 3fc2fab. Consider uploading reports for the commit 3fc2fab to get more accurate results

```diff
@@            Coverage Diff             @@
##             main    #4819      +/-   ##
==========================================
+ Coverage   75.53%   75.58%   +0.04%     
==========================================
  Files         223      223              
  Lines       32666    32690      +24     
==========================================
+ Hits        24675    24708      +33     
+ Misses       7991     7982       -9     
```


| [Files](https://app.codecov.io/gh/gammapy/gammapy/pull/4819?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gammapy) | Coverage Δ | |
|---|---|---|
| [gammapy/modeling/models/spatial.py](https://app.codecov.io/gh/gammapy/gammapy/pull/4819?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gammapy#diff-Z2FtbWFweS9tb2RlbGluZy9tb2RlbHMvc3BhdGlhbC5weQ==) | `85.02% <100.00%> (+0.09%)` | :arrow_up: |
| [gammapy/modeling/models/tests/test\_io.py](https://app.codecov.io/gh/gammapy/gammapy/pull/4819?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gammapy#diff-Z2FtbWFweS9tb2RlbGluZy9tb2RlbHMvdGVzdHMvdGVzdF9pby5weQ==) | `54.66% <100.00%> (+2.13%)` | :arrow_up: |
| [gammapy/utils/metadata.py](https://app.codecov.io/gh/gammapy/gammapy/pull/4819?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gammapy#diff-Z2FtbWFweS91dGlscy9tZXRhZGF0YS5weQ==) | `81.81% <100.00%> (+0.42%)` | :arrow_up: |
| [gammapy/modeling/models/core.py](https://app.codecov.io/gh/gammapy/gammapy/pull/4819?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gammapy#diff-Z2FtbWFweS9tb2RlbGluZy9tb2RlbHMvY29yZS5weQ==) | `85.08% <90.90%> (+0.09%)` | :arrow_up: |
| [gammapy/utils/check.py](https://app.codecov.io/gh/gammapy/gammapy/pull/4819?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gammapy#diff-Z2FtbWFweS91dGlscy9jaGVjay5weQ==) | `60.00% <66.66%> (+60.00%)` | :arrow_up: |

... and [2 files with indirect coverage changes](https://app.codecov.io/gh/gammapy/gammapy/pull/4819/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gammapy)

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gammapy)


Resolving patch:
diff --git a/gammapy/modeling/models/core.py b/gammapy/modeling/models/core.py
--- a/gammapy/modeling/models/core.py
+++ b/gammapy/modeling/models/core.py
@@ -12,6 +12,7 @@
 import yaml
 from gammapy.maps import Map, RegionGeom
 from gammapy.modeling import Covariance, Parameter, Parameters
+from gammapy.utils.metadata import CreatorMetaData
 from gammapy.utils.scripts import make_name, make_path
 
 __all__ = ["Model", "Models", "DatasetModels", "ModelBase"]
@@ -431,6 +432,8 @@ def read(cls, filename):
     def from_yaml(cls, yaml_str, path=""):
         """Create from YAML string."""
         data = yaml.safe_load(yaml_str)
+        # TODO : for now metadata are not kept. Add proper metadata creation.
+        data.pop("metadata", None)
         return cls.from_dict(data, path=path)
 
     @classmethod
@@ -487,11 +490,11 @@ def write(
         overwrite : bool, optional
             Overwrite existing file. Default is False.
         full_output : bool
-            Store full parameter output.
+            Store full parameter output. Default is False.
         overwrite_templates : bool
-            overwrite templates FITS files
+            Overwrite templates FITS files. Default is False.
         write_covariance : bool
-            save covariance or not
+            Save covariance or not. Default is True.
         """
         base_path, _ = split(path)
         path = make_path(path)
@@ -517,9 +520,11 @@ def write(
     def to_yaml(self, full_output=False, overwrite_templates=False):
         """Convert to YAML string."""
         data = self.to_dict(full_output, overwrite_templates)
-        return yaml.dump(
+        text = yaml.dump(
             data, sort_keys=False, indent=4, width=80, default_flow_style=False
         )
+        creation = CreatorMetaData.from_default()
+        return text + creation.to_yaml()
 
     def update_link_label(self):
         """update linked parameters labels used for serialization and print"""
diff --git a/gammapy/utils/metadata.py b/gammapy/utils/metadata.py
--- a/gammapy/utils/metadata.py
+++ b/gammapy/utils/metadata.py
@@ -159,7 +159,7 @@ def from_header(cls, header, format="gadf"):
 
     def to_yaml(self):
         """Dump metadata content to yaml."""
-        meta = json.loads(self.json())
+        meta = {"metadata": json.loads(self.json())}
         return yaml.dump(
             meta, sort_keys=False, indent=4, width=80, default_flow_style=False
         )


Test patch:
diff --git a/gammapy/modeling/models/tests/test_io.py b/gammapy/modeling/models/tests/test_io.py
--- a/gammapy/modeling/models/tests/test_io.py
+++ b/gammapy/modeling/models/tests/test_io.py
@@ -483,3 +483,13 @@ def test_compound_models_io(tmp_path):
         "model.spectral.alpha",
         "model.spectral.beta",
     ]
+
+
+def test_meta_io(caplog, tmp_path):
+    m = PowerLawSpectralModel()
+    sk = SkyModel(spectral_model=m, name="model")
+    Models([sk]).write(tmp_path / "test.yaml")
+
+    sk_dict = read_yaml(tmp_path / "test.yaml")
+    assert "metadata" in sk_dict
+    assert "Gammapy" in sk_dict["metadata"]["creator"]