Skip to content

Commit 58e1cb0

Browse files
committed
CLN: split off frozen (immutable) data structures into pandas/indexes/frozen.py
1 parent f4edb05 commit 58e1cb0

File tree

7 files changed

+220
-193
lines changed

7 files changed

+220
-193
lines changed

Diff for: pandas/compat/pickle_compat.py

+19-8
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,25 @@ def load_reduce(self):
5252

5353
stack[-1] = value
5454

55-
if compat.PY3:
56-
class Unpickler(pkl._Unpickler):
57-
pass
58-
else:
59-
class Unpickler(pkl.Unpickler):
60-
pass
55+
56+
# if classes are moved, provide compat here
57+
_class_locations_map = {
58+
59+
# 15477
60+
('pandas.core.base', 'FrozenNDArray'): ('pandas.indexes.frozen', 'FrozenNDArray'),
61+
('pandas.core.base', 'FrozenList'): ('pandas.indexes.frozen', 'FrozenList')
62+
}
63+
64+
65+
# our Unpickler sub-class to override methods and some dispatcher
66+
# functions for compat
67+
base_class = pkl._Unpickler if compat.PY3 else pkl.Unpickler
68+
class Unpickler(base_class):
69+
70+
def find_class(self, module, name):
71+
key = (module, name)
72+
module, name = _class_locations_map.get(key, key)
73+
return super(Unpickler, self).find_class(module, name)
6174

6275
Unpickler.dispatch = copy.copy(Unpickler.dispatch)
6376
Unpickler.dispatch[pkl.REDUCE[0]] = load_reduce
@@ -76,8 +89,6 @@ def load_newobj(self):
7689
self.stack[-1] = obj
7790
Unpickler.dispatch[pkl.NEWOBJ[0]] = load_newobj
7891

79-
# py3 compat
80-
8192

8293
def load_newobj_ex(self):
8394
kwargs = self.stack.pop()

Diff for: pandas/core/base.py

-105
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
from pandas.util.decorators import (Appender, cache_readonly,
1818
deprecate_kwarg, Substitution)
1919
from pandas.core.common import AbstractMethodError
20-
from pandas.formats.printing import pprint_thing
2120

