@@ -55,7 +55,7 @@ class NumericIndex(Index):
5555 """
5656
5757 _values : np .ndarray
58- _default_dtype : np .dtype
58+ _default_dtype : np .dtype | None = None
5959 _dtype_validation_metadata : tuple [Callable [..., bool ], str ]
6060
6161 _is_numeric_dtype = True
@@ -88,7 +88,10 @@ def _ensure_array(cls, data, dtype, copy: bool):
8888 if issubclass (data .dtype .type , str ):
8989 cls ._string_data_error (data )
9090
91- if copy or not is_dtype_equal (data .dtype , cls ._default_dtype ):
91+ if copy or (
92+ cls ._default_dtype is not None
93+ and not is_dtype_equal (data .dtype , cls ._default_dtype )
94+ ):
9295 subarr = np .array (data , dtype = cls ._default_dtype , copy = copy )
9396 cls ._assert_safe_casting (data , subarr )
9497 else :
@@ -202,173 +205,6 @@ def _is_all_dates(self) -> bool:
202205 An Index instance can **only** contain hashable objects.
203206"""
204207
205- _int64_descr_args = {
206- "klass" : "Int64Index" ,
207- "ltype" : "integer" ,
208- "dtype" : "int64" ,
209- "extra" : "" ,
210- }
211-
212-
213- class IntegerIndex (NumericIndex ):
214- """
215- This is an abstract class for Int64Index, UInt64Index.
216- """
217-
218- _default_dtype : np .dtype
219- _can_hold_na = False
220-
221- @classmethod
222- def _assert_safe_casting (cls , data , subarr ):
223- """
224- Ensure incoming data can be represented with matching signed-ness.
225- """
226- if data .dtype .kind != cls ._default_dtype .kind :
227- if not np .array_equal (data , subarr ):
228- raise TypeError ("Unsafe NumPy casting, you must explicitly cast" )
229-
230- def __contains__ (self , key ) -> bool :
231- """
232- Check if key is a float and has a decimal. If it has, return False.
233- """
234- hash (key )
235- try :
236- if is_float (key ) and int (key ) != key :
237- # otherwise the `key in self._engine` check casts e.g. 1.1 -> 1
238- return False
239- return key in self ._engine
240- except (OverflowError , TypeError , ValueError ):
241- return False
242-
243- @property
244- def inferred_type (self ) -> str :
245- """
246- Always 'integer' for ``Int64Index`` and ``UInt64Index``
247- """
248- return "integer"
249-
250- @property
251- def asi8 (self ) -> np .ndarray :
252- # do not cache or you'll create a memory leak
253- warnings .warn (
254- "Index.asi8 is deprecated and will be removed in a future version" ,
255- FutureWarning ,
256- stacklevel = 2 ,
257- )
258- return self ._values .view (self ._default_dtype )
259-
260-
261- class Int64Index (IntegerIndex ):
262- __doc__ = _num_index_shared_docs ["class_descr" ] % _int64_descr_args
263-
264- _typ = "int64index"
265- _engine_type = libindex .Int64Engine
266- _default_dtype = np .dtype (np .int64 )
267- _dtype_validation_metadata = (is_signed_integer_dtype , "signed integer" )
268-
269-
270- _uint64_descr_args = {
271- "klass" : "UInt64Index" ,
272- "ltype" : "unsigned integer" ,
273- "dtype" : "uint64" ,
274- "extra" : "" ,
275- }
276-
277-
278- class UInt64Index (IntegerIndex ):
279- __doc__ = _num_index_shared_docs ["class_descr" ] % _uint64_descr_args
280-
281- _typ = "uint64index"
282- _engine_type = libindex .UInt64Engine
283- _default_dtype = np .dtype (np .uint64 )
284- _dtype_validation_metadata = (is_unsigned_integer_dtype , "unsigned integer" )
285-
286- # ----------------------------------------------------------------
287- # Indexing Methods
288-
289- @doc (Index ._convert_arr_indexer )
290- def _convert_arr_indexer (self , keyarr ):
291- # Cast the indexer to uint64 if possible so that the values returned
292- # from indexing are also uint64.
293- dtype = None
294- if is_integer_dtype (keyarr ) or (
295- lib .infer_dtype (keyarr , skipna = False ) == "integer"
296- ):
297- dtype = np .dtype (np .uint64 )
298-
299- return com .asarray_tuplesafe (keyarr , dtype = dtype )
300-
301-
302- _float64_descr_args = {
303- "klass" : "Float64Index" ,
304- "dtype" : "float64" ,
305- "ltype" : "float" ,
306- "extra" : "" ,
307- }
308-
309-
310- class Float64Index (NumericIndex ):
311- __doc__ = _num_index_shared_docs ["class_descr" ] % _float64_descr_args
312-
313- _typ = "float64index"
314- _engine_type = libindex .Float64Engine
315- _default_dtype = np .dtype (np .float64 )
316- _dtype_validation_metadata = (is_float_dtype , "float" )
317-
318- @property
319- def inferred_type (self ) -> str :
320- """
321- Always 'floating' for ``Float64Index``
322- """
323- return "floating"
324-
325- @doc (Index .astype )
326- def astype (self , dtype , copy = True ):
327- dtype = pandas_dtype (dtype )
328- if needs_i8_conversion (dtype ):
329- raise TypeError (
330- f"Cannot convert Float64Index to dtype { dtype } ; integer "
331- "values are required for conversion"
332- )
333- elif is_integer_dtype (dtype ) and not is_extension_array_dtype (dtype ):
334- # TODO(jreback); this can change once we have an EA Index type
335- # GH 13149
336- arr = astype_nansafe (self ._values , dtype = dtype )
337- return Int64Index (arr , name = self .name )
338- return super ().astype (dtype , copy = copy )
339-
340- # ----------------------------------------------------------------
341- # Indexing Methods
342-
343- @doc (Index ._should_fallback_to_positional )
344- def _should_fallback_to_positional (self ) -> bool :
345- return False
346-
347- @doc (Index ._convert_slice_indexer )
348- def _convert_slice_indexer (self , key : slice , kind : str ):
349- assert kind in ["loc" , "getitem" ]
350-
351- # We always treat __getitem__ slicing as label-based
352- # translate to locations
353- return self .slice_indexer (key .start , key .stop , key .step , kind = kind )
354-
355- # ----------------------------------------------------------------
356-
357- def _format_native_types (
358- self , na_rep = "" , float_format = None , decimal = "." , quoting = None , ** kwargs
359- ):
360- from pandas .io .formats .format import FloatArrayFormatter
361-
362- formatter = FloatArrayFormatter (
363- self ._values ,
364- na_rep = na_rep ,
365- float_format = float_format ,
366- decimal = decimal ,
367- quoting = quoting ,
368- fixed_width = False ,
369- )
370- return formatter .get_result_as_array ()
371-
372208
373209_numindex_descr_args = {
374210 "klass" : "NumIndex" ,
@@ -382,7 +218,6 @@ class NumIndex(NumericIndex):
382218 __doc__ = _num_index_shared_docs ["class_descr" ] % _numindex_descr_args
383219
384220 _typ = "numindex"
385- _default_dtype : np .dtype
386221 _dtype_validation_metadata = (is_numeric_dtype , "numeric type" )
387222
388223 @cache_readonly
@@ -416,21 +251,13 @@ def inferred_type(self) -> str:
416251 }[self .dtype .kind ]
417252
418253 @classmethod
419- def _ensure_array (cls , data , dtype , copy : bool ) -> np .ndarray :
420- """
421- Ensure we have a valid array to pass to _simple_new.
422- """
423- arr = np .array (data , dtype = dtype , copy = copy )
424- cls ._validate_dtype (arr .dtype )
425- return arr
426-
427- @classmethod
428- def _assert_safe_casting (cls , data , subarr ):
254+ def _assert_safe_casting (cls , data , subarr ) -> None :
429255 """
430256 Ensure incoming data can be represented with matching signed-ness.
431257 """
432- if data .dtype .kind not in {"i" , "u" } and not np .array_equal (data , subarr ):
433- raise TypeError ("Unsafe NumPy casting, you must explicitly cast" )
258+ if is_integer_dtype (subarr .dtype ):
259+ if not np .array_equal (data , subarr ):
260+ raise TypeError ("Unsafe NumPy casting, you must explicitly cast" )
434261
435262 def __contains__ (self , key ) -> bool :
436263 """
@@ -450,11 +277,7 @@ def __contains__(self, key) -> bool:
450277
451278 @doc (Index .astype )
452279 def astype (self , dtype , copy = True ):
453- if is_categorical_dtype (dtype ):
454- from pandas import CategoricalIndex
455-
456- return CategoricalIndex (self , name = self .name , dtype = dtype , copy = copy )
457- elif is_float_dtype (dtype ):
280+ if is_float_dtype (self .dtype ):
458281 dtype = pandas_dtype (dtype )
459282 if needs_i8_conversion (dtype ):
460283 raise TypeError (
@@ -465,17 +288,52 @@ def astype(self, dtype, copy=True):
465288 # TODO(jreback); this can change once we have an EA Index type
466289 # GH 13149
467290 arr = astype_nansafe (self ._values , dtype = dtype )
468- return type (self )(arr , name = self .name , dtype = dtype )
291+ if isinstance (self , Float64Index ):
292+ return Int64Index (arr , name = self .name )
293+ else :
294+ return NumIndex (arr , name = self .name , dtype = dtype )
295+ elif is_categorical_dtype (dtype ):
296+ from pandas import CategoricalIndex
297+
298+ return CategoricalIndex (self , name = self .name , dtype = dtype , copy = copy )
469299
470300 return super ().astype (dtype , copy = copy )
471301
302+ # ----------------------------------------------------------------
303+ # Indexing Methods
304+
305+ @doc (Index ._should_fallback_to_positional )
306+ def _should_fallback_to_positional (self ) -> bool :
307+ if self .inferred_type == "floating" :
308+ return False
309+
310+ return super ()._should_fallback_to_positional ()
311+
472312 @doc (Index ._convert_slice_indexer )
473313 def _convert_slice_indexer (self , key : slice , kind : str ):
474- assert kind in ["loc" , "getitem" ]
314+ if is_float_dtype (self .dtype ):
315+ assert kind in ["loc" , "getitem" ]
316+
317+ # We always treat __getitem__ slicing as label-based
318+ # translate to locations
319+ return self .slice_indexer (key .start , key .stop , key .step , kind = kind )
320+
321+ return super ()._convert_slice_indexer (key , kind = kind )
322+
323+ @doc (Index ._convert_arr_indexer )
324+ def _convert_arr_indexer (self , keyarr ) -> np .ndarray :
325+ if is_unsigned_integer_dtype (self .dtype ):
326+ # Cast the indexer to uint64 if possible so that the values returned
327+ # from indexing are also uint64.
328+ dtype = None
329+ if is_integer_dtype (keyarr ) or (
330+ lib .infer_dtype (keyarr , skipna = False ) == "integer"
331+ ):
332+ dtype = np .dtype (np .uint64 )
475333
476- # We always treat __getitem__ slicing as label-based
477- # translate to locations
478- return self . slice_indexer ( key . start , key . stop , key . step , kind = kind )
334+ return com . asarray_tuplesafe ( keyarr , dtype = dtype )
335+
336+ return super (). _convert_arr_indexer ( keyarr )
479337
480338 # ----------------------------------------------------------------
481339
@@ -502,3 +360,67 @@ def _format_native_types(
502360 fixed_width = False ,
503361 )
504362 return formatter .get_result_as_array ()
363+
364+
365+ _int64_descr_args = {
366+ "klass" : "Int64Index" ,
367+ "ltype" : "integer" ,
368+ "dtype" : "int64" ,
369+ "extra" : "" ,
370+ }
371+
372+
373+ class Int64Index (NumIndex ):
374+ __doc__ = _num_index_shared_docs ["class_descr" ] % _int64_descr_args
375+
376+ _typ = "int64index"
377+ _engine_type = libindex .Int64Engine
378+ _default_dtype = np .dtype (np .int64 )
379+ _dtype_validation_metadata = (is_signed_integer_dtype , "signed integer" )
380+
381+ @property
382+ def asi8 (self ) -> np .ndarray :
383+ # do not cache or you'll create a memory leak
384+ warnings .warn (
385+ "Index.asi8 is deprecated and will be removed in a future version" ,
386+ FutureWarning ,
387+ stacklevel = 2 ,
388+ )
389+ return self ._values .view (self ._default_dtype )
390+
391+
392+ _uint64_descr_args = {
393+ "klass" : "UInt64Index" ,
394+ "ltype" : "unsigned integer" ,
395+ "dtype" : "uint64" ,
396+ "extra" : "" ,
397+ }
398+
399+
400+ class UInt64Index (NumIndex ):
401+ __doc__ = _num_index_shared_docs ["class_descr" ] % _uint64_descr_args
402+
403+ _typ = "uint64index"
404+ _engine_type = libindex .UInt64Engine
405+ _default_dtype = np .dtype (np .uint64 )
406+ _dtype_validation_metadata = (is_unsigned_integer_dtype , "unsigned integer" )
407+
408+ # ----------------------------------------------------------------
409+ # Indexing Methods
410+
411+
412+ _float64_descr_args = {
413+ "klass" : "Float64Index" ,
414+ "dtype" : "float64" ,
415+ "ltype" : "float" ,
416+ "extra" : "" ,
417+ }
418+
419+
420+ class Float64Index (NumIndex ):
421+ __doc__ = _num_index_shared_docs ["class_descr" ] % _float64_descr_args
422+
423+ _typ = "float64index"
424+ _engine_type = libindex .Float64Engine
425+ _default_dtype = np .dtype (np .float64 )
426+ _dtype_validation_metadata = (is_float_dtype , "float" )
0 commit comments