|
19 | 19 | cast, |
20 | 20 | overload, |
21 | 21 | ) |
| 22 | +import warnings |
22 | 23 |
|
23 | 24 | import numpy as np |
24 | 25 |
|
|
33 | 34 | cache_readonly, |
34 | 35 | set_module, |
35 | 36 | ) |
| 37 | +from pandas.util._exceptions import find_stack_level |
36 | 38 | from pandas.util._validators import ( |
37 | 39 | validate_bool_kwarg, |
38 | 40 | validate_insert_loc, |
|
86 | 88 | AstypeArg, |
87 | 89 | AxisInt, |
88 | 90 | Dtype, |
| 91 | + DtypeObj, |
89 | 92 | FillnaOptions, |
90 | 93 | InterpolateOptions, |
91 | 94 | NumpySorter, |
@@ -353,6 +356,38 @@ def _from_sequence_of_strings( |
353 | 356 | """ |
354 | 357 | raise AbstractMethodError(cls) |
355 | 358 |
|
| 359 | + @classmethod |
| 360 | + def _from_scalars(cls, scalars, *, dtype: DtypeObj) -> Self: |
| 361 | + """ |
| 362 | + Strict analogue to _from_sequence, allowing only sequences of scalars |
| 363 | + that should be specifically inferred to the given dtype. |
| 364 | +
|
| 365 | + Parameters |
| 366 | + ---------- |
| 367 | + scalars : sequence |
| 368 | + dtype : ExtensionDtype |
| 369 | +
|
| 370 | + Raises |
| 371 | + ------ |
| 372 | + TypeError or ValueError |
| 373 | +
|
| 374 | + Notes |
| 375 | + ----- |
| 376 | + This is called in a try/except block when casting the result of a |
| 377 | + pointwise operation. |
| 378 | + """ |
| 379 | + try: |
| 380 | + return cls._from_sequence(scalars, dtype=dtype, copy=False) |
| 381 | + except (ValueError, TypeError): |
| 382 | + raise |
| 383 | + except Exception: |
| 384 | + warnings.warn( |
| 385 | + "_from_scalars should only raise ValueError or TypeError. " |
| 386 | + "Consider overriding _from_scalars where appropriate.", |
| 387 | + stacklevel=find_stack_level(), |
| 388 | + ) |
| 389 | + raise |
| 390 | + |
356 | 391 | @classmethod |
357 | 392 | def _from_factorized(cls, values, original): |
358 | 393 | """ |
@@ -383,13 +418,26 @@ def _from_factorized(cls, values, original): |
383 | 418 | """ |
384 | 419 | raise AbstractMethodError(cls) |
385 | 420 |
|
386 | | - def _cast_pointwise_result(self, values) -> ArrayLike: |
| 421 | + def _cast_pointwise_result(self, values: ArrayLike) -> ArrayLike: |
387 | 422 | """ |
| 423 | + Construct an ExtensionArray after a pointwise operation. |
| 424 | +
|
388 | 425 | Cast the result of a pointwise operation (e.g. Series.map) to an |
389 | | - array, preserve dtype_backend if possible. |
| 426 | + array. This is not required to return an ExtensionArray of the same |
| 427 | + type as self or of the same dtype. It can also return another |
| 428 | + ExtensionArray of the same "family" if you implement multiple |
| 429 | + ExtensionArrays/Dtypes that are interoperable (e.g. if you have float |
| 430 | + array with units, this method can return an int array with units). |
| 431 | +
|
| 432 | + If converting to your own ExtensionArray is not possible, this method |
| 433 | + can raise an error (TypeError or ValueError) or return the input |
| 434 | + `values` as-is. Then pandas will do the further type inference. |
| 435 | +
|
390 | 436 | """ |
391 | | - values = np.asarray(values, dtype=object) |
392 | | - return lib.maybe_convert_objects(values, convert_non_numeric=True) |
| 437 | + try: |
| 438 | + return type(self)._from_scalars(values, dtype=self.dtype) |
| 439 | + except (ValueError, TypeError): |
| 440 | + return values |
393 | 441 |
|
394 | 442 | # ------------------------------------------------------------------------ |
395 | 443 | # Must be a Sequence |
|
0 commit comments