Repository: pandas-dev/pandas

Issue:
infer_freq broken in 0.13.1
``` python
In [3]: dates = pd.date_range('01-Jan-2015', '01-Jan-2016', freq='MS')
   ...: s = pd.TimeSeries(1, dates)
   ...: pd.infer_freq(s)
   ...: 
Traceback (most recent call last):

  File "<ipython-input-3-a7de7a7e9245>", line 3, in <module>
    pd.infer_freq(s)

  File "C:\dev\bin\Anaconda\lib\site-packages\pandas\tseries\frequencies.py", line 656, in infer_freq
    inferer = _FrequencyInferer(index, warn=warn)

  File "C:\dev\bin\Anaconda\lib\site-packages\pandas\tseries\frequencies.py", line 680, in __init__
    self.is_monotonic = self.index.is_monotonic

  File "C:\dev\bin\Anaconda\lib\site-packages\pandas\core\generic.py", line 1815, in __getattr__
    (type(self).__name__, name))

AttributeError: 'Series' object has no attribute 'is_monotonic'


In [4]: pd.__version__
Out[4]: '0.13.1'
```



Discussion:
This is actually an enhancement it didn't work in 0.12 (just gave a wrong answer!)

takes a DatetimeIndex only

```
In [10]: pd.infer_freq?
Type:       function
String Form:<function infer_freq at 0x3b207d0>
File:       /mnt/home/jreback/pandas/pandas/tseries/frequencies.py
Definition: pd.infer_freq(index, warn=True)
Docstring:
Infer the most likely frequency given the input index. If the frequency is
uncertain, a warning will be printed

Parameters
----------
index : DatetimeIndex
warn : boolean, default True

Returns
-------
freq : string or None
    None if no discernible frequency
```

works correctly on the index

```
In [12]: pd.infer_freq(s.index)
Out[12]: 'MS'
```

out of curiosity, what is your usecase for this?


Resolving patch:
diff --git a/pandas/tseries/frequencies.py b/pandas/tseries/frequencies.py
--- a/pandas/tseries/frequencies.py
+++ b/pandas/tseries/frequencies.py
@@ -13,7 +13,6 @@
 import pandas.lib as lib
 import pandas.tslib as tslib
 
-
 class FreqGroup(object):
     FR_ANN = 1000
     FR_QTR = 2000
@@ -637,22 +636,28 @@ def infer_freq(index, warn=True):
     Parameters
     ----------
     index : DatetimeIndex
+            if passed a Series will use the values of the series (NOT THE INDEX)
     warn : boolean, default True
 
     Returns
     -------
     freq : string or None
         None if no discernible frequency
+        TypeError if the index is not datetime-like
     """
-    from pandas.tseries.index import DatetimeIndex
-
-    if not isinstance(index, DatetimeIndex):
-        from pandas.tseries.period import PeriodIndex
-        if isinstance(index, PeriodIndex):
-            raise ValueError("PeriodIndex given. Check the `freq` attribute "
-                             "instead of using infer_freq.")
-        index = DatetimeIndex(index)
-
+    import pandas as pd
+
+    if isinstance(index, com.ABCSeries):
+        values = index.values
+        if not (com.is_datetime64_dtype(index.values) or values.dtype == object):
+            raise TypeError("cannot infer freq from a non-convertible dtype on a Series of {0}".format(index.dtype))
+        index = values
+    if isinstance(index, pd.PeriodIndex):
+        raise TypeError("PeriodIndex given. Check the `freq` attribute "
+                         "instead of using infer_freq.")
+    if not isinstance(index, pd.DatetimeIndex) and isinstance(index, pd.Index):
+        raise TypeError("cannot infer freq from a non-convertible index type {0}".format(type(index)))
+    index = pd.DatetimeIndex(index)
     inferer = _FrequencyInferer(index, warn=warn)
     return inferer.get_freq()
 


Test patch:
diff --git a/pandas/tseries/tests/test_frequencies.py b/pandas/tseries/tests/test_frequencies.py
--- a/pandas/tseries/tests/test_frequencies.py
+++ b/pandas/tseries/tests/test_frequencies.py
@@ -7,7 +7,7 @@
 
 import numpy as np
 
-from pandas import Index, DatetimeIndex, Timestamp, date_range, period_range
+from pandas import Index, DatetimeIndex, Timestamp, Series, date_range, period_range
 
 from pandas.tseries.frequencies import to_offset, infer_freq
 from pandas.tseries.tools import to_datetime
@@ -72,7 +72,7 @@ def test_to_offset_negative():
     freqstr = '-5min10s'
     result = to_offset(freqstr)
     assert(result.n == -310)
-    
+
 
 def test_to_offset_leading_zero():
     freqstr = '00H 00T 01S'
@@ -101,7 +101,7 @@ class TestFrequencyInference(tm.TestCase):
 
     def test_raise_if_period_index(self):
         index = PeriodIndex(start="1/1/1990", periods=20, freq="M")
-        self.assertRaises(ValueError, infer_freq, index)
+        self.assertRaises(TypeError, infer_freq, index)
 
     def test_raise_if_too_few(self):
         index = _dti(['12/31/1998', '1/3/1999'])
@@ -269,6 +269,44 @@ def test_non_datetimeindex(self):
         result = infer_freq(vals)
         self.assertEqual(result, rng.inferred_freq)
 
+    def test_invalid_index_types(self):
+
+        # test all index types
+        for i in [ tm.makeIntIndex(10),
+                   tm.makeFloatIndex(10),
+                   tm.makeStringIndex(10),
+                   tm.makeUnicodeIndex(10),
+                   tm.makePeriodIndex(10) ]:
+            self.assertRaises(TypeError, lambda : infer_freq(i))
+
+    def test_series(self):
+
+        # GH6407
+        # inferring series
+
+        # invalid type of Series
+        for s in [ Series(np.arange(10)),
+                   Series(np.arange(10.))]:
+            self.assertRaises(TypeError, lambda : infer_freq(s))
+
+        # a non-convertible string
+        self.assertRaises(ValueError, lambda : infer_freq(Series(['foo','bar'])))
+
+        # cannot infer on PeriodIndex
+        for freq in [None, 'MS', 'Y']:
+            s = Series(period_range('2013',periods=10,freq=freq))
+            self.assertRaises(TypeError, lambda : infer_freq(s))
+
+        # DateTimeIndex
+        for freq in ['MS', 'L', 'S']:
+            s = Series(date_range('20130101',periods=10,freq=freq))
+            inferred = infer_freq(s)
+            self.assertEqual(inferred,freq)
+
+        s = Series(date_range('20130101','20130110'))
+        inferred = infer_freq(s)
+        self.assertEqual(inferred,'D')
+
 MONTHS = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP',
           'OCT', 'NOV', 'DEC']