Hello community,

here is the log from the commit of package python3-openpyxl for 
openSUSE:Factory checked in at 2015-04-05 02:03:56
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-openpyxl (Old)
 and      /work/SRC/openSUSE:Factory/.python3-openpyxl.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python3-openpyxl"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-openpyxl/python3-openpyxl.changes        
2015-03-16 07:01:09.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.python3-openpyxl.new/python3-openpyxl.changes   
2015-04-05 02:04:09.000000000 +0200
@@ -1,0 +2,17 @@
+Fri Apr  3 00:19:48 UTC 2015 - a...@gmx.de
+
+- update to version 2.2.1:
+  * PR54 Improved precision on times near midnight.
+  * PR55 Preserve macro buttons
+  * #429 Workbook fails to load because header and footers cannot be
+     parsed.
+  * #433 File-like object with encoding=None
+  * #434 SyntaxError when writing page breaks.
+  * #436 Read-only mode duplicates empty rows.
+  * #437 Cell.offset raises an exception
+  * #438 Cells with pivotButton and quotePrefix styles cannot be read
+  * #440 Error when customised versions of builtin formats
+  * #442 Exception raised when a fill element contains no children
+  * #444 Styles cannot be copied
+
+-------------------------------------------------------------------

Old:
----
  openpyxl-2.2.0.tar.gz

New:
----
  openpyxl-2.2.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python3-openpyxl.spec ++++++
--- /var/tmp/diff_new_pack.QLPM4W/_old  2015-04-05 02:04:10.000000000 +0200
+++ /var/tmp/diff_new_pack.QLPM4W/_new  2015-04-05 02:04:10.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           python3-openpyxl
-Version:        2.2.0
+Version:        2.2.1
 Release:        0
 Summary:        A Python library to read/write Excel 2007 xlsx/xlsm files
 License:        MIT and Python-2.0

++++++ openpyxl-2.2.0.tar.gz -> openpyxl-2.2.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/PKG-INFO new/openpyxl-2.2.1/PKG-INFO
--- old/openpyxl-2.2.0/PKG-INFO 2015-03-11 17:14:43.000000000 +0100
+++ new/openpyxl-2.2.1/PKG-INFO 2015-03-31 11:14:50.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: openpyxl
-Version: 2.2.0
+Version: 2.2.1
 Summary: A Python library to read/write Excel 2007 xlsx/xlsm files
 Home-page: http://openpyxl.readthedocs.org
 Author: See AUTHORS
@@ -59,7 +59,6 @@
         Release notes: http://openpyxl.readthedocs.org/en/latest/changes.html
         
 Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Operating System :: MacOS :: MacOS X
 Classifier: Operating System :: Microsoft :: Windows
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/__init__.py 
new/openpyxl-2.2.1/openpyxl/__init__.py
--- old/openpyxl-2.2.0/openpyxl/__init__.py     2015-03-11 16:10:31.000000000 
+0100
+++ new/openpyxl-2.2.1/openpyxl/__init__.py     2015-03-20 16:18:11.000000000 
+0100
@@ -11,7 +11,7 @@
 
 
 # constants
-__version__ = '2.2.0'
+__version__ = '2.2.1'
 
 __author__ = 'Eric Gazoni'
 __license__ = 'MIT/Expat'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/cell/cell.py 
new/openpyxl-2.2.1/openpyxl/cell/cell.py
--- old/openpyxl-2.2.0/openpyxl/cell/cell.py    2015-03-11 16:10:31.000000000 
+0100
+++ new/openpyxl-2.2.1/openpyxl/cell/cell.py    2015-03-31 11:12:52.000000000 
+0200
@@ -71,6 +71,9 @@
 NUMBER_REGEX = 
re.compile(r'^-?([\d]|[\d]+\.[\d]*|\.[\d]+|[1-9][\d]+\.?[\d]*)((E|e)[-+]?[\d]+)?$')
 ILLEGAL_CHARACTERS_RE = re.compile(r'[\000-\010]|[\013-\014]|[\016-\037]')
 
