4
4
"""
5
5
6
6
import copy
7
- from datetime import date
7
+ from datetime import date , tzinfo
8
8
import itertools
9
9
import os
10
10
import re
@@ -2918,7 +2918,8 @@ def read_array(
2918
2918
if dtype == "datetime64" :
2919
2919
2920
2920
# reconstruct a timezone if indicated
2921
- ret = _set_tz (ret , getattr (attrs , "tz" , None ), coerce = True )
2921
+ tz = getattr (attrs , "tz" , None )
2922
+ ret = _set_tz (ret , tz , coerce = True )
2922
2923
2923
2924
elif dtype == "timedelta64" :
2924
2925
ret = np .asarray (ret , dtype = "m8[ns]" )
@@ -3734,7 +3735,7 @@ def read_axes(
3734
3735
3735
3736
return True
3736
3737
3737
- def get_object (self , obj ):
3738
+ def get_object (self , obj , transposed : bool ):
3738
3739
""" return the data for this obj """
3739
3740
return obj
3740
3741
@@ -3838,15 +3839,13 @@ def create_axes(
3838
3839
)
3839
3840
3840
3841
# create according to the new data
3841
- self . non_index_axes = []
3842
- self . data_columns = []
3842
+ new_non_index_axes : List = []
3843
+ new_data_columns : List [ Optional [ str ]] = []
3843
3844
3844
3845
# nan_representation
3845
3846
if nan_rep is None :
3846
3847
nan_rep = "nan"
3847
3848
3848
- self .nan_rep = nan_rep
3849
-
3850
3849
# create axes to index and non_index
3851
3850
index_axes_map = dict ()
3852
3851
for i , a in enumerate (obj .axes ):
@@ -3863,7 +3862,7 @@ def create_axes(
3863
3862
# necessary
3864
3863
append_axis = list (a )
3865
3864
if existing_table is not None :
3866
- indexer = len (self . non_index_axes )
3865
+ indexer = len (new_non_index_axes )
3867
3866
exist_axis = existing_table .non_index_axes [indexer ][1 ]
3868
3867
if not array_equivalent (
3869
3868
np .array (append_axis ), np .array (exist_axis )
@@ -3880,34 +3879,37 @@ def create_axes(
3880
3879
info ["names" ] = list (a .names )
3881
3880
info ["type" ] = type (a ).__name__
3882
3881
3883
- self .non_index_axes .append ((i , append_axis ))
3882
+ new_non_index_axes .append ((i , append_axis ))
3883
+
3884
+ self .non_index_axes = new_non_index_axes
3884
3885
3885
3886
# set axis positions (based on the axes)
3886
3887
new_index_axes = [index_axes_map [a ] for a in axes ]
3887
3888
for j , iax in enumerate (new_index_axes ):
3888
3889
iax .set_pos (j )
3889
3890
iax .update_info (self .info )
3890
- self .index_axes = new_index_axes
3891
3891
3892
- j = len (self . index_axes )
3892
+ j = len (new_index_axes )
3893
3893
3894
3894
# check for column conflicts
3895
- for a in self . axes :
3895
+ for a in new_index_axes :
3896
3896
a .maybe_set_size (min_itemsize = min_itemsize )
3897
3897
3898
3898
# reindex by our non_index_axes & compute data_columns
3899
- for a in self . non_index_axes :
3899
+ for a in new_non_index_axes :
3900
3900
obj = _reindex_axis (obj , a [0 ], a [1 ])
3901
3901
3902
3902
def get_blk_items (mgr , blocks ):
3903
3903
return [mgr .items .take (blk .mgr_locs ) for blk in blocks ]
3904
3904
3905
+ transposed = new_index_axes [0 ].axis == 1
3906
+
3905
3907
# figure out data_columns and get out blocks
3906
- block_obj = self .get_object (obj )._consolidate ()
3908
+ block_obj = self .get_object (obj , transposed )._consolidate ()
3907
3909
blocks = block_obj ._data .blocks
3908
3910
blk_items = get_blk_items (block_obj ._data , blocks )
3909
- if len (self . non_index_axes ):
3910
- axis , axis_labels = self . non_index_axes [0 ]
3911
+ if len (new_non_index_axes ):
3912
+ axis , axis_labels = new_non_index_axes [0 ]
3911
3913
data_columns = self .validate_data_columns (data_columns , min_itemsize )
3912
3914
if len (data_columns ):
3913
3915
mgr = block_obj .reindex (
@@ -3945,7 +3947,7 @@ def get_blk_items(mgr, blocks):
3945
3947
blk_items = new_blk_items
3946
3948
3947
3949
# add my values
3948
- self . values_axes = []
3950
+ vaxes = []
3949
3951
for i , (b , b_items ) in enumerate (zip (blocks , blk_items )):
3950
3952
3951
3953
# shape of the data column are the indexable axes
@@ -3959,7 +3961,7 @@ def get_blk_items(mgr, blocks):
3959
3961
if not (name is None or isinstance (name , str )):
3960
3962
# TODO: should the message here be more specifically non-str?
3961
3963
raise ValueError ("cannot have non-object label DataIndexableCol" )
3962
- self . data_columns .append (name )
3964
+ new_data_columns .append (name )
3963
3965
3964
3966
# make sure that we match up the existing columns
3965
3967
# if we have an existing table
@@ -3987,10 +3989,15 @@ def get_blk_items(mgr, blocks):
3987
3989
)
3988
3990
col .set_pos (j )
3989
3991
3990
- self . values_axes .append (col )
3992
+ vaxes .append (col )
3991
3993
3992
3994
j += 1
3993
3995
3996
+ self .nan_rep = nan_rep
3997
+ self .data_columns = new_data_columns
3998
+ self .values_axes = vaxes
3999
+ self .index_axes = new_index_axes
4000
+
3994
4001
# validate our min_itemsize
3995
4002
self .validate_min_itemsize (min_itemsize )
3996
4003
@@ -4158,7 +4165,7 @@ def read_column(
4158
4165
encoding = self .encoding ,
4159
4166
errors = self .errors ,
4160
4167
)
4161
- return Series (_set_tz (a .take_data (), a .tz , True ), name = column )
4168
+ return Series (_set_tz (a .take_data (), a .tz ), name = column )
4162
4169
4163
4170
raise KeyError (f"column [{ column } ] not found in the table" )
4164
4171
@@ -4428,9 +4435,9 @@ class AppendableFrameTable(AppendableTable):
4428
4435
def is_transposed (self ) -> bool :
4429
4436
return self .index_axes [0 ].axis == 1
4430
4437
4431
- def get_object (self , obj ):
4438
+ def get_object (self , obj , transposed : bool ):
4432
4439
""" these are written transposed """
4433
- if self . is_transposed :
4440
+ if transposed :
4434
4441
obj = obj .T
4435
4442
return obj
4436
4443
@@ -4512,7 +4519,7 @@ class AppendableSeriesTable(AppendableFrameTable):
4512
4519
def is_transposed (self ) -> bool :
4513
4520
return False
4514
4521
4515
- def get_object (self , obj ):
4522
+ def get_object (self , obj , transposed : bool ):
4516
4523
return obj
4517
4524
4518
4525
def write (self , obj , data_columns = None , ** kwargs ):
@@ -4687,37 +4694,39 @@ def _get_info(info, name):
4687
4694
# tz to/from coercion
4688
4695
4689
4696
4690
- def _get_tz (tz ) :
4697
+ def _get_tz (tz : tzinfo ) -> Union [ str , tzinfo ] :
4691
4698
""" for a tz-aware type, return an encoded zone """
4692
4699
zone = timezones .get_timezone (tz )
4693
- if zone is None :
4694
- zone = tz .utcoffset ().total_seconds ()
4695
4700
return zone
4696
4701
4697
4702
4698
- def _set_tz (values , tz , preserve_UTC : bool = False , coerce : bool = False ):
4703
+ def _set_tz (
4704
+ values : Union [np .ndarray , Index ],
4705
+ tz : Optional [Union [str , tzinfo ]],
4706
+ coerce : bool = False ,
4707
+ ) -> Union [np .ndarray , DatetimeIndex ]:
4699
4708
"""
4700
4709
coerce the values to a DatetimeIndex if tz is set
4701
4710
preserve the input shape if possible
4702
4711
4703
4712
Parameters
4704
4713
----------
4705
- values : ndarray
4706
- tz : string/pickled tz object
4707
- preserve_UTC : bool,
4708
- preserve the UTC of the result
4714
+ values : ndarray or Index
4715
+ tz : str or tzinfo
4709
4716
coerce : if we do not have a passed timezone, coerce to M8[ns] ndarray
4710
4717
"""
4718
+ if isinstance (values , DatetimeIndex ):
4719
+ # If values is tzaware, the tz gets dropped in the values.ravel()
4720
+ # call below (which returns an ndarray). So we are only non-lossy
4721
+ # if `tz` matches `values.tz`.
4722
+ assert values .tz is None or values .tz == tz
4723
+
4711
4724
if tz is not None :
4712
4725
name = getattr (values , "name" , None )
4713
4726
values = values .ravel ()
4714
4727
tz = timezones .get_timezone (_ensure_decoded (tz ))
4715
4728
values = DatetimeIndex (values , name = name )
4716
- if values .tz is None :
4717
- values = values .tz_localize ("UTC" ).tz_convert (tz )
4718
- if preserve_UTC :
4719
- if tz == "UTC" :
4720
- values = list (values )
4729
+ values = values .tz_localize ("UTC" ).tz_convert (tz )
4721
4730
elif coerce :
4722
4731
values = np .asarray (values , dtype = "M8[ns]" )
4723
4732
0 commit comments