From a60e2f132e67ebdfab6a4220953c8b15d6e97378 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Fri, 13 May 2011 00:28:50 -0400 Subject: [PATCH] Finally! :sparkles:Python 3:sparkles: port of openpyxl --- tablib/packages/openpyxl3/cell.py | 4 +- tablib/packages/openpyxl3/chart.py | 680 +++++++-------- tablib/packages/openpyxl3/drawing.py | 804 +++++++++--------- tablib/packages/openpyxl3/reader/__init__.py | 10 +- tablib/packages/openpyxl3/reader/excel.py | 14 +- .../openpyxl3/reader/iter_worksheet.py | 686 +++++++-------- tablib/packages/openpyxl3/reader/worksheet.py | 13 +- tablib/packages/openpyxl3/shared/__init__.py | 12 +- tablib/packages/openpyxl3/shared/date_time.py | 4 +- tablib/packages/openpyxl3/style.py | 2 +- tablib/packages/openpyxl3/tests/helper.py | 4 +- tablib/packages/openpyxl3/tests/test_cell.py | 2 +- tablib/packages/openpyxl3/tests/test_chart.py | 262 +++--- tablib/packages/openpyxl3/tests/test_iter.py | 224 ++--- tablib/packages/openpyxl3/tests/test_meta.py | 2 +- .../openpyxl3/tests/test_named_range.py | 2 +- .../openpyxl3/tests/test_number_format.py | 6 +- tablib/packages/openpyxl3/tests/test_props.py | Bin 9060 -> 4494 bytes tablib/packages/openpyxl3/tests/test_read.py | 2 +- .../packages/openpyxl3/tests/test_strings.py | 2 +- tablib/packages/openpyxl3/tests/test_style.py | 2 +- tablib/packages/openpyxl3/tests/test_write.py | 4 +- tablib/packages/openpyxl3/worksheet.py | 8 +- tablib/packages/openpyxl3/writer/charts.py | 523 ++++++------ .../openpyxl3/writer/dump_worksheet.py | 8 +- tablib/packages/openpyxl3/writer/excel.py | 16 +- tablib/packages/openpyxl3/writer/strings.py | 4 +- tablib/packages/openpyxl3/writer/styles.py | 6 +- tablib/packages/openpyxl3/writer/worksheet.py | 2 +- 29 files changed, 1657 insertions(+), 1651 deletions(-) diff --git a/tablib/packages/openpyxl3/cell.py b/tablib/packages/openpyxl3/cell.py index 300f0ed..1171fde 100644 --- a/tablib/packages/openpyxl3/cell.py +++ b/tablib/packages/openpyxl3/cell.py @@ -335,7 +335,7 @@ class Cell(object): @property def style(self): - """Returns the :class:`openpyxl.style.Style` object for this cell""" + """Returns the :class:`.style.Style` object for this cell""" return self.parent.get_style(self.get_coordinate()) @property @@ -367,7 +367,7 @@ class Cell(object): :param column: number of columns to offset :type column: int - :rtype: :class:`openpyxl.cell.Cell` + :rtype: :class:`.cell.Cell` """ offset_column = get_column_letter(column_index_from_string( column = self.column) + column) diff --git a/tablib/packages/openpyxl3/chart.py b/tablib/packages/openpyxl3/chart.py index 19ba3b9..265ccaf 100644 --- a/tablib/packages/openpyxl3/chart.py +++ b/tablib/packages/openpyxl3/chart.py @@ -1,340 +1,340 @@ -''' -Copyright (c) 2010 openpyxl - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -@license: http://www.opensource.org/licenses/mit-license.php -@author: Eric Gazoni -''' - -import math - -from .style import NumberFormat -from .drawing import Drawing, Shape -from .shared.units import pixels_to_EMU, short_color -from .cell import get_column_letter - -class Axis(object): - - POSITION_BOTTOM = 'b' - POSITION_LEFT = 'l' - - ORIENTATION_MIN_MAX = "minMax" - - def __init__(self): - - self.orientation = self.ORIENTATION_MIN_MAX - self.number_format = NumberFormat() - for attr in ('position','tick_label_position','crosses', - 'auto','label_align','label_offset','cross_between'): - setattr(self, attr, None) - self.min = 0 - self.max = None - self.unit = None - - @classmethod - def default_category(cls): - """ default values for category axes """ - - ax = Axis() - ax.id = 60871424 - ax.cross = 60873344 - ax.position = Axis.POSITION_BOTTOM - ax.tick_label_position = 'nextTo' - ax.crosses = "autoZero" - ax.auto = True - ax.label_align = 'ctr' - ax.label_offset = 100 - return ax - - @classmethod - def default_value(cls): - """ default values for value axes """ - - ax = Axis() - ax.id = 60873344 - ax.cross = 60871424 - ax.position = Axis.POSITION_LEFT - ax.major_gridlines = None - ax.tick_label_position = 'nextTo' - ax.crosses = 'autoZero' - ax.auto = False - ax.cross_between = 'between' - return ax - -class Reference(object): - """ a simple wrapper around a serie of reference data """ - - def __init__(self, sheet, pos1, pos2=None): - - self.sheet = sheet - self.pos1 = pos1 - self.pos2 = pos2 - - def get_type(self): - - if isinstance(self.cache[0], str): - return 'str' - else: - return 'num' - - def _get_ref(self): - """ format excel reference notation """ - - if self.pos2: - return '%s!$%s$%s:$%s$%s' % (self.sheet.title, - get_column_letter(self.pos1[1]+1), self.pos1[0]+1, - get_column_letter(self.pos2[1]+1), self.pos2[0]+1) - else: - return '%s!$%s$%s' % (self.sheet.title, - get_column_letter(self.pos1[1]+1), self.pos1[0]+1) - - - def _get_cache(self): - """ read data in sheet - to be used at writing time """ - - cache = [] - if self.pos2: - for row in range(self.pos1[0], self.pos2[0]+1): - for col in range(self.pos1[1], self.pos2[1]+1): - cache.append(self.sheet.cell(row=row, column=col).value) - else: - cell = self.sheet.cell(row=self.pos1[0], column=self.pos1[1]) - cache.append(cell.value) - return cache - - -class Serie(object): - """ a serie of data and possibly associated labels """ - - MARKER_NONE = 'none' - - def __init__(self, values, labels=None, legend=None, color=None, xvalues=None): - - self.marker = Serie.MARKER_NONE - self.values = values - self.xvalues = xvalues - self.labels = labels - self.legend = legend - self.error_bar = None - self._color = color - - def _get_color(self): - return self._color - - def _set_color(self, color): - self._color = short_color(color) - - color = property(_get_color, _set_color) - - def get_min_max(self): - - if self.error_bar: - err_cache = self.error_bar.values._get_cache() - vals = [v + err_cache[i] \ - for i,v in enumerate(self.values._get_cache())] - else: - vals = self.values._get_cache() - return min(vals), max(vals) - - def __len__(self): - - return len(self.values.cache) - -class Legend(object): - - def __init__(self): - - self.position = 'r' - self.layout = None - -class ErrorBar(object): - - PLUS = 1 - MINUS = 2 - PLUS_MINUS = 3 - - def __init__(self, _type, values): - - self.type = _type - self.values = values - -class Chart(object): - """ raw chart class """ - - GROUPING_CLUSTERED = 'clustered' - GROUPING_STANDARD = 'standard' - - BAR_CHART = 1 - LINE_CHART = 2 - SCATTER_CHART = 3 - - def __init__(self, _type, grouping): - - self._series = [] - - # public api - self.type = _type - self.grouping = grouping - self.x_axis = Axis.default_category() - self.y_axis = Axis.default_value() - self.legend = Legend() - self.lang = 'fr-FR' - self.title = '' - self.print_margins = dict(b=.75, l=.7, r=.7, t=.75, header=0.3, footer=.3) - - # the containing drawing - self.drawing = Drawing() - - # the offset for the plot part in percentage of the drawing size - self.width = .6 - self.height = .6 - self.margin_top = self._get_max_margin_top() - self.margin_left = 0 - - # the user defined shapes - self._shapes = [] - - def add_serie(self, serie): - - serie.id = len(self._series) - self._series.append(serie) - self._compute_min_max() - if not None in [s.xvalues for s in self._series]: - self._compute_xmin_xmax() - - def add_shape(self, shape): - - shape._chart = self - self._shapes.append(shape) - - def get_x_units(self): - """ calculate one unit for x axis in EMU """ - - return max([len(s.values._get_cache()) for s in self._series]) - - def get_y_units(self): - """ calculate one unit for y axis in EMU """ - - dh = pixels_to_EMU(self.drawing.height) - return (dh * self.height) / self.y_axis.max - - def get_y_chars(self): - """ estimate nb of chars for y axis """ - - _max = max([max([x for x in s.values._get_cache() if x is not None]) for s in self._series]) - return len(str(int(_max))) - - def _compute_min_max(self): - """ compute y axis limits and units """ - - maxi = max([max([x for x in s.values._get_cache() if x is not None]) for s in self._series]) - - mul = None - if maxi < 1: - s = str(maxi).split('.')[1] - mul = 10 - for x in s: - if x == '0': - mul *= 10 - else: - break - maxi = maxi * mul - - maxi = math.ceil(maxi * 1.1) - sz = len(str(int(maxi))) - 1 - unit = math.ceil(math.ceil(maxi / pow(10, sz)) * pow(10, sz-1)) - maxi = math.ceil(maxi/unit) * unit - - if mul is not None: - maxi = maxi/mul - unit = unit/mul - - if maxi / unit > 9: - # no more that 10 ticks - unit *= 2 - - self.y_axis.max = maxi - self.y_axis.unit = unit - - def _compute_xmin_xmax(self): - """ compute x axis limits and units """ - - maxi = max([max([x for x in s.xvalues._get_cache() if x is not None]) for s in self._series]) - - mul = None - if maxi < 1: - s = str(maxi).split('.')[1] - mul = 10 - for x in s: - if x == '0': - mul *= 10 - else: - break - maxi = maxi * mul - - maxi = math.ceil(maxi * 1.1) - sz = len(str(int(maxi))) - 1 - unit = math.ceil(math.ceil(maxi / pow(10, sz)) * pow(10, sz-1)) - maxi = math.ceil(maxi/unit) * unit - - if mul is not None: - maxi = maxi/mul - unit = unit/mul - - if maxi / unit > 9: - # no more that 10 ticks - unit *= 2 - - self.x_axis.max = maxi - self.x_axis.unit = unit - - def _get_max_margin_top(self): - - mb = Shape.FONT_HEIGHT + Shape.MARGIN_BOTTOM - plot_height = self.drawing.height * self.height - return float(self.drawing.height - plot_height - mb)/self.drawing.height - - def _get_min_margin_left(self): - - ml = (self.get_y_chars() * Shape.FONT_WIDTH) + Shape.MARGIN_LEFT - return float(ml)/self.drawing.width - - def _get_margin_top(self): - """ get margin in percent """ - - return min(self.margin_top, self._get_max_margin_top()) - - def _get_margin_left(self): - - return max(self._get_min_margin_left(), self.margin_left) - -class BarChart(Chart): - def __init__(self): - super(BarChart, self).__init__(Chart.BAR_CHART, Chart.GROUPING_CLUSTERED) - -class LineChart(Chart): - def __init__(self): - super(LineChart, self).__init__(Chart.LINE_CHART, Chart.GROUPING_STANDARD) - -class ScatterChart(Chart): - def __init__(self): - super(ScatterChart, self).__init__(Chart.SCATTER_CHART, Chart.GROUPING_STANDARD) - - +''' +Copyright (c) 2010 openpyxl + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +@license: http://www.opensource.org/licenses/mit-license.php +@author: Eric Gazoni +''' + +import math + +from .style import NumberFormat +from .drawing import Drawing, Shape +from .shared.units import pixels_to_EMU, short_color +from .cell import get_column_letter + +class Axis(object): + + POSITION_BOTTOM = 'b' + POSITION_LEFT = 'l' + + ORIENTATION_MIN_MAX = "minMax" + + def __init__(self): + + self.orientation = self.ORIENTATION_MIN_MAX + self.number_format = NumberFormat() + for attr in ('position','tick_label_position','crosses', + 'auto','label_align','label_offset','cross_between'): + setattr(self, attr, None) + self.min = 0 + self.max = None + self.unit = None + + @classmethod + def default_category(cls): + """ default values for category axes """ + + ax = Axis() + ax.id = 60871424 + ax.cross = 60873344 + ax.position = Axis.POSITION_BOTTOM + ax.tick_label_position = 'nextTo' + ax.crosses = "autoZero" + ax.auto = True + ax.label_align = 'ctr' + ax.label_offset = 100 + return ax + + @classmethod + def default_value(cls): + """ default values for value axes """ + + ax = Axis() + ax.id = 60873344 + ax.cross = 60871424 + ax.position = Axis.POSITION_LEFT + ax.major_gridlines = None + ax.tick_label_position = 'nextTo' + ax.crosses = 'autoZero' + ax.auto = False + ax.cross_between = 'between' + return ax + +class Reference(object): + """ a simple wrapper around a serie of reference data """ + + def __init__(self, sheet, pos1, pos2=None): + + self.sheet = sheet + self.pos1 = pos1 + self.pos2 = pos2 + + def get_type(self): + + if isinstance(self.cache[0], str): + return 'str' + else: + return 'num' + + def _get_ref(self): + """ format excel reference notation """ + + if self.pos2: + return '%s!$%s$%s:$%s$%s' % (self.sheet.title, + get_column_letter(self.pos1[1]+1), self.pos1[0]+1, + get_column_letter(self.pos2[1]+1), self.pos2[0]+1) + else: + return '%s!$%s$%s' % (self.sheet.title, + get_column_letter(self.pos1[1]+1), self.pos1[0]+1) + + + def _get_cache(self): + """ read data in sheet - to be used at writing time """ + + cache = [] + if self.pos2: + for row in range(self.pos1[0], self.pos2[0]+1): + for col in range(self.pos1[1], self.pos2[1]+1): + cache.append(self.sheet.cell(row=row, column=col).value) + else: + cell = self.sheet.cell(row=self.pos1[0], column=self.pos1[1]) + cache.append(cell.value) + return cache + + +class Serie(object): + """ a serie of data and possibly associated labels """ + + MARKER_NONE = 'none' + + def __init__(self, values, labels=None, legend=None, color=None, xvalues=None): + + self.marker = Serie.MARKER_NONE + self.values = values + self.xvalues = xvalues + self.labels = labels + self.legend = legend + self.error_bar = None + self._color = color + + def _get_color(self): + return self._color + + def _set_color(self, color): + self._color = short_color(color) + + color = property(_get_color, _set_color) + + def get_min_max(self): + + if self.error_bar: + err_cache = self.error_bar.values._get_cache() + vals = [v + err_cache[i] \ + for i,v in enumerate(self.values._get_cache())] + else: + vals = self.values._get_cache() + return min(vals), max(vals) + + def __len__(self): + + return len(self.values.cache) + +class Legend(object): + + def __init__(self): + + self.position = 'r' + self.layout = None + +class ErrorBar(object): + + PLUS = 1 + MINUS = 2 + PLUS_MINUS = 3 + + def __init__(self, _type, values): + + self.type = _type + self.values = values + +class Chart(object): + """ raw chart class """ + + GROUPING_CLUSTERED = 'clustered' + GROUPING_STANDARD = 'standard' + + BAR_CHART = 1 + LINE_CHART = 2 + SCATTER_CHART = 3 + + def __init__(self, _type, grouping): + + self._series = [] + + # public api + self.type = _type + self.grouping = grouping + self.x_axis = Axis.default_category() + self.y_axis = Axis.default_value() + self.legend = Legend() + self.lang = 'fr-FR' + self.title = '' + self.print_margins = dict(b=.75, l=.7, r=.7, t=.75, header=0.3, footer=.3) + + # the containing drawing + self.drawing = Drawing() + + # the offset for the plot part in percentage of the drawing size + self.width = .6 + self.height = .6 + self.margin_top = self._get_max_margin_top() + self.margin_left = 0 + + # the user defined shapes + self._shapes = [] + + def add_serie(self, serie): + + serie.id = len(self._series) + self._series.append(serie) + self._compute_min_max() + if not None in [s.xvalues for s in self._series]: + self._compute_xmin_xmax() + + def add_shape(self, shape): + + shape._chart = self + self._shapes.append(shape) + + def get_x_units(self): + """ calculate one unit for x axis in EMU """ + + return max([len(s.values._get_cache()) for s in self._series]) + + def get_y_units(self): + """ calculate one unit for y axis in EMU """ + + dh = pixels_to_EMU(self.drawing.height) + return (dh * self.height) / self.y_axis.max + + def get_y_chars(self): + """ estimate nb of chars for y axis """ + + _max = max([max(s.values._get_cache()) for s in self._series]) + return len(str(int(_max))) + + def _compute_min_max(self): + """ compute y axis limits and units """ + + maxi = max([max(s.values._get_cache()) for s in self._series]) + + mul = None + if maxi < 1: + s = str(maxi).split('.')[1] + mul = 10 + for x in s: + if x == '0': + mul *= 10 + else: + break + maxi = maxi * mul + + maxi = math.ceil(maxi * 1.1) + sz = len(str(int(maxi))) - 1 + unit = math.ceil(math.ceil(maxi / pow(10, sz)) * pow(10, sz-1)) + maxi = math.ceil(maxi/unit) * unit + + if mul is not None: + maxi = maxi/mul + unit = unit/mul + + if maxi / unit > 9: + # no more that 10 ticks + unit *= 2 + + self.y_axis.max = maxi + self.y_axis.unit = unit + + def _compute_xmin_xmax(self): + """ compute x axis limits and units """ + + maxi = max([max(s.xvalues._get_cache()) for s in self._series]) + + mul = None + if maxi < 1: + s = str(maxi).split('.')[1] + mul = 10 + for x in s: + if x == '0': + mul *= 10 + else: + break + maxi = maxi * mul + + maxi = math.ceil(maxi * 1.1) + sz = len(str(int(maxi))) - 1 + unit = math.ceil(math.ceil(maxi / pow(10, sz)) * pow(10, sz-1)) + maxi = math.ceil(maxi/unit) * unit + + if mul is not None: + maxi = maxi/mul + unit = unit/mul + + if maxi / unit > 9: + # no more that 10 ticks + unit *= 2 + + self.x_axis.max = maxi + self.x_axis.unit = unit + + def _get_max_margin_top(self): + + mb = Shape.FONT_HEIGHT + Shape.MARGIN_BOTTOM + plot_height = self.drawing.height * self.height + return float(self.drawing.height - plot_height - mb)/self.drawing.height + + def _get_min_margin_left(self): + + ml = (self.get_y_chars() * Shape.FONT_WIDTH) + Shape.MARGIN_LEFT + return float(ml)/self.drawing.width + + def _get_margin_top(self): + """ get margin in percent """ + + return min(self.margin_top, self._get_max_margin_top()) + + def _get_margin_left(self): + + return max(self._get_min_margin_left(), self.margin_left) + +class BarChart(Chart): + def __init__(self): + super(BarChart, self).__init__(Chart.BAR_CHART, Chart.GROUPING_CLUSTERED) + +class LineChart(Chart): + def __init__(self): + super(LineChart, self).__init__(Chart.LINE_CHART, Chart.GROUPING_STANDARD) + +class ScatterChart(Chart): + def __init__(self): + super(ScatterChart, self).__init__(Chart.SCATTER_CHART, Chart.GROUPING_STANDARD) + + diff --git a/tablib/packages/openpyxl3/drawing.py b/tablib/packages/openpyxl3/drawing.py index 6b3c76d..0007569 100644 --- a/tablib/packages/openpyxl3/drawing.py +++ b/tablib/packages/openpyxl3/drawing.py @@ -1,402 +1,402 @@ -''' -Copyright (c) 2010 openpyxl - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -@license: http://www.opensource.org/licenses/mit-license.php -@author: Eric Gazoni -''' - -import math -from .style import Color -from .shared.units import pixels_to_EMU, EMU_to_pixels, short_color - -class Shadow(object): - - SHADOW_BOTTOM = 'b' - SHADOW_BOTTOM_LEFT = 'bl' - SHADOW_BOTTOM_RIGHT = 'br' - SHADOW_CENTER = 'ctr' - SHADOW_LEFT = 'l' - SHADOW_TOP = 't' - SHADOW_TOP_LEFT = 'tl' - SHADOW_TOP_RIGHT = 'tr' - - def __init__(self): - self.visible = False - self.blurRadius = 6 - self.distance = 2 - self.direction = 0 - self.alignment = self.SHADOW_BOTTOM_RIGHT - self.color = Color(Color.BLACK) - self.alpha = 50 - -class Drawing(object): - """ a drawing object - eg container for shapes or charts - we assume user specifies dimensions in pixels; units are - converted to EMU in the drawing part - """ - - count = 0 - - def __init__(self): - - self.name = '' - self.description = '' - self.coordinates = ((1,2), (16,8)) - self.left = 0 - self.top = 0 - self._width = EMU_to_pixels(200000) - self._height = EMU_to_pixels(1828800) - self.resize_proportional = False - self.rotation = 0 -# self.shadow = Shadow() - - def _set_width(self, w): - - if self.resize_proportional and w: - ratio = self._height / self._width - self._height = round(ratio * w) - self._width = w - - def _get_width(self): - - return self._width - - width = property(_get_width, _set_width) - - def _set_height(self, h): - - if self.resize_proportional and h: - ratio = self._width / self._height - self._width = round(ratio * h) - self._height = h - - def _get_height(self): - - return self._height - - height = property(_get_height, _set_height) - - def set_dimension(self, w=0, h=0): - - xratio = w / self._width - yratio = h / self._height - - if self.resize_proportional and w and h: - if (xratio * self._height) < h: - self._height = math.ceil(xratio * self._height) - self._width = width - else: - self._width = math.ceil(yratio * self._width) - self._height = height - - def get_emu_dimensions(self): - """ return (x, y, w, h) in EMU """ - - return (pixels_to_EMU(self.left), pixels_to_EMU(self.top), - pixels_to_EMU(self._width), pixels_to_EMU(self._height)) - - -class Shape(object): - """ a drawing inside a chart - coordiantes are specified by the user in the axis units - """ - - MARGIN_LEFT = 6 + 13 + 1 - MARGIN_BOTTOM = 17 + 11 - - FONT_WIDTH = 7 - FONT_HEIGHT = 8 - - ROUND_RECT = 'roundRect' - RECT = 'rect' - - # other shapes to define : - ''' - "line" - "lineInv" - "triangle" - "rtTriangle" - "diamond" - "parallelogram" - "trapezoid" - "nonIsoscelesTrapezoid" - "pentagon" - "hexagon" - "heptagon" - "octagon" - "decagon" - "dodecagon" - "star4" - "star5" - "star6" - "star7" - "star8" - "star10" - "star12" - "star16" - "star24" - "star32" - "roundRect" - "round1Rect" - "round2SameRect" - "round2DiagRect" - "snipRoundRect" - "snip1Rect" - "snip2SameRect" - "snip2DiagRect" - "plaque" - "ellipse" - "teardrop" - "homePlate" - "chevron" - "pieWedge" - "pie" - "blockArc" - "donut" - "noSmoking" - "rightArrow" - "leftArrow" - "upArrow" - "downArrow" - "stripedRightArrow" - "notchedRightArrow" - "bentUpArrow" - "leftRightArrow" - "upDownArrow" - "leftUpArrow" - "leftRightUpArrow" - "quadArrow" - "leftArrowCallout" - "rightArrowCallout" - "upArrowCallout" - "downArrowCallout" - "leftRightArrowCallout" - "upDownArrowCallout" - "quadArrowCallout" - "bentArrow" - "uturnArrow" - "circularArrow" - "leftCircularArrow" - "leftRightCircularArrow" - "curvedRightArrow" - "curvedLeftArrow" - "curvedUpArrow" - "curvedDownArrow" - "swooshArrow" - "cube" - "can" - "lightningBolt" - "heart" - "sun" - "moon" - "smileyFace" - "irregularSeal1" - "irregularSeal2" - "foldedCorner" - "bevel" - "frame" - "halfFrame" - "corner" - "diagStripe" - "chord" - "arc" - "leftBracket" - "rightBracket" - "leftBrace" - "rightBrace" - "bracketPair" - "bracePair" - "straightConnector1" - "bentConnector2" - "bentConnector3" - "bentConnector4" - "bentConnector5" - "curvedConnector2" - "curvedConnector3" - "curvedConnector4" - "curvedConnector5" - "callout1" - "callout2" - "callout3" - "accentCallout1" - "accentCallout2" - "accentCallout3" - "borderCallout1" - "borderCallout2" - "borderCallout3" - "accentBorderCallout1" - "accentBorderCallout2" - "accentBorderCallout3" - "wedgeRectCallout" - "wedgeRoundRectCallout" - "wedgeEllipseCallout" - "cloudCallout" - "cloud" - "ribbon" - "ribbon2" - "ellipseRibbon" - "ellipseRibbon2" - "leftRightRibbon" - "verticalScroll" - "horizontalScroll" - "wave" - "doubleWave" - "plus" - "flowChartProcess" - "flowChartDecision" - "flowChartInputOutput" - "flowChartPredefinedProcess" - "flowChartInternalStorage" - "flowChartDocument" - "flowChartMultidocument" - "flowChartTerminator" - "flowChartPreparation" - "flowChartManualInput" - "flowChartManualOperation" - "flowChartConnector" - "flowChartPunchedCard" - "flowChartPunchedTape" - "flowChartSummingJunction" - "flowChartOr" - "flowChartCollate" - "flowChartSort" - "flowChartExtract" - "flowChartMerge" - "flowChartOfflineStorage" - "flowChartOnlineStorage" - "flowChartMagneticTape" - "flowChartMagneticDisk" - "flowChartMagneticDrum" - "flowChartDisplay" - "flowChartDelay" - "flowChartAlternateProcess" - "flowChartOffpageConnector" - "actionButtonBlank" - "actionButtonHome" - "actionButtonHelp" - "actionButtonInformation" - "actionButtonForwardNext" - "actionButtonBackPrevious" - "actionButtonEnd" - "actionButtonBeginning" - "actionButtonReturn" - "actionButtonDocument" - "actionButtonSound" - "actionButtonMovie" - "gear6" - "gear9" - "funnel" - "mathPlus" - "mathMinus" - "mathMultiply" - "mathDivide" - "mathEqual" - "mathNotEqual" - "cornerTabs" - "squareTabs" - "plaqueTabs" - "chartX" - "chartStar" - "chartPlus" - ''' - - def __init__(self, coordinates=((0,0), (1,1)), text=None, scheme="accent1"): - - self.coordinates = coordinates # in axis unit - self.text = text - self.scheme = scheme - self.style = Shape.RECT - self._border_width = 3175 # in EMU - self._border_color = Color.BLACK[2:] #"F3B3C5" - self._color = Color.WHITE[2:] - self._text_color = Color.BLACK[2:] - - def _get_border_color(self): - return self._border_color - - def _set_border_color(self, color): - self._border_color = short_color(color) - - border_color = property(_get_border_color, _set_border_color) - - def _get_color(self): - return self._color - - def _set_color(self, color): - self._color = short_color(color) - - color = property(_get_color, _set_color) - - def _get_text_color(self): - return self._text_color - - def _set_text_color(self, color): - self._text_color = short_color(color) - - text_color = property(_get_text_color, _set_text_color) - - def _get_border_width(self): - - return EMU_to_pixels(self._border_width) - - def _set_border_width(self, w): - - self._border_width = pixels_to_EMU(w) - print(self._border_width) - - border_width = property(_get_border_width, _set_border_width) - - def get_coordinates(self): - """ return shape coordinates in percentages (left, top, right, bottom) """ - - (x1, y1), (x2, y2) = self.coordinates - - drawing_width = pixels_to_EMU(self._chart.drawing.width) - drawing_height = pixels_to_EMU(self._chart.drawing.height) - plot_width = drawing_width * self._chart.width - plot_height = drawing_height * self._chart.height - - margin_left = self._chart._get_margin_left() * drawing_width - xunit = plot_width / self._chart.get_x_units() - - margin_top = self._chart._get_margin_top() * drawing_height - yunit = self._chart.get_y_units() - - x_start = (margin_left + (float(x1) * xunit)) / drawing_width - y_start = (margin_top + plot_height - (float(y1) * yunit)) / drawing_height - - x_end = (margin_left + (float(x2) * xunit)) / drawing_width - y_end = (margin_top + plot_height - (float(y2) * yunit)) / drawing_height - - def _norm_pct(pct): - """ force shapes to appear by truncating too large sizes """ - if pct>1: pct = 1 - elif pct<0: pct = 0 - return pct - - # allow user to specify y's in whatever order - # excel expect y_end to be lower - if y_end < y_start: - y_end, y_start = y_start, y_end - - return (_norm_pct(x_start), _norm_pct(y_start), - _norm_pct(x_end), _norm_pct(y_end)) - +''' +Copyright (c) 2010 openpyxl + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +@license: http://www.opensource.org/licenses/mit-license.php +@author: Eric Gazoni +''' + +import math +from .style import Color +from .shared.units import pixels_to_EMU, EMU_to_pixels, short_color + +class Shadow(object): + + SHADOW_BOTTOM = 'b' + SHADOW_BOTTOM_LEFT = 'bl' + SHADOW_BOTTOM_RIGHT = 'br' + SHADOW_CENTER = 'ctr' + SHADOW_LEFT = 'l' + SHADOW_TOP = 't' + SHADOW_TOP_LEFT = 'tl' + SHADOW_TOP_RIGHT = 'tr' + + def __init__(self): + self.visible = False + self.blurRadius = 6 + self.distance = 2 + self.direction = 0 + self.alignment = self.SHADOW_BOTTOM_RIGHT + self.color = Color(Color.BLACK) + self.alpha = 50 + +class Drawing(object): + """ a drawing object - eg container for shapes or charts + we assume user specifies dimensions in pixels; units are + converted to EMU in the drawing part + """ + + count = 0 + + def __init__(self): + + self.name = '' + self.description = '' + self.coordinates = ((1,2), (16,8)) + self.left = 0 + self.top = 0 + self._width = EMU_to_pixels(200000) + self._height = EMU_to_pixels(1828800) + self.resize_proportional = False + self.rotation = 0 +# self.shadow = Shadow() + + def _set_width(self, w): + + if self.resize_proportional and w: + ratio = self._height / self._width + self._height = round(ratio * w) + self._width = w + + def _get_width(self): + + return self._width + + width = property(_get_width, _set_width) + + def _set_height(self, h): + + if self.resize_proportional and h: + ratio = self._width / self._height + self._width = round(ratio * h) + self._height = h + + def _get_height(self): + + return self._height + + height = property(_get_height, _set_height) + + def set_dimension(self, w=0, h=0): + + xratio = w / self._width + yratio = h / self._height + + if self.resize_proportional and w and h: + if (xratio * self._height) < h: + self._height = math.ceil(xratio * self._height) + self._width = width + else: + self._width = math.ceil(yratio * self._width) + self._height = height + + def get_emu_dimensions(self): + """ return (x, y, w, h) in EMU """ + + return (pixels_to_EMU(self.left), pixels_to_EMU(self.top), + pixels_to_EMU(self._width), pixels_to_EMU(self._height)) + + +class Shape(object): + """ a drawing inside a chart + coordiantes are specified by the user in the axis units + """ + + MARGIN_LEFT = 6 + 13 + 1 + MARGIN_BOTTOM = 17 + 11 + + FONT_WIDTH = 7 + FONT_HEIGHT = 8 + + ROUND_RECT = 'roundRect' + RECT = 'rect' + + # other shapes to define : + ''' + "line" + "lineInv" + "triangle" + "rtTriangle" + "diamond" + "parallelogram" + "trapezoid" + "nonIsoscelesTrapezoid" + "pentagon" + "hexagon" + "heptagon" + "octagon" + "decagon" + "dodecagon" + "star4" + "star5" + "star6" + "star7" + "star8" + "star10" + "star12" + "star16" + "star24" + "star32" + "roundRect" + "round1Rect" + "round2SameRect" + "round2DiagRect" + "snipRoundRect" + "snip1Rect" + "snip2SameRect" + "snip2DiagRect" + "plaque" + "ellipse" + "teardrop" + "homePlate" + "chevron" + "pieWedge" + "pie" + "blockArc" + "donut" + "noSmoking" + "rightArrow" + "leftArrow" + "upArrow" + "downArrow" + "stripedRightArrow" + "notchedRightArrow" + "bentUpArrow" + "leftRightArrow" + "upDownArrow" + "leftUpArrow" + "leftRightUpArrow" + "quadArrow" + "leftArrowCallout" + "rightArrowCallout" + "upArrowCallout" + "downArrowCallout" + "leftRightArrowCallout" + "upDownArrowCallout" + "quadArrowCallout" + "bentArrow" + "uturnArrow" + "circularArrow" + "leftCircularArrow" + "leftRightCircularArrow" + "curvedRightArrow" + "curvedLeftArrow" + "curvedUpArrow" + "curvedDownArrow" + "swooshArrow" + "cube" + "can" + "lightningBolt" + "heart" + "sun" + "moon" + "smileyFace" + "irregularSeal1" + "irregularSeal2" + "foldedCorner" + "bevel" + "frame" + "halfFrame" + "corner" + "diagStripe" + "chord" + "arc" + "leftBracket" + "rightBracket" + "leftBrace" + "rightBrace" + "bracketPair" + "bracePair" + "straightConnector1" + "bentConnector2" + "bentConnector3" + "bentConnector4" + "bentConnector5" + "curvedConnector2" + "curvedConnector3" + "curvedConnector4" + "curvedConnector5" + "callout1" + "callout2" + "callout3" + "accentCallout1" + "accentCallout2" + "accentCallout3" + "borderCallout1" + "borderCallout2" + "borderCallout3" + "accentBorderCallout1" + "accentBorderCallout2" + "accentBorderCallout3" + "wedgeRectCallout" + "wedgeRoundRectCallout" + "wedgeEllipseCallout" + "cloudCallout" + "cloud" + "ribbon" + "ribbon2" + "ellipseRibbon" + "ellipseRibbon2" + "leftRightRibbon" + "verticalScroll" + "horizontalScroll" + "wave" + "doubleWave" + "plus" + "flowChartProcess" + "flowChartDecision" + "flowChartInputOutput" + "flowChartPredefinedProcess" + "flowChartInternalStorage" + "flowChartDocument" + "flowChartMultidocument" + "flowChartTerminator" + "flowChartPreparation" + "flowChartManualInput" + "flowChartManualOperation" + "flowChartConnector" + "flowChartPunchedCard" + "flowChartPunchedTape" + "flowChartSummingJunction" + "flowChartOr" + "flowChartCollate" + "flowChartSort" + "flowChartExtract" + "flowChartMerge" + "flowChartOfflineStorage" + "flowChartOnlineStorage" + "flowChartMagneticTape" + "flowChartMagneticDisk" + "flowChartMagneticDrum" + "flowChartDisplay" + "flowChartDelay" + "flowChartAlternateProcess" + "flowChartOffpageConnector" + "actionButtonBlank" + "actionButtonHome" + "actionButtonHelp" + "actionButtonInformation" + "actionButtonForwardNext" + "actionButtonBackPrevious" + "actionButtonEnd" + "actionButtonBeginning" + "actionButtonReturn" + "actionButtonDocument" + "actionButtonSound" + "actionButtonMovie" + "gear6" + "gear9" + "funnel" + "mathPlus" + "mathMinus" + "mathMultiply" + "mathDivide" + "mathEqual" + "mathNotEqual" + "cornerTabs" + "squareTabs" + "plaqueTabs" + "chartX" + "chartStar" + "chartPlus" + ''' + + def __init__(self, coordinates=((0,0), (1,1)), text=None, scheme="accent1"): + + self.coordinates = coordinates # in axis unit + self.text = text + self.scheme = scheme + self.style = Shape.RECT + self._border_width = 3175 # in EMU + self._border_color = Color.BLACK[2:] #"F3B3C5" + self._color = Color.WHITE[2:] + self._text_color = Color.BLACK[2:] + + def _get_border_color(self): + return self._border_color + + def _set_border_color(self, color): + self._border_color = short_color(color) + + border_color = property(_get_border_color, _set_border_color) + + def _get_color(self): + return self._color + + def _set_color(self, color): + self._color = short_color(color) + + color = property(_get_color, _set_color) + + def _get_text_color(self): + return self._text_color + + def _set_text_color(self, color): + self._text_color = short_color(color) + + text_color = property(_get_text_color, _set_text_color) + + def _get_border_width(self): + + return EMU_to_pixels(self._border_width) + + def _set_border_width(self, w): + + self._border_width = pixels_to_EMU(w) + print(self._border_width) + + border_width = property(_get_border_width, _set_border_width) + + def get_coordinates(self): + """ return shape coordinates in percentages (left, top, right, bottom) """ + + (x1, y1), (x2, y2) = self.coordinates + + drawing_width = pixels_to_EMU(self._chart.drawing.width) + drawing_height = pixels_to_EMU(self._chart.drawing.height) + plot_width = drawing_width * self._chart.width + plot_height = drawing_height * self._chart.height + + margin_left = self._chart._get_margin_left() * drawing_width + xunit = plot_width / self._chart.get_x_units() + + margin_top = self._chart._get_margin_top() * drawing_height + yunit = self._chart.get_y_units() + + x_start = (margin_left + (float(x1) * xunit)) / drawing_width + y_start = (margin_top + plot_height - (float(y1) * yunit)) / drawing_height + + x_end = (margin_left + (float(x2) * xunit)) / drawing_width + y_end = (margin_top + plot_height - (float(y2) * yunit)) / drawing_height + + def _norm_pct(pct): + """ force shapes to appear by truncating too large sizes """ + if pct>1: pct = 1 + elif pct<0: pct = 0 + return pct + + # allow user to specify y's in whatever order + # excel expect y_end to be lower + if y_end < y_start: + y_end, y_start = y_start, y_end + + return (_norm_pct(x_start), _norm_pct(y_start), + _norm_pct(x_end), _norm_pct(y_end)) + \ No newline at end of file diff --git a/tablib/packages/openpyxl3/reader/__init__.py b/tablib/packages/openpyxl3/reader/__init__.py index 9b0ee2f..76f10f8 100644 --- a/tablib/packages/openpyxl3/reader/__init__.py +++ b/tablib/packages/openpyxl3/reader/__init__.py @@ -26,8 +26,8 @@ """Imports for the openpyxl.reader namespace.""" # package imports -from ..reader import excel -from ..reader import strings -from ..reader import style -from ..reader import workbook -from ..reader import worksheet +from . import excel +from . import strings +from . import style +from . import workbook +from . import worksheet diff --git a/tablib/packages/openpyxl3/reader/excel.py b/tablib/packages/openpyxl3/reader/excel.py index 698d292..3fee695 100644 --- a/tablib/packages/openpyxl3/reader/excel.py +++ b/tablib/packages/openpyxl3/reader/excel.py @@ -33,12 +33,12 @@ from ..shared.exc import OpenModeError, InvalidFileException from ..shared.ooxml import ARC_SHARED_STRINGS, ARC_CORE, ARC_APP, \ ARC_WORKBOOK, PACKAGE_WORKSHEETS, ARC_STYLE from ..workbook import Workbook -from ..reader.strings import read_string_table -from ..reader.style import read_style_table -from ..reader.workbook import read_sheets_titles, read_named_ranges, \ +from .strings import read_string_table +from .style import read_style_table +from .workbook import read_sheets_titles, read_named_ranges, \ read_properties_core, get_sheet_ids -from ..reader.worksheet import read_worksheet -from ..reader.iter_worksheet import unpack_worksheet +from .worksheet import read_worksheet +from .iter_worksheet import unpack_worksheet def load_workbook(filename, use_iterators = False): """Open the given filename and return the workbook @@ -49,11 +49,11 @@ def load_workbook(filename, use_iterators = False): :param use_iterators: use lazy load for cells :type use_iterators: bool - :rtype: :class:`openpyxl.workbook.Workbook` + :rtype: :class:`..workbook.Workbook` .. note:: - When using lazy load, all worksheets will be :class:`openpyxl.reader.iter_worksheet.IterableWorksheet` + When using lazy load, all worksheets will be :class:`.iter_worksheet.IterableWorksheet` and the returned workbook will be read-only. """ diff --git a/tablib/packages/openpyxl3/reader/iter_worksheet.py b/tablib/packages/openpyxl3/reader/iter_worksheet.py index 7bc9ed4..670e6b1 100644 --- a/tablib/packages/openpyxl3/reader/iter_worksheet.py +++ b/tablib/packages/openpyxl3/reader/iter_worksheet.py @@ -1,343 +1,343 @@ -# file openpyxl/reader/iter_worksheet.py - -# Copyright (c) 2010 openpyxl -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# @license: http://www.opensource.org/licenses/mit-license.php -# @author: Eric Gazoni - -""" Iterators-based worksheet reader -*Still very raw* -""" - -from io import BytesIO as StringIO -import warnings -import operator -from functools import partial -from itertools import groupby -from ..worksheet import Worksheet -from ..cell import coordinate_from_string, get_column_letter, Cell -from ..reader.excel import get_sheet_ids -from ..reader.strings import read_string_table -from ..reader.style import read_style_table, NumberFormat -from ..shared.date_time import SharedDate -from ..reader.worksheet import read_dimension -from ..shared.ooxml import (MIN_COLUMN, MAX_COLUMN, PACKAGE_WORKSHEETS, - MAX_ROW, MIN_ROW, ARC_SHARED_STRINGS, ARC_APP, ARC_STYLE) -from xml.etree.cElementTree import iterparse -from zipfile import ZipFile -from .. import cell -import re -import tempfile -import zlib -import zipfile -import struct - -TYPE_NULL = Cell.TYPE_NULL -MISSING_VALUE = None - -RE_COORDINATE = re.compile('^([A-Z]+)([0-9]+)$') - -SHARED_DATE = SharedDate() - -_COL_CONVERSION_CACHE = dict((get_column_letter(i), i) for i in range(1, 18279)) -def column_index_from_string(str_col, _col_conversion_cache=_COL_CONVERSION_CACHE): - # we use a function argument to get indexed name lookup - return _col_conversion_cache[str_col] -del _COL_CONVERSION_CACHE - -RAW_ATTRIBUTES = ['row', 'column', 'coordinate', 'internal_value', 'data_type', 'style_id', 'number_format'] - -try: - from collections import namedtuple - BaseRawCell = namedtuple('RawCell', RAW_ATTRIBUTES) -except ImportError: - - warnings.warn("""Unable to import 'namedtuple' module, this may cause memory issues when using optimized reader. Please upgrade your Python installation to 2.6+""") - - class BaseRawCell(object): - - def __init__(self, *args): - assert len(args)==len(RAW_ATTRIBUTES) - - for attr, val in zip(RAW_ATTRIBUTES, args): - setattr(self, attr, val) - - def _replace(self, **kwargs): - - self.__dict__.update(kwargs) - - return self - - -class RawCell(BaseRawCell): - """Optimized version of the :class:`openpyxl.cell.Cell`, using named tuples. - - Useful attributes are: - - * row - * column - * coordinate - * internal_value - - You can also access if needed: - - * data_type - * number_format - - """ - - @property - def is_date(self): - res = (self.data_type == Cell.TYPE_NUMERIC - and self.number_format is not None - and ('d' in self.number_format - or 'm' in self.number_format - or 'y' in self.number_format - or 'h' in self.number_format - or 's' in self.number_format - )) - - return res - -def iter_rows(workbook_name, sheet_name, xml_source, range_string = '', row_offset = 0, column_offset = 0): - - archive = get_archive_file(workbook_name) - - source = xml_source - - if range_string: - min_col, min_row, max_col, max_row = get_range_boundaries(range_string, row_offset, column_offset) - else: - min_col, min_row, max_col, max_row = read_dimension(xml_source = source) - min_col = column_index_from_string(min_col) - max_col = column_index_from_string(max_col) + 1 - max_row += 6 - - try: - string_table = read_string_table(archive.read(ARC_SHARED_STRINGS)) - except KeyError: - string_table = {} - - style_table = read_style_table(archive.read(ARC_STYLE)) - - source.seek(0) - p = iterparse(source) - - return get_squared_range(p, min_col, min_row, max_col, max_row, string_table, style_table) - - -def get_rows(p, min_column = MIN_COLUMN, min_row = MIN_ROW, max_column = MAX_COLUMN, max_row = MAX_ROW): - - return groupby(get_cells(p, min_row, min_column, max_row, max_column), operator.attrgetter('row')) - -def get_cells(p, min_row, min_col, max_row, max_col, _re_coordinate=RE_COORDINATE): - - for _event, element in p: - - if element.tag == '{http://schemas.openxmlformats.org/spreadsheetml/2006/main}c': - coord = element.get('r') - column_str, row = _re_coordinate.match(coord).groups() - - row = int(row) - column = column_index_from_string(column_str) - - if min_col <= column <= max_col and min_row <= row <= max_row: - data_type = element.get('t', 'n') - style_id = element.get('s') - value = element.findtext('{http://schemas.openxmlformats.org/spreadsheetml/2006/main}v') - yield RawCell(row, column_str, coord, value, data_type, style_id, None) - - if element.tag == '{http://schemas.openxmlformats.org/spreadsheetml/2006/main}v': - continue - element.clear() - - - -def get_range_boundaries(range_string, row = 0, column = 0): - - if ':' in range_string: - min_range, max_range = range_string.split(':') - min_col, min_row = coordinate_from_string(min_range) - max_col, max_row = coordinate_from_string(max_range) - - min_col = column_index_from_string(min_col) + column - max_col = column_index_from_string(max_col) + column - min_row += row - max_row += row - - else: - min_col, min_row = coordinate_from_string(range_string) - min_col = column_index_from_string(min_col) - max_col = min_col + 1 - max_row = min_row - - return (min_col, min_row, max_col, max_row) - -def get_archive_file(archive_name): - - return ZipFile(archive_name, 'r') - -def get_xml_source(archive_file, sheet_name): - - return archive_file.read('%s/%s' % (PACKAGE_WORKSHEETS, sheet_name)) - -def get_missing_cells(row, columns): - - return dict([(column, RawCell(row, column, '%s%s' % (column, row), MISSING_VALUE, TYPE_NULL, None, None)) for column in columns]) - -def get_squared_range(p, min_col, min_row, max_col, max_row, string_table, style_table): - - expected_columns = [get_column_letter(ci) for ci in range(min_col, max_col)] - - current_row = min_row - for row, cells in get_rows(p, min_row = min_row, max_row = max_row, min_column = min_col, max_column = max_col): - full_row = [] - if current_row < row: - - for gap_row in range(current_row, row): - - dummy_cells = get_missing_cells(gap_row, expected_columns) - - yield tuple([dummy_cells[column] for column in expected_columns]) - - current_row = row - - temp_cells = list(cells) - - retrieved_columns = dict([(c.column, c) for c in temp_cells]) - - missing_columns = list(set(expected_columns) - set(retrieved_columns.keys())) - - replacement_columns = get_missing_cells(row, missing_columns) - - for column in expected_columns: - - if column in retrieved_columns: - cell = retrieved_columns[column] - - if cell.style_id is not None: - style = style_table[int(cell.style_id)] - cell = cell._replace(number_format = style.number_format.format_code) #pylint: disable-msg=W0212 - if cell.internal_value is not None: - if cell.data_type == Cell.TYPE_STRING: - cell = cell._replace(internal_value = string_table[int(cell.internal_value)]) #pylint: disable-msg=W0212 - elif cell.data_type == Cell.TYPE_BOOL: - cell = cell._replace(internal_value = cell.internal_value == 'True') - elif cell.is_date: - cell = cell._replace(internal_value = SHARED_DATE.from_julian(float(cell.internal_value))) - elif cell.data_type == Cell.TYPE_NUMERIC: - cell = cell._replace(internal_value = float(cell.internal_value)) - full_row.append(cell) - - else: - full_row.append(replacement_columns[column]) - - current_row = row + 1 - - yield tuple(full_row) - -#------------------------------------------------------------------------------ - -class IterableWorksheet(Worksheet): - - def __init__(self, parent_workbook, title, workbook_name, - sheet_codename, xml_source): - - Worksheet.__init__(self, parent_workbook, title) - self._workbook_name = workbook_name - self._sheet_codename = sheet_codename - self._xml_source = xml_source - - def iter_rows(self, range_string = '', row_offset = 0, column_offset = 0): - """ Returns a squared range based on the `range_string` parameter, - using generators. - - :param range_string: range of cells (e.g. 'A1:C4') - :type range_string: string - - :param row: row index of the cell (e.g. 4) - :type row: int - - :param column: column index of the cell (e.g. 3) - :type column: int - - :rtype: generator - - """ - - return iter_rows(workbook_name = self._workbook_name, - sheet_name = self._sheet_codename, - xml_source = self._xml_source, - range_string = range_string, - row_offset = row_offset, - column_offset = column_offset) - - def cell(self, *args, **kwargs): - - raise NotImplementedError("use 'iter_rows()' instead") - - def range(self, *args, **kwargs): - - raise NotImplementedError("use 'iter_rows()' instead") - -def unpack_worksheet(archive, filename): - - temp_file = tempfile.TemporaryFile(mode='r+', prefix='openpyxl.', suffix='.unpack.temp') - - zinfo = archive.getinfo(filename) - - if zinfo.compress_type == zipfile.ZIP_STORED: - decoder = None - elif zinfo.compress_type == zipfile.ZIP_DEFLATED: - decoder = zlib.decompressobj(-zlib.MAX_WBITS) - else: - raise zipfile.BadZipFile("Unrecognized compression method") - - archive.fp.seek(_get_file_offset(archive, zinfo)) - bytes_to_read = zinfo.compress_size - - while True: - buff = archive.fp.read(min(bytes_to_read, 102400)) - if not buff: - break - bytes_to_read -= len(buff) - if decoder: - buff = decoder.decompress(buff) - temp_file.write(buff) - - if decoder: - temp_file.write(decoder.decompress('Z')) - - return temp_file - -def _get_file_offset(archive, zinfo): - - try: - return zinfo.file_offset - except AttributeError: - # From http://stackoverflow.com/questions/3781261/how-to-simulate-zipfile-open-in-python-2-5 - - # Seek over the fixed size fields to the "file name length" field in - # the file header (26 bytes). Unpack this and the "extra field length" - # field ourselves as info.extra doesn't seem to be the correct length. - archive.fp.seek(zinfo.header_offset + 26) - file_name_len, extra_len = struct.unpack("TITLE') - - def test_write_xaxis(self): - - self.cw._write_axis(self.root, self.chart.x_axis, 'c:catAx') - eq_(get_xml(self.root), '') - - def test_write_yaxis(self): - - self.cw._write_axis(self.root, self.chart.y_axis, 'c:valAx') - eq_(get_xml(self.root), '') - - def test_write_series(self): - - self.cw._write_series(self.root) - eq_(get_xml(self.root), 'data!$A$1:$A$11General0123456789None') - - def test_write_legend(self): - - self.cw._write_legend(self.root) - eq_(get_xml(self.root), '') - - def test_write_print_settings(self): - - self.cw._write_print_settings(self.root) - eq_(get_xml(self.root), '') - - def test_write_chart(self): - - self.cw._write_chart(self.root) - eq_(get_xml(self.root), 'TITLEdata!$A$1:$A$11General0123456789None') - - -class TestScatterChartWriter(object): - - def setUp(self): - - wb = Workbook() - ws = wb.get_active_sheet() - ws.title = 'data' - for i in range(10): - ws.cell(row = i, column = 0).value = i - ws.cell(row = i, column = 1).value = i - self.scatterchart = ScatterChart() - self.scatterchart.add_serie(Serie(Reference(ws, (0, 0), (10, 0)), - xvalues = Reference(ws, (0, 1), (10, 1)))) - self.cw = ChartWriter(self.scatterchart) - self.root = Element('test') - - def test_write_xaxis(self): - - self.cw._write_axis(self.root, self.scatterchart.x_axis, 'c:valAx') - eq_(get_xml(self.root), '') - - - def test_write_yaxis(self): - - self.cw._write_axis(self.root, self.scatterchart.y_axis, 'c:valAx') - eq_(get_xml(self.root), '') - - def test_write_series(self): - - self.cw._write_series(self.root) - eq_(get_xml(self.root), 'data!$B$1:$B$11General0123456789Nonedata!$A$1:$A$11General0123456789None') - - def test_write_legend(self): - - self.cw._write_legend(self.root) - eq_(get_xml(self.root), '') - - def test_write_print_settings(self): - - self.cw._write_print_settings(self.root) - eq_(get_xml(self.root), '') - - def test_write_chart(self): - - self.cw._write_chart(self.root) - eq_(get_xml(self.root), 'data!$B$1:$B$11General0123456789Nonedata!$A$1:$A$11General0123456789None') +# file openpyxl/tests/test_chart.py + +# Copyright (c) 2010 openpyxl +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# @license: http://www.opensource.org/licenses/mit-license.php +# @author: Eric Gazoni + +from nose.tools import eq_ + +from openpyxl.tests.helper import get_xml +from openpyxl.shared.xmltools import Element +from openpyxl.writer.charts import ChartWriter +from openpyxl.workbook import Workbook +from openpyxl.chart import BarChart, ScatterChart, Serie, Reference +from openpyxl.style import Color + +class TestChartWriter(object): + + def setUp(self): + + wb = Workbook() + ws = wb.get_active_sheet() + ws.title = 'data' + for i in range(10): + ws.cell(row = i, column = 0).value = i + self.chart = BarChart() + self.chart.title = 'TITLE' + self.chart.add_serie(Serie(Reference(ws, (0, 0), (10, 0)))) + self.chart._series[-1].color = Color.GREEN + self.cw = ChartWriter(self.chart) + self.root = Element('test') + + def test_write_title(self): + self.cw._write_title(self.root) + eq_(get_xml(self.root), 'TITLE') + + def test_write_xaxis(self): + + self.cw._write_axis(self.root, self.chart.x_axis, 'c:catAx') + eq_(get_xml(self.root), '') + + def test_write_yaxis(self): + + self.cw._write_axis(self.root, self.chart.y_axis, 'c:valAx') + eq_(get_xml(self.root), '') + + def test_write_series(self): + + self.cw._write_series(self.root) + eq_(get_xml(self.root), 'data!$A$1:$A$11General0123456789None') + + def test_write_legend(self): + + self.cw._write_legend(self.root) + eq_(get_xml(self.root), '') + + def test_write_print_settings(self): + + self.cw._write_print_settings(self.root) + eq_(get_xml(self.root), '') + + def test_write_chart(self): + + self.cw._write_chart(self.root) + eq_(get_xml(self.root), 'TITLEdata!$A$1:$A$11General0123456789None') + + +class TestScatterChartWriter(object): + + def setUp(self): + + wb = Workbook() + ws = wb.get_active_sheet() + ws.title = 'data' + for i in range(10): + ws.cell(row = i, column = 0).value = i + ws.cell(row = i, column = 1).value = i + self.scatterchart = ScatterChart() + self.scatterchart.add_serie(Serie(Reference(ws, (0, 0), (10, 0)), + xvalues = Reference(ws, (0, 1), (10, 1)))) + self.cw = ChartWriter(self.scatterchart) + self.root = Element('test') + + def test_write_xaxis(self): + + self.cw._write_axis(self.root, self.scatterchart.x_axis, 'c:valAx') + eq_(get_xml(self.root), '') + + + def test_write_yaxis(self): + + self.cw._write_axis(self.root, self.scatterchart.y_axis, 'c:valAx') + eq_(get_xml(self.root), '') + + def test_write_series(self): + + self.cw._write_series(self.root) + eq_(get_xml(self.root), 'data!$B$1:$B$11General0123456789Nonedata!$A$1:$A$11General0123456789None') + + def test_write_legend(self): + + self.cw._write_legend(self.root) + eq_(get_xml(self.root), '') + + def test_write_print_settings(self): + + self.cw._write_print_settings(self.root) + eq_(get_xml(self.root), '') + + def test_write_chart(self): + + self.cw._write_chart(self.root) + eq_(get_xml(self.root), 'data!$B$1:$B$11General0123456789Nonedata!$A$1:$A$11General0123456789None') diff --git a/tablib/packages/openpyxl3/tests/test_iter.py b/tablib/packages/openpyxl3/tests/test_iter.py index b34ab95..899f8d7 100644 --- a/tablib/packages/openpyxl3/tests/test_iter.py +++ b/tablib/packages/openpyxl3/tests/test_iter.py @@ -1,112 +1,112 @@ -# file openpyxl/tests/test_iter.py - -# Copyright (c) 2010 openpyxl -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# @license: http://www.opensource.org/licenses/mit-license.php -# @author: Eric Gazoni - -from nose.tools import eq_, raises, assert_raises -import os.path as osp -from openpyxl.tests.helper import DATADIR -from openpyxl.reader.iter_worksheet import get_range_boundaries -from openpyxl.reader.excel import load_workbook -import datetime - -class TestWorksheet(object): - - workbook_name = osp.join(DATADIR, 'genuine', 'empty.xlsx') - -class TestText(TestWorksheet): - sheet_name = 'Sheet1 - Text' - - expected = [['This is cell A1 in Sheet 1', None, None, None, None, None, None], - [None, None, None, None, None, None, None], - [None, None, None, None, None, None, None], - [None, None, None, None, None, None, None], - [None, None, None, None, None, None, 'This is cell G5'], ] - - def test_read_fast_integrated(self): - - wb = load_workbook(filename = self.workbook_name, use_iterators = True) - ws = wb.get_sheet_by_name(name = self.sheet_name) - - for row, expected_row in zip(ws.iter_rows(), self.expected): - - row_values = [x.internal_value for x in row] - - eq_(row_values, expected_row) - - - def test_get_boundaries_range(self): - - eq_(get_range_boundaries('C1:C4'), (3, 1, 3, 4)) - - def test_get_boundaries_one(self): - - - eq_(get_range_boundaries('C1'), (3, 1, 4, 1)) - - def test_read_single_cell_range(self): - - wb = load_workbook(filename = self.workbook_name, use_iterators = True) - ws = wb.get_sheet_by_name(name = self.sheet_name) - - eq_('This is cell A1 in Sheet 1', list(ws.iter_rows('A1'))[0][0].internal_value) - -class TestIntegers(TestWorksheet): - - sheet_name = 'Sheet2 - Numbers' - - expected = [[x + 1] for x in range(30)] - - query_range = 'D1:E30' - - def test_read_fast_integrated(self): - - wb = load_workbook(filename = self.workbook_name, use_iterators = True) - ws = wb.get_sheet_by_name(name = self.sheet_name) - - for row, expected_row in zip(ws.iter_rows(self.query_range), self.expected): - - row_values = [x.internal_value for x in row] - - eq_(row_values, expected_row) - -class TestFloats(TestWorksheet): - - sheet_name = 'Sheet2 - Numbers' - query_range = 'K1:L30' - expected = expected = [[(x + 1) / 100.0] for x in range(30)] - -class TestDates(TestWorksheet): - - sheet_name = 'Sheet4 - Dates' - - def test_read_single_cell_date(self): - - wb = load_workbook(filename = self.workbook_name, use_iterators = True) - ws = wb.get_sheet_by_name(name = self.sheet_name) - - eq_(datetime.datetime(1973, 5, 20), list(ws.iter_rows('A1'))[0][0].internal_value) - eq_(datetime.datetime(1973, 5, 20, 9, 15, 2), list(ws.iter_rows('C1'))[0][0].internal_value) - - - +# file openpyxl/tests/test_iter.py + +# Copyright (c) 2010 openpyxl +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# @license: http://www.opensource.org/licenses/mit-license.php +# @author: Eric Gazoni + +from nose.tools import eq_, raises, assert_raises +import os.path as osp +from openpyxl.tests.helper import DATADIR +from openpyxl.reader.iter_worksheet import get_range_boundaries +from openpyxl.reader.excel import load_workbook +import datetime + +class TestWorksheet(object): + + workbook_name = osp.join(DATADIR, 'genuine', 'empty.xlsx') + +class TestText(TestWorksheet): + sheet_name = 'Sheet1 - Text' + + expected = [['This is cell A1 in Sheet 1', None, None, None, None, None, None], + [None, None, None, None, None, None, None], + [None, None, None, None, None, None, None], + [None, None, None, None, None, None, None], + [None, None, None, None, None, None, 'This is cell G5'], ] + + def test_read_fast_integrated(self): + + wb = load_workbook(filename = self.workbook_name, use_iterators = True) + ws = wb.get_sheet_by_name(name = self.sheet_name) + + for row, expected_row in zip(ws.iter_rows(), self.expected): + + row_values = [x.internal_value for x in row] + + eq_(row_values, expected_row) + + + def test_get_boundaries_range(self): + + eq_(get_range_boundaries('C1:C4'), (3, 1, 3, 4)) + + def test_get_boundaries_one(self): + + + eq_(get_range_boundaries('C1'), (3, 1, 4, 1)) + + def test_read_single_cell_range(self): + + wb = load_workbook(filename = self.workbook_name, use_iterators = True) + ws = wb.get_sheet_by_name(name = self.sheet_name) + + eq_('This is cell A1 in Sheet 1', list(ws.iter_rows('A1'))[0][0].internal_value) + +class TestIntegers(TestWorksheet): + + sheet_name = 'Sheet2 - Numbers' + + expected = [[x + 1] for x in range(30)] + + query_range = 'D1:E30' + + def test_read_fast_integrated(self): + + wb = load_workbook(filename = self.workbook_name, use_iterators = True) + ws = wb.get_sheet_by_name(name = self.sheet_name) + + for row, expected_row in zip(ws.iter_rows(self.query_range), self.expected): + + row_values = [x.internal_value for x in row] + + eq_(row_values, expected_row) + +class TestFloats(TestWorksheet): + + sheet_name = 'Sheet2 - Numbers' + query_range = 'K1:L30' + expected = expected = [[(x + 1) / 100.0] for x in range(30)] + +class TestDates(TestWorksheet): + + sheet_name = 'Sheet4 - Dates' + + def test_read_single_cell_date(self): + + wb = load_workbook(filename = self.workbook_name, use_iterators = True) + ws = wb.get_sheet_by_name(name = self.sheet_name) + + eq_(datetime.datetime(1973, 5, 20), list(ws.iter_rows('A1'))[0][0].internal_value) + eq_(datetime.datetime(1973, 5, 20, 9, 15, 2), list(ws.iter_rows('C1'))[0][0].internal_value) + + + diff --git a/tablib/packages/openpyxl3/tests/test_meta.py b/tablib/packages/openpyxl3/tests/test_meta.py index 3aefdcf..06051ad 100644 --- a/tablib/packages/openpyxl3/tests/test_meta.py +++ b/tablib/packages/openpyxl3/tests/test_meta.py @@ -24,7 +24,7 @@ # @author: Eric Gazoni # Python stdlib imports -from __future__ import with_statement + import os.path # package imports diff --git a/tablib/packages/openpyxl3/tests/test_named_range.py b/tablib/packages/openpyxl3/tests/test_named_range.py index a56ed86..c6d9d58 100644 --- a/tablib/packages/openpyxl3/tests/test_named_range.py +++ b/tablib/packages/openpyxl3/tests/test_named_range.py @@ -24,7 +24,7 @@ # @author: Eric Gazoni # Python stdlib imports -from __future__ import with_statement + import os.path # 3rd-party imports diff --git a/tablib/packages/openpyxl3/tests/test_number_format.py b/tablib/packages/openpyxl3/tests/test_number_format.py index 2f5c9da..54b0b88 100644 --- a/tablib/packages/openpyxl3/tests/test_number_format.py +++ b/tablib/packages/openpyxl3/tests/test_number_format.py @@ -24,7 +24,7 @@ # @author: Eric Gazoni # Python stdlib imports -from __future__ import with_statement + from datetime import datetime, date # 3rd party imports @@ -57,7 +57,7 @@ class TestNumberFormat(object): date_pairs= ( (40167, datetime(2009, 12, 20)), - (21980, datetime(1960, 03, 05)), + (21980, datetime(1960, 0o3, 0o5)), ) for count, dt in date_pairs: @@ -128,7 +128,7 @@ class TestNumberFormat(object): def check_bad_date(year, month, day): assert_raises(ValueError, self.sd.to_julian, year, month, day) - bad_dates = ((1776, 07, 04), (1899, 12, 31), ) + bad_dates = ((1776, 0o7, 0o4), (1899, 12, 31), ) for year, month, day in bad_dates: yield check_bad_date, year, month, day diff --git a/tablib/packages/openpyxl3/tests/test_props.py b/tablib/packages/openpyxl3/tests/test_props.py index 1c5adb64a9f03e67c98e58fbe7fb1c606cce0ec4..07d447c9234f743e7a1c02871547bf57bcdaf170 100644 GIT binary patch literal 4494 zcmcgv?QYx175%TLxJZ6TUeI(Lr)X;+Kxm1IiRud!y{5h=-%oU~|B!?w)f{XF;HbH{IKs#2NHKd#K|{7;RyG?SSiRfxQJe#$P4C{1a9 z$Awl!=@!oo2(?x5tmS-Rs5L#K_wO#>ZB_6V-y@-yvMi;_NtUz_T1=j4u9Mt|)S;Oc z@G+z5BGGf-+cQ?}wjXqv4Uo9*jN zE@kC|)hz-g%pv|&i99%3hn4_z#-G9_SF9$PEEf)?l8sMR29hNoPDRdI$mK$5Dn-Vj z!G=WiHsf7{R*L-qBg9ZaRr1Mtp_VVRksQ-(rE|CiIFLydptD|o5mUn_9REyZnObv# zQ>Lr zdd6{1rAae6A-UuZD;tfO#*BQGg(bJmDg7jiE{MXRpMp``@w+__O|X$nK`KTr(a6>S z)z6LUS%C)=vtWl;I;A4f=6UPP`pQ))T%%N0);7eiG0PXp^f8&&mdlO5nr>Z7x9&n@ z7_M5e<3(O42vM{C$bK%9M-iK4kxC89$wZQGpZ?aM>I>v3w28&9t0XI9&O64C8*t=- zOD&RAXm_pj<3y>)+AAMh%7+#35tKEc+S#}7K`+9Tv5^LZ>(E@7IA1L%LdR+rGb)Gq zt+g~KoY~`Vc{>tFisB#-kdGFrtJKpntCR4;cI=Ht+}rKAJq-N=ox`L%)fyRL)ot%s}mCRmAp9Ynqjit;>Wb zcP{dk%!Msdo}lYKQq^GYFG}XEZ38qb$)-b1u`JB9`;?VW&9fKQ5-$=lSM5k(5u`);<6#HKqDH@|RegRI)B z%eTvvFC!2=X}Ie1oiIkP#R~2e@`)^5kO3_;8t4&Q6Exr^v^ueJ&JGda>uPcWx-=Cd`s`mF%`4VbY`4WmBVC0IG zw=K29^~DhWr>J5&b`e=i)il@OzO;T4+I_Wsil}@1OLNRTaY^TxohQTHYY*PzU|{K@ z+@4+GtgG~Lg-UD>Kj5$fN-mo}1A)_H*q2Wt{qJT`iy7{z`Sisk?ijC5=at#yRunu_ zO>omW5-{?7LyRsMX|HGau4!+}tz(C0xYW`D7s5>JID#GX3|HWzG8+lk&c^FKQB^Wt zT4)Z&ZNF%zYi-By`vu>UPmRx)W~ADTLmLyVlc{+CdF($&a)VPxERku`IkM2~fesTb zzlyZG%I$5O_4|o_6t;aL{3B6T|6kaiVBcG|Iaoo5BVqSawWpBziKS&VYPfgfVOfHg zTBUp(c-GSLpv>^X%Os zz}I#0xX*C4cy$-mcaSFY&#CoO5%cjTt(U^d1^J!*vb*BcR<^}Hx*70A<*?+omG?IQ z>fVg}aTMdu8aB7t@8k{_0V|A$eg9_Ic{n9s@jt|l7XULk7QhvL-o4vFy>nJCfRoyP zz}mnT!N=8}@{S8$2f*cwcm7_#5w^Af)NSwz$5~%?mc>(nOOL?xQj-ziaNKcgZ~4Qz sc)e=i%)_FsC%~h=eeJdAda~K$BDQn(Z@u{jT@O!jiUXq?JM-B&c8zaW>7i72?SY4Pe$LCA(EWaKAJkL+y_Zc9MDq`=G?MVXHrB_d>MJb*@NV(SM}z zoAg99pR`bMF8q66^v3B*=O_AH2;a3%Fe`+Qy|Z*I?h4@_rz7pc;c5C>D?{6LIfj~_ z=){rMeh>uvx58G~8O|f=Sa_YnNLX*Rhn8GZK)UYGhI2O(4e*?o9C3Q6`JK^$G8~=S z2>&DTaG^ElvCs}HA0;1JhTg6AorACfl6JL@v_*QD-ZW@Dls2<8r-C|?rJO%Fcm6or zJXwg(3&T7zFDOi3SQmSpOnCu2m`;TEvt$2wuT8}V^0Zt#P1g9kP^KQ?I`=VS_bVmc05ZkNZRG8Q#fFQ-~_J}$I| z?z4^CbO^6uW0%MM$n{Y7DzG`sowy!J#?RRXdEAOa$uO4wU0S?5@ZdjiKQbM-tbY;T z*e+l~|3g6`LcPJ z>!cdR^;1|9&%G3eW5ZMRIhUFh=PV$bwsLFY9e9K110oKrH{xkn>+gdBqzGi#ryR@A)wYsU5hk{^-{fB0scltd@uLbv3V^QKb5L{pL z_gVpWVRL4`7kpp1@UfTa4@Tpquz__?^js6$X;(Wtf`u-yoZ8UJTh00XN^37lnth#w zHt@Up8h3$)e~1bYsLp1v!0uoXP+=o6B; z#@0<2*x_KR%R;>DiTZn^@k%Gr5->Z`A`&CT3;lB4A@z>UvSfX;A(~$oPrGJ|P5s{0 zA3TTMu%2r=Y=||Qdc;4lMnHy~cnjLu(9X6nF>}8`0(64i*u@vHE4p@%sZz!p(KJxl zgIRbBn%*-BTw~#}P6v#^jnl-=Rer+LL+@>I<5@vR{7wWx|qkxhkSa<4&*7IsE1=a!zy*>aRUqekLUQ6#tt3O zx&EBP=gK{FSmgV$(SE5BehT@-QTkcyWcKKo_Eqm3`dSd=uv5c-tQplcau~IN{>H1w zVLH?dI`Dm_*{iOkd-{`oh4A`Q(dh|R%+pmPLtQ^;;P)%bwstn{yjmC z^tsfm4qs^ZM@bU40Pjiqpl|w)I&2+xcuw@m(1<>{CywbZyav{>;N9zr&UKC3iYkv- z@_C+LiT(#+I22CoPqiK!B>foO-gV2~pCm=m_#8=MG=Q!SHU21Xp)yW13ws|*VmuQ5 z`L0@VR!V&BNF0H)rx?P=KUl9Y(%6(Wp!0pfdGSumDFcHR+W61s=@riO;U0os=wHyq z#Li+ZB)pb%J9*dIsx>=aHT0wq$@#182u9)Dd>#pFG#I+xSG^ z9dVcCY4V1zbL+h*dv`dgXYi15u^dEYNBEqZd08KBGC#{(fJlQ|ZZvn&d>UZ9*VAe*P`g{nx|aK#`AolnmY@8bkdt@?JQ<9xh{@`_;_Ih)@qb zd(X6@9E1hv6Ibjzx<%?J{ZV_KiPur8x8DrACfOnhdEF*^anJO(L3&f()xz(ZWAqYr z&-a+A;^-ND`k?#Nw0TiNZq8mq4>Z5B&BJk@xDE=`mtP*?^R*e;CAtTqv@!LEjgl_^ zDd3Ity=0~;hrcxU2UeHz{-)r$kMU;8nZ-PGbR+i85IPsS?^B_+lCyH?j7arr>ixg#kX*_e_COuHzt$ee_h&O;8@@%ifuO)UE-(8p zG;S(8FN;6(>+#IJYndBB^yGd6SSxP=Pc*i5oo$jeZvZaIGPHkfd1$q~i}(x<+9=oS zrPKHl58!Ru?|5xgzT|zd+u{L{1!BBkAD89Ib(eme4vdP4g`-}Ek5~J+WokrSpPq$- z+b@YV?=u%g+MRB`Zo8-${8yEi()KJ0d^Hy7rgJ^}*PW?rV_EMCnc?#P!<$^9U+hc& E1ogd)IRF3v diff --git a/tablib/packages/openpyxl3/tests/test_read.py b/tablib/packages/openpyxl3/tests/test_read.py index eb6ab07..1240164 100644 --- a/tablib/packages/openpyxl3/tests/test_read.py +++ b/tablib/packages/openpyxl3/tests/test_read.py @@ -24,7 +24,7 @@ # @author: Eric Gazoni # Python stdlib imports -from __future__ import with_statement + import os.path # 3rd party imports diff --git a/tablib/packages/openpyxl3/tests/test_strings.py b/tablib/packages/openpyxl3/tests/test_strings.py index bf3cc57..7dbf17a 100644 --- a/tablib/packages/openpyxl3/tests/test_strings.py +++ b/tablib/packages/openpyxl3/tests/test_strings.py @@ -24,7 +24,7 @@ # @author: Eric Gazoni # Python stdlib imports -from __future__ import with_statement + import os.path # 3rd party imports diff --git a/tablib/packages/openpyxl3/tests/test_style.py b/tablib/packages/openpyxl3/tests/test_style.py index a11ea43..4c8962c 100644 --- a/tablib/packages/openpyxl3/tests/test_style.py +++ b/tablib/packages/openpyxl3/tests/test_style.py @@ -24,7 +24,7 @@ # @author: Eric Gazoni # Python stdlib imports -from __future__ import with_statement + import os.path import datetime diff --git a/tablib/packages/openpyxl3/tests/test_write.py b/tablib/packages/openpyxl3/tests/test_write.py index 51e3c15..74363cb 100644 --- a/tablib/packages/openpyxl3/tests/test_write.py +++ b/tablib/packages/openpyxl3/tests/test_write.py @@ -24,8 +24,8 @@ # @author: Eric Gazoni # Python stdlib imports -from __future__ import with_statement -from io import BytesIO as StringIO + +from io import StringIO import os.path # 3rd party imports diff --git a/tablib/packages/openpyxl3/worksheet.py b/tablib/packages/openpyxl3/worksheet.py index 2eb6499..6cdda6b 100644 --- a/tablib/packages/openpyxl3/worksheet.py +++ b/tablib/packages/openpyxl3/worksheet.py @@ -187,7 +187,7 @@ class Worksheet(object): """Represents a worksheet. Do not create worksheets yourself, - use :func:`openpyxl.workbook.Workbook.create_sheet` instead + use :func:`.workbook.Workbook.create_sheet` instead """ BREAK_NONE = 0 @@ -241,7 +241,7 @@ class Worksheet(object): def get_cell_collection(self): """Return an unordered list of the cells in this worksheet.""" - return self._cells.values() + return list(self._cells.values()) def _set_title(self, value): """Set a sheet title, ensuring it is valid.""" @@ -325,7 +325,7 @@ class Worksheet(object): :raise: InsufficientCoordinatesException when coordinate or (row and column) are not given - :rtype: :class:`openpyxl.cell.Cell` + :rtype: :class:`.cell.Cell` """ if not coordinate: @@ -390,7 +390,7 @@ class Worksheet(object): :param column: number of columns to offset :type column: int - :rtype: tuples of tuples of :class:`openpyxl.cell.Cell` + :rtype: tuples of tuples of :class:`.cell.Cell` """ if ':' in range_string: diff --git a/tablib/packages/openpyxl3/writer/charts.py b/tablib/packages/openpyxl3/writer/charts.py index c0dfadb..420328d 100644 --- a/tablib/packages/openpyxl3/writer/charts.py +++ b/tablib/packages/openpyxl3/writer/charts.py @@ -1,261 +1,262 @@ -# coding=UTF-8 -''' -Copyright (c) 2010 openpyxl - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -@license: http://www.opensource.org/licenses/mit-license.php -@author: Eric Gazoni -''' - -from ..shared.xmltools import Element, SubElement, get_document_content -from ..chart import Chart, ErrorBar - -class ChartWriter(object): - - def __init__(self, chart): - self.chart = chart - - def write(self): - """ write a chart """ - - root = Element('c:chartSpace', - {'xmlns:c':"http://schemas.openxmlformats.org/drawingml/2006/chart", - 'xmlns:a':"http://schemas.openxmlformats.org/drawingml/2006/main", - 'xmlns:r':"http://schemas.openxmlformats.org/officeDocument/2006/relationships"}) - - SubElement(root, 'c:lang', {'val':self.chart.lang}) - self._write_chart(root) - self._write_print_settings(root) - self._write_shapes(root) - - return get_document_content(root) - - def _write_chart(self, root): - - chart = self.chart - - ch = SubElement(root, 'c:chart') - self._write_title(ch) - plot_area = SubElement(ch, 'c:plotArea') - layout = SubElement(plot_area, 'c:layout') - mlayout = SubElement(layout, 'c:manualLayout') - SubElement(mlayout, 'c:layoutTarget', {'val':'inner'}) - SubElement(mlayout, 'c:xMode', {'val':'edge'}) - SubElement(mlayout, 'c:yMode', {'val':'edge'}) - SubElement(mlayout, 'c:x', {'val':str(chart._get_margin_left())}) - SubElement(mlayout, 'c:y', {'val':str(chart._get_margin_top())}) - SubElement(mlayout, 'c:w', {'val':str(chart.width)}) - SubElement(mlayout, 'c:h', {'val':str(chart.height)}) - - if chart.type == Chart.SCATTER_CHART: - subchart = SubElement(plot_area, 'c:scatterChart') - SubElement(subchart, 'c:scatterStyle', {'val':str('lineMarker')}) - else: - if chart.type == Chart.BAR_CHART: - subchart = SubElement(plot_area, 'c:barChart') - SubElement(subchart, 'c:barDir', {'val':'col'}) - else: - subchart = SubElement(plot_area, 'c:lineChart') - - SubElement(subchart, 'c:grouping', {'val':chart.grouping}) - - self._write_series(subchart) - - SubElement(subchart, 'c:marker', {'val':'1'}) - SubElement(subchart, 'c:axId', {'val':str(chart.x_axis.id)}) - SubElement(subchart, 'c:axId', {'val':str(chart.y_axis.id)}) - - if chart.type == Chart.SCATTER_CHART: - self._write_axis(plot_area, chart.x_axis, 'c:valAx') - else: - self._write_axis(plot_area, chart.x_axis, 'c:catAx') - self._write_axis(plot_area, chart.y_axis, 'c:valAx') - - self._write_legend(ch) - - SubElement(ch, 'c:plotVisOnly', {'val':'1'}) - - def _write_title(self, chart): - if self.chart.title != '': - title = SubElement(chart, 'c:title') - tx = SubElement(title, 'c:tx') - rich = SubElement(tx, 'c:rich') - SubElement(rich, 'a:bodyPr') - SubElement(rich, 'a:lstStyle') - p = SubElement(rich, 'a:p') - pPr = SubElement(p, 'a:pPr') - SubElement(pPr, 'a:defRPr') - r = SubElement(p, 'a:r') - SubElement(r, 'a:rPr', {'lang':self.chart.lang}) - t = SubElement(r, 'a:t').text = self.chart.title - SubElement(title, 'c:layout') - - def _write_axis(self, plot_area, axis, label): - - ax = SubElement(plot_area, label) - SubElement(ax, 'c:axId', {'val':str(axis.id)}) - - scaling = SubElement(ax, 'c:scaling') - SubElement(scaling, 'c:orientation', {'val':axis.orientation}) - if label == 'c:valAx': - SubElement(scaling, 'c:max', {'val':str(axis.max)}) - SubElement(scaling, 'c:min', {'val':str(axis.min)}) - - SubElement(ax, 'c:axPos', {'val':axis.position}) - if label == 'c:valAx': - SubElement(ax, 'c:majorGridlines') - SubElement(ax, 'c:numFmt', {'formatCode':"General", 'sourceLinked':'1'}) - SubElement(ax, 'c:tickLblPos', {'val':axis.tick_label_position}) - SubElement(ax, 'c:crossAx', {'val':str(axis.cross)}) - SubElement(ax, 'c:crosses', {'val':axis.crosses}) - if axis.auto: - SubElement(ax, 'c:auto', {'val':'1'}) - if axis.label_align: - SubElement(ax, 'c:lblAlgn', {'val':axis.label_align}) - if axis.label_offset: - SubElement(ax, 'c:lblOffset', {'val':str(axis.label_offset)}) - if label == 'c:valAx': - if self.chart.type == Chart.SCATTER_CHART: - SubElement(ax, 'c:crossBetween', {'val':'midCat'}) - else: - SubElement(ax, 'c:crossBetween', {'val':'between'}) - SubElement(ax, 'c:majorUnit', {'val':str(axis.unit)}) - - def _write_series(self, subchart): - - for i, serie in enumerate(self.chart._series): - ser = SubElement(subchart, 'c:ser') - SubElement(ser, 'c:idx', {'val':str(i)}) - SubElement(ser, 'c:order', {'val':str(i)}) - - if serie.legend: - tx = SubElement(ser, 'c:tx') - self._write_serial(tx, serie.legend) - - if serie.color: - sppr = SubElement(ser, 'c:spPr') - if self.chart.type == Chart.BAR_CHART: - # fill color - fillc = SubElement(sppr, 'a:solidFill') - SubElement(fillc, 'a:srgbClr', {'val':serie.color}) - # edge color - ln = SubElement(sppr, 'a:ln') - fill = SubElement(ln, 'a:solidFill') - SubElement(fill, 'a:srgbClr', {'val':serie.color}) - - if serie.error_bar: - self._write_error_bar(ser, serie) - - marker = SubElement(ser, 'c:marker') - SubElement(marker, 'c:symbol', {'val':serie.marker}) - - if serie.labels: - cat = SubElement(ser, 'c:cat') - self._write_serial(cat, serie.labels) - - if self.chart.type == Chart.SCATTER_CHART: - if serie.xvalues: - xval = SubElement(ser, 'c:xVal') - self._write_serial(xval, serie.xvalues) - - yval = SubElement(ser, 'c:yVal') - self._write_serial(yval, serie.values) - else: - val = SubElement(ser, 'c:val') - self._write_serial(val, serie.values) - - def _write_serial(self, node, serie, literal=False): - - cache = serie._get_cache() - if isinstance(cache[0], str): - typ = 'str' - else: - typ = 'num' - - if not literal: - if typ == 'num': - ref = SubElement(node, 'c:numRef') - else: - ref = SubElement(node, 'c:strRef') - SubElement(ref, 'c:f').text = serie._get_ref() - if typ == 'num': - data = SubElement(ref, 'c:numCache') - else: - data = SubElement(ref, 'c:strCache') - else: - data = SubElement(node, 'c:numLit') - - if typ == 'num': - SubElement(data, 'c:formatCode').text = 'General' - if literal: - values = (1,) - else: - values = cache - - SubElement(data, 'c:ptCount', {'val':str(len(values))}) - for j, val in enumerate(values): - point = SubElement(data, 'c:pt', {'idx':str(j)}) - SubElement(point, 'c:v').text = str(val) - - def _write_error_bar(self, node, serie): - - flag = {ErrorBar.PLUS_MINUS:'both', - ErrorBar.PLUS:'plus', - ErrorBar.MINUS:'minus'} - - eb = SubElement(node, 'c:errBars') - SubElement(eb, 'c:errBarType', {'val':flag[serie.error_bar.type]}) - SubElement(eb, 'c:errValType', {'val':'cust'}) - - plus = SubElement(eb, 'c:plus') - self._write_serial(plus, serie.error_bar.values, - literal=(serie.error_bar.type==ErrorBar.MINUS)) - - minus = SubElement(eb, 'c:minus') - self._write_serial(minus, serie.error_bar.values, - literal=(serie.error_bar.type==ErrorBar.PLUS)) - - def _write_legend(self, chart): - - legend = SubElement(chart, 'c:legend') - SubElement(legend, 'c:legendPos', {'val':self.chart.legend.position}) - SubElement(legend, 'c:layout') - - def _write_print_settings(self, root): - - settings = SubElement(root, 'c:printSettings') - SubElement(settings, 'c:headerFooter') - margins = dict([(k, str(v)) for (k,v) in self.chart.print_margins.items()]) - SubElement(settings, 'c:pageMargins', margins) - SubElement(settings, 'c:pageSetup') - - def _write_shapes(self, root): - - if self.chart._shapes: - SubElement(root, 'c:userShapes', {'r:id':'rId1'}) - - def write_rels(self, drawing_id): - - root = Element('Relationships', {'xmlns' : 'http://schemas.openxmlformats.org/package/2006/relationships'}) - attrs = {'Id' : 'rId1', - 'Type' : 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartUserShapes', - 'Target' : '../drawings/drawing%s.xml' % drawing_id } - SubElement(root, 'Relationship', attrs) - return get_document_content(root) +# coding=UTF-8 +''' +Copyright (c) 2010 openpyxl + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +@license: http://www.opensource.org/licenses/mit-license.php +@author: Eric Gazoni +''' + +from ..shared.xmltools import Element, SubElement, get_document_content +from ..chart import Chart, ErrorBar + + +class ChartWriter(object): + + def __init__(self, chart): + self.chart = chart + + def write(self): + """ write a chart """ + + root = Element('c:chartSpace', + {'xmlns:c':"http://schemas.openxmlformats.org/drawingml/2006/chart", + 'xmlns:a':"http://schemas.openxmlformats.org/drawingml/2006/main", + 'xmlns:r':"http://schemas.openxmlformats.org/officeDocument/2006/relationships"}) + + SubElement(root, 'c:lang', {'val':self.chart.lang}) + self._write_chart(root) + self._write_print_settings(root) + self._write_shapes(root) + + return get_document_content(root) + + def _write_chart(self, root): + + chart = self.chart + + ch = SubElement(root, 'c:chart') + self._write_title(ch) + plot_area = SubElement(ch, 'c:plotArea') + layout = SubElement(plot_area, 'c:layout') + mlayout = SubElement(layout, 'c:manualLayout') + SubElement(mlayout, 'c:layoutTarget', {'val':'inner'}) + SubElement(mlayout, 'c:xMode', {'val':'edge'}) + SubElement(mlayout, 'c:yMode', {'val':'edge'}) + SubElement(mlayout, 'c:x', {'val':str(chart._get_margin_left())}) + SubElement(mlayout, 'c:y', {'val':str(chart._get_margin_top())}) + SubElement(mlayout, 'c:w', {'val':str(chart.width)}) + SubElement(mlayout, 'c:h', {'val':str(chart.height)}) + + if chart.type == Chart.SCATTER_CHART: + subchart = SubElement(plot_area, 'c:scatterChart') + SubElement(subchart, 'c:scatterStyle', {'val':str('lineMarker')}) + else: + if chart.type == Chart.BAR_CHART: + subchart = SubElement(plot_area, 'c:barChart') + SubElement(subchart, 'c:barDir', {'val':'col'}) + else: + subchart = SubElement(plot_area, 'c:lineChart') + + SubElement(subchart, 'c:grouping', {'val':chart.grouping}) + + self._write_series(subchart) + + SubElement(subchart, 'c:marker', {'val':'1'}) + SubElement(subchart, 'c:axId', {'val':str(chart.x_axis.id)}) + SubElement(subchart, 'c:axId', {'val':str(chart.y_axis.id)}) + + if chart.type == Chart.SCATTER_CHART: + self._write_axis(plot_area, chart.x_axis, 'c:valAx') + else: + self._write_axis(plot_area, chart.x_axis, 'c:catAx') + self._write_axis(plot_area, chart.y_axis, 'c:valAx') + + self._write_legend(ch) + + SubElement(ch, 'c:plotVisOnly', {'val':'1'}) + + def _write_title(self, chart): + if self.chart.title != '': + title = SubElement(chart, 'c:title') + tx = SubElement(title, 'c:tx') + rich = SubElement(tx, 'c:rich') + SubElement(rich, 'a:bodyPr') + SubElement(rich, 'a:lstStyle') + p = SubElement(rich, 'a:p') + pPr = SubElement(p, 'a:pPr') + SubElement(pPr, 'a:defRPr') + r = SubElement(p, 'a:r') + SubElement(r, 'a:rPr', {'lang':self.chart.lang}) + t = SubElement(r, 'a:t').text = self.chart.title + SubElement(title, 'c:layout') + + def _write_axis(self, plot_area, axis, label): + + ax = SubElement(plot_area, label) + SubElement(ax, 'c:axId', {'val':str(axis.id)}) + + scaling = SubElement(ax, 'c:scaling') + SubElement(scaling, 'c:orientation', {'val':axis.orientation}) + if label == 'c:valAx': + SubElement(scaling, 'c:max', {'val':str(axis.max)}) + SubElement(scaling, 'c:min', {'val':str(axis.min)}) + + SubElement(ax, 'c:axPos', {'val':axis.position}) + if label == 'c:valAx': + SubElement(ax, 'c:majorGridlines') + SubElement(ax, 'c:numFmt', {'formatCode':"General", 'sourceLinked':'1'}) + SubElement(ax, 'c:tickLblPos', {'val':axis.tick_label_position}) + SubElement(ax, 'c:crossAx', {'val':str(axis.cross)}) + SubElement(ax, 'c:crosses', {'val':axis.crosses}) + if axis.auto: + SubElement(ax, 'c:auto', {'val':'1'}) + if axis.label_align: + SubElement(ax, 'c:lblAlgn', {'val':axis.label_align}) + if axis.label_offset: + SubElement(ax, 'c:lblOffset', {'val':str(axis.label_offset)}) + if label == 'c:valAx': + if self.chart.type == Chart.SCATTER_CHART: + SubElement(ax, 'c:crossBetween', {'val':'midCat'}) + else: + SubElement(ax, 'c:crossBetween', {'val':'between'}) + SubElement(ax, 'c:majorUnit', {'val':str(axis.unit)}) + + def _write_series(self, subchart): + + for i, serie in enumerate(self.chart._series): + ser = SubElement(subchart, 'c:ser') + SubElement(ser, 'c:idx', {'val':str(i)}) + SubElement(ser, 'c:order', {'val':str(i)}) + + if serie.legend: + tx = SubElement(ser, 'c:tx') + self._write_serial(tx, serie.legend) + + if serie.color: + sppr = SubElement(ser, 'c:spPr') + if self.chart.type == Chart.BAR_CHART: + # fill color + fillc = SubElement(sppr, 'a:solidFill') + SubElement(fillc, 'a:srgbClr', {'val':serie.color}) + # edge color + ln = SubElement(sppr, 'a:ln') + fill = SubElement(ln, 'a:solidFill') + SubElement(fill, 'a:srgbClr', {'val':serie.color}) + + if serie.error_bar: + self._write_error_bar(ser, serie) + + marker = SubElement(ser, 'c:marker') + SubElement(marker, 'c:symbol', {'val':serie.marker}) + + if serie.labels: + cat = SubElement(ser, 'c:cat') + self._write_serial(cat, serie.labels) + + if self.chart.type == Chart.SCATTER_CHART: + if serie.xvalues: + xval = SubElement(ser, 'c:xVal') + self._write_serial(xval, serie.xvalues) + + yval = SubElement(ser, 'c:yVal') + self._write_serial(yval, serie.values) + else: + val = SubElement(ser, 'c:val') + self._write_serial(val, serie.values) + + def _write_serial(self, node, serie, literal=False): + + cache = serie._get_cache() + if isinstance(cache[0], str): + typ = 'str' + else: + typ = 'num' + + if not literal: + if typ == 'num': + ref = SubElement(node, 'c:numRef') + else: + ref = SubElement(node, 'c:strRef') + SubElement(ref, 'c:f').text = serie._get_ref() + if typ == 'num': + data = SubElement(ref, 'c:numCache') + else: + data = SubElement(ref, 'c:strCache') + else: + data = SubElement(node, 'c:numLit') + + if typ == 'num': + SubElement(data, 'c:formatCode').text = 'General' + if literal: + values = (1,) + else: + values = cache + + SubElement(data, 'c:ptCount', {'val':str(len(values))}) + for j, val in enumerate(values): + point = SubElement(data, 'c:pt', {'idx':str(j)}) + SubElement(point, 'c:v').text = str(val) + + def _write_error_bar(self, node, serie): + + flag = {ErrorBar.PLUS_MINUS:'both', + ErrorBar.PLUS:'plus', + ErrorBar.MINUS:'minus'} + + eb = SubElement(node, 'c:errBars') + SubElement(eb, 'c:errBarType', {'val':flag[serie.error_bar.type]}) + SubElement(eb, 'c:errValType', {'val':'cust'}) + + plus = SubElement(eb, 'c:plus') + self._write_serial(plus, serie.error_bar.values, + literal=(serie.error_bar.type==ErrorBar.MINUS)) + + minus = SubElement(eb, 'c:minus') + self._write_serial(minus, serie.error_bar.values, + literal=(serie.error_bar.type==ErrorBar.PLUS)) + + def _write_legend(self, chart): + + legend = SubElement(chart, 'c:legend') + SubElement(legend, 'c:legendPos', {'val':self.chart.legend.position}) + SubElement(legend, 'c:layout') + + def _write_print_settings(self, root): + + settings = SubElement(root, 'c:printSettings') + SubElement(settings, 'c:headerFooter') + margins = dict([(k, str(v)) for (k,v) in self.chart.print_margins.items()]) + SubElement(settings, 'c:pageMargins', margins) + SubElement(settings, 'c:pageSetup') + + def _write_shapes(self, root): + + if self.chart._shapes: + SubElement(root, 'c:userShapes', {'r:id':'rId1'}) + + def write_rels(self, drawing_id): + + root = Element('Relationships', {'xmlns' : 'http://schemas.openxmlformats.org/package/2006/relationships'}) + attrs = {'Id' : 'rId1', + 'Type' : 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartUserShapes', + 'Target' : '../drawings/drawing%s.xml' % drawing_id } + SubElement(root, 'Relationship', attrs) + return get_document_content(root) diff --git a/tablib/packages/openpyxl3/writer/dump_worksheet.py b/tablib/packages/openpyxl3/writer/dump_worksheet.py index 521cae0..36d68d4 100644 --- a/tablib/packages/openpyxl3/writer/dump_worksheet.py +++ b/tablib/packages/openpyxl3/writer/dump_worksheet.py @@ -66,7 +66,7 @@ class DumpWorksheet(Worksheet): """ .. warning:: - You shouldn't initialize this yourself, use :class:`openpyxl.workbook.Workbook` constructor instead, + You shouldn't initialize this yourself, use :class:`..workbook.Workbook` constructor instead, with `optimized_write = True`. """ @@ -77,9 +77,9 @@ class DumpWorksheet(Worksheet): self._max_col = 0 self._max_row = 0 self._parent = parent_workbook - self._fileobj_header = NamedTemporaryFile(mode='r+', prefix='openpyxl.', suffix='.header', delete=False) - self._fileobj_content = NamedTemporaryFile(mode='r+', prefix='openpyxl.', suffix='.content', delete=False) - self._fileobj = NamedTemporaryFile(mode='w', prefix='openpyxl.', delete=False) + self._fileobj_header = NamedTemporaryFile(mode='r+', prefix='..', suffix='.header', delete=False) + self._fileobj_content = NamedTemporaryFile(mode='r+', prefix='..', suffix='.content', delete=False) + self._fileobj = NamedTemporaryFile(mode='w', prefix='..', delete=False) self.doc = XMLGenerator(self._fileobj_content, 'utf-8') self.header = XMLGenerator(self._fileobj_header, 'utf-8') self.title = 'Sheet' diff --git a/tablib/packages/openpyxl3/writer/excel.py b/tablib/packages/openpyxl3/writer/excel.py index f09746f..a19666d 100644 --- a/tablib/packages/openpyxl3/writer/excel.py +++ b/tablib/packages/openpyxl3/writer/excel.py @@ -27,22 +27,22 @@ # Python stdlib imports from zipfile import ZipFile, ZIP_DEFLATED -from io import BytesIO as StringIO +from io import StringIO # package imports from ..shared.ooxml import ARC_SHARED_STRINGS, ARC_CONTENT_TYPES, \ ARC_ROOT_RELS, ARC_WORKBOOK_RELS, ARC_APP, ARC_CORE, ARC_THEME, \ ARC_STYLE, ARC_WORKBOOK, \ PACKAGE_WORKSHEETS, PACKAGE_DRAWINGS, PACKAGE_CHARTS -from ..writer.strings import create_string_table, write_string_table -from ..writer.workbook import write_content_types, write_root_rels, \ +from .strings import create_string_table, write_string_table +from .workbook import write_content_types, write_root_rels, \ write_workbook_rels, write_properties_app, write_properties_core, \ write_workbook -from ..writer.theme import write_theme -from ..writer.styles import StyleWriter -from ..writer.drawings import DrawingWriter, ShapeWriter -from ..writer.charts import ChartWriter -from ..writer.worksheet import write_worksheet, write_worksheet_rels +from .theme import write_theme +from .styles import StyleWriter +from .drawings import DrawingWriter, ShapeWriter +from .charts import ChartWriter +from .worksheet import write_worksheet, write_worksheet_rels class ExcelWriter(object): diff --git a/tablib/packages/openpyxl3/writer/strings.py b/tablib/packages/openpyxl3/writer/strings.py index f3e882e..706c2b6 100644 --- a/tablib/packages/openpyxl3/writer/strings.py +++ b/tablib/packages/openpyxl3/writer/strings.py @@ -26,7 +26,7 @@ """Write the shared string table.""" # Python stdlib imports -from io import BytesIO as StringIO +from io import StringIO # package imports from ..shared.xmltools import start_tag, end_tag, tag, XMLGenerator @@ -49,7 +49,7 @@ def write_string_table(string_table): start_tag(doc, 'sst', {'xmlns': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main', 'uniqueCount': '%d' % len(string_table)}) - strings_to_write = sorted(string_table.items(), + strings_to_write = sorted(iter(string_table.items()), key=lambda pair: pair[1]) for key in [pair[0] for pair in strings_to_write]: start_tag(doc, 'si') diff --git a/tablib/packages/openpyxl3/writer/styles.py b/tablib/packages/openpyxl3/writer/styles.py index 7e3fb64..3d73382 100644 --- a/tablib/packages/openpyxl3/writer/styles.py +++ b/tablib/packages/openpyxl3/writer/styles.py @@ -40,11 +40,11 @@ class StyleWriter(object): def _get_style_list(self, workbook): crc = {} for worksheet in workbook.worksheets: - for style in worksheet._styles.values(): + for style in list(worksheet._styles.values()): crc[hash(style)] = style self.style_table = dict([(style, i+1) \ - for i, style in enumerate(crc.values())]) - sorted_styles = sorted(self.style_table.items(), \ + for i, style in enumerate(list(crc.values()))]) + sorted_styles = sorted(iter(self.style_table.items()), \ key = lambda pair:pair[1]) return [s[0] for s in sorted_styles] diff --git a/tablib/packages/openpyxl3/writer/worksheet.py b/tablib/packages/openpyxl3/writer/worksheet.py index b7633f8..21d9e9b 100644 --- a/tablib/packages/openpyxl3/writer/worksheet.py +++ b/tablib/packages/openpyxl3/writer/worksheet.py @@ -26,7 +26,7 @@ """Write worksheets to xml representations.""" # Python stdlib imports -from io import BytesIO as StringIO # cStringIO doesn't handle unicode +from io import StringIO # cStringIO doesn't handle unicode # package imports from ..cell import coordinate_from_string, column_index_from_string