<p dir="auto">Hi,</p>
<p dir="auto">I am running on the git cloned version of <code class="notranslate">pandas</code>, and there seems to be quite a few issues with user defined classes extending <code class="notranslate">DataFrame</code>.</p>
<p dir="auto">It seems that <code class="notranslate">DataFrame</code> class constructor is hardcoded in a lot of places, where <code class="notranslate">self.__class__</code> or <code class="notranslate">cls</code> constructors should be used instead. This causes some weird behaviour.</p>
<p dir="auto">Allow me to illustrate, let's import pandas and define some class that would extend <code class="notranslate">DataFrame</code></p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="In[2]: import pandas as pd
In [3]: pd.__version__
Out[3]: '0.10.1'
In [4]: class ClassExtendingDataFrame(pd.DataFrame):
   ...:     pass
   ...: "><pre class="notranslate"><span class="pl-v">In</span>[<span class="pl-c1">2</span>]: <span class="pl-s1">import</span> <span class="pl-s1">pandas</span> <span class="pl-k">as</span> <span class="pl-s1">pd</span>
<span class="pl-v">In</span> [<span class="pl-c1">3</span>]: <span class="pl-s1">pd</span>.<span class="pl-s1">__version__</span>
<span class="pl-v">Out</span>[<span class="pl-c1">3</span>]: <span class="pl-s">'0.10.1'</span>
<span class="pl-v">In</span> [<span class="pl-c1">4</span>]: <span class="pl-s1">class</span> <span class="pl-v">ClassExtendingDataFrame</span>(<span class="pl-s1">pd</span>.<span class="pl-v">DataFrame</span>):
   ...:     <span class="pl-s1">pass</span>
   ...: </pre></div>
<p dir="auto">Note that <code class="notranslate">ClassExtendingDataFrame</code> does not override anything and is essentially the same <code class="notranslate">DataFrame</code>, just renamed.</p>
<p dir="auto">Now one would expect a new instance of <code class="notranslate">ClassExtendingDataFrame</code> to be created by the following code:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="In [5]: dict = {'a' : [1,2,3], 'b': [2,3,4]}
In [6]: x = ClassExtendingDataFrame.from_dict(dict)"><pre class="notranslate"><span class="pl-v">In</span> [<span class="pl-c1">5</span>]: <span class="pl-s1">dict</span> <span class="pl-c1">=</span> {<span class="pl-s">'a'</span> : [<span class="pl-c1">1</span>,<span class="pl-c1">2</span>,<span class="pl-c1">3</span>], <span class="pl-s">'b'</span>: [<span class="pl-c1">2</span>,<span class="pl-c1">3</span>,<span class="pl-c1">4</span>]}
<span class="pl-v">In</span> [<span class="pl-c1">6</span>]: <span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-v">ClassExtendingDataFrame</span>.<span class="pl-en">from_dict</span>(<span class="pl-s1">dict</span>)</pre></div>
<p dir="auto">Unfortunately:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="In [10]: assert(isinstance(x, ClassExtendingDataFrame))
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
&lt;ipython-input-10-3f1ceeb1b90f&gt; in &lt;module&gt;()
----&gt; 1 assert(isinstance(x, ClassExtendingDataFrame))

AssertionError: 

In [11]: type(x)
Out[11]: pandas.core.frame.DataFrame"><pre class="notranslate"><span class="pl-v">In</span> [<span class="pl-c1">10</span>]: <span class="pl-en">assert</span>(<span class="pl-en">isinstance</span>(<span class="pl-s1">x</span>, <span class="pl-v">ClassExtendingDataFrame</span>))
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span>
<span class="pl-v">AssertionError</span>                            <span class="pl-v">Traceback</span> (<span class="pl-s1">most</span> <span class="pl-s1">recent</span> <span class="pl-s1">call</span> <span class="pl-s1">last</span>)
<span class="pl-c1">&lt;</span><span class="pl-s1">ipython</span><span class="pl-c1">-</span><span class="pl-s1">input</span><span class="pl-c1">-</span><span class="pl-c1">10</span><span class="pl-c1">-</span><span class="pl-c1">3</span><span class="pl-s1">f1ceeb1b90f</span><span class="pl-c1">&gt;</span> <span class="pl-s1">in</span> <span class="pl-c1">&lt;</span><span class="pl-s1">module</span><span class="pl-c1">&gt;</span>()
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">&gt;</span> <span class="pl-c1">1</span> <span class="pl-en">assert</span>(<span class="pl-en">isinstance</span>(<span class="pl-s1">x</span>, <span class="pl-v">ClassExtendingDataFrame</span>))

<span class="pl-v">AssertionError</span>: 

