[Scipy-svn] r2633 - in trunk/Lib/sandbox/timeseries: . examples tests

scipy-svn at scipy.org scipy-svn at scipy.org
Mon Jan 29 22:08:36 CST 2007


Author: pierregm
Date: 2007-01-29 22:08:29 -0600 (Mon, 29 Jan 2007)
New Revision: 2633

Modified:
   trunk/Lib/sandbox/timeseries/.project
   trunk/Lib/sandbox/timeseries/examples/example.py
   trunk/Lib/sandbox/timeseries/examples/example.wiki
   trunk/Lib/sandbox/timeseries/tcore.py
   trunk/Lib/sandbox/timeseries/tdates.py
   trunk/Lib/sandbox/timeseries/tests/test_dates.py
   trunk/Lib/sandbox/timeseries/tests/test_misc.py
   trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py
   trunk/Lib/sandbox/timeseries/tests/test_timeseries.py
   trunk/Lib/sandbox/timeseries/tmulti.py
   trunk/Lib/sandbox/timeseries/tseries.py
Log:
fixed freq/freqstr
force DateArray singletons to shape (1,)
misc. improvements on tshift

Modified: trunk/Lib/sandbox/timeseries/.project
===================================================================
--- trunk/Lib/sandbox/timeseries/.project	2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/.project	2007-01-30 04:08:29 UTC (rev 2633)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-	<name>timeseries</name>
+	<name>scipy_svn_timeseries</name>
 	<comment></comment>
 	<projects>
 	</projects>

Modified: trunk/Lib/sandbox/timeseries/examples/example.py
===================================================================
--- trunk/Lib/sandbox/timeseries/examples/example.py	2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/examples/example.py	2007-01-30 04:08:29 UTC (rev 2633)
@@ -14,15 +14,20 @@
 TD.Date('D', mxDate=datetime.datetime.now())
 mybirthday = D-1
 infivemonths = M + 5
+mybirthday.asfreq('M')
+mybirthday.asfreq('M').asfreq('D')
 data = N.random.uniform(-100,100,600)
 today = TD.thisday('B')
 series = TS.time_series(data, dtype=N.float_, freq='B', observed='SUMMED',
                         start_date=today-600)
+isinstance(series.dates, TD.DateArray)
+isinstance(series.series, MA.MaskedArray)
 series[0]
 series[-30:]
 thirtydaysago = today - 30
 series[thirtydaysago:]
 series[thirtydaysago.tostring():]
+series[[0,-1]]
 series[series<0] = 0
 series[series.day_of_week == 4] = 100
 weekdays = TD.day_of_week(series)
@@ -32,14 +37,14 @@
 mlist_1 += ['2006-%02i' % i for i in range(2,13)]
 mdata_1 = N.arange(len(mlist_1))
 mser_1 = TS.time_series(mdata_1, mlist_1, observed='SUMMED')
-mser = mser1.asfreq('M')
-mser1.has_duplicated_dates()
-mser1.has_missing_dates()
+mser_1 = mser_1.asfreq('M')
+mser_1.has_duplicated_dates()
+mser_1.has_missing_dates()
 mlist_2 = ['2004-%02i' % i for i in range(1,13)]
 mlist_2 += ['2005-%02i' % i for i in range(1,13)]
 mser_2 = TS.time_series(N.arange(len(mlist_2)), mlist_2, observed='SUMMED')
-mser_3 = mser_1 + mser_2
-(malg_1,malg_2) = aligned(mser_1, mser_2) 
+#mser_3 = mser_1 + mser_2
+(malg_1,malg_2) = TS.aligned(mser_1, mser_2) 
 mser_1_filled = fill_missing_dates(mser_1)
 (malg_1,malg_2) = align_series(mser_1_filled, mser_2) 
 mser_3 = malg_1 + malg_2

Modified: trunk/Lib/sandbox/timeseries/examples/example.wiki
===================================================================
--- trunk/Lib/sandbox/timeseries/examples/example.wiki	2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/examples/example.wiki	2007-01-30 04:08:29 UTC (rev 2633)
@@ -89,20 +89,26 @@
 
 To construct a `DateArray` object, you can call the class directly
 {{{#!python numbers=disable
+DateArray(dates=None, freq='U', copy=False)
 }}}
