Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita682616

Browse files
authored
ENH: Add future.python_scalars (pandas-dev#63016)
1 parentec63444 commita682616

27 files changed

+322
-134
lines changed

‎.github/workflows/unit-tests.yml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
# Prevent the include jobs from overriding other jobs
3232
pattern:[""]
3333
pandas_future_infer_string:["1"]
34+
pandas_future_python_scalars:["0"]
3435
include:
3536
-name:"Downstream Compat"
3637
env_file:actions-313-downstream_compat.yaml
@@ -75,6 +76,10 @@ jobs:
7576
env_file:actions-313.yaml
7677
pandas_future_infer_string:"0"
7778
platform:ubuntu-24.04
79+
-name:"PANDAS_FUTURE_PYTHON_SCALARS=1"
80+
env_file:actions-313.yaml
81+
pandas_future_python_scalars:"1"
82+
platform:ubuntu-24.04
7883
-name:"Numpy Dev"
7984
env_file:actions-313-numpydev.yaml
8085
pattern:"not slow and not network and not single_cpu"
@@ -92,6 +97,7 @@ jobs:
9297
LC_ALL:${{ matrix.lc_all || '' }}
9398
PANDAS_CI:'1'
9499
PANDAS_FUTURE_INFER_STRING:${{ matrix.pandas_future_infer_string || '1' }}
100+
PANDAS_FUTURE_PYTHON_SCALARS:${{ matrix.pandas_future_python_scalars || '0' }}
95101
TEST_ARGS:${{ matrix.test_args || '' }}
96102
PYTEST_WORKERS:'auto'
97103
PYTEST_TARGET:${{ matrix.pytest_target || 'pandas' }}

‎pandas/_config/__init__.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ def using_string_dtype() -> bool:
3535
return_mode_options["infer_string"]
3636

3737

38+
defusing_python_scalars()->bool:
39+
_mode_options=_global_config["future"]
40+
return_mode_options["python_scalars"]
41+
42+
3843
defis_nan_na()->bool:
3944
_mode_options=_global_config["future"]
4045
returnnot_mode_options["distinguish_nan_and_na"]

‎pandas/conftest.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,6 +2094,11 @@ def using_infer_string() -> bool:
20942094
returnpd.options.future.infer_stringisTrue
20952095

20962096

2097+
@pytest.fixture
2098+
defusing_python_scalars()->bool:
2099+
returnpd.options.future.python_scalarsisTrue
2100+
2101+
20972102
_warsaws:list[Any]= ["Europe/Warsaw","dateutil/Europe/Warsaw"]
20982103
ifpytzisnotNone:
20992104
_warsaws.append(pytz.timezone("Europe/Warsaw"))

‎pandas/core/arraylike.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
frompandas._libsimportlib
1616
frompandas._libs.ops_dispatchimportmaybe_dispatch_ufunc_to_dunder_op
1717

18+
frompandas.core.dtypes.castimportmaybe_unbox_numpy_scalar
1819
frompandas.core.dtypes.genericimportABCNDFrame
1920

2021
frompandas.coreimportroperator
@@ -529,4 +530,6 @@ def dispatch_reduction_ufunc(self, ufunc: np.ufunc, method: str, *inputs, **kwar
529530

530531
# By default, numpy's reductions do not skip NaNs, so we have to
531532
# pass skipna=False
532-
returngetattr(self,method_name)(skipna=False,**kwargs)
533+
result=getattr(self,method_name)(skipna=False,**kwargs)
534+
result=maybe_unbox_numpy_scalar(result)
535+
returnresult

‎pandas/core/arrays/masked.py‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212

1313
importnumpyasnp
1414

15-
frompandas._configimportis_nan_na
15+
frompandas._configimport (
16+
is_nan_na,
17+
using_python_scalars,
18+
)
1619

1720
frompandas._libsimport (
1821
algosaslibalgos,
@@ -28,7 +31,9 @@
2831

2932
frompandas.core.dtypes.astypeimportastype_is_view
3033
frompandas.core.dtypes.baseimportExtensionDtype
31-
frompandas.core.dtypes.castimportmaybe_downcast_to_dtype
34+
frompandas.core.dtypes.castimport (
35+
maybe_downcast_to_dtype,
36+
)
3237
frompandas.core.dtypes.commonimport (
3338
is_bool,
3439
is_integer_dtype,
@@ -1537,7 +1542,10 @@ def _reduce(
15371542
ifisna(result):
15381543
returnself._wrap_na_result(name=name,axis=0,mask_size=(1,))
15391544
else:
1540-
result=result.reshape(1)
1545+
ifusing_python_scalars():
1546+
result=np.array([result])
1547+
else:
1548+
result=result.reshape(1)
15411549
mask=np.zeros(1,dtype=bool)
15421550
returnself._maybe_mask_result(result,mask)
15431551

‎pandas/core/config_init.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,14 @@ def register_converter_cb(key: str) -> None:
901901
validator=is_one_of_factory([True,False]),
902902
)
903903

904+
cf.register_option(
905+
"python_scalars",
906+
Falseifos.environ.get("PANDAS_FUTURE_PYTHON_SCALARS","0")=="0"elseTrue,
907+
"Whether to return Python scalars instead of NumPy or PyArrow scalars. "
908+
"Currently experimental, setting to True is not recommended for end users.",
909+
validator=is_one_of_factory([True,False]),
910+
)
911+
904912

905913
# GH#59502
906914
cf.deprecate_option("future.no_silent_downcasting",Pandas4Warning)

‎pandas/core/dtypes/cast.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
frompandas._configimport (
2222
is_nan_na,
23+
using_python_scalars,
2324
using_string_dtype,
2425
)
2526

@@ -1439,6 +1440,22 @@ def construct_1d_arraylike_from_scalar(
14391440
returnsubarr
14401441

14411442

1443+
defmaybe_unbox_numpy_scalar(value):
1444+
result=value
1445+
ifusing_python_scalars()andisinstance(value,np.generic):
1446+
ifisinstance(result,np.longdouble):
1447+
result=float(result)
1448+
elifisinstance(result,np.complex256):
1449+
result=complex(result)
1450+
elifisinstance(result,np.datetime64):
1451+
result=Timestamp(result)
1452+
elifisinstance(result,np.timedelta64):
1453+
result=Timedelta(result)
1454+
else:
1455+
result=value.item()
1456+
returnresult
1457+
1458+
14421459
def_maybe_box_and_unbox_datetimelike(value:Scalar,dtype:DtypeObj):
14431460
# Caller is responsible for checking dtype.kind in "mM"
14441461

‎pandas/core/indexes/base.py‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
common_dtype_categorical_compat,
9393
find_result_type,
9494
infer_dtype_from,
95+
maybe_unbox_numpy_scalar,
9596
np_can_hold_element,
9697
)
9798
frompandas.core.dtypes.commonimport (
@@ -7534,7 +7535,7 @@ def min(self, axis: AxisInt | None = None, skipna: bool = True, *args, **kwargs)
75347535
# quick check
75357536
first=self[0]
75367537
ifnotisna(first):
7537-
returnfirst
7538+
returnmaybe_unbox_numpy_scalar(first)
75387539

75397540
ifnotself._is_multiandself.hasnans:
75407541
# Take advantage of cache
@@ -7545,7 +7546,7 @@ def min(self, axis: AxisInt | None = None, skipna: bool = True, *args, **kwargs)
75457546
ifnotself._is_multiandnotisinstance(self._values,np.ndarray):
75467547
returnself._values._reduce(name="min",skipna=skipna)
75477548

7548-
returnnanops.nanmin(self._values,skipna=skipna)
7549+
returnmaybe_unbox_numpy_scalar(nanops.nanmin(self._values,skipna=skipna))
75497550

75507551
defmax(self,axis:AxisInt|None=None,skipna:bool=True,*args,**kwargs):
75517552
"""
@@ -7598,18 +7599,18 @@ def max(self, axis: AxisInt | None = None, skipna: bool = True, *args, **kwargs)
75987599
# quick check
75997600
last=self[-1]
76007601
ifnotisna(last):
7601-
returnlast
7602+
returnmaybe_unbox_numpy_scalar(last)
76027603

76037604
ifnotself._is_multiandself.hasnans:
76047605
# Take advantage of cache
76057606
mask=self._isnan
76067607
ifnotskipnaormask.all():
7607-
returnself._na_value
7608+
returnmaybe_unbox_numpy_scalar(self._na_value)
76087609

76097610
ifnotself._is_multiandnotisinstance(self._values,np.ndarray):
76107611
returnself._values._reduce(name="max",skipna=skipna)
76117612

7612-
returnnanops.nanmax(self._values,skipna=skipna)
7613+
returnmaybe_unbox_numpy_scalar(nanops.nanmax(self._values,skipna=skipna))
76137614

76147615
# --------------------------------------------------------------------
76157616

‎pandas/core/interchange/column.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
importnumpyasnp
99

10+
frompandas._configimportusing_python_scalars
11+
1012
frompandas._libs.libimportinfer_dtype
1113
frompandas._libs.tslibsimportiNaT
1214
frompandas.errorsimportNoBufferPresent
@@ -232,7 +234,10 @@ def null_count(self) -> int:
232234
"""
233235
Number of null elements. Should always be known.
234236
"""
235-
returnself._col.isna().sum().item()
237+
result=self._col.isna().sum()
238+
ifnotusing_python_scalars():
239+
result=result.item()
240+
returnresult
236241

237242
@property
238243
defmetadata(self)->dict[str,pd.Index]:

‎pandas/core/series.py‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
find_common_type,
7474
infer_dtype_from,
7575
maybe_box_native,
76+
maybe_unbox_numpy_scalar,
7677
)
7778
frompandas.core.dtypes.commonimport (
7879
is_dict_like,
@@ -2079,7 +2080,7 @@ def count(self) -> int:
20792080
>>> s.count()
20802081
2
20812082
"""
2082-
returnnotna(self._values).sum().astype("int64")
2083+
returnmaybe_unbox_numpy_scalar(notna(self._values).sum().astype("int64"))
20832084

20842085
defmode(self,dropna:bool=True)->Series:
20852086
"""
@@ -7402,7 +7403,7 @@ def _reduce(
74027403

74037404
ifisinstance(delegate,ExtensionArray):
74047405
# dispatch to ExtensionArray interface
7405-
returndelegate._reduce(name,skipna=skipna,**kwds)
7406+
result=delegate._reduce(name,skipna=skipna,**kwds)
74067407

74077408
else:
74087409
# dispatch to numpy arrays
@@ -7416,7 +7417,10 @@ def _reduce(
74167417
f"Series.{name} does not allow{kwd_name}={numeric_only} "
74177418
"with non-numeric dtypes."
74187419
)
7419-
returnop(delegate,skipna=skipna,**kwds)
7420+
result=op(delegate,skipna=skipna,**kwds)
7421+
7422+
result=maybe_unbox_numpy_scalar(result)
7423+
returnresult
74207424

74217425
@Appender(make_doc("any",ndim=1))
74227426
# error: Signature of "any" incompatible with supertype "NDFrame"

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp