From 76866b33c7ab043e59600dab1ab30ab4245dd04b Mon Sep 17 00:00:00 2001
From: Romain Broucquart <romain.broucquart@synchrotron-soleil.fr>
Date: Thu, 16 Mar 2023 17:33:59 +0100
Subject: [PATCH] feat:Date parser can now recognize time delta, auto init at
 start

---
 ArchiveExtractor.py | 85 +++++++++++++++++++++++++++++----------------
 README.md           | 25 ++++++-------
 2 files changed, 66 insertions(+), 44 deletions(-)

diff --git a/ArchiveExtractor.py b/ArchiveExtractor.py
index 24f5cc3..2f3fa64 100755
--- a/ArchiveExtractor.py
+++ b/ArchiveExtractor.py
@@ -57,14 +57,16 @@ def _check_initialized():
 ##----------------------------------------------------------------------##
 def _dateparse(datestr):
     """
-    Convenient function to parse date strings.
-    Global format is %Y-%m-%d-%H:%M:%S and it can be reduced to be less precise.
+    Convenient function to parse date or duration strings.
+    Exact date format is %Y-%m-%d-%H:%M:%S and it can be reduced to be less precise.
+    Duration format is 'Xu' where X is a number and u is a unit in ('m':minutes, 'h':hours, 'd':days, 'M':months)
     If datstr is None, take the actual date and time.
 
     Parameters
     ---------
     datestr : string
         Date as a string, format %Y-%m-%d-%H:%M:%S or less precise.
+        Duration as a string, format 'Xu' where X is a number and u is a unit in ('m':minutes, 'h':hours, 'd':days, 'M':months)
 
     Exceptions
     ----------
@@ -73,35 +75,52 @@ def _dateparse(datestr):
 
     Returns
     -------
-    date : datetime.datetime
-        Parsed date
+    date : datetime.datetime or datetime.timedelta
+        Parsed date or duration
     """
+    logger.debug("Parsing date string '%s'"%datestr)
+
+    # Determine date/duration by looking at the last char
+    if datestr[-1] in "mhdM":
+        # Duration
+        logger.debug("Assuming a duration")
 
-    if datestr is None:
-        return datetime.datetime.now()
-
-    # This gives all format that will be tried, in order.
-    # Stop on first parse success. Raise error if none succeed.
-    fmt = [
-        "%Y-%m-%d-%H:%M:%S",
-        "%Y-%m-%d-%H:%M",
-        "%Y-%m-%d-%H",
-        "%Y-%m-%d",
-        "%Y-%m",
-        ]
-
-    date = None
-    for f in fmt:
         try:
-            date = datetime.datetime.strptime(datestr, f)
-        except ValueError:
-            continue
-        else:
-            break
+            q=float(datestr[:-1])
+        except ValueError as e:
+            logger.error("Failed to parse date string. Given the last character, a duration was assumed.")
+            raise Exception("Could not parse argument to a date") from e
+
+        # Convert all in minutes
+        minutes = q*{'m':1, 'h':60, 'd':60*24, 'm':30*60*24}[datestr[-1]]
+
+        return datetime.timedelta(minutes=minutes)
+
     else:
-        raise ValueError("Could not parse argument to a date")
+        # Probably a date string
+
+        # This gives all format that will be tried, in order.
+        # Stop on first parse success. Raise error if none succeed.
+        fmt = [
+            "%Y-%m-%d-%H:%M:%S",
+            "%Y-%m-%d-%H:%M",
+            "%Y-%m-%d-%H",
+            "%Y-%m-%d",
+            "%Y-%m",
+            ]
+
+        date = None
+        for f in fmt:
+            try:
+                date = datetime.datetime.strptime(datestr, f)
+            except ValueError:
+                continue
+            else:
+                break
+        else:
+            raise ValueError("Could not parse argument to a date")
 
-    return date
+        return date
 
 ##----------------------------------------------------------------------##
 def _check_attribute(attribute, db):
