Repository: StingraySoftware/stingray (python)

Issue:
Error reading the event file
Hi Stingray Development Team,

When analyzing a NICER X-ray data, I got an error when reading the event file: 

File /data/software/anaconda/envs/tugbabztp/lib/python3.12/site-packages/stingray/events.py:625, in EventList.read(cls, filename, fmt, **kwargs)
    622                 setattr(evt, key.lower(), evtdata.additional_data[key])
    623     return evt
--> 625 return super().read(filename=filename, fmt=fmt)

File /data/software/anaconda/envs/tugbabztp/lib/python3.12/site-packages/stingray/base.py:647, in StingrayObject.read(cls, filename, fmt)
    643             ts[col_strip] += new_value
    645         ts.remove_column(col)
--> 647 return cls.from_astropy_table(ts)

File /data/software/anaconda/envs/tugbabztp/lib/python3.12/site-packages/stingray/base.py:425, in StingrayObject.from_astropy_table(cls, ts)
    422     setattr(cls, attr.lower(), np.array(ts[attr]))
    424 for key, val in ts.meta.items():
--> 425     setattr(cls, key.lower(), val)
    427 return cls

AttributeError: property 'exposure' of 'EventList' object has no setter

but I realized that I only get this error when we use the most recent version distributed by conda which I installed just a few days ago (stingray version: 2.0.0). The same code works just fine with the previous version (stingray version: 1.1.1) again installed earlier from conda. 

Thanks !

Pull request:
Fix property setting from astropy
Resolve #813

Patch:
diff --git a/docs/changes/814.bugfix.rst b/docs/changes/814.bugfix.rst
new file mode 100644
index 00000000..d90606d6
--- /dev/null
+++ b/docs/changes/814.bugfix.rst
@@ -0,0 +1,1 @@
+Fix issue when setting a property from a FITS file read
diff --git a/stingray/base.py b/stingray/base.py
index 717630d7..a70fed44 100644
--- a/stingray/base.py
+++ b/stingray/base.py
@@ -421,9 +421,25 @@ class StingrayObject(object):
                 continue
             setattr(cls, attr.lower(), np.array(ts[attr]))
 
+        attributes_left_unchanged = []
         for key, val in ts.meta.items():
-            setattr(cls, key.lower(), val)
+            if (
+                isinstance(getattr(cls.__class__, key.lower(), None), property)
+                and getattr(cls.__class__, key.lower(), None).fset is None
+            ):
+                attributes_left_unchanged.append(key)
+                continue
 
+            setattr(cls, key.lower(), val)
+        if len(attributes_left_unchanged) > 0:
+            # Only warn once, if multiple properties are affected.
+            attrs = ",".join(attributes_left_unchanged)
+            warnings.warn(
+                f"The input table contains protected attribute(s) of StingrayTimeseries: {attrs}. "
+                "These values are set internally by the class, and cannot be overwritten. "
+                "This issue is common when reading from FITS files using `fmt='fits'`."
+                " If this is the case, please consider using `fmt='ogip'` instead."
+            )
         return cls
 
     def to_xarray(self) -> Dataset:


Test patch:
diff --git a/stingray/tests/test_base.py b/stingray/tests/test_base.py
index cb3c7143..37128486 100644
--- a/stingray/tests/test_base.py
+++ b/stingray/tests/test_base.py
@@ -4,6 +4,7 @@ import copy
 import pytest
 import numpy as np
 import matplotlib.pyplot as plt
+from astropy.table import Table
 from stingray.base import StingrayObject, StingrayTimeseries
 
 _HAS_XARRAY = importlib.util.find_spec("xarray") is not None
@@ -879,6 +880,14 @@ class TestStingrayTimeseries:
         new_so = StingrayTimeseries.from_astropy_table(ts)
         assert so == new_so
 
+    def test_setting_property_fails(self):
+        ts = Table(dict(time=[1, 2, 3]))
+        ts.meta["exposure"] = 10
+        with pytest.warns(
+            UserWarning, match=r".*protected attribute\(s\) of StingrayTimeseries: exposure"
+        ):
+            StingrayTimeseries.from_astropy_table(ts)
+
     @pytest.mark.parametrize("highprec", [True, False])
     def test_astropy_ts_roundtrip(self, highprec):
         if highprec: