Skip to content

Commit b178066

Browse files
author
locojaydev
committed
excel format
1 parent bce9118 commit b178066

File tree

1 file changed

+151
-46
lines changed

1 file changed

+151
-46
lines changed

pandas/io/parsers.py

+151-46
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from itertools import izip
77
from urlparse import urlparse
88
import csv
9+
import xlwt
910

1011
try:
1112
next
@@ -1881,6 +1882,89 @@ def _trim_excel_header(row):
18811882
return row
18821883

18831884

1885+
class CellStyleConverter(object):
1886+
"""
1887+
Utility Class which converts a style dict to xlrd or openpyxl style
1888+
"""
1889+
1890+
@staticmethod
1891+
def to_xls(style_dict):
1892+
"""
1893+
converts a style_dict to an xlwt style object
1894+
Parameters
1895+
----------
1896+
style_dict: style dictionary to convert
1897+
"""
1898+
def style_to_xlwt(item, firstlevel=True, field_sep=',', line_sep=';'):
1899+
"""helper wich recursively generate an xlwt easy style string
1900+
for example:
1901+
1902+
hstyle = {"font": {"bold": True},
1903+
"border": {"top": "thin",
1904+
"right": "thin",
1905+
"bottom": "thin",
1906+
"left": "thin"},
1907+
"align": {"horiz": "center"}}
1908+
will be converted to
1909+
font: bold on; \
1910+
border: top thin, right thin, bottom thin, left thin; \
1911+
align: horiz center;
1912+
"""
1913+
if hasattr(item, 'items'):
1914+
if firstlevel:
1915+
it = ["%s: %s" % (key, style_to_xlwt(value, False))
1916+
for key, value in item.items()]
1917+
out = "%s " % (line_sep).join(it)
1918+
return out
1919+
else:
1920+
it = ["%s %s" % (key, style_to_xlwt(value, False))
1921+
for key, value in item.items()]
1922+
out = "%s " % (field_sep).join(it)
1923+
return out
1924+
else:
1925+
item = "%s" % item
1926+
item = item.replace("True", "on")
1927+
item = item.replace("False", "off")
1928+
return item
1929+
1930+
if style_dict:
1931+
xlwt_stylestr = style_to_xlwt(style_dict)
1932+
return xlwt.easyxf(xlwt_stylestr, field_sep=',', line_sep=';')
1933+
else:
1934+
return xlwt.XFStyle()
1935+
1936+
@staticmethod
1937+
def to_xlsx(style_dict):
1938+
"""
1939+
converts a style_dict to an openpyxl style object
1940+
Parameters
1941+
----------
1942+
style_dict: style dictionary to convert
1943+
"""
1944+
1945+
from openpyxl.style import Style
1946+
xls_style = Style()
1947+
for key, value in style_dict.items():
1948+
for nk, nv in value.items():
1949+
if key == "borders":
1950+
(xls_style.borders.__getattribute__(nk)
1951+
.__setattr__('border_style', nv))
1952+
else:
1953+
xls_style.__getattribute__(key).__setattr__(nk, nv)
1954+
1955+
return xls_style
1956+
1957+
1958+
def _conv_value(val):
1959+
#convert value for excel dump
1960+
if isinstance(val, np.int64):
1961+
val = int(val)
1962+
if isinstance(val, np.bool8):
1963+
val = bool(val)
1964+
1965+
return val
1966+
1967+
18841968
class ExcelWriter(object):
18851969
"""
18861970
Class for writing DataFrame objects into excel sheets, uses xlwt for xls,
@@ -1897,11 +1981,12 @@ def __init__(self, path):
18971981
self.use_xlsx = False
18981982
import xlwt
18991983
self.book = xlwt.Workbook()
1900-
self.fm_datetime = xlwt.easyxf(num_format_str='YYYY-MM-DD HH:MM:SS')
1984+
self.fm_datetime = xlwt.easyxf(
1985+
num_format_str='YYYY-MM-DD HH:MM:SS')
19011986
self.fm_date = xlwt.easyxf(num_format_str='YYYY-MM-DD')
19021987
else:
19031988
from openpyxl.workbook import Workbook
1904-
self.book = Workbook(optimized_write=True)
1989+
self.book = Workbook()#optimized_write=True)
19051990
self.path = path
19061991
self.sheets = {}
19071992
self.cur_sheet = None
@@ -1912,66 +1997,86 @@ def save(self):
19121997
"""
19131998
self.book.save(self.path)
19141999

