9
9
Literal ,
10
10
Sequence ,
11
11
TypeVar ,
12
+ cast ,
12
13
overload ,
13
14
)
15
+ import warnings
14
16
15
17
import numpy as np
16
18
49
51
cache_readonly ,
50
52
doc ,
51
53
)
54
+ from pandas .util ._exceptions import find_stack_level
52
55
53
56
from pandas .core .dtypes .common import (
54
57
ensure_object ,
@@ -116,9 +119,7 @@ class PeriodArray(dtl.DatelikeOps, libperiod.PeriodMixin): # type: ignore[misc]
116
119
"""
117
120
Pandas ExtensionArray for storing Period data.
118
121
119
- Users should use :func:`~pandas.period_array` to create new instances.
120
- Alternatively, :func:`~pandas.array` can be used to create new instances
121
- from a sequence of Period scalars.
122
+ Users should use :func:`~pandas.array` to create new instances.
122
123
123
124
Parameters
124
125
----------
@@ -213,10 +214,21 @@ def _scalar_type(self) -> type[Period]:
213
214
def __init__ (
214
215
self , values , dtype : Dtype | None = None , freq = None , copy : bool = False
215
216
) -> None :
216
- freq = validate_dtype_freq (dtype , freq )
217
-
218
217
if freq is not None :
219
- freq = Period ._maybe_convert_freq (freq )
218
+ # GH#52462
219
+ warnings .warn (
220
+ "The 'freq' keyword in the PeriodArray constructor is deprecated "
221
+ "and will be removed in a future version. Pass 'dtype' instead" ,
222
+ FutureWarning ,
223
+ stacklevel = find_stack_level (),
224
+ )
225
+ freq = validate_dtype_freq (dtype , freq )
226
+ dtype = PeriodDtype (freq )
227
+
228
+ if dtype is not None :
229
+ dtype = pandas_dtype (dtype )
230
+ if not isinstance (dtype , PeriodDtype ):
231
+ raise ValueError (f"Invalid dtype { dtype } for PeriodArray" )
220
232
221
233
if isinstance (values , ABCSeries ):
222
234
values = values ._values
@@ -227,36 +239,38 @@ def __init__(
227
239
values = values ._values
228
240
229
241
if isinstance (values , type (self )):
230
- if freq is not None and freq != values .freq :
231
- raise raise_on_incompatible (values , freq )
232
- values , freq = values ._ndarray , values .freq
242
+ if dtype is not None and dtype != values .dtype :
243
+ raise raise_on_incompatible (values , dtype . freq )
244
+ values , dtype = values ._ndarray , values .dtype
233
245
234
246
values = np .array (values , dtype = "int64" , copy = copy )
235
- if freq is None :
236
- raise ValueError ("freq is not specified and cannot be inferred" )
237
- NDArrayBacked .__init__ (self , values , PeriodDtype (freq ))
247
+ if dtype is None :
248
+ raise ValueError ("dtype is not specified and cannot be inferred" )
249
+ dtype = cast (PeriodDtype , dtype )
250
+ NDArrayBacked .__init__ (self , values , dtype )
238
251
239
252
# error: Signature of "_simple_new" incompatible with supertype "NDArrayBacked"
240
253
@classmethod
241
254
def _simple_new ( # type: ignore[override]
242
255
cls ,
243
256
values : npt .NDArray [np .int64 ],
244
- freq : BaseOffset | None = None ,
245
- dtype : Dtype | None = None ,
257
+ dtype : PeriodDtype ,
246
258
) -> Self :
247
259
# alias for PeriodArray.__init__
248
260
assertion_msg = "Should be numpy array of type i8"
249
261
assert isinstance (values , np .ndarray ) and values .dtype == "i8" , assertion_msg
250
- return cls (values , freq = freq , dtype = dtype )
262
+ return cls (values , dtype = dtype )
251
263
252
264
@classmethod
253
265
def _from_sequence (
254
266
cls ,
255
- scalars : Sequence [ Period | None ] | AnyArrayLike ,
267
+ scalars ,
256
268
* ,
257
269
dtype : Dtype | None = None ,
258
270
copy : bool = False ,
259
271
) -> Self :
272
+ if dtype is not None :
273
+ dtype = pandas_dtype (dtype )
260
274
if dtype and isinstance (dtype , PeriodDtype ):
261
275
freq = dtype .freq
262
276
else :
@@ -266,16 +280,14 @@ def _from_sequence(
266
280
validate_dtype_freq (scalars .dtype , freq )
267
281
if copy :
268
282
scalars = scalars .copy ()
269
- # error: Incompatible return value type
270
- # (got "Union[Sequence[Optional[Period]], Union[Union[ExtensionArray,
271
- # ndarray[Any, Any]], Index, Series]]", expected "PeriodArray")
272
- return scalars # type: ignore[return-value]
283
+ return scalars
273
284
274
285
periods = np .asarray (scalars , dtype = object )
275
286
276
287
freq = freq or libperiod .extract_freq (periods )
277
288
ordinals = libperiod .extract_ordinals (periods , freq )
278
- return cls (ordinals , freq = freq )
289
+ dtype = PeriodDtype (freq )
290
+ return cls (ordinals , dtype = dtype )
279
291
280
292
@classmethod
281
293
def _from_sequence_of_strings (
@@ -299,7 +311,8 @@ def _from_datetime64(cls, data, freq, tz=None) -> Self:
299
311
PeriodArray[freq]
300
312
"""
301
313
data , freq = dt64arr_to_periodarr (data , freq , tz )
302
- return cls (data , freq = freq )
314
+ dtype = PeriodDtype (freq )
315
+ return cls (data , dtype = dtype )
303
316
304
317
@classmethod
305
318
def _generate_range (cls , start , end , periods , freq , fields ):
@@ -610,7 +623,8 @@ def asfreq(self, freq=None, how: str = "E") -> Self:
610
623
if self ._hasna :
611
624
new_data [self ._isnan ] = iNaT
612
625
613
- return type (self )(new_data , freq = freq )
626
+ dtype = PeriodDtype (freq )
627
+ return type (self )(new_data , dtype = dtype )
614
628
615
629
# ------------------------------------------------------------------
616
630
# Rendering Methods
@@ -697,7 +711,7 @@ def _addsub_int_array_or_scalar(
697
711
if op is operator .sub :
698
712
other = - other
699
713
res_values = algos .checked_add_with_arr (self .asi8 , other , arr_mask = self ._isnan )
700
- return type (self )(res_values , freq = self .freq )
714
+ return type (self )(res_values , dtype = self .dtype )
701
715
702
716
def _add_offset (self , other : BaseOffset ):
703
717
assert not isinstance (other , Tick )
@@ -768,7 +782,7 @@ def _add_timedelta_arraylike(
768
782
self .asi8 , delta .view ("i8" ), arr_mask = self ._isnan , b_mask = b_mask
769
783
)
770
784
np .putmask (res_values , self ._isnan | b_mask , iNaT )
771
- return type (self )(res_values , freq = self .freq )
785
+ return type (self )(res_values , dtype = self .dtype )
772
786
773
787
def _check_timedeltalike_freq_compat (self , other ):
774
788
"""
@@ -904,7 +918,12 @@ def period_array(
904
918
if is_datetime64_dtype (data_dtype ):
905
919
return PeriodArray ._from_datetime64 (data , freq )
906
920
if isinstance (data_dtype , PeriodDtype ):
907
- return PeriodArray (data , freq = freq )
921
+ out = PeriodArray (data )
922
+ if freq is not None :
923
+ if freq == data_dtype .freq :
924
+ return out
925
+ return out .asfreq (freq )
926
+ return out
908
927
909
928
# other iterable of some kind
910
929
if not isinstance (data , (np .ndarray , list , tuple , ABCSeries )):
0 commit comments