@@ -1672,8 +1672,8 @@ def __new__(cls, data, dtype=None, copy=False, name=None, fastpath=False):
1672
1672
subarr = np .array (data , dtype = np .int64 , copy = copy )
1673
1673
if len (data ) > 0 :
1674
1674
if (subarr != data ).any ():
1675
- raise TypeError ('Unsafe NumPy casting, you must '
1676
- 'explicitly cast' )
1675
+ raise TypeError ('Unsafe NumPy casting to integer , you must'
1676
+ ' explicitly cast' )
1677
1677
1678
1678
subarr = subarr .view (cls )
1679
1679
subarr .name = name
@@ -1857,11 +1857,12 @@ class MultiIndex(Index):
1857
1857
1858
1858
def __new__ (cls , levels = None , labels = None , sortorder = None , names = None ,
1859
1859
copy = False ):
1860
+ if levels is None or labels is None :
1861
+ raise TypeError ("Must pass both levels and labels" )
1860
1862
if len (levels ) != len (labels ):
1861
- raise ValueError (
1862
- 'Length of levels and labels must be the same' )
1863
+ raise ValueError ('Length of levels and labels must be the same.' )
1863
1864
if len (levels ) == 0 :
1864
- raise TypeError ('Must pass non-zero number of levels/labels' )
1865
+ raise ValueError ('Must pass non-zero number of levels/labels' )
1865
1866
if len (levels ) == 1 :
1866
1867
if names :
1867
1868
name = names [0 ]
@@ -1872,10 +1873,12 @@ def __new__(cls, levels=None, labels=None, sortorder=None, names=None,
1872
1873
1873
1874
# v3, 0.8.0
1874
1875
subarr = np .empty (0 , dtype = object ).view (cls )
1875
- subarr ._set_levels (levels , copy = copy )
1876
- subarr ._set_labels (labels , copy = copy )
1876
+ # we've already validated levels and labels, so shortcut here
1877
+ subarr ._set_levels (levels , copy = copy , validate = False )
1878
+ subarr ._set_labels (labels , copy = copy , validate = False )
1877
1879
1878
1880
if names is not None :
1881
+ # handles name validation
1879
1882
subarr ._set_names (names )
1880
1883
1881
1884
if sortorder is not None :
@@ -1888,12 +1891,14 @@ def __new__(cls, levels=None, labels=None, sortorder=None, names=None,
1888
1891
def _get_levels (self ):
1889
1892
return self ._levels
1890
1893
1891
- def _set_levels (self , levels , copy = False ):
1894
+ def _set_levels (self , levels , copy = False , validate = True ):
1892
1895
# This is NOT part of the levels property because it should be
1893
1896
# externally not allowed to set levels. User beware if you change
1894
1897
# _levels directly
1895
- if len (levels ) == 0 :
1896
- raise ValueError ("Must set non-zero number of levels." )
1898
+ if validate and len (levels ) == 0 :
1899
+ raise ValueError ('Must set non-zero number of levels.' )
1900
+ if validate and len (levels ) != len (self ._labels ):
1901
+ raise ValueError ('Length of levels must match length of labels.' )
1897
1902
levels = FrozenList (_ensure_index (lev , copy = copy )._shallow_copy ()
1898
1903
for lev in levels )
1899
1904
names = self .names
@@ -1917,13 +1922,16 @@ def set_levels(self, levels, inplace=False):
1917
1922
-------
1918
1923
new index (of same type and class...etc)
1919
1924
"""
1925
+ if not com .is_list_like (levels ) or not com .is_list_like (levels [0 ]):
1926
+ raise TypeError ("Levels must be list of lists-like" )
1920
1927
if inplace :
1921
1928
idx = self
1922
1929
else :
1923
1930
idx = self ._shallow_copy ()
1924
1931
idx ._reset_identity ()
1925
1932
idx ._set_levels (levels )
1926
- return idx
1933
+ if not inplace :
1934
+ return idx
1927
1935
1928
1936
# remove me in 0.14 and change to read only property
1929
1937
__set_levels = deprecate ("setting `levels` directly" ,
@@ -1934,9 +1942,9 @@ def set_levels(self, levels, inplace=False):
1934
1942
def _get_labels (self ):
1935
1943
return self ._labels
1936
1944
1937
- def _set_labels (self , labels , copy = False ):
1938
- if len (labels ) != self .nlevels :
1939
- raise ValueError ("Length of levels and labels must be the same. " )
1945
+ def _set_labels (self , labels , copy = False , validate = True ):
1946
+ if validate and len (labels ) != self .nlevels :
1947
+ raise ValueError ("Length of labels must match length of levels " )
1940
1948
self ._labels = FrozenList (_ensure_frozen (labs , copy = copy )._shallow_copy ()
1941
1949
for labs in labels )
1942
1950
@@ -1956,13 +1964,16 @@ def set_labels(self, labels, inplace=False):
1956
1964
-------
1957
1965
new index (of same type and class...etc)
1958
1966
"""
1967
+ if not com .is_list_like (labels ) or not com .is_list_like (labels [0 ]):
1968
+ raise TypeError ("Labels must be list of lists-like" )
1959
1969
if inplace :
1960
1970
idx = self
1961
1971
else :
1962
1972
idx = self ._shallow_copy ()
1963
1973
idx ._reset_identity ()
1964
1974
idx ._set_labels (labels )
1965
- return idx
1975
+ if not inplace :
1976
+ return idx
1966
1977
1967
1978
# remove me in 0.14 and change to readonly property
1968
1979
__set_labels = deprecate ("setting labels directly" ,
@@ -2021,7 +2032,8 @@ def __array_finalize__(self, obj):
2021
2032
# instance.
2022
2033
return
2023
2034
2024
- self ._set_levels (getattr (obj , 'levels' , []))
2035
+ # skip the validation on first, rest will catch the errors
2036
+ self ._set_levels (getattr (obj , 'levels' , []), validate = False )
2025
2037
self ._set_labels (getattr (obj , 'labels' , []))
2026
2038
self ._set_names (getattr (obj , 'names' , []))
2027
2039
self .sortorder = getattr (obj , 'sortorder' , None )
@@ -2083,16 +2095,15 @@ def _convert_slice_indexer(self, key, typ=None):
2083
2095
def _get_names (self ):
2084
2096
return FrozenList (level .name for level in self .levels )
2085
2097
2086
- def _set_names (self , values ):
2098
+ def _set_names (self , values , validate = True ):
2087
2099
"""
2088
2100
sets names on levels. WARNING: mutates!
2089
2101
2090
2102
Note that you generally want to set this *after* changing levels, so that it only
2091
2103
acts on copies"""
2092
2104
values = list (values )
2093
- if len (values ) != self .nlevels :
2094
- raise ValueError ('Length of names (%d) must be same as level '
2095
- '(%d)' % (len (values ), self .nlevels ))
2105
+ if validate and len (values ) != self .nlevels :
2106
+ raise ValueError ('Length of names must match length of levels' )
2096
2107
# set the name
2097
2108
for name , level in zip (values , self .levels ):
2098
2109
level .rename (name , inplace = True )
@@ -2446,7 +2457,7 @@ def __setstate__(self, state):
2446
2457
np .ndarray .__setstate__ (self , nd_state )
2447
2458
levels , labels , sortorder , names = own_state
2448
2459
2449
- self ._set_levels ([Index (x ) for x in levels ])
2460
+ self ._set_levels ([Index (x ) for x in levels ], validate = False )
2450
2461
self ._set_labels (labels )
2451
2462
self ._set_names (names )
2452
2463
self .sortorder = sortorder
@@ -2473,7 +2484,7 @@ def __getitem__(self, key):
2473
2484
new_labels = [lab [key ] for lab in self .labels ]
2474
2485
2475
2486
# an optimization
2476
- result ._set_levels (self .levels )
2487
+ result ._set_levels (self .levels , validate = False )
2477
2488
result ._set_labels (new_labels )
2478
2489
result .sortorder = sortorder
2479
2490
result ._set_names (self .names )
@@ -3351,17 +3362,12 @@ def _ensure_index(index_like, copy=False):
3351
3362
return Index (index_like )
3352
3363
3353
3364
3354
- def _ensure_frozen (nd_array_like , copy = False ):
3355
- if not isinstance (nd_array_like , FrozenNDArray ):
3356
- arr = np .asarray (nd_array_like , dtype = np .int_ )
3357
- # have to do this separately so that non-index input gets copied
3358
- if copy :
3359
- arr = arr .copy ()
3360
- nd_array_like = arr .view (FrozenNDArray )
3361
- else :
3362
- if copy :
3363
- nd_array_like = nd_array_like .copy ()
3364
- return nd_array_like
3365
+ def _ensure_frozen (array_like , copy = False ):
3366
+ array_like = np .asanyarray (array_like , dtype = np .int_ )
3367
+ array_like = array_like .view (FrozenNDArray )
3368
+ if copy :
3369
+ array_like = array_like .copy ()
3370
+ return array_like
3365
3371
3366
3372
3367
3373
def _validate_join_method (method ):
0 commit comments