1915-
def writerow(self, row, sheet_name=None):
2000+
def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0):
19162001
"""
1917-
Write the given row into Excel an excel sheet
2002+
Write given formated cells into Excel an excel sheet
19182003
19192004
Parameters
19202005
----------
1921-
row : list
1922-
Row of data to save to Excel sheet
2006+
cells : generator
2007+
cell of formated data to save to Excel sheet
19232008
sheet_name : string, default None
19242009
Name of Excel sheet, if None, then use self.cur_sheet
2010+
startrow: upper left cell row to dump data frame
2011+
startcol: upper left cell column to dump data frame
19252012
"""
19262013
if sheet_name is None:
19272014
sheet_name = self.cur_sheet
19282015
if sheet_name is None: # pragma: no cover
19292016
raise Exception('Must pass explicit sheet_name or set '
19302017
'cur_sheet property')
19312018
if self.use_xlsx:
1932-
self._writerow_xlsx(row, sheet_name)
2019+
self._writecells_xlsx(cells, sheet_name, startrow, startcol)
19332020
else:
1934-
self._writerow_xls(row, sheet_name)
2021+
self._writecells_xls(cells, sheet_name, startrow, startcol)
2022+
2023+
def _writecells_xlsx(self, cells, sheet_name, startrow, startcol):
2024+
from openpyxl.cell import get_column_letter
19352025

1936-
def _writerow_xls(self, row, sheet_name):
19372026
if sheet_name in self.sheets:
1938-
sheet, row_idx = self.sheets[sheet_name]
2027+
wks = self.sheets[sheet_name]
19392028
else:
1940-
sheet = self.book.add_sheet(sheet_name)
1941-
row_idx = 0
1942-
sheetrow = sheet.row(row_idx)
1943-
for i, val in enumerate(row):
1944-
if isinstance(val, (datetime.datetime, datetime.date)):
1945-
if isinstance(val, datetime.datetime):
1946-
sheetrow.write(i, val, self.fm_datetime)
1947-
else:
1948-
sheetrow.write(i, val, self.fm_date)
1949-
elif isinstance(val, np.int64):
1950-
sheetrow.write(i, int(val))
1951-
elif isinstance(val, np.bool8):
1952-
sheetrow.write(i, bool(val))
1953-
else:
1954-
sheetrow.write(i, val)
1955-
row_idx += 1
1956-
if row_idx == 1000:
1957-
sheet.flush_row_data()
1958-
self.sheets[sheet_name] = (sheet, row_idx)
1959-
1960-
def _writerow_xlsx(self, row, sheet_name):
2029+
wks = self.book.create_sheet()
2030+
wks.title = sheet_name
2031+
self.sheets[sheet_name] = wks
2032+
2033+
for cell in cells:
2034+
colletter = get_column_letter(startcol + cell.col + 1)
2035+
xcell = wks.cell("%s%s" % (colletter, startrow + cell.row + 1))
2036+
xcell.value = _conv_value(cell.val)
2037+
if cell.style:
2038+
style = CellStyleConverter.to_xlsx(cell.style)
2039+
for field in style.__fields__:
2040+
xcell.style.__setattr__(field,
2041+
style.__getattribute__(field))
2042+
2043+
if isinstance(cell.val, datetime.datetime):
2044+
style.num_format_str = "YYYY-MM-DD HH:SS"
2045+
elif isinstance(cell.val, datetime.date):
2046+
style.num_format_str = "YYYY-MM-DD"
2047+
2048+
#merging requires openpyxl latest (works on 1.5.7)
2049+
if cell.mergestart is not None and cell.mergeend is not None:
2050+
cletterstart = get_column_letter(startcol + cell.col + 1)
2051+
cletterend = get_column_letter(startcol + cell.mergeend + 1)
2052+
2053+
wks.merge_cells('%s%s:%s%s' % (cletterstart,
2054+
startrow + cell.row + 1,
2055+
cletterend,
2056+
startrow + cell.mergestart + 1))
2057+
2058+
def _writecells_xls(self, cells, sheet_name, startrow, startcol):
19612059
if sheet_name in self.sheets:
1962-
sheet, row_idx = self.sheets[sheet_name]
2060+
wks = self.sheets[sheet_name]
19632061
else:
1964-
sheet = self.book.create_sheet()
1965-
sheet.title = sheet_name
1966-
row_idx = 0
1967-
1968-
conv_row = []
1969-
for val in row:
1970-
if isinstance(val, np.int64):
1971-
val = int(val)
1972-
elif isinstance(val, np.bool8):
1973-
val = bool(val)
1974-
conv_row.append(val)
1975-
sheet.append(conv_row)
1976-
row_idx += 1
1977-
self.sheets[sheet_name] = (sheet, row_idx)
2062+
wks = self.book.add_sheet(sheet_name)
2063+
self.sheets[sheet_name] = wks
2064+
2065+
for cell in cells:
2066+
val = _conv_value(cell.val)
2067+
style = CellStyleConverter.to_xls(cell.style)
2068+
if isinstance(val, datetime.datetime):
2069+
style.num_format_str = "YYYY-MM-DD HH:SS"
2070+
elif isinstance(val, datetime.date):
2071+
style.num_format_str = "YYYY-MM-DD"
2072+
2073+
if cell.mergestart is not None and cell.mergeend is not None:
2074+
wks.write_merge(startrow + cell.row,
2075+
startrow + cell.mergestart,
2076+
startcol + cell.col,
2077+
startcol + cell.mergeend,
2078+
val, style)
2079+
else:
2080+
wks.write(startrow + cell.row,
2081+
startcol + cell.col,
2082+
val, style)

0 commit comments

Comments
 (0)