+ERROR_CODES = ('#NULL!', '#DIV/0!', '#VALUE!', '#REF!', '#NAME?', '#NUM!',
+               '#N/A')
+
 
 class Cell(StyleableObject):
     """Describes cell associated properties.
@@ -90,13 +93,7 @@
         '_comment',
                  )
 
-    ERROR_CODES = ('#NULL!',
-                   '#DIV/0!',
-                   '#VALUE!',
-                   '#REF!',
-                   '#NAME?',
-                   '#NUM!',
-                   '#N/A')
+    ERROR_CODES = ERROR_CODES
 
     TYPE_STRING = 's'
     TYPE_FORMULA = 'f'
@@ -111,14 +108,17 @@
                    TYPE_NULL, TYPE_INLINE, TYPE_ERROR, 
TYPE_FORMULA_CACHE_STRING)
 
 
-    def __init__(self, worksheet, column, row, value=None, fontId=0, fillId=0,
-                 borderId=0, alignmentId=0, protectionId=0, numFmtId=0, 
xfId=None):
+    def __init__(self, worksheet, column, row, value=None, fontId=0,
+                 fillId=0, borderId=0, alignmentId=0, protectionId=0, 
numFmtId=0,
+                 pivotButton=None, quotePrefix=None, xfId=None):
         self._font_id = fontId
         self._fill_id = fillId
         self._border_id = borderId
         self._alignment_id = alignmentId
         self._protection_id = protectionId
         self._number_format_id = numFmtId
+        self.quotePrefix = quotePrefix
+        self.pivotButton = pivotButton
         self.parent = worksheet
         self.column = column
         self.row = row
@@ -363,8 +363,7 @@
 
         :rtype: :class:`openpyxl.cell.Cell`
         """
-        offset_column = get_column_letter(
-            column_index_from_string(self.column) + column)
+        offset_column = column_index_from_string(self.column) + column
         offset_row = self.row + row
         return self.parent.cell(column=offset_column, row=offset_row)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/profiling.py 