+where `dates` can be ''(i)'' an existing `DateArray`; ''(ii)'' a sequence of `Date` objects; ''(iii)''' a sequence of objects that `Date` can recognize (such as strings, integers, `mx.DateTime` objects...).
+Alternatively, you can use the `date_array` constructor:
+{{{#!python numbers=disable
+date_array(dlist=None, start_date=None, end_date=None, 
+           include_last=True, length=None,  freq=None)
+}}}
+If `dlist` is None, a new list of dates will be created from `start_date` and `end_date`. You should set `include_last` to True if you want `end_date` to be included. If `end_date` is None, then a series of length `length` will be created.
 
 
-
 ----
 
 == TimeSeries ==
 
 A `TimeSeries` object is the combination of three ndarrays:
-
     * `dates`: DateArray object.
     * `data` : ndarray.
     * `mask` : Boolean ndarray, indicating missing or invalid data.
-    
+These three arrays can be accessed as attributes of a TimeSeries object. Another very useful attribute is `series`, that gives you the possibility to directly access `data` and `mask` as a masked array.
 
 ==== Construction ====
 
@@ -131,7 +137,16 @@
 >>> series = TS.time_series(data, dtype=N.float_, freq='B', observed='SUMMED',
 >>>                         start_date=today-600)
 }}}
+We can check that `series.dates` is a `DateArray` object and that `series.series` is a `MaskedArray` object.
+{{{#!python numbers=disable
+>>> isinstance(series.dates, TD.DateArray)
+True
+>>> isinstance(series.series, MA.MaskedArray)
+True
+}}}
+So, if you are already familiar with `MaskedArray`, using `TimeSeries` should be straightforward. Just keep in mind that another attribute is always present, `dates`.
 
+
 ==== Indexing ====
 
 Elements of a TimeSeries can be accessed just like with regular ndarrrays. Thus,
@@ -153,6 +168,11 @@
 {{{#!python numbers=disable
 >>> series[thirtydaysago.tostring():]
 }}}
+or a sequence/ndarray of integers... 
+{{{#!python numbers=disable
+>>> series[[0,-1]]
+}}}
+~-This latter is quite useful: it gives you the first and last data of your series.-~
 
 In a similar way, setting elements of a TimeSeries works seamlessly.
 Let us set negative values to zero...
@@ -190,16 +210,20 @@
 }}}
 Note that the frequency is 'U', for undefined. In fact, you have to specify what kind of data is actually missing by forcing a given frequency.
 {{{#!python numbers=disable
->>> mser = mser1.asfreq('M')
+>>> mser = mser_1.asfreq('M')
 }}}
 Let us check whether there are some duplicated dates (no):
 {{{#!python numbers=disable
->>> mser1.has_duplicated_dates()
+>>> mser_1.has_duplicated_dates()
+False
 }}}
 ...or missing dates (yes):
 {{{#!python numbers=disable
->>> mser1.has_missing_dates()
+>>> mser_1.has_missing_dates()
+True
 }}}
+
+
 Let us construct a second monthly series, this time without missing dates
 {{{#!python numbers=disable
 >>> mlist_2 = ['2004-%02i' % i for i in range(1,13)]
@@ -227,7 +251,7 @@
 {{{#!python numbers=disable
 >>> mser_3 = filled(malg_1,0) + filled(malg_2,0)
 }}}
-Alternatively, we can force the series to start/end at some given dates
+When aligning the series, we could have forced the series to start/end at some given dates:
 {{{#!python numbers=disable
 >>> (malg_1,malg_2) = aligned(mser_1_filled, mser2, 
 >>>                           start_date='2004-06', end_date='2006-06')

Modified: trunk/Lib/sandbox/timeseries/tcore.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tcore.py	2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tcore.py	2007-01-30 04:08:29 UTC (rev 2633)
@@ -81,87 +81,114 @@
         raise ValueError("Invalid value for observed attribute: %s " % str(obStr))
 
 
-fmtfreq_dict = {'A': ['ANNUAL','ANNUALLY','YEAR','YEARLY'],
-                'B': ['BUSINESS','BUSINESSLYT'],
-                'D': ['DAY','DAILY',],
-                'H': ['HOUR','HOURLY',],
-                'M': ['MONTH','MONTHLY',],
-                'Q': ['QUARTER','QUARTERLY',],
-                'S': ['SECOND','SECONDLY',],
-                'T': ['MINUTE','MINUTELY',],
-                'W': ['WEEK','WEEKLY',],
-                'U': ['UNDEF','UNDEFINED'],
+
+freq_dict = { 1000: ['A','Y','ANNUAL','ANNUALLY','YEAR','YEARLY'],
+              2000: ['Q','QUARTER','QUARTERLY',],
+              3000: ['M','MONTH','MONTHLY',],
+              4000: ['W','WEEK','WEEKLY',],
+              5000: ['B','BUSINESS','BUSINESSLYT'],
+              6000: ['D','DAY','DAILY',],
+              7000: ['H','HOUR','HOURLY',],
+              8000: ['T','MINUTE','MINUTELY',],
+              9000: ['S','SECOND','SECONDLY',],
+             -9999: ['U','UNDEF','UNDEFINED'],
                 }
-fmtfreq_revdict = reverse_dict(fmtfreq_dict)
+freq_revdict = reverse_dict(freq_dict)
 
-def fmtFreq (freqStr):
+def freq_fromstr(freq_asstr):
+    "Converts a frequency given as string to the corresponding integer."
+    freq_asstr = freq_asstr.upper()
+    if freq_asstr not in freq_revdict.keys():
+        raise ValueError, "Invalid frequency string %s" % freq_asstr
+    return freq_revdict[freq_asstr]
+    
+def freq_tostr(freq_asint):
+    "Converts a frequency given as integer to the corresponding symbol."
+    if freq_asint not in freq_dict.keys():
+        raise ValueError, "Invalid frequency representation %s" % freq_asint
+    return freq_dict[freq_asint][0]
+
+def check_freq(freq):
     "Converts a possible 'frequency' string to acceptable values."
-    if freqStr is None:
-        return None    
-    elif freqStr.upper() in fmtfreq_dict.keys():
-        return freqStr[0].upper()
-    elif freqStr.upper() in fmtfreq_revdict.keys():
-        return fmtfreq_revdict[freqStr.upper()]
+    if freq is None:
+        return None
+    elif isinstance(freq, int):
+        if freq not in freq_dict.keys():
+            raise ValueError("Invalid frequency: %s " % str(freq))
+        return freq
+    elif freq.upper() in freq_revdict.keys():
+        return freq_revdict[freq.upper()]
     else:
-        raise ValueError("Invalid frequency: %s " % str(freqStr))
-        
-class DateSpec:
-    "Fake data type for date variables."
-    def __init__(self, freq):
-        self.freq = fmtFreq(freq)
-        
-    def __hash__(self): 
-        return hash(self.freq)
+        raise ValueError("Invalid frequency: %s " % str(freq))
     
-    def __eq__(self, other):
-        if hasattr(other, "freq"): 
-            return self.freq == other.freq
-        else: 
-            return False
-    def __str__(self): 
-        return "Date(%s)" % str(self.freq)
-    
-    
-
-# define custom numpy types.
-# Note: A more robust approach would register these as actual valid numpy types
-# this is just a hack for now
-numpy.dateA = DateSpec("Annual")
-numpy.dateB = DateSpec("Business")
-numpy.dateD = DateSpec("Daily")
-numpy.dateH = DateSpec("Hourly")
-numpy.dateM = DateSpec("Monthly")
-numpy.dateQ = DateSpec("Quarterly")
-numpy.dateS = DateSpec("Secondly")
-numpy.dateT = DateSpec("Minutely")
-numpy.dateW = DateSpec("Weekly")
-numpy.dateU = DateSpec("Undefined")
-
-
-freq_type_mapping = {'A': numpy.dateA,
-                     'B': numpy.dateB,
-                     'D': numpy.dateD,
-                     'H': numpy.dateH,
-                     'M': numpy.dateM,
-                     'Q': numpy.dateQ,
-                     'S': numpy.dateS,
-                     'T': numpy.dateT,
-                     'W': numpy.dateW,
-                     'U': numpy.dateU,
-                     }
+def check_freqstr(freq):
+    if freq is None:
+        return None
+    elif isinstance(freq, int):
+        if freq not in freq_dict.keys():
+            raise ValueError("Invalid frequency: %s " % str(freq))
+        return freq_dict[freq][0]
+    elif freq.upper() in freq_revdict.keys():
+        return freq_dict[freq_revdict[freq.upper()]][0]
+    else:
+        raise ValueError("Invalid frequency: %s " % str(freq))    
+fmtFreq = check_freqstr
         
-def freqToType(freq):
-    "Returns the Date dtype corresponding to the given frequency."
-    return freq_type_mapping[fmtFreq(freq)]
+#class DateSpec:
+#    "Fake data type for date variables."
+#    def __init__(self, freq):
+#        self.freq = fmtFreq(freq)
+#        
+#    def __hash__(self): 
+#        return hash(self.freq)
+#    
+#    def __eq__(self, other):
+#        if hasattr(other, "freq"): 
+#            return self.freq == other.freq
+#        else: 
+#            return False
+#    def __str__(self): 
+#        return "Date(%s)" % str(self.freq) 
+#
+## define custom numpy types.
+## Note: A more robust approach would register these as actual valid numpy types
+## this is just a hack for now
+#numpy.dateA = DateSpec("Annual")
+#numpy.dateB = DateSpec("Business")
+#numpy.dateD = DateSpec("Daily")
+#numpy.dateH = DateSpec("Hourly")
+#numpy.dateM = DateSpec("Monthly")
+#numpy.dateQ = DateSpec("Quarterly")
+#numpy.dateS = DateSpec("Secondly")
+#numpy.dateT = DateSpec("Minutely")
+#numpy.dateW = DateSpec("Weekly")
+#numpy.dateU = DateSpec("Undefined")
+#
+#
+#freq_type_mapping = {'A': numpy.dateA,
+#                     'B': numpy.dateB,
+#                     'D': numpy.dateD,
+#                     'H': numpy.dateH,
+#                     'M': numpy.dateM,
+#                     'Q': numpy.dateQ,
+#                     'S': numpy.dateS,
+#                     'T': numpy.dateT,
+#                     'W': numpy.dateW,
+#                     'U': numpy.dateU,
+#                     }
+#        
+#def freqToType(freq):
+#    "Returns the Date dtype corresponding to the given frequency."
+#    return freq_type_mapping[fmtFreq(freq)]
+#
+#def isDateType(dtype):
+#    "Returns True whether the argument is the dtype of a Date."
+#    #TODO: That looks messy. We should simplify that
+#    if len([x for x in freq_type_mapping.values() if x == dtype]) > 0: 
+#        return True
+#    else: 
+#        return False
 
-def isDateType(dtype):
-    "Returns True whether the argument is the dtype of a Date."
-    #TODO: That looks messy. We should simplify that
-    if len([x for x in freq_type_mapping.values() if x == dtype]) > 0: 
-        return True
-    else: 
-        return False
-
 #####---------------------------------------------------------------------------
 #---- --- Misc functions ---
 #####---------------------------------------------------------------------------

Modified: trunk/Lib/sandbox/timeseries/tdates.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tdates.py	2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tdates.py	2007-01-30 04:08:29 UTC (rev 2633)
@@ -32,10 +32,6 @@
 import cseries
 
 
-import logging
-logging.basicConfig(level=logging.DEBUG,format='%(name)-15s %(levelname)s %(message)s',)
-daflog = logging.getLogger('darray_from')
-dalog = logging.getLogger('DateArray')
 
 
 __all__ = [
@@ -116,38 +112,54 @@
       >>> td.Date('D', mxDate=mx.DateTime.now())
       >>> td.Date('D', mxDate=datetime.datetime.now())
       """
-    def __init__(self, freq, year=None, month=None, day=None, quarter=None, 
+    default_fmtstr = {'A': "%Y",
+                      'Q': "%YQ%q",
+                      'M': "%b-%Y",
+                      'W': "%d-%b-%y",
+                      'B': "%d-%b-%Y",
+                      'D': "%d-%b-%Y",
+                      'U': "%d-%b-%Y",
+                      'H': "%d-%b-%Y %H:00",
+                      'T': "%d-%b-%Y %H:%M",
+                      'S': "%d-%b-%Y %H:%M:%S"
+                      }
+      
+    def __init__(self, freq, value=None, string=None,
+                 year=None, month=None, day=None, quarter=None, 
                  hour=None, minute=None, second=None, 
-                 mxDate=None, value=None, string=None):
+                 mxDate=None):
         
         if hasattr(freq, 'freq'):
-            self.freq = corelib.fmtFreq(freq.freq)
+            self.freq = corelib.check_freq(freq.freq)
         else:
-            self.freq = corelib.fmtFreq(freq)
-        self.freqstr = self.freq
+            self.freq = corelib.check_freq(freq)
+        self.freqstr = corelib.freq_tostr(self.freq)
         
         if value is not None:
-            if self.freq == 'A':
+            if isinstance(value, str):
+                self.mxDate = mxDFromString(string)
+            elif self.freqstr == 'A':
                 self.mxDate = mxD.Date(value, -1, -1)
-            elif self.freq == 'B':
+            elif self.freqstr == 'B':
                 valtmp = (value - 1)//5
-                self.mxDate = mxD.DateTimeFromAbsDateTime(value + valtmp*7 - valtmp*5)
-            elif self.freq in ['D','U']:
+                #... (value + valtmp*7 - valtmp*5)
+                self.mxDate = mxD.DateTimeFromAbsDateTime(value + valtmp*2)
+            elif self.freqstr in ['D','U']:
                 self.mxDate = mxD.DateTimeFromAbsDateTime(value)
-            elif self.freq == 'H':
+            elif self.freqstr == 'H':
                 self.mxDate = hourlyOriginDate + mxD.DateTimeDeltaFrom(hours=value)
-            elif self.freq == 'M':
+            elif self.freqstr == 'M':
                 self.mxDate = mxD.DateTimeFromAbsDateTime(1) + \
                               mxD.RelativeDateTime(months=value-1, day=-1)
-            elif self.freq == 'Q':
+            elif self.freqstr == 'Q':
                 self.mxDate = mxD.DateTimeFromAbsDateTime(1) + \
                               mxD.RelativeDateTime(years=(value // 4), 
                                                    month=((value * 3) % 12), day=-1)
-            elif self.freq == 'S':
+            elif self.freqstr == 'S':
                 self.mxDate = secondlyOriginDate + mxD.DateTimeDeltaFromSeconds(value)
-            elif self.freq == 'T':
+            elif self.freqstr == 'T':
                 self.mxDate = minutelyOriginDate + mxD.DateTimeDeltaFrom(minutes=value)
-            elif self.freq == 'W':
+            elif self.freqstr == 'W':
                 self.mxDate = mxD.Date(1,1,7) + \
                               mxD.RelativeDateTime(weeks=value-1)
         
@@ -163,31 +175,31 @@
             # First, some basic checks.....
             if year is None:
                 raise InsufficientDateError            
-            if self.freq in ('B', 'D', 'W'):
+            if self.freqstr in 'BDWU':
                 if month is None or day is None: 
                     raise InsufficientDateError
-            elif self.freq == 'M':
+            elif self.freqstr == 'M':
                 if month is None: 
                     raise InsufficientDateError
                 day = -1
-            elif self.freq == 'Q':
+            elif self.freqstr == 'Q':
                 if quarter is None: 
                     raise InsufficientDateError
                 month = quarter * 3
                 day = -1
-            elif self.freq == 'A':
+            elif self.freqstr == 'A':
                 month = -1
                 day = -1
-            elif self.freq == 'S':
+            elif self.freqstr == 'S':
                 if month is None or day is None or second is None: 
                     raise InsufficientDateError
                 
-            if self.freq in ['A','B','D','M','Q','W']:
+            if self.freqstr in ['A','B','D','M','Q','W']:
                 self.mxDate = truncateDate(self.freq, mxD.Date(year, month, day))
-                if self.freq == 'B':
+                if self.freqstr == 'B':
                     if self.mxDate.day_of_week in [5,6]:
                         raise ValueError("Weekend passed as business day")
-            elif self.freq in ['H','S','T']:
+            elif self.freqstr in 'HTS':
                 if hour is None:
                     if minute is None:
                         if second is None:
@@ -205,7 +217,7 @@
                     second = 0
                 else:
                     second = second % 60
-                self.mxDate = truncateDate(self.freq,
+                self.mxDate = truncateDate(self.freqstr,
                                            mxD.Date(year, month, day, 
                                                     hour, minute, second))
         self.value = self.__value()
@@ -252,11 +264,13 @@
         return self.__getDateInfo('I')
         
     def __getDateInfo(self, info):
-        return int(cseries.getDateInfo(numpy.asarray(self.value), self.freq, info))
+        return int(cseries.getDateInfo(numpy.asarray(self.value), 
+                                       self.freqstr, info))
  
     def __add__(self, other):
         if isinstance(other, Date):
-            raise FrequencyDateError("Cannot add dates", self.freq, other.freq)
+            raise FrequencyDateError("Cannot add dates", 
+                                     self.freqstr, other.freqstr)
         return Date(freq=self.freq, value=int(self) + other)
     
     def __radd__(self, other): 
@@ -266,7 +280,7 @@
         if isinstance(other, Date):
             if self.freq != other.freq:
                 raise FrequencyDateError("Cannot subtract dates", \
-                                         self.freq, other.freq)
+                                         self.freqstr, other.freqstr)
             else:
                 return int(self) - int(other) 
         else:
@@ -276,16 +290,16 @@
         if not hasattr(other, 'freq'):
             return False
         elif self.freq != other.freq:
-            raise FrequencyDateError("Cannot subtract dates", \
-                                     self.freq, other.freq)
+            raise FrequencyDateError("Cannot compare dates", \
+                                     self.freqstr, other.freqstr)
         return int(self) == int(other) 
     
     def __cmp__(self, other): 
         if not hasattr(other, 'freq'):
             return False
         elif self.freq != other.freq:
-            raise FrequencyDateError("Cannot subtract dates", \
-                                     self.freq, other.freq)
+            raise FrequencyDateError("Cannot compare dates", \
+                                     self.freqstr, other.freqstr)
         return int(self)-int(other)    
         
     def __hash__(self): 
@@ -300,63 +314,41 @@
     def __value(self):   
         "Converts the date to an integer, depending on the current frequency."
         # Annual .......
-        if self.freq == 'A':
+        if self.freqstr == 'A':
             val = self.mxDate.year
         # Business days.
-        elif self.freq == 'B':
+        elif self.freqstr == 'B':
             days = self.mxDate.absdate
             weeks = days // 7
             val = days - weeks*2  
             # (weeks*5) + (days - weeks*7)
         # Daily/undefined
-        elif self.freq in ['D', 'U']:
+        elif self.freqstr in 'DU':
             val = self.mxDate.absdate
         # Hourly........
-        elif self.freq == 'H':
+        elif self.freqstr == 'H':
             val = (self.mxDate - hourlyOriginDate).hours
         # Monthly.......
-        elif self.freq == 'M':
+        elif self.freqstr == 'M':
             val = (self.mxDate.year-1)*12 + self.mxDate.month
         # Quarterly.....
-        elif self.freq == 'Q':
+        elif self.freqstr == 'Q':
             val = (self.mxDate.year-1)*4 + self.mxDate.month//3
         # Secondly......
-        elif self.freq == 'S':
+        elif self.freqstr == 'S':
             val = (self.mxDate - secondlyOriginDate).seconds
         # Minutely......
-        elif self.freq == 'T':
+        elif self.freqstr == 'T':
             val = (self.mxDate - minutelyOriginDate).minutes
         # Weekly........
-        elif self.freq == 'W':
+        elif self.freqstr == 'W':
             val = self.mxDate.absdate//7
         return int(val)
-    #......................................................
-    def default_fmtstr(self):
-        "Defines the default formats for printing Dates."
-        if self.freq == "A":
-            fmt =  "%Y"
-        elif self.freq in ("B","D"):
-            fmt =  "%d-%b-%Y"
-        elif self.freq == "M":
-            fmt =  "%b-%Y"
-        elif self.freq == "Q":
-            fmt =  "%YQ%q"
-        elif self.freq == 'H':
-            fmt = "%d-%b-%Y %H:00"
-        elif self.freq == 'T':
-            fmt = "%d-%b-%Y %H:%M"
-        elif self.freq == "S":
-            fmt =  "%d-%b-%Y %H:%M:%S"
-        elif self.freq == "W":
-            fmt =  "%YW%W"
-        else:
-            fmt = "%d-%b-%y"
-        return fmt
-        
+    #......................................................        
     def strfmt(self, fmt):
         "Formats the date"
         if fmt is None:
-            fmt = self.default_fmtstr()
+            fmt = self.default_fmtstr[self.freqstr]
         qFmt = fmt.replace("%q", "XXXX")
         tmpStr = self.mxDate.strftime(qFmt)
         if "XXXX" in tmpStr: 
@@ -364,10 +356,10 @@
         return tmpStr
             
     def __str__(self):
-        return self.strfmt(self.default_fmtstr())
+        return self.strfmt(self.default_fmtstr[self.freqstr])
 
     def __repr__(self): 
-        return "<%s : %s>" % (str(self.freq), str(self))
+        return "<%s : %s>" % (str(self.freqstr), str(self))
     #......................................................
     def toordinal(self):
         "Returns the date as an ordinal."
@@ -400,24 +392,24 @@
 #####---------------------------------------------------------------------------
 def truncateDate(freq, mxDate):
     """Chops off the irrelevant information from the mxDate passed in."""
-    freq = corelib.fmtFreq(freq)
-    if freq == 'A':
+    freqstr = corelib.check_freqstr(freq)
+    if freqstr == 'A':
         return mxD.Date(mxDate.year)
-    elif freq == 'Q':
+    elif freqstr == 'Q':
         return mxD.Date(mxDate.year, monthToQuarter(mxDate.month)*3)
-    elif freq == 'M':
+    elif freqstr == 'M':
         return mxD.Date(mxDate.year, mxDate.month)
-    elif freq == 'W':
+    elif freqstr == 'W':
         d = mxDate.absdate
         return mxD.DateTimeFromAbsDateTime(d + (7 - d % 7) % 7)
-    elif freq in ('B', 'D'):
+    elif freqstr in 'BD':
         if freq == 'B' and mxDate.day_of_week in [5,6]:
             raise ValueError("Weekend passed as business day")
         return mxD.Date(mxDate.year, mxDate.month, mxDate.day)
-    elif freq == 'H':
+    elif freqstr == 'H':
         return mxD.Date(mxDate.year, mxDate.month, mxDate.day, \
                         mxDate.hour)
-    elif freq == 'T':
+    elif freqstr == 'T':
         return mxD.Date(mxDate.year, mxDate.month, mxDate.day, \
                         mxDate.hour, mxDate.minute)
     else:
@@ -430,18 +422,18 @@
 
 def thisday(freq):
     "Returns today's date, at the given frequency `freq`."
-    freq = corelib.fmtFreq(freq)
+    freqstr = corelib.check_freqstr(freq)
     tempDate = mxD.now()
     # if it is Saturday or Sunday currently, freq==B, then we want to use Friday
-    if freq == 'B' and tempDate.day_of_week >= 5:
+    if freqstr == 'B' and tempDate.day_of_week >= 5:
         tempDate -= (tempDate.day_of_week - 4)
-    if freq in ('B','D','H','S','T','W'):
+    if freqstr in ('B','D','H','S','T','W','U'):
         return Date(freq, mxDate=tempDate)
-    elif freq == 'M':
+    elif freqstr == 'M':
         return Date(freq, year=tempDate.year, month=tempDate.month)
-    elif freq == 'Q':
+    elif freqstr == 'Q':
         return Date(freq, year=tempDate.year, quarter=monthToQuarter(tempDate.month))
-    elif freq == 'A':
+    elif freqstr == 'A':
         return Date(freq, year=tempDate.year)
 today = thisday
 
@@ -458,7 +450,7 @@
 def asfreq(date, toFreq, relation="BEFORE"):
     """Returns a date converted to another frequency `toFreq`, according to the
     relation `relation` ."""
-    tofreq = corelib.fmtFreq(toFreq)
+    tofreq = corelib.check_freqstr(toFreq)
     _rel = relation.upper()[0]
     if _rel not in ['B', 'A']:
         msg = "Invalid relation '%s': Should be in ['before', 'after']"
@@ -467,11 +459,11 @@
     if not isinstance(date, Date):
         raise DateError, "Date should be a valid Date instance!"
 
-    if date.freq == 'U':
+    if date.freqstr == 'U':
         warnings.warn("Undefined frequency: assuming daily!")
         fromfreq = 'D'
     else:
-        fromfreq = date.freq
+        fromfreq = date.freqstr
     
     if fromfreq == tofreq:
         return date
@@ -507,21 +499,20 @@
 accesses the array element by element. Therefore, `d` is a Date object.    
     """
     def __new__(cls, dates=None, freq='U', copy=False):
-        #logging.debug('DA:__new__ received %s [%i]" % (type(dates), numpy.size(dates)))
         if isinstance(dates, DateArray):
-            #logging.debug('DA:__new__ sends %s as %s" % (type(dates), cls))
             cls.__defaultfreq = dates.freq
             if not copy:
                 return dates.view(cls)
             return dates.copy().view(cls)
         else:
             _dates = numeric.asarray(dates, dtype=int_)
+            if _dates.ndim == 0:
+                _dates.shape = (1,)
             if copy:
                 _dates = _dates.copy()
-            #logging.debug('DA:__new__ sends %s as %s" % (type(_dates), cls))
             if freq is None:
                 freq = 'U'
-            cls.__defaultfreq = corelib.fmtFreq(freq)
+            cls.__defaultfreq = corelib.check_freq(freq)
             (cls.__toobj, cls.__toord, cls.__tostr) = (None, None, None)
             (cls.__steps, cls.__full, cls.__hasdups) = (None, None, None)
             return _dates.view(cls)
@@ -533,25 +524,22 @@
             raise ArithmeticDateError, "(function %s)" % context[0].__name__
     
     def __array_finalize__(self, obj):
-        #logging.debug('DA:__array_finalize__ received %s" % type(obj))
         if hasattr(obj, 'freq'):
             self.freq = obj.freq
             self.freqstr = obj.freqstr
         else:
             self.freq = self.__defaultfreq
-            self.freqstr = self.__defaultfreq
-        #logging.debug('DA:__array_finalize__ sends %s" % type(self))
+            self.freqstr = corelib.freq_tostr(self.__defaultfreq)
     
-    def __getitem__(self, index):
-        #logging.debug('DA:__getitem__ got  index %s (%s)"%(index, type(index)))
-        if isinstance(index, Date):
-            index = self.find_dates(index)
-        elif numeric.asarray(index).dtype.kind == 'O':
+    def __getitem__(self, indx):
+        if isinstance(indx, Date):
+            index = self.find_dates(indx)
+        elif numeric.asarray(indx).dtype.kind == 'O':
             try:
-                index = self.find_dates(index)       
+                indx = self.find_dates(indx)       
             except AttributeError:
                 pass     
-        r = ndarray.__getitem__(self, index)
+        r = ndarray.__getitem__(self, indx)
         if not hasattr(r, "size"):
             if isinstance(r, int): 
                 return Date(self.freq, value=r)
@@ -661,7 +649,7 @@
         tofreq = corelib.fmtFreq(freq)
         if tofreq == self.freq:
             return self        
-        if self.freq == 'U':
+        if self.freqstr == 'U':
             warnings.warn("Undefined frequency: assuming daily!")
             fromfreq = 'D'
         else:
@@ -709,14 +697,15 @@
                     self.__full = (steps.max() == 1)
                 if self.__hasdups is None:
                     self.__hasdups = (steps.min() == 0)
-            elif val.size == 1:
+            else:
+#            elif val.size == 1:
                 self.__full = True
                 self.__hasdups = False
                 steps = numeric.array([], dtype=int_)
-            else:
-                self.__full = False
-                self.__hasdups = False
-                steps = None
+#            else:
+#                self.__full = False
+#                self.__hasdups = False
+#                steps = None
             self.__steps = steps
         return self.__steps
     
@@ -758,7 +747,6 @@
         self._asdates = asdates
         self.__doc__ = getattr(methodname, '__doc__')
         self.obj = None
-        #logging.debug('DA:__datearithmetics got method %s' % methodname)
     #
     def __get__(self, obj, objtype=None):
         self.obj = obj
@@ -770,7 +758,6 @@
         freq = instance.freq
         if 'context' not in kwargs:
             kwargs['context'] = 'DateOK'
-        #logging.debug('DA:__datearithmetics got other %s' % type(other))
         method = getattr(super(DateArray,instance), self.methodname)
         if isinstance(other, DateArray):
             if other.freq != freq:
@@ -782,7 +769,6 @@
                 raise FrequencyDateError("Cannot operate on dates", \
                                          freq, other.freq)
             other = other.value
-            #logging.debug('DA:__datearithmetics got other %s' % type(other))
         elif isinstance(other, ndarray):
             if other.dtype.kind not in ['i','f']:
                 raise ArithmeticDateError
@@ -848,6 +834,8 @@
     "Constructs a DateArray from a list."
     dlist = numeric.asarray(dlist)
     dlist.sort()
+    if dlist.ndim == 0:
+        dlist.shape = (1,)
     # Case #1: dates as strings .................
     if dlist.dtype.kind == 'S':
         #...construct a list of ordinals
@@ -860,7 +848,7 @@
         #...construct a list of dates
         dates = [Date(freq, string=s) for s in dlist]
     # Case #2: dates as numbers .................
-    elif dlist.dtype.kind in ['i','f']:
+    elif dlist.dtype.kind in 'if':
         #...hopefully, they are values
         if freq is None:
             freq = guess_freq(dlist)
@@ -868,9 +856,17 @@
     # Case #3: dates as objects .................
     elif dlist.dtype.kind == 'O':
         template = dlist[0]
+#        if dlist.size > 1:
+#            template = dlist[0]
+#        else:
+#            template = dlist.item()
         #...as Date objects
         if isinstance(template, Date):
-            dates = numpy.fromiter((d.value for d in dlist), float_)
+            dates = numpy.fromiter((d.value for d in dlist), int_)
+#            if dlist.size > 1:
+#                dates = numpy.fromiter((d.value for d in dlist), int_)
+#            else:
+#                dates = [template]
         #...as mx.DateTime objects
         elif hasattr(template,'absdays'):
             # no freq given: try to guess it from absdays
@@ -880,7 +876,7 @@
                 freq = guess_freq(ords)
             dates = [Date(freq, mxDate=m) for m in dlist]
         #...as datetime objects
-        elif hasattr(dlist[0], 'toordinal'):
+        elif hasattr(template, 'toordinal'):
             ords = numpy.fromiter((d.toordinal() for d in dlist), float_)
             if freq is None:
                 freq = guess_freq(ords)
@@ -896,8 +892,7 @@
     - a starting date and either an ending date or a given length.
     - a list of dates.
     """
-    #TODO: make sure we can use a string for a date!
-    freq = corelib.fmtFreq(freq)
+    freq = corelib.check_freq(freq)
     # Case #1: we have a list ...................
     if dlist is not None:
         # Already a DateArray....................

Modified: trunk/Lib/sandbox/timeseries/tests/test_dates.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tests/test_dates.py	2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tests/test_dates.py	2007-01-30 04:08:29 UTC (rev 2633)
@@ -26,8 +26,9 @@
 from maskedarray.testutils import assert_equal, assert_array_equal
 
 from timeseries import tdates
+reload(tdates)
 from timeseries import tcore
-reload(tdates)
+reload(tcore)
 from timeseries.tdates import date_array_fromlist, Date, DateArray, mxDFromString
 
 class test_creation(NumpyTestCase):
@@ -41,33 +42,33 @@
         dlist = ['2007-01-%02i' % i for i in range(1,15)]
         # A simple case: daily data
         dates = date_array_fromlist(dlist, 'D')
-        assert_equal(dates.freq,'D')
+        assert_equal(dates.freqstr,'D')
         assert(dates.isfull())
         assert(not dates.has_duplicated_dates())
         assert_equal(dates, 732677+numpy.arange(len(dlist)))
         # as simple, but we need to guess the frequency this time
         dates = date_array_fromlist(dlist, 'D')
-        assert_equal(dates.freq,'D')
+        assert_equal(dates.freqstr,'D')
         assert(dates.isfull())
         assert(not dates.has_duplicated_dates())
         assert_equal(dates, 732677+numpy.arange(len(dlist)))
         # Still daily data, that we force to month
         dates = date_array_fromlist(dlist, 'M')
-        assert_equal(dates.freq,'M')
+        assert_equal(dates.freqstr,'M')
         assert(not dates.isfull())
         assert(dates.has_duplicated_dates())
         assert_equal(dates, [24073]*len(dlist))
         # Now, for monthly data
         dlist = ['2007-%02i' % i for i in range(1,13)]
         dates = date_array_fromlist(dlist, 'M')
-        assert_equal(dates.freq,'M')
+        assert_equal(dates.freqstr,'M')
         assert(dates.isfull())
         assert(not dates.has_duplicated_dates())
         assert_equal(dates, 24073 + numpy.arange(12))
         # Monthly data  w/ guessing
         dlist = ['2007-%02i' % i for i in range(1,13)]
         dates = date_array_fromlist(dlist, )
-        assert_equal(dates.freq,'M')
+        assert_equal(dates.freqstr,'M')
         assert(dates.isfull())
         assert(not dates.has_duplicated_dates())
         assert_equal(dates, 24073 + numpy.arange(12))
@@ -76,18 +77,18 @@
         "Tests creation from list of strings w/ missing dates"
         dlist = ['2007-01-%02i' % i for i in (1,2,4,5,7,8,10,11,13)]
         dates = date_array_fromlist(dlist)
-        assert_equal(dates.freq,'U')
+        assert_equal(dates.freqstr,'U')
         assert(not dates.isfull())
         assert(not dates.has_duplicated_dates())
         assert_equal(dates.tovalue(),732676+numpy.array([1,2,4,5,7,8,10,11,13]))
         #
         ddates = date_array_fromlist(dlist, 'D')
-        assert_equal(ddates.freq,'D')
+        assert_equal(ddates.freqstr,'D')
         assert(not ddates.isfull())
         assert(not ddates.has_duplicated_dates())
         #
         mdates = date_array_fromlist(dlist, 'M')
-        assert_equal(mdates.freq,'M')
+        assert_equal(mdates.freqstr,'M')
         assert(not dates.isfull())
         assert(mdates.has_duplicated_dates())
         #
@@ -105,7 +106,8 @@
 
     def test_consistent_value(self):
         "Tests that values don't get mutated when constructing dates from a value"
-        freqs = [x for x in list(tcore.fmtfreq_dict) if x != 'U']
+        freqs = [x[0] for x in tcore.freq_dict.values() if x[0] != 'U']
+        print freqs
         for f in freqs:
             today = tdates.thisday(f)
             assert(tdates.Date(freq=f, value=today.value) == today)

Modified: trunk/Lib/sandbox/timeseries/tests/test_misc.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tests/test_misc.py	2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tests/test_misc.py	2007-01-30 04:08:29 UTC (rev 2633)
@@ -2,11 +2,11 @@
 """Tests suite for miscellaneous functions in timeseries module.
 Adapted from the original test_ma by Pierre Gerard-Marchant
 
-:author: Matt Knox
-:contact: mattknox_ca_at_hotmail_dot_com
-:version: $Id: test_misc.py 2578 2007-01-17 19:25:10Z mattknox_ca $
+:author: Pierre Gerard-Marchant & Matt Knox
+:contact: pierregm_at_uga_dot_edu & mattknox_ca_at_hotmail_dot_com
+:version: $Id: test_timeseries.py 2578 2007-01-17 19:25:10Z mattknox_ca $
 """
-__author__ = "Matt Knox ($Author: mattknox_ca $)"
+__author__ = "Pierre GF Gerard-Marchant & Matt Knox ($Author: mattknox_ca $)"
 __version__ = '1.0'
 __revision__ = "$Revision: 2578 $"
 __date__     = '$Date: 2007-01-17 14:25:10 -0500 (Wed, 17 Jan 2007) $'

Modified: trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py	2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py	2007-01-30 04:08:29 UTC (rev 2633)
@@ -1,11 +1,11 @@
 # pylint: disable-msg=W0611, W0612, W0511,R0201
 """Tests suite for mrecarray.
 
-:author: Pierre Gerard-Marchant
-:contact: pierregm_at_uga_dot_edu
+:author: Pierre Gerard-Marchant & Matt Knox
+:contact: pierregm_at_uga_dot_edu  & mattknox_ca_at_hotmail_dot_com
 :version: $Id$
 """
-__author__ = "Pierre GF Gerard-Marchant ($Author$)"
+__author__ = "Pierre GF Gerard-Marchant & Matt Knox ($Author$)"
 __version__ = '1.0'
 __revision__ = "$Revision$"
 __date__     = '$Date$'

Modified: trunk/Lib/sandbox/timeseries/tests/test_timeseries.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tests/test_timeseries.py	2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tests/test_timeseries.py	2007-01-30 04:08:29 UTC (rev 2633)
@@ -2,11 +2,11 @@
 """Tests suite for MaskedArray.
 Adapted from the original test_ma by Pierre Gerard-Marchant
 
-:author: Pierre Gerard-Marchant
-:contact: pierregm_at_uga_dot_edu
+:author: Pierre Gerard-Marchant & Matt Knox 
+:contact: pierregm_at_uga_dot_edu & mattknox_ca_at_hotmail_dot_com
 :version: $Id$
 """
-__author__ = "Pierre GF Gerard-Marchant ($Author$)"
+__author__ = "Pierre GF Gerard-Marchant & Matt Knox ($Author$)"
 __version__ = '1.0'
 __revision__ = "$Revision$"
 __date__     = '$Date$'
@@ -28,7 +28,8 @@
 from timeseries import tseries
 #reload(tseries)
 from timeseries.tseries import Date, date_array_fromlist
-from timeseries.tseries import time_series, TimeSeries, adjust_endpoints, mask_period, align_series
+from timeseries.tseries import time_series, TimeSeries, adjust_endpoints, \
+    mask_period, align_series
 
 class test_creation(NumpyTestCase):
     "Base test class for MaskedArrays."
@@ -47,7 +48,7 @@
         assert_equal(series._mask, [1,0,0,0,0]*3)
         assert_equal(series._series, data)
         assert_equal(series._dates, date_array_fromlist(dlist))
-        assert_equal(series.freq, 'D')
+        assert_equal(series.freqstr, 'D')
 
     def test_fromrange (self):
         "Base data definition."
@@ -57,7 +58,7 @@
         assert_equal(series._mask, [1,0,0,0,0]*3)
         assert_equal(series._series, data)
         assert_equal(series._dates, dates)
-        assert_equal(series.freq, 'D')
+        assert_equal(series.freqstr, 'D')
 
     def test_fromseries (self):
         "Base data definition."
@@ -69,7 +70,7 @@
         assert_equal(series._mask, [1,0,0,0,0]*3)
         assert_equal(series._series, data)
         assert_equal(series._dates, dates)
-        assert_equal(series.freq, 'D')
+        assert_equal(series.freqstr, 'D')
         
         
     def test_fromdatearray(self):
@@ -81,7 +82,7 @@
         assert(isinstance(series, TimeSeries))
         assert_equal(series._dates, dates)
         assert_equal(series._data, data)
-        assert_equal(series.freq, 'D')
+        assert_equal(series.freqstr, 'D')
         
         series[5] = MA.masked
         
@@ -270,12 +271,12 @@
                                    end_date=Date('D', string='2007-01-31'))
         assert_equal(dseries.size, 26)
         assert_equal(dseries._mask, N.r_[series._mask[5:], [1]*16])
-        
+        #
         empty_series = time_series([], freq='d')
         a, b = align_series(series, empty_series)
         assert_equal(a.start_date, b.start_date)
         assert_equal(a.end_date, b.end_date)
-        
+    #    
     def test_tshift(self):
         "Test tshift function"
         series = self.d[0]
@@ -291,7 +292,6 @@
         
         assert_array_equal(shift_negative, shift_negative_result)
         assert_array_equal(shift_positive, shift_positive_result)
-        
     #
     def test_maskperiod(self):        
         "Test mask_period"

Modified: trunk/Lib/sandbox/timeseries/tmulti.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tmulti.py	2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tmulti.py	2007-01-30 04:08:29 UTC (rev 2633)
@@ -51,8 +51,6 @@
 reserved_fields = MR.reserved_fields + ['_dates']
 
 import warnings
-import logging
-logging.basicConfig(level=logging.DEBUG,
                     format='%(name)-15s %(levelname)s %(message)s',)
 
 __all__ = [
@@ -103,7 +101,6 @@
         mroptions = dict(fill_value=fill_value, hard_mask=hard_mask, 
                          formats=formats, names=names, titles=titles, 
                          byteorder=byteorder, aligned=aligned)
-        logging.debug("__new__ received %s" % type(data))
         #
         if isinstance(data, MultiTimeSeries):
             cls._defaultfieldmask = data._series._fieldmask
@@ -142,7 +139,6 @@
         """
 #        mclass = self.__class__
         #..........
-        logging.debug("__wrap__ received %s" % type(obj))
         if context is None:
 #            return mclass(obj, mask=self._mask, copy=False)
             return MaskedArray(obj, mask=self._mask, copy=False,
@@ -157,7 +153,6 @@
     
         
     def __array_finalize__(self,obj):
-        logging.debug("__array_finalize__ received %s" % type(obj))      
         if isinstance(obj, MultiTimeSeries):
             self.__dict__.update(_dates=obj._dates,
                                  _series=obj._series,
@@ -167,8 +162,6 @@
                                  _fill_value=obj._fill_value                                 
                                  )
         else:     
-            logging.debug("__array_finalize__ dtype %s" % obj.dtype)  
-            logging.debug("__array_finalize__ mask %s" % self._defaultfieldmask)  
             self.__dict__.update(_data = obj.view(recarray),
                                  _dates = self._defaultdates,
                                  _series = MaskedRecords(obj, dtype=obj.dtype),
@@ -178,11 +171,9 @@
                                 )
             MultiTimeSeries._defaultfieldmask = nomask
             MultiTimeSeries._defaulthardmask = False
-#        logging.debug("__array_finalize__ exit ")  
         return
     #......................................................
     def __getattribute__(self, attr):
-#        logging.debug('__getattribute__ %s' % attr)
         try:
             # Returns a generic attribute
             return object.__getattribute__(self,attr)
@@ -190,7 +181,6 @@
             # OK, so attr must be a field name
             pass
         # Get the list of fields ......
-#        logging.debug('__getattribute__ %s listfield' % attr)
         _names = self.dtype.names
         _local = self.__dict__
         _mask = _local['_fieldmask']
@@ -200,21 +190,18 @@
             obj._mask = make_mask(_mask.__getattribute__(attr))
             return obj
         elif attr == '_mask':
-#            logging.debug('__getattribute__ return mask')
             if self.size > 1:
                 return _mask.view((bool_, len(self.dtype))).all(1)
             return _mask.view((bool_, len(self.dtype)))
         raise AttributeError,"No attribute '%s' !" % attr
             
     def __setattr__(self, attr, val):
-#        logging.debug('__setattribute__ %s' % attr)
         newattr = attr not in self.__dict__
         try:
             # Is attr a generic attribute ?
             ret = object.__setattr__(self, attr, val)
         except:
             # Not a generic attribute: exit if it's not a valid field
-#            logging.debug('__setattribute__ %s' % attr)
             fielddict = self.dtype.names or {}
             if attr not in fielddict:
                 exctype, value = sys.exc_info()[:2]
@@ -242,16 +229,12 @@
         elif attr == '_mask':
             if self._hardmask:
                 val = make_mask(val)
-                logging.debug("setattr: object has hardmask %s" % val)
-                logging.debug("setattr: val is nomask: %s" % (val is nomask))
                 if val is not nomask:
 #                    mval = getmaskarray(val)
                     for k in _names:
                         m = mask_or(val, base_fmask.__getattr__(k))
-                        logging.debug("setattr: %k to: %s" % (k,m))
                         base_fmask.__setattr__(k, m)
                 else:
-                    logging.debug("setattr: VAL IS NOMASK: %s" % (val is nomask))
                 return
             else:
                 mval = getmaskarray(val)
@@ -262,14 +245,11 @@
     def __getitem__(self, indx):
         """Returns all the fields sharing the same fieldname base.
     The fieldname base is either `_data` or `_mask`."""
-        logging.debug('__getitem__(%s)' % indx)
         _localdict = self.__dict__
         # We want a field ........
         if indx in self.dtype.names:
-            logging.debug('__getitem__ getfield %s' % indx)
             obj = _localdict['_series'][indx].view(TimeSeries)
             obj._mask = make_mask(_localdict['_fieldmask'][indx])
-            logging.debug('__getitem__ field %s mask %s:' % (indx, obj._mask))
             return obj
         # We want some elements ..
         indx = super(MultiTimeSeries, self)._TimeSeries__checkindex(indx)
@@ -280,7 +260,6 @@
         
     def __getslice__(self, i, j):
         """Returns the slice described by [i,j]."""
-        logging.debug("__Getslice__ [%i,%i]" % (i,j))
         _localdict = self.__dict__
         return MultiTimeSeries(_localdict['_data'][i:j], 
                                mask=_localdict['_fieldmask'][i:j],
@@ -358,7 +337,6 @@
         """Returns a view of the mrecarray."""
         try:
             if issubclass(obj, ndarray):
-#                logging.debug('direct view as %s' % obj)
                 return ndarray.view(self, obj)
         except TypeError:
             pass
@@ -426,7 +404,6 @@
     # Define formats from scratch ...............
     if formats is None and dtype is None:
         formats = _getformats(arraylist)
-#    logging.debug("fromarrays: formats",formats)
     # Define the dtype ..........................
     if dtype is not None:
         descr = numeric.dtype(dtype)
@@ -545,7 +522,6 @@
         line = f.readline()
         firstline = line[:line.find(commentchar)].strip()
         _varnames = firstline.split(delimitor)
-#        logging.debug("_VARNAMES:%s-%s"% (_varnames,len(_varnames)))
         if len(_varnames) > 1:
             break
     if varnames is None:
@@ -586,7 +562,6 @@
             vartypes = _guessvartypes(_variables[0])
     # Construct the descriptor ..................
     mdescr = [(n,f) for (n,f) in zip(varnames, vartypes)]
-#    logging.debug("fromtextfile: descr: %s" % mdescr)
     # Get the data and the mask .................
     # We just need a list of masked_arrays. It's easier to create it like that:
     _mask = (_variables.T == missingchar)

Modified: trunk/Lib/sandbox/timeseries/tseries.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tseries.py	2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tseries.py	2007-01-30 04:08:29 UTC (rev 2633)
@@ -42,11 +42,11 @@
     masked_array
 
 import tcore as corelib
-#reload(corelib)
+reload(corelib)
 from tcore import *
 
 import tdates
-#reload(tdates)
+reload(tdates)
 from tdates import DateError, InsufficientDateError
 from tdates import Date, isDate, DateArray, isDateArray, \
     date_array, date_array_fromlist, date_array_fromrange, thisday
@@ -64,12 +64,7 @@
            ]
 
 #...............................................................................
-import logging
-logging.basicConfig(level=logging.DEBUG,
                     format='%(name)-15s %(levelname)s %(message)s',)
-talog = logging.getLogger('log.TimeArray')
-tslog = logging.getLogger('TimeSeries')
-btslog = logging.getLogger('BaseTimeSeries')
 
 ufunc_domain = {}
 ufunc_fills = {}
@@ -183,7 +178,7 @@
             cls._defaultdates = newdates    
             # Check frequency......
             if freq is not None:
-                freq = corelib.fmtFreq(freq)
+                freq = corelib.check_freq(freq)[0]
                 if freq != newdates.freq:
                     _dates = newdates.tofreq(freq)
             else:
@@ -265,32 +260,32 @@
             super(self._series.__class__, self._series).__setattribute__(attr, value)
             setattr(self._series, attr, value)
     #............................................
-    def __checkindex(self, index):
+    def __checkindex(self, indx):
         "Checks the validity of an index."
-        if isinstance(index, int):
-            return index
-        if isinstance(index, str):
-            return self._dates.date_to_index(Date(self._dates.freq, string=index))
-        elif isDate(index) or isDateArray(index):
-            return self._dates.date_to_index(index)
-        elif isinstance(index,slice):
-            slice_start = self.__checkindex(index.start)
-            slice_stop = self.__checkindex(index.stop)
-            return slice(slice_start, slice_stop, index.step)
-        elif isTimeSeries(index):
-            index = index._series
-        if getmask(index) is not nomask:
+        if isinstance(indx, int):
+            return indx
+        if isinstance(indx, str):
+            return self._dates.date_to_index(Date(self._dates.freq, string=indx))
+        elif isDate(indx) or isDateArray(indx):
+            return self._dates.date_to_index(indx)
+        elif isinstance(indx,slice):
+            slice_start = self.__checkindex(indx.start)
+            slice_stop = self.__checkindex(indx.stop)
+            return slice(slice_start, slice_stop, indx.step)
+        elif isTimeSeries(indx):
+            indx = indx._series
+        if getmask(indx) is not nomask:
             msg = "Masked arrays must be filled before they can be used as indices!"
             raise IndexError, msg
-        return index
+        return indx
 
-    def __getitem__(self, index):
+    def __getitem__(self, indx):
         """x.__getitem__(y) <==> x[y]
 Returns the item described by i. Not a copy as in previous versions.
         """
-        index = self.__checkindex(index)
-        data = self._series[index]
-        date = self._dates[index]
+        indx = self.__checkindex(indx)
+        data = self._series[indx]
+        date = self._dates[indx]
         m = self._mask
         scalardata = (len(numeric.shape(data))==0)
         # 
@@ -301,7 +296,7 @@
                 return TimeSeries(data, dates=date, mask=nomask, keep_mask=True,
                                   copy=False)
         #....
-        mi = m[index]
+        mi = m[indx]
         if mi.size == 1:
             if mi:
                 return TimeSeries(data, dates=date, mask=True)
@@ -309,19 +304,19 @@
         else:
             return TimeSeries(data, dates=date, mask=mi)
     #........................
-    def __setitem__(self, index, value):
+    def __setitem__(self, indx, value):
         """x.__setitem__(i, y) <==> x[i]=y
 Sets item described by index. If value is masked, masks those locations.
         """
         if self is masked:
             raise MAError, 'Cannot alter the masked element.'
-        index = self.__checkindex(index)
+        indx = self.__checkindex(indx)
         #....
         if isinstance(value, TimeSeries):
-            assert(_timeseriescompat(self[index], value))
-            self._series[index] = value._series
+            assert(_timeseriescompat(self[indx], value))
+            self._series[indx] = value._series
         else:
-            self._series[index] = value
+            self._series[indx] = value
         # Don't forget to update the mask !
         self._mask = self._series._mask
         
@@ -338,7 +333,7 @@
         i = self.__checkindex(i)
         j = self.__checkindex(j)
         #....
-        data = self._series[i:j]
+#        data = self._series[i:j]
         if isinstance(value, TimeSeries):
             assert(_timeseriescompat(self[i:j], value))
             self._series[i:j] = value._series
@@ -379,10 +374,10 @@
         if self.ndim <= 1:
             return desc_short % {'data': str(self._series),
                                  'time': timestr,
-                                 'freq': self.freq, }
+                                 'freq': self.freqstr, }
         return desc % {'data': str(self._series),
                        'time': timestr,
-                       'freq': self.freq, }
+                       'freq': self.freqstr, }
     #............................................
     def _get_mask(self):
         """Returns the current mask."""
@@ -419,8 +414,12 @@
         return self._dates
     @property
     def freq(self):
-        """Returns the corresponding frequency."""
+        """Returns the corresponding frequency (as an integer)."""
         return self._dates.freq
+    @property
+    def freqstr(self):
+        """Returns the corresponding frequency (as a string)."""
+        return self._dates.freqstr
         
     @property
     def day(self):          
@@ -474,7 +473,6 @@
     hours = hour
     weeks = week
 
-    
     @property
     def start_date(self):
         """Returns the first date of the series."""
@@ -482,7 +480,6 @@
             return self._dates[0]
         else:
             return None
-
     @property
     def end_date(self):
         """Returns the last date of the series."""
@@ -490,7 +487,6 @@
             return self._dates[-1]
         else:
             return None
-
     
     def isvalid(self):
         """Returns whether the series has no duplicate/missing dates."""
@@ -517,8 +513,16 @@
         if freq is None:
             return self
         return TimeSeries(self._series, dates=self._dates.asfreq(freq))
+    
+    def convert(self, freq, func='auto', position='END'):
+        "Converts the dates to another frequency, and adapt the data."
+        return convert(self, freq, func=func, position=position)
+    #.....................................................
+    def nonzero(self):
+        """Returns a tuple of ndarrays, one for each dimension of the array,
+    containing the indices of the non-zero elements in that dimension."""
+        return self._series.nonzero()
         
-        
 ##### --------------------------------------------------------------------------
 ##--- ... Additional methods ...
 ##### --------------------------------------------------------------------------
@@ -681,7 +685,10 @@
 TimeSeries.varu = _tsaxismethod('varu')
 TimeSeries.std = _tsaxismethod('std')
 TimeSeries.stdu = _tsaxismethod('stdu')
+TimeSeries.all = _tsaxismethod('all')
+TimeSeries.any = _tsaxismethod('any')
 
+
 class _tsblockedmethods(object):
     """Defines a wrapper for array methods that should be temporarily disabled.
     """
@@ -930,16 +937,16 @@
         start_date = data._dates[0]
     elif isinstance(start_date, str):
         start_date = Date(data.freq, string=start_date)
-    elif not isDateType(start_date):
-        raise DateError,"Starting date should be a valid date!"
+    elif not isinstance(start_date, Date):
+        raise DateError,"Starting date should be a valid Date object!"
     start_date = max(start_date, data.dates[0])
     # Check the ending date ................
     if end_date is None:
         end_date = data._dates[-1]
     elif isinstance(end_date, str):
         end_date = Date(data.freq, string=end_date)
-    elif not isDateType(end_date):
-        raise DateError,"Starting date should be a valid date!"
+    elif not isinstance(end_date, Date):
+        raise DateError,"Starting date should be a valid Date object!"
     end_date = min(end_date, data.dates[-1])
     # Constructs the selection mask .........
     if inside:
@@ -984,64 +991,65 @@
     if a.freq == 'U':
         raise TimeSeriesError, \
             "Cannot adjust a series with 'Undefined' frequency."
-    if not a.dates.isvalid() and a.ndim > 0 and a.size > 1:
+    if not a.dates.isvalid():
         raise TimeSeriesError, \
             "Cannot adjust a series with missing or duplicated dates."
     # Flatten the series if needed ..............
     a = a.flatten()
     shp_flat = a.shape
     # Dates validity checks .,...................
-    msg = "%s should be a valid Date instance! (got %s instead)"
-    
-    (dstart, dend) = a.start_date, a.end_date
-    if dstart is not None:
-
-        if start_date is None: 
-            start_date = dstart
-            start_lag = 0
-        else:
-            if not isDateType(start_date):
-                raise TypeError, msg % ('start_date', type(start_date))
+    msg = "%s should be a valid Date object! (got %s instead)"
+    if a.dates.size >= 1:
+        (dstart, dend) = a.dates[[0,-1]]
+    else:
+        (dstart, dend) = (None, None)
+    # Skip the empty series case
+    if dstart is None and (start_date is None or end_date is None):
+        raise TimeSeriesError, "Both start_date and end_date must be specified"+\
+                               " to adjust endpoints of a zero length series!" 
+    #....
+    if start_date is None: 
+        start_date = dstart
+        start_lag = 0
+    else:
+        if not isinstance(start_date, Date):
+            raise TypeError, msg % ('start_date', type(start_date))
+        if dstart is not None:
             start_lag = start_date - dstart
-        #....          
-        if end_date is None: 
-            end_date = dend
-            end_lag = 0
         else:
-            if not isDateType(end_date):
-                raise TypeError, msg % ('end_date', type(end_date))
+            start_lag = start_date
+    #....          
+    if end_date is None: 
+        end_date = dend
+        end_lag = 0
+    else:
+        if not isinstance(end_date, Date):
+            raise TypeError, msg % ('end_date', type(end_date))
+        if dend is not None:
             end_lag = end_date - dend    
-        # Check if the new range is included in the old one
-        if start_lag >= 0:
-            if end_lag == 0:
-                return a[start_lag:]
-            elif end_lag < 0:
-                return a[start_lag:end_lag]
-
-    else:                
-        if start_date is None or end_date is None:
-            raise TimeSeriesError, \
-                """start_date and end_date must be specified to adjust
-endpoints of a zero length series"""
-                
+        else:
+            end_lag = end_date
+    # Check if the new range is included in the old one
+    if start_lag >= 0:
+        if end_lag == 0:
+            return a[start_lag:]
+        elif end_lag < 0:
+            return a[start_lag:end_lag]
     # Create a new series .......................
     newdates = date_array(start_date=start_date, end_date=end_date)
+    
     newshape = list(shp_flat)
     newshape[0] = len(newdates)
     newshape = tuple(newshape)
-
+    
     newdata = masked_array(numeric.empty(newshape, dtype=a.dtype), mask=True)
-    
-    # need to ensure that we preserve attributes of the series in the result
+    #backup the series attributes
     options = dict(fill_value=a.fill_value, observed=a.observed)
-    
     newseries = TimeSeries(newdata, newdates, **options)
-    
     if dstart is not None:
         start_date = max(start_date, dstart)
         end_date = min(end_date, dend) + 1
         newseries[start_date:end_date] = a[start_date:end_date]
-        
     return newseries
 #....................................................................
 def align_series(*series, **kwargs):
@@ -1056,7 +1064,7 @@
     """
     if len(series) < 2:
         return series  
-    unique_freqs = numpy.unique([x.freq for x in series])
+    unique_freqs = numpy.unique([x.freqstr for x in series])
     try:
         common_freq = unique_freqs.item()
     except ValueError:
@@ -1065,15 +1073,19 @@
     if common_freq == 'U':
         raise TimeSeriesError, \
             "Cannot adjust a series with 'Undefined' frequency."
-    valid_states = [x.isvalid() or (x.size == 0 and x.ndim > 0) for x in series]
+    valid_states = [x.isvalid() for x in series]
     if not numpy.all(valid_states):
         raise TimeSeriesError, \
             "Cannot adjust a series with missing or duplicated dates."
     
-    start_date = kwargs.pop('start_date', min([x.start_date for x in series if x.start_date is not None]))
+    start_date = kwargs.pop('start_date', 
+                            min([x.start_date for x in series 
+                                     if x.start_date is not None]))
     if isinstance(start_date,str):
         start_date = Date(common_freq, string=start_date)
-    end_date = kwargs.pop('end_date', max([x.end_date for x in series if x.end_date is not None]))
+    end_date = kwargs.pop('end_date', 
+                          max([x.end_date for x in series
+                                   if x.end_date is not None]))
     if isinstance(end_date,str):
         end_date = Date(common_freq, string=end_date)
     
@@ -1137,7 +1149,9 @@
                            observed=series.observed, 
                            start_date=start_date)
     return newseries
-#....................................................................
+TimeSeries.convert = convert
+
+#...............................................................................
 def tshift(series, nper):
     """Returns a series of the same size as `series`, with the same
 start_date and end_date, but values shifted by `nper`. This is useful
@@ -1155,28 +1169,26 @@
            dates = [2005 ... 2008],
            freq  = A)
 """
-    newdata = masked_array(numeric.empty(series.shape, dtype=series.dtype), mask=True)
-
-    # need to ensure that we preserve attributes of the series in the result
+    #Backup series attributes
     options = dict(fill_value=series.fill_value, observed=series.observed)
-    newseries = TimeSeries(newdata, series._dates, **options)
-
+    newdata = masked_array(numeric.empty(series.shape, dtype=series.dtype), 
+                           mask=True)
+    inidata = series._series.copy()
     if nper < 0:
-        nper = max(-series.shape[0],nper)
-        newseries[-nper:] = series._series[:nper].copy()
-        newseries[:-nper] = masked
+        nper = max(-len(series), nper)
+        newdata[-nper:] = inidata[:nper]
     elif nper > 0:
-        nper = min(series.shape[0],nper)
-        newseries[-nper:] = masked
-        newseries[:-nper] = series._series[nper:].copy()
+        nper = min(len(series), nper)
+        newdata[:-nper] = inidata[nper:]
     else:
-        newseries[:] = self._series[:].copy()
-
+        newdata = inidata
+    newseries = TimeSeries(newdata, series._dates, **options)
     return newseries
+TimeSeries.tshift = tshift
 #....................................................................
-TimeSeries.convert = convert
-TimeSeries.tshift = tshift
 
+
+
 #....................................................................
 def fill_missing_dates(data, dates=None, freq=None,fill_value=None):
     """Finds and fills the missing dates in a time series.
@@ -1193,10 +1205,10 @@
     `fill_value` : float *[None]*
         Default value for missing data. If None, the data are just masked.
     """
-    freq = corelib.fmtFreq(freq)
-    if freq == 'U':
+    (freq, freqstr) = corelib.check_freq(freq)
+    if freqstr == 'U':
         raise ValueError,\
-              "Unable to define a proper date resolution (found %s)." % freq
+              "Unable to define a proper date resolution (found %s)." % freqstr
     if dates is None:
         if not isTimeSeries(data):
             raise InsufficientDateError
@@ -1272,7 +1284,6 @@
 
 ################################################################################
 if __name__ == '__main__':
-    logging.basicConfig(level=logging.DEBUG)
     from maskedarray.testutils import assert_equal
 #    if 0:
 #        dlist = ['2007-01-%02i' % i for i in range(1,16)]
@@ -1331,7 +1342,14 @@
         dates = date_array_fromlist(dlist)
         data = masked_array(numeric.arange(15), mask=[1,0,0,0,0]*3, dtype=float_)
         self_d = (time_series(range(15), dlist), data, dates)
-        (series, data, dates) = self_d
+        (ser, data, dates) = self_d
+        
+    if 1:
+        hodie = tdates.today('M')
+        ser_0 = time_series([], [], freq='M')
+        ser_2 = time_series([1,2], start_date=hodie)
+        ser_1 = time_series([1], hodie, freq='M')
+        
 #        # Testing a basic condition on data
 #        cond = (series<8).filled(False)
 #        dseries = series[cond]



More information about the Scipy-svn mailing list