1+ import os
2+
13from typing import (
24 Any ,
35 Callable ,
810 Optional
911)
1012
13+ import pandas as pd
1114from pandas import (
1215 Series
1316)
3336 MetaDataFrame
3437)
3538
39+ # #27
40+ if os .environ .get ('STOCK_PANDAS_COW' , '' ).lower () in ('1' , 'on' , 'true' ):
41+ # Enable pandas Copy-on-Write mode
42+ # https://pandas.pydata.org/pandas-docs/stable/user_guide/copy_on_write.html#copy-on-write-chained-assignment
43+ pd .options .mode .copy_on_write = True
44+
3645
3746class StockDataFrame (MetaDataFrame ):
3847 """The wrapper class for `pandas.DataFrame`
@@ -326,23 +335,10 @@ def _get_or_calc_series(
326335 period
327336 )
328337
329- self ._set_new_item ( name , array )
338+ self .loc [:, name ] = array
330339
331340 return name , array
332341
333- def _set_new_item (
334- self ,
335- name : str ,
336- value : ndarray
337- ) -> None :
338- """Set a new column and avoid SettingWithCopyWarning by using
339- pandas internal APIs
340-
341- see: https://github.com/pandas-dev/pandas/blob/v1.1.0/pandas/core/frame.py#L3114
342- """
343-
344- self ._set_item (name , value )
345-
346342 def _fulfill_series (self , column_name : str ) -> ndarray :
347343 column_info = self ._stock_columns_info_map .get (column_name )
348344 size = len (self )
@@ -369,9 +365,15 @@ def _fulfill_series(self, column_name: str) -> ndarray:
369365 if neg_delta == calc_delta :
370366 array = partial
371367 else :
368+ # #27
369+ # With `pd.options.mode.copy_on_write = True`,
370+ # Series.to_numpy() will returns the
371+ # read-only underlying numpy array of the Series
372+ # so we need to copy it before modifying
373+ array = array .copy ()
372374 array [fulfill_slice ] = partial [fulfill_slice ]
373375
374- self ._set_new_item ( column_name , array )
376+ self .loc [:, column_name ] = array
375377
376378 column_info .size = size
377379
0 commit comments