new/openpyxl-2.2.1/openpyxl/profiling.py
--- old/openpyxl-2.2.0/openpyxl/profiling.py    2015-02-09 23:50:31.000000000 
+0100
+++ new/openpyxl-2.2.1/openpyxl/profiling.py    1970-01-01 01:00:00.000000000 
+0100
@@ -1,130 +0,0 @@
-from io import BytesIO
-import os
-from random import randint
-
-from openpyxl import Workbook
-from openpyxl.xml.functions import XMLGenerator
-
-def make_worksheet():
-    wb = Workbook()
-    ws = wb.active
-    for i in range(1000):
-        ws.append(list(range(100)))
-    return ws
-
-
-
-
-def make_dump_worksheet():
-    wb = Workbook(write_only=True)
-    ws = wb.create_sheet()
-    return ws
-
-def dump_writer(ws=None):
-    if ws is None:
-        ws = make_dump_worksheet()
-    for i in range(1000):
-        ws.append(list(range(100)))
-
-
-COLUMNS = 100
-ROWS = 1000
-BOLD = 1
-ITALIC = 2
-UNDERLINE = 4
-RED_BG = 8
-formatData = [[None] * COLUMNS for _ in range(ROWS)]
-
-def generate_format_data():
-    for row in range(ROWS):
-        for col in range(COLUMNS):
-            formatData[row][col] = randint(1, 15)
-
-
-def styled_sheet():
-    from openpyxl import Workbook
-    from openpyxl.styles import Font, Style, PatternFill, Color, colors
-
-    wb = Workbook()
-    ws = wb.active
-    ws.title = 'Test 1'
-
-    red_fill = PatternFill(fill_type='solid', fgColor=Color(colors.RED), 
bgColor=Color(colors.RED))
-    empty_fill = PatternFill()
-    styles = []
-    # pregenerate relevant styles
-    for row in range(ROWS):
-        _row = []
-        for col in range(COLUMNS):
-            cell = ws.cell(row=row+1, column=col+1)
-            cell.value = 1
-            font = {}
-            fill = PatternFill()
-            if formatData[row][col] & BOLD:
-                font['bold'] = True
-            if formatData[row][col] & ITALIC:
-                font['italic'] = True
-            if formatData[row][col] & UNDERLINE:
-                font['underline'] = 'single'
-            if formatData[row][col] & RED_BG:
-                fill = red_fill
-            cell.style = Style(font=Font(**font), fill=fill)
-
-    #wb.save(get_output_path('test_openpyxl_style_std_pregen.xlsx'))
-
-
-def read_workbook():
-    from openpyxl import load_workbook
-    folder = os.path.split(__file__)[0]
-    src = os.path.join(folder, "files", "very_large.xlsx")
-    wb = load_workbook(src, read_only=True)
-    return wb
-
-
-def rows_without_values(wb):
-    ws = wb.active
-    rows = ws.iter_rows()
-    for r, row in enumerate(rows):
-        for c, col in enumerate(row):
-            pass
-    print((r+1)* (c+1), "cells")
-
-
-def rows_with_values(wb):
-    ws = wb.active
-    rows = ws.iter_rows()
-    for r, row in enumerate(rows):
-        for c, col in enumerate(row):
-            col.value
-    print((r+1)* (c+1), "cells")
-
-def col_index1():
-    from openpyxl.cell import get_column_letter
-    for i in range(1, 18279):
-        c = get_column_letter(i)
-
-
-
-"""
-Sample use
-import cProfile
-ws = make_worksheet()
-cProfile.run("profiling.lxml_writer(ws)", sort="tottime")
-"""
-
-
-if __name__ == '__main__':
-    import cProfile
-    # ws = make_worksheet()
-    wb = read_workbook()
-    print("Looping without values")
-    cProfile.run("rows_without_values(wb)", sort="tottime")
-    print("Looping with values")
-    cProfile.run("rows_with_values(wb)", sort="tottime")
-    cProfile.run("make_worksheet()", sort="tottime")
-    #cProfile.run("lxml_writer(ws)", sort="tottime")
-    generate_format_data()
-    cProfile.run("styled_sheet()", sort="tottime")
-    ws = make_dump_worksheet()
-    cProfile.run("dump_writer(ws)", sort="tottime")
-    cProfile.run("col_index1()", sort="tottime")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/reader/excel.py 
new/openpyxl-2.2.1/openpyxl/reader/excel.py
--- old/openpyxl-2.2.0/openpyxl/reader/excel.py 2015-03-11 16:10:31.000000000 
+0100
+++ new/openpyxl-2.2.1/openpyxl/reader/excel.py 2015-03-31 11:12:52.000000000 
+0200
@@ -131,7 +131,7 @@
     if is_file_like:
         # fileobject must have been opened with 'rb' flag
         # it is required by zipfile
-        if hasattr(filename, 'encoding'):
+        if getattr(filename, 'encoding', None) is not None:
             raise IOError("File-object must be opened in binary mode")
 
     try:
@@ -233,8 +233,7 @@
         else:
             new_ws = read_worksheet(archive.read(worksheet_path), wb,
                                     sheet_name, shared_strings, 
wb.shared_styles,
-                                    color_index=wb._colors,
-                                    keep_vba=keep_vba)
+                                    color_index=wb._colors)
         new_ws.sheet_state = sheet.get('state') or 'visible'
         wb._add_sheet(new_ws)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/reader/style.py 
new/openpyxl-2.2.1/openpyxl/reader/style.py
--- old/openpyxl-2.2.0/openpyxl/reader/style.py 2015-03-11 16:10:31.000000000 
+0100
+++ new/openpyxl-2.2.1/openpyxl/reader/style.py 2015-03-31 11:12:52.000000000 
+0200
@@ -42,6 +42,7 @@
         self.border_list = IndexedList()
         self.alignments = IndexedList([Alignment()])
         self.protections = IndexedList([Protection()])
+        self.custom_number_formats = {}
         self.number_formats = IndexedList()
 
     def parse(self):
