diff options
| author | Kenneth Reitz <me@kennethreitz.com> | 2011-05-13 00:28:50 -0400 |
|---|---|---|
| committer | Kenneth Reitz <me@kennethreitz.com> | 2011-05-13 00:28:50 -0400 |
| commit | a60e2f132e67ebdfab6a4220953c8b15d6e97378 (patch) | |
| tree | 634a31452eda5bf6f0af16967be76e2cc29aec80 /tablib/packages | |
| parent | 2b36d71554b50e4123bc2a6eb5065689b8860272 (diff) | |
| download | tablib-a60e2f132e67ebdfab6a4220953c8b15d6e97378.tar.gz | |
Finally! :sparkles:Python 3:sparkles: port of openpyxl
Diffstat (limited to 'tablib/packages')
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("<HH", archive.fp.read(4))
- return zinfo.header_offset + 30 + file_name_len + extra_len
+# 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 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 .excel import get_sheet_ids +from .strings import read_string_table +from .style import read_style_table, NumberFormat +from ..shared.date_time import SharedDate +from .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:`..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("<HH", archive.fp.read(4)) + return zinfo.header_offset + 30 + file_name_len + extra_len diff --git a/tablib/packages/openpyxl3/reader/worksheet.py b/tablib/packages/openpyxl3/reader/worksheet.py index 10b355a..c1c084c 100644 --- a/tablib/packages/openpyxl3/reader/worksheet.py +++ b/tablib/packages/openpyxl3/reader/worksheet.py @@ -30,7 +30,8 @@ try: from xml.etree.cElementTree import iterparse except ImportError: from xml.etree.ElementTree import iterparse -from io import BytesIO as StringIO + +from io import StringIO # package imports from ..cell import Cell, coordinate_from_string @@ -54,8 +55,12 @@ def read_dimension(xml_source): if element.tag == '{http://schemas.openxmlformats.org/spreadsheetml/2006/main}dimension': ref = element.get('ref') + + if ':' in ref: + min_range, max_range = ref.split(':') + else: + min_range = max_range = ref - min_range, max_range = ref.split(':') min_col, min_row = coordinate_from_string(min_range) max_col, max_row = coordinate_from_string(max_range) @@ -66,9 +71,9 @@ def read_dimension(xml_source): return None -def filter_cells(pair): - (event, element) = pair +def filter_cells(xxx_todo_changeme): + (event, element) = xxx_todo_changeme return element.tag == '{http://schemas.openxmlformats.org/spreadsheetml/2006/main}c' def fast_parse(ws, xml_source, string_table, style_table): diff --git a/tablib/packages/openpyxl3/shared/__init__.py b/tablib/packages/openpyxl3/shared/__init__.py index 002fd68..c19d52c 100644 --- a/tablib/packages/openpyxl3/shared/__init__.py +++ b/tablib/packages/openpyxl3/shared/__init__.py @@ -23,11 +23,11 @@ # @license: http://www.opensource.org/licenses/mit-license.php # @author: Eric Gazoni -"""Imports for the openpyxl.shared namespace.""" +"""Imports for the . namespace.""" # package imports -from ..shared import date_time -from ..shared import exc -from ..shared import ooxml -from ..shared import password_hasher -from ..shared import xmltools +from . import date_time +from . import exc +from . import ooxml +from . import password_hasher +from . import xmltools diff --git a/tablib/packages/openpyxl3/shared/date_time.py b/tablib/packages/openpyxl3/shared/date_time.py index 7d87788..8a58cd0 100644 --- a/tablib/packages/openpyxl3/shared/date_time.py +++ b/tablib/packages/openpyxl3/shared/date_time.py @@ -26,7 +26,7 @@ """Manage Excel date weirdness.""" # Python stdlib imports -from __future__ import division + from math import floor import calendar import datetime @@ -48,7 +48,7 @@ def datetime_to_W3CDTF(dt): def W3CDTF_to_datetime(formatted_string): """Convert from a timestamp string to a datetime object.""" match = re.match(RE_W3CDTF,formatted_string) - digits = map(int, match.groups()[:6]) + digits = list(map(int, match.groups()[:6])) return datetime.datetime(*digits) diff --git a/tablib/packages/openpyxl3/style.py b/tablib/packages/openpyxl3/style.py index 38628db..c113bd9 100644 --- a/tablib/packages/openpyxl3/style.py +++ b/tablib/packages/openpyxl3/style.py @@ -340,7 +340,7 @@ class NumberFormat(HashableObject): """Check if a format code is a standard format code.""" if format is None: format = self._format_code - return format in self._BUILTIN_FORMATS.values() + return format in list(self._BUILTIN_FORMATS.values()) def builtin_format_id(self, format): """Return the id of a standard style.""" diff --git a/tablib/packages/openpyxl3/tests/helper.py b/tablib/packages/openpyxl3/tests/helper.py index a60712b..9dfbfaf 100644 --- a/tablib/packages/openpyxl3/tests/helper.py +++ b/tablib/packages/openpyxl3/tests/helper.py @@ -24,12 +24,12 @@ # @author: Eric Gazoni # Python stdlib imports -from __future__ import with_statement + import os import os.path import shutil import difflib -from io import BytesIO as StringIO +from io import StringIO from pprint import pprint from tempfile import gettempdir diff --git a/tablib/packages/openpyxl3/tests/test_cell.py b/tablib/packages/openpyxl3/tests/test_cell.py index edc35c0..07f0b6f 100644 --- a/tablib/packages/openpyxl3/tests/test_cell.py +++ b/tablib/packages/openpyxl3/tests/test_cell.py @@ -134,7 +134,7 @@ class TestCellValueTypes(): def check_error(): eq_(self.cell.TYPE_ERROR, self.cell.data_type) - for error_string in self.cell.ERROR_CODES.keys(): + for error_string in list(self.cell.ERROR_CODES.keys()): self.cell.value = error_string yield check_error diff --git a/tablib/packages/openpyxl3/tests/test_chart.py b/tablib/packages/openpyxl3/tests/test_chart.py index cc3fcda..09a7bbc 100644 --- a/tablib/packages/openpyxl3/tests/test_chart.py +++ b/tablib/packages/openpyxl3/tests/test_chart.py @@ -1,131 +1,131 @@ -# 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), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:title><c:tx><c:rich><a:bodyPr /><a:lstStyle /><a:p><a:pPr><a:defRPr /></a:pPr><a:r><a:rPr lang="fr-FR" /><a:t>TITLE</a:t></a:r></a:p></c:rich></c:tx><c:layout /></c:title></test>')
-
- def test_write_xaxis(self):
-
- self.cw._write_axis(self.root, self.chart.x_axis, 'c:catAx')
- eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:catAx><c:axId val="60871424" /><c:scaling><c:orientation val="minMax" /></c:scaling><c:axPos val="b" /><c:tickLblPos val="nextTo" /><c:crossAx val="60873344" /><c:crosses val="autoZero" /><c:auto val="1" /><c:lblAlgn val="ctr" /><c:lblOffset val="100" /></c:catAx></test>')
-
- def test_write_yaxis(self):
-
- self.cw._write_axis(self.root, self.chart.y_axis, 'c:valAx')
- eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:valAx><c:axId val="60873344" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="l" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60871424" /><c:crosses val="autoZero" /><c:crossBetween val="between" /><c:majorUnit val="2.0" /></c:valAx></test>')
-
- def test_write_series(self):
-
- self.cw._write_series(self.root)
- eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:ser><c:idx val="0" /><c:order val="0" /><c:spPr><a:solidFill><a:srgbClr val="00FF00" /></a:solidFill><a:ln><a:solidFill><a:srgbClr val="00FF00" /></a:solidFill></a:ln></c:spPr><c:marker><c:symbol val="none" /></c:marker><c:val><c:numRef><c:f>data!$A$1:$A$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:val></c:ser></test>')
-
- def test_write_legend(self):
-
- self.cw._write_legend(self.root)
- eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:legend><c:legendPos val="r" /><c:layout /></c:legend></test>')
-
- def test_write_print_settings(self):
-
- self.cw._write_print_settings(self.root)
- eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:printSettings><c:headerFooter /><c:pageMargins b="0.75" footer="0.3" header="0.3" l="0.7" r="0.7" t="0.75" /><c:pageSetup /></c:printSettings></test>')
-
- def test_write_chart(self):
-
- self.cw._write_chart(self.root)
- eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:chart><c:title><c:tx><c:rich><a:bodyPr /><a:lstStyle /><a:p><a:pPr><a:defRPr /></a:pPr><a:r><a:rPr lang="fr-FR" /><a:t>TITLE</a:t></a:r></a:p></c:rich></c:tx><c:layout /></c:title><c:plotArea><c:layout><c:manualLayout><c:layoutTarget val="inner" /><c:xMode val="edge" /><c:yMode val="edge" /><c:x val="1.28571428571" /><c:y val="0.2125" /><c:w val="0.6" /><c:h val="0.6" /></c:manualLayout></c:layout><c:barChart><c:barDir val="col" /><c:grouping val="clustered" /><c:ser><c:idx val="0" /><c:order val="0" /><c:spPr><a:solidFill><a:srgbClr val="00FF00" /></a:solidFill><a:ln><a:solidFill><a:srgbClr val="00FF00" /></a:solidFill></a:ln></c:spPr><c:marker><c:symbol val="none" /></c:marker><c:val><c:numRef><c:f>data!$A$1:$A$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:val></c:ser><c:marker val="1" /><c:axId val="60871424" /><c:axId val="60873344" /></c:barChart><c:catAx><c:axId val="60871424" /><c:scaling><c:orientation val="minMax" /></c:scaling><c:axPos val="b" /><c:tickLblPos val="nextTo" /><c:crossAx val="60873344" /><c:crosses val="autoZero" /><c:auto val="1" /><c:lblAlgn val="ctr" /><c:lblOffset val="100" /></c:catAx><c:valAx><c:axId val="60873344" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="l" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60871424" /><c:crosses val="autoZero" /><c:crossBetween val="between" /><c:majorUnit val="2.0" /></c:valAx></c:plotArea><c:legend><c:legendPos val="r" /><c:layout /></c:legend><c:plotVisOnly val="1" /></c:chart></test>')
-
-
-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), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:valAx><c:axId val="60871424" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="b" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60873344" /><c:crosses val="autoZero" /><c:auto val="1" /><c:lblAlgn val="ctr" /><c:lblOffset val="100" /><c:crossBetween val="midCat" /><c:majorUnit val="2.0" /></c:valAx></test>')
-
-
- def test_write_yaxis(self):
-
- self.cw._write_axis(self.root, self.scatterchart.y_axis, 'c:valAx')
- eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:valAx><c:axId val="60873344" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="l" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60871424" /><c:crosses val="autoZero" /><c:crossBetween val="midCat" /><c:majorUnit val="2.0" /></c:valAx></test>')
-
- def test_write_series(self):
-
- self.cw._write_series(self.root)
- eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:ser><c:idx val="0" /><c:order val="0" /><c:marker><c:symbol val="none" /></c:marker><c:xVal><c:numRef><c:f>data!$B$1:$B$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:xVal><c:yVal><c:numRef><c:f>data!$A$1:$A$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:yVal></c:ser></test>')
-
- def test_write_legend(self):
-
- self.cw._write_legend(self.root)
- eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:legend><c:legendPos val="r" /><c:layout /></c:legend></test>')
-
- def test_write_print_settings(self):
-
- self.cw._write_print_settings(self.root)
- eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:printSettings><c:headerFooter /><c:pageMargins b="0.75" footer="0.3" header="0.3" l="0.7" r="0.7" t="0.75" /><c:pageSetup /></c:printSettings></test>')
-
- def test_write_chart(self):
-
- self.cw._write_chart(self.root)
- eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:chart><c:plotArea><c:layout><c:manualLayout><c:layoutTarget val="inner" /><c:xMode val="edge" /><c:yMode val="edge" /><c:x val="1.28571428571" /><c:y val="0.2125" /><c:w val="0.6" /><c:h val="0.6" /></c:manualLayout></c:layout><c:scatterChart><c:scatterStyle val="lineMarker" /><c:ser><c:idx val="0" /><c:order val="0" /><c:marker><c:symbol val="none" /></c:marker><c:xVal><c:numRef><c:f>data!$B$1:$B$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:xVal><c:yVal><c:numRef><c:f>data!$A$1:$A$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:yVal></c:ser><c:marker val="1" /><c:axId val="60871424" /><c:axId val="60873344" /></c:scatterChart><c:valAx><c:axId val="60871424" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="b" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60873344" /><c:crosses val="autoZero" /><c:auto val="1" /><c:lblAlgn val="ctr" /><c:lblOffset val="100" /><c:crossBetween val="midCat" /><c:majorUnit val="2.0" /></c:valAx><c:valAx><c:axId val="60873344" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="l" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60871424" /><c:crosses val="autoZero" /><c:crossBetween val="midCat" /><c:majorUnit val="2.0" /></c:valAx></c:plotArea><c:legend><c:legendPos val="r" /><c:layout /></c:legend><c:plotVisOnly val="1" /></c:chart></test>')
+# 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), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:title><c:tx><c:rich><a:bodyPr /><a:lstStyle /><a:p><a:pPr><a:defRPr /></a:pPr><a:r><a:rPr lang="fr-FR" /><a:t>TITLE</a:t></a:r></a:p></c:rich></c:tx><c:layout /></c:title></test>') + + def test_write_xaxis(self): + + self.cw._write_axis(self.root, self.chart.x_axis, 'c:catAx') + eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:catAx><c:axId val="60871424" /><c:scaling><c:orientation val="minMax" /></c:scaling><c:axPos val="b" /><c:tickLblPos val="nextTo" /><c:crossAx val="60873344" /><c:crosses val="autoZero" /><c:auto val="1" /><c:lblAlgn val="ctr" /><c:lblOffset val="100" /></c:catAx></test>') + + def test_write_yaxis(self): + + self.cw._write_axis(self.root, self.chart.y_axis, 'c:valAx') + eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:valAx><c:axId val="60873344" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="l" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60871424" /><c:crosses val="autoZero" /><c:crossBetween val="between" /><c:majorUnit val="2.0" /></c:valAx></test>') + + def test_write_series(self): + + self.cw._write_series(self.root) + eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:ser><c:idx val="0" /><c:order val="0" /><c:spPr><a:solidFill><a:srgbClr val="00FF00" /></a:solidFill><a:ln><a:solidFill><a:srgbClr val="00FF00" /></a:solidFill></a:ln></c:spPr><c:marker><c:symbol val="none" /></c:marker><c:val><c:numRef><c:f>data!$A$1:$A$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:val></c:ser></test>') + + def test_write_legend(self): + + self.cw._write_legend(self.root) + eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:legend><c:legendPos val="r" /><c:layout /></c:legend></test>') + + def test_write_print_settings(self): + + self.cw._write_print_settings(self.root) + eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:printSettings><c:headerFooter /><c:pageMargins b="0.75" footer="0.3" header="0.3" l="0.7" r="0.7" t="0.75" /><c:pageSetup /></c:printSettings></test>') + + def test_write_chart(self): + + self.cw._write_chart(self.root) + eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:chart><c:title><c:tx><c:rich><a:bodyPr /><a:lstStyle /><a:p><a:pPr><a:defRPr /></a:pPr><a:r><a:rPr lang="fr-FR" /><a:t>TITLE</a:t></a:r></a:p></c:rich></c:tx><c:layout /></c:title><c:plotArea><c:layout><c:manualLayout><c:layoutTarget val="inner" /><c:xMode val="edge" /><c:yMode val="edge" /><c:x val="1.28571428571" /><c:y val="0.2125" /><c:w val="0.6" /><c:h val="0.6" /></c:manualLayout></c:layout><c:barChart><c:barDir val="col" /><c:grouping val="clustered" /><c:ser><c:idx val="0" /><c:order val="0" /><c:spPr><a:solidFill><a:srgbClr val="00FF00" /></a:solidFill><a:ln><a:solidFill><a:srgbClr val="00FF00" /></a:solidFill></a:ln></c:spPr><c:marker><c:symbol val="none" /></c:marker><c:val><c:numRef><c:f>data!$A$1:$A$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:val></c:ser><c:marker val="1" /><c:axId val="60871424" /><c:axId val="60873344" /></c:barChart><c:catAx><c:axId val="60871424" /><c:scaling><c:orientation val="minMax" /></c:scaling><c:axPos val="b" /><c:tickLblPos val="nextTo" /><c:crossAx val="60873344" /><c:crosses val="autoZero" /><c:auto val="1" /><c:lblAlgn val="ctr" /><c:lblOffset val="100" /></c:catAx><c:valAx><c:axId val="60873344" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="l" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60871424" /><c:crosses val="autoZero" /><c:crossBetween val="between" /><c:majorUnit val="2.0" /></c:valAx></c:plotArea><c:legend><c:legendPos val="r" /><c:layout /></c:legend><c:plotVisOnly val="1" /></c:chart></test>') + + +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), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:valAx><c:axId val="60871424" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="b" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60873344" /><c:crosses val="autoZero" /><c:auto val="1" /><c:lblAlgn val="ctr" /><c:lblOffset val="100" /><c:crossBetween val="midCat" /><c:majorUnit val="2.0" /></c:valAx></test>') + + + def test_write_yaxis(self): + + self.cw._write_axis(self.root, self.scatterchart.y_axis, 'c:valAx') + eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:valAx><c:axId val="60873344" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="l" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60871424" /><c:crosses val="autoZero" /><c:crossBetween val="midCat" /><c:majorUnit val="2.0" /></c:valAx></test>') + + def test_write_series(self): + + self.cw._write_series(self.root) + eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:ser><c:idx val="0" /><c:order val="0" /><c:marker><c:symbol val="none" /></c:marker><c:xVal><c:numRef><c:f>data!$B$1:$B$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:xVal><c:yVal><c:numRef><c:f>data!$A$1:$A$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:yVal></c:ser></test>') + + def test_write_legend(self): + + self.cw._write_legend(self.root) + eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:legend><c:legendPos val="r" /><c:layout /></c:legend></test>') + + def test_write_print_settings(self): + + self.cw._write_print_settings(self.root) + eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:printSettings><c:headerFooter /><c:pageMargins b="0.75" footer="0.3" header="0.3" l="0.7" r="0.7" t="0.75" /><c:pageSetup /></c:printSettings></test>') + + def test_write_chart(self): + + self.cw._write_chart(self.root) + eq_(get_xml(self.root), '<?xml version=\'1.0\' encoding=\'UTF-8\'?><test><c:chart><c:plotArea><c:layout><c:manualLayout><c:layoutTarget val="inner" /><c:xMode val="edge" /><c:yMode val="edge" /><c:x val="1.28571428571" /><c:y val="0.2125" /><c:w val="0.6" /><c:h val="0.6" /></c:manualLayout></c:layout><c:scatterChart><c:scatterStyle val="lineMarker" /><c:ser><c:idx val="0" /><c:order val="0" /><c:marker><c:symbol val="none" /></c:marker><c:xVal><c:numRef><c:f>data!$B$1:$B$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:xVal><c:yVal><c:numRef><c:f>data!$A$1:$A$11</c:f><c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="11" /><c:pt idx="0"><c:v>0</c:v></c:pt><c:pt idx="1"><c:v>1</c:v></c:pt><c:pt idx="2"><c:v>2</c:v></c:pt><c:pt idx="3"><c:v>3</c:v></c:pt><c:pt idx="4"><c:v>4</c:v></c:pt><c:pt idx="5"><c:v>5</c:v></c:pt><c:pt idx="6"><c:v>6</c:v></c:pt><c:pt idx="7"><c:v>7</c:v></c:pt><c:pt idx="8"><c:v>8</c:v></c:pt><c:pt idx="9"><c:v>9</c:v></c:pt><c:pt idx="10"><c:v>None</c:v></c:pt></c:numCache></c:numRef></c:yVal></c:ser><c:marker val="1" /><c:axId val="60871424" /><c:axId val="60873344" /></c:scatterChart><c:valAx><c:axId val="60871424" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="b" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60873344" /><c:crosses val="autoZero" /><c:auto val="1" /><c:lblAlgn val="ctr" /><c:lblOffset val="100" /><c:crossBetween val="midCat" /><c:majorUnit val="2.0" /></c:valAx><c:valAx><c:axId val="60873344" /><c:scaling><c:orientation val="minMax" /><c:max val="10.0" /><c:min val="0" /></c:scaling><c:axPos val="l" /><c:majorGridlines /><c:numFmt formatCode="General" sourceLinked="1" /><c:tickLblPos val="nextTo" /><c:crossAx val="60871424" /><c:crosses val="autoZero" /><c:crossBetween val="midCat" /><c:majorUnit val="2.0" /></c:valAx></c:plotArea><c:legend><c:legendPos val="r" /><c:layout /></c:legend><c:plotVisOnly val="1" /></c:chart></test>') 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 Binary files differindex 1c5adb6..07d447c 100644 --- a/tablib/packages/openpyxl3/tests/test_props.py +++ b/tablib/packages/openpyxl3/tests/test_props.py 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 |
