Repository: sunpy/sunpy

Issue:
instr Lyra has a lightcurve dependency
This needs moving to timeseries.


Discussion:

Resolving patch:
diff --git a/sunpy/instr/lyra.py b/sunpy/instr/lyra.py
--- a/sunpy/instr/lyra.py
+++ b/sunpy/instr/lyra.py
@@ -12,32 +12,42 @@
 import pandas
 
 from sunpy.time import parse_time
-from sunpy import config
 from sunpy.util.net import check_download_file
 from sunpy.util.config import get_and_create_download_dir
-from sunpy import lightcurve
+from sunpy.util.decorators import deprecated
 
 from sunpy.extern.six.moves import urllib
 
 LYTAF_REMOTE_PATH = "http://proba2.oma.be/lyra/data/lytaf/"
 
 
-def remove_lytaf_events_from_lightcurve(lc, artifacts=None,
+@deprecated('v0.8',
+            message="""``remove_lytaf_events_from_lightcurve`` is deprecated as of SunPy v0.8 due to
+            the deprecation of ``LightCurve`` in favour of ``TimeSeries``. You should use
+            ``remove_lytaf_events_from_timeseries`` instead.""",
+            name="remove_lytaf_events_from_lightcurve",
+            alternative="remove_lytaf_events_from_timeseries"
+            )
+def remove_lytaf_events_from_lightcurve(lc, **kwargs):
+    return remove_lytaf_events_from_timeseries(lc, **kwargs)
+
+
+def remove_lytaf_events_from_timeseries(ts, artifacts=None,
                                         return_artifacts=False,
                                         lytaf_path=None,
                                         force_use_local_lytaf=False):
     """
-    Removes periods of LYRA artifacts defined in LYTAF from a LYRALightCurve.
+    Removes periods of LYRA artifacts defined in LYTAF from a TimeSeries.
 
     Parameters
     ----------
-    lc : `sunpy.lightcurve.LightCurve`
+    ts : `sunpy.timeseries.TimeSeries`
 
-     artifacts : list of strings
-        Contain the artifact types to be removed.  For list of artifact types
-        see reference [1].  For example, if user wants to remove only large
-        angle rotations, listed at reference [1] as LAR, let artifacts=["LAR"].
-        Default=[], i.e. no artifacts will be removed.
+    artifacts : list of strings
+        Sets the artifact types to be removed.  For a list of artifact types
+        see reference [1].  For example, if a user wants to remove only large
+        angle rotations, listed at reference [1] as LAR, set artifacts=["LAR"].
+        The default is that no artifacts will be removed.
 
     return_artifacts : `bool`
         Set to True to return a `numpy.recarray` containing the start time, end
@@ -55,8 +65,8 @@ def remove_lytaf_events_from_lightcurve(lc, artifacts=None,
 
     Returns
     -------
-    lc_new : `sunpy.lightcurve.LightCurve`
-        copy of input LYRALightCurve with periods corresponding to artifacts
+    ts_new : `sunpy.timeseries.TimeSeries`
+        copy of input TimeSeries with periods corresponding to artifacts
         removed.
 
     artifact_status : `dict`
@@ -75,45 +85,49 @@ def remove_lytaf_events_from_lightcurve(lc, artifacts=None,
             Artifacts listed to be removed by user when defining
             artifacts kwarg which were not found in time series time range.
 
+    Notes
+    -----
+    This function is intended to take TimeSeries objects as input, but the
+    deprecated LightCurve is still supported here.
+
     References
     ----------
     [1] http://proba2.oma.be/data/TARDIS
 
     Examples
     --------
-    Remove LARs (Large Angle Rotations) from LYRALightCurve for 4-Dec-2014:
+    Remove LARs (Large Angle Rotations) from TimeSeries for 4-Dec-2014:
 
-        >>> import sunpy.lightcurve as lc
-        >>> lc = lc.LYRALightCurve.create("2014-12-02")
-        >>> lc_nolars = lc.remove_artifacts_from_lyralightcurve(lc, artifacts=["LAR"])
+        >>> import sunpy.timeseries as ts
+        >>> import sunpy.data.sample
+        >>> lyrats = ts.TimeSeries(sunpy.data.sample.LYRA_LEVEL3_TIMESERIES, source='LYRA')
+        >>> ts_nolars = ts.remove_artifacts_from_timeseries(lyrats, artifacts=["LAR"])
 
     To also retrieve information on the artifacts during that day:
-        >>> lc_nolars, artifact_status = lc.remove_artifacts_from_lyralightcurve(
-                lc, artifacts=["LAR"], return_artifacts=True)
+        >>> ts_nolars, artifact_status = ts.remove_artifacts_from_timeseries(
+                lyrats, artifacts=["LAR"], return_artifacts=True)
 
     """
     # Check that input argument is of correct type
     if not lytaf_path:
         lytaf_path = get_and_create_download_dir()
-    if not isinstance(lc, lightcurve.LightCurve):
-        raise TypeError("lc must be a LightCurve object.")
     # Remove artifacts from time series
-    data_columns = lc.data.columns
+    data_columns = ts.data.columns
     time, channels, artifact_status = _remove_lytaf_events(
-        lc.data.index,
-        channels=[np.asanyarray(lc.data[col]) for col in data_columns],
+        ts.data.index,
+        channels=[np.asanyarray(ts.data[col]) for col in data_columns],
         artifacts=artifacts, return_artifacts=True, lytaf_path=lytaf_path,
         force_use_local_lytaf=force_use_local_lytaf)
-    # Create new copy copy of lightcurve and replace data with
+    # Create new copy copy of timeseries and replace data with
     # artifact-free time series.
-    lc_new = copy.deepcopy(lc)
-    lc_new.data = pandas.DataFrame(
+    ts_new = copy.deepcopy(ts)
+    ts_new.data = pandas.DataFrame(
         index=time, data=dict((col, channels[i])
                               for i, col in enumerate(data_columns)))
     if return_artifacts:
-        return lc_new, artifact_status
+        return ts_new, artifact_status
     else:
-        return lc_new
+        return ts_new
 
 
 def _remove_lytaf_events(time, channels=None, artifacts=None,


Test patch:
diff --git a/sunpy/instr/tests/test_lyra.py b/sunpy/instr/tests/test_lyra.py
--- a/sunpy/instr/tests/test_lyra.py
+++ b/sunpy/instr/tests/test_lyra.py
@@ -11,6 +11,7 @@
 from sunpy.data.test import rootdir
 from sunpy.time import parse_time
 from sunpy import lightcurve
+from sunpy import timeseries
 from sunpy.instr import lyra
 
 from sunpy.extern.six.moves import range
@@ -81,34 +82,53 @@ def test_split_series_using_lytaf():
     assert split_no_lytaf[0]["subdata"].all() == dummy_data.all()
 
 
+@pytest.fixture
+def get_lyradata(dtype):
+    if dtype == 'lc':
+        # Create sample LYRALightCurve
+        lyrats = lightcurve.LYRALightCurve.create("2014-01-01")
+        lyrats.data = pandas.DataFrame(index=TIME,
+                                       data={"CHANNEL1": CHANNELS[0],
+                                             "CHANNEL2": CHANNELS[1],
+                                             "CHANNEL3": CHANNELS[0],
+                                             "CHANNEL4": CHANNELS[1]})
+    else:
+        # Create sample TimeSeries
+        lyrats = timeseries.TimeSeries(
+            os.path.join(rootdir, 'lyra_20150101-000000_lev3_std_truncated.fits.gz'),
+            source='LYRA')
+        lyrats.data = pandas.DataFrame(index=TIME,
+                                       data={"CHANNEL1": CHANNELS[0],
+                                             "CHANNEL2": CHANNELS[1],
+                                             "CHANNEL3": CHANNELS[0],
+                                             "CHANNEL4": CHANNELS[1]})
+    return lyrats
+
+
 @pytest.mark.online
-def test_remove_lytaf_events_from_lightcurve():
-    """Test if artefacts are correctly removed from a LYRAlightCurve."""
-    # Create sample LYRALightCurve
-    lyralc = lightcurve.LYRALightCurve.create("2014-01-01")
-    lyralc.data = pandas.DataFrame(index=TIME,
-                                   data={"CHANNEL1": CHANNELS[0],
-                                         "CHANNEL2": CHANNELS[1],
-                                         "CHANNEL3": CHANNELS[0],
-                                         "CHANNEL4": CHANNELS[1]})
+@pytest.mark.parametrize('dtype', ['ts', 'lc'])
+def test_remove_lytaf_events_from_timeseries(dtype):
+    """Test if artefacts are correctly removed from a TimeSeries.
+    Also test LYRALightCurve for backwards compatibility."""
     # Check correct errors are raised due to bad input
-    with pytest.raises(TypeError):
-        lyralc_test = lyra.remove_lytaf_events_from_lightcurve(
+    with pytest.raises(AttributeError):
+        ts_test = lyra.remove_lytaf_events_from_timeseries(
             [], lytaf_path=TEST_DATA_PATH, force_use_local_lytaf=True)
 
-    # Run remove_artifacts_from_lyralightcurve, returning artifact
+    # Run remove_artifacts_from_timeseries, returning artifact
     # status
-    lyralc_test, artifact_status_test = \
-      lyra.remove_lytaf_events_from_lightcurve(
-          lyralc, artifacts=["LAR", "Offpoint"], return_artifacts=True,
-          lytaf_path=TEST_DATA_PATH, force_use_local_lytaf=True)
+    ts = get_lyradata(dtype)
+    ts_test, artifact_status_test = \
+        lyra.remove_lytaf_events_from_timeseries(
+            ts, artifacts=["LAR", "Offpoint"], return_artifacts=True,
+            lytaf_path=TEST_DATA_PATH, force_use_local_lytaf=True)
     # Generate expected data by calling _remove_lytaf_events and
     # constructing expected dataframe manually.
     time, channels, artifact_status_expected = lyra._remove_lytaf_events(
-        lyralc.data.index, channels=[np.asanyarray(lyralc.data["CHANNEL1"]),
-                                     np.asanyarray(lyralc.data["CHANNEL2"]),
-                                     np.asanyarray(lyralc.data["CHANNEL3"]),
-                                     np.asanyarray(lyralc.data["CHANNEL4"])],
+        ts.data.index, channels=[np.asanyarray(ts.data["CHANNEL1"]),
+                                 np.asanyarray(ts.data["CHANNEL2"]),
+                                 np.asanyarray(ts.data["CHANNEL3"]),
+                                 np.asanyarray(ts.data["CHANNEL4"])],
         artifacts=["LAR", "Offpoint"], return_artifacts=True,
         lytaf_path=TEST_DATA_PATH, force_use_local_lytaf=True)
     dataframe_expected = pandas.DataFrame(index=time,
@@ -117,7 +137,7 @@ def test_remove_lytaf_events_from_lightcurve():
                                                 "CHANNEL3": channels[2],
                                                 "CHANNEL4": channels[3]})
     # Assert expected result is returned
-    pandas.util.testing.assert_frame_equal(lyralc_test.data, dataframe_expected)
+    pandas.util.testing.assert_frame_equal(ts_test.data, dataframe_expected)
     assert artifact_status_test.keys() == artifact_status_expected.keys()
     np.testing.assert_array_equal(artifact_status_test["lytaf"],
                                   artifact_status_expected["lytaf"])
@@ -126,26 +146,26 @@ def test_remove_lytaf_events_from_lightcurve():
     np.testing.assert_array_equal(artifact_status_test["not_removed"],
                                   artifact_status_expected["not_removed"])
     assert artifact_status_test["not_found"] == \
-      artifact_status_expected["not_found"]
+        artifact_status_expected["not_found"]
 
-    # Run remove_artifacts_from_lyralightcurve, without returning
+    # Run remove_artifacts_from_timeseries, without returning
     # artifact status
-    lyralc_test = \
-      lyra.remove_lytaf_events_from_lightcurve(
-          lyralc, artifacts=["LAR", "Offpoint"],
-          lytaf_path=TEST_DATA_PATH, force_use_local_lytaf=True)
+    ts_test = \
+        lyra.remove_lytaf_events_from_timeseries(
+            ts, artifacts=["LAR", "Offpoint"],
+            lytaf_path=TEST_DATA_PATH, force_use_local_lytaf=True)
     # Assert expected result is returned
-    pandas.util.testing.assert_frame_equal(lyralc_test.data, dataframe_expected)
+    pandas.util.testing.assert_frame_equal(ts_test.data, dataframe_expected)
 
 
 def test_remove_lytaf_events_1():
     """Test _remove_lytaf_events() with some artifacts found and others not."""
     # Run _remove_lytaf_events
     time_test, channels_test, artifacts_status_test = \
-      lyra._remove_lytaf_events(
-          TIME, channels=CHANNELS, artifacts=["LAR", "Offpoint"],
-          return_artifacts=True, lytaf_path=TEST_DATA_PATH,
-          force_use_local_lytaf=True)
+        lyra._remove_lytaf_events(
+            TIME, channels=CHANNELS, artifacts=["LAR", "Offpoint"],
+            return_artifacts=True, lytaf_path=TEST_DATA_PATH,
+            force_use_local_lytaf=True)
     # Generated expected result
     bad_indices = np.logical_and(TIME >= LYTAF_TEST["begin_time"][0],
                                  TIME <= LYTAF_TEST["end_time"][0])
@@ -168,16 +188,16 @@ def test_remove_lytaf_events_1():
     np.testing.assert_array_equal(artifacts_status_test["not_removed"],
                                   artifacts_status_expected["not_removed"])
     assert artifacts_status_test["not_found"] == \
-      artifacts_status_expected["not_found"]
+        artifacts_status_expected["not_found"]
 
     # Test that correct values are returned when channels kwarg not
     # supplied.
     # Run _remove_lytaf_events
     time_test, artifacts_status_test = \
-      lyra._remove_lytaf_events(
-          TIME, artifacts=["LAR", "Offpoint"],
-          return_artifacts=True, lytaf_path=TEST_DATA_PATH,
-          force_use_local_lytaf=True)
+        lyra._remove_lytaf_events(
+            TIME, artifacts=["LAR", "Offpoint"],
+            return_artifacts=True, lytaf_path=TEST_DATA_PATH,
+            force_use_local_lytaf=True)
     # Assert test values are same as expected
     assert time_test.all() == time_expected.all()
     assert artifacts_status_test.keys() == artifacts_status_expected.keys()
@@ -188,17 +208,17 @@ def test_remove_lytaf_events_1():
     np.testing.assert_array_equal(artifacts_status_test["not_removed"],
                                   artifacts_status_expected["not_removed"])
     assert artifacts_status_test["not_found"] == \
-      artifacts_status_expected["not_found"]
+        artifacts_status_expected["not_found"]
 
 
 def test_remove_lytaf_events_2():
     """Test _remove_lytaf_events() with no user artifacts found."""
     # Run _remove_lytaf_events
     time_test, channels_test, artifacts_status_test = \
-      lyra._remove_lytaf_events(
-          TIME, channels=CHANNELS, artifacts="Offpoint",
-          return_artifacts=True, lytaf_path=TEST_DATA_PATH,
-          force_use_local_lytaf=True)
+        lyra._remove_lytaf_events(
+            TIME, channels=CHANNELS, artifacts="Offpoint",
+            return_artifacts=True, lytaf_path=TEST_DATA_PATH,
+            force_use_local_lytaf=True)
     # Generated expected result
     time_expected = TIME
     channels_expected = CHANNELS
@@ -217,7 +237,7 @@ def test_remove_lytaf_events_2():
     np.testing.assert_array_equal(artifacts_status_test["not_removed"],
                                   artifacts_status_expected["not_removed"])
     assert artifacts_status_test["not_found"] == \
-      artifacts_status_expected["not_found"]
+        artifacts_status_expected["not_found"]
 
     # Test correct values are returned when return_artifacts kwarg not
     # supplied.
@@ -236,6 +256,7 @@ def test_remove_lytaf_events_2():
         lytaf_path=TEST_DATA_PATH, force_use_local_lytaf=True)
     assert time_test.all() == time_expected.all()
 
+
 def test_remove_lytaf_events_3():
     """Test if correct errors are raised by _remove_lytaf_events()."""
     with pytest.raises(TypeError):
@@ -252,10 +273,11 @@ def test_remove_lytaf_events_3():
                                   force_use_local_lytaf=True)
     with pytest.raises(ValueError):
         lyra._remove_lytaf_events(TIME,
-                                  artifacts=["LAR","incorrect artifact type"],
+                                  artifacts=["LAR", "incorrect artifact type"],
                                   lytaf_path=TEST_DATA_PATH,
                                   force_use_local_lytaf=True)
 
+
 def test_get_lytaf_events():
     """Test if LYTAF events are correctly downloaded and read in."""
     # Run get_lytaf_events
@@ -363,7 +385,7 @@ def test_prep_columns():
 
     # Test case when channels supplied by user by not filecolumns
     string_time_test, filecolumns_test = lyra._prep_columns(time_input,
-                                                                channels_input)
+                                                            channels_input)
     np.testing.assert_array_equal(string_time_test, string_time_expected)
     assert filecolumns_test == filecolumns_expected
 
@@ -375,7 +397,7 @@ def test_prep_columns():
     # Test correct exceptions are raised
     with pytest.raises(TypeError):
         string_time_test, filecolumns_test = lyra._prep_columns(
-        time_input, channels_input, ["channel0", 1])
+            time_input, channels_input, ["channel0", 1])
     with pytest.raises(ValueError):
         string_time_test = lyra._prep_columns(time_input,
-                                          filecolumns=filecolumns_input)
+                                              filecolumns=filecolumns_input)