Repository: gammapy/gammapy (python)

Issue:
Named arguments aren't checked for some functions (leading to fat-fingering bugs)
**Gammapy version**
Both in version 0.19 and 1.2

**Bug description**

`PowerLawSpectralModel` has three named arguments: `index, amplitude, reference`.

If one of these is mistyped, then the default value is taken for the argument, and the mistyped argument is ignored.  

This leads to silent errors.

**Expected behavior**

Normally in Python, if a function has named arguments, then if a "misnomer" is given, then an error of this type occurs:
```
TypeError: call_by_named() got an unexpected keyword argument 'val3'
```
In this way there are no silent errors.

**To Reproduce**
Try this code:
```
from astropy import units as u
from gammapy.modeling.models import PowerLawSpectralModel

model_simu = PowerLawSpectralModel(
        index=5.32,
        amplitude = u.Quantity("2.04e-8 TeV-1 cm-2 s-1"),
        reference = 80*u.GeV,)

bad_simu = PowerLawSpectralModel(
        index=5.32,
        amplitude = u.Quantity("2.04e-8 TeV-1 cm-2 s-1"),
        referecne = 80*u.GeV,)

energy_bounds = [0.01, 1.0] * u.TeV

from matplotlib import pyplot as plt
model_simu.plot(energy_bounds,sed_type="e2dnde",label="Good spectrum, reference")
bad_simu.plot(energy_bounds,sed_type="e2dnde",label="Misnomer spectrum, referecne")
plt.grid(which="both")
plt.plot(0.08,2.1e-10,'o',label="Good spectrum point")

plt.legend()
plt.show()
```

**Other information**
Not urgent, but this kind of unexpected and non-Pythonic behaviour can lead to loss of time.


Pull request:
Fix unknown arguments defined in Models
This fixes #5413

Currently a test fails `gammapy/modeling/models/tests/test_io.py` but I am not sure how to fix that 


`SpectralModels`:
- `ExpCutoffPowerLawNormSpectralModel` requires the kwargs on super because we have the deprecation there
- super init is required on the `EBLAbsorptionNormSpectralModel` -- because it needs to be able to 'read_builtin' --> this should be fine like this because we do not define a kwargs
- all other inits are empty 

SpatialModels:
- `TemplateSpatialModel` has the kwargs in super init (not sure it can be removed?)
- `PiecewiseNormSpatialModel` same as above?

Patch:
diff --git a/examples/models/spectral/plot_gauss_spectral.py b/examples/models/spectral/plot_gauss_spectral.py
index 54e77ed8e..f210bc4e5 100644
--- a/examples/models/spectral/plot_gauss_spectral.py
+++ b/examples/models/spectral/plot_gauss_spectral.py
@@ -23,7 +23,9 @@ import matplotlib.pyplot as plt
 from gammapy.modeling.models import GaussianSpectralModel, Models, SkyModel
 
 energy_bounds = [0.1, 100] * u.TeV
-model = GaussianSpectralModel(norm="1e-2 cm-2 s-1", mean=2 * u.TeV, sigma=0.2 * u.TeV)
+model = GaussianSpectralModel(
+    amplitude="1e-2 cm-2 s-1", mean=2 * u.TeV, sigma=0.2 * u.TeV
+)
 model.plot(energy_bounds)
 plt.grid(which="both")
 plt.ylim(1e-24, 1e-1)
diff --git a/examples/models/temporal/plot_constant_temporal.py b/examples/models/temporal/plot_constant_temporal.py
index 6ac955c99..e5910a0f0 100644
--- a/examples/models/temporal/plot_constant_temporal.py
+++ b/examples/models/temporal/plot_constant_temporal.py
@@ -26,7 +26,7 @@ from gammapy.modeling.models import (
 )
 
 time_range = [Time.now(), Time.now() + 1 * u.d]
-constant_model = ConstantTemporalModel(const=1)
+constant_model = ConstantTemporalModel()
 constant_model.plot(time_range)
 plt.grid(which="both")
 
diff --git a/gammapy/modeling/models/core.py b/gammapy/modeling/models/core.py
index 39205c5f1..2e88646b0 100644
--- a/gammapy/modeling/models/core.py
+++ b/gammapy/modeling/models/core.py
@@ -134,6 +134,10 @@ class ModelBase:
         # Copy default parameters from the class to the instance
         default_parameters = self.default_parameters.copy()
 
+        for key in kwargs.keys():
+            if key != "covariance_data" and key not in default_parameters.names :
+                raise NameError(f"Unknown Parameter name '{key}'")
+
         for par in default_parameters:
             value = kwargs.get(par.name, par)
 
diff --git a/gammapy/modeling/models/spectral.py b/gammapy/modeling/models/spectral.py
index 2da660505..b8b21bc7f 100644
--- a/gammapy/modeling/models/spectral.py
+++ b/gammapy/modeling/models/spectral.py
@@ -1693,18 +1693,6 @@ class LogParabolaNormSpectralModel(SpectralModel):
     alpha = Parameter("alpha", 0)
     beta = Parameter("beta", 0)
 
-    def __init__(self, norm=None, reference=None, alpha=None, beta=None, **kwargs):
-        if norm is not None:
-            kwargs.update({"norm": norm})
-        if beta is not None:
-            kwargs.update({"beta": beta})
-        if reference is not None:
-            kwargs.update({"reference": reference})
-        if alpha is not None:
-            kwargs.update({"alpha": alpha})
-
-        super().__init__(**kwargs)
-
     @classmethod
     def from_log10(cls, norm, reference, alpha, beta):
         """Construct from :math:`log_{10}` parametrization."""