2221
_shared_docs = dict()
2322
_indexops_doc_kwargs = dict(klass='IndexOpsMixin', inplace='',
@@ -694,110 +693,6 @@ def _gotitem(self, key, ndim, subset=None):
694693
return self
695694

696695

697-
class FrozenList(PandasObject, list):
698-
699-
"""
700-
Container that doesn't allow setting item *but*
701-
because it's technically non-hashable, will be used
702-
for lookups, appropriately, etc.
703-
"""
704-
# Sidenote: This has to be of type list, otherwise it messes up PyTables
705-
# typechecks
706-
707-
def __add__(self, other):
708-
if isinstance(other, tuple):
709-
other = list(other)
710-
return self.__class__(super(FrozenList, self).__add__(other))
711-
712-
__iadd__ = __add__
713-
714-
# Python 2 compat
715-
def __getslice__(self, i, j):
716-
return self.__class__(super(FrozenList, self).__getslice__(i, j))
717-
718-
def __getitem__(self, n):
719-
# Python 3 compat
720-
if isinstance(n, slice):
721-
return self.__class__(super(FrozenList, self).__getitem__(n))
722-
return super(FrozenList, self).__getitem__(n)
723-
724-
def __radd__(self, other):
725-
if isinstance(other, tuple):
726-
other = list(other)
727-
return self.__class__(other + list(self))
728-
729-
def __eq__(self, other):
730-
if isinstance(other, (tuple, FrozenList)):
731-
other = list(other)
732-
return super(FrozenList, self).__eq__(other)
733-
734-
__req__ = __eq__
735-
736-
def __mul__(self, other):
737-
return self.__class__(super(FrozenList, self).__mul__(other))
738-
739-
__imul__ = __mul__
740-
741-
def __reduce__(self):
742-
return self.__class__, (list(self),)
743-
744-
def __hash__(self):
745-
return hash(tuple(self))
746-
747-
def _disabled(self, *args, **kwargs):
748-
"""This method will not function because object is immutable."""
749-
raise TypeError("'%s' does not support mutable operations." %
750-
self.__class__.__name__)
751-
752-
def __unicode__(self):
753-
return pprint_thing(self, quote_strings=True,
754-
escape_chars=('\t', '\r', '\n'))
755-
756-
def __repr__(self):
757-
return "%s(%s)" % (self.__class__.__name__,
758-
str(self))
759-
760-
__setitem__ = __setslice__ = __delitem__ = __delslice__ = _disabled
761-
pop = append = extend = remove = sort = insert = _disabled
762-
763-
764-
class FrozenNDArray(PandasObject, np.ndarray):
765-
766-
# no __array_finalize__ for now because no metadata
767-
def __new__(cls, data, dtype=None, copy=False):
768-
if copy is None:
769-
copy = not isinstance(data, FrozenNDArray)
770-
res = np.array(data, dtype=dtype, copy=copy).view(cls)
771-
return res
772-
773-
def _disabled(self, *args, **kwargs):
774-
"""This method will not function because object is immutable."""
775-
raise TypeError("'%s' does not support mutable operations." %
776-
self.__class__)
777-
778-
__setitem__ = __setslice__ = __delitem__ = __delslice__ = _disabled
779-
put = itemset = fill = _disabled
780-
781-
def _shallow_copy(self):
782-
return self.view()
783-
784-
def values(self):
785-
"""returns *copy* of underlying array"""
786-
arr = self.view(np.ndarray).copy()
787-
return arr
788-
789-
def __unicode__(self):
790-
"""
791-
Return a string representation for this object.
792-
793-
Invoked by unicode(df) in py2 only. Yields a Unicode String in both
794-
py2/py3.
795-
"""
796-
prepr = pprint_thing(self, escape_chars=('\t', '\r', '\n'),
797-
quote_strings=True)
798-
return "%s(%s, dtype='%s')" % (type(self).__name__, prepr, self.dtype)
799-
800-
801696
class IndexOpsMixin(object):
802697
""" common ops mixin to support a unified inteface / docs for Series /
803698
Index

Diff for: pandas/indexes/base.py

+2-11
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,15 @@
3535
needs_i8_conversion,
3636
is_iterator, is_list_like,
3737
is_scalar)
38-
from pandas.types.cast import _coerce_indexer_dtype
3938
from pandas.core.common import (is_bool_indexer,
4039
_values_from_object,
4140
_asarray_tuplesafe)
4241

43-
from pandas.core.base import (PandasObject, FrozenList, FrozenNDArray,
44-
IndexOpsMixin)
42+
from pandas.core.base import PandasObject, IndexOpsMixin
4543
import pandas.core.base as base
4644
from pandas.util.decorators import (Appender, Substitution, cache_readonly,
4745
deprecate, deprecate_kwarg)
46+
from pandas.indexes.frozen import FrozenList
4847
import pandas.core.common as com
4948
import pandas.types.concat as _concat
5049
import pandas.core.missing as missing
@@ -3844,14 +3843,6 @@ def _get_na_value(dtype):
38443843
np.timedelta64: tslib.NaT}.get(dtype, np.nan)
38453844

38463845

3847-
def _ensure_frozen(array_like, categories, copy=False):
3848-
array_like = _coerce_indexer_dtype(array_like, categories)
3849-
array_like = array_like.view(FrozenNDArray)
3850-
if copy:
3851-
array_like = array_like.copy()
3852-
return array_like
3853-
3854-
38553846
def _ensure_has_len(seq):
38563847
"""If seq is an iterator, put its values into a list."""
38573848
try:

Diff for: pandas/indexes/frozen.py

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
"""
2+
frozen (immutable) data structures to support MultiIndexing
3+
4+
These are used for:
5+
6+
- .names (FrozenList)
7+
- .levels & .labels (FrozenNDArray)
8+
9+
"""
10+
11+
import numpy as np
12+
from pandas.core.base import PandasObject
13+
from pandas.types.cast import _coerce_indexer_dtype
14+
from pandas.formats.printing import pprint_thing
15+
16+
17+
class FrozenList(PandasObject, list):
18+
19+
"""
20+
Container that doesn't allow setting item *but*
21+
because it's technically non-hashable, will be used
22+
for lookups, appropriately, etc.
23+
"""
24+
# Sidenote: This has to be of type list, otherwise it messes up PyTables
25+
# typechecks
26+
27+
def __add__(self, other):
28+
if isinstance(other, tuple):
29+
other = list(other)
30+
return self.__class__(super(FrozenList, self).__add__(other))
31+
32+
__iadd__ = __add__
33+
34+
# Python 2 compat
35+
def __getslice__(self, i, j):
36+
return self.__class__(super(FrozenList, self).__getslice__(i, j))
37+
38+
def __getitem__(self, n):
39+
# Python 3 compat
40+
if isinstance(n, slice):
41+
return self.__class__(super(FrozenList, self).__getitem__(n))
42+
return super(FrozenList, self).__getitem__(n)
43+
44+
def __radd__(self, other):
45+
if isinstance(other, tuple):
46+
other = list(other)
47+
return self.__class__(other + list(self))
48+
49+
def __eq__(self, other):
50+
if isinstance(other, (tuple, FrozenList)):
51+
other = list(other)
52+
return super(FrozenList, self).__eq__(other)
53+
54+
__req__ = __eq__
55+
56+
def __mul__(self, other):
57+
return self.__class__(super(FrozenList, self).__mul__(other))
58+
59+
__imul__ = __mul__
60+
61+
def __reduce__(self):
62+
return self.__class__, (list(self),)
63+
64+
def __hash__(self):
65+
return hash(tuple(self))
66+
67+
def _disabled(self, *args, **kwargs):
68+
"""This method will not function because object is immutable."""
69+
raise TypeError("'%s' does not support mutable operations." %
70+
self.__class__.__name__)
71+
72+
def __unicode__(self):
73+
return pprint_thing(self, quote_strings=True,
74+
escape_chars=('\t', '\r', '\n'))
75+
76+
def __repr__(self):
77+
return "%s(%s)" % (self.__class__.__name__,
78+
str(self))
79+
80+
__setitem__ = __setslice__ = __delitem__ = __delslice__ = _disabled
81+
pop = append = extend = remove = sort = insert = _disabled
82+
83+
84+
class FrozenNDArray(PandasObject, np.ndarray):
85+
86+
# no __array_finalize__ for now because no metadata
87+
def __new__(cls, data, dtype=None, copy=False):
88+
if copy is None:
89+
copy = not isinstance(data, FrozenNDArray)
90+
res = np.array(data, dtype=dtype, copy=copy).view(cls)
91+
return res
92+
93+
def _disabled(self, *args, **kwargs):
94+
"""This method will not function because object is immutable."""
95+
raise TypeError("'%s' does not support mutable operations." %
96+
self.__class__)
97+
98+
__setitem__ = __setslice__ = __delitem__ = __delslice__ = _disabled
99+
put = itemset = fill = _disabled
100+
101+
def _shallow_copy(self):
102+
return self.view()
103+
104+
def values(self):
105+
"""returns *copy* of underlying array"""
106+
arr = self.view(np.ndarray).copy()
107+
return arr
108+
109+
def __unicode__(self):
110+
"""
111+
Return a string representation for this object.
112+
113+
Invoked by unicode(df) in py2 only. Yields a Unicode String in both
114+
py2/py3.
115+
"""
116+
prepr = pprint_thing(self, escape_chars=('\t', '\r', '\n'),
117+
quote_strings=True)
118+
return "%s(%s, dtype='%s')" % (type(self).__name__, prepr, self.dtype)
119+
120+
121+
def _ensure_frozen(array_like, categories, copy=False):
122+
array_like = _coerce_indexer_dtype(array_like, categories)
123+
array_like = array_like.view(FrozenNDArray)
124+
if copy:
125+
array_like = array_like.copy()
126+
return array_like

Diff for: pandas/indexes/multi.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
UnsortedIndexError)
2929

3030

31-
from pandas.core.base import FrozenList
3231
import pandas.core.base as base
3332
from pandas.util.decorators import (Appender, cache_readonly,
3433
deprecate, deprecate_kwarg)
@@ -39,9 +38,10 @@
3938

4039
from pandas.core.config import get_option
4140

42-
from pandas.indexes.base import (Index, _ensure_index, _ensure_frozen,
41+
from pandas.indexes.base import (Index, _ensure_index,
4342
_get_na_value, InvalidIndexError,
4443
_index_shared_docs)
44+
from pandas.indexes.frozen import FrozenNDArray, FrozenList, _ensure_frozen
4545
import pandas.indexes.base as ibase
4646
_index_doc_kwargs = dict(ibase._index_doc_kwargs)
4747
_index_doc_kwargs.update(
@@ -1276,7 +1276,7 @@ def _assert_take_fillable(self, values, indices, allow_fill=True,
12761276
for new_label in taken:
12771277
label_values = new_label.values()
12781278
label_values[mask] = na_value
1279-
masked.append(base.FrozenNDArray(label_values))
1279+
masked.append(FrozenNDArray(label_values))
12801280
taken = masked
12811281
else:
12821282
taken = [lab.take(indices) for lab in self.labels]

0 commit comments

Comments
 (0)