@@ -58,9 +59,10 @@
         """Read in custom numeric formatting rules from the shared style 
table"""
         custom_formats = {}
         num_fmts = self.root.findall('{%s}numFmts/{%s}numFmt' % 
(SHEET_MAIN_NS, SHEET_MAIN_NS))
-        for num_fmt_node in num_fmts:
-            fmt_code = num_fmt_node.get('formatCode').lower()
-            self.number_formats.append(fmt_code)
+        for node in num_fmts:
+            idx = int(node.get('numFmtId'))
+            self.custom_number_formats[idx] = node.get('formatCode')
+            self.number_formats.append(node.get('formatCode'))
 
 
     def parse_color_index(self):
@@ -154,10 +156,13 @@
             fillId = int(xf.get("fillId", 0))
             borderId = int(xf.get("borderId", 0))
 
-            if numFmtId < 164:
-                format_code = builtin_formats.get(numFmtId, 'General')
+            # check for custom formats and normalise indices
+
+            if numFmtId in self.custom_number_formats:
+                format_code = self.custom_number_formats[numFmtId]
+                attrs["numFmtId"] = self.number_formats.add(format_code) + 164
             else:
-                format_code = self.number_formats[numFmtId-165]
+                format_code = builtin_formats[numFmtId]
             _style['number_format'] = format_code
 
             if bool_attrib(xf, 'applyAlignment'):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/reader/worksheet.py 
new/openpyxl-2.2.1/openpyxl/reader/worksheet.py
--- old/openpyxl-2.2.0/openpyxl/reader/worksheet.py     2015-03-11 
16:10:31.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl/reader/worksheet.py     2015-03-31 
11:12:52.000000000 +0200
@@ -65,6 +65,7 @@
         self.guess_types = ws.parent._guess_types
         self.data_only = ws.parent.data_only
         self.styles = [dict(style) for style in self.ws.parent._cell_styles]
+        self.keep_vba = ws.parent.vba_archive is not None
 
     def parse(self):
         dispatcher = {
@@ -129,7 +130,6 @@
             style_id = int(style_id)
             style = self.styles[style_id]
 
-
         column, row = coordinate_from_string(coordinate)
         cell = Cell(self.ws, column, row, **style)
         self.ws._add_cell(cell)
@@ -297,7 +297,10 @@
 
 
     def parse_legacy_drawing(self, element):
-        self.ws.vba_controls = element.get("r:id")
+        if self.keep_vba:
+            # Create an id that will not clash with any other ids that will
+            # be generated.
+            self.ws.vba_controls = 'vbaControlId'
 
 
     def parse_sheet_views(self, element):
@@ -307,14 +310,14 @@
         self.ws.sheet_view = SheetView.from_tree(el)
 
 
-def fast_parse(ws, xml_source, shared_strings, style_table, color_index=None):
+def fast_parse(ws, xml_source, shared_strings, style_table, color_index=None, 
keep_vba=False):
     parser = WorkSheetParser(ws, xml_source, shared_strings, style_table, 
color_index)
     parser.parse()
     del parser
 
 
 def read_worksheet(xml_source, parent, preset_title, shared_strings,
-                   style_table, color_index=None, worksheet_path=None, 
keep_vba=False):
+                   style_table, color_index=None, worksheet_path=None):
     """Read an xml worksheet"""
     if worksheet_path:
         ws = IterableWorksheet(parent, preset_title,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/styles/__init__.py 
new/openpyxl-2.2.1/openpyxl/styles/__init__.py
--- old/openpyxl-2.2.0/openpyxl/styles/__init__.py      2015-03-11 
16:10:31.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl/styles/__init__.py      2015-03-31 
11:12:52.000000000 +0200
@@ -2,6 +2,7 @@
 # Copyright (c) 2010-2015 openpyxl
 
 from openpyxl.descriptors import Typed
+from openpyxl.compat import deprecated
 
 from .alignment import Alignment
 from .borders import Border, Side
@@ -24,12 +25,12 @@
                   'protection')
     __base__ = True
 
-    _font = Typed(expected_type=Font)
-    _fill = Typed(expected_type=Fill)
-    _border = Typed(expected_type=Border)
-    _alignment = Typed(expected_type=Alignment)
+    font = Typed(expected_type=Font)
+    fill = Typed(expected_type=Fill, allow_none=True)
+    border = Typed(expected_type=Border)
+    alignment = Typed(expected_type=Alignment)
     number_format = NumberFormatDescriptor()