@@ -243,11 +262,13 @@ def init(
     Initialize the module.
     Instanciate tango.DeviceProxy for extractors (TDB and HDB)
 
-        HdbExtractorPath, TdbExtractorPath: string
-            Tango path to the extractors.
+    Parameters:
+    -----------
+    HdbExtractorPath, TdbExtractorPath: string
+        Tango path to the extractors.
 
-        loglevel: string
-            loglevel to pass to logging.Logger
+    loglevel: string
+        loglevel to pass to logging.Logger
     """
     global _extractors
     global _AttrTables
@@ -641,3 +662,7 @@ def ExtrBetweenDates_MinMaxMean(
                 "Max":value_max,
                 },)
 
+## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
+## Initialize on import
+## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
+init()
diff --git a/README.md b/README.md
index 64b7954..4098332 100644
--- a/README.md
+++ b/README.md
@@ -13,12 +13,9 @@ Usage example, with an ipython prompt
 ```python
 In [1]: import pySoleilControl.ArchiveExtractor as AE
 
-In [2]: # For now, we need manual initialization of the module
-   ...: AE.init()
-
-In [3]: # Looking for an attribute in HDB
+In [2]: # Looking for an attribute in HDB
    ...: AE.findattr("ans/dg/*dcct*")
-Out[3]: 
+Out[2]: 
 ['ANS/DG/DCCT-CTRL/State',
  'ANS/DG/DCCT-CTRL/Status',
  'ANS/DG/DCCT-CTRL/current',
@@ -26,10 +23,10 @@ Out[3]:
  'ANS/DG/DCCT-CTRL/lifeTime',
  'ANS/DG/DCCT-CTRL/lifeTimeErr']
 
-In [4]: # Get data between two dates, this return a pandas.Dataframe object
+In [3]: # Get data between two dates, this return a pandas.Dataframe object
    ...: AE.ExtrBetweenDates('ANS/DG/DCCT-CTRL/current', '2021-12-13', '2021-12-13-12:00')
 INFO:Perform ExtractBetweenDates (ans/dg/dcct-ctrl/current, 2021-12-13 00:00:00, 2021-12-13 12:00:00)
-Out[4]: 
+Out[3]: 
 2021-12-13 00:00:00    450.993568
 2021-12-13 00:00:01    450.981979
 2021-12-13 00:00:02    450.971455
@@ -43,11 +40,11 @@ Out[4]:
 2021-12-13 12:00:00     15.005410
 Length: 42725, dtype: float64
 
-In [5]: # Get min, max and mean with a 10 minute window
+In [4]: # Get min, max and mean with a 10 minute window
    ...: d=AE.ExtrBetweenDates_MinMaxMean('ANS/DG/DCCT-CTRL/current', '2021-12-13', '2021-12-13-12:00', timeInterval='10m')
 
-In [6]: d
-Out[6]: 
+In [5]: d
+Out[5]: 
                             Min        Mean         Max
 2021-12-13 00:05:00  449.762286  450.619654  451.617095
 2021-12-13 00:15:00  449.761171  450.676306  451.595391
@@ -64,14 +61,14 @@ Out[6]:
 [72 rows x 3 columns]
 
 
-In [7]: # Activate inline matplotlib
+In [6]: # Activate inline matplotlib
    ...: %matplotlib
 Using matplotlib backend: TkAgg
 
-In [7]: # Simply plot
+In [6]: # Simply plot
    ...: d.plot()
 
-In [8]: # ipython prompt supports autocompletion. The doc of function can be quickly read by adding a '?'
+In [7]: # ipython prompt supports autocompletion. The doc of function can be quickly read by adding a '?'
     ...: AE.ExtrBetweenDates?
 Signature: AE.ExtrBetweenDates(attribute, dateStart, dateStop=None, db='H')
 Docstring:
@@ -114,4 +111,4 @@ Type:      function
 
 
 
-```
\ No newline at end of file
+```
-- 
GitLab