<span class="pl-v">In</span> [<span class="pl-c1">11</span>]: <span class="pl-s1">type</span>(<span class="pl-s1">x</span>)
<span class="pl-v">Out</span>[<span class="pl-c1">11</span>]: <span class="pl-s1">pandas</span>.<span class="pl-s1">core</span>.<span class="pl-s1">frame</span>.<span class="pl-v">DataFrame</span></pre></div>
<p dir="auto">This is due to <code class="notranslate">DataFrame</code> being hardcoded in <code class="notranslate">from_dict</code>: <a href="https://github.com/pydata/pandas/blob/master/pandas/core/frame.py#L905">https://github.com/pydata/pandas/blob/master/pandas/core/frame.py#L905</a> .<br>
<code class="notranslate">cls</code> variable should be used here.</p>
<p dir="auto">Note that <code class="notranslate">ClassExtendingDataFrame</code> is initialised using constructor, rather than <code class="notranslate">from_dict</code> method, correct object is created:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="In [12]: a = ClassExtendingDataFrame(dict)
In [13]: isinstance(a, ClassExtendingDataFrame)
Out[13]: True"><pre class="notranslate"><span class="pl-v">In</span> [<span class="pl-c1">12</span>]: <span class="pl-s1">a</span> <span class="pl-c1">=</span> <span class="pl-v">ClassExtendingDataFrame</span>(<span class="pl-s1">dict</span>)
<span class="pl-v">In</span> [<span class="pl-c1">13</span>]: <span class="pl-en">isinstance</span>(<span class="pl-s1">a</span>, <span class="pl-v">ClassExtendingDataFrame</span>)
<span class="pl-v">Out</span>[<span class="pl-c1">13</span>]: <span class="pl-c1">True</span></pre></div>
<p dir="auto">However, operations as simple as slicing break this:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="In [14]: isinstance(a[:5], ClassExtendingDataFrame)
Out[14]: False"><pre class="notranslate"><span class="pl-v">In</span> [<span class="pl-c1">14</span>]: <span class="pl-en">isinstance</span>(<span class="pl-s1">a</span>[:<span class="pl-c1">5</span>], <span class="pl-v">ClassExtendingDataFrame</span>)
<span class="pl-v">Out</span>[<span class="pl-c1">14</span>]: <span class="pl-c1">False</span></pre></div>
<p dir="auto">These are just the two examples I have noticed myself, but I am sure there could be more.<br>
A thorough review of Hardcoded <code class="notranslate">DataFrame</code> constructors is needed to check if they could be replaced by <code class="notranslate">self.__class__</code> or <code class="notranslate">cls</code> instead.</p>
<p dir="auto"><a href="https://travis-ci.org/pandas-dev/pandas/jobs/267760269" rel="nofollow">https://travis-ci.org/pandas-dev/pandas/jobs/267760269</a></p>
<p dir="auto">Master and some PRs (strangely not all) are all failing on the same test, but only on Mac:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="=================================== FAILURES ===================================
_____________________ TestCategoricalIndex.test_reindexing _____________________
[gw1] darwin -- Python 3.5.4 /Users/travis/miniconda3/envs/pandas/bin/python
self = &lt;pandas.tests.indexes.test_category.TestCategoricalIndex object at 0x111d5e860&gt;
    def test_reindexing(self):
    
        ci = self.create_index()
        oidx = Index(np.array(ci))
    
        for n in [1, 2, 5, len(ci)]:
            finder = oidx[np.random.randint(0, len(ci), size=n)]
            expected = oidx.get_indexer_non_unique(finder)[0]
    
            actual = ci.get_indexer(finder)
&gt;           tm.assert_numpy_array_equal(expected, actual)
pandas/tests/indexes/test_category.py:389: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
pandas/util/testing.py:1174: in assert_numpy_array_equal
    _raise(left, right, err_msg)
pandas/util/testing.py:1157: in _raise
    .format(obj=obj), left.shape, right.shape)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
obj = 'numpy array', message = 'numpy array shapes are different', left = (14,)
right = (6,), diff = None
    def raise_assert_detail(obj, message, left, right, diff=None):
        if isinstance(left, np.ndarray):
            left = pprint_thing(left)
        if isinstance(right, np.ndarray):
            right = pprint_thing(right)
    
        msg = &quot;&quot;&quot;{obj} are different
    
    {message}
    [left]:  {left}
    [right]: {right}&quot;&quot;&quot;.format(obj=obj, message=message, left=left, right=right)
    
        if diff is not None:
            msg += &quot;\n[diff]: {diff}&quot;.format(diff=diff)
    
&gt;       raise AssertionError(msg)
E       AssertionError: numpy array are different
E       
E       numpy array shapes are different
E       [left]:  (14,)
E       [right]: (6,)
pandas/util/testing.py:1105: AssertionError"><pre class="notranslate"><code class="notranslate">=================================== FAILURES ===================================
_____________________ TestCategoricalIndex.test_reindexing _____________________
[gw1] darwin -- Python 3.5.4 /Users/travis/miniconda3/envs/pandas/bin/python
self = &lt;pandas.tests.indexes.test_category.TestCategoricalIndex object at 0x111d5e860&gt;
    def test_reindexing(self):
    
        ci = self.create_index()
        oidx = Index(np.array(ci))
    
        for n in [1, 2, 5, len(ci)]:
            finder = oidx[np.random.randint(0, len(ci), size=n)]
            expected = oidx.get_indexer_non_unique(finder)[0]
    
            actual = ci.get_indexer(finder)
&gt;           tm.assert_numpy_array_equal(expected, actual)
pandas/tests/indexes/test_category.py:389: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
pandas/util/testing.py:1174: in assert_numpy_array_equal
    _raise(left, right, err_msg)
pandas/util/testing.py:1157: in _raise
    .format(obj=obj), left.shape, right.shape)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
obj = 'numpy array', message = 'numpy array shapes are different', left = (14,)
right = (6,), diff = None
    def raise_assert_detail(obj, message, left, right, diff=None):
        if isinstance(left, np.ndarray):
            left = pprint_thing(left)
        if isinstance(right, np.ndarray):
            right = pprint_thing(right)
    
        msg = """{obj} are different
    
    {message}
    [left]:  {left}
    [right]: {right}""".format(obj=obj, message=message, left=left, right=right)
    
        if diff is not None:
            msg += "\n[diff]: {diff}".format(diff=diff)
    
&gt;       raise AssertionError(msg)
E       AssertionError: numpy array are different
E       
E       numpy array shapes are different
E       [left]:  (14,)
E       [right]: (6,)
pandas/util/testing.py:1105: AssertionError
</code></pre></div>