PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/tablib/packages/openpyxl/writer/dump_worksheet.py

http://github.com/kennethreitz/tablib
Python | 256 lines | 211 code | 9 blank | 36 comment | 1 complexity | fc84b53f988bbbe4aba418acdf5cbd60 MD5 | raw file
  1. # file openpyxl/writer/straight_worksheet.py
  2. # Copyright (c) 2010 openpyxl
  3. #
  4. # Permission is hereby granted, free of charge, to any person obtaining a copy
  5. # of this software and associated documentation files (the "Software"), to deal
  6. # in the Software without restriction, including without limitation the rights
  7. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. # copies of the Software, and to permit persons to whom the Software is
  9. # furnished to do so, subject to the following conditions:
  10. #
  11. # The above copyright notice and this permission notice shall be included in
  12. # all copies or substantial portions of the Software.
  13. #
  14. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. # THE SOFTWARE.
  21. #
  22. # @license: http://www.opensource.org/licenses/mit-license.php
  23. # @author: Eric Gazoni
  24. """Write worksheets to xml representations in an optimized way"""
  25. import datetime
  26. import os
  27. from ..cell import column_index_from_string, get_column_letter, Cell
  28. from ..worksheet import Worksheet
  29. from ..shared.xmltools import XMLGenerator, get_document_content, \
  30. start_tag, end_tag, tag
  31. from ..shared.date_time import SharedDate
  32. from ..shared.ooxml import MAX_COLUMN, MAX_ROW
  33. from tempfile import NamedTemporaryFile
  34. from ..writer.excel import ExcelWriter
  35. from ..writer.strings import write_string_table
  36. from ..writer.styles import StyleWriter
  37. from ..style import Style, NumberFormat
  38. from ..shared.ooxml import ARC_SHARED_STRINGS, ARC_CONTENT_TYPES, \
  39. ARC_ROOT_RELS, ARC_WORKBOOK_RELS, ARC_APP, ARC_CORE, ARC_THEME, \
  40. ARC_STYLE, ARC_WORKBOOK, \
  41. PACKAGE_WORKSHEETS, PACKAGE_DRAWINGS, PACKAGE_CHARTS
  42. STYLES = {'datetime' : {'type':Cell.TYPE_NUMERIC,
  43. 'style':'1'},
  44. 'string':{'type':Cell.TYPE_STRING,
  45. 'style':'0'},
  46. 'numeric':{'type':Cell.TYPE_NUMERIC,
  47. 'style':'0'},
  48. 'formula':{'type':Cell.TYPE_FORMULA,
  49. 'style':'0'},
  50. 'boolean':{'type':Cell.TYPE_BOOL,
  51. 'style':'0'},
  52. }
  53. DATETIME_STYLE = Style()
  54. DATETIME_STYLE.number_format.format_code = NumberFormat.FORMAT_DATE_YYYYMMDD2
  55. BOUNDING_BOX_PLACEHOLDER = 'A1:%s%d' % (get_column_letter(MAX_COLUMN), MAX_ROW)
  56. class DumpWorksheet(Worksheet):
  57. """
  58. .. warning::
  59. You shouldn't initialize this yourself, use :class:`openpyxl.workbook.Workbook` constructor instead,
  60. with `optimized_write = True`.
  61. """
  62. def __init__(self, parent_workbook):
  63. Worksheet.__init__(self, parent_workbook)
  64. self._max_col = 0
  65. self._max_row = 0
  66. self._parent = parent_workbook
  67. self._fileobj_header = NamedTemporaryFile(mode='r+', prefix='openpyxl.', suffix='.header', delete=False)
  68. self._fileobj_content = NamedTemporaryFile(mode='r+', prefix='openpyxl.', suffix='.content', delete=False)
  69. self._fileobj = NamedTemporaryFile(mode='w', prefix='openpyxl.', delete=False)
  70. self.doc = XMLGenerator(self._fileobj_content, 'utf-8')
  71. self.header = XMLGenerator(self._fileobj_header, 'utf-8')
  72. self.title = 'Sheet'
  73. self._shared_date = SharedDate()
  74. self._string_builder = self._parent.strings_table_builder
  75. @property
  76. def filename(self):
  77. return self._fileobj.name
  78. def write_header(self):
  79. doc = self.header
  80. start_tag(doc, 'worksheet',
  81. {'xml:space': 'preserve',
  82. 'xmlns': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
  83. 'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'})
  84. start_tag(doc, 'sheetPr')
  85. tag(doc, 'outlinePr',
  86. {'summaryBelow': '1',
  87. 'summaryRight': '1'})
  88. end_tag(doc, 'sheetPr')
  89. tag(doc, 'dimension', {'ref': 'A1:%s' % (self.get_dimensions())})
  90. start_tag(doc, 'sheetViews')
  91. start_tag(doc, 'sheetView', {'workbookViewId': '0'})
  92. tag(doc, 'selection', {'activeCell': 'A1',
  93. 'sqref': 'A1'})
  94. end_tag(doc, 'sheetView')
  95. end_tag(doc, 'sheetViews')
  96. tag(doc, 'sheetFormatPr', {'defaultRowHeight': '15'})
  97. start_tag(doc, 'sheetData')
  98. def close(self):
  99. self._close_content()
  100. self._close_header()
  101. self._write_fileobj(self._fileobj_header)
  102. self._write_fileobj(self._fileobj_content)
  103. self._fileobj.close()
  104. def _write_fileobj(self, fobj):
  105. fobj.flush()
  106. fobj.seek(0)
  107. while True:
  108. chunk = fobj.read(4096)
  109. if not chunk:
  110. break
  111. self._fileobj.write(chunk)
  112. fobj.close()
  113. os.remove(fobj.name)
  114. self._fileobj.flush()
  115. def _close_header(self):
  116. doc = self.header
  117. #doc.endDocument()
  118. def _close_content(self):
  119. doc = self.doc
  120. end_tag(doc, 'sheetData')
  121. end_tag(doc, 'worksheet')
  122. #doc.endDocument()
  123. def get_dimensions(self):
  124. if not self._max_col or not self._max_row:
  125. return 'A1'
  126. else:
  127. return '%s%d' % (get_column_letter(self._max_col), (self._max_row))
  128. def append(self, row):
  129. """
  130. :param row: iterable containing values to append
  131. :type row: iterable
  132. """
  133. doc = self.doc
  134. self._max_row += 1
  135. span = len(row)
  136. self._max_col = max(self._max_col, span)
  137. row_idx = self._max_row
  138. attrs = {'r': '%d' % row_idx,
  139. 'spans': '1:%d' % span}
  140. start_tag(doc, 'row', attrs)
  141. for col_idx, cell in enumerate(row):
  142. if cell is None:
  143. continue
  144. coordinate = '%s%d' % (get_column_letter(col_idx+1), row_idx)
  145. attributes = {'r': coordinate}
  146. if isinstance(cell, bool):
  147. dtype = 'boolean'
  148. elif isinstance(cell, (int, float)):
  149. dtype = 'numeric'
  150. elif isinstance(cell, (datetime.datetime, datetime.date)):
  151. dtype = 'datetime'
  152. cell = self._shared_date.datetime_to_julian(cell)
  153. attributes['s'] = STYLES[dtype]['style']
  154. elif cell and cell[0] == '=':
  155. dtype = 'formula'
  156. else:
  157. dtype = 'string'
  158. cell = self._string_builder.add(cell)
  159. attributes['t'] = STYLES[dtype]['type']
  160. start_tag(doc, 'c', attributes)
  161. if dtype == 'formula':
  162. tag(doc, 'f', body = '%s' % cell[1:])
  163. tag(doc, 'v')
  164. else:
  165. tag(doc, 'v', body = '%s' % cell)
  166. end_tag(doc, 'c')
  167. end_tag(doc, 'row')
  168. def save_dump(workbook, filename):
  169. writer = ExcelDumpWriter(workbook)
  170. writer.save(filename)
  171. return True
  172. class ExcelDumpWriter(ExcelWriter):
  173. def __init__(self, workbook):
  174. self.workbook = workbook
  175. self.style_writer = StyleDumpWriter(workbook)
  176. self.style_writer._style_list.append(DATETIME_STYLE)
  177. def _write_string_table(self, archive):
  178. shared_string_table = self.workbook.strings_table_builder.get_table()
  179. archive.writestr(ARC_SHARED_STRINGS,
  180. write_string_table(shared_string_table))
  181. return shared_string_table
  182. def _write_worksheets(self, archive, shared_string_table, style_writer):
  183. for i, sheet in enumerate(self.workbook.worksheets):
  184. sheet.write_header()
  185. sheet.close()
  186. archive.write(sheet.filename, PACKAGE_WORKSHEETS + '/sheet%d.xml' % (i + 1))
  187. os.remove(sheet.filename)
  188. class StyleDumpWriter(StyleWriter):
  189. def _get_style_list(self, workbook):
  190. return []