Repository: pandas-dev/pandas

Issue:
TST: yahoo retrieve tests failure
cc @dstephens99

prob just need to protect these a bit

here as well: https://travis-ci.org/jreback/pandas/jobs/28958102

```
======================================================================
ERROR: test_get_all_data (pandas.io.tests.test_data.TestYahooOptions)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "c:\Users\Jeff Reback\Documents\GitHub\pandas\build\lib.win32-2.7\pandas\util\testing.py", line 1337, in wrapper
    return t(*args, **kwargs)
  File "c:\Users\Jeff Reback\Documents\GitHub\pandas\build\lib.win32-2.7\pandas\io\tests\test_data.py", line 307, in test_get_all_data
    data = self.aapl.get_all_data(put=True)
  File "c:\Users\Jeff Reback\Documents\GitHub\pandas\build\lib.win32-2.7\pandas\io\data.py", line 1095, in get_all_data
    months = self._get_expiry_months()
  File "c:\Users\Jeff Reback\Documents\GitHub\pandas\build\lib.win32-2.7\pandas\io\data.py", line 1130, in _get_expiry_months
    links = root.xpath('.//*[@id="yfncsumtab"]')[0].xpath('.//a')
IndexError: list index out of range

----------------------------------------------------------------------
Ran 6897 tests in 353.413s

FAILED (SKIP=315, errors=1)

C:\Users\Jeff Reback\Documents\GitHub\pandas>
```



Discussion:

Resolving patch:
diff --git a/pandas/io/data.py b/pandas/io/data.py
--- a/pandas/io/data.py
+++ b/pandas/io/data.py
@@ -661,31 +661,35 @@ def get_options_data(self, month=None, year=None, expiry=None):
 
     _OPTIONS_BASE_URL = 'http://finance.yahoo.com/q/op?s={sym}'
 
-    def _get_option_tables(self, month, year, expiry):
+    def _get_option_tables(self, expiry):
+        root = self._get_option_page_from_yahoo(expiry)
+        tables = self._parse_option_page_from_yahoo(root)
+        m1 = _two_char_month(expiry.month)
+        table_name = '_tables' + m1 + str(expiry.year)[-2:]
+        setattr(self, table_name, tables)
+        return tables
 
-        year, month, expiry = self._try_parse_dates(year, month, expiry)
+    def _get_option_page_from_yahoo(self, expiry):
 
         url = self._OPTIONS_BASE_URL.format(sym=self.symbol)
 
-        if month and year:  # try to get specified month from yahoo finance
-            m1 = _two_char_month(month)
+        m1 = _two_char_month(expiry.month)
 
-            # if this month use other url
-            if month == CUR_MONTH and year == CUR_YEAR:
-                url += '+Options'
-            else:
-                url += '&m={year}-{m1}'.format(year=year, m1=m1)
-        else:  # Default to current month
+        # if this month use other url
+        if expiry.month == CUR_MONTH and expiry.year == CUR_YEAR:
             url += '+Options'
+        else:
+            url += '&m={year}-{m1}'.format(year=expiry.year, m1=m1)
 
         root = self._parse_url(url)
+        return root
+
+    def _parse_option_page_from_yahoo(self, root):
+
         tables = root.xpath('.//table')
         ntables = len(tables)
         if ntables == 0:
-            raise RemoteDataError("No tables found at {0!r}".format(url))
-
-        table_name = '_tables' + m1 + str(year)[-2:]
-        setattr(self, table_name, tables)
+            raise RemoteDataError("No tables found")
 
         try:
             self.underlying_price, self.quote_time = self._get_underlying_price(root)
@@ -723,7 +727,7 @@ def _get_option_data(self, month, year, expiry, name):
         try:
             tables = getattr(self, table_name)
         except AttributeError:
-            tables = self._get_option_tables(month, year, expiry)
+            tables = self._get_option_tables(expiry)
 
         ntables = len(tables)
         table_loc = self._TABLE_LOC[name]
@@ -903,13 +907,14 @@ def get_near_stock_price(self, above_below=2, call=True, put=False,
                 meth_name = 'get_{0}_data'.format(nam[:-1])
                 df = getattr(self, meth_name)(expiry=expiry)
 
-            start_index = np.where(df.index.get_level_values('Strike')
+            if self.underlying_price:
+                start_index = np.where(df.index.get_level_values('Strike')
                                    > self.underlying_price)[0][0]
 
-            get_range = slice(start_index - above_below,
+                get_range = slice(start_index - above_below,
                               start_index + above_below + 1)
-            chop = df[get_range].dropna(how='all')
-            data[nam] = chop
+                chop = df[get_range].dropna(how='all')
+                data[nam] = chop
 
         return concat([data[nam] for nam in to_ret]).sortlevel()
 
@@ -948,6 +953,8 @@ def _try_parse_dates(year, month, expiry):
             year = CUR_YEAR
             month = CUR_MONTH
             expiry = dt.date(year, month, 1)
+        else:
+            expiry = dt.date(year, month, 1)
 
         return year, month, expiry
 
@@ -1127,7 +1134,11 @@ def _get_expiry_months(self):
         url = 'http://finance.yahoo.com/q/op?s={sym}'.format(sym=self.symbol)
         root = self._parse_url(url)
 
-        links = root.xpath('.//*[@id="yfncsumtab"]')[0].xpath('.//a')
+        try:
+            links = root.xpath('.//*[@id="yfncsumtab"]')[0].xpath('.//a')
+        except IndexError:
+            return RemoteDataError('Expiry months not available')
+
         month_gen = (element.attrib['href'].split('=')[-1]
                  for element in links
                  if '/q/op?s=' in element.attrib['href']


Test patch:
diff --git a/pandas/io/tests/test_data.py b/pandas/io/tests/test_data.py
--- a/pandas/io/tests/test_data.py
+++ b/pandas/io/tests/test_data.py
@@ -334,7 +334,7 @@ def test_sample_page_price_quote_time2(self):
     @network
     def test_sample_page_chg_float(self):
         #Tests that numeric columns with comma's are appropriately dealt with
-        tables = self.root1.xpath('.//table')
+        tables = self.aapl._parse_option_page_from_yahoo(self.root1)
         data = web._parse_options_data(tables[self.aapl._TABLE_LOC['puts']])
         option_data = self.aapl._process_data(data)
         self.assertEqual(option_data['Chg'].dtype, 'float64')