-    _protection = Typed(expected_type=Protection)
+    protection = Typed(expected_type=Protection)
 
     def __init__(self,
                  font=Font(),
@@ -39,33 +40,24 @@
                  number_format=None,
                  protection=Protection()
                  ):
-        self._font = font
-        self._fill = fill
-        self._border = border
-        self._alignment = alignment
+        self.font = font
+        self.fill = fill
+        self.border = border
+        self.alignment = alignment
         self.number_format = number_format
-        self._protection = protection
+        self.protection = protection
 
 
-    @property
-    def font(self):
-        return StyleProxy(self._font)
-
-    @property
-    def fill(self):
-        return StyleProxy(self._fill)
-
-    @property
-    def border(self):
-        return StyleProxy(self._border)
-
-    @property
-    def alignment(self):
-        return StyleProxy(self._alignment)
-
-    @property
-    def protection(self):
-        return StyleProxy(self._protection)
+    @deprecated("Copy formatting objects like font directly")
+    def copy(self):
+        cls = self.__class__
+        return cls(font=self.font.copy(),
+                   fill=self.fill.copy(),
+                   border=self.border.copy(),
+                   alignment=self.alignment.copy(),
+                   number_format=self.number_format,
+                   protection=self.protection.copy()
+                   )
 
 
 DEFAULTS = Style()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/styles/fills.py 
new/openpyxl-2.2.1/openpyxl/styles/fills.py
--- old/openpyxl-2.2.0/openpyxl/styles/fills.py 2015-03-11 16:10:31.000000000 
+0100
+++ new/openpyxl-2.2.1/openpyxl/styles/fills.py 2015-03-31 11:12:52.000000000 
+0200
@@ -48,7 +48,10 @@
 
     @classmethod
     def from_tree(cls, el):
-        child = [c for c in el][0]
+        children = [c for c in el]
+        if not children:
+            return
+        child = children[0]
         if "patternFill" in child.tag:
             return PatternFill._from_tree(child)
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/styles/styleable.py 
new/openpyxl-2.2.1/openpyxl/styles/styleable.py
--- old/openpyxl-2.2.0/openpyxl/styles/styleable.py     2015-03-11 
16:10:31.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl/styles/styleable.py     2015-03-31 
11:12:52.000000000 +0200
@@ -1,7 +1,7 @@
 from __future__ import absolute_import
 # Copyright (c) 2010-2015 openpyxl
 
-from collections import namedtuple
+from warnings import warn
 
 from openpyxl.utils.indexed_list import IndexedList
 from .numbers import BUILTIN_FORMATS, BUILTIN_FORMATS_REVERSE
@@ -62,9 +62,11 @@
     alignment = StyleDescriptor('_alignments', '_alignment_id')
 
     __slots__ = ('parent', '_font_id', '_border_id', '_fill_id',
-                 '_alignment_id', '_protection_id', '_number_format_id')
+                 '_alignment_id', '_protection_id', '_number_format_id', 
'pivotButton',
+                 'quotePrefix')
 
-    def __init__(self, sheet, fontId=0, fillId=0, borderId=0, alignmentId=0, 
protectionId=0, numFmtId=0):
+    def __init__(self, sheet, fontId=0, fillId=0, borderId=0, alignmentId=0,
+                 protectionId=0, numFmtId=0, pivotButton=None, 
quotePrefix=None):
         self._font_id = fontId
         self._fill_id = fillId
         self._border_id = borderId
@@ -72,6 +74,8 @@
         self._protection_id = protectionId
         self._number_format_id = numFmtId
         self.parent = sheet
+        self.pivotButton = pivotButton
+        self.quotePrefix = quotePrefix
 
 
     @property
@@ -82,7 +86,10 @@
             fillId=self._fill_id,
             fontId=self._font_id,
             numFmtId=self._number_format_id,
-            protectionId=self._protection_id)
+            protectionId=self._protection_id,
+            pivotButton=self.pivotButton,
+            quotePrefix=self.quotePrefix
+        )
 
         return self.parent.parent._cell_styles.add(style)
 
