28
28
from pandas .core import config
29
29
from pandas .io .formats .printing import pprint_thing
30
30
import pandas .compat as compat
31
- import pandas .compat .openpyxl_compat as openpyxl_compat
32
31
from warnings import warn
33
32
from distutils .version import LooseVersion
34
33
from pandas .util ._decorators import Appender , deprecate_kwarg
@@ -185,22 +184,6 @@ def _get_default_writer(ext):
185
184
186
185
187
186
def get_writer (engine_name ):
188
- if engine_name == 'openpyxl' :
189
- try :
190
- import openpyxl
191
-
192
- # with version-less openpyxl engine
193
- # make sure we make the intelligent choice for the user
194
- if LooseVersion (openpyxl .__version__ ) < '2.0.0' :
195
- return _writers ['openpyxl1' ]
196
- elif LooseVersion (openpyxl .__version__ ) < '2.2.0' :
197
- return _writers ['openpyxl20' ]
198
- else :
199
- return _writers ['openpyxl22' ]
200
- except ImportError :
201
- # fall through to normal exception handling below
202
- pass
203
-
204
187
try :
205
188
return _writers [engine_name ]
206
189
except KeyError :
@@ -828,20 +811,15 @@ def close(self):
828
811
return self .save ()
829
812
830
813
831
- class _Openpyxl1Writer (ExcelWriter ):
832
- engine = 'openpyxl1 '
814
+ class _OpenpyxlWriter (ExcelWriter ):
815
+ engine = 'openpyxl '
833
816
supported_extensions = ('.xlsx' , '.xlsm' )
834
- openpyxl_majorver = 1
835
817
836
818
def __init__ (self , path , engine = None , ** engine_kwargs ):
837
- if not openpyxl_compat .is_compat (major_ver = self .openpyxl_majorver ):
838
- raise ValueError ('Installed openpyxl is not supported at this '
839
- 'time. Use {majorver}.x.y.'
840
- .format (majorver = self .openpyxl_majorver ))
841
819
# Use the openpyxl module as the Excel writer.
842
820
from openpyxl .workbook import Workbook
843
821
844
- super (_Openpyxl1Writer , self ).__init__ (path , ** engine_kwargs )
822
+ super (_OpenpyxlWriter , self ).__init__ (path , ** engine_kwargs )
845
823
846
824
# Create workbook object with default optimized_write=True.
847
825
self .book = Workbook ()
@@ -861,72 +839,6 @@ def save(self):
861
839
"""
862
840
return self .book .save (self .path )
863
841
864
- def write_cells (self , cells , sheet_name = None , startrow = 0 , startcol = 0 ,
865
- freeze_panes = None ):
866
- # Write the frame cells using openpyxl.
867
- from openpyxl .cell import get_column_letter
868
-
869
- sheet_name = self ._get_sheet_name (sheet_name )
870
-
871
- if sheet_name in self .sheets :
872
- wks = self .sheets [sheet_name ]
873
- else :
874
- wks = self .book .create_sheet ()
875
- wks .title = sheet_name
876
- self .sheets [sheet_name ] = wks
877
-
878
- for cell in cells :
879
- colletter = get_column_letter (startcol + cell .col + 1 )
880
- xcell = wks .cell ("{col}{row}" .format (col = colletter ,
881
- row = startrow + cell .row + 1 ))
882
- if (isinstance (cell .val , compat .string_types ) and
883
- xcell .data_type_for_value (cell .val ) != xcell .TYPE_STRING ):
884
- xcell .set_value_explicit (cell .val )
885
- else :
886
- xcell .value = _conv_value (cell .val )
887
- style = None
888
- if cell .style :
889
- style = self ._convert_to_style (cell .style )
890
- for field in style .__fields__ :
891
- xcell .style .__setattr__ (field ,
892
- style .__getattribute__ (field ))
893
-
894
- if isinstance (cell .val , datetime ):
895
- xcell .style .number_format .format_code = self .datetime_format
896
- elif isinstance (cell .val , date ):
897
- xcell .style .number_format .format_code = self .date_format
898
-
899
- if cell .mergestart is not None and cell .mergeend is not None :
900
- cletterstart = get_column_letter (startcol + cell .col + 1 )
901
- cletterend = get_column_letter (startcol + cell .mergeend + 1 )
902
-
903
- wks .merge_cells ('{start}{row}:{end}{mergestart}'
904
- .format (start = cletterstart ,
905
- row = startrow + cell .row + 1 ,
906
- end = cletterend ,
907
- mergestart = startrow +
908
- cell .mergestart + 1 ))
909
-
910
- # Excel requires that the format of the first cell in a merged
911
- # range is repeated in the rest of the merged range.
912
- if style :
913
- first_row = startrow + cell .row + 1
914
- last_row = startrow + cell .mergestart + 1
915
- first_col = startcol + cell .col + 1
916
- last_col = startcol + cell .mergeend + 1
917
-
918
- for row in range (first_row , last_row + 1 ):
919
- for col in range (first_col , last_col + 1 ):
920
- if row == first_row and col == first_col :
921
- # Ignore first cell. It is already handled.
922
- continue
923
- colletter = get_column_letter (col )
924
- xcell = wks .cell ("{col}{row}"
925
- .format (col = colletter , row = row ))
926
- for field in style .__fields__ :
927
- xcell .style .__setattr__ (
928
- field , style .__getattribute__ (field ))
929
-
930
842
@classmethod
931
843
def _convert_to_style (cls , style_dict ):
932
844
"""
@@ -948,88 +860,6 @@ def _convert_to_style(cls, style_dict):
948
860
949
861
return xls_style
950
862
951
-
952
- register_writer (_Openpyxl1Writer )
953
-
954
-
955
- class _OpenpyxlWriter (_Openpyxl1Writer ):
956
- engine = 'openpyxl'
957
-
958
-
959
- register_writer (_OpenpyxlWriter )
960
-
961
-
962
- class _Openpyxl20Writer (_Openpyxl1Writer ):
963
- """
964
- Note: Support for OpenPyxl v2 is currently EXPERIMENTAL (GH7565).
965
- """
966
- engine = 'openpyxl20'
967
- openpyxl_majorver = 2
968
-
969
- def write_cells (self , cells , sheet_name = None , startrow = 0 , startcol = 0 ,
970
- freeze_panes = None ):
971
- # Write the frame cells using openpyxl.
972
- from openpyxl .cell import get_column_letter
973
-
974
- sheet_name = self ._get_sheet_name (sheet_name )
975
-
976
- if sheet_name in self .sheets :
977
- wks = self .sheets [sheet_name ]
978
- else :
979
- wks = self .book .create_sheet ()
980
- wks .title = sheet_name
981
- self .sheets [sheet_name ] = wks
982
-
983
- for cell in cells :
984
- colletter = get_column_letter (startcol + cell .col + 1 )
985
- xcell = wks ["{col}{row}"
986
- .format (col = colletter , row = startrow + cell .row + 1 )]
987
- xcell .value = _conv_value (cell .val )
988
- style_kwargs = {}
989
-
990
- # Apply format codes before cell.style to allow override
991
- if isinstance (cell .val , datetime ):
992
- style_kwargs .update (self ._convert_to_style_kwargs ({
993
- 'number_format' : {'format_code' : self .datetime_format }}))
994
- elif isinstance (cell .val , date ):
995
- style_kwargs .update (self ._convert_to_style_kwargs ({
996
- 'number_format' : {'format_code' : self .date_format }}))
997
-
998
- if cell .style :
999
- style_kwargs .update (self ._convert_to_style_kwargs (cell .style ))
1000
-
1001
- if style_kwargs :
1002
- xcell .style = xcell .style .copy (** style_kwargs )
1003
-
1004
- if cell .mergestart is not None and cell .mergeend is not None :
1005
- cletterstart = get_column_letter (startcol + cell .col + 1 )
1006
- cletterend = get_column_letter (startcol + cell .mergeend + 1 )
1007
-
1008
- wks .merge_cells ('{start}{row}:{end}{mergestart}'
1009
- .format (start = cletterstart ,
1010
- row = startrow + cell .row + 1 ,
1011
- end = cletterend ,
1012
- mergestart = startrow +
1013
- cell .mergestart + 1 ))
1014
-
1015
- # Excel requires that the format of the first cell in a merged
1016
- # range is repeated in the rest of the merged range.
1017
- if style_kwargs :
1018
- first_row = startrow + cell .row + 1
1019
- last_row = startrow + cell .mergestart + 1
1020
- first_col = startcol + cell .col + 1
1021
- last_col = startcol + cell .mergeend + 1
1022
-
1023
- for row in range (first_row , last_row + 1 ):
1024
- for col in range (first_col , last_col + 1 ):
1025
- if row == first_row and col == first_col :
1026
- # Ignore first cell. It is already handled.
1027
- continue
1028
- colletter = get_column_letter (col )
1029
- xcell = wks ["{col}{row}"
1030
- .format (col = colletter , row = row )]
1031
- xcell .style = xcell .style .copy (** style_kwargs )
1032
-
1033
863
@classmethod
1034
864
def _convert_to_style_kwargs (cls , style_dict ):
1035
865
"""
@@ -1341,13 +1171,7 @@ def _convert_to_number_format(cls, number_format_dict):
1341
1171
-------
1342
1172
number_format : str
1343
1173
"""
1344
- try :
1345
- # >= 2.0.0 < 2.1.0
1346
- from openpyxl .styles import NumberFormat
1347
- return NumberFormat (** number_format_dict )
1348
- except :
1349
- # >= 2.1.0
1350
- return number_format_dict ['format_code' ]
1174
+ return number_format_dict ['format_code' ]
1351
1175
1352
1176
@classmethod
1353
1177
def _convert_to_protection (cls , protection_dict ):
@@ -1367,17 +1191,6 @@ def _convert_to_protection(cls, protection_dict):
1367
1191
1368
1192
return Protection (** protection_dict )
1369
1193
1370
-
1371
- register_writer (_Openpyxl20Writer )
1372
-
1373
-
1374
- class _Openpyxl22Writer (_Openpyxl20Writer ):
1375
- """
1376
- Note: Support for OpenPyxl v2.2 is currently EXPERIMENTAL (GH7565).
1377
- """
1378
- engine = 'openpyxl22'
1379
- openpyxl_majorver = 2
1380
-
1381
1194
def write_cells (self , cells , sheet_name = None , startrow = 0 , startcol = 0 ,
1382
1195
freeze_panes = None ):
1383
1196
# Write the frame cells using openpyxl.
@@ -1443,7 +1256,7 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0,
1443
1256
setattr (xcell , k , v )
1444
1257
1445
1258
1446
- register_writer (_Openpyxl22Writer )
1259
+ register_writer (_OpenpyxlWriter )
1447
1260
1448
1261
1449
1262
class _XlwtWriter (ExcelWriter ):
0 commit comments