@@ -1186,6 +1186,7 @@ cdef class Seen:
1186
1186
bint coerce_numeric # coerce data to numeric
1187
1187
bint timedelta_ # seen_timedelta
1188
1188
bint datetimetz_ # seen_datetimetz
1189
+ bint period_ # seen_period
1189
1190
1190
1191
def __cinit__(self , bint coerce_numeric = False ):
1191
1192
"""
@@ -1210,6 +1211,7 @@ cdef class Seen:
1210
1211
self .datetime_ = False
1211
1212
self .timedelta_ = False
1212
1213
self .datetimetz_ = False
1214
+ self .period_ = False
1213
1215
self .coerce_numeric = coerce_numeric
1214
1216
1215
1217
cdef inline bint check_uint64_conflict(self ) except - 1 :
@@ -1996,18 +1998,35 @@ cpdef bint is_time_array(ndarray values, bint skipna=False):
1996
1998
return validator.validate(values)
1997
1999
1998
2000
1999
- cdef class PeriodValidator(TemporalValidator):
2000
- cdef inline bint is_value_typed(self , object value) except - 1 :
2001
- return is_period_object(value)
2001
+ cdef bint is_period_array(ndarray[object ] values):
2002
+ """
2003
+ Is this an ndarray of Period objects (or NaT) with a single `freq`?
2004
+ """
2005
+ cdef:
2006
+ Py_ssize_t i, n = len (values)
2007
+ int dtype_code = - 10000 # i.e. c_FreqGroup.FR_UND
2008
+ object val
2002
2009
2003
- cdef inline bint is_valid_null( self , object value) except - 1 :
2004
- return checknull_with_nat(value)
2010
+ if len (values) == 0 :
2011
+ return False
2005
2012
2013
+ for val in values:
2014
+ if is_period_object(val):
2015
+ if dtype_code == - 10000 :
2016
+ dtype_code = val._dtype._dtype_code
2017
+ elif dtype_code != val._dtype._dtype_code:
2018
+ # mismatched freqs
2019
+ return False
2020
+ elif checknull_with_nat(val):
2021
+ pass
2022
+ else :
2023
+ # Not a Period or NaT-like
2024
+ return False
2006
2025
2007
- cpdef bint is_period_array(ndarray values) :
2008
- cdef:
2009
- PeriodValidator validator = PeriodValidator( len (values), skipna = True )
2010
- return validator.validate(values)
2026
+ if dtype_code == - 10000 :
2027
+ # we saw all-NaTs, no actual Periods
2028
+ return False
2029
+ return True
2011
2030
2012
2031
2013
2032
cdef class IntervalValidator(Validator):
@@ -2249,9 +2268,13 @@ def maybe_convert_numeric(
2249
2268
2250
2269
@ cython.boundscheck (False )
2251
2270
@ cython.wraparound (False )
2252
- def maybe_convert_objects (ndarray[object] objects , bint try_float = False ,
2253
- bint safe = False , bint convert_datetime = False ,
2271
+ def maybe_convert_objects (ndarray[object] objects ,
2272
+ *,
2273
+ bint try_float = False ,
2274
+ bint safe = False ,
2275
+ bint convert_datetime = False ,
2254
2276
bint convert_timedelta = False ,
2277
+ bint convert_period = False ,
2255
2278
bint convert_to_nullable_integer = False ) -> "ArrayLike":
2256
2279
"""
2257
2280
Type inference function-- convert object array to proper dtype
@@ -2272,6 +2295,9 @@ def maybe_convert_objects(ndarray[object] objects, bint try_float=False,
2272
2295
convert_timedelta : bool , default False
2273
2296
If an array-like object contains only timedelta values or NaT is
2274
2297
encountered , whether to convert and return an array of m8[ns] dtype.
2298
+ convert_period : bool , default False
2299
+ If an array-like object contains only (homogeneous-freq ) Period values
2300
+ or NaT , whether to convert and return a PeriodArray.
2275
2301
convert_to_nullable_integer : bool , default False
2276
2302
If an array-like object contains only integer values (and NaN ) is
2277
2303
encountered , whether to convert and return an IntegerArray.
@@ -2292,7 +2318,7 @@ def maybe_convert_objects(ndarray[object] objects, bint try_float=False,
2292
2318
int64_t[:] itimedeltas
2293
2319
Seen seen = Seen()
2294
2320
object val
2295
- float64_t fval , fnan
2321
+ float64_t fval , fnan = np.nan
2296
2322
2297
2323
n = len (objects)
2298
2324
@@ -2311,8 +2337,6 @@ def maybe_convert_objects(ndarray[object] objects, bint try_float=False,
2311
2337
timedeltas = np.empty(n, dtype = ' m8[ns]' )
2312
2338
itimedeltas = timedeltas.view(np.int64)
2313
2339
2314
- fnan = np.nan
2315
-
2316
2340
for i in range(n ):
2317
2341
val = objects[i]
2318
2342
if itemsize_max != - 1 :
@@ -2330,7 +2354,7 @@ def maybe_convert_objects(ndarray[object] objects, bint try_float=False,
2330
2354
idatetimes[i] = NPY_NAT
2331
2355
if convert_timedelta:
2332
2356
itimedeltas[i] = NPY_NAT
2333
- if not (convert_datetime or convert_timedelta):
2357
+ if not (convert_datetime or convert_timedelta or convert_period ):
2334
2358
seen.object_ = True
2335
2359
break
2336
2360
elif val is np.nan:
@@ -2343,14 +2367,6 @@ def maybe_convert_objects(ndarray[object] objects, bint try_float=False,
2343
2367
elif util.is_float_object(val):
2344
2368
floats[i] = complexes[i] = val
2345
2369
seen.float_ = True
2346
- elif util.is_datetime64_object(val):
2347
- if convert_datetime:
2348
- idatetimes[i] = convert_to_tsobject(
2349
- val, None , None , 0 , 0 ).value
2350
- seen.datetime_ = True
2351
- else :
2352
- seen.object_ = True
2353
- break
2354
2370
elif is_timedelta(val):
2355
2371
if convert_timedelta:
2356
2372
itimedeltas[i] = convert_to_timedelta64(val, " ns" ).view(" i8" )
@@ -2396,6 +2412,13 @@ def maybe_convert_objects(ndarray[object] objects, bint try_float=False,
2396
2412
else :
2397
2413
seen.object_ = True
2398
2414
break
2415
+ elif is_period_object(val):
2416
+ if convert_period:
2417
+ seen.period_ = True
2418
+ break
2419
+ else :
2420
+ seen.object_ = True
2421
+ break
2399
2422
elif try_float and not isinstance (val, str ):
2400
2423
# this will convert Decimal objects
2401
2424
try :
@@ -2419,6 +2442,14 @@ def maybe_convert_objects(ndarray[object] objects, bint try_float=False,
2419
2442
return dti._data
2420
2443
seen.object_ = True
2421
2444
2445
+ if seen.period_:
2446
+ if is_period_array(objects):
2447
+ from pandas import PeriodIndex
2448
+ pi = PeriodIndex(objects)
2449
+
2450
+ # unbox to PeriodArray
2451
+ return pi._data
2452
+
2422
2453
if not seen.object_:
2423
2454
result = None
2424
2455
if not safe:
0 commit comments