Repository: pandas-dev/pandas

Issue:
ENH: update stata for Stata 13 format
http://www.stata.com/help.cgi?dta



Discussion:
New Stata format is obviously inspired by XML, although it doesn't fully behave like it: The "marker pairs" (which are tags in XML terminology) have to appear in a fixed order, so they are basically a help for easier reading through raw stata files.Thus, binary reading just like for old formats should still work. A XML reader, however, might make reading those files easier and more flexible (in case that they someday start to really implement it as XML).
Do you prefer an implementation based on the XML approach (for example using the xml.dom.minidom module of python) or the binary approach?

`lxml` is on pandas list of optional deps, so you can use that. but isn't the binary _similar_ to the existing?

so that would be easier? 

inside the tags, most stuff should be the same as before. Since there is a map with seek positions for all content tags, the parser could rely on that. I think, that I'll try the binary attempt.

great! leave all of the existing data files alone and add a new one for (for version 13). to ensure back compat. thanks!

The statsmodels repo has an [issue](https://github.com/statsmodels/statsmodels/issues/974) about this too.  I don't know if @jseabold or anyone else has done anything with it.

I haven't yet. If I do get to it (unlikely right now), I'll make a PR against pandas.


Resolving patch:
diff --git a/pandas/io/stata.py b/pandas/io/stata.py
--- a/pandas/io/stata.py
+++ b/pandas/io/stata.py
@@ -20,28 +20,36 @@
 from pandas.core.categorical import Categorical
 import datetime
 from pandas import compat
-from pandas import compat
-from pandas.compat import StringIO, long, lrange, lmap, lzip
+from pandas.compat import long, lrange, lmap, lzip
 from pandas import isnull
-from pandas.io.parsers import _parser_params, Appender
-from pandas.io.common import get_filepath_or_buffer, maybe_read_encoded_stream
-
-
-_read_stata_doc = """
-Read Stata file into DataFrame
-
-%s
-""" % (_parser_params)
+from pandas.io.common import get_filepath_or_buffer
 
 
-@Appender(_read_stata_doc)
 def read_stata(filepath_or_buffer, convert_dates=True, convert_categoricals=True, encoding=None, index=None):
+    """
+    Read Stata file into DataFrame
+
+    Parameters
+    ----------
+    filepath_or_buffer : string or file-like object
+        Path to .dta file or object implementing a binary read() functions
+    convert_dates : boolean, defaults to True
+        Convert date variables to DataFrame time values
+    convert_categoricals : boolean, defaults to True
+        Read value labels and convert columns to Categorical/Factor variables
+    encoding : string, None or encoding
+        Encoding used to parse the files. Note that Stata doesn't
+        support unicode. None defaults to cp1252.
+    index : identifier of index column
+        identifier of column that should be used as index of the DataFrame
+    """
     reader = StataReader(filepath_or_buffer, encoding)
 
     return reader.data(convert_dates, convert_categoricals, index)
 
 _date_formats = ["%tc", "%tC", "%td", "%tw", "%tm", "%tq", "%th", "%ty"]
 
+
 def _stata_elapsed_date_to_datetime(date, fmt):
     """
     Convert from SIF to datetime. http://www.stata.com/help.cgi?datetime
@@ -205,7 +213,7 @@ def __repr__(self):
 class StataParser(object):
     _default_encoding = 'cp1252'
 
-    def __init__(self, encoding=None):
+    def __init__(self, encoding):
         self._encoding = encoding
 
         #type          code.
@@ -234,7 +242,28 @@ def __init__(self, encoding=None):
                     (255, np.float64)
                 ]
             )
+        self.DTYPE_MAP_XML = \
+            dict(
+                [
+                    (32768, np.string_),
+                    (65526, np.float64),
+                    (65527, np.float32),
+                    (65528, np.int64),
+                    (65529, np.int32),
+                    (65530, np.int16)
+                ]
+            )
         self.TYPE_MAP = lrange(251) + list('bhlfd')
+        self.TYPE_MAP_XML = \
+            dict(
+                [
+                    (65526, 'd'),
+                    (65527, 'f'),
+                    (65528, 'l'),
+                    (65529, 'h'),
+                    (65530, 'b')
+                ]
+            )
         #NOTE: technically, some of these are wrong. there are more numbers
         # that can be represented. it's the 27 ABOVE and BELOW the max listed
         # numeric data type in [U] 12.2.2 of the 11.2 manual
@@ -294,7 +323,7 @@ def __init__(self, path_or_buf, encoding='cp1252'):
         self._data_read = False
         self._value_labels_read = False
         if isinstance(path_or_buf, str):
-            path_or_buf, encoding = get_filepath_or_buffer(path_or_buf, encoding='cp1252')
+            path_or_buf, encoding = get_filepath_or_buffer(path_or_buf, encoding=self._default_encoding)
 
         if isinstance(path_or_buf, (str, compat.text_type, bytes)):
             self.path_or_buf = open(path_or_buf, 'rb')
@@ -304,86 +333,159 @@ def __init__(self, path_or_buf, encoding='cp1252'):
         self._read_header()
 
     def _read_header(self):
-        # header
-        self.format_version = struct.unpack('b', self.path_or_buf.read(1))[0]
-        if self.format_version not in [104, 105, 108, 113, 114, 115]:
-            raise ValueError("Version of given Stata file is not 104, 105, 108, 113 (Stata 8/9), 114 (Stata 10/11) or 115 (Stata 12)")
-        self.byteorder = self.path_or_buf.read(1) == 0x1 and '>' or '<'
-        self.filetype = struct.unpack('b', self.path_or_buf.read(1))[0]
-        self.path_or_buf.read(1)  # unused
-
-        self.nvar = struct.unpack(self.byteorder + 'H', self.path_or_buf.read(2))[0]
-        self.nobs = struct.unpack(self.byteorder + 'I', self.path_or_buf.read(4))[0]
-        if self.format_version > 105:
-            self.data_label = self.path_or_buf.read(81)
-        else:
-            self.data_label = self.path_or_buf.read(32)
-        if self.format_version > 104:
-            self.time_stamp = self.path_or_buf.read(18)
+        first_char = self.path_or_buf.read(1)
+        if struct.unpack('c', first_char)[0] == b'<':  # format 117 or higher (XML like)
+            self.path_or_buf.read(27)  # stata_dta><header><release>
+            self.format_version = int(self.path_or_buf.read(3))
+            if self.format_version not in [117]:
+                raise ValueError("Version of given Stata file is not 104, 105, 108, 113 (Stata 8/9), 114 (Stata 10/11), 115 (Stata 12) or 117 (Stata 13)")
+            self.path_or_buf.read(21)  # </release><byteorder>
+            self.byteorder = self.path_or_buf.read(3) == "MSF" and '>' or '<'
+            self.path_or_buf.read(15)  # </byteorder><K>
+            self.nvar = struct.unpack(self.byteorder + 'H', self.path_or_buf.read(2))[0]
+            self.path_or_buf.read(7)  # </K><N>
+            self.nobs = struct.unpack(self.byteorder + 'I', self.path_or_buf.read(4))[0]
+            self.path_or_buf.read(11)  # </N><label>
+            strlen = struct.unpack('b', self.path_or_buf.read(1))[0]
+            self.data_label = self.path_or_buf.read(strlen)
+            self.path_or_buf.read(19)  # </label><timestamp>
+            strlen = struct.unpack('b', self.path_or_buf.read(1))[0]
+            self.time_stamp = self.path_or_buf.read(strlen)
+            self.path_or_buf.read(26)  # </timestamp></header><map>
+            self.path_or_buf.read(8)  # 0x0000000000000000
+            self.path_or_buf.read(8)  # position of <map>
+            seek_vartypes = struct.unpack(self.byteorder + 'q', self.path_or_buf.read(8))[0] + 16
+            seek_varnames = struct.unpack(self.byteorder + 'q', self.path_or_buf.read(8))[0] + 10
+            seek_sortlist = struct.unpack(self.byteorder + 'q', self.path_or_buf.read(8))[0] + 10
+            seek_formats = struct.unpack(self.byteorder + 'q', self.path_or_buf.read(8))[0] + 9
+            seek_value_label_names = struct.unpack(self.byteorder + 'q', self.path_or_buf.read(8))[0] + 19
+            seek_variable_labels = struct.unpack(self.byteorder + 'q', self.path_or_buf.read(8))[0] + 17
+            self.path_or_buf.read(8)  # <characteristics>
+            self.data_location = struct.unpack(self.byteorder + 'q', self.path_or_buf.read(8))[0] + 6
+            self.seek_strls = struct.unpack(self.byteorder + 'q', self.path_or_buf.read(8))[0] + 7
+            self.seek_value_labels = struct.unpack(self.byteorder + 'q', self.path_or_buf.read(8))[0] + 14
+            #self.path_or_buf.read(8)  # </stata_dta>
+            #self.path_or_buf.read(8)  # EOF
+            self.path_or_buf.seek(seek_vartypes)
+            typlist = [struct.unpack(self.byteorder + 'H', self.path_or_buf.read(2))[0] for i in range(self.nvar)]
+            self.typlist = [None]*self.nvar
+            try:
+                i = 0
+                for typ in typlist:
+                    if typ <= 2045 or typ == 32768:
+                        self.typlist[i] = None
+                    else:
+                        self.typlist[i] = self.TYPE_MAP_XML[typ]
+                    i += 1
+            except:
+                raise ValueError("cannot convert stata types [{0}]".format(','.join(typlist)))
+            self.dtyplist = [None]*self.nvar
+            try:
+                i = 0
+                for typ in typlist:
+                    if typ <= 2045:
+                        self.dtyplist[i] = str(typ)
+                    else:
+                        self.dtyplist[i] = self.DTYPE_MAP_XML[typ]
+                    i += 1
+            except:
+                raise ValueError("cannot convert stata dtypes [{0}]".format(','.join(typlist)))
 
-        # descriptors
-        if self.format_version > 108:
-            typlist = [ord(self.path_or_buf.read(1)) for i in range(self.nvar)]
-        else:
-            typlist = [self.OLD_TYPE_MAPPING[self._decode_bytes(self.path_or_buf.read(1))] for i in range(self.nvar)]
-
-        try:
-            self.typlist = [self.TYPE_MAP[typ] for typ in typlist]
-        except:
-            raise ValueError("cannot convert stata types [{0}]".format(','.join(typlist)))
-        try:
-            self.dtyplist = [self.DTYPE_MAP[typ] for typ in typlist]
-        except:
-            raise ValueError("cannot convert stata dtypes [{0}]".format(','.join(typlist)))
-
-        if self.format_version > 108:
+            self.path_or_buf.seek(seek_varnames)
             self.varlist = [self._null_terminate(self.path_or_buf.read(33)) for i in range(self.nvar)]
-        else:
-            self.varlist = [self._null_terminate(self.path_or_buf.read(9)) for i in range(self.nvar)]
-        self.srtlist = struct.unpack(self.byteorder + ('h' * (self.nvar + 1)), self.path_or_buf.read(2 * (self.nvar + 1)))[:-1]
-        if self.format_version > 113:
+
+            self.path_or_buf.seek(seek_sortlist)
+            self.srtlist = struct.unpack(self.byteorder + ('h' * (self.nvar + 1)), self.path_or_buf.read(2 * (self.nvar + 1)))[:-1]
+
+            self.path_or_buf.seek(seek_formats)
             self.fmtlist = [self._null_terminate(self.path_or_buf.read(49)) for i in range(self.nvar)]
-        elif self.format_version > 104:
-            self.fmtlist = [self._null_terminate(self.path_or_buf.read(12)) for i in range(self.nvar)]
-        else:
-            self.fmtlist = [self._null_terminate(self.path_or_buf.read(7)) for i in range(self.nvar)]
-        if self.format_version > 108:
+
+            self.path_or_buf.seek(seek_value_label_names)
             self.lbllist = [self._null_terminate(self.path_or_buf.read(33)) for i in range(self.nvar)]
-        else:
-            self.lbllist = [self._null_terminate(self.path_or_buf.read(9)) for i in range(self.nvar)]
-        if self.format_version > 105:
+
+            self.path_or_buf.seek(seek_variable_labels)
             self.vlblist = [self._null_terminate(self.path_or_buf.read(81)) for i in range(self.nvar)]
         else:
-            self.vlblist = [self._null_terminate(self.path_or_buf.read(32)) for i in range(self.nvar)]
-
-        # ignore expansion fields (Format 105 and later)
-        # When reading, read five bytes; the last four bytes now tell you the
-        # size of the next read, which you discard.  You then continue like
-        # this until you read 5 bytes of zeros.
-
-        if self.format_version > 104:
-            while True:
-                data_type = struct.unpack(self.byteorder + 'b', self.path_or_buf.read(1))[0]
-                if self.format_version > 108:
-                    data_len = struct.unpack(self.byteorder + 'i', self.path_or_buf.read(4))[0]
-                else:
-                    data_len = struct.unpack(self.byteorder + 'h', self.path_or_buf.read(2))[0]
-                if data_type == 0:
-                    break
-                self.path_or_buf.read(data_len)
+            # header
+            self.format_version = struct.unpack('b', first_char)[0]
+            if self.format_version not in [104, 105, 108, 113, 114, 115]:
+                raise ValueError("Version of given Stata file is not 104, 105, 108, 113 (Stata 8/9), 114 (Stata 10/11), 115 (Stata 12) or 117 (Stata 13)")
+            self.byteorder = self.path_or_buf.read(1) == 0x1 and '>' or '<'
+            self.filetype = struct.unpack('b', self.path_or_buf.read(1))[0]
+            self.path_or_buf.read(1)  # unused
+
+            self.nvar = struct.unpack(self.byteorder + 'H', self.path_or_buf.read(2))[0]
+            self.nobs = struct.unpack(self.byteorder + 'I', self.path_or_buf.read(4))[0]
+            if self.format_version > 105:
+                self.data_label = self.path_or_buf.read(81)
+            else:
+                self.data_label = self.path_or_buf.read(32)
+            if self.format_version > 104:
+                self.time_stamp = self.path_or_buf.read(18)
+
+            # descriptors
+            if self.format_version > 108:
+                typlist = [ord(self.path_or_buf.read(1)) for i in range(self.nvar)]
+            else:
+                typlist = [self.OLD_TYPE_MAPPING[self._decode_bytes(self.path_or_buf.read(1))] for i in range(self.nvar)]
+
+            try:
+                self.typlist = [self.TYPE_MAP[typ] for typ in typlist]
+            except:
+                raise ValueError("cannot convert stata types [{0}]".format(','.join(typlist)))
+            try:
+                self.dtyplist = [self.DTYPE_MAP[typ] for typ in typlist]
+            except:
+                raise ValueError("cannot convert stata dtypes [{0}]".format(','.join(typlist)))
+
+            if self.format_version > 108:
+                self.varlist = [self._null_terminate(self.path_or_buf.read(33)) for i in range(self.nvar)]
+            else:
+                self.varlist = [self._null_terminate(self.path_or_buf.read(9)) for i in range(self.nvar)]
+            self.srtlist = struct.unpack(self.byteorder + ('h' * (self.nvar + 1)), self.path_or_buf.read(2 * (self.nvar + 1)))[:-1]
+            if self.format_version > 113:
+                self.fmtlist = [self._null_terminate(self.path_or_buf.read(49)) for i in range(self.nvar)]
+            elif self.format_version > 104:
+                self.fmtlist = [self._null_terminate(self.path_or_buf.read(12)) for i in range(self.nvar)]
+            else:
+                self.fmtlist = [self._null_terminate(self.path_or_buf.read(7)) for i in range(self.nvar)]
+            if self.format_version > 108:
+                self.lbllist = [self._null_terminate(self.path_or_buf.read(33)) for i in range(self.nvar)]
+            else:
+                self.lbllist = [self._null_terminate(self.path_or_buf.read(9)) for i in range(self.nvar)]
+            if self.format_version > 105:
+                self.vlblist = [self._null_terminate(self.path_or_buf.read(81)) for i in range(self.nvar)]
+            else:
+                self.vlblist = [self._null_terminate(self.path_or_buf.read(32)) for i in range(self.nvar)]
+
+            # ignore expansion fields (Format 105 and later)
+            # When reading, read five bytes; the last four bytes now tell you the
+            # size of the next read, which you discard.  You then continue like
+            # this until you read 5 bytes of zeros.
+
+            if self.format_version > 104:
+                while True:
+                    data_type = struct.unpack(self.byteorder + 'b', self.path_or_buf.read(1))[0]
+                    if self.format_version > 108:
+                        data_len = struct.unpack(self.byteorder + 'i', self.path_or_buf.read(4))[0]
+                    else:
+                        data_len = struct.unpack(self.byteorder + 'h', self.path_or_buf.read(2))[0]
+                    if data_type == 0:
+                        break
+                    self.path_or_buf.read(data_len)
+
+            # necessary data to continue parsing
+            self.data_location = self.path_or_buf.tell()
 
-        # necessary data to continue parsing
-        self.data_location = self.path_or_buf.tell()
         self.has_string_data = len([x for x in self.typlist if type(x) is int]) > 0
-        self._col_size()
+
+        """Calculate size of a data record."""
+        self.col_sizes = lmap(lambda x: self._calcsize(x), self.typlist)
 
     def _calcsize(self, fmt):
         return type(fmt) is int and fmt or struct.calcsize(self.byteorder + fmt)
 
     def _col_size(self, k=None):
-        """Calculate size of a data record."""
-        if len(self.col_sizes) == 0:
-            self.col_sizes = lmap(lambda x: self._calcsize(x), self.typlist)
         if k is None:
             return self.col_sizes
         else:
@@ -427,8 +529,8 @@ def _next(self):
             return data
         else:
             return list(map(lambda i: self._unpack(typlist[i],
-                                              self.path_or_buf.read(self._col_size(i))),
-                       range(self.nvar)))
+                                                   self.path_or_buf.read(self._col_size(i))),
+                            range(self.nvar)))
 
     def _dataset(self):
         """
@@ -450,19 +552,19 @@ def _dataset(self):
         be handled by your applcation.
         """
 
-        try:
-            self._file.seek(self._data_location)
-        except Exception:
-            pass
+        self.path_or_buf.seek(self.data_location)
 
         for i in range(self.nobs):
             yield self._next()
 
     def _read_value_labels(self):
-        if not self._data_read:
-            raise Exception("Data has not been read. Because of the layout of Stata files, this is necessary before reading value labels.")
-        if self._value_labels_read:
-            raise Exception("Value labels have already been read.")
+        if self.format_version >= 117:
+            self.path_or_buf.seek(self.seek_value_labels)
+        else:
+            if not self._data_read:
+                raise Exception("Data has not been read. Because of the layout of Stata files, this is necessary before reading value labels.")
+            if self._value_labels_read:
+                raise Exception("Value labels have already been read.")
 
         self.value_label_dict = dict()
 
@@ -470,9 +572,13 @@ def _read_value_labels(self):
             return  # Value labels are not supported in version 108 and earlier.
 
         while True:
+            if self.format_version >= 117:
+                if self.path_or_buf.read(5) == b'</val':  # <lbl>
+                    break  # end o f variable lable table
+
             slength = self.path_or_buf.read(4)
             if not slength:
-                break  # end of variable lable table
+                break  # end of variable lable table (format < 117)
             labname = self._null_terminate(self.path_or_buf.read(33))
             self.path_or_buf.read(3)  # padding
 
@@ -488,8 +594,24 @@ def _read_value_labels(self):
             self.value_label_dict[labname] = dict()
             for i in range(n):
                 self.value_label_dict[labname][val[i]] = self._null_terminate(txt[off[i]:])
+
+            if self.format_version >= 117:
+                self.path_or_buf.read(6)  # </lbl>
         self._value_labels_read = True
 
+    def _read_strls(self):
+        self.path_or_buf.seek(self.seek_strls)
+        self.GSO = dict()
+        while True:
+            if self.path_or_buf.read(3) != b'GSO':
+                break
+
+            v_o = struct.unpack(self.byteorder + 'L', self.path_or_buf.read(8))[0]
+            typ = self.path_or_buf.read(1)
+            length = struct.unpack(self.byteorder + 'I', self.path_or_buf.read(4))[0]
+            self.GSO[v_o] = self.path_or_buf.read(length-1)
+            self.path_or_buf.read(1)  # zero-termination
+
     def data(self, convert_dates=True, convert_categoricals=True, index=None):
         """
         Reads observations from Stata file, converting them into a dataframe
@@ -511,6 +633,9 @@ def data(self, convert_dates=True, convert_categoricals=True, index=None):
             raise Exception("Data has already been read.")
         self._data_read = True
 
+        if self.format_version >= 117:
+            self._read_strls()
+
         stata_dta = self._dataset()
 
         data = []


Test patch:
diff --git a/pandas/io/tests/data/stata1_v13.dta b/pandas/io/tests/data/stata1_v13.dta
new file mode 100644
Binary files /dev/null and b/pandas/io/tests/data/stata1_v13.dta differ
diff --git a/pandas/io/tests/data/stata2_v13.dta b/pandas/io/tests/data/stata2_v13.dta
new file mode 100644
Binary files /dev/null and b/pandas/io/tests/data/stata2_v13.dta differ
diff --git a/pandas/io/tests/data/stata3_v13.dta b/pandas/io/tests/data/stata3_v13.dta
new file mode 100644
Binary files /dev/null and b/pandas/io/tests/data/stata3_v13.dta differ
diff --git a/pandas/io/tests/data/stata4_v13.dta b/pandas/io/tests/data/stata4_v13.dta
new file mode 100644
Binary files /dev/null and b/pandas/io/tests/data/stata4_v13.dta differ
diff --git a/pandas/io/tests/test_stata.py b/pandas/io/tests/test_stata.py
--- a/pandas/io/tests/test_stata.py
+++ b/pandas/io/tests/test_stata.py
@@ -33,6 +33,10 @@ def setUp(self):
         self.dta9 = os.path.join(self.dirpath, 'lbw.dta')
         self.csv9 = os.path.join(self.dirpath, 'lbw.csv')
         self.dta_encoding = os.path.join(self.dirpath, 'stata1_encoding.dta')
+        self.dta1_13 = os.path.join(self.dirpath, 'stata1_v13.dta')
+        self.dta2_13 = os.path.join(self.dirpath, 'stata2_v13.dta')
+        self.dta3_13 = os.path.join(self.dirpath, 'stata3_v13.dta')
+        self.dta4_13 = os.path.join(self.dirpath, 'stata4_v13.dta')
 
     def read_dta(self, file):
         return read_stata(file, convert_dates=True)
@@ -43,6 +47,8 @@ def read_csv(self, file):
     def test_read_dta1(self):
         reader = StataReader(self.dta1)
         parsed = reader.data()
+        reader_13 = StataReader(self.dta1_13)
+        parsed_13 = reader_13.data()
         # Pandas uses np.nan as missing value.
         # Thus, all columns will be of type float, regardless of their name.
         expected = DataFrame([(np.nan, np.nan, np.nan, np.nan, np.nan)],
@@ -52,7 +58,9 @@ def test_read_dta1(self):
         # this is an oddity as really the nan should be float64, but
         # the casting doesn't fail so need to match stata here
         expected['float_miss'] = expected['float_miss'].astype(np.float32)
+
         tm.assert_frame_equal(parsed, expected)
+        tm.assert_frame_equal(parsed_13, expected)
 
     def test_read_dta2(self):
         expected = DataFrame.from_records(
@@ -95,25 +103,29 @@ def test_read_dta2(self):
 
         with warnings.catch_warnings(record=True) as w:
             parsed = self.read_dta(self.dta2)
+            parsed_13 = self.read_dta(self.dta2_13)
             np.testing.assert_equal(
                 len(w), 1)  # should get a warning for that format.
 
         tm.assert_frame_equal(parsed, expected)
+        tm.assert_frame_equal(parsed_13, expected)
 
     def test_read_dta3(self):
-
         parsed = self.read_dta(self.dta3)
+        parsed_13 = self.read_dta(self.dta3_13)
 
         # match stata here
         expected = self.read_csv(self.csv3)
         expected = expected.astype(np.float32)
         expected['year'] = expected['year'].astype(np.int32)
-        expected['quarter']= expected['quarter'].astype(np.int16)
+        expected['quarter'] = expected['quarter'].astype(np.int16)
 
-        tm.assert_frame_equal(parsed,expected)
+        tm.assert_frame_equal(parsed, expected)
+        tm.assert_frame_equal(parsed_13, expected)
 
     def test_read_dta4(self):
         parsed = self.read_dta(self.dta4)
+        parsed_13 = self.read_dta(self.dta4_13)
         expected = DataFrame.from_records(
             [
                 ["one", "ten", "one", "one", "one"],
@@ -131,6 +143,7 @@ def test_read_dta4(self):
                      'labeled_with_missings', 'float_labelled'])
 
         tm.assert_frame_equal(parsed, expected)
+        tm.assert_frame_equal(parsed_13, expected)
 
     def test_read_write_dta5(self):
         if not is_little_endian():
@@ -178,7 +191,7 @@ def test_read_dta8(self):
     def test_read_dta9(self):
         expected = read_csv(self.csv9, parse_dates=True, sep='\t')
         parsed = self.read_dta(self.dta9)
-        assert_frame_equal(parsed, expected)
+        tm.assert_frame_equal(parsed, expected)
 
     def test_read_write_dta10(self):
         if not is_little_endian():
@@ -213,11 +226,11 @@ def test_encoding(self):
         if compat.PY3:
             expected = raw.kreis1849[0]
             self.assert_(result == expected)
-            self.assert_(isinstance(result,compat.string_types))
+            self.assert_(isinstance(result, compat.string_types))
         else:
             expected = raw.kreis1849.str.decode("latin-1")[0]
             self.assert_(result == expected)
-            self.assert_(isinstance(result,unicode))
+            self.assert_(isinstance(result, unicode))
 
 if __name__ == '__main__':
     nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],