Skip to content

Commit 18cbadc

Browse files
use python instead of c implementation
1 parent 624be60 commit 18cbadc

File tree

8 files changed

+40
-90
lines changed

8 files changed

+40
-90
lines changed

pandas/_libs/include/pandas/frame_utils.h

Lines changed: 0 additions & 16 deletions
This file was deleted.

pandas/_libs/lib.pyx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@ cdef extern from "pandas/parser/pd_parser.h":
7777

7878
PandasParser_IMPORT
7979

80-
cdef extern from "pandas/frame_utils.h":
81-
int is_local_in_caller_frame_impl(PyObject *object)
82-
8380
from pandas._libs cimport util
8481
from pandas._libs.util cimport (
8582
INT64_MAX,
@@ -3330,8 +3327,3 @@ def is_np_dtype(object dtype, str kinds=None) -> bool:
33303327
if kinds is None:
33313328
return True
33323329
return dtype.kind in kinds
3333-
3334-
3335-
def is_local_in_caller_frame(object obj):
3336-
"""Return whether or not the object is a local in the caller's frame."""
3337-
return is_local_in_caller_frame_impl(<PyObject *>obj)

pandas/_libs/meson.build

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,7 @@ libs_sources = {
9797
'sources': ['join.pyx', _khash_primitive_helper],
9898
'deps': _khash_primitive_helper_dep,
9999
},
100-
'lib': {
101-
'sources': ['lib.pyx', 'src/parser/tokenizer.c', 'src/frame_utils.c'],
102-
},
100+
'lib': {'sources': ['lib.pyx', 'src/parser/tokenizer.c']},
103101
'missing': {'sources': ['missing.pyx']},
104102
'pandas_datetime': {
105103
'sources': [

pandas/_libs/src/frame_utils.c

Lines changed: 0 additions & 51 deletions
This file was deleted.

pandas/core/common.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import contextlib
2323
from functools import partial
2424
import inspect
25+
import sys
2526
from typing import (
2627
TYPE_CHECKING,
2728
Any,
@@ -650,3 +651,29 @@ def fill_missing_names(names: Sequence[Hashable | None]) -> list[Hashable]:
650651
list of column names with the None values replaced.
651652
"""
652653
return [f"level_{i}" if name is None else name for i, name in enumerate(names)]
654+
655+
656+
def is_local_in_caller_frame(obj):
657+
"""
658+
Helper function used in detecting chained assignment.
659+
660+
If the pandas object (DataFrame/Series) is a local variable
661+
in the caller's frame, it should not be a case of chained
662+
assignment or method call.
663+
664+
For example:
665+
666+
def test():
667+
df = pd.DataFrame(...)
668+
df["a"] = 1 # not chained assignment
669+
670+
Inside ``df.__setitem__``, we call this function to check whether `df`
671+
(`self`) is a local variable in `test` frame (the frame calling setitem). If
672+
so, we know it is not a case of chained assignment (even when the refcount
673+
of `df` is below the threshold due to optimization of local variables).
674+
"""
675+
frame = sys._getframe(2)
676+
for v in frame.f_locals.values():
677+
if v is obj:
678+
return True
679+
return False

pandas/core/frame.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4406,7 +4406,7 @@ def __setitem__(self, key, value) -> None:
44064406
# Values for 'a' and 'b' are completely ignored!
44074407
"""
44084408
if not CHAINED_WARNING_DISABLED:
4409-
if sys.getrefcount(self) <= REF_COUNT and not lib.is_local_in_caller_frame(
4409+
if sys.getrefcount(self) <= REF_COUNT and not com.is_local_in_caller_frame(
44104410
self
44114411
):
44124412
warnings.warn(
@@ -9368,7 +9368,7 @@ def update(
93689368
if not CHAINED_WARNING_DISABLED:
93699369
if sys.getrefcount(
93709370
self
9371-
) <= REF_COUNT_METHOD and not lib.is_local_in_caller_frame(self):
9371+
) <= REF_COUNT_METHOD and not com.is_local_in_caller_frame(self):
93729372
warnings.warn(
93739373
_chained_assignment_method_msg,
93749374
ChainedAssignmentError,

pandas/core/generic.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7084,7 +7084,7 @@ def fillna(
70847084
if not CHAINED_WARNING_DISABLED:
70857085
if sys.getrefcount(
70867086
self
7087-
) <= REF_COUNT_METHOD and not lib.is_local_in_caller_frame(self):
7087+
) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self):
70887088
warnings.warn(
70897089
_chained_assignment_method_msg,
70907090
ChainedAssignmentError,
@@ -7333,7 +7333,7 @@ def ffill(
73337333
if not CHAINED_WARNING_DISABLED:
73347334
if sys.getrefcount(
73357335
self
7336-
) <= REF_COUNT_METHOD and not lib.is_local_in_caller_frame(self):
7336+
) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self):
73377337
warnings.warn(
73387338
_chained_assignment_method_msg,
73397339
ChainedAssignmentError,
@@ -7475,7 +7475,7 @@ def bfill(
74757475
if not CHAINED_WARNING_DISABLED:
74767476
if sys.getrefcount(
74777477
self
7478-
) <= REF_COUNT_METHOD and not lib.is_local_in_caller_frame(self):
7478+
) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self):
74797479
warnings.warn(
74807480
_chained_assignment_method_msg,
74817481
ChainedAssignmentError,
@@ -7562,7 +7562,7 @@ def replace(
75627562
if not CHAINED_WARNING_DISABLED:
75637563
if sys.getrefcount(
75647564
self
7565-
) <= REF_COUNT_METHOD and not lib.is_local_in_caller_frame(self):
7565+
) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self):
75667566
warnings.warn(
75677567
_chained_assignment_method_msg,
75687568
ChainedAssignmentError,
@@ -7927,7 +7927,7 @@ def interpolate(
79277927
if not CHAINED_WARNING_DISABLED:
79287928
if sys.getrefcount(
79297929
self
7930-
) <= REF_COUNT_METHOD and not lib.is_local_in_caller_frame(self):
7930+
) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self):
79317931
warnings.warn(
79327932
_chained_assignment_method_msg,
79337933
ChainedAssignmentError,
@@ -8584,7 +8584,7 @@ def clip(
85848584
if not CHAINED_WARNING_DISABLED:
85858585
if sys.getrefcount(
85868586
self
8587-
) <= REF_COUNT_METHOD and not lib.is_local_in_caller_frame(self):
8587+
) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self):
85888588
warnings.warn(
85898589
_chained_assignment_method_msg,
85908590
ChainedAssignmentError,
@@ -10221,7 +10221,7 @@ def where(
1022110221
if not CHAINED_WARNING_DISABLED:
1022210222
if sys.getrefcount(
1022310223
self
10224-
) <= REF_COUNT_METHOD and not lib.is_local_in_caller_frame(self):
10224+
) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self):
1022510225
warnings.warn(
1022610226
_chained_assignment_method_msg,
1022710227
ChainedAssignmentError,
@@ -10287,7 +10287,7 @@ def mask(
1028710287
if not CHAINED_WARNING_DISABLED:
1028810288
if sys.getrefcount(
1028910289
self
10290-
) <= REF_COUNT_METHOD and not lib.is_local_in_caller_frame(self):
10290+
) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self):
1029110291
warnings.warn(
1029210292
_chained_assignment_method_msg,
1029310293
ChainedAssignmentError,

pandas/core/series.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,7 @@ def _get_value(self, label, takeable: bool = False):
10591059

10601060
def __setitem__(self, key, value) -> None:
10611061
if not CHAINED_WARNING_DISABLED:
1062-
if sys.getrefcount(self) <= REF_COUNT and not lib.is_local_in_caller_frame(
1062+
if sys.getrefcount(self) <= REF_COUNT and not com.is_local_in_caller_frame(
10631063
self
10641064
):
10651065
warnings.warn(
@@ -3357,7 +3357,7 @@ def update(self, other: Series | Sequence | Mapping) -> None:
33573357
if not CHAINED_WARNING_DISABLED:
33583358
if sys.getrefcount(
33593359
self
3360-
) <= REF_COUNT_METHOD and not lib.is_local_in_caller_frame(self):
3360+
) <= REF_COUNT_METHOD and not com.is_local_in_caller_frame(self):
33613361
warnings.warn(
33623362
_chained_assignment_method_msg,
33633363
ChainedAssignmentError,

0 commit comments

Comments
 (0)