@@ -93,26 +100,30 @@
                or self._fill_id
                or self._font_id
                or self._number_format_id
-               or self._protection_id)
+               or self._protection_id
+               or self.pivotButton
+               or self.quotePrefix
+               )
 
     #legacy
     @property
     def style(self):
+        warn("Use formatting objects such as font directly")
         return Style(
-            font=self.font,
-            fill=self.fill,
-            border=self.border,
-            alignment=self.alignment,
+            font=self.font.copy(),
+            fill=self.fill.copy(),
+            border=self.border.copy(),
+            alignment=self.alignment.copy(),
             number_format=self.number_format,
-            protection=self.protection
+            protection=self.protection.copy()
         )
 
     #legacy
     @style.setter
     def style(self, value):
-        self.font = value.font._StyleProxy__target
-        self.fill = value.fill._StyleProxy__target
-        self.border = value.border._StyleProxy__target
-        self.protection = value.protection._StyleProxy__target
-        self.alignment = value.alignment._StyleProxy__target
+        self.font = value.font.copy()
+        self.fill = value.fill.copy()
+        self.border = value.border.copy()
+        self.protection = value.protection.copy()
+        self.alignment = value.alignment.copy()
         self.number_format = value.number_format
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/utils/datetime.py 
new/openpyxl-2.2.1/openpyxl/utils/datetime.py
--- old/openpyxl-2.2.0/openpyxl/utils/datetime.py       2015-03-11 
16:10:31.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl/utils/datetime.py       2015-03-31 
11:12:52.000000000 +0200
@@ -58,10 +58,15 @@
         value += 1
     parts = list(jd2gcal(MJD_0, value + offset - MJD_0))
     _, fraction = divmod(value, 1)
+    jumped = (parts[-1] == 0 and fraction > 0)
     diff = datetime.timedelta(days=fraction)
+
     if 0 < abs(value) < 1:
         return days_to_time(diff)
-    return datetime.datetime(*parts[:3]) + diff
+    if not jumped:
+        return datetime.datetime(*parts[:3]) + diff
+    else:
+        return datetime.datetime(*parts[:3] + [0])
 
 
 @lru_cache()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/workbook/workbook.py 
new/openpyxl-2.2.1/openpyxl/workbook/workbook.py
--- old/openpyxl-2.2.0/openpyxl/workbook/workbook.py    2015-03-11 
16:10:31.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl/workbook/workbook.py    2015-03-20 
16:18:11.000000000 +0100
@@ -290,6 +290,8 @@
             you will only be able to call this function once. Subsequents 
attempts to
             modify or save the file will raise an 