Test patch:
diff --git a/gammapy/modeling/models/tests/test_cube.py b/gammapy/modeling/models/tests/test_cube.py
index e37c4585c..773bd2234 100644
--- a/gammapy/modeling/models/tests/test_cube.py
+++ b/gammapy/modeling/models/tests/test_cube.py
@@ -754,7 +754,9 @@ def test_sky_model_create():
 
 
 def test_integrate_geom():
-    model = GaussianSpatialModel(lon="0d", lat="0d", sigma=0.1 * u.deg, frame="icrs")
+    model = GaussianSpatialModel(
+        lon_0="0 deg", lat_0="0 deg", sigma=0.1 * u.deg, frame="icrs"
+    )
     spectral_model = PowerLawSpectralModel(amplitude="1e-11 cm-2 s-1 TeV-1")
     sky_model = SkyModel(spectral_model=spectral_model, spatial_model=model)
 
@@ -771,7 +773,9 @@ def test_integrate_geom():
 
 
 def test_evaluate_integrate_nd_geom():
-    model = GaussianSpatialModel(lon="0d", lat="0d", sigma=0.1 * u.deg, frame="icrs")
+    model = GaussianSpatialModel(
+        lon_0="0 deg", lat_0="0 deg", sigma=0.1 * u.deg, frame="icrs"
+    )
     spectral_model = PowerLawSpectralModel(amplitude="1e-11 cm-2 s-1 TeV-1")
     sky_model = SkyModel(spectral_model=spectral_model, spatial_model=model)
 
@@ -816,7 +820,7 @@ def test_evaluate_integrate_nd_geom():
 
 def test_evaluate_integrate_geom_with_time():
     spatial_model = GaussianSpatialModel(
-        lon="0d", lat="0d", sigma=0.1 * u.deg, frame="icrs"
+        lon_0="0 deg", lat_0="0 deg", sigma=0.1 * u.deg, frame="icrs"
     )
     spectral_model = PowerLawSpectralModel(amplitude="1e-11 cm-2 s-1 TeV-1")
     temporal_model = PowerLawTemporalModel()
@@ -891,7 +895,7 @@ def test_evaluate_integrate_geom_with_time():
 
 def test_evaluate_integrate_geom_with_time_and_gti():
     spatial_model = GaussianSpatialModel(
-        lon="0d", lat="0d", sigma=0.1 * u.deg, frame="icrs"
+        lon_0="0 deg", lat_0="0 deg", sigma=0.1 * u.deg, frame="icrs"
     )
     spectral_model = PowerLawSpectralModel(amplitude="1e-11 cm-2 s-1 TeV-1")
     temporal_model = PowerLawTemporalModel()
diff --git a/gammapy/modeling/models/tests/test_spatial.py b/gammapy/modeling/models/tests/test_spatial.py
index bbef5b49b..2e6ff8db0 100644
--- a/gammapy/modeling/models/tests/test_spatial.py
+++ b/gammapy/modeling/models/tests/test_spatial.py
@@ -572,9 +572,10 @@ models_test = [
 
 @pytest.mark.parametrize(("model_class", "extension_param"), models_test)
 def test_spatial_model_plot_error(model_class, extension_param):
-    model = model_class(lon="0d", lat="0d", sigma=0.2 * u.deg, frame="galactic")
+    model = model_class(lon_0="0 deg", lat_0="0 deg", frame="galactic")
     model.lat_0.error = 0.04
     model.lon_0.error = 0.02
+    model.parameters[extension_param].value = 0.2
     model.parameters[extension_param].error = 0.04
     model.e.error = 0.002
 
@@ -664,7 +665,9 @@ def test_integrate_geom_parameter_issue():
 
 def test_integrate_geom_energy_axis():
     center = SkyCoord("0d", "0d", frame="icrs")
-    model = GaussianSpatialModel(lon="0d", lat="0d", sigma=0.1 * u.deg, frame="icrs")
+    model = GaussianSpatialModel(
+        lon_0="0 deg", lat_0="0 deg", sigma=0.1 * u.deg, frame="icrs"
+    )
 
     radius = 1 * u.deg
     square = RectangleSkyRegion(center, radius, radius)
diff --git a/gammapy/modeling/models/tests/test_spectral.py b/gammapy/modeling/models/tests/test_spectral.py
index 86b4e6f41..795bd816a 100644
--- a/gammapy/modeling/models/tests/test_spectral.py
+++ b/gammapy/modeling/models/tests/test_spectral.py
@@ -1303,3 +1303,8 @@ def test_template_ND_EBL(tmpdir):
     assert_allclose(template_new.map.data, region_map.data)
     assert len(template.parameters) == 1
     assert_allclose(template.parameters["redshift"].value, 0.1)
+
+
+def test_incorrect_param_name():
+    with pytest.raises(NameError):
+        PowerLawSpectralModel(indxe=2)
diff --git a/gammapy/modeling/models/tests/test_temporal.py b/gammapy/modeling/models/tests/test_temporal.py
index ceae2b634..4dd4bf63a 100644
--- a/gammapy/modeling/models/tests/test_temporal.py
+++ b/gammapy/modeling/models/tests/test_temporal.py
@@ -387,7 +387,7 @@ def test_with_skymodel(light_curve):
 
 def test_plot_constant_model():
     time_range = [Time.now(), Time.now() + 1 * u.d]
-    constant_model = ConstantTemporalModel(const=1)
+    constant_model = ConstantTemporalModel()
     with mpl_plot_check():
         constant_model.plot(time_range)