:class:`openpyxl.shared.exc.WorkbookAlreadySaved` exception.
         """
+        if self.read_only:
+            raise TypeError("""Workbook is read-only""")
         if self.write_only:
             save_dump(self, filename)
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/worksheet/header_footer.py 
new/openpyxl-2.2.1/openpyxl/worksheet/header_footer.py
--- old/openpyxl-2.2.0/openpyxl/worksheet/header_footer.py      2015-03-11 
16:10:31.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl/worksheet/header_footer.py      2015-03-20 
16:18:11.000000000 +0100
@@ -109,7 +109,7 @@
 
         m = SIZE_REGEX.search(text)
         if m:
-            self.font_size = m.group(0)
+            self.font_size = int(m.group('size'))
             text = SIZE_REGEX.sub('', text)
 
         m = COLOR_REGEX.search(text)
@@ -194,14 +194,23 @@
 (&L(?P<left>.+?))?
 (&C(?P<center>.+?))?
 (&R(?P<right>.+?))?
-$""", re.VERBOSE)
+$""", re.VERBOSE | re.DOTALL)
+
+# add support for multiline strings (how do re.flags combine?)
+
+from warnings import warn
 
 def _split_string(text):
     """Split the combined (decoded) string into left, center and right parts"""
     m = ITEM_REGEX.match(text)
-    return m.groupdict()
+    try:
+        parts = m.groupdict()
+    except AttributeError:
+        warn("""Cannot parse header or footer so it will be ignored""")
+        parts = {'left':'', 'right':'', 'center':''}
+    return parts
 
 HEADER_REGEX = re.compile(r"(&[ABDEGHINOPSTUXYZ\+\-])") # split part into 
commands
 FONT_REGEX = re.compile('&"(?P<font>.+)"')
 COLOR_REGEX = re.compile("&K(?P<color>[A-F0-9]{6})")
-SIZE_REGEX = re.compile(r"&\d+")
+SIZE_REGEX = re.compile(r"&(?P<size>\d+)")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/worksheet/iter_worksheet.py 
new/openpyxl-2.2.1/openpyxl/worksheet/iter_worksheet.py
--- old/openpyxl-2.2.0/openpyxl/worksheet/iter_worksheet.py     2015-03-11 
16:10:31.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl/worksheet/iter_worksheet.py     2015-03-31 
11:12:52.000000000 +0200
@@ -96,7 +96,7 @@
         if max_col is not None:
             empty_row = tuple(EMPTY_CELL for column in range(min_col, max_col 
+ 1))
         else:
-            expected_columns = []
+            empty_row = []
         row_counter = min_row
 
         p = iterparse(self.xml_source, tag=[ROW_TAG], remove_blank_text=True)
@@ -110,6 +110,7 @@
 
                 # some rows are missing
                 for row_counter in range(row_counter, row_id):
+                    row_counter += 1
                     yield empty_row
 
                 # return cells from a row
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/writer/excel.py 
new/openpyxl-2.2.1/openpyxl/writer/excel.py
--- old/openpyxl-2.2.0/openpyxl/writer/excel.py 2015-03-11 16:10:31.000000000 
+0100
+++ new/openpyxl-2.2.1/openpyxl/writer/excel.py 2015-03-31 11:12:52.000000000 
+0200
@@ -105,6 +105,7 @@
         image_id = 1
         shape_id = 1
         comments_id = 1
+        vba_controls_id = 1
 
         for i, sheet in enumerate(self.workbook.worksheets):
             archive.writestr(PACKAGE_WORKSHEETS + '/sheet%d.xml' % (i + 1),
@@ -112,8 +113,9 @@
                                              ))
             if (sheet._charts or sheet._images
                 or sheet.relationships
-                or sheet._comment_count > 0):
-                rels = write_rels(sheet, drawing_id, comments_id)
+                or sheet._comment_count > 0
+                or sheet.vba_controls is not None):
+                rels = write_rels(sheet, drawing_id, comments_id, 
vba_controls_id)
                 archive.writestr(
                     PACKAGE_WORKSHEETS + '/_rels/sheet%d.xml.rels' % (i + 1),
                     tostring(rels)
@@ -152,6 +154,9 @@
                     cw.write_comments_vml())
                 comments_id += 1
 
+            if sheet.vba_controls is not None:
+                vba_controls_id += 1
+
     def _write_external_links(self, archive):
         """Write links to external workbooks"""
         wb = self.workbook
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/writer/relations.py 
new/openpyxl-2.2.1/openpyxl/writer/relations.py
--- old/openpyxl-2.2.0/openpyxl/writer/relations.py     2015-02-09 
16:59:20.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl/writer/relations.py     2015-03-31 
11:12:52.000000000 +0200
@@ -11,7 +11,7 @@
 )
 
 
-def write_rels(worksheet, drawing_id, comments_id):
+def write_rels(worksheet, drawing_id, comments_id, vba_controls_id):
     """Write relationships for the worksheet to xml."""
     root = Element('{%s}Relationships' % PKG_REL_NS)
     for rel in worksheet.relationships:
@@ -35,5 +35,9 @@
                  'Type': VML_NS,
                  'Target': '../drawings/commentsDrawing%s.vml' % comments_id}
         SubElement(root, '{%s}Relationship' % PKG_REL_NS, attrs)
+    if worksheet.vba_controls is not None:
+        attrs = {'Id': worksheet.vba_controls,
+                 'Type': VML_NS,
+                 'Target': '../drawings/vmlDrawing%s.vml' % vba_controls_id}
+        SubElement(root, '{%s}Relationship' % PKG_REL_NS, attrs)
     return root
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/writer/worksheet.py 
new/openpyxl-2.2.1/openpyxl/writer/worksheet.py
--- old/openpyxl-2.2.0/openpyxl/writer/worksheet.py     2015-03-11 
16:10:31.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl/writer/worksheet.py     2015-03-31 
11:12:52.000000000 +0200
@@ -199,7 +199,7 @@
         tag = Element('rowBreaks', {'count': str(len(breaks)),
                                      'manualBreakCount': str(len(breaks))})
         for b in breaks:
-            tag.append(Element('brk', id=str(b), man=true, max='16383',
+            tag.append(Element('brk', id=str(b), man="true", max='16383',
                                min='0'))
         return tag
 
@@ -295,7 +295,8 @@
 
             # add a legacyDrawing so that excel can draw comments
             if worksheet._comment_count > 0:
-                comments = Element('legacyDrawing', {'{%s}id' % REL_NS: 
'commentsvml'})
+                comments = Element('{%s}legacyDrawing' % SHEET_MAIN_NS,
+                                {'{%s}id' % REL_NS: 'commentsvml'})
                 xf.write(comments)
 
     xml = out.getvalue()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl/xml/constants.py 
new/openpyxl-2.2.1/openpyxl/xml/constants.py
--- old/openpyxl-2.2.0/openpyxl/xml/constants.py        2015-03-11 
16:10:31.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl/xml/constants.py        2015-03-31 
11:12:52.000000000 +0200
@@ -31,7 +31,7 @@
 ARC_SHARED_STRINGS = PACKAGE_XL + '/sharedStrings.xml'
 ARC_CUSTOM_UI = 'customUI/customUI.xml'
 ARC_VBA = ('xl/vba', 'xl/activeX', 'xl/drawings', 'xl/media', 'xl/ctrlProps',
-           'xl/worksheets/_rels', 'customUI', 'xl/printerSettings')
+           'customUI', 'xl/printerSettings')
 
 ## namespaces
 # Dublin Core
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl.egg-info/PKG-INFO 
new/openpyxl-2.2.1/openpyxl.egg-info/PKG-INFO
--- old/openpyxl-2.2.0/openpyxl.egg-info/PKG-INFO       2015-03-11 
17:14:43.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl.egg-info/PKG-INFO       2015-03-31 
11:14:50.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: openpyxl
-Version: 2.2.0
+Version: 2.2.1
 Summary: A Python library to read/write Excel 2007 xlsx/xlsm files
 Home-page: http://openpyxl.readthedocs.org
 Author: See AUTHORS
@@ -59,7 +59,6 @@
         Release notes: http://openpyxl.readthedocs.org/en/latest/changes.html
         
 Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Operating System :: MacOS :: MacOS X
 Classifier: Operating System :: Microsoft :: Windows
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/openpyxl.egg-info/SOURCES.txt 
new/openpyxl-2.2.1/openpyxl.egg-info/SOURCES.txt
--- old/openpyxl-2.2.0/openpyxl.egg-info/SOURCES.txt    2015-03-11 
17:14:43.000000000 +0100
+++ new/openpyxl-2.2.1/openpyxl.egg-info/SOURCES.txt    2015-03-31 
11:14:50.000000000 +0200
@@ -11,7 +11,6 @@
 et_xmfile/xmlfile.py
 openpyxl/__init__.py
 openpyxl/conftest.py
-openpyxl/profiling.py
 openpyxl.egg-info/PKG-INFO
 openpyxl.egg-info/SOURCES.txt
 openpyxl.egg-info/dependency_links.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openpyxl-2.2.0/setup.py new/openpyxl-2.2.1/setup.py
--- old/openpyxl-2.2.0/setup.py 2015-03-11 17:14:11.000000000 +0100
+++ new/openpyxl-2.2.1/setup.py 2015-03-20 16:18:11.000000000 +0100
@@ -72,7 +72,6 @@
         'jdcal',
         ],
     classifiers=[
-                 'Development Status :: 4 - Beta',
                  'Development Status :: 5 - Production/Stable',
                  'Operating System :: MacOS :: MacOS X',
                  'Operating System :: Microsoft :: Windows',


Reply via email to