Эх сурвалжийг харах

HUE-2523 [core] Add openpyxl to ext-py

Romain Rigaux 10 жил өмнө
parent
commit
ff69eb2eed
100 өөрчлөгдсөн 13120 нэмэгдсэн , 0 устгасан
  1. 66 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/AUTHORS.rst
  2. 34 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/LICENCE.rst
  3. 9 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/MANIFEST.in
  4. 72 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/PKG-INFO
  5. 51 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/README.rst
  6. 8 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/.constants.json
  7. 25 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/__init__.py
  8. 4 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/cell/__init__.py
  9. 409 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/cell/cell.py
  10. 61 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/cell/interface.py
  11. 146 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/cell/read_only.py
  12. 103 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/_3d.py
  13. 14 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/__init__.py
  14. 151 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/_chart.py
  15. 106 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/area_chart.py
  16. 381 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/axis.py
  17. 147 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/bar_chart.py
  18. 68 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/bubble_chart.py
  19. 444 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/chartspace.py
  20. 172 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/data_source.py
  21. 44 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/descriptors.py
  22. 60 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/error_bar.py
  23. 130 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/label.py
  24. 72 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/layout.py
  25. 71 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/legend.py
  26. 133 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/line_chart.py
  27. 100 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/marker.py
  28. 36 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/picture.py
  29. 175 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/pie_chart.py
  30. 54 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/radar_chart.py
  31. 127 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/reference.py
  32. 54 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/scatter_chart.py
  33. 196 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/series.py
  34. 42 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/series_factory.py
  35. 91 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/shapes.py
  36. 55 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/stock_chart.py
  37. 119 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/surface_chart.py
  38. 66 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/text.py
  39. 74 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/title.py
  40. 94 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/trendline.py
  41. 32 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/updown_bars.py
  42. 5 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/comments/__init__.py
  43. 49 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/comments/comments.py
  44. 81 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/__init__.py
  45. 9 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/abc.py
  46. 170 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/functools.py
  47. 37 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/itertools.py
  48. 14 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/numbers.py
  49. 269 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/odict.py
  50. 41 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/singleton.py
  51. 36 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/strings.py
  52. 50 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/conftest.py
  53. 57 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/__init__.py
  54. 261 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/base.py
  55. 66 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/excel.py
  56. 141 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/nested.py
  57. 144 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/serialisable.py
  58. 18 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/slots.py
  59. 5 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/__init__.py
  60. 323 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/colors.py
  61. 103 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/drawing.py
  62. 402 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/effect.py
  63. 349 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/fill.py
  64. 519 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/graphic.py
  65. 82 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/image.py
  66. 164 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/line.py
  67. 416 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/shape.py
  68. 537 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/shapes.py
  69. 298 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/spreadsheet_drawing.py
  70. 702 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/text.py
  71. 5 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formatting/__init__.py
  72. 50 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formatting/formatting.py
  73. 274 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formatting/rule.py
  74. 4 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formula/__init__.py
  75. 431 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formula/tokenizer.py
  76. 166 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formula/translate.py
  77. 3 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/packaging/__init__.py
  78. 46 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/packaging/relationship.py
  79. 11 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/__init__.py
  80. 54 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/comments.py
  81. 254 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/excel.py
  82. 44 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/strings.py
  83. 193 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/style.py
  84. 130 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/workbook.py
  85. 326 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/worksheet.py
  86. 63 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/__init__.py
  87. 73 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/alignment.py
  88. 107 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/borders.py
  89. 119 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/colors.py
  90. 62 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/differential.py
  91. 174 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/fills.py
  92. 101 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/fonts.py
  93. 86 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/hashable.py
  94. 94 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/named_styles.py
  95. 120 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/numbers.py
  96. 21 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/protection.py
  97. 47 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/proxy.py
  98. 208 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/styleable.py
  99. 183 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/utils/__init__.py
  100. 27 0
      desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/utils/bound_dictionary.py

+ 66 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/AUTHORS.rst

@@ -0,0 +1,66 @@
+This project is developed by Eric Gazoni.
+
+It is *heavily* inspired by the PHPExcel library that can be
+found here: http://www.phpexcel.net/
+
+Kudos goes to the PHPExcel team, I'm only standing on their shoulders.
+
+I'd also like to greatly thank all those who participate in the project (in alphabetical order):
+
+* Stephane Bard
+* Day Barr
+* Stefan Behnel
+* Bernt R. Brenna
+* Sven Burk
+* Anders Chrigstrom
+* ccoacley
+* Charlie Clark
+* Maarten De Paepe
+* Etienne Desautels
+* Eric Chlebek
+* Alexandre Fayolle
+* Eric Gazoni
+* Brice Gelineau
+* Alex Gronholm
+* Yaroslav Halchenko
+* Josh Haywood
+* Jeff Holman
+* Brent Hoover
+* Eric Hurkman
+* Jean Pierre Huart
+* JarekPS
+* Heikki Junes
+* Chi Ho Kwok
+* Yingjie Lan
+* Detlef Lannert
+* Nicholas Laver
+* Greg Lehmann
+* Adam Lofts
+* Marko Loparic
+* Samuel Loretan
+* Amin Mirzaee
+* Adam Morris
+* aceMueller
+* Gabi Nagy
+* Felipe Ochoa
+* Jun Omae
+* Waldemar Osuch
+* Jonathan Peirce
+* Sergey Pikhovkin
+* Ted Pollari
+* Elias Rabel
+* Rick Rankin
+* ramn_se
+* Philip Roche
+* James Smagala
+* Wolfgane Scherer
+* Joseph Tate
+* Dieter Vandenbussche
+* Paul Van Der Linden
+* Gerald Van Huffelen
+* Laurent Vasseur
+* Kay Webber
+* Shibukawa Yoshiki
+
+Project logo designed by Eric Gazoni, font by claudeserieux
+(http://www.dafont.com/profile.php?user=337503)

+ 34 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/LICENCE.rst

@@ -0,0 +1,34 @@
+This software is under the MIT Licence
+======================================
+
+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.
+
+Odict implementation in openpyxl/writer/odict.py uses the following licence:
+
+Copyright (c) 2001-2011 Python Software Foundation
+              2011 Raymond Hettinger
+License: PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+         See http://www.opensource.org/licenses/Python-2.0 for full terms
+Note: backport changes by Raymond were originally distributed under MIT
+      license, but since the original license for Python is more 
+      restrictive than MIT, code cannot be released under its terms and
+      still adheres to the limitations of Python license.

+ 9 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/MANIFEST.in

@@ -0,0 +1,9 @@
+prune openpyxl/tests
+prune openpyxl/sample
+prune openpyxl/benchmarks
+prune openpyxl/develop
+
+recursive-exclude openpyxl test_*.py tests/*.py
+
+include *.rst
+include openpyxl/.constants.json

+ 72 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/PKG-INFO

@@ -0,0 +1,72 @@
+Metadata-Version: 1.1
+Name: openpyxl
+Version: 2.3.0-b2
+Summary: A Python library to read/write Excel 2010 xlsx/xlsm files
+Home-page: http://openpyxl.readthedocs.org
+Author: See AUTHORS
+Author-email: eric.gazoni@gmail.com
+License: MIT/Expat
+Description: openpyxl
+        ========
+        
+        openpyxl is a Python library to read/write Excel 2010 xlsx/xlsm/xltx/xltm files.
+        
+        It was born from lack of existing library to read/write natively from Python
+        the Office Open XML format.
+        
+        All kudos to the PHPExcel team as openpyxl is based on PHPExcel
+        http://www.phpexcel.net/
+        
+        
+        Mailing List
+        ============
+        
+        Official user list can be found on
+        http://groups.google.com/group/openpyxl-users
+        
+        
+        Sample code::
+        
+            from openpyxl import Workbook
+            wb = Workbook()
+        
+            # grab the active worksheet
+            ws = wb.active
+        
+            # Data can be assigned directly to cells
+            ws['A1'] = 42
+        
+            # Rows can also be appended
+            ws.append([1, 2, 3])
+        
+            # Python types will automatically be converted
+            import datetime
+            ws['A2'] = datetime.datetime.now()
+        
+            # Save the file
+            wb.save("sample.xlsx")
+        
+        
+        Official documentation
+        ======================
+        
+        The documentation is at: http://openpyxl.readthedocs.org
+        
+        * installation methods
+        * code examples
+        * instructions for contributing
+        
+        Release notes: http://openpyxl.readthedocs.org/en/latest/changes.html
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Requires: python (>=2.6.0)

+ 51 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/README.rst

@@ -0,0 +1,51 @@
+openpyxl
+========
+
+openpyxl is a Python library to read/write Excel 2010 xlsx/xlsm/xltx/xltm files.
+
+It was born from lack of existing library to read/write natively from Python
+the Office Open XML format.
+
+All kudos to the PHPExcel team as openpyxl is based on PHPExcel
+http://www.phpexcel.net/
+
+
+Mailing List
+============
+
+Official user list can be found on
+http://groups.google.com/group/openpyxl-users
+
+
+Sample code::
+
+    from openpyxl import Workbook
+    wb = Workbook()
+
+    # grab the active worksheet
+    ws = wb.active
+
+    # Data can be assigned directly to cells
+    ws['A1'] = 42
+
+    # Rows can also be appended
+    ws.append([1, 2, 3])
+
+    # Python types will automatically be converted
+    import datetime
+    ws['A2'] = datetime.datetime.now()
+
+    # Save the file
+    wb.save("sample.xlsx")
+
+
+Official documentation
+======================
+
+The documentation is at: http://openpyxl.readthedocs.org
+
+* installation methods
+* code examples
+* instructions for contributing
+
+Release notes: http://openpyxl.readthedocs.org/en/latest/changes.html

+ 8 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/.constants.json

@@ -0,0 +1,8 @@
+{
+    "__author__": "See AUTHORS",
+    "__author_email__": "eric.gazoni@gmail.com",
+    "__license__": "MIT/Expat",
+    "__maintainer_email__": "openpyxl-users@googlegroups.com",
+    "__url__": "http://openpyxl.readthedocs.org",
+    "__version__": "2.3.0-b2"
+}

+ 25 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/__init__.py

@@ -0,0 +1,25 @@
+# Copyright (c) 2010-2015 openpyxl
+
+# @license: http://www.opensource.org/licenses/mit-license.php
+# @author: see AUTHORS file
+
+
+import json
+import os
+
+here = os.path.abspath(os.path.dirname(__file__))
+src_file = os.path.join(here, ".constants.json")
+with open(src_file) as src:
+    constants = json.load(src)
+    __author__ = constants['__author__']
+    __author_email__ = constants["__author_email__"]
+    __license__ = constants["__license__"]
+    __maintainer_email__ = constants["__maintainer_email__"]
+    __url__ = constants["__url__"]
+    __version__ = constants["__version__"]
+
+"""Imports for the openpyxl package."""
+from openpyxl.xml import LXML
+
+from openpyxl.workbook import Workbook
+from openpyxl.reader.excel import load_workbook

+ 4 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/cell/__init__.py

@@ -0,0 +1,4 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from .cell import *

+ 409 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/cell/cell.py

@@ -0,0 +1,409 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+"""Manage individual cells in a spreadsheet.
+
+The Cell class is required to know its value and type, display options,
+and any other features of an Excel cell.  Utilities for referencing
+cells using Excel's 'A1' column/row nomenclature are also provided.
+
+"""
+
+__docformat__ = "restructuredtext en"
+
+# Python stdlib imports
+import datetime
+import re
+
+from openpyxl.compat import (
+    unicode,
+    basestring,
+    bytes,
+    NUMERIC_TYPES,
+    range,
+    deprecated,
+)
+from openpyxl.utils.units import (
+    DEFAULT_ROW_HEIGHT,
+    DEFAULT_COLUMN_WIDTH
+)
+from openpyxl.utils.datetime  import (
+    to_excel,
+    time_to_days,
+    timedelta_to_days,
+    from_excel
+    )
+from openpyxl.utils.exceptions import (
+    IllegalCharacterError
+)
+from openpyxl.utils.units import points_to_pixels
+from openpyxl.utils import (
+    get_column_letter,
+    column_index_from_string,
+)
+from openpyxl.styles import numbers, is_date_format
+from openpyxl.styles.styleable import StyleableObject
+from openpyxl.worksheet.hyperlink import Hyperlink
+
+# constants
+
+
+TIME_TYPES = (datetime.datetime, datetime.date, datetime.time, datetime.timedelta)
+STRING_TYPES = (basestring, unicode, bytes)
+KNOWN_TYPES = NUMERIC_TYPES + TIME_TYPES + STRING_TYPES + (bool, type(None))
+
+PERCENT_REGEX = re.compile(r'^\-?(?P<number>[0-9]*\.?[0-9]*\s?)\%$')
+TIME_REGEX = re.compile(r"""
+^(?: # HH:MM and HH:MM:SS
+(?P<hour>[0-1]{0,1}[0-9]{2}):
+(?P<minute>[0-5][0-9]):?
+(?P<second>[0-5][0-9])?$)
+|
+^(?: # MM:SS.
+([0-5][0-9]):
+([0-5][0-9])?\.
+(?P<microsecond>\d{1,6}))
+""", re.VERBOSE)
+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.
+
+    Properties of interest include style, type, value, and address.
+
+    """
+    __slots__ = (
+        'row',
+        'col_idx',
+        '_value',
+        'data_type',
+        'parent',
+        '_hyperlink',
+        '_comment',
+                 )
+
+    ERROR_CODES = ERROR_CODES
+
+    TYPE_STRING = 's'
+    TYPE_FORMULA = 'f'
+    TYPE_NUMERIC = 'n'
+    TYPE_BOOL = 'b'
+    TYPE_NULL = 'n'
+    TYPE_INLINE = 'inlineStr'
+    TYPE_ERROR = 'e'
+    TYPE_FORMULA_CACHE_STRING = 'str'
+
+    VALID_TYPES = (TYPE_STRING, TYPE_FORMULA, TYPE_NUMERIC, TYPE_BOOL,
+                   TYPE_NULL, TYPE_INLINE, TYPE_ERROR, TYPE_FORMULA_CACHE_STRING)
+
+
+    def __init__(self, worksheet, column=None, row=None, value=None, col_idx=None, style_array=None):
+        super(Cell, self).__init__(worksheet, style_array)
+        self.row = row
+        # _value is the stored value, while value is the displayed value
+        self._value = None
+        self._hyperlink = None
+        self.data_type = 'n'
+        if value is not None:
+            self.value = value
+        self._comment = None
+        if column is not None:
+            col_idx = column_index_from_string(column)
+        self.col_idx = col_idx
+
+
+    @property
+    def coordinate(self):
+        return '%s%d' % (self.column, self.row)
+
+    @property
+    def column(self):
+        return get_column_letter(self.col_idx)
+
+    @property
+    def encoding(self):
+        return self.parent.encoding
+
+    @property
+    def base_date(self):
+        return self.parent.parent.excel_base_date
+
+    @property
+    def guess_types(self):
+        return getattr(self.parent.parent, '_guess_types', False)
+
+    def __repr__(self):
+        return unicode("<Cell %s.%s>") % (self.parent.title, self.coordinate)
+
+    def check_string(self, value):
+        """Check string coding, length, and line break character"""
+        if value is None:
+            return
+        # convert to unicode string
+        if not isinstance(value, unicode):
+            value = unicode(value, self.encoding)
+        value = unicode(value)
+        # string must never be longer than 32,767 characters
+        # truncate if necessary
+        value = value[:32767]
+        if next(ILLEGAL_CHARACTERS_RE.finditer(value), None):
+            raise IllegalCharacterError
+        return value
+
+    def check_error(self, value):
+        """Tries to convert Error" else N/A"""
+        try:
+            return unicode(value)
+        except:
+            return unicode('#N/A')
+
+    def set_explicit_value(self, value=None, data_type=TYPE_STRING):
+        """Coerce values according to their explicit type"""
+        if data_type not in self.VALID_TYPES:
+            raise ValueError('Invalid data type: %s' % data_type)
+        if isinstance(value, STRING_TYPES):
+            value = self.check_string(value)
+        self._value = value
+        self.data_type = data_type
+
+
+    @deprecated("Method is private")
+    def bind_value(self, value):
+        self._bind_value(value)
+
+
+    def _bind_value(self, value):
+        """Given a value, infer the correct data type"""
+
+        self.data_type = "n"
+
+        if value is True or value is False:
+            self.data_type = self.TYPE_BOOL
+
+        elif isinstance(value, NUMERIC_TYPES):
+            pass
+
+        elif isinstance(value, NUMERIC_TYPES):
+            self.data_type = self.TYPE_NUMERIC
+
+        elif isinstance(value, TIME_TYPES):
+            self.data_type = self.TYPE_NUMERIC
+            value = self._cast_datetime(value)
+
+        elif isinstance(value, STRING_TYPES):
+            value = self.check_string(value)
+            self.data_type = self.TYPE_STRING
+            if len(value) > 1 and value.startswith("="):
+                self.data_type = self.TYPE_FORMULA
+            elif value in self.ERROR_CODES:
+                self.data_type = self.TYPE_ERROR
+            elif self.guess_types:
+                value = self._infer_value(value)
+
+        elif value is not None:
+            raise ValueError("Cannot convert {0} to Excel".format(value))
+
+        self._value = value
+
+
+    @deprecated("Method is private")
+    def infer_value(self, value):
+        return self._infer_value(value)
+
+
+    def _infer_value(self, value):
+        """Given a string, infer type and formatting options."""
+        if not isinstance(value, unicode):
+            value = str(value)
+
+        # number detection
+        v = self._cast_numeric(value)
+        if v is None:
+            # percentage detection
+            v = self._cast_percentage(value)
+        if v is None:
+            # time detection
+            v = self._cast_time(value)
+        if v is not None:
+            self.data_type = self.TYPE_NUMERIC
+            return v
+
+        return value
+
+
+    def _cast_numeric(self, value):
+        """Explicity convert a string to a numeric value"""
+        if NUMBER_REGEX.match(value):
+            try:
+                return int(value)
+            except ValueError:
+                return float(value)
+
+    def _cast_percentage(self, value):
+        """Explicitly convert a string to numeric value and format as a
+        percentage"""
+        match = PERCENT_REGEX.match(value)
+        if match:
+            self.number_format = numbers.FORMAT_PERCENTAGE
+            return float(match.group('number')) / 100
+
+
+    def _cast_time(self, value):
+        """Explicitly convert a string to a number and format as datetime or
+        time"""
+        match = TIME_REGEX.match(value)
+        if match:
+            if match.group("microsecond") is not None:
+                value = value[:12]
+                pattern = "%M:%S.%f"
+                fmt = numbers.FORMAT_DATE_TIME5
+            elif match.group('second') is None:
+                fmt = numbers.FORMAT_DATE_TIME3
+                pattern = "%H:%M"
+            else:
+                pattern = "%H:%M:%S"
+                fmt = numbers.FORMAT_DATE_TIME6
+            value = datetime.datetime.strptime(value, pattern)
+            self.number_format = fmt
+            return time_to_days(value)
+
+
+    def _cast_datetime(self, value):
+        """Convert Python datetime to Excel and set formatting"""
+        if isinstance(value, datetime.datetime):
+            value = to_excel(value, self.base_date)
+            self.number_format = numbers.FORMAT_DATE_DATETIME
+        elif isinstance(value, datetime.date):
+            value = to_excel(value, self.base_date)
+            self.number_format = numbers.FORMAT_DATE_YYYYMMDD2
+        elif isinstance(value, datetime.time):
+            value = time_to_days(value)
+            self.number_format = numbers.FORMAT_DATE_TIME6
+        elif isinstance(value, datetime.timedelta):
+            value = timedelta_to_days(value)
+            self.number_format = numbers.FORMAT_DATE_TIMEDELTA
+        return value
+
+    @property
+    def value(self):
+        """Get or set the value held in the cell.
+            ':rtype: depends on the value (string, float, int or '
+            ':class:`datetime.datetime`)'"""
+        value = self._value
+        if value is not None and self.is_date:
+            value = from_excel(value, self.base_date)
+        return value
+
+    @value.setter
+    def value(self, value):
+        """Set the value and infer type and display options."""
+        self._bind_value(value)
+
+    @property
+    def internal_value(self):
+        """Always returns the value for excel."""
+        return self._value
+
+    @property
+    def hyperlink(self):
+        """Return the hyperlink target or an empty string"""
+        return self._hyperlink
+
+    @hyperlink.setter
+    def hyperlink(self, val):
+        """Set value and display for hyperlinks in a cell.
+        Automatically sets the `value` of the cell with link text,
+        but you can modify it afterwards by setting the `value`
+        property, and the hyperlink will remain."""
+        self._hyperlink = Hyperlink(ref=self.coordinate, target=val)
+        self.parent.hyperlinks.add(self)
+        if self._value is None:
+            self.value = val
+
+    @property
+    def is_date(self):
+        """Whether the value is formatted as a date
+
+        :rtype: bool
+        """
+        if self.data_type == "n" and self.number_format != "General":
+            return is_date_format(self.number_format)
+        return False
+
+    def offset(self, row=0, column=0):
+        """Returns a cell location relative to this cell.
+
+        :param row: number of rows to offset
+        :type row: int
+
+        :param column: number of columns to offset
+        :type column: int
+
+        :rtype: :class:`openpyxl.cell.Cell`
+        """
+        offset_column = self.col_idx + column
+        offset_row = self.row + row
+        return self.parent.cell(column=offset_column, row=offset_row)
+
+    @property
+    def anchor(self):
+        """ returns the expected position of a cell in pixels from the top-left
+            of the sheet. For example, A1 anchor should be (0,0).
+
+            :rtype: tuple(int, int)
+        """
+        left_columns = (column_index_from_string(self.column) - 1)
+        column_dimensions = self.parent.column_dimensions
+        left_anchor = 0
+        default_width = points_to_pixels(DEFAULT_COLUMN_WIDTH)
+
+        for col_idx in range(left_columns):
+            letter = get_column_letter(col_idx + 1)
+            if letter in column_dimensions:
+                cdw = column_dimensions.get(letter).width or default_width
+                if cdw > 0:
+                    left_anchor += points_to_pixels(cdw)
+                    continue
+            left_anchor += default_width
+
+        row_dimensions = self.parent.row_dimensions
+        top_anchor = 0
+        top_rows = (self.row - 1)
+        default_height = points_to_pixels(DEFAULT_ROW_HEIGHT)
+        for row_idx in range(1, top_rows + 1):
+            if row_idx in row_dimensions:
+                rdh = row_dimensions[row_idx].height or default_height
+                if rdh > 0:
+                    top_anchor += points_to_pixels(rdh)
+                    continue
+            top_anchor += default_height
+
+        return (left_anchor, top_anchor)
+
+    @property
+    def comment(self):
+        """ Returns the comment associated with this cell
+
+            :rtype: :class:`openpyxl.comments.Comment`
+        """
+        return self._comment
+
+    @comment.setter
+    def comment(self, value):
+
+        # Ensure the number of comments for the parent worksheet is up-to-date
+        if value is None and self._comment is not None:
+            self.parent._comment_count -= 1
+        if value is not None and self._comment is None:
+            self.parent._comment_count += 1
+
+        if value is not None:
+            value.parent = self
+        elif value is None and self._comment:
+            self._comment.parent = None
+        self._comment = value

+ 61 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/cell/interface.py

@@ -0,0 +1,61 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.compat.abc import ABC
+from abc import abstractmethod, abstractproperty
+
+
+class AbstractCell(ABC):
+
+
+    def __init__(self, value=None):
+        self.value = value
+
+    @abstractproperty
+    def encoding(self):
+        pass
+
+    @abstractproperty
+    def coordinate(self):
+        pass
+
+    @abstractproperty
+    def base_date(self):
+        pass
+
+    @abstractproperty
+    def guess_types(self):
+        pass
+
+    @abstractproperty
+    def value(self):
+        pass
+
+    @abstractproperty
+    def internal_value(self):
+        pass
+
+    @abstractmethod
+    def __repr__(self):
+        pass
+
+    @abstractmethod
+    def offset(self, row=0, column=0):
+        pass
+
+    @abstractproperty
+    def comment(self):
+        pass
+
+    @abstractproperty
+    def style(self):
+        pass
+
+    @abstractproperty
+    def number_format(self):
+        pass
+
+    @abstractproperty
+    def is_date(self):
+        pass
+

+ 146 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/cell/read_only.py

@@ -0,0 +1,146 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+import re
+
+from openpyxl.compat import unicode, long
+
+from openpyxl.cell import Cell
+from openpyxl.utils import get_column_letter
+from openpyxl.utils.datetime import from_excel
+from openpyxl.styles import is_date_format, Style
+from openpyxl.styles.numbers import BUILTIN_FORMATS
+
+
+FLOAT_REGEX = re.compile(r"\.|[E-e]")
+
+
+def _cast_number(value):
+    "Convert numbers as string to an int or float"
+    m = FLOAT_REGEX.search(value)
+    if m is not None:
+        return float(value)
+    return long(value)
+
+
+class ReadOnlyCell(object):
+
+    __slots__ =  ('parent', 'row', 'column', '_value', 'data_type', '_style_id')
+
+    def __init__(self, sheet, row, column, value, data_type='n', style_id=None):
+        self.parent = sheet
+        self._value = None
+        self.row = row
+        self.column = column
+        self.data_type = data_type
+        self.value = value
+        self._style_id = style_id
+
+    def __eq__(self, other):
+        for a in self.__slots__:
+            if getattr(self, a) != getattr(other, a):
+                return
+        return True
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    @property
+    def shared_strings(self):
+        return self.parent.shared_strings
+
+    @property
+    def base_date(self):
+        return self.parent.base_date
+
+    @property
+    def coordinate(self):
+        if self.row is None or self.column is None:
+            raise AttributeError("Empty cells have no coordinates")
+        column = get_column_letter(self.column)
+        return "{1}{0}".format(self.row, column)
+
+    @property
+    def style_array(self):
+        if not self._style_id:
+            return
+        return self.parent.parent._cell_styles[self._style_id]
+
+    @property
+    def number_format(self):
+        if not self.style_array:
+            return
+        _id = self.style_array.numFmtId
+        if _id < 164:
+            return BUILTIN_FORMATS.get(_id, "General")
+        else:
+            return self.parent.parent._number_formats[_id - 164]
+
+    @property
+    def font(self):
+        _id = self.style_array.fontId
+        return self.parent.parent._fonts[_id]
+
+    @property
+    def fill(self):
+        _id = self.style_array.fillId
+        return self.parent.parent._fills[_id]
+
+    @property
+    def border(self):
+        _id = self.style_array.borderId
+        return self.parent.parent._borders[_id]
+
+    @property
+    def alignment(self):
+        _id = self.style_array.alignmentId
+        return self.parent.parent._alignments[_id]
+
+    @property
+    def protection(self):
+        _id = self.style_array.protectionId
+        return self.parent.parent._protections[_id]
+
+    @property
+    def is_date(self):
+        return self.data_type == 'n' and is_date_format(self.number_format)
+
+    @property
+    def internal_value(self):
+        return self._value
+
+    @property
+    def value(self):
+        if self._value is None:
+            return
+        if self.data_type == 'n':
+            if self.style_array:
+                if is_date_format(self.number_format):
+                    return from_excel(self._value, self.base_date)
+            return self._value
+        if self.data_type == 'b':
+            return self._value == '1'
+        elif self.data_type in(Cell.TYPE_INLINE, Cell.TYPE_FORMULA_CACHE_STRING):
+            return unicode(self._value)
+        elif self.data_type == 's':
+            return unicode(self.shared_strings[int(self._value)])
+        return self._value
+
+    @value.setter
+    def value(self, value):
+        if self._value is not None:
+            raise AttributeError("Cell is read only")
+        if value is None:
+            self.data_type = 'n'
+        elif self.data_type == 'n':
+            value = _cast_number(value)
+        self._value = value
+
+    @property
+    def style(self):
+        return Style(font=self.font, alignment=self.alignment,
+                     fill=self.fill, number_format=self.number_format, border=self.border,
+                     protection=self.protection)
+
+
+EMPTY_CELL = ReadOnlyCell(None, None, None, None)

+ 103 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/_3d.py

@@ -0,0 +1,103 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors import Typed, Alias
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors.nested import (
+    NestedBool,
+    NestedInteger,
+    NestedMinMax,
+)
+from openpyxl.descriptors.excel import ExtensionList
+from .marker import PictureOptions
+from .shapes import ShapeProperties
+
+
+class View3D(Serialisable):
+
+    tagname = "view3D"
+
+    rotX = NestedMinMax(min=-90, max=90, allow_none=True)
+    x_rotation = Alias('rotX')
+    hPercent = NestedMinMax(min=5, max=500, allow_none=True)
+    height_percent = Alias('hPercent')
+    rotY = NestedInteger(min=-90, max=90, allow_none=True)
+    y_rotation = Alias('rotY')
+    depthPercent = NestedInteger(allow_none=True)
+    rAngAx = NestedBool(allow_none=True)
+    right_angle_axes = Alias('rAngAx')
+    perspective = NestedInteger(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('rotX', 'hPercent', 'rotY', 'depthPercent', 'rAngAx',
+                    'perspective',)
+
+    def __init__(self,
+                 rotX=15,
+                 hPercent=None,
+                 rotY=20,
+                 depthPercent=None,
+                 rAngAx=True,
+                 perspective=None,
+                 extLst=None,
+                ):
+        self.rotX = rotX
+        self.hPercent = hPercent
+        self.rotY = rotY
+        self.depthPercent = depthPercent
+        self.rAngAx = rAngAx
+        self.perspective = perspective
+
+
+class Surface(Serialisable):
+
+    tagname = "surface"
+
+    thickness = NestedInteger(allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    shapeProperties = Alias('spPr')
+    pictureOptions = Typed(expected_type=PictureOptions, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('thickness', 'spPr', 'pictureOptions',)
+
+    def __init__(self,
+                 thickness=None,
+                 spPr=None,
+                 pictureOptions=None,
+                 extLst=None,
+                ):
+        self.thickness = thickness
+        self.spPr = spPr
+        self.pictureOptions = pictureOptions
+
+
+class _3DBase(Serialisable):
+
+    """
+    Base class for 3D charts
+    """
+
+    view3D = Typed(expected_type=View3D, allow_none=True)
+    floor = Typed(expected_type=Surface, allow_none=True)
+    sideWall = Typed(expected_type=Surface, allow_none=True)
+    backWall = Typed(expected_type=Surface, allow_none=True)
+
+    def __init__(self,
+                 view3D=None,
+                 floor=None,
+                 sideWall=None,
+                 backWall=None
+                 ):
+        if view3D is None:
+            view3D = View3D()
+        self.view3D = view3D
+        if floor is None:
+            floor = Surface()
+        self.floor = floor
+        if sideWall is None:
+            sideWall = Surface()
+        self.sideWall = sideWall
+        if backWall is None:
+            backWall = Surface()
+        self.backWall = backWall

+ 14 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/__init__.py

@@ -0,0 +1,14 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from .area_chart import AreaChart, AreaChart3D
+from .bar_chart import BarChart, BarChart3D
+from .bubble_chart import BubbleChart
+from .line_chart import LineChart, LineChart3D
+from .pie_chart import PieChart, PieChart3D, DoughnutChart, ProjectedPieChart
+from .scatter_chart import ScatterChart
+from .stock_chart import StockChart
+from .surface_chart import SurfaceChart, SurfaceChart3D
+
+from .series_factory import SeriesFactory as Series
+from .reference import Reference

+ 151 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/_chart.py

@@ -0,0 +1,151 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.compat import basestring
+
+from openpyxl.descriptors import Typed, Integer, Alias
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.xml.constants import CHART_NS, PACKAGE_CHARTS
+
+from ._3d import _3DBase
+from .data_source import AxDataSource, NumRef
+from .legend import Legend
+from .reference import Reference
+from .series_factory import SeriesFactory
+from .series import attribute_mapping
+from .shapes import ShapeProperties
+from .title import TitleDescriptor
+
+class AxId(Serialisable):
+
+    val = Integer()
+
+    def __init__(self, val):
+        self.val = val
+
+
+class ChartBase(Serialisable):
+
+    """
+    Base class for all charts
+    """
+
+    legend = Typed(expected_type=Legend, allow_none=True)
+
+    _series_type = ""
+    ser = ()
+    series = Alias('ser')
+    title = TitleDescriptor()
+    anchor = "E15" # default anchor position
+    width = 15 # in cm, approx 5 rows
+    height = 7.5 # in cm, approx 14 rows
+    _id = 1
+    style = Integer(allow_none=True)
+    graphical_properties = Typed(expected_type=ShapeProperties, allow_none=True)
+
+    __elements__ = ()
+
+    def __init__(self, **kw):
+        self._charts = [self]
+        self.title = None
+        self.legend = Legend()
+        self.graphical_properties = None
+        self.style = None
+        super(ChartBase, self).__init__(**kw)
+
+    def __hash__(self):
+        """
+        Just need to check for identity
+        """
+        return id(self)
+
+    def __iadd__(self, other):
+        """
+        Combine the chart with another one
+        """
+        if not isinstance(other, ChartBase):
+            raise TypeError("Only other charts can be added")
+        self._charts.append(other)
+        return self
+
+
+    def to_tree(self, tagname=None, idx=None):
+        if self.ser is not None:
+            for s in self.ser:
+                s.__elements__ = attribute_mapping[self._series_type]
+        return super(ChartBase, self).to_tree(tagname, idx)
+
+
+    def _write(self):
+        from .chartspace import ChartSpace, ChartContainer, PlotArea
+        plot = PlotArea()
+        plot.graphical_properties = self.graphical_properties
+        idx_base = 0
+        for chart in self._charts:
+            chart.idx_base = idx_base
+            plot._charts.append(chart)
+            idx_base += len(chart.series)
+
+        for axis in ("x_axis", "y_axis", 'z_axis'):
+            axis = getattr(self, axis, None)
+            if axis is None:
+                continue
+            ax = getattr(plot, axis.tagname)
+            ax.append(axis)
+
+        container = ChartContainer(plotArea=plot, legend=self.legend, title=self.title)
+        if isinstance(chart, _3DBase):
+            container.view3D = chart.view3D
+            container.floor = chart.floor
+            container.sideWall = chart.sideWall
+            container.backWall = chart.backWall
+        cs = ChartSpace(chart=container)
+        cs.style = self.style
+        tree = cs.to_tree()
+        tree.set("xmlns", CHART_NS)
+        return tree
+
+
+    @property
+    def axId(self):
+        x = getattr(self, "x_axis", None)
+        y = getattr(self, "y_axis", None)
+        z = getattr(self, "z_axis", None)
+        ids = [AxId(axis.axId) for axis in (x, y, z) if axis]
+
+        return ids
+
+
+    def set_categories(self, labels):
+        """
+        Set the categories / x-axis values
+        """
+        if not isinstance(labels, Reference):
+            labels = Reference(range_string=labels)
+        for s in self.ser:
+            s.cat = AxDataSource(numRef=NumRef(f=labels))
+
+
+    def add_data(self, data, from_rows=False, titles_from_data=False):
+        """
+        Add a range of data in a single pass.
+        The default is to treat each column as a data series.
+        """
+        if not isinstance(data, Reference):
+            data = Reference(range_string=data)
+
+        if from_rows:
+            values = data.rows
+
+        else:
+            values = data.cols
+
+        for v in values:
+            range_string = "{0}!{1}:{2}".format(data.sheetname, v[0], v[-1])
+            series = SeriesFactory(range_string, title_from_data=titles_from_data)
+            self.ser.append(series)
+
+
+    @property
+    def _path(self):
+        return PACKAGE_CHARTS + '/chart{0}.xml'.format(self._id)

+ 106 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/area_chart.py

@@ -0,0 +1,106 @@
+from __future__ import absolute_import
+#Autogenerated schema
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Set,
+    Bool,
+    Integer,
+    Sequence,
+    Alias,
+)
+
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedMinMax,
+    NestedSet,
+    NestedBool,
+)
+
+from ._chart import ChartBase
+from .descriptors import NestedGapAmount
+from .axis import TextAxis, NumericAxis, SeriesAxis, ChartLines
+from .label import DataLabels
+from .series import Series
+
+
+class _AreaChartBase(ChartBase):
+
+    grouping = NestedSet(values=(['percentStacked', 'standard', 'stacked']))
+    varyColors = NestedBool(nested=True, allow_none=True)
+    ser = Sequence(expected_type=Series, allow_none=True)
+    dLbls = Typed(expected_type=DataLabels, allow_none=True)
+    dataLabels = Alias("dLbls")
+    dropLines = Typed(expected_type=ChartLines, allow_none=True)
+
+    _series_type = "area"
+
+    __elements__ = ('grouping', 'varyColors', 'ser', 'dLbls', 'dropLines')
+
+    def __init__(self,
+                 grouping="standard",
+                 varyColors=None,
+                 ser=(),
+                 dLbls=None,
+                 dropLines=None,
+                ):
+        self.grouping = grouping
+        self.varyColors = varyColors
+        self.ser = ser
+        self.dLbls = dLbls
+        self.dropLines = dropLines
+        super(_AreaChartBase, self).__init__()
+
+
+class AreaChart(_AreaChartBase):
+
+    tagname = "areaChart"
+
+    grouping = _AreaChartBase.grouping
+    varyColors = _AreaChartBase.varyColors
+    ser = _AreaChartBase.ser
+    dLbls = _AreaChartBase.dLbls
+    dropLines = _AreaChartBase.dropLines
+
+    # chart properties actually used by containing classes
+    x_axis = Typed(expected_type=TextAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = _AreaChartBase.__elements__ + ('axId',)
+
+    def __init__(self,
+                 axId=None,
+                 extLst=None,
+                 **kw
+                ):
+        self.x_axis = TextAxis()
+        self.y_axis = NumericAxis()
+        super(AreaChart, self).__init__(**kw)
+
+
+class AreaChart3D(AreaChart):
+
+    tagname = "area3DChart"
+
+    grouping = _AreaChartBase.grouping
+    varyColors = _AreaChartBase.varyColors
+    ser = _AreaChartBase.ser
+    dLbls = _AreaChartBase.dLbls
+    dropLines = _AreaChartBase.dropLines
+
+    gapDepth = NestedGapAmount()
+
+    x_axis = Typed(expected_type=TextAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+    z_axis = Typed(expected_type=SeriesAxis, allow_none=True)
+
+    __elements__ = AreaChart.__elements__ + ('gapDepth', )
+
+    def __init__(self, gapDepth=None, **kw):
+        self.gapDepth = gapDepth
+        super(AreaChart3D, self).__init__(**kw)
+        self.x_axis = TextAxis()
+        self.y_axis = NumericAxis()
+        self.z_axis = SeriesAxis()

+ 381 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/axis.py

@@ -0,0 +1,381 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Float,
+    NoneSet,
+    Bool,
+    Integer,
+    MinMax,
+    NoneSet,
+    Set,
+    String,
+    Alias,
+)
+
+from openpyxl.descriptors.excel import ExtensionList, Percentage
+from openpyxl.descriptors.nested import (
+    NestedValue,
+    NestedSet,
+    NestedBool,
+    NestedNoneSet,
+    NestedFloat,
+    NestedInteger,
+    NestedMinMax,
+    NestedSequence,
+)
+
+from .descriptors import NumberFormatDescriptor
+from .layout import Layout
+from .text import Text, RichText
+from .shapes import ShapeProperties
+from .title import Title, TitleDescriptor
+
+
+class ChartLines(Serialisable):
+
+    tagname = "chartLines"
+
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    shapeProperties = Alias('spPr')
+
+    def __init__(self, spPr=None):
+        self.spPr = spPr
+
+
+class Scaling(Serialisable):
+
+    tagname = "scaling"
+
+    logBase = NestedFloat(allow_none=True)
+    orientation = NestedSet(values=(['maxMin', 'minMax']))
+    max = NestedFloat(allow_none=True)
+    min = NestedFloat(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('logBase', 'orientation', 'max', 'min',)
+
+    def __init__(self,
+                 logBase=None,
+                 orientation="minMax",
+                 max=None,
+                 min=None,
+                 extLst=None,
+                ):
+        self.logBase = logBase
+        self.orientation = orientation
+        self.max = max
+        self.min = min
+
+
+class _BaseAxis(Serialisable):
+
+    axId = NestedInteger(expected_type=int)
+    scaling = Typed(expected_type=Scaling)
+    delete = NestedBool(allow_none=True)
+    axPos = NestedSet(values=(['b', 'l', 'r', 't']))
+    majorGridlines = Typed(expected_type=ChartLines, allow_none=True)
+    minorGridlines = Typed(expected_type=ChartLines, allow_none=True)
+    title = TitleDescriptor()
+    numFmt = NumberFormatDescriptor()
+    number_format = Alias("numFmt")
+    majorTickMark = NestedNoneSet(values=(['cross', 'in', 'out']))
+    minorTickMark = NestedNoneSet(values=(['cross', 'in', 'out']))
+    tickLblPos = NestedNoneSet(values=(['high', 'low', 'nextTo']))
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    shapeProperties = Alias('spPr')
+    txPr = Typed(expected_type=RichText, allow_none=True)
+    textProperties = Alias('txPr')
+    crossAx = NestedInteger(expected_type=int) # references other axis
+    crosses = NestedNoneSet(values=(['autoZero', 'max', 'min']))
+    crossesAt = NestedFloat(allow_none=True)
+
+    # crosses & crossesAt are mutually exclusive
+
+    __elements__ = ('axId', 'scaling', 'delete', 'axPos', 'majorGridlines',
+                    'minorGridlines', 'numFmt', 'majorTickMark', 'minorTickMark',
+                    'tickLblPos', 'spPr', 'title', 'txPr', 'crossAx', 'crosses', 'crossesAt')
+
+    def __init__(self,
+                 axId=None,
+                 scaling=None,
+                 delete=None,
+                 axPos='l',
+                 majorGridlines=None,
+                 minorGridlines=None,
+                 title=None,
+                 numFmt=None,
+                 majorTickMark=None,
+                 minorTickMark=None,
+                 tickLblPos=None,
+                 spPr=None,
+                 txPr= None,
+                 crossAx=None,
+                 crosses=None,
+                 crossesAt=None,
+                ):
+        self.axId = axId
+        if scaling is None:
+            scaling = Scaling()
+        self.scaling = Scaling()
+        self.delete = delete
+        self.axPos = axPos
+        self.majorGridlines = majorGridlines
+        self.minorGridlines = minorGridlines
+        self.title = title
+        self.numFmt = numFmt
+        self.majorTickMark = majorTickMark
+        self.minorTickMark = minorTickMark
+        self.tickLblPos = tickLblPos
+        self.spPr = spPr
+        self.txPr = txPr
+        self.crossAx = crossAx
+        self.crosses = crosses
+        self.crossesAt = None
+
+
+class DisplayUnitsLabel(Serialisable):
+
+    tagname = "dispUnitsLbl"
+
+    layout = Typed(expected_type=Layout, allow_none=True)
+    tx = Typed(expected_type=Text, allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    txPr = Typed(expected_type=RichText, allow_none=True)
+
+    __elements__ = ('layout', 'tx', 'spPr', 'txPr')
+
+    def __init__(self,
+                 layout=None,
+                 tx=None,
+                 spPr=None,
+                 txPr=None,
+                ):
+        self.layout = layout
+        self.tx = tx
+        self.spPr = spPr
+        self.txPr = txPr
+
+
+class DisplayUnits(Serialisable):
+
+    tagname = "dispUnits"
+
+    custUnit = NestedFloat(allow_none=True)
+    builtInUnit = NestedNoneSet(values=(['hundreds', 'thousands',
+                                         'tenThousands', 'hundredThousands', 'millions', 'tenMillions',
+                                         'hundredMillions', 'billions', 'trillions']))
+    dispUnitsLbl = Typed(expected_type=DisplayUnitsLabel, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('custUnit', 'builtInUnit', 'dispUnitsLbl',)
+
+    def __init__(self,
+                 custUnit=None,
+                 builtInUnit=None,
+                 dispUnitsLbl=None,
+                 extLst=None,
+                ):
+        self.custUnit = custUnit
+        self.builtInUnit = builtInUnit
+        self.dispUnitsLbl = dispUnitsLbl
+
+
+class NumericAxis(_BaseAxis):
+
+    tagname = "valAx"
+
+    axId = _BaseAxis.axId
+    scaling = _BaseAxis.scaling
+    delete = _BaseAxis.delete
+    axPos = _BaseAxis.axPos
+    majorGridlines = _BaseAxis.majorGridlines
+    minorGridlines = _BaseAxis.minorGridlines
+    title = _BaseAxis.title
+    numFmt = _BaseAxis.numFmt
+    majorTickMark = _BaseAxis.majorTickMark
+    minorTickMark = _BaseAxis.minorTickMark
+    tickLblPos = _BaseAxis.tickLblPos
+    spPr = _BaseAxis.spPr
+    txPr = _BaseAxis.txPr
+    crossAx = _BaseAxis.crossAx
+    crosses = _BaseAxis.crosses
+    crossesAt = _BaseAxis.crossesAt
+
+    crossBetween = NestedNoneSet(values=(['between', 'midCat']))
+    majorUnit = NestedFloat(allow_none=True)
+    minorUnit = NestedFloat(allow_none=True)
+    dispUnits = Typed(expected_type=DisplayUnits, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = _BaseAxis.__elements__ + ('crossBetween', 'majorUnit',
+                                             'minorUnit', 'dispUnits',)
+
+
+    def __init__(self,
+                 crossBetween=None,
+                 majorUnit=None,
+                 minorUnit=None,
+                 dispUnits=None,
+                 extLst=None,
+                 **kw
+                ):
+        self.crossBetween = crossBetween
+        self.majorUnit = majorUnit
+        self.minorUnit = minorUnit
+        self.dispUnits = dispUnits
+        kw.setdefault('majorGridlines', ChartLines())
+        kw.setdefault('axId', 100)
+        kw.setdefault('crossAx', 10)
+        super(NumericAxis, self).__init__(**kw)
+
+
+class TextAxis(_BaseAxis):
+
+    tagname = "catAx"
+
+    axId = _BaseAxis.axId
+    scaling = _BaseAxis.scaling
+    delete = _BaseAxis.delete
+    axPos = _BaseAxis.axPos
+    majorGridlines = _BaseAxis.majorGridlines
+    minorGridlines = _BaseAxis.minorGridlines
+    title = _BaseAxis.title
+    numFmt = _BaseAxis.numFmt
+    majorTickMark = _BaseAxis.majorTickMark
+    minorTickMark = _BaseAxis.minorTickMark
+    tickLblPos = _BaseAxis.tickLblPos
+    spPr = _BaseAxis.spPr
+    txPr = _BaseAxis.txPr
+    crossAx = _BaseAxis.crossAx
+    crosses = _BaseAxis.crosses
+    crossesAt = _BaseAxis.crossesAt
+
+    auto = NestedBool(allow_none=True)
+    lblAlgn = NestedNoneSet(values=(['ctr', 'l', 'r']))
+    lblOffset = NestedMinMax(min=0, max=1000)
+    tickLblSkip = NestedInteger(allow_none=True)
+    tickMarkSkip = NestedInteger(allow_none=True)
+    noMultiLvlLbl = NestedBool(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = _BaseAxis.__elements__ + ('auto', 'lblAlgn', 'lblOffset',
+                                             'tickLblSkip', 'tickMarkSkip', 'noMultiLvlLbl')
+
+    def __init__(self,
+                 auto=None,
+                 lblAlgn=None,
+                 lblOffset=100,
+                 tickLblSkip=None,
+                 tickMarkSkip=None,
+                 noMultiLvlLbl=None,
+                 extLst=None,
+                 **kw
+                ):
+        self.auto = auto
+        self.lblAlgn = lblAlgn
+        self.lblOffset = lblOffset
+        self.tickLblSkip = tickLblSkip
+        self.tickMarkSkip = tickMarkSkip
+        self.noMultiLvlLbl = noMultiLvlLbl
+        kw.setdefault('axId', 10)
+        kw.setdefault('crossAx', 100)
+        super(TextAxis, self).__init__(**kw)
+
+
+class DateAxis(_BaseAxis):
+
+    tagname = "dateAx"
+
+    axId = _BaseAxis.axId
+    scaling = _BaseAxis.scaling
+    delete = _BaseAxis.delete
+    axPos = _BaseAxis.axPos
+    majorGridlines = _BaseAxis.majorGridlines
+    minorGridlines = _BaseAxis.minorGridlines
+    title = _BaseAxis.title
+    numFmt = _BaseAxis.numFmt
+    majorTickMark = _BaseAxis.majorTickMark
+    minorTickMark = _BaseAxis.minorTickMark
+    tickLblPos = _BaseAxis.tickLblPos
+    spPr = _BaseAxis.spPr
+    txPr = _BaseAxis.txPr
+    crossAx = _BaseAxis.crossAx
+    crosses = _BaseAxis.crosses
+    crossesAt = _BaseAxis.crossesAt
+
+    auto = NestedBool(allow_none=True)
+    lblOffset = NestedInteger(allow_none=True)
+    baseTimeUnit = NestedNoneSet(values=(['days', 'months', 'years']))
+    majorUnit = NestedFloat(allow_none=True)
+    majorTimeUnit = NestedNoneSet(values=(['days', 'months', 'years']))
+    minorUnit = NestedFloat(allow_none=True)
+    minorTimeUnit = NestedNoneSet(values=(['days', 'months', 'years']))
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = _BaseAxis.__elements__ + ('auto', 'lblOffset',
+                                             'baseTimeUnit', 'majorUnit', 'majorTimeUnit', 'minorUnit',
+                                             'minorTimeUnit')
+
+    def __init__(self,
+                 auto=None,
+                 lblOffset=None,
+                 baseTimeUnit=None,
+                 majorUnit=1,
+                 majorTimeUnit=None,
+                 minorUnit=None,
+                 minorTimeUnit=None,
+                 extLst=None,
+                 **kw
+                ):
+        self.auto = auto
+        self.lblOffset = lblOffset
+        self.baseTimeUnit = baseTimeUnit
+        self.majorUnit = majorUnit
+        self.majorTimeUnit = majorTimeUnit
+        self.minorUnit = minorUnit
+        self.minorTimeUnit = minorTimeUnit
+        kw.setdefault('axId', 500)
+        super(DateAxis, self).__init__(**kw)
+
+
+class SeriesAxis(_BaseAxis):
+
+    tagname = "serAx"
+
+    axId = _BaseAxis.axId
+    scaling = _BaseAxis.scaling
+    delete = _BaseAxis.delete
+    axPos = _BaseAxis.axPos
+    majorGridlines = _BaseAxis.majorGridlines
+    minorGridlines = _BaseAxis.minorGridlines
+    title = _BaseAxis.title
+    numFmt = _BaseAxis.numFmt
+    majorTickMark = _BaseAxis.majorTickMark
+    minorTickMark = _BaseAxis.minorTickMark
+    tickLblPos = _BaseAxis.tickLblPos
+    spPr = _BaseAxis.spPr
+    txPr = _BaseAxis.txPr
+    crossAx = _BaseAxis.crossAx
+    crosses = _BaseAxis.crosses
+    crossesAt = _BaseAxis.crossesAt
+
+    tickLblSkip = NestedInteger(allow_none=True)
+    tickMarkSkip = NestedInteger(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = _BaseAxis.__elements__ + ('tickLblSkip', 'tickMarkSkip')
+
+    def __init__(self,
+                 tickLblSkip=None,
+                 tickMarkSkip=None,
+                 extLst=None,
+                 **kw
+                ):
+        self.tickLblSkip = tickLblSkip
+        self.tickMarkSkip = tickMarkSkip
+        kw.setdefault('axId', 1000)
+        kw.setdefault('crossAx', 10)
+        super(SeriesAxis, self).__init__(**kw)

+ 147 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/bar_chart.py

@@ -0,0 +1,147 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Bool,
+    Integer,
+    Sequence,
+    Alias,
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedNoneSet,
+    NestedSet,
+    NestedBool,
+    NestedInteger,
+    NestedMinMax,
+    NestedSequence,
+)
+
+from .descriptors import (
+    NestedGapAmount,
+    NestedOverlap,
+)
+from ._chart import ChartBase
+from ._3d import _3DBase
+from .axis import TextAxis, NumericAxis, SeriesAxis, ChartLines
+from .shapes import ShapeProperties
+from .series import Series
+from .legend import Legend
+from .label import DataLabels
+
+
+class _BarChartBase(ChartBase):
+
+    barDir = NestedSet(values=(['bar', 'col']))
+    type = Alias("barDir")
+    grouping = NestedSet(values=(['percentStacked', 'clustered', 'standard',
+                                  'stacked']))
+    varyColors = NestedBool(nested=True, allow_none=True)
+    ser = Sequence(expected_type=Series, allow_none=True)
+    dLbls = Typed(expected_type=DataLabels, allow_none=True)
+    dataLabels = Alias("dLbls")
+
+    __elements__ = ('barDir', 'grouping', 'varyColors', 'ser', 'dLbls')
+
+    _series_type = "bar"
+
+    def __init__(self,
+                 barDir="col",
+                 grouping="clustered",
+                 varyColors=None,
+                 ser=[],
+                 dLbls=None,
+                ):
+        self.barDir = barDir
+        self.grouping = grouping
+        self.varyColors = varyColors
+        self.ser = ser
+        self.dLbls = dLbls
+        super(_BarChartBase, self).__init__()
+
+
+class BarChart(_BarChartBase):
+
+    tagname = "barChart"
+
+    barDir = _BarChartBase.barDir
+    grouping = _BarChartBase.grouping
+    varyColors = _BarChartBase.varyColors
+    ser = _BarChartBase.ser
+    dLbls = _BarChartBase.dLbls
+
+    gapWidth = NestedGapAmount()
+    overlap = NestedOverlap()
+    serLines = Typed(expected_type=ChartLines, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    # chart properties actually used by containing classes
+    x_axis = Typed(expected_type=TextAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+
+    __elements__ = _BarChartBase.__elements__ + ('gapWidth', 'overlap', 'serLines', 'axId')
+
+    def __init__(self,
+                 gapWidth=150,
+                 overlap=100,
+                 serLines=None,
+                 axId=None,
+                 extLst=None,
+                 **kw
+                ):
+        self.gapWidth = gapWidth
+        self.overlap = overlap
+        self.serLines = serLines
+        self.x_axis = TextAxis()
+        self.y_axis = NumericAxis()
+        self.legend = Legend()
+        super(BarChart, self).__init__(**kw)
+
+
+class BarChart3D(_BarChartBase, _3DBase):
+
+    tagname = "bar3DChart"
+
+    barDir = _BarChartBase.barDir
+    grouping = _BarChartBase.grouping
+    varyColors = _BarChartBase.varyColors
+    ser = _BarChartBase.ser
+    dLbls = _BarChartBase.dLbls
+
+    view3D = _3DBase.view3D
+    floor = _3DBase.floor
+    sideWall = _3DBase.sideWall
+    backWall = _3DBase.backWall
+
+    gapWidth = NestedGapAmount()
+    gapDepth = NestedGapAmount()
+    shape = NestedNoneSet(values=(['cone', 'coneToMax', 'box', 'cylinder', 'pyramid', 'pyramidToMax']))
+    serLines = Typed(expected_type=ChartLines, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    x_axis = Typed(expected_type=TextAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+    z_axis = Typed(expected_type=SeriesAxis, allow_none=True)
+
+    __elements__ = _BarChartBase.__elements__ + ('gapWidth', 'gapDepth', 'shape', 'serLines', 'axId')
+
+    def __init__(self,
+                 gapWidth=150,
+                 gapDepth=150,
+                 shape=None,
+                 serLines=None,
+                 axId=None,
+                 extLst=None,
+                 **kw
+                ):
+        self.gapWidth = gapWidth
+        self.gapDepth = gapDepth
+        self.shape = shape
+        self.serLines = serLines
+        self.x_axis = TextAxis()
+        self.y_axis = NumericAxis()
+        self.z_axis = SeriesAxis()
+
+        super(BarChart3D, self).__init__(**kw)

+ 68 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/bubble_chart.py

@@ -0,0 +1,68 @@
+from __future__ import absolute_import
+#Autogenerated schema
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Set,
+    MinMax,
+    Bool,
+    Integer,
+    Alias,
+    Sequence,
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedNoneSet,
+    NestedMinMax,
+    NestedBool,
+)
+
+from ._chart import ChartBase
+from .axis import TextAxis, NumericAxis
+from .series import XYSeries
+from .label import DataLabels
+
+
+class BubbleChart(ChartBase):
+
+    tagname = "bubbleChart"
+
+    varyColors = NestedBool(allow_none=True)
+    ser = Sequence(expected_type=XYSeries, allow_none=True)
+    dLbls = Typed(expected_type=DataLabels, allow_none=True)
+    dataLabels = Alias("dLbls")
+    bubble3D = NestedBool(allow_none=True)
+    bubbleScale = NestedMinMax(min=0, max=300, allow_none=True)
+    showNegBubbles = NestedBool(allow_none=True)
+    sizeRepresents = NestedNoneSet(values=(['area', 'w']))
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    x_axis = Typed(expected_type=NumericAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+
+    _series_type = "bubble"
+
+    __elements__ = ('varyColors', 'ser', 'dLbls', 'bubble3D', 'bubbleScale',
+                    'showNegBubbles', 'sizeRepresents', 'axId')
+
+    def __init__(self,
+                 varyColors=None,
+                 ser=(),
+                 dLbls=None,
+                 bubble3D=None,
+                 bubbleScale=None,
+                 showNegBubbles=None,
+                 sizeRepresents=None,
+                 axId=None,
+                 extLst=None,
+                ):
+        self.varyColors = varyColors
+        self.ser = ser
+        self.dLbls = dLbls
+        self.bubble3D = bubble3D
+        self.bubbleScale = bubbleScale
+        self.showNegBubbles = showNegBubbles
+        self.sizeRepresents = sizeRepresents
+        self.x_axis = NumericAxis(axId=10, crossAx=20)
+        self.y_axis = NumericAxis(axId=20, crossAx=10)
+        super(BubbleChart, self).__init__()

+ 444 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/chartspace.py

@@ -0,0 +1,444 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+"""
+Enclosing chart object. The various chart types are actually child objects.
+Will probably need to call this indirectly
+"""
+
+from openpyxl.compat import unicode
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Bool,
+    Float,
+    Typed,
+    MinMax,
+    Integer,
+    NoneSet,
+    String,
+    Alias,
+    Sequence,
+)
+from openpyxl.descriptors.excel import (
+    Percentage,
+    ExtensionList
+    )
+
+from openpyxl.descriptors.nested import (
+    NestedBool,
+    NestedNoneSet,
+    NestedInteger,
+    NestedString,
+    NestedMinMax,
+    NestedText,
+)
+
+from openpyxl.drawing.colors import ColorMapping
+from .text import Text, RichText
+from .layout import Layout
+from .shapes import ShapeProperties
+from .legend import Legend
+from .marker import PictureOptions, Marker
+from .label import DataLabel
+from ._3d import _3DBase, View3D
+
+from .area_chart import AreaChart, AreaChart3D
+from .bar_chart import BarChart, BarChart3D
+from .bubble_chart import BubbleChart
+from .line_chart import LineChart, LineChart3D
+from .pie_chart import PieChart, PieChart3D, ProjectedPieChart, DoughnutChart
+from .radar_chart import RadarChart
+from .scatter_chart import ScatterChart
+from .stock_chart import StockChart
+from .surface_chart import SurfaceChart, SurfaceChart3D
+
+from .axis import NumericAxis, TextAxis, SeriesAxis, DateAxis
+from .title import Title
+
+from openpyxl.xml.functions import Element
+from openpyxl.worksheet.page import PageMargins, PrintPageSetup
+from openpyxl.worksheet.header_footer import HeaderFooter
+
+
+class PivotFormat(Serialisable):
+
+    tagname = "pivotFmt"
+
+    idx = NestedInteger(nested=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    ShapeProperties = Alias("spPr")
+    txPr = Typed(expected_type=RichText, allow_none=True)
+    TextBody = Alias("txPr")
+    marker = Typed(expected_type=Marker, allow_none=True)
+    dLbl = Typed(expected_type=DataLabel, allow_none=True)
+    DataLabel = Alias("dLbl")
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('idx', 'spPr', 'txPr', 'marker', 'dLbl')
+
+    def __init__(self,
+                 idx=0,
+                 spPr=None,
+                 txPr=None,
+                 marker=None,
+                 dLbl=None,
+                 extLst=None,
+                ):
+        self.idx = idx
+        self.spPr = spPr
+        self.txPr = txPr
+        self.marker = marker
+        self.dLbl = dLbl
+
+
+class PivotFormats(Serialisable):
+
+    tagname = "pivotFmts"
+
+    pivotFmt = Sequence(expected_type=PivotFormat, allow_none=True)
+
+    __elements__ = ('pivotFmt',)
+
+    def __init__(self,
+                 pivotFmt=(),
+                ):
+        self.pivotFmt = pivotFmt
+
+
+class DataTable(Serialisable):
+
+    tagname = "dTable"
+
+    showHorzBorder = NestedBool(allow_none=True)
+    showVertBorder = NestedBool(allow_none=True)
+    showOutline = NestedBool(allow_none=True)
+    showKeys = NestedBool(allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    ShapeProperties = Alias('spPr')
+    txPr = Typed(expected_type=RichText, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('showHorzBorder', 'showVertBorder', 'showOutline',
+                    'showKeys', 'spPr', 'txPr')
+
+    def __init__(self,
+                 showHorzBorder=None,
+                 showVertBorder=None,
+                 showOutline=None,
+                 showKeys=None,
+                 spPr=None,
+                 txPr=None,
+                 extLst=None,
+                ):
+        self.showHorzBorder = showHorzBorder
+        self.showVertBorder = showVertBorder
+        self.showOutline = showOutline
+        self.showKeys = showKeys
+        self.spPr = spPr
+        self.txPr = txPr
+
+
+class PlotArea(Serialisable):
+
+    tagname = "plotArea"
+
+    layout = Typed(expected_type=Layout, allow_none=True)
+    dTable = Typed(expected_type=DataTable, allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    graphical_properties = Alias("spPr")
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    # at least one chart
+    areaChart = Typed(expected_type=AreaChart, allow_none=True)
+    area3DChart = Typed(expected_type=AreaChart3D, allow_none=True)
+    lineChart = Typed(expected_type=LineChart, allow_none=True)
+    line3DChart = Typed(expected_type=LineChart3D, allow_none=True)
+    stockChart = Typed(expected_type=StockChart, allow_none=True)
+    radarChart = Typed(expected_type=RadarChart, allow_none=True)
+    scatterChart = Typed(expected_type=ScatterChart, allow_none=True)
+    pieChart = Typed(expected_type=PieChart, allow_none=True)
+    pie3DChart = Typed(expected_type=PieChart3D, allow_none=True)
+    doughnutChart = Typed(expected_type=DoughnutChart, allow_none=True)
+    barChart = Typed(expected_type=BarChart, allow_none=True)
+    bar3DChart = Typed(expected_type=BarChart3D, allow_none=True)
+    ofPieChart = Typed(expected_type=ProjectedPieChart, allow_none=True)
+    surfaceChart = Typed(expected_type=SurfaceChart, allow_none=True)
+    surface3DChart = Typed(expected_type=SurfaceChart3D, allow_none=True)
+    bubbleChart = Typed(expected_type=BubbleChart, allow_none=True)
+
+    # maybe axes
+    valAx = Sequence(expected_type=NumericAxis, allow_none=True)
+    catAx = Sequence(expected_type=TextAxis, allow_none=True)
+    dateAx = Sequence(expected_type=DateAxis, allow_none=True)
+    serAx = Sequence(expected_type=SeriesAxis, allow_none=True)
+
+    __elements__ = ('layout', 'areaChart', 'area3DChart', 'lineChart',
+                    'line3DChart', 'stockChart', 'radarChart', 'scatterChart', 'pieChart',
+                    'pie3DChart', 'doughnutChart', 'barChart', 'bar3DChart', 'ofPieChart',
+                    'surfaceChart', 'surface3DChart', 'bubbleChart', 'valAx', 'catAx', 'dateAx', 'serAx',
+                    'dTable', 'spPr')
+
+    def __init__(self,
+                 layout=None,
+                 dTable=None,
+                 spPr=None,
+                 areaChart=None,
+                 area3DChart=None,
+                 lineChart=None,
+                 line3DChart=None,
+                 stockChart=None,
+                 radarChart=None,
+                 scatterChart=None,
+                 pieChart=None,
+                 pie3DChart=None,
+                 doughnutChart=None,
+                 barChart=None,
+                 bar3DChart=None,
+                 ofPieChart=None,
+                 surfaceChart=None,
+                 surface3DChart=None,
+                 bubbleChart=None,
+                 valAx=(),
+                 catAx=(),
+                 serAx=(),
+                 dateAx=(),
+                 extLst=None,
+                ):
+        self.layout = layout
+        self.dTable = dTable
+        self.spPr = spPr
+        self.areaChart = areaChart
+        self.area3DChart = area3DChart
+        self.lineChart = lineChart
+        self.line3DChart = line3DChart
+        self.stockChart = stockChart
+        self.radarChart = radarChart
+        self.scatterChart = scatterChart
+        self.pieChart = pieChart
+        self.pie3DChart = pie3DChart
+        self.doughnutChart = doughnutChart
+        self.barChart = barChart
+        self.bar3DChart = bar3DChart
+        self.ofPieChart = ofPieChart
+        self.surfaceChart = surfaceChart
+        self.surface3DChart = surface3DChart
+        self.bubbleChart = bubbleChart
+        self.valAx = valAx
+        self.catAx = catAx
+        self.dateAx = dateAx
+        self.serAx = serAx
+        self._charts = []
+
+
+    def to_tree(self, tagname=None, idx=None):
+        if tagname is None:
+            tagname = self.tagname
+        el = Element(tagname)
+        if self.layout is not None:
+            el.append(self.layout.to_tree())
+        for chart in self._charts:
+            el.append(chart.to_tree())
+        for ax in ['valAx', 'catAx', 'dateAx', 'serAx',]:
+            seq = getattr(self, ax)
+            if seq:
+                for obj in seq:
+                    el.append(obj.to_tree())
+        for attr in ['dTable', 'spPr']:
+            obj = getattr(self, attr)
+            if obj is not None:
+                el.append(obj.to_tree())
+        return el
+
+
+class ChartContainer(Serialisable):
+
+    tagname = "chart"
+
+    title = Typed(expected_type=Title, allow_none=True)
+    autoTitleDeleted = NestedBool(allow_none=True)
+    pivotFmts = Typed(expected_type=PivotFormats, allow_none=True)
+    view3D = _3DBase.view3D
+    floor = _3DBase.floor
+    sideWall = _3DBase.sideWall
+    backWall = _3DBase.backWall
+    plotArea = Typed(expected_type=PlotArea, )
+    legend = Typed(expected_type=Legend, allow_none=True)
+    plotVisOnly = NestedBool(allow_none=True)
+    dispBlanksAs = NestedNoneSet(values=(['span', 'gap', 'zero']))
+    showDLblsOverMax = NestedBool(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('title', 'autoTitleDeleted', 'pivotFmts', 'view3D',
+                    'floor', 'sideWall', 'backWall', 'plotArea', 'legend', 'plotVisOnly',
+                    'dispBlanksAs', 'showDLblsOverMax')
+
+    def __init__(self,
+                 title=None,
+                 autoTitleDeleted=None,
+                 pivotFmts=None,
+                 view3D=None,
+                 floor=None,
+                 sideWall=None,
+                 backWall=None,
+                 plotArea=None,
+                 legend=None,
+                 plotVisOnly=None,
+                 dispBlanksAs="gap",
+                 showDLblsOverMax=None,
+                 extLst=None,
+                ):
+        self.title = title
+        self.autoTitleDeleted = autoTitleDeleted
+        self.pivotFmts = pivotFmts
+        self.view3D = view3D
+        self.floor = floor
+        self.sideWall = sideWall
+        self.backWall = backWall
+        if plotArea is None:
+            plotArea = PlotArea()
+        self.plotArea = plotArea
+        self.legend = legend
+        self.plotVisOnly = plotVisOnly
+        self.dispBlanksAs = dispBlanksAs
+        self.showDLblsOverMax = showDLblsOverMax
+
+
+class Protection(Serialisable):
+
+    tagname = "protection"
+
+    chartObject = NestedBool(allow_none=True)
+    data = NestedBool(allow_none=True)
+    formatting = NestedBool(allow_none=True)
+    selection = NestedBool(allow_none=True)
+    userInterface = NestedBool(allow_none=True)
+
+    __elements__ = ("chartObject", "data", "formatting", "selection", "userInterface")
+
+    def __init__(self,
+                 chartObject=None,
+                 data=None,
+                 formatting=None,
+                 selection=None,
+                 userInterface=None,
+                ):
+        self.chartObject = chartObject
+        self.data = data
+        self.formatting = formatting
+        self.selection = selection
+        self.userInterface = userInterface
+
+
+class PivotSource(Serialisable):
+
+    tagname = "pivotSource"
+
+    name = NestedText(expected_type=unicode)
+    fmtId = NestedText(expected_type=int)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('name', 'fmtId')
+
+    def __init__(self,
+                 name=None,
+                 fmtId=None,
+                 extLst=None,
+                ):
+        self.name = name
+        self.fmtId = fmtId
+
+
+class ExternalData(Serialisable):
+
+    tagname = "externalData"
+
+    autoUpdate = NestedBool(allow_none=True)
+    id = String() # Needs namespace
+
+    def __init__(self,
+                 autoUpdate=None,
+                 id=None
+                ):
+        self.autoUpdate = autoUpdate
+        self.id = id
+
+
+class RelId(Serialisable):
+
+    pass # todo
+
+
+class PrintSettings(Serialisable):
+
+    tagname = "printSettings"
+
+    headerFooter = Typed(expected_type=HeaderFooter, allow_none=True)
+    pageMargins = Typed(expected_type=PageMargins, allow_none=True)
+    pageSetup = Typed(expected_type=PrintPageSetup, allow_none=True)
+
+    __elements__ = ("headerFooter", "pageMargins", "pageMargins")
+
+    def __init__(self,
+                 headerFooter=None,
+                 pageMargins=None,
+                 pageSetup=None,
+                ):
+        self.headerFooter = headerFooter
+        self.pageMargins = pageMargins
+        self.pageSetup = pageSetup
+
+
+class ChartSpace(Serialisable):
+
+    tagname = "chartSpace"
+
+    date1904 = NestedBool(allow_none=True)
+    lang = NestedString(allow_none=True)
+    roundedCorners = NestedBool(allow_none=True)
+    style = NestedInteger(allow_none=True)
+    clrMapOvr = Typed(expected_type=ColorMapping, allow_none=True)
+    pivotSource = Typed(expected_type=PivotSource, allow_none=True)
+    protection = Typed(expected_type=Protection, allow_none=True)
+    chart = Typed(expected_type=ChartContainer)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    txPr = Typed(expected_type=RichText, allow_none=True)
+    externalData = Typed(expected_type=ExternalData, allow_none=True)
+    printSettings = Typed(expected_type=PrintSettings, allow_none=True)
+    userShapes = Typed(expected_type=RelId, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('date1904', 'lang', 'roundedCorners', 'style',
+                    'clrMapOvr', 'pivotSource', 'protection', 'chart', 'spPr', 'txPr',
+                    'externalData', 'printSettings', 'userShapes')
+
+    def __init__(self,
+                 date1904=None,
+                 lang=None,
+                 roundedCorners=None,
+                 style=None,
+                 clrMapOvr=None,
+                 pivotSource=None,
+                 protection=None,
+                 chart=None,
+                 spPr=None,
+                 txPr=None,
+                 externalData=None,
+                 printSettings=None,
+                 userShapes=None,
+                 extLst=None,
+                ):
+        self.date1904 = date1904
+        self.lang = lang
+        self.roundedCorners = roundedCorners
+        self.style = style
+        self.clrMapOvr = clrMapOvr
+        self.pivotSource = pivotSource
+        self.protection = protection
+        self.chart = chart
+        self.spPr = spPr
+        self.txPr = txPr
+        self.externalData = externalData
+        self.printSettings = printSettings
+        self.userShapes = userShapes
+        self.extLst = extLst

+ 172 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/data_source.py

@@ -0,0 +1,172 @@
+"""
+Collection of utility primitives for charts.
+"""
+
+from openpyxl.compat import unicode
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Bool,
+    Typed,
+    Alias,
+    String,
+    Integer,
+    Sequence,
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedString,
+    NestedText,
+    NestedInteger,
+)
+
+
+class NumFmt(Serialisable):
+
+    formatCode = String()
+    sourceLinked = Bool()
+
+    def __init__(self,
+                 formatCode=None,
+                 sourceLinked=False
+                ):
+        self.formatCode = formatCode
+        self.sourceLinked = sourceLinked
+
+
+class NumVal(Serialisable):
+
+    idx = Integer()
+    formatCode = NestedText(allow_none=True, expected_type=unicode)
+    v = NestedText(allow_none=True, expected_type=float)
+
+    def __init__(self,
+                 idx=None,
+                 formatCode=None,
+                 v=None,
+                ):
+        self.idx = idx
+        self.formatCode = formatCode
+        self.v = v
+
+
+class NumData(Serialisable):
+
+    formatCode = NestedText(expected_type=str, allow_none=True)
+    ptCount = NestedInteger(allow_none=True)
+    pt = Sequence(expected_type=NumVal)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('formatCode', 'ptCount', 'pt')
+
+    def __init__(self,
+                 formatCode=None,
+                 ptCount=None,
+                 pt=None,
+                 extLst=None,
+                ):
+        self.formatCode = formatCode
+        self.ptCount = ptCount
+        self.pt = pt
+
+
+class NumRef(Serialisable):
+
+    f = NestedText(expected_type=unicode)
+    ref = Alias('f')
+    numCache = Typed(expected_type=NumData, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('f')
+
+    def __init__(self,
+                 f=None,
+                 numCache=None,
+                 extLst=None,
+                ):
+        self.f = f
+
+
+class StrVal(Serialisable):
+
+    tagname = "strVal"
+
+    idx = Integer()
+    v = NestedString()
+
+    def __init__(self,
+                 idx=0,
+                 v=None,
+                ):
+        self.idx = idx
+        self.v = v
+
+
+class StrData(Serialisable):
+
+    tagname = "strData"
+
+    ptCount = NestedInteger(allow_none=True)
+    pt = Typed(expected_type=StrVal, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('ptCount', 'pt')
+
+    def __init__(self,
+                 ptCount=None,
+                 pt=None,
+                 extLst=None,
+                ):
+        self.ptCount = ptCount
+        self.pt = pt
+
+
+class StrRef(Serialisable):
+
+    tagname = "strRef"
+
+    f = NestedText(expected_type=unicode, allow_none=True)
+    strCache = Typed(expected_type=StrData, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('f', 'strCache')
+
+    def __init__(self,
+                 f=None,
+                 strCache=None,
+                 extLst=None,
+                ):
+        self.f = f
+        self.strCache = strCache
+
+
+class NumDataSource(Serialisable):
+
+    numRef = Typed(expected_type=NumRef, allow_none=True)
+    numLit = Typed(expected_type=NumData, allow_none=True)
+
+
+    def __init__(self,
+                 numRef=None,
+                 numLit=None,
+                 ):
+        self.numRef = numRef
+        self.numLit = numLit
+
+
+class AxDataSource(Serialisable):
+
+    numRef = Typed(expected_type=NumRef, allow_none=True)
+    numLit = Typed(expected_type=NumData, allow_none=True)
+    strRef = Typed(expected_type=StrRef, allow_none=True)
+    strLit = Typed(expected_type=StrData, allow_none=True)
+
+    def __init__(self,
+                 numRef=None,
+                 numLit=None,
+                 strRef=None,
+                 strLit=None,
+                 ):
+        self.numRef = numRef
+        self.numLit = numLit
+        self.strRef = strRef
+        self.strLit = strLit

+ 44 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/descriptors.py

@@ -0,0 +1,44 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.compat import basestring
+
+from openpyxl.descriptors.nested import (
+    NestedMinMax
+    )
+
+from openpyxl.descriptors import Typed
+
+from .data_source import NumFmt
+
+"""
+Utility descriptors for the chart module.
+For convenience but also clarity.
+"""
+
+class NestedGapAmount(NestedMinMax):
+
+    allow_none = True
+    min = 0
+    max = 500
+
+
+class NestedOverlap(NestedMinMax):
+
+    allow_none = True
+    min = -100
+    max = 100
+
+
+class NumberFormatDescriptor(Typed):
+    """
+    Allow direct assignment of format code
+    """
+
+    expected_type = NumFmt
+    allow_none = True
+
+    def __set__(self, instance, value):
+        if isinstance(value, basestring):
+            value = NumFmt(value)
+        super(NumberFormatDescriptor, self).__set__(instance, value)

+ 60 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/error_bar.py

@@ -0,0 +1,60 @@
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Float,
+    Set,
+    Alias
+)
+
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedNoneSet,
+    NestedSet,
+    NestedBool,
+    NestedFloat,
+)
+
+from .data_source import NumDataSource
+from .shapes import ShapeProperties
+
+
+class ErrorBars(Serialisable):
+
+    tagname = "errBars"
+
+    errDir = NestedNoneSet(values=(['x', 'y']))
+    direction = Alias("errDir")
+    errBarType = NestedSet(values=(['both', 'minus', 'plus']))
+    style = Alias("errBarType")
+    errValType = NestedSet(values=(['cust', 'fixedVal', 'percentage', 'stdDev', 'stdErr']))
+    size = Alias("errValType")
+    noEndCap = NestedBool(nested=True, allow_none=True)
+    plus = Typed(expected_type=NumDataSource, allow_none=True)
+    minus = Typed(expected_type=NumDataSource, allow_none=True)
+    val = NestedFloat(allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    shapeProperties = Alias("spPr")
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('errDir','errBarType', 'errValType', 'noEndCap','minus', 'plus', 'val', 'spPr')
+
+
+    def __init__(self,
+                 errDir=None,
+                 errBarType="both",
+                 errValType="fixedVal",
+                 noEndCap=None,
+                 plus=None,
+                 minus=None,
+                 val=None,
+                 spPr=None,
+                 extLst=None,
+                ):
+        self.errDir = errDir
+        self.errBarType = errBarType
+        self.errValType = errValType
+        self.noEndCap = noEndCap
+        self.plus = plus
+        self.minus = minus
+        self.val = val
+        self.spPr = spPr

+ 130 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/label.py

@@ -0,0 +1,130 @@
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    String,
+    Integer,
+    Bool,
+    Set,
+    Float,
+    Sequence,
+    Alias
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedNoneSet,
+    NestedBool,
+    NestedString,
+    NestedInteger,
+    )
+
+from .shapes import ShapeProperties
+from .text import RichText
+
+
+class _DataLabelBase(Serialisable):
+
+    numFmt = NestedString(allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    shapeProperties = Alias('spPr')
+    txPr = Typed(expected_type=RichText, allow_none=True)
+    textProperties = Alias('txPr')
+    dLblPos = NestedNoneSet(values=['bestFit', 'b', 'ctr', 'inBase', 'inEnd',
+                                    'l', 'outEnd', 'r', 't'])
+    position = Alias('dLblPos')
+    showLegendKey = NestedBool(allow_none=True)
+    showVal = NestedBool(allow_none=True)
+    showCatName = NestedBool(allow_none=True)
+    showSerName = NestedBool(allow_none=True)
+    showPercent = NestedBool(allow_none=True)
+    showBubbleSize = NestedBool(allow_none=True)
+    showLeaderLines = NestedBool(allow_none=True)
+    separator = NestedString(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ("delete", "numFmt", "spPr", "txPr", "dLblPos",
+                    "showLegendKey", "showVal", "showCatName", "showSerName", "showPercent",
+                    "showBubbleSize", "showLeaderLines", "separator")
+
+    def __init__(self,
+                 delete=None,
+                 numFmt=None,
+                 spPr=None,
+                 txPr=None,
+                 dLblPos=None,
+                 showLegendKey=None,
+                 showVal=None,
+                 showCatName=None,
+                 showSerName=None,
+                 showPercent=None,
+                 showBubbleSize=None,
+                 showLeaderLines=None,
+                 separator=None,
+                 extLst=None,
+                 ):
+        self.delete = delete
+        self.numFmt = numFmt
+        self.spPr = spPr
+        self.txPr = txPr
+        self.dLblPos = dLblPos
+        self.showLegendKey = showLegendKey
+        self.showVal = showVal
+        self.showCatName = showCatName
+        self.showSerName = showSerName
+        self.showPercent = showPercent
+        self.showBubbleSize = showBubbleSize
+        self.showLeaderLines = showLeaderLines
+        self.separator = separator
+
+
+class DataLabel(_DataLabelBase):
+
+    tagname = "dLbl"
+
+    idx = NestedInteger()
+
+    numFmt = _DataLabelBase.numFmt
+    spPr = _DataLabelBase.spPr
+    txPr = _DataLabelBase.txPr
+    dLblPos = _DataLabelBase.dLblPos
+    showLegendKey = _DataLabelBase.showLegendKey
+    showVal = _DataLabelBase.showVal
+    showCatName = _DataLabelBase.showCatName
+    showSerName = _DataLabelBase.showSerName
+    showPercent = _DataLabelBase.showPercent
+    showBubbleSize = _DataLabelBase.showBubbleSize
+    showLeaderLines = _DataLabelBase.showLeaderLines
+    separator = _DataLabelBase.separator
+    extLst = _DataLabelBase.extLst
+
+    __elements__ = ("idx",)  + _DataLabelBase.__elements__
+
+    def __init__(self, idx=0, **kw ):
+        self.idx = idx
+        super(DataLabel, self).__init__(**kw)
+
+
+class DataLabels(_DataLabelBase):
+
+    tagname = "dLbls"
+
+    dLbl = Sequence(expected_type=DataLabel, allow_none=True)
+
+    numFmt = _DataLabelBase.numFmt
+    spPr = _DataLabelBase.spPr
+    txPr = _DataLabelBase.txPr
+    dLblPos = _DataLabelBase.dLblPos
+    showLegendKey = _DataLabelBase.showLegendKey
+    showVal = _DataLabelBase.showVal
+    showCatName = _DataLabelBase.showCatName
+    showSerName = _DataLabelBase.showSerName
+    showPercent = _DataLabelBase.showPercent
+    showBubbleSize = _DataLabelBase.showBubbleSize
+    showLeaderLines = _DataLabelBase.showLeaderLines
+    separator = _DataLabelBase.separator
+    extLst = _DataLabelBase.extLst
+
+    __elements__ = ("dLbl",) + _DataLabelBase.__elements__
+
+    def __init__(self, dLbl=(), **kw ):
+        self.dLbl = dLbl
+        super(DataLabels, self).__init__(**kw)

+ 72 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/layout.py

@@ -0,0 +1,72 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    NoneSet,
+    Float,
+    Typed,
+)
+
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedNoneSet,
+    NestedFloat
+
+)
+
+class ManualLayout(Serialisable):
+
+    tagname = "manualLayout"
+
+    layoutTarget = NestedNoneSet(values=(['inner', 'outer']))
+    xMode = NestedNoneSet(values=(['edge', 'factor']))
+    yMode = NestedNoneSet(values=(['edge', 'factor']))
+    wMode = NestedNoneSet(values=(['edge', 'factor']))
+    hMode = NestedNoneSet(values=(['edge', 'factor']))
+    x = NestedFloat(allow_none=True)
+    y = NestedFloat(allow_none=True)
+    w = NestedFloat(allow_none=True)
+    h = NestedFloat(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('layoutTarget', 'xMode', 'yMode', 'wMode', 'hMode', 'x',
+                    'y', 'w', 'h')
+
+    def __init__(self,
+                 layoutTarget=None,
+                 xMode=None,
+                 yMode=None,
+                 wMode=None,
+                 hMode=None,
+                 x=None,
+                 y=None,
+                 w=None,
+                 h=None,
+                 extLst=None,
+                ):
+        self.layoutTarget = layoutTarget
+        self.xMode = xMode
+        self.yMode = yMode
+        self.wMode = wMode
+        self.hMode = hMode
+        self.x = x
+        self.y = y
+        self.w = w
+        self.h = h
+
+
+class Layout(Serialisable):
+
+    tagname = "layout"
+
+    manualLayout = Typed(expected_type=ManualLayout, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('manualLayout',)
+
+    def __init__(self,
+                 manualLayout=None,
+                 extLst=None,
+                ):
+        self.manualLayout = manualLayout

+ 71 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/legend.py

@@ -0,0 +1,71 @@
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Integer,
+    Alias,
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedBool,
+    NestedSet,
+    NestedInteger
+)
+
+from .layout import Layout
+from .shapes import ShapeProperties
+from .text import RichText
+
+
+class LegendEntry(Serialisable):
+
+    tagname = "legendEntry"
+
+    idx = NestedInteger()
+    delete = NestedBool()
+    txPr = Typed(expected_type=RichText, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('idx',)
+
+    def __init__(self,
+                 idx=0,
+                 delete=False,
+                 txPr=None,
+                 extLst=None,
+                ):
+        self.idx = idx
+        self.delete = delete
+        self.txPr = txPr
+
+
+class Legend(Serialisable):
+
+    tagname = "legend"
+
+    legendPos = NestedSet(values=(['b', 'tr', 'l', 'r', 't']))
+    legendEntry = Typed(expected_type=LegendEntry, allow_none=True)
+    layout = Typed(expected_type=Layout, allow_none=True)
+    overlay = NestedBool(allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    shapeProperties = Alias('spPr')
+    txPr = Typed(expected_type=RichText, allow_none=True)
+    textProperies = Alias('txPr')
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('legendPos', 'legendEntry', 'layout', 'overlay', 'spPr', 'txPr',)
+
+    def __init__(self,
+                 legendPos="r",
+                 legendEntry=None,
+                 layout=None,
+                 overlay=None,
+                 spPr=None,
+                 txPr=None,
+                 extLst=None,
+                ):
+        self.legendPos = legendPos
+        self.legendEntry = legendEntry
+        self.layout = layout
+        self.overlay = overlay
+        self.spPr = spPr
+        self.txPr = txPr

+ 133 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/line_chart.py

@@ -0,0 +1,133 @@
+from __future__ import absolute_import
+#Autogenerated schema
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Sequence,
+    Alias,
+    )
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedSet,
+    NestedBool,
+    NestedMinMax,
+)
+
+from ._chart import ChartBase
+from .updown_bars import UpDownBars
+from .descriptors import NestedGapAmount
+from .axis import TextAxis, NumericAxis, SeriesAxis, ChartLines, _BaseAxis
+from .label import DataLabels
+from .series import Series
+
+
+class _LineChartBase(ChartBase):
+
+    grouping = NestedSet(values=(['percentStacked', 'standard', 'stacked']))
+    varyColors = NestedBool(allow_none=True)
+    ser = Sequence(expected_type=Series, allow_none=True)
+    dLbls = Typed(expected_type=DataLabels, allow_none=True)
+    dataLabels = Alias("dLbls")
+    dropLines = Typed(expected_type=ChartLines, allow_none=True)
+
+    _series_type = "line"
+
+    __elements__ = ('grouping', 'varyColors', 'ser', 'dLbls', 'dropLines')
+
+    def __init__(self,
+                 grouping="standard",
+                 varyColors=None,
+                 ser=[],
+                 dLbls=None,
+                 dropLines=None,
+                ):
+        self.grouping = grouping
+        self.varyColors = varyColors
+        self.ser = ser
+        self.dLbls = dLbls
+        self.dropLines = dropLines
+        super(_LineChartBase, self).__init__()
+
+
+class LineChart(_LineChartBase):
+
+    tagname = "lineChart"
+
+    grouping = _LineChartBase.grouping
+    varyColors = _LineChartBase.varyColors
+    ser = _LineChartBase.ser
+    dLbls = _LineChartBase.dLbls
+    dropLines =_LineChartBase.dropLines
+
+    hiLowLines = Typed(expected_type=ChartLines, allow_none=True)
+    upDownBars = Typed(expected_type=UpDownBars, allow_none=True)
+    marker = NestedBool(allow_none=True)
+    smooth = NestedBool(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    x_axis = Typed(expected_type=_BaseAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+
+    __elements__ = _LineChartBase.__elements__ + ('hiLowLines', 'upDownBars', 'marker', 'smooth', 'axId')
+
+    def __init__(self,
+                 hiLowLines=None,
+                 upDownBars=None,
+                 marker=None,
+                 smooth=None,
+                 axId=None,
+                 extLst=None,
+                 **kw
+                ):
+        self.hiLowLines = hiLowLines
+        self.upDownBars = upDownBars
+        self.marker = marker
+        self.smooth = smooth
+        self.x_axis = TextAxis()
+        self.y_axis = NumericAxis()
+
+        super(LineChart, self).__init__(**kw)
+
+
+class LineChart3D(_LineChartBase):
+
+    tagname = "line3DChart"
+
+    grouping = _LineChartBase.grouping
+    varyColors = _LineChartBase.varyColors
+    ser = _LineChartBase.ser
+    dLbls = _LineChartBase.dLbls
+    dropLines =_LineChartBase.dropLines
+
+    gapDepth = NestedGapAmount()
+    hiLowLines = Typed(expected_type=ChartLines, allow_none=True)
+    upDownBars = Typed(expected_type=UpDownBars, allow_none=True)
+    marker = NestedBool(allow_none=True)
+    smooth = NestedBool(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    x_axis = Typed(expected_type=TextAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+    z_axis = Typed(expected_type=SeriesAxis)
+
+    __elements__ = _LineChartBase.__elements__ + ('gapDepth', 'hiLowLines',
+                                                  'upDownBars', 'marker', 'smooth', 'axId')
+
+    def __init__(self,
+                 gapDepth=None,
+                 hiLowLines=None,
+                 upDownBars=None,
+                 marker=None,
+                 smooth=None,
+                 axId=None,
+                 **kw
+                ):
+        self.gapDepth = gapDepth
+        self.hiLowLines = hiLowLines
+        self.upDownBars = upDownBars
+        self.marker = marker
+        self.smooth = smooth
+        self.x_axis = TextAxis()
+        self.y_axis = NumericAxis()
+        self.z_axis = SeriesAxis()
+        super(LineChart3D, self).__init__(**kw)

+ 100 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/marker.py

@@ -0,0 +1,100 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.compat import safe_string
+from openpyxl.xml.functions import Element
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Alias,
+)
+
+from openpyxl.descriptors.excel import(
+    ExtensionList,
+)
+
+from openpyxl.descriptors.nested import (
+    NestedBool,
+    NestedInteger,
+    NestedMinMax,
+    NestedNoneSet,
+)
+
+from .layout import Layout
+from .picture import PictureOptions
+from .shapes import *
+from .text import *
+from .error_bar import *
+
+
+def _marker_symbol(tagname, value, namespace=None):
+    """
+    Override serialisation because explicit none required
+    """
+    if namespace is not None:
+        tagname = "{%s}%s" % (namespace, tagname)
+    return Element(tagname, val=safe_string(value))
+
+
+class Marker(Serialisable):
+
+    tagname = "marker"
+
+    symbol = NestedNoneSet(values=(['circle', 'dash', 'diamond', 'dot', 'picture',
+                              'plus', 'square', 'star', 'triangle', 'x', 'auto']),
+                           to_tree=_marker_symbol)
+    size = NestedMinMax(min=2, max=72, allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    ShapeProperties = Alias('sprPr')
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('symbol', 'size', 'spPr')
+
+    def __init__(self,
+                 symbol=None,
+                 size=None,
+                 spPr=None,
+                 extLst=None,
+                ):
+        self.symbol = symbol
+        self.size = size
+        self.spPr = spPr
+
+
+class DataPoint(Serialisable):
+
+    tagname = "dPt"
+
+    idx = NestedInteger()
+    invertIfNegative = NestedBool(allow_none=True)
+    marker = Typed(expected_type=Marker, allow_none=True)
+    bubble3D = NestedBool(allow_none=True)
+    explosion = Integer(allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    shapeProperties = Alias('spPr')
+    pictureOptions = Typed(expected_type=PictureOptions, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('idx', 'invertIfNegative', 'marker', 'bubble3D',
+                    'explosion', 'spPr', 'pictureOptions')
+
+    def __init__(self,
+                 idx=None,
+                 invertIfNegative=None,
+                 marker=None,
+                 bubble3D=None,
+                 explosion=None,
+                 spPr=None,
+                 pictureOptions=None,
+                 extLst=None,
+                ):
+        self.idx = idx
+        self.invertIfNegative = invertIfNegative
+        self.marker = marker
+        self.bubble3D = bubble3D
+        self.explosion = explosion
+        if spPr is None:
+            spPr = ShapeProperties()
+        self.spPr = spPr
+        self.pictureOptions = pictureOptions

+ 36 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/picture.py

@@ -0,0 +1,36 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+
+from openpyxl.descriptors.nested import (
+    NestedBool,
+    NestedFloat,
+    NestedMinMax,
+    NestedNoneSet,
+)
+
+class PictureOptions(Serialisable):
+
+    tagname = "pictureOptions"
+
+    applyToFront = NestedBool(allow_none=True, nested=True)
+    applyToSides = NestedBool(allow_none=True, nested=True)
+    applyToEnd = NestedBool(allow_none=True, nested=True)
+    pictureFormat = NestedNoneSet(values=(['stretch', 'stack', 'stackScale']), nested=True)
+    pictureStackUnit = NestedFloat(allow_none=True, nested=True)
+
+    __elements__ = ('applyToFront', 'applyToSides', 'applyToEnd', 'pictureFormat', 'pictureStackUnit')
+
+    def __init__(self,
+                 applyToFront=None,
+                 applyToSides=None,
+                 applyToEnd=None,
+                 pictureFormat=None,
+                 pictureStackUnit=None,
+                ):
+        self.applyToFront = applyToFront
+        self.applyToSides = applyToSides
+        self.applyToEnd = applyToEnd
+        self.pictureFormat = pictureFormat
+        self.pictureStackUnit = pictureStackUnit

+ 175 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/pie_chart.py

@@ -0,0 +1,175 @@
+
+#Autogenerated schema
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Bool,
+    MinMax,
+    Integer,
+    NoneSet,
+    Float,
+    Alias,
+    Sequence,
+)
+from openpyxl.descriptors.excel import ExtensionList, Percentage
+from openpyxl.descriptors.nested import (
+    NestedBool,
+    NestedMinMax,
+    NestedInteger,
+    NestedFloat,
+    NestedNoneSet,
+    NestedSet,
+    NestedSequence
+)
+
+from ._chart import ChartBase
+from .axis import ChartLines
+from .descriptors import NestedGapAmount
+from .series import Series
+from .label import DataLabels
+
+
+class _PieChartBase(ChartBase):
+
+    varyColors = NestedBool(allow_none=True)
+    ser = Sequence(expected_type=Series, allow_none=True)
+    dLbls = Typed(expected_type=DataLabels, allow_none=True)
+    dataLabels = Alias("dLbls")
+
+    _series_type = "pie"
+
+    __elements__ = ('varyColors', 'ser', 'dLbls')
+
+    def __init__(self,
+                 varyColors=True,
+                 ser=(),
+                 dLbls=None,
+                ):
+        self.varyColors = varyColors
+        self.ser = ser
+        self.dLbls = dLbls
+        super(_PieChartBase, self).__init__()
+
+
+
+class PieChart(_PieChartBase):
+
+    tagname = "pieChart"
+
+    varyColors = _PieChartBase.varyColors
+    ser = _PieChartBase.ser
+    dLbls = _PieChartBase.dLbls
+
+    firstSliceAng = NestedMinMax(min=0, max=360)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = _PieChartBase.__elements__ + ('firstSliceAng', )
+
+    def __init__(self,
+                 firstSliceAng=0,
+                 extLst=None,
+                 **kw
+                ):
+        self.firstSliceAng = firstSliceAng
+        super(PieChart, self).__init__(*kw)
+
+
+class PieChart3D(_PieChartBase):
+
+    tagname = "pie3DChart"
+
+    varyColors = _PieChartBase.varyColors
+    ser = _PieChartBase.ser
+    dLbls = _PieChartBase.dLbls
+
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = _PieChartBase.__elements__
+
+
+class DoughnutChart(_PieChartBase):
+
+    tagname = "doughnutChart"
+
+    varyColors = _PieChartBase.varyColors
+    ser = _PieChartBase.ser
+    dLbls = _PieChartBase.dLbls
+
+    firstSliceAng = NestedMinMax(min=0, max=360)
+    holeSize = NestedMinMax(min=10, max=90, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = _PieChartBase.__elements__ + ('firstSliceAng', 'holeSize')
+
+    def __init__(self,
+                 firstSliceAng=0,
+                 holeSize=10,
+                 extLst=None,
+                 **kw
+                ):
+        self.firstSliceAng = firstSliceAng
+        self.holeSize = holeSize
+        super(DoughnutChart, self).__init__(**kw)
+
+
+class CustomSplit(Serialisable):
+
+    tagname = "custSplit"
+
+    secondPiePt = NestedSequence(expected_type=int)
+
+    __elements__ = ('secondPiePt',)
+
+    def __init__(self,
+                 secondPiePt=(),
+                ):
+        self.secondPiePt = secondPiePt
+
+
+class ProjectedPieChart(_PieChartBase):
+
+    """
+    From the spec 21.2.2.126
+
+    This element contains the pie of pie or bar of pie series on this
+    chart. Only the first series shall be displayed. The splitType element
+    shall determine whether the splitPos and custSplit elements apply.
+    """
+
+    tagname = "ofPieChart"
+
+    varyColors = _PieChartBase.varyColors
+    ser = _PieChartBase.ser
+    dLbls = _PieChartBase.dLbls
+
+    ofPieType = NestedSet(values=(['pie', 'bar']))
+    gapWidth = NestedGapAmount()
+    splitType = NestedNoneSet(values=(['auto', 'cust', 'percent', 'pos', 'val']))
+    splitPos = NestedFloat(allow_none=True)
+    custSplit = Typed(expected_type=CustomSplit, allow_none=True)
+    secondPieSize = NestedMinMax(min=5, max=200, allow_none=True)
+    serLines = Typed(expected_type=ChartLines, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = _PieChartBase.__elements__ + ('ofPieType', 'gapWidth',
+                                                 'splitType', 'splitPos', 'custSplit', 'secondPieSize', 'serLines')
+
+    def __init__(self,
+                 ofPieType="pie",
+                 gapWidth=None,
+                 splitType=None,
+                 splitPos=None,
+                 custSplit=None,
+                 secondPieSize=75,
+                 serLines=None,
+                 extLst=None,
+                 **kw
+                ):
+        self.ofPieType = ofPieType
+        self.gapWidth = gapWidth
+        self.splitType = splitType
+        self.splitPos = splitPos
+        self.custSplit = custSplit
+        self.secondPieSize = secondPieSize
+        self.serLines = serLines
+        super(ProjectedPieChart, self).__init__(**kw)

+ 54 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/radar_chart.py

@@ -0,0 +1,54 @@
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Sequence,
+    Typed,
+    Alias,
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedBool,
+    NestedInteger,
+    NestedSet
+)
+
+from ._chart import ChartBase
+from .axis import TextAxis, NumericAxis
+from .series import Series
+from .label import DataLabels
+
+
+class RadarChart(ChartBase):
+
+    tagname = "radarChart"
+
+    radarStyle = NestedSet(values=(['standard', 'marker', 'filled']))
+    type = Alias("radarStyle")
+    varyColors = NestedBool(nested=True, allow_none=True)
+    ser = Typed(expected_type=Series, allow_none=True)
+    dLbls = Typed(expected_type=DataLabels, allow_none=True)
+    dataLabels = Alias("dLbls")
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    _series_type = "radar"
+
+    x_axis = Typed(expected_type=TextAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+
+    __elements__ = ('radarStyle', 'varyColors', 'ser', 'dLbls', 'axId')
+
+    def __init__(self,
+                 radarStyle="standard",
+                 varyColors=None,
+                 ser=None,
+                 dLbls=None,
+                 axId=None,
+                 extLst=None,
+                ):
+        self.radarStyle = radarStyle
+        self.varyColors = varyColors
+        self.ser = ser
+        self.dLbls = dLbls
+        self.x_axis = TextAxis()
+        self.y_axis = NumericAxis()
+        super(RadarChart, self).__init__()
+

+ 127 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/reference.py

@@ -0,0 +1,127 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from itertools import chain
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    MinMax,
+    Typed,
+    String,
+    Strict,
+)
+from openpyxl.worksheet import Worksheet
+from openpyxl.utils import (
+    get_column_letter,
+    range_to_tuple,
+    quote_sheetname
+)
+
+
+class DummyWorksheet:
+
+
+    def __init__(self, title):
+        self.title = title
+
+
+class Reference(Strict):
+
+    """
+    Normalise cell range references
+    """
+
+    min_row = MinMax(min=1, max=1000000, expected_type=int)
+    max_row = MinMax(min=1, max=1000000, expected_type=int)
+    min_col = MinMax(min=1, max=16384, expected_type=int)
+    max_col = MinMax(min=1, max=16384, expected_type=int)
+    range_string = String(allow_none=True)
+
+    def __init__(self,
+                 worksheet=None,
+                 min_col=None,
+                 min_row=None,
+                 max_col=None,
+                 max_row=None,
+                 range_string=None
+                 ):
+        if range_string is not None:
+            sheetname, boundaries = range_to_tuple(range_string)
+            min_col, min_row, max_col, max_row = boundaries
+            worksheet = DummyWorksheet(sheetname)
+
+        self.worksheet = worksheet
+        self.min_col = min_col
+        self.min_row = min_row
+        if max_col is None:
+            max_col = min_col
+        self.max_col = max_col
+        if max_row is None:
+            max_row = min_row
+        self.max_row = max_row
+
+
+    def __repr__(self):
+        fmt = "{0}!${1}${2}:${3}${4}"
+        if (self.min_col == self.max_col
+            and self.min_row == self.max_row):
+            fmt = "{0}!${1}${2}"
+        return fmt.format(self.sheetname,
+                          get_column_letter(self.min_col), self.min_row,
+                          get_column_letter(self.max_col), self.max_row
+                          )
+
+
+    def __str__(self):
+        return repr(self)
+
+
+    def __len__(self):
+        if self.min_row == self.max_row:
+            return 1 + self.max_col - self.min_col
+        return 1 + self.max_row - self.min_row
+
+
+    @property
+    def rows(self):
+        """
+        Return all cells in range by column
+        """
+        for row in range(self.min_row, self.max_row+1):
+            yield tuple('%s%d' % (get_column_letter(col), row)
+                    for col in range(self.min_col, self.max_col+1))
+
+
+    @property
+    def cols(self):
+        """
+        Return all cells in range by row
+        """
+        for col in range(self.min_col, self.max_col+1):
+            yield tuple('%s%d' % (get_column_letter(col), row)
+                        for row in range(self.min_row, self.max_row+1))
+
+
+    @property
+    def cells(self):
+        """
+        Return a flattened list of all cells (by column)
+        """
+        return chain.from_iterable(self.cols)
+
+
+    def pop(self):
+        """
+        Return and remove the first cell
+        """
+        cell = next(self.cells)
+        if self.min_row == self.max_row:
+            self.min_col += 1
+        else:
+            self.min_row += 1
+        return cell
+
+
+    @property
+    def sheetname(self):
+        return quote_sheetname(self.worksheet.title)

+ 54 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/scatter_chart.py

@@ -0,0 +1,54 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Sequence,
+    Alias
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedNoneSet,
+    NestedBool,
+)
+
+from ._chart import ChartBase
+from .axis import NumericAxis
+from .series import XYSeries
+from .label import DataLabels
+
+
+class ScatterChart(ChartBase):
+
+    tagname = "scatterChart"
+
+    scatterStyle = NestedNoneSet(values=(['line', 'lineMarker', 'marker', 'smooth', 'smoothMarker']))
+    varyColors = NestedBool(allow_none=True)
+    ser = Sequence(expected_type=XYSeries, allow_none=True)
+    dLbls = Typed(expected_type=DataLabels, allow_none=True)
+    dataLabels = Alias("dLbls")
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    x_axis = Typed(expected_type=NumericAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+
+    _series_type = "scatter"
+
+    __elements__ = ('scatterStyle', 'varyColors', 'ser', 'dLbls', 'axId',)
+
+    def __init__(self,
+                 scatterStyle=None,
+                 varyColors=None,
+                 ser=(),
+                 dLbls=None,
+                 axId=None,
+                 extLst=None,
+                ):
+        self.scatterStyle = scatterStyle
+        self.varyColors = varyColors
+        self.ser = ser
+        self.dLbls = dLbls
+        self.x_axis = NumericAxis(axId=10, crossAx=20)
+        self.y_axis = NumericAxis(axId=20, crossAx=10)
+        super(ScatterChart, self).__init__()

+ 196 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/series.py

@@ -0,0 +1,196 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.compat import unicode
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    String,
+    Integer,
+    Bool,
+    Alias,
+    Sequence,
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedInteger,
+    NestedBool,
+    NestedNoneSet,
+    NestedText,
+)
+
+from .shapes import ShapeProperties
+from .data_source import (
+    AxDataSource,
+    NumDataSource,
+    NumRef,
+    StrRef,
+)
+from .error_bar import ErrorBars
+from .label import DataLabels
+from .marker import DataPoint, PictureOptions, Marker
+from .trendline import Trendline
+
+attribute_mapping = {
+    'area': ('idx', 'order', 'tx', 'spPr', 'pictureOptions', 'dPt', 'dLbls', 'errBars',
+             'trendline', 'cat', 'val',),
+    'bar':('idx', 'order','tx', 'spPr', 'invertIfNegative', 'pictureOptions', 'dPt',
+           'dLbls', 'trendline', 'errBars', 'cat', 'val', 'shape'),
+    'bubble':('idx','order', 'tx', 'spPr', 'invertIfNegative', 'dPt', 'dLbls',
+              'trendline', 'errBars', 'xVal', 'yVal', 'bubbleSize', 'bubble3D'),
+    'line':('idx', 'order', 'tx', 'spPr', 'marker', 'dPt', 'dLbls', 'trendline',
+            'errBars', 'cat', 'val', 'smooth'),
+    'pie':('idx', 'order', 'tx', 'spPr', 'explosion', 'dPt', 'dLbls', 'cat', 'val'),
+    'radar':('idx', 'order', 'tx', 'spPr', 'marker', 'dPt', 'dLbls', 'cat', 'val'),
+    'scatter':('idx', 'order', 'tx', 'spPr', 'marker', 'dPt', 'dLbls', 'trendline',
+               'errBars', 'xVal', 'yVal', 'smooth'),
+    'surface':('idx', 'order', 'tx', 'spPr', 'cat', 'val'),
+                     }
+
+
+class SeriesLabel(Serialisable):
+
+    tagname = "tx"
+
+    strRef = Typed(expected_type=StrRef, allow_none=True)
+    v = NestedText(expected_type=unicode, allow_none=True)
+    value = Alias('v')
+
+    __elements__ = ('strRef', 'v')
+
+    def __init__(self,
+                 strRef=None,
+                 v=None):
+        self.strRef = strRef
+        self.v = v
+
+
+class Series(Serialisable):
+
+    """
+    Generic series object. Should not be instantiated directly.
+    User the chart.Series factory instead.
+    """
+
+    tagname = "ser"
+
+    idx = NestedInteger()
+    order = NestedInteger()
+    tx = Typed(expected_type=SeriesLabel, allow_none=True)
+    title = Alias('tx')
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    shapeProperties = Alias('spPr')
+
+    # area chart
+    pictureOptions = Typed(expected_type=PictureOptions, allow_none=True)
+    dPt = Sequence(expected_type=DataPoint, allow_none=True)
+    data_points = Alias("dPt")
+    dLbls = Typed(expected_type=DataLabels, allow_none=True)
+    labels = Alias("dLbls")
+    trendline = Typed(expected_type=Trendline, allow_none=True)
+    errBars = Typed(expected_type=ErrorBars, allow_none=True)
+    cat = Typed(expected_type=AxDataSource, allow_none=True)
+    identifiers = Alias("cat")
+    val = Typed(expected_type=NumDataSource, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    #bar chart
+    invertIfNegative = NestedBool(allow_none=True)
+    shape = NestedNoneSet(values=(['cone', 'coneToMax', 'box', 'cylinder', 'pyramid', 'pyramidToMax']))
+
+    #bubble chart
+    xVal = Typed(expected_type=AxDataSource, allow_none=True)
+    yVal = Typed(expected_type=NumDataSource, allow_none=True)
+    bubbleSize = Typed(expected_type=NumDataSource, allow_none=True)
+    zVal = Alias("bubbleSize")
+    bubble3D = NestedBool(allow_none=True)
+
+    #line chart
+    marker = Typed(expected_type=Marker, allow_none=True)
+    smooth = NestedBool(allow_none=True)
+
+    #pie chart
+    explosion = NestedInteger(allow_none=True)
+
+    __elements__ = ()
+
+
+    def __init__(self,
+                 idx=0,
+                 order=0,
+                 tx=None,
+                 spPr=None,
+                 pictureOptions=None,
+                 dPt=(),
+                 dLbls=None,
+                 trendline=None,
+                 errBars=None,
+                 cat=None,
+                 val=None,
+                 invertIfNegative=None,
+                 shape=None,
+                 xVal=None,
+                 yVal=None,
+                 bubbleSize=None,
+                 bubble3D=None,
+                 marker=None,
+                 smooth=None,
+                 explosion=None
+                ):
+        self.idx = idx
+        self.order = order
+        self.tx = tx
+        if spPr is None:
+            spPr = ShapeProperties()
+        self.spPr = spPr
+        self.pictureOptions = pictureOptions
+        self.dPt = dPt
+        self.dLbls = dLbls
+        self.trendline = trendline
+        self.errBars = errBars
+        self.cat = cat
+        self.val = val
+        self.invertIfNegative = invertIfNegative
+        self.shape = shape
+        self.xVal = xVal
+        self.yVal = yVal
+        self.bubbleSize = bubbleSize
+        self.bubble3D = bubble3D
+        if marker is None:
+            marker = Marker()
+        self.marker = marker
+        self.smooth = smooth
+        self.explosion = explosion
+
+    def to_tree(self, tagname=None, idx=None):
+        if idx is not None:
+            if self.order == self.idx:
+                self.order = idx
+            self.idx = idx
+        return super(Series, self).to_tree(tagname)
+
+
+class XYSeries(Series):
+
+    """Dedicated series for charts that have x and y series"""
+
+    idx = Series.idx
+    order = Series.order
+    tx = Series.tx
+    spPr = Series.spPr
+
+    dPt = Series.dPt
+    dLbls = Series.dLbls
+    trendline = Series.trendline
+    errBars = Series.errBars
+    xVal = Series.xVal
+    yVal = Series.yVal
+
+    invertIfNegative = Series.invertIfNegative
+
+    bubbleSize = Series.bubbleSize
+    bubble3D = Series.bubble3D
+
+    marker = Series.marker
+    smooth = Series.smooth

+ 42 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/series_factory.py

@@ -0,0 +1,42 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from .data_source import NumDataSource, NumRef, AxDataSource
+from .reference import Reference
+from .series import Series, XYSeries, SeriesLabel, StrRef
+from ..utils import SHEETRANGE_RE, rows_from_range, quote_sheetname
+
+
+def SeriesFactory(values, xvalues=None, zvalues=None, title=None, title_from_data=False):
+    """
+    Convenience Factory for creating chart data series.
+    """
+
+    if not isinstance(values, Reference):
+        values = Reference(range_string=values)
+
+    if title_from_data:
+        cell = values.pop()
+        title = "{0}!{1}".format(values.sheetname, cell)
+        title = SeriesLabel(strRef=StrRef(title))
+    elif title is not None:
+        title = SeriesLabel(v=title)
+
+    source = NumDataSource(numRef=NumRef(f=values))
+    if xvalues is not None:
+        if not isinstance(xvalues, Reference):
+            xvalues = Reference(range_string=xvalues)
+        series = XYSeries()
+        series.yVal = source
+        series.xVal = AxDataSource(numRef=NumRef(f=xvalues))
+        if zvalues is not None:
+            if not isinstance(zvalues, Reference):
+                zvalues = Reference(range_string=zvalues)
+            series.zVal = NumDataSource(NumRef(f=zvalues))
+    else:
+        series = Series()
+        series.val = source
+
+    if title is not None:
+        series.title = title
+    return series

+ 91 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/shapes.py

@@ -0,0 +1,91 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Alias
+)
+from openpyxl.descriptors.nested import (
+    EmptyTag
+)
+from openpyxl.drawing.colors import ColorChoiceDescriptor
+from openpyxl.drawing.fill import *
+from openpyxl.drawing.line import LineProperties
+from openpyxl.drawing.shapes import (
+    Shape3D,
+    Scene3D,
+    Transform2D,
+    CustomGeometry2D,
+    PresetGeometry2D,
+)
+
+
+class ShapeProperties(Serialisable):
+
+    """
+    Somewhat vaguely 21.2.2.197 says this:
+
+    This element specifies the formatting for the parent chart element. The
+    custGeom, prstGeom, scene3d, and xfrm elements are not supported. The
+    bwMode attribute is not supported.
+
+    This doesn't leave much. And the element is used in different places.
+    """
+
+    tagname = "spPr"
+
+    bwMode = NoneSet(values=(['clr', 'auto', 'gray', 'ltGray', 'invGray',
+                          'grayWhite', 'blackGray', 'blackWhite', 'black', 'white', 'hidden']
+                         )
+                 )
+
+    xfrm = Typed(expected_type=Transform2D, allow_none=True)
+    transform = Alias('xfrm')
+    custGeom = Typed(expected_type=CustomGeometry2D, allow_none=True) # either or
+    prstGeom = Typed(expected_type=PresetGeometry2D, allow_none=True)
+
+    # fills one of
+    noFill = EmptyTag(namespace=DRAWING_NS)
+    solidFill = ColorChoiceDescriptor()
+    gradFill = Typed(expected_type=GradientFillProperties, allow_none=True)
+    pattFill = Typed(expected_type=PatternFillProperties, allow_none=True)
+    #pattFill = Typed(expected_type=CT_PatternFillProperties)
+    #grpFill = Typed(expected_type=CT_GroupFillProperties)
+
+    ln = Typed(expected_type=LineProperties, allow_none=True)
+    line = Alias('ln')
+    scene3d = Typed(expected_type=Scene3D, allow_none=True)
+    sp3d = Typed(expected_type=Shape3D, allow_none=True)
+    shape3D = Alias('sp3d')
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    __elements__ = ('xfrm', 'prstGeom', 'noFill', 'solidFill', 'gradFill', 'pattFill',
+                    'ln', 'scene3d', 'sp3d')
+
+    def __init__(self,
+                 bwMode=None,
+                 xfrm=None,
+                 noFill=None,
+                 solidFill=None,
+                 gradFill=None,
+                 pattFill=None,
+                 ln=None,
+                 scene3d=None,
+                 custGeom=None,
+                 prstGeom=None,
+                 sp3d=None,
+                 extLst=None,
+                ):
+        self.bwMode = bwMode
+        self.xfrm = xfrm
+        self.noFill = noFill
+        self.solidFill = solidFill
+        self.gradFill = gradFill
+        self.pattFill = pattFill
+        if ln is None:
+            ln = LineProperties()
+        self.ln = ln
+        self.custGeom = custGeom
+        self.prstGeom = prstGeom
+        self.scene3d = scene3d
+        self.sp3d = sp3d

+ 55 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/stock_chart.py

@@ -0,0 +1,55 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Sequence,
+    Alias,
+)
+from openpyxl.descriptors.excel import ExtensionList
+
+from ._chart import ChartBase
+from .axis import TextAxis, NumericAxis, ChartLines
+from .updown_bars import UpDownBars
+from .label import DataLabels
+from .series import Series
+
+
+class StockChart(ChartBase):
+
+    tagname = "stockChart"
+
+    ser = Sequence(expected_type=Series) #min 3, max4
+    dLbls = Typed(expected_type=DataLabels, allow_none=True)
+    dropLines = Typed(expected_type=ChartLines, allow_none=True)
+    hiLowLines = Typed(expected_type=ChartLines, allow_none=True)
+    upDownBars = Typed(expected_type=UpDownBars, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    x_axis = Typed(expected_type=TextAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+
+    _series_type = "line"
+
+    __elements__ = ('ser', 'dLbls', 'dropLines', 'hiLowLines', 'upDownBars',
+                    'axId')
+
+    def __init__(self,
+                 ser=None,
+                 dLbls=None,
+                 dropLines=None,
+                 hiLowLines=None,
+                 upDownBars=None,
+                 axId=None,
+                 extLst=None,
+                ):
+        self.ser = ser
+        self.dLbls = dLbls
+        self.dropLines = dropLines
+        self.hiLowLines = hiLowLines
+        self.upDownBars = upDownBars
+        self.x_axis = TextAxis()
+        self.y_axis = NumericAxis()
+        super(StockChart, self).__init__()
+

+ 119 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/surface_chart.py

@@ -0,0 +1,119 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Integer,
+    Bool,
+    Alias,
+    Sequence,
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedInteger,
+    NestedBool,
+)
+
+from ._chart import ChartBase
+from .axis import TextAxis, NumericAxis, SeriesAxis
+from .shapes import ShapeProperties
+from .series import Series
+
+
+class BandFormat(Serialisable):
+
+    tagname = "bandFmt"
+
+    idx = NestedInteger()
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+
+    __elements__ = ('idx', 'spPr')
+
+    def __init__(self,
+                 idx=0,
+                 spPr=None,
+                ):
+        self.idx = idx
+        self.spPr = spPr
+
+
+class BandFormats(Serialisable):
+
+    tagname = "bandFmts"
+
+    bandFmt = Sequence(expected_type=BandFormat, allow_none=True)
+
+    __elements__ = ('bandFmt',)
+
+    def __init__(self,
+                 bandFmt=(),
+                ):
+        self.bandFmt = bandFmt
+
+
+class _SurfaceChartBase(ChartBase):
+
+    wireframe = NestedBool(allow_none=True)
+    ser = Sequence(expected_type=Series, allow_none=True)
+    bandFmts = Typed(expected_type=BandFormats, allow_none=True)
+
+    _series_type = "surface"
+
+    __elements__ = ('wireframe', 'ser', 'bandFmts')
+
+    def __init__(self,
+                 wireframe=None,
+                 ser=(),
+                 bandFmts=None,
+                ):
+        self.wireframe = wireframe
+        self.ser = ser
+        self.bandFmts = bandFmts
+        super(_SurfaceChartBase, self).__init__()
+
+
+class SurfaceChart(_SurfaceChartBase):
+
+    tagname = "surfaceChart"
+
+    wireframe = _SurfaceChartBase.wireframe
+    ser = _SurfaceChartBase.ser
+    bandFmts = _SurfaceChartBase.bandFmts
+
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    x_axis = Typed(expected_type=TextAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+    z_axis = Typed(expected_type=SeriesAxis, allow_none=True)
+
+    __elements__ = _SurfaceChartBase.__elements__ + ('axId',)
+
+    def __init__(self, axId=None, extLst=None, **kw ):
+        self.x_axis = TextAxis()
+        self.y_axis = NumericAxis()
+        self.z_axis = None
+        super(SurfaceChart, self).__init__(**kw)
+
+
+class SurfaceChart3D(_SurfaceChartBase):
+
+    tagname = "surface3DChart"
+
+    wireframe = _SurfaceChartBase.wireframe
+    ser = _SurfaceChartBase.ser
+    bandFmts = _SurfaceChartBase.bandFmts
+
+    extLst = SurfaceChart.extLst
+
+    x_axis = Typed(expected_type=TextAxis)
+    y_axis = Typed(expected_type=NumericAxis)
+    z_axis = Typed(expected_type=SeriesAxis)
+
+    __elements__ = _SurfaceChartBase.__elements__ + ('axId',)
+
+    def __init__(self, axId=None, **kw):
+        self.x_axis = TextAxis()
+        self.y_axis = NumericAxis()
+        self.z_axis = SeriesAxis()
+        super(SurfaceChart3D, self).__init__(**kw)

+ 66 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/text.py

@@ -0,0 +1,66 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Alias,
+    Sequence,
+)
+
+
+from openpyxl.drawing.text import (
+    RichTextProperties,
+    ListStyle,
+    Paragraph,
+)
+
+from .data_source import StrRef
+
+
+class RichText(Serialisable):
+
+    """
+    From the specification: 21.2.2.216
+
+    This element specifies text formatting. The lstStyle element is not supported.
+    """
+
+    tagname = "rich"
+
+    bodyPr = Typed(expected_type=RichTextProperties)
+    properties = Alias("bodyPr")
+    lstStyle = Typed(expected_type=ListStyle, allow_none=True)
+    p = Sequence(expected_type=Paragraph, allow_none=True)
+    paragraphs = Alias('p')
+
+    __elements__ = ("bodyPr", "lstStyle", "p")
+
+    def __init__(self,
+                 bodyPr=None,
+                 lstStyle=None,
+                 p=None,
+                ):
+        if bodyPr is None:
+            bodyPr = RichTextProperties()
+        self.bodyPr = bodyPr
+        self.lstStyle = lstStyle
+        if p is None:
+            p = [Paragraph()]
+        self.p = p
+
+
+class Text(Serialisable):
+
+    strRef = Typed(expected_type=StrRef, allow_none=True)
+    rich = Typed(expected_type=RichText, allow_none=True)
+
+    __elements__ = ("strRef", "rich")
+
+    def __init__(self,
+                 strRef=None,
+                 rich=None
+                 ):
+        self.strRef = strRef
+        if rich is None:
+            rich = RichText()
+        self.rich = rich

+ 74 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/title.py

@@ -0,0 +1,74 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.compat import basestring
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Alias,
+)
+
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import NestedBool
+
+from .text import Text, RichTextProperties
+from .layout import Layout
+from .shapes import ShapeProperties
+
+from openpyxl.drawing.text import (
+    Paragraph,
+    RegularTextRun,
+    LineBreak
+)
+
+
+class Title(Serialisable):
+    tagname = "title"
+
+    tx = Typed(expected_type=Text, allow_none=True)
+    text = Alias('tx')
+    layout = Typed(expected_type=Layout, allow_none=True)
+    overlay = NestedBool(allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    shapeProperties = Alias('spPr')
+    txPr = Typed(expected_type=RichTextProperties, allow_none=True)
+    body = Alias('txPr')
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('tx', 'layout', 'overlay', 'spPr', 'txPr')
+
+    def __init__(self,
+                 tx=None,
+                 layout=None,
+                 overlay=None,
+                 spPr=None,
+                 txPr=None,
+                 extLst=None,
+                ):
+        if tx is None:
+            tx = Text()
+        self.tx = tx
+        self.layout = layout
+        self.overlay = overlay
+        self.spPr = spPr
+        self.txPr = txPr
+
+
+def title_maker(text):
+    title = Title()
+    paras = [Paragraph(r=RegularTextRun(t=s)) for s in text.split("\n")]
+
+    title.tx.rich.paragraphs = paras
+    return title
+
+
+class TitleDescriptor(Typed):
+
+    expected_type = Title
+    allow_none = True
+
+    def __set__(self, instance, value):
+        if isinstance(value, basestring):
+            value = title_maker(value)
+        super(TitleDescriptor, self).__set__(instance, value)

+ 94 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/trendline.py

@@ -0,0 +1,94 @@
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    String,
+    Alias
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedBool,
+    NestedInteger,
+    NestedFloat,
+    NestedSet
+)
+
+from .data_source import NumFmt
+from .shapes import ShapeProperties
+from .text import RichText, Text
+from .layout import Layout
+
+
+class TrendlineLabel(Serialisable):
+
+    tagname = "trendlineLbl"
+
+    layout = Typed(expected_type=Layout, allow_none=True)
+    tx = Typed(expected_type=Text, allow_none=True)
+    numFmt = Typed(expected_type=NumFmt, allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    txPr = Typed(expected_type=RichText, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('layout', 'tx', 'numFmt', 'spPr', 'txPr')
+
+    def __init__(self,
+                 layout=None,
+                 tx=None,
+                 numFmt=None,
+                 spPr=None,
+                 txPr=None,
+                 extLst=None,
+                ):
+        self.layout = layout
+        self.tx = tx
+        self.numFmt = numFmt
+        self.spPr = spPr
+        self.txPr = txPr
+
+
+class Trendline(Serialisable):
+
+    tagname = "trendline"
+
+    name = String(allow_none=True)
+    spPr = Typed(expected_type=ShapeProperties, allow_none=True)
+    shapeProperties = Alias('spPr')
+    trendlineType = NestedSet(values=(['exp', 'linear', 'log', 'movingAvg', 'poly', 'power']))
+    order = NestedInteger(allow_none=True)
+    period = NestedInteger(allow_none=True)
+    forward = NestedFloat(allow_none=True)
+    backward = NestedFloat(allow_none=True)
+    intercept = NestedFloat(allow_none=True)
+    dispRSqr = NestedBool(allow_none=True)
+    dispEq = NestedBool(allow_none=True)
+    trendlineLbl = Typed(expected_type=TrendlineLabel, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('name', 'spPr', 'trendlineType', 'order', 'period',
+                    'forward', 'backward', 'intercept', 'dispRSqr', 'dispEq', 'trendlineLbl')
+
+    def __init__(self,
+                 name=None,
+                 spPr=None,
+                 trendlineType='linear',
+                 order=None,
+                 period=None,
+                 forward=None,
+                 backward=None,
+                 intercept=None,
+                 dispRSqr=None,
+                 dispEq=None,
+                 trendlineLbl=None,
+                 extLst=None,
+                ):
+        self.name = name
+        self.spPr = spPr
+        self.trendlineType = trendlineType
+        self.order = order
+        self.period = period
+        self.forward = forward
+        self.backward = backward
+        self.intercept = intercept
+        self.dispRSqr = dispRSqr
+        self.dispEq = dispEq
+        self.trendlineLbl = trendlineLbl

+ 32 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/chart/updown_bars.py

@@ -0,0 +1,32 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import Typed
+from openpyxl.descriptors.excel import ExtensionList
+
+from .shapes import ShapeProperties
+from .axis import ChartLines
+from .descriptors import NestedGapAmount
+
+
+class UpDownBars(Serialisable):
+
+    tagname = "upbars"
+
+    gapWidth = NestedGapAmount()
+    upBars = Typed(expected_type=ChartLines, allow_none=True)
+    downBars = Typed(expected_type=ChartLines, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('gapWidth', 'upBars', 'downBars')
+
+    def __init__(self,
+                 gapWidth=150,
+                 upBars=None,
+                 downBars=None,
+                 extLst=None,
+                ):
+        self.gapWidth = gapWidth
+        self.upBars = upBars
+        self.downBars = downBars

+ 5 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/comments/__init__.py

@@ -0,0 +1,5 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+
+from .comments import *

+ 49 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/comments/comments.py

@@ -0,0 +1,49 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+
+class Comment(object):
+    __slots__ = ('_parent',
+                 '_text',
+                 '_author',
+                 '_width',
+                 '_height')
+
+    def __init__(self, text, author):
+        self._text = text
+        self._author = author
+        self._parent = None
+        self._width = '108pt'
+        self._height = '59.25pt'
+
+    @property
+    def author(self):
+        """ The name recorded for the author
+
+            :rtype: string
+        """
+        return self._author
+    @author.setter
+    def author(self, value):
+        self._author = value
+
+    @property
+    def text(self):
+        """ The text of the commment
+
+            :rtype: string
+        """
+        return self._text
+    @text.setter
+    def text(self, value):
+        self._text = value
+
+    @property
+    def parent(self):
+        return self._parent
+
+    @parent.setter
+    def parent(self, cell):
+        if cell is not None and self._parent is not None and self._parent != cell:
+            raise AttributeError("Comment already assigned to %s in worksheet %s. Cannot assign a comment to more than one cell" % (cell.coordinate, cell.parent.title))
+        self._parent = cell

+ 81 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/__init__.py

@@ -0,0 +1,81 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+
+from tempfile import NamedTemporaryFile
+
+from .strings import (
+    basestring,
+    unicode,
+    bytes,
+    file,
+    tempfile,
+    safe_string
+    )
+from .numbers import long, NUMERIC_TYPES
+from .itertools import (
+    range,
+    iteritems,
+    iterkeys,
+    itervalues,
+    zip,
+)
+try:
+    from functools import lru_cache
+except ImportError:
+    from .functools import lru_cache
+
+# Python 2.6
+try:
+    from collections import OrderedDict
+except ImportError:
+    from .odict import OrderedDict
+
+import warnings
+from functools import wraps
+import inspect
+
+
+class DummyCode:
+
+    pass
+
+
+class deprecated(object):
+
+    def __init__(self, reason):
+        if inspect.isclass(reason) or inspect.isfunction(reason):
+            raise TypeError("Reason for deprecation must be supplied")
+        self.reason = reason
+
+    def __call__(self, obj, *args, **kwargs):
+        @wraps(obj)
+        def new_func(*args, **kwargs):
+            msg = "Call to deprecated function or class {0} ({1})".format(obj.__name__,
+                                                               self.reason)
+            if inspect.isfunction(obj):
+                _code = self._wrap_function(obj)
+            elif inspect.isclass(obj):
+                _code = self._wrap_class(obj)
+
+            warnings.warn_explicit(
+                '{0}.'.format(msg),
+                category=UserWarning,
+                filename=_code.co_filename,
+                lineno=_code.co_firstlineno + 1
+            )
+            return obj(*args, **kwargs)
+        return new_func
+
+    def _wrap_function(self, obj):
+        if hasattr(obj, 'func_code'):
+            _code = obj.func_code
+        else:
+            _code = obj.__code__
+        return _code
+
+    def _wrap_class(self, obj):
+        _code = DummyCode()
+        _code.co_filename = obj.__module__
+        _code.co_firstlineno = 0
+        return _code

+ 9 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/abc.py

@@ -0,0 +1,9 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+
+try:
+    from abc import ABC
+except ImportError:
+    from abc import ABCMeta
+    ABC = ABCMeta('ABC', (object, ), {})

+ 170 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/functools.py

@@ -0,0 +1,170 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+# lru_cache backport copyright Raymong Hettinger
+# http://code.activestate.com/recipes/578078-py26-and-py30-backport-of-python-33s-lru-cache/?in=user-178123
+
+from collections import namedtuple
+from functools import update_wrapper
+from threading import RLock
+
+_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
+
+class _HashedSeq(list):
+    __slots__ = 'hashvalue'
+
+    def __init__(self, tup, hash=hash):
+        self[:] = tup
+        self.hashvalue = hash(tup)
+
+    def __hash__(self):
+        return self.hashvalue
+
+def _make_key(args, kwds, typed,
+             kwd_mark = (object(),),
+             fasttypes = set((int, str, frozenset, type(None))),
+             sorted=sorted, tuple=tuple, type=type, len=len):
+    'Make a cache key from optionally typed positional and keyword arguments'
+    key = args
+    if kwds:
+        sorted_items = sorted(kwds.items())
+        key += kwd_mark
+        for item in sorted_items:
+            key += item
+    if typed:
+        key += tuple(type(v) for v in args)
+        if kwds:
+            key += tuple(type(v) for k, v in sorted_items)
+    elif len(key) == 1 and type(key[0]) in fasttypes:
+        return key[0]
+    return _HashedSeq(key)
+
+def lru_cache(maxsize=100, typed=False):
+    """Least-recently-used cache decorator.
+
+    If *maxsize* is set to None, the LRU features are disabled and the cache
+    can grow without bound.
+
+    If *typed* is True, arguments of different types will be cached separately.
+    For example, f(3.0) and f(3) will be treated as distinct calls with
+    distinct results.
+
+    Arguments to the cached function must be hashable.
+
+    View the cache statistics named tuple (hits, misses, maxsize, currsize) with
+    f.cache_info().  Clear the cache and statistics with f.cache_clear().
+    Access the underlying function with f.__wrapped__.
+
+    See:  http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
+
+    """
+
+    # Users should only access the lru_cache through its public API:
+    #       cache_info, cache_clear, and f.__wrapped__
+    # The internals of the lru_cache are encapsulated for thread safety and
+    # to allow the implementation to change (including a possible C version).
+
+    def decorating_function(user_function):
+
+        cache = dict()
+        stats = [0, 0]                  # make statistics updateable non-locally
+        HITS, MISSES = 0, 1             # names for the stats fields
+        make_key = _make_key
+        cache_get = cache.get           # bound method to lookup key or return None
+        _len = len                      # localize the global len() function
+        lock = RLock()                  # because linkedlist updates aren't threadsafe
+        root = []                       # root of the circular doubly linked list
+        root[:] = [root, root, None, None]      # initialize by pointing to self
+        nonlocal_root = [root]                  # make updateable non-locally
+        PREV, NEXT, KEY, RESULT = 0, 1, 2, 3    # names for the link fields
+
+        if maxsize == 0:
+
+            def wrapper(*args, **kwds):
+                # no caching, just do a statistics update after a successful call
+                result = user_function(*args, **kwds)
+                stats[MISSES] += 1
+                return result
+
+        elif maxsize is None:
+
+            def wrapper(*args, **kwds):
+                # simple caching without ordering or size limit
+                key = make_key(args, kwds, typed)
+                result = cache_get(key, root)   # root used here as a unique not-found sentinel
+                if result is not root:
+                    stats[HITS] += 1
+                    return result
+                result = user_function(*args, **kwds)
+                cache[key] = result
+                stats[MISSES] += 1
+                return result
+
+        else:
+
+            def wrapper(*args, **kwds):
+                # size limited caching that tracks accesses by recency
+                key = make_key(args, kwds, typed) if kwds or typed else args
+                with lock:
+                    link = cache_get(key)
+                    if link is not None:
+                        # record recent use of the key by moving it to the front of the list
+                        root, = nonlocal_root
+                        link_prev, link_next, key, result = link
+                        link_prev[NEXT] = link_next
+                        link_next[PREV] = link_prev
+                        last = root[PREV]
+                        last[NEXT] = root[PREV] = link
+                        link[PREV] = last
+                        link[NEXT] = root
+                        stats[HITS] += 1
+                        return result
+                result = user_function(*args, **kwds)
+                with lock:
+                    root, = nonlocal_root
+                    if key in cache:
+                        # getting here means that this same key was added to the
+                        # cache while the lock was released.  since the link
+                        # update is already done, we need only return the
+                        # computed result and update the count of misses.
+                        pass
+                    elif _len(cache) >= maxsize:
+                        # use the old root to store the new key and result
+                        oldroot = root
+                        oldroot[KEY] = key
+                        oldroot[RESULT] = result
+                        # empty the oldest link and make it the new root
+                        root = nonlocal_root[0] = oldroot[NEXT]
+                        oldkey = root[KEY]
+                        oldvalue = root[RESULT]
+                        root[KEY] = root[RESULT] = None
+                        # now update the cache dictionary for the new links
+                        del cache[oldkey]
+                        cache[key] = oldroot
+                    else:
+                        # put result in a new link at the front of the list
+                        last = root[PREV]
+                        link = [last, root, key, result]
+                        last[NEXT] = root[PREV] = cache[key] = link
+                    stats[MISSES] += 1
+                return result
+
+        def cache_info():
+            """Report cache statistics"""
+            with lock:
+                return _CacheInfo(stats[HITS], stats[MISSES], maxsize, len(cache))
+
+        def cache_clear():
+            """Clear the cache and cache statistics"""
+            with lock:
+                cache.clear()
+                root = nonlocal_root[0]
+                root[:] = [root, root, None, None]
+                stats[:] = [0, 0]
+
+        wrapper.__wrapped__ = user_function
+        wrapper.cache_info = cache_info
+        wrapper.cache_clear = cache_clear
+        return update_wrapper(wrapper, user_function)
+
+    return decorating_function

+ 37 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/itertools.py

@@ -0,0 +1,37 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+try:
+    from itertools import izip as zip
+except ImportError:
+    zip = zip
+
+try:
+    range = xrange
+except NameError:
+    range = range
+
+def iteritems(iterable):
+    if hasattr(iterable, 'iteritems'):
+        for item in iterable.iteritems():
+            yield item
+    else:
+        for item in iterable.items():
+            yield item
+
+def iterkeys(iterable):
+    if hasattr(iterable, 'iterkeys'):
+        for item in iterable.iterkeys():
+            yield item
+    else:
+        for item in iterable.keys():
+            yield item
+
+
+def itervalues(iterable):
+    if hasattr(iterable, 'itervalues'):
+        for item in iterable.itervalues():
+            yield item
+    else:
+        for item in iterable.values():
+            yield item

+ 14 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/numbers.py

@@ -0,0 +1,14 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+try:
+    # Python 2
+    long = long
+except NameError:
+    # Python 3
+    long = int
+
+from decimal import Decimal
+
+NUMERIC_TYPES = (int, float, long, Decimal)
+

+ 269 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/odict.py

@@ -0,0 +1,269 @@
+# Copyright (c) 2001-2011 Python Software Foundation
+#               2011 Raymond Hettinger
+# License: PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+#          See http://www.opensource.org/licenses/Python-2.0 for full terms
+# Note: backport changes by Raymond were originally distributed under MIT
+#       license, but since the original license for Python is more
+#       restrictive than MIT, code cannot be released under its terms and
+#       still adheres to the limitations of Python license.
+
+# # {{{ http://code.activestate.com/recipes/576693/ (r9)
+# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
+# Passes Python2.7's test suite and incorporates all the latest updates.
+
+try:
+    from thread import get_ident as _get_ident
+except ImportError:
+    from dummy_thread import get_ident as _get_ident
+
+try:
+    from _abcoll import KeysView, ValuesView, ItemsView
+except ImportError:
+    pass
+
+
+class OrderedDict(dict):
+    'Dictionary that remembers insertion order'
+    # An inherited dict maps keys to values.
+    # The inherited dict provides __getitem__, __len__, __contains__, and get.
+    # The remaining methods are order-aware.
+    # Big-O running times for all methods are the same as for regular dictionaries.
+
+    # The internal self.__map dictionary maps keys to links in a doubly linked list.
+    # The circular doubly linked list starts and ends with a sentinel element.
+    # The sentinel element never gets deleted (this simplifies the algorithm).
+    # Each link is stored as a list of length three:  [PREV, NEXT, KEY].
+
+    def __init__(self, *args, **kwds):
+        '''Initialize an ordered dictionary.  Signature is the same as for
+        regular dictionaries, but keyword arguments are not recommended
+        because their insertion order is arbitrary.
+
+        '''
+        if len(args) > 1:
+            raise TypeError('expected at most 1 arguments, got %d' % len(args))
+        try:
+            self.__root
+        except AttributeError:
+            self.__root = root = []  # sentinel node
+            root[:] = [root, root, None]
+            self.__map = {}
+        self.__update(*args, **kwds)
+
+    def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
+        'od.__setitem__(i, y) <==> od[i]=y'
+        # Setting a new item creates a new link which goes at the end of the linked
+        # list, and the inherited dictionary is updated with the new key/value pair.
+        if key not in self:
+            root = self.__root
+            last = root[0]
+            last[1] = root[0] = self.__map[key] = [last, root, key]
+        dict_setitem(self, key, value)
+
+    def __delitem__(self, key, dict_delitem=dict.__delitem__):
+        'od.__delitem__(y) <==> del od[y]'
+        # Deleting an existing item uses self.__map to find the link which is
+        # then removed by updating the links in the predecessor and successor nodes.
+        dict_delitem(self, key)
+        link_prev, link_next, key = self.__map.pop(key)
+        link_prev[1] = link_next
+        link_next[0] = link_prev
+
+    def __iter__(self):
+        'od.__iter__() <==> iter(od)'
+        root = self.__root
+        curr = root[1]
+        while curr is not root:
+            yield curr[2]
+            curr = curr[1]
+
+    def __reversed__(self):
+        'od.__reversed__() <==> reversed(od)'
+        root = self.__root
+        curr = root[0]
+        while curr is not root:
+            yield curr[2]
+            curr = curr[0]
+
+    def clear(self):
+        'od.clear() -> None.  Remove all items from od.'
+        try:
+            for node in self.__map.itervalues():
+                del node[:]
+            root = self.__root
+            root[:] = [root, root, None]
+            self.__map.clear()
+        except AttributeError:
+            pass
+        dict.clear(self)
+
+    def popitem(self, last=True):
+        '''od.popitem() -> (k, v), return and remove a (key, value) pair.
+        Pairs are returned in LIFO order if last is true or FIFO order if false.
+
+        '''
+        if not self:
+            raise KeyError('dictionary is empty')
+        root = self.__root
+        if last:
+            link = root[0]
+            link_prev = link[0]
+            link_prev[1] = root
+            root[0] = link_prev
+        else:
+            link = root[1]
+            link_next = link[1]
+            root[1] = link_next
+            link_next[0] = root
+        key = link[2]
+        del self.__map[key]
+        value = dict.pop(self, key)
+        return key, value
+
+    # -- the following methods do not depend on the internal structure --
+
+    def keys(self):
+        'od.keys() -> list of keys in od'
+        return list(self)
+
+    def values(self):
+        'od.values() -> list of values in od'
+        return [self[key] for key in self]
+
+    def items(self):
+        'od.items() -> list of (key, value) pairs in od'
+        return [(key, self[key]) for key in self]
+
+    def iterkeys(self):
+        'od.iterkeys() -> an iterator over the keys in od'
+        return iter(self)
+
+    def itervalues(self):
+        'od.itervalues -> an iterator over the values in od'
+        for k in self:
+            yield self[k]
+
+    def iteritems(self):
+        'od.iteritems -> an iterator over the (key, value) items in od'
+        for k in self:
+            yield (k, self[k])
+
+    def update(*args, **kwds):
+        '''od.update(E, **F) -> None.  Update od from dict/iterable E and F.
+
+        If E is a dict instance, does:           for k in E: od[k] = E[k]
+        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
+        Or if E is an iterable of items, does:   for k, v in E: od[k] = v
+        In either case, this is followed by:     for k, v in F.items(): od[k] = v
+
+        '''
+        if len(args) > 2:
+            raise TypeError('update() takes at most 2 positional '
+                            'arguments (%d given)' % (len(args),))
+        elif not args:
+            raise TypeError('update() takes at least 1 argument (0 given)')
+        self = args[0]
+        # Make progressively weaker assumptions about "other"
+        other = ()
+        if len(args) == 2:
+            other = args[1]
+        if isinstance(other, dict):
+            for key in other:
+                self[key] = other[key]
+        elif hasattr(other, 'keys'):
+            for key in other.keys():
+                self[key] = other[key]
+        else:
+            for key, value in other:
+                self[key] = value
+        for key, value in kwds.items():
+            self[key] = value
+
+    __update = update  # let subclasses override update without breaking __init__
+
+    __marker = object()
+
+    def pop(self, key, default=__marker):
+        '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
+        If key is not found, d is returned if given, otherwise KeyError is raised.
+
+        '''
+        if key in self:
+            result = self[key]
+            del self[key]
+            return result
+        if default is self.__marker:
+            raise KeyError(key)
+        return default
+
+    def setdefault(self, key, default=None):
+        'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
+        if key in self:
+            return self[key]
+        self[key] = default
+        return default
+
+    def __repr__(self, _repr_running={}):
+        'od.__repr__() <==> repr(od)'
+        call_key = id(self), _get_ident()
+        if call_key in _repr_running:
+            return '...'
+        _repr_running[call_key] = 1
+        try:
+            if not self:
+                return '%s()' % (self.__class__.__name__,)
+            return '%s(%r)' % (self.__class__.__name__, self.items())
+        finally:
+            del _repr_running[call_key]
+
+    def __reduce__(self):
+        'Return state information for pickling'
+        items = [[k, self[k]] for k in self]
+        inst_dict = vars(self).copy()
+        for k in vars(OrderedDict()):
+            inst_dict.pop(k, None)
+        if inst_dict:
+            return (self.__class__, (items,), inst_dict)
+        return self.__class__, (items,)
+
+    def copy(self):
+        'od.copy() -> a shallow copy of od'
+        return self.__class__(self)
+
+    @classmethod
+    def fromkeys(cls, iterable, value=None):
+        '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
+        and values equal to v (which defaults to None).
+
+        '''
+        d = cls()
+        for key in iterable:
+            d[key] = value
+        return d
+
+    def __eq__(self, other):
+        '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive
+        while comparison to a regular mapping is order-insensitive.
+
+        '''
+        if isinstance(other, OrderedDict):
+            return len(self) == len(other) and self.items() == other.items()
+        return dict.__eq__(self, other)
+
+    def __ne__(self, other):
+        return not self == other
+
+    # -- the following methods are only used in Python 2.7 --
+
+    def viewkeys(self):
+        "od.viewkeys() -> a set-like object providing a view on od's keys"
+        return KeysView(self)
+
+    def viewvalues(self):
+        "od.viewvalues() -> an object providing a view on od's values"
+        return ValuesView(self)
+
+    def viewitems(self):
+        "od.viewitems() -> a set-like object providing a view on od's items"
+        return ItemsView(self)
+# # end of http://code.activestate.com/recipes/576693/ }}}

+ 41 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/singleton.py

@@ -0,0 +1,41 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+import weakref
+
+
+class Singleton(type):
+    """
+    Singleton metaclass
+    Based on Python Cookbook 3rd Edition Recipe 9.13
+    Only one instance of a class can exist. Does not work with __slots__
+    """
+
+    def __init__(self, *args, **kw):
+        super(Singleton, self).__init__(*args, **kw)
+        self.__instance = None
+
+    def __call__(self, *args, **kw):
+        if self.__instance is None:
+            self.__instance = super(Singleton, self).__call__(*args, **kw)
+        return self.__instance
+
+
+class Cached(type):
+    """
+    Caching metaclass
+    Child classes will only create new instances of themselves if
+    one doesn't already exist. Does not work with __slots__
+    """
+
+    def __init__(self, *args, **kw):
+        super(Singleton, self).__init__(*args, **kw)
+        self.__cache = weakref.WeakValueDictionary()
+
+    def __call__(self, *args):
+        if args in self.__cache:
+            return self.__cache[args]
+
+        obj = super(Singleton, self).__call__(*args)
+        self.__cache[args] = obj
+        return obj

+ 36 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/compat/strings.py

@@ -0,0 +1,36 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+
+from __future__ import absolute_import
+import sys
+
+VER = sys.version_info
+
+from .numbers import NUMERIC_TYPES
+
+if VER[0] == 3:
+    basestring = str
+    unicode = str
+    from io import BufferedReader
+    file = BufferedReader
+    from io import BufferedRandom
+    tempfile = BufferedRandom
+    bytes = bytes
+else:
+    basestring = basestring
+    unicode = unicode
+    file = file
+    tempfile = file
+    bytes = str
+
+
+def safe_string(value):
+    """Safely and consistently format numeric values"""
+    if isinstance(value, NUMERIC_TYPES):
+        value = "%.16g" % value
+    elif value is None:
+        value = "none"
+    elif not isinstance(value, basestring):
+        value = str(value)
+    return value

+ 50 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/conftest.py

@@ -0,0 +1,50 @@
+import pytest
+
+# Global objects under tests
+
+@pytest.fixture
+def Workbook():
+    """Workbook Class"""
+    from openpyxl import Workbook
+    return Workbook
+
+
+@pytest.fixture
+def Worksheet():
+    """Worksheet Class"""
+    from openpyxl.worksheet import Worksheet
+    return Worksheet
+
+
+# Global fixtures
+
+@pytest.fixture
+def root_xml():
+    """Root XML element <test>"""
+    from openpyxl.xml.functions import Element
+    return Element("test")
+
+
+### Markers ###
+
+def pytest_runtest_setup(item):
+    if isinstance(item, item.Function):
+        try:
+            from PIL import Image
+        except ImportError:
+            Image = False
+        if item.get_marker("pil_required") and Image is False:
+            pytest.skip("PIL must be installed")
+        elif item.get_marker("pil_not_installed") and Image:
+            pytest.skip("PIL is installed")
+        elif item.get_marker("not_py33"):
+            pytest.skip("Ordering is not a given in Python 3")
+        elif item.get_marker("lxml_required"):
+            from openpyxl import LXML
+            if not LXML:
+                pytest.skip("LXML is required for some features such as schema validation")
+        elif item.get_marker("lxml_buffering"):
+            from lxml.etree import LIBXML_VERSION
+            if LIBXML_VERSION < (3, 4, 0, 0):
+                pytest.skip("LXML >= 3.4 is required")
+

+ 57 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/__init__.py

@@ -0,0 +1,57 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from .base import *
+
+
+class MetaStrict(type):
+
+    def __new__(cls, clsname, bases, methods):
+        for k, v in methods.items():
+            if isinstance(v, Descriptor):
+                v.name = k
+        return type.__new__(cls, clsname, bases, methods)
+
+
+class MetaSerialisable(type):
+
+    def __new__(cls, clsname, bases, methods):
+        attrs = []
+        nested = []
+        elements = []
+        namespaced = []
+        for k, v in methods.items():
+            if isinstance(v, Descriptor):
+                ns= getattr(v, 'namespace', None)
+                if ns:
+                    namespaced.append((k, "{%s}%s" % (ns, k)))
+                if getattr(v, 'nested', False):
+                    nested.append(k)
+                    elements.append(k)
+                elif isinstance(v, Sequence):
+                    elements.append(k)
+                elif isinstance(v, Typed):
+                    if hasattr(v.expected_type, 'to_tree'):
+                        elements.append(k)
+                    else:
+                        attrs.append(k)
+                else:
+                    if not isinstance(v, Alias):
+                        attrs.append(k)
+
+        if methods.get('__attrs__') is None:
+            methods['__attrs__'] = tuple(attrs)
+        methods['__namespaced__'] = tuple(namespaced)
+        if methods.get('__nested__') is None:
+            methods['__nested__'] = tuple(sorted(nested))
+        if methods.get('__elements__') is None:
+            methods['__elements__'] = tuple(sorted(elements))
+        return MetaStrict.__new__(cls, clsname, bases, methods)
+
+
+Strict = MetaStrict('Strict', (object,), {})
+
+_Serialiasable = MetaSerialisable('_Serialisable', (object,), {})
+
+#del MetaStrict
+#del MetaSerialisable

+ 261 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/base.py

@@ -0,0 +1,261 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+
+"""
+Based on Python Cookbook 3rd Edition, 8.13
+http://chimera.labs.oreilly.com/books/1230000000393/ch08.html#_discussion_130
+"""
+
+from openpyxl.compat import basestring, bytes, long
+import re
+
+class Descriptor(object):
+
+    def __init__(self, name=None, **kw):
+        self.name = name
+        for k, v in kw.items():
+            setattr(self, k, v)
+
+    def __set__(self, instance, value):
+        instance.__dict__[self.name] = value
+
+
+class Typed(Descriptor):
+    """Values must of a particular type"""
+
+    expected_type = type(None)
+    allow_none = False
+    nested = False
+
+    def __init__(self, *args, **kw):
+        super(Typed, self).__init__(*args, **kw)
+        self.__doc__ = "Values must be of type {0}".format(self.expected_type)
+
+    def __set__(self, instance, value):
+        if not isinstance(value, self.expected_type):
+            if (not self.allow_none
+                or (self.allow_none and value is not None)):
+                raise TypeError('expected ' + str(self.expected_type))
+        super(Typed, self).__set__(instance, value)
+
+    def __repr__(self):
+        return  self.__doc__
+
+
+def _convert(expected_type, value):
+    """
+    Check value is of or can be converted to expected type.
+    """
+    if not isinstance(value, expected_type):
+        try:
+            value = expected_type(value)
+        except:
+            raise TypeError('expected ' + str(expected_type))
+    return value
+
+
+class Convertible(Typed):
+    """Values must be convertible to a particular type"""
+
+    def __set__(self, instance, value):
+        if ((self.allow_none and value is not None)
+            or not self.allow_none):
+            value = _convert(self.expected_type, value)
+        super(Convertible, self).__set__(instance, value)
+
+
+class Max(Convertible):
+    """Values must be less than a `max` value"""
+
+    expected_type = float
+    allow_none = False
+
+    def __init__(self, **kw):
+        if 'max' not in kw and not hasattr(self, 'max'):
+            raise TypeError('missing max value')
+        super(Max, self).__init__(**kw)
+
+    def __set__(self, instance, value):
+        if ((self.allow_none and value is not None)
+            or not self.allow_none):
+            value = _convert(self.expected_type, value)
+            if value > self.max:
+                raise ValueError('Max value is {0}'.format(self.max))
+        super(Max, self).__set__(instance, value)
+
+
+class Min(Convertible):
+    """Values must be greater than a `min` value"""
+
+    expected_type = float
+    allow_none = False
+
+    def __init__(self, **kw):
+        if 'min' not in kw and not hasattr(self, 'min'):
+            raise TypeError('missing min value')
+        super(Min, self).__init__(**kw)
+
+    def __set__(self, instance, value):
+        if ((self.allow_none and value is not None)
+            or not self.allow_none):
+            value = _convert(self.expected_type, value)
+            if value < self.min:
+                raise ValueError('Min value is {0}'.format(self.min))
+        super(Min, self).__set__(instance, value)
+
+
+class MinMax(Min, Max):
+    """Values must be greater than `min` value and less than a `max` one"""
+    pass
+
+
+class Set(Descriptor):
+    """Value can only be from a set of know values"""
+
+    def __init__(self, name=None, **kw):
+        if not 'values' in kw:
+            raise TypeError("missing set of values")
+        kw['values'] = set(kw['values'])
+        super(Set, self).__init__(name, **kw)
+        self.__doc__ = "Value must be one of {0}".format(self.values)
+
+    def __set__(self, instance, value):
+        if value not in self.values:
+            raise ValueError(self.__doc__)
+        super(Set, self).__set__(instance, value)
+
+
+class NoneSet(Set):
+
+    """'none' will be treated as None"""
+
+    def __init__(self, name=None, **kw):
+        super(NoneSet, self).__init__(name, **kw)
+        self.values.add(None)
+
+    def __set__(self, instance, value):
+        if value == 'none':
+            value = None
+        super(NoneSet, self).__set__(instance, value)
+
+
+class Integer(Convertible):
+
+    expected_type = long
+
+
+class Float(Convertible):
+
+    expected_type = float
+
+
+class Bool(Convertible):
+
+    expected_type = bool
+
+    def __set__(self, instance, value):
+        if isinstance(value, str):
+            if value in ('false', 'f', '0'):
+                value = False
+        super(Bool, self).__set__(instance, value)
+
+
+class String(Typed):
+
+    expected_type = basestring
+
+
+class ASCII(Typed):
+
+    expected_type = bytes
+
+
+class Tuple(Typed):
+
+    expected_type = tuple
+
+
+class Sequence(Descriptor):
+    """
+    A sequence (list or tuple) that may only contain objects of the declared
+    type
+    """
+
+    expected_type = type(None)
+    seq_types = (list, tuple)
+
+    def __set__(self, instance, seq):
+        if not isinstance(seq, self.seq_types):
+            raise TypeError("Value must be a sequence")
+        seq = [_convert(self.expected_type, value) for value in seq]
+
+        super(Sequence, self).__set__(instance, seq)
+
+
+class Length(Descriptor):
+
+    def __init__(self, name=None, **kw):
+        if "length" not in kw:
+            raise TypeError("value length must be supplied")
+        super(Length, self).__init__(**kw)
+
+
+    def __set__(self, instance, value):
+        if len(value) != self.length:
+            raise ValueError("Value must be length {0}".format(self.length))
+        super(Length, self).__set__(instance, value)
+
+
+class Default(Typed):
+    """
+    When called returns an instance of the expected type.
+    Additional default values can be passed in to the descriptor
+    """
+
+    def __init__(self, name=None, **kw):
+        if "defaults" not in kw:
+            kw['defaults'] = {}
+        super(Default, self).__init__(**kw)
+
+    def __call__(self):
+        return self.expected_type()
+
+
+class Alias(Descriptor):
+    """
+    Aliases can be used when either the desired attribute name is not allowed
+    or confusing in Python (eg. "type") or a more descriptve name is desired
+    (eg. "underline" for "u")
+    """
+
+    def __init__(self, alias):
+        self.alias = alias
+
+    def __set__(self, instance, value):
+        setattr(instance, self.alias, value)
+
+    def __get__(self, instance, cls):
+        return getattr(instance, self.alias)
+
+
+class MatchPattern(Descriptor):
+    """Values must match a regex pattern """
+    allow_none = False
+
+    def __init__(self, name=None, **kw):
+        if 'pattern' not in kw and not hasattr(self, 'pattern'):
+            raise TypeError('missing pattern value')
+
+        super(MatchPattern, self).__init__(name, **kw)
+        self.test_pattern = re.compile(self.pattern)
+
+
+    def __set__(self, instance, value):
+
+        if ((self.allow_none and value is not None)
+            or not self.allow_none):
+            if not self.test_pattern.match(value):
+                raise ValueError('Value does not match pattern {0}'.format(self.pattern))
+
+        super(MatchPattern, self).__set__(instance, value)

+ 66 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/excel.py

@@ -0,0 +1,66 @@
+from __future__ import absolute_import
+#copyright openpyxl 2010-2015
+
+"""
+Excel specific descriptors
+"""
+
+from openpyxl.compat import basestring
+from openpyxl.xml.constants import REL_NS
+from . import MatchPattern, MinMax, Integer, String, Typed, Sequence
+from .serialisable import Serialisable
+
+
+class HexBinary(MatchPattern):
+
+    pattern = "[0-9a-fA-F]+$"
+
+
+class UniversalMeasure(MatchPattern):
+
+    pattern = "[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"
+
+
+class TextPoint(MinMax):
+    """
+    Size in hundredths of points.
+    In theory other units of measurement can be used but these are unbounded
+    """
+    expected_type = int
+
+    min = -400000
+    max = 400000
+
+
+Coordinate = Integer
+
+
+class Percentage(MatchPattern):
+
+    pattern = "((100)|([0-9][0-9]?))(\.[0-9][0-9]?)?%"
+
+
+class Extension(Serialisable):
+
+    uri = String()
+
+    def __init__(self,
+                 uri=None,
+                ):
+        self.uri = uri
+
+
+class ExtensionList(Serialisable):
+
+    ext = Sequence(expected_type=Extension)
+
+    def __init__(self,
+                 ext=None,
+                ):
+        self.ext = ext
+
+
+class Relation(String):
+
+    namespace = REL_NS
+    allow_none = True

+ 141 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/nested.py

@@ -0,0 +1,141 @@
+from __future__ import absolute_import
+#copyright openpyxl 2010-2015
+
+"""
+Generic serialisable classes
+"""
+from .base import (
+    Convertible,
+    Bool,
+    Descriptor,
+    NoneSet,
+    MinMax,
+    Sequence,
+    Set,
+    Float,
+    Integer,
+    String,
+    )
+from openpyxl.compat import safe_string
+from openpyxl.xml.functions import Element, localname
+
+
+class Nested(Descriptor):
+
+    nested = True
+    attribute = "val"
+
+    def __set__(self, instance, value):
+        if hasattr(value, "tag"):
+            tag = localname(value)
+            if tag != self.name:
+                raise ValueError("Tag does not match attribute")
+
+            value = self.from_tree(value)
+        super(Nested, self).__set__(instance, value)
+
+
+    def from_tree(self, node):
+        return node.get(self.attribute)
+
+
+    def to_tree(self, tagname=None, value=None, namespace=None):
+        namespace = getattr(self, "namespace", namespace)
+        if value is not None:
+            if namespace is not None:
+                tagname = "{%s}%s" % (namespace, tagname)
+            value = safe_string(value)
+            return Element(tagname, {self.attribute:value})
+
+
+class NestedValue(Nested, Convertible):
+    """
+    Nested tag storing the value on the 'val' attribute
+    """
+    pass
+
+
+class NestedText(NestedValue):
+    """
+    Represents any nested tag with the value as the contents of the tag
+    """
+
+
+    def from_tree(self, node):
+        return node.text
+
+
+    def to_tree(self, tagname=None, value=None, namespace=None):
+        namespace = getattr(self, "namespace", namespace)
+        if value is not None:
+            if namespace is not None:
+                tagname = "{%s}%s" % (namespace, tagname)
+            el = Element(tagname)
+            el.text = safe_string(value)
+            return el
+
+
+class NestedFloat(NestedValue, Float):
+
+    pass
+
+
+class NestedInteger(NestedValue, Integer):
+
+    pass
+
+
+class NestedString(NestedValue, String):
+
+    pass
+
+
+class NestedBool(NestedValue, Bool):
+
+
+    def from_tree(self, node):
+        return node.get("val", True)
+
+
+class NestedNoneSet(Nested, NoneSet):
+
+    pass
+
+
+class NestedSet(Nested, Set):
+
+    pass
+
+
+class NestedMinMax(Nested, MinMax):
+
+    pass
+
+
+class NestedSequence(Nested, Sequence):
+
+
+    def to_tree(self, tagname, value, namespace=None):
+        namespace = getattr(self, "namespace", namespace)
+        if namespace is not None:
+            tagname = "{%s}%s" % (namespace, tagname)
+        for s in value:
+            yield Element(tagname, val=safe_string(s))
+
+
+class EmptyTag(Nested, Bool):
+
+    """
+    Boolean if a tag exists or not.
+    """
+
+    def from_tree(self, node):
+        return True
+
+
+    def to_tree(self, tagname=None, value=None, namespace=None):
+        if value:
+            namespace = getattr(self, "namespace", namespace)
+            if namespace is not None:
+                tagname = "{%s}%s" % (namespace, tagname)
+            return Element(tagname)

+ 144 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/serialisable.py

@@ -0,0 +1,144 @@
+from __future__ import absolute_import
+# copyright openpyxl 2010-2015
+
+from keyword import kwlist
+KEYWORDS = frozenset(kwlist)
+
+from . import _Serialiasable, Sequence
+
+from openpyxl.compat import safe_string
+from openpyxl.xml.functions import (
+    Element,
+    SubElement,
+    safe_iterator,
+    localname,
+)
+
+seq_types = (list, tuple)
+
+class Serialisable(_Serialiasable):
+    """
+    Objects can serialise to XML their attributes and child objects.
+    The following class attributes are created by the metaclass at runtime:
+    __attrs__ = attributes
+    __nested__ = single-valued child treated as an attribute
+    __elements__ = child elements
+    """
+
+    __attrs__ = None
+    __nested__ = None
+    __elements__ = None
+    __namespaced__ = None
+
+    idx_base = 0
+
+    @property
+    def tagname(self):
+        raise(NotImplementedError)
+
+    namespace = None
+
+    @classmethod
+    def from_tree(cls, node):
+        """
+        Create object from XML
+        """
+        attrib = dict(node.attrib)
+        for key, ns in cls.__namespaced__:
+            if ns in attrib:
+                attrib[key] = attrib[ns]
+                del attrib[ns]
+        for el in node:
+            tag = localname(el)
+            if tag in KEYWORDS:
+                tag = "_" + tag
+            desc = getattr(cls, tag, None)
+            if desc is None:
+                continue
+            if tag in cls.__nested__:
+                if hasattr(desc, 'from_tree'):
+                    if isinstance(desc, Sequence):
+                        attrib.setdefault(tag, [])
+                        attrib[tag].append(desc.from_tree(el))
+                    else:
+                        attrib[tag] = desc.from_tree(el)
+            else:
+                if isinstance(desc, property):
+                    continue
+                elif hasattr(desc.expected_type, "from_tree"):
+                    obj = desc.expected_type.from_tree(el)
+                else:
+                    obj = el.text
+                if isinstance(desc, Sequence):
+                    if tag not in attrib:
+                        attrib[tag] = []
+                    attrib[tag].append(obj)
+                else:
+                    attrib[tag] = obj
+        return cls(**attrib)
+
+
+    def to_tree(self, tagname=None, idx=None, namespace=None):
+        if tagname is None:
+            tagname = self.tagname
+        namespace = getattr(self, "namespace", namespace)
+        if namespace is not None:
+            tagname = "{%s}%s" % (namespace, tagname)
+
+        attrs = dict(self)
+        for key, ns in self.__namespaced__:
+            if key in attrs:
+                attrs[ns] = attrs[key]
+                del attrs[key]
+
+        # keywords have to be masked
+        if tagname.startswith("_"):
+            tagname = tagname[1:]
+        el = Element(tagname, attrs)
+
+        for child in self.__elements__:
+            if child in self.__nested__:
+                desc = getattr(self.__class__, child)
+                value = getattr(self, child)
+                if hasattr(desc, "to_tree"):
+                    if isinstance(value, seq_types):
+                        for obj in desc.to_tree(child, value, namespace):
+                            el.append(obj)
+                    else:
+                        obj = desc.to_tree(child, value, namespace)
+                        if obj is not None:
+                            el.append(obj)
+                elif value:
+                    SubElement(el, child, val=safe_string(value))
+
+            else:
+                obj = getattr(self, child)
+                if isinstance(obj, seq_types):
+                    for idx, v in enumerate(obj, self.idx_base):
+                        if hasattr(v, 'to_tree'):
+                            el.append(v.to_tree(tagname=child, idx=idx))
+                        else:
+                            SubElement(el, child).text = safe_string(v)
+                elif obj is not None:
+                    el.append(obj.to_tree(tagname=child))
+        return el
+
+
+    def __iter__(self):
+        for attr in self.__attrs__:
+            value = getattr(self, attr)
+            if value is not None:
+                yield attr, safe_string(value)
+
+
+    def __eq__(self, other):
+        if not dict(self) == dict(other):
+            return False
+        for el in self.__elements__:
+            if getattr(self, el) != getattr(other, el):
+                return False
+        return True
+
+
+    def __ne__(self, other):
+        return not self == other

+ 18 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/descriptors/slots.py

@@ -0,0 +1,18 @@
+# Metaclass for mixing slots and descriptors
+# From "Programming in Python 3" by Mark Summerfield Ch.8 p. 383
+
+class AutoSlotProperties(type):
+
+    def __new__(mcl, classname, bases, dictionary):
+        slots = list(dictionary.get("__slots__", []))
+        for getter_name in [key for key in dictionary if key.startswith("get_")]:
+            name = getter_name
+            slots.append("__" + name)
+            getter = dictionary.pop(getter_name)
+            setter = dictionary.get(setter_name, None)
+            if (setter is not None
+                and isinstance(setter, collections.Callable)):
+                del dictionary[setter_name]
+            dictionary[name] = property(getter. setter)
+            dictionary["__slots__"] = tuple(slots)
+            return super().__new__(mcl, classname, bases, dictionary)

+ 5 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/__init__.py

@@ -0,0 +1,5 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+
+from .drawing import *

+ 323 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/colors.py

@@ -0,0 +1,323 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.compat import basestring, unicode
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Alias,
+    Typed,
+    Integer,
+    Set,
+    MinMax,
+)
+from openpyxl.descriptors.excel import Percentage
+from openpyxl.descriptors.nested import (
+    NestedNoneSet,
+    NestedValue,
+    NestedInteger,
+)
+
+from openpyxl.styles.colors import RGB
+from openpyxl.xml.constants import DRAWING_NS
+
+from openpyxl.descriptors.excel import ExtensionList as OfficeArtExtensionList
+
+PRESET_COLORS = [
+        'aliceBlue', 'antiqueWhite', 'aqua', 'aquamarine',
+        'azure', 'beige', 'bisque', 'black', 'blanchedAlmond', 'blue',
+        'blueViolet', 'brown', 'burlyWood', 'cadetBlue', 'chartreuse',
+        'chocolate', 'coral', 'cornflowerBlue', 'cornsilk', 'crimson', 'cyan',
+        'darkBlue', 'darkCyan', 'darkGoldenrod', 'darkGray', 'darkGrey',
+        'darkGreen', 'darkKhaki', 'darkMagenta', 'darkOliveGreen', 'darkOrange',
+        'darkOrchid', 'darkRed', 'darkSalmon', 'darkSeaGreen', 'darkSlateBlue',
+        'darkSlateGray', 'darkSlateGrey', 'darkTurquoise', 'darkViolet',
+        'dkBlue', 'dkCyan', 'dkGoldenrod', 'dkGray', 'dkGrey', 'dkGreen',
+        'dkKhaki', 'dkMagenta', 'dkOliveGreen', 'dkOrange', 'dkOrchid', 'dkRed',
+        'dkSalmon', 'dkSeaGreen', 'dkSlateBlue', 'dkSlateGray', 'dkSlateGrey',
+        'dkTurquoise', 'dkViolet', 'deepPink', 'deepSkyBlue', 'dimGray',
+        'dimGrey', 'dodgerBlue', 'firebrick', 'floralWhite', 'forestGreen',
+        'fuchsia', 'gainsboro', 'ghostWhite', 'gold', 'goldenrod', 'gray',
+        'grey', 'green', 'greenYellow', 'honeydew', 'hotPink', 'indianRed',
+        'indigo', 'ivory', 'khaki', 'lavender', 'lavenderBlush', 'lawnGreen',
+        'lemonChiffon', 'lightBlue', 'lightCoral', 'lightCyan',
+        'lightGoldenrodYellow', 'lightGray', 'lightGrey', 'lightGreen',
+        'lightPink', 'lightSalmon', 'lightSeaGreen', 'lightSkyBlue',
+        'lightSlateGray', 'lightSlateGrey', 'lightSteelBlue', 'lightYellow',
+        'ltBlue', 'ltCoral', 'ltCyan', 'ltGoldenrodYellow', 'ltGray', 'ltGrey',
+        'ltGreen', 'ltPink', 'ltSalmon', 'ltSeaGreen', 'ltSkyBlue',
+        'ltSlateGray', 'ltSlateGrey', 'ltSteelBlue', 'ltYellow', 'lime',
+        'limeGreen', 'linen', 'magenta', 'maroon', 'medAquamarine', 'medBlue',
+        'medOrchid', 'medPurple', 'medSeaGreen', 'medSlateBlue',
+        'medSpringGreen', 'medTurquoise', 'medVioletRed', 'mediumAquamarine',
+        'mediumBlue', 'mediumOrchid', 'mediumPurple', 'mediumSeaGreen',
+        'mediumSlateBlue', 'mediumSpringGreen', 'mediumTurquoise',
+        'mediumVioletRed', 'midnightBlue', 'mintCream', 'mistyRose', 'moccasin',
+        'navajoWhite', 'navy', 'oldLace', 'olive', 'oliveDrab', 'orange',
+        'orangeRed', 'orchid', 'paleGoldenrod', 'paleGreen', 'paleTurquoise',
+        'paleVioletRed', 'papayaWhip', 'peachPuff', 'peru', 'pink', 'plum',
+        'powderBlue', 'purple', 'red', 'rosyBrown', 'royalBlue', 'saddleBrown',
+        'salmon', 'sandyBrown', 'seaGreen', 'seaShell', 'sienna', 'silver',
+        'skyBlue', 'slateBlue', 'slateGray', 'slateGrey', 'snow', 'springGreen',
+        'steelBlue', 'tan', 'teal', 'thistle', 'tomato', 'turquoise', 'violet',
+        'wheat', 'white', 'whiteSmoke', 'yellow', 'yellowGreen'
+    ]
+
+
+SCHEME_COLORS= ['bg1', 'tx1', 'bg2', 'tx2', 'accent1', 'accent2', 'accent3',
+                'accent4', 'accent5', 'accent6', 'hlink', 'folHlink', 'phClr', 'dk1', 'lt1',
+                'dk2', 'lt2'
+                ]
+
+
+class Transform(Serialisable):
+
+    pass
+
+
+class SystemColor(Serialisable):
+
+    tagname = "sysClr"
+
+    # color transform options
+    tint = NestedInteger(allow_none=True)
+    shade = NestedInteger(allow_none=True)
+    comp = Typed(expected_type=Transform, allow_none=True)
+    inv = Typed(expected_type=Transform, allow_none=True)
+    gray = Typed(expected_type=Transform, allow_none=True)
+    alpha = NestedInteger(allow_none=True)
+    alphaOff = NestedInteger(allow_none=True)
+    alphaMod = NestedInteger(allow_none=True)
+    hue = NestedInteger(allow_none=True)
+    hueOff = NestedInteger(allow_none=True)
+    hueMod = NestedInteger(allow_none=True)
+    sat = NestedInteger(allow_none=True)
+    satOff = NestedInteger(allow_none=True)
+    satMod = NestedInteger(allow_none=True)
+    lum = NestedInteger(allow_none=True)
+    lumOff = NestedInteger(allow_none=True)
+    lumMod = NestedInteger(allow_none=True)
+    red = NestedInteger(allow_none=True)
+    redOff = NestedInteger(allow_none=True)
+    redMod = NestedInteger(allow_none=True)
+    green = NestedInteger(allow_none=True)
+    greenOff = NestedInteger(allow_none=True)
+    greenMod = NestedInteger(allow_none=True)
+    blue = NestedInteger(allow_none=True)
+    blueOff = NestedInteger(allow_none=True)
+    blueMod = NestedInteger(allow_none=True)
+    gamma = Typed(expected_type=Transform, allow_none=True)
+    invGamma = Typed(expected_type=Transform, allow_none=True)
+
+    val = Set(values=(["bg1", "tx1", "bg2", "tx2", "accent1", "accent2",
+                       "accent3", "accent4", "accent5", "accent6", "hlink", "folHlink", "phClr",
+                       "dk1", "lt1", "dk2", "lt2", ]))
+    lastClr = Typed(expected_type=RGB, allow_none=True)
+
+    __elements__ = ('tint', 'shade', 'comp', 'inv', 'gray', "alpha",
+                    "alphaOff", "alphaMod", "hue", "hueOff", "hueMod", "hueOff", "sat",
+                    "satOff", "satMod", "lum", "lumOff", "lumMod", "red", "redOff", "redMod",
+                    "green", "greenOff", "greenMod", "blue", "blueOff", "blueMod", "gamma",
+                    "invGamma")
+
+    def __init__(self,
+                 val="bg1",
+                 lastClr=None,
+                 tint=None,
+                 shade=None,
+                 comp=None,
+                 inv=None,
+                 gray=None,
+                 alpha=None,
+                 alphaOff=None,
+                 alphaMod=None,
+                 hue=None,
+                 hueOff=None,
+                 hueMod=None,
+                 sat=None,
+                 satOff=None,
+                 satMod=None,
+                 lum=None,
+                 lumOff=None,
+                 lumMod=None,
+                 red=None,
+                 redOff=None,
+                 redMod=None,
+                 green=None,
+                 greenOff=None,
+                 greenMod=None,
+                 blue=None,
+                 blueOff=None,
+                 blueMod=None,
+                 gamma=None,
+                 invGamma=None
+                ):
+        self.val = val
+        self.lastClr = lastClr
+        self.tint = tint
+        self.shade = shade
+        self.comp = comp
+        self.inv = inv
+        self.gray = gray
+        self.alpha = alpha
+        self.alphaOff = alphaOff
+        self.alphaMod = alphaMod
+        self.hue = hue
+        self.hueOff = hueOff
+        self.hueMod = hueMod
+        self.sat = sat
+        self.satOff = satOff
+        self.satMod = satMod
+        self.lum = lum
+        self.lumOff = lumOff
+        self.lumMod = lumMod
+        self.red = red
+        self.redOff = redOff
+        self.redMod = redMod
+        self.green = green
+        self.greenOff = greenOff
+        self.greenMod = greenMod
+        self.blue = blue
+        self.blueOff = blueOff
+        self.blueMod = blueMod
+        self.gamma = gamma
+        self.invGamma = invGamma
+
+
+class HSLColor(Serialisable):
+
+    tagname = "hslClr"
+
+    hue = Integer()
+    sat = MinMax(min=0, max=100)
+    lum = MinMax(min=0, max=100)
+
+    #TODO add color transform options
+
+    def __init__(self,
+                 hue=None,
+                 sat=None,
+                 lum=None,
+                ):
+        self.hue = hue
+        self.sat = sat
+        self.lum = lum
+
+
+
+class RGBPercent(Serialisable):
+
+    tagname = "rgbClr"
+
+    r = MinMax(min=0, max=100)
+    g = MinMax(min=0, max=100)
+    b = MinMax(min=0, max=100)
+
+    #TODO add color transform options
+
+    def __init__(self,
+                 r=None,
+                 g=None,
+                 b=None,
+                ):
+        self.r = r
+        self.g = g
+        self.b = b
+
+
+class ColorChoice(Serialisable):
+
+    tagname = "colorChoice"
+    namespace = DRAWING_NS
+
+    scrgbClr = Typed(expected_type=RGBPercent, allow_none=True)
+    RGBPercent = Alias('scrgbClr')
+    srgbClr = NestedValue(expected_type=unicode, allow_none=True) # needs pattern and can have transform
+    RGB = Alias('srgbClr')
+    hslClr = Typed(expected_type=HSLColor, allow_none=True)
+    sysClr = Typed(expected_type=SystemColor, allow_none=True)
+    schemeClr = NestedNoneSet(values=SCHEME_COLORS)
+    prstClr = NestedNoneSet(values=PRESET_COLORS)
+
+    __elements__ = ('scrgbClr', 'srgbClr', 'hslClr', 'sysClr', 'schemeClr', 'prstClr')
+
+    def __init__(self,
+                 scrgbClr=None,
+                 srgbClr=None,
+                 hslClr=None,
+                 sysClr=None,
+                 schemeClr=None,
+                 prstClr=None,
+                ):
+        self.scrgbClr = scrgbClr
+        self.srgbClr = srgbClr
+        self.hslClr = hslClr
+        self.sysClr = sysClr
+        self.schemeClr = schemeClr
+        self.prstClr = prstClr
+
+_COLOR_SET = ('dk1', 'lt1', 'dk2', 'lt2', 'accent1', 'accent2', 'accent3',
+               'accent4', 'accent5', 'accent6', 'hlink', 'folHlink')
+
+
+class ColorMapping(Serialisable):
+
+    tagname = "clrMapOvr"
+
+    bg1 = Set(values=_COLOR_SET)
+    tx1 = Set(values=_COLOR_SET)
+    bg2 = Set(values=_COLOR_SET)
+    tx2 = Set(values=_COLOR_SET)
+    accent1 = Set(values=_COLOR_SET)
+    accent2 = Set(values=_COLOR_SET)
+    accent3 = Set(values=_COLOR_SET)
+    accent4 = Set(values=_COLOR_SET)
+    accent5 = Set(values=_COLOR_SET)
+    accent6 = Set(values=_COLOR_SET)
+    hlink = Set(values=_COLOR_SET)
+    folHlink = Set(values=_COLOR_SET)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 bg1="lt1",
+                 tx1="dk1",
+                 bg2="lt2",
+                 tx2="dk2",
+                 accent1="accent1",
+                 accent2="accent2",
+                 accent3="accent3",
+                 accent4="accent4",
+                 accent5="accent5",
+                 accent6="accent6",
+                 hlink="hlink",
+                 folHlink="folHlink",
+                 extLst=None,
+                ):
+        self.bg1 = bg1
+        self.tx1 = tx1
+        self.bg2 = bg2
+        self.tx2 = tx2
+        self.accent1 = accent1
+        self.accent2 = accent2
+        self.accent3 = accent3
+        self.accent4 = accent4
+        self.accent5 = accent5
+        self.accent6 = accent6
+        self.hlink = hlink
+        self.folHlink = folHlink
+        self.extLst = extLst
+
+
+class ColorChoiceDescriptor(Typed):
+    """
+    Objects can choose from 7 different kinds of color system.
+    Assume RGBHex if a string is passed in.
+    """
+
+    expected_type = ColorChoice
+    allow_none = True
+
+    def __set__(self, instance, value):
+        if isinstance(value, basestring):
+            value = ColorChoice(srgbClr=value)
+        super(ColorChoiceDescriptor, self).__set__(instance, value)

+ 103 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/drawing.py

@@ -0,0 +1,103 @@
+from __future__ import absolute_import
+from __future__ import division
+# Copyright (c) 2010-2015 openpyxl
+
+import math
+
+from openpyxl.compat import deprecated
+
+from openpyxl.styles.colors import Color, BLACK, WHITE
+from openpyxl.utils.units import (
+    pixels_to_EMU,
+    EMU_to_pixels,
+    short_color,
+)
+
+
+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 = 21 # default in px
+        self._height = 192 #default in px
+        self.resize_proportional = False
+        self.rotation = 0
+        self.anchortype = "absolute"
+        self.anchorcol = 0 # left cell
+        self.anchorrow = 0 # top row
+
+
+    @property
+    def width(self):
+        return self._width
+
+    @width.setter
+    def width(self, w):
+        if self.resize_proportional and w:
+            ratio = self._height / self._width
+            self._height = round(ratio * w)
+        self._width = w
+
+    @property
+    def height(self):
+        return self._height
+
+    @height.setter
+    def height(self, h):
+        if self.resize_proportional and h:
+            ratio = self._width / self._height
+            self._width = round(ratio * h)
+        self._height = h
+
+    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 = w
+            else:
+                self._width = math.ceil(yratio * self._width)
+                self._height = h
+
+    @deprecated("Private method used when serialising")
+    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))
+
+
+    @property
+    def anchor(self):
+        from .spreadsheet_drawing import (
+            OneCellAnchor,
+            TwoCellAnchor,
+            AbsoluteAnchor)
+        if self.anchortype == "absolute":
+            anchor = AbsoluteAnchor()
+            anchor.pos.x = pixels_to_EMU(self.left)
+            anchor.pos.y = pixels_to_EMU(self.top)
+
+        elif self.anchortype == "oneCell":
+            anchor = OneCellAnchor()
+            anchor._from.col = self.anchorcol
+            anchor._from.row = self.anchorrow
+
+        anchor.ext.width = pixels_to_EMU(self._width)
+        anchor.ext.height = pixels_to_EMU(self._height)
+
+        return anchor

+ 402 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/effect.py

@@ -0,0 +1,402 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    String,
+    Set,
+    Bool,
+    Integer,
+    NoneSet,
+    Float,)
+
+
+from .colors import ColorChoice
+
+
+class TintEffect(Serialisable):
+
+    hue = Integer()
+    amt = Integer()
+
+    def __init__(self,
+                 hue=None,
+                 amt=None,
+                ):
+        self.hue = hue
+        self.amt = amt
+
+
+class LuminanceEffect(Serialisable):
+
+    bright = Integer()
+    contrast = Integer()
+
+    def __init__(self,
+                 bright=None,
+                 contrast=None,
+                ):
+        self.bright = bright
+        self.contrast = contrast
+
+
+class HSLEffect(Serialisable):
+
+    hue = Integer()
+    sat = Integer()
+    lum = Integer()
+
+    def __init__(self,
+                 hue=None,
+                 sat=None,
+                 lum=None,
+                ):
+        self.hue = hue
+        self.sat = sat
+        self.lum = lum
+
+
+class GrayscaleEffect(Serialisable):
+
+    pass
+
+class FillOverlayEffect(Serialisable):
+
+    blend = Set(values=(['over', 'mult', 'screen', 'darken', 'lighten']))
+
+    def __init__(self,
+                 blend=None,
+                ):
+        self.blend = blend
+
+
+class DuotoneEffect(Serialisable):
+
+    pass
+
+class ColorReplaceEffect(Serialisable):
+
+    pass
+
+class Color(Serialisable):
+
+    pass
+
+class ColorChangeEffect(Serialisable):
+
+    useA = Bool(allow_none=True)
+    clrFrom = Typed(expected_type=Color, )
+    clrTo = Typed(expected_type=Color, )
+
+    def __init__(self,
+                 useA=None,
+                 clrFrom=None,
+                 clrTo=None,
+                ):
+        self.useA = useA
+        self.clrFrom = clrFrom
+        self.clrTo = clrTo
+
+
+class BlurEffect(Serialisable):
+
+    rad = Float()
+    grow = Bool(allow_none=True)
+
+    def __init__(self,
+                 rad=None,
+                 grow=None,
+                ):
+        self.rad = rad
+        self.grow = grow
+
+
+class BiLevelEffect(Serialisable):
+
+    thresh = Integer()
+
+    def __init__(self,
+                 thresh=None,
+                ):
+        self.thresh = thresh
+
+
+class AlphaReplaceEffect(Serialisable):
+
+    a = Integer()
+
+    def __init__(self,
+                 a=None,
+                ):
+        self.a = a
+
+
+class AlphaModulateFixedEffect(Serialisable):
+
+    amt = Integer()
+
+    def __init__(self,
+                 amt=None,
+                ):
+        self.amt = amt
+
+
+class EffectContainer(Serialisable):
+
+    type = Set(values=(['sib', 'tree']))
+    name = String(allow_none=True)
+
+    def __init__(self,
+                 type=None,
+                 name=None,
+                ):
+        self.type = type
+        self.name = name
+
+
+class AlphaModulateEffect(Serialisable):
+
+    cont = Typed(expected_type=EffectContainer, )
+
+    def __init__(self,
+                 cont=None,
+                ):
+        self.cont = cont
+
+
+class AlphaInverseEffect(Serialisable):
+
+    pass
+
+class AlphaFloorEffect(Serialisable):
+
+    pass
+
+class AlphaCeilingEffect(Serialisable):
+
+    pass
+
+class AlphaBiLevelEffect(Serialisable):
+
+    thresh = Integer()
+
+    def __init__(self,
+                 thresh=None,
+                ):
+        self.thresh = thresh
+
+
+class GlowEffect(ColorChoice):
+
+    rad = Float()
+    # uses element group EG_ColorChoice
+    scrgbClr = ColorChoice.scrgbClr
+    srgbClr = ColorChoice.srgbClr
+    hslClr = ColorChoice.hslClr
+    sysClr = ColorChoice.sysClr
+    schemeClr = ColorChoice.schemeClr
+    prstClr = ColorChoice.prstClr
+
+    __elements__ = ('scrgbClr', 'srgbClr', 'hslClr', 'sysClr', 'schemeClr', 'prstClr')
+
+    def __init__(self,
+                 rad=None,
+                 **kw
+                ):
+        self.rad = rad
+        super(GlowEffect, self).__init__(**kw)
+
+
+class InnerShadowEffect(ColorChoice):
+
+    blurRad = Float()
+    dist = Float()
+    dir = Integer()
+    # uses element group EG_ColorChoice
+    scrgbClr = ColorChoice.scrgbClr
+    srgbClr = ColorChoice.srgbClr
+    hslClr = ColorChoice.hslClr
+    sysClr = ColorChoice.sysClr
+    schemeClr = ColorChoice.schemeClr
+    prstClr = ColorChoice.prstClr
+
+    __elements__ = ('scrgbClr', 'srgbClr', 'hslClr', 'sysClr', 'schemeClr', 'prstClr')
+
+    def __init__(self,
+                 blurRad=None,
+                 dist=None,
+                 dir=None,
+                 **kw
+                 ):
+        self.blurRad = blurRad
+        self.dist = dist
+        self.dir = dir
+        super(InnerShadowEffect, self).__init__(**kw)
+
+
+class OuterShadowEffect(ColorChoice):
+
+    blurRad = Float()
+    dist = Float()
+    dir = Integer()
+    sx = Integer()
+    sy = Integer()
+    kx = Integer()
+    ky = Integer()
+    algn = Set(values=(['tl', 't', 'tr', 'l', 'ctr', 'r', 'bl', 'b', 'br']))
+    rotWithShape = Bool(allow_none=True)
+    # uses element group EG_ColorChoice
+    scrgbClr = ColorChoice.scrgbClr
+    srgbClr = ColorChoice.srgbClr
+    hslClr = ColorChoice.hslClr
+    sysClr = ColorChoice.sysClr
+    schemeClr = ColorChoice.schemeClr
+    prstClr = ColorChoice.prstClr
+
+    __elements__ = ('scrgbClr', 'srgbClr', 'hslClr', 'sysClr', 'schemeClr', 'prstClr')
+
+    def __init__(self,
+                 blurRad=None,
+                 dist=None,
+                 dir=None,
+                 sx=None,
+                 sy=None,
+                 kx=None,
+                 ky=None,
+                 algn=None,
+                 rotWithShape=None,
+                 **kw
+                ):
+        self.blurRad = blurRad
+        self.dist = dist
+        self.dir = dir
+        self.sx = sx
+        self.sy = sy
+        self.kx = kx
+        self.ky = ky
+        self.algn = algn
+        self.rotWithShape = rotWithShape
+        super(OuterShadowEffect, self).__init__(**kw)
+
+
+class PresetShadowEffect(ColorChoice):
+
+    prst = Set(values=(['shdw1', 'shdw2', 'shdw3', 'shdw4', 'shdw5', 'shdw6',
+                        'shdw7', 'shdw8', 'shdw9', 'shdw10', 'shdw11', 'shdw12', 'shdw13',
+                        'shdw14', 'shdw15', 'shdw16', 'shdw17', 'shdw18', 'shdw19', 'shdw20']))
+    dist = Float()
+    dir = Integer()
+    # uses element group EG_ColorChoice
+    scrgbClr = ColorChoice.scrgbClr
+    srgbClr = ColorChoice.srgbClr
+    hslClr = ColorChoice.hslClr
+    sysClr = ColorChoice.sysClr
+    schemeClr = ColorChoice.schemeClr
+    prstClr = ColorChoice.prstClr
+
+    __elements__ = ('scrgbClr', 'srgbClr', 'hslClr', 'sysClr', 'schemeClr', 'prstClr')
+
+    def __init__(self,
+                 prst=None,
+                 dist=None,
+                 dir=None,
+                 **kw
+                ):
+        self.prst = prst
+        self.dist = dist
+        self.dir = dir
+        super(PresetShadowEffect, self).__init__(**kw)
+
+
+class ReflectionEffect(Serialisable):
+
+    blurRad = Float()
+    stA = Integer()
+    stPos = Integer()
+    endA = Integer()
+    endPos = Integer()
+    dist = Float()
+    dir = Integer()
+    fadeDir = Integer()
+    sx = Integer()
+    sy = Integer()
+    kx = Integer()
+    ky = Integer()
+    algn = Set(values=(['tl', 't', 'tr', 'l', 'ctr', 'r', 'bl', 'b', 'br']))
+    rotWithShape = Bool(allow_none=True)
+
+    def __init__(self,
+                 blurRad=None,
+                 stA=None,
+                 stPos=None,
+                 endA=None,
+                 endPos=None,
+                 dist=None,
+                 dir=None,
+                 fadeDir=None,
+                 sx=None,
+                 sy=None,
+                 kx=None,
+                 ky=None,
+                 algn=None,
+                 rotWithShape=None,
+                ):
+        self.blurRad = blurRad
+        self.stA = stA
+        self.stPos = stPos
+        self.endA = endA
+        self.endPos = endPos
+        self.dist = dist
+        self.dir = dir
+        self.fadeDir = fadeDir
+        self.sx = sx
+        self.sy = sy
+        self.kx = kx
+        self.ky = ky
+        self.algn = algn
+        self.rotWithShape = rotWithShape
+
+
+class SoftEdgesEffect(Serialisable):
+
+    rad = Float()
+
+    def __init__(self,
+                 rad=None,
+                ):
+        self.rad = rad
+
+
+class EffectList(Serialisable):
+
+    blur = Typed(expected_type=BlurEffect, allow_none=True)
+    fillOverlay = Typed(expected_type=FillOverlayEffect, allow_none=True)
+    glow = Typed(expected_type=GlowEffect, allow_none=True)
+    innerShdw = Typed(expected_type=InnerShadowEffect, allow_none=True)
+    outerShdw = Typed(expected_type=OuterShadowEffect, allow_none=True)
+    prstShdw = Typed(expected_type=PresetShadowEffect, allow_none=True)
+    reflection = Typed(expected_type=ReflectionEffect, allow_none=True)
+    softEdge = Typed(expected_type=SoftEdgesEffect, allow_none=True)
+
+    __elements__ = ('blur', 'fillOverlay', 'glow', 'innerShdw', 'outerShdw',
+                    'prstShdw', 'reflection', 'softEdge')
+
+    def __init__(self,
+                 blur=None,
+                 fillOverlay=None,
+                 glow=None,
+                 innerShdw=None,
+                 outerShdw=None,
+                 prstShdw=None,
+                 reflection=None,
+                 softEdge=None,
+                ):
+        self.blur = blur
+        self.fillOverlay = fillOverlay
+        self.glow = glow
+        self.innerShdw = innerShdw
+        self.outerShdw = outerShdw
+        self.prstShdw = prstShdw
+        self.reflection = reflection
+        self.softEdge = softEdge

+ 349 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/fill.py

@@ -0,0 +1,349 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+
+from openpyxl.descriptors import (
+    Alias,
+    Bool,
+    Integer,
+    Set,
+    NoneSet,
+    Typed,
+    MinMax,
+    Sequence,
+)
+from openpyxl.descriptors.excel import Relation
+from openpyxl.descriptors.nested import (
+    NestedNoneSet,
+    NestedSequence,
+)
+from openpyxl.xml.constants import DRAWING_NS
+
+from .colors import ColorChoice
+from openpyxl.descriptors.excel import ExtensionList as OfficeArtExtensionList
+from .effect import *
+
+"""
+Fill elements from drawing main schema
+"""
+
+class PatternFillProperties(Serialisable):
+
+    tagname = "pattFill"
+
+    prst = NoneSet(values=(['pct5', 'pct10', 'pct20', 'pct25', 'pct30', 'pct40',
+                        'pct50', 'pct60', 'pct70', 'pct75', 'pct80', 'pct90', 'horz', 'vert',
+                        'ltHorz', 'ltVert', 'dkHorz', 'dkVert', 'narHorz', 'narVert', 'dashHorz',
+                        'dashVert', 'cross', 'dnDiag', 'upDiag', 'ltDnDiag', 'ltUpDiag',
+                        'dkDnDiag', 'dkUpDiag', 'wdDnDiag', 'wdUpDiag', 'dashDnDiag',
+                        'dashUpDiag', 'diagCross', 'smCheck', 'lgCheck', 'smGrid', 'lgGrid',
+                        'dotGrid', 'smConfetti', 'lgConfetti', 'horzBrick', 'diagBrick',
+                        'solidDmnd', 'openDmnd', 'dotDmnd', 'plaid', 'sphere', 'weave', 'divot',
+                        'shingle', 'wave', 'trellis', 'zigZag']))
+    preset = Alias("prst")
+    fgClr = Typed(expected_type=ColorChoice, allow_none=True)
+    foreground = Alias("fgClr")
+    bgClr = Typed(expected_type=ColorChoice, allow_none=True)
+    background = Alias("bgClr")
+
+    __elements__ = ("fgClr", "bgClr")
+
+    def __init__(self,
+                 prst=None,
+                 fgClr=None,
+                 bgClr=None,
+                ):
+        self.prst = prst
+        self.fgClr = fgClr
+        self.bgClr = bgClr
+
+
+class RelativeRect(Serialisable):
+
+    tagname = "rect"
+    namespace = DRAWING_NS
+
+    l = MinMax(min=0, max=100, allow_none=True)
+    left = Alias('l')
+    t = MinMax(min=0, max=100, allow_none=True)
+    top = Alias('t')
+    r = MinMax(min=0, max=100, allow_none=True)
+    right = Alias('r')
+    b = MinMax(min=0, max=100, allow_none=True)
+    bottom = Alias('b')
+
+    def __init__(self,
+                 l=None,
+                 t=None,
+                 r=None,
+                 b=None,
+                ):
+        self.l = l
+        self.t = t
+        self.r = r
+        self.b = b
+
+
+class StretchInfoProperties(Serialisable):
+
+    tagname = "stretch"
+    namespace = DRAWING_NS
+
+    fillRect = Typed(expected_type=RelativeRect, allow_none=True)
+
+    def __init__(self,
+                 fillRect=None,
+                ):
+        self.fillRect = fillRect
+
+
+class GradientStop(Serialisable):
+
+    tagname = "gradStop"
+
+    pos = MinMax(min=0, max=100, allow_none=True)
+    # Color Choice Group
+
+    def __init__(self,
+                 pos=None,
+                ):
+        self.pos = pos
+
+
+class GradientStopList(Serialisable):
+
+    tagname = "gradStopLst"
+
+    gs = Sequence(expected_type=GradientStop)
+
+    def __init__(self,
+                 gs=None,
+                ):
+        if gs is None:
+            gs = [GradientStop(), GradientStop()]
+        self.gs = gs
+
+
+class LinearShadeProperties(Serialisable):
+
+    ang = Integer()
+    scaled = Bool(allow_none=True)
+
+    def __init__(self,
+                 ang=None,
+                 scaled=None,
+                ):
+        self.ang = ang
+        self.scaled = scaled
+
+
+class PathShadeProperties(Serialisable):
+
+    path = Set(values=(['shape', 'circle', 'rect']))
+    fillToRect = Typed(expected_type=RelativeRect, allow_none=True)
+
+    def __init__(self,
+                 path=None,
+                 fillToRect=None,
+                ):
+        self.path = path
+        self.fillToRect = fillToRect
+
+
+class GradientFillProperties(Serialisable):
+
+    tagname = "gradFill"
+
+    flip = NoneSet(values=(['x', 'y', 'xy']))
+    rotWithShape = Bool(allow_none=True)
+
+    gsLst = Typed(expected_type=GradientStopList, allow_none=True)
+    stop_list = Alias("gsLst")
+
+    lin = Typed(expected_type=LinearShadeProperties, allow_none=True)
+    linear = Alias("lin")
+    path = Typed(expected_type=PathShadeProperties, allow_none=True)
+
+    tileRect = Typed(expected_type=RelativeRect, allow_none=True)
+
+    __elements__ = ('gsLst', 'lin', 'path', 'tileRect')
+
+    def __init__(self,
+                 flip=None,
+                 rotWithShape=None,
+                 gsLst=None,
+                 lin=None,
+                 path=None,
+                 tileRect=None,
+                ):
+        self.flip = flip
+        self.rotWithShape = rotWithShape
+        self.gsLst = gsLst
+        self.lin = lin
+        self.path = path
+        self.tileRect = tileRect
+
+
+class Blip(Serialisable):
+
+    tagname = "blip"
+    namespace = DRAWING_NS
+
+    #Using attribute groupAG_Blob
+    cstate = NoneSet(values=(['email', 'screen', 'print', 'hqprint']))
+    embed = Relation() #rId
+    link = Relation() #hyperlink
+    noGrp = Bool(allow_none=True)
+    noSelect = Bool(allow_none=True)
+    noRot = Bool(allow_none=True)
+    noChangeAspect = Bool(allow_none=True)
+    noMove = Bool(allow_none=True)
+    noResize = Bool(allow_none=True)
+    noEditPoints = Bool(allow_none=True)
+    noAdjustHandles = Bool(allow_none=True)
+    noChangeArrowheads = Bool(allow_none=True)
+    noChangeShapeType = Bool(allow_none=True)
+    # some elements are choice
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+    alphaBiLevel = Typed(expected_type=AlphaBiLevelEffect, allow_none=True)
+    alphaCeiling = Typed(expected_type=AlphaCeilingEffect, allow_none=True)
+    alphaFloor = Typed(expected_type=AlphaFloorEffect, allow_none=True)
+    alphaInv = Typed(expected_type=AlphaInverseEffect, allow_none=True)
+    alphaMod = Typed(expected_type=AlphaModulateEffect, allow_none=True)
+    alphaModFix = Typed(expected_type=AlphaModulateFixedEffect, allow_none=True)
+    alphaRepl = Typed(expected_type=AlphaReplaceEffect, allow_none=True)
+    biLevel = Typed(expected_type=BiLevelEffect, allow_none=True)
+    blur = Typed(expected_type=BlurEffect, allow_none=True)
+    clrChange = Typed(expected_type=ColorChangeEffect, allow_none=True)
+    clrRepl = Typed(expected_type=ColorReplaceEffect, allow_none=True)
+    duotone = Typed(expected_type=DuotoneEffect, allow_none=True)
+    fillOverlay = Typed(expected_type=FillOverlayEffect, allow_none=True)
+    grayscl = Typed(expected_type=GrayscaleEffect, allow_none=True)
+    hsl = Typed(expected_type=HSLEffect, allow_none=True)
+    lum = Typed(expected_type=LuminanceEffect, allow_none=True)
+    tint = Typed(expected_type=TintEffect, allow_none=True)
+
+    __elements__ = ('alphaBiLevel', 'alphaCeiling', 'alphaFloor', 'alphaInv',
+                    'alphaMod', 'alphaModFix', 'alphaRepl', 'biLevel', 'blur', 'clrChange',
+                    'clrRepl', 'duotone', 'fillOverlay', 'grayscl', 'hsl', 'lum', 'tint')
+
+    def __init__(self,
+                 cstate=None,
+                 embed=None,
+                 link=None,
+                 noGrp=None,
+                 noSelect=None,
+                 noRot=None,
+                 noChangeAspect=None,
+                 noMove=None,
+                 noResize=None,
+                 noEditPoints=None,
+                 noAdjustHandles=None,
+                 noChangeArrowheads=None,
+                 noChangeShapeType=None,
+                 extLst=None,
+                 alphaBiLevel=None,
+                 alphaCeiling=None,
+                 alphaFloor=None,
+                 alphaInv=None,
+                 alphaMod=None,
+                 alphaModFix=None,
+                 alphaRepl=None,
+                 biLevel=None,
+                 blur=None,
+                 clrChange=None,
+                 clrRepl=None,
+                 duotone=None,
+                 fillOverlay=None,
+                 grayscl=None,
+                 hsl=None,
+                 lum=None,
+                 tint=None,
+                ):
+        self.cstate = cstate
+        self.embed = embed
+        self.link = link
+        self.noGrp = noGrp
+        self.noSelect = noSelect
+        self.noRot = noRot
+        self.noChangeAspect = noChangeAspect
+        self.noMove = noMove
+        self.noResize = noResize
+        self.noEditPoints = noEditPoints
+        self.noAdjustHandles = noAdjustHandles
+        self.noChangeArrowheads = noChangeArrowheads
+        self.noChangeShapeType = noChangeShapeType
+        self.extLst = extLst
+        self.alphaBiLevel = alphaBiLevel
+        self.alphaCeiling = alphaCeiling
+        self.alphaFloor = alphaFloor
+        self.alphaInv = alphaInv
+        self.alphaMod = alphaMod
+        self.alphaModFix = alphaModFix
+        self.alphaRepl = alphaRepl
+        self.biLevel = biLevel
+        self.blur = blur
+        self.clrChange = clrChange
+        self.clrRepl = clrRepl
+        self.duotone = duotone
+        self.fillOverlay = fillOverlay
+        self.grayscl = grayscl
+        self.hsl = hsl
+        self.lum = lum
+        self.tint = tint
+
+
+class TileInfoProperties(Serialisable):
+
+    tx = Integer(allow_none=True)
+    ty = Integer(allow_none=True)
+    sx = Integer(allow_none=True)
+    sy = Integer(allow_none=True)
+    flip = NoneSet(values=(['x', 'y', 'xy']))
+    algn = Set(values=(['tl', 't', 'tr', 'l', 'ctr', 'r', 'bl', 'b', 'br']))
+
+    def __init__(self,
+                 tx=None,
+                 ty=None,
+                 sx=None,
+                 sy=None,
+                 flip=None,
+                 algn=None,
+                ):
+        self.tx = tx
+        self.ty = ty
+        self.sx = sx
+        self.sy = sy
+        self.flip = flip
+        self.algn = algn
+
+
+class BlipFillProperties(Serialisable):
+
+    tagname = "blipFill"
+
+    dpi = Integer(allow_none=True)
+    rotWithShape = Bool(allow_none=True)
+
+    blip = Typed(expected_type=Blip, allow_none=True)
+    srcRect = Typed(expected_type=RelativeRect, allow_none=True)
+    tile = Typed(expected_type=TileInfoProperties, allow_none=True)
+    stretch = Typed(expected_type=StretchInfoProperties, allow_none=True)
+
+    __elements__ = ("blip", "srcRect", "tile", "stretch")
+
+    def __init__(self,
+                 dpi=None,
+                 rotWithShape=None,
+                 blip=None,
+                 tile=None,
+                 stretch=None,
+                 srcRect=None,
+                ):
+        self.dpi = dpi
+        self.rotWithShape = rotWithShape
+        self.blip = blip
+        self.tile = tile
+        self.stretch = stretch
+        self.srcRect = srcRect

+ 519 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/graphic.py

@@ -0,0 +1,519 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.xml.functions import NS_REGEX, Element
+from openpyxl.xml.constants import CHART_NS, REL_NS, DRAWING_NS
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Bool,
+    NoneSet,
+    Integer,
+    Set,
+    String,
+)
+from openpyxl.descriptors.excel import Relation
+from openpyxl.descriptors.excel import ExtensionList as OfficeArtExtensionList
+
+from openpyxl.chart.shapes import ShapeProperties
+
+from .effect import *
+from .fill import RelativeRect, BlipFillProperties
+from .text import Hyperlink, EmbeddedWAVAudioFile
+from .shapes import (
+    Transform2D,
+    Point2D,
+    PositiveSize2D,
+    Scene3D,
+    ShapeStyle,
+)
+
+class GroupTransform2D(Serialisable):
+
+    rot = Integer()
+    flipH = Bool(allow_none=True)
+    flipV = Bool(allow_none=True)
+    off = Typed(expected_type=Point2D, allow_none=True)
+    ext = Typed(expected_type=PositiveSize2D, allow_none=True)
+    chOff = Typed(expected_type=Point2D, allow_none=True)
+    chExt = Typed(expected_type=PositiveSize2D, allow_none=True)
+
+    def __init__(self,
+                 rot=None,
+                 flipH=None,
+                 flipV=None,
+                 off=None,
+                 ext=None,
+                 chOff=None,
+                 chExt=None,
+                ):
+        self.rot = rot
+        self.flipH = flipH
+        self.flipV = flipV
+        self.off = off
+        self.ext = ext
+        self.chOff = chOff
+        self.chExt = chExt
+
+
+class GroupShapeProperties(Serialisable):
+
+    bwMode = Set(values=(['clr', 'auto', 'gray', 'ltGray', 'invGray',
+                          'grayWhite', 'blackGray', 'blackWhite', 'black', 'white', 'hidden']))
+    xfrm = Typed(expected_type=GroupTransform2D, allow_none=True)
+    scene3d = Typed(expected_type=Scene3D, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 bwMode=None,
+                 xfrm=None,
+                 scene3d=None,
+                 extLst=None,
+                ):
+        self.bwMode = bwMode
+        self.xfrm = xfrm
+        self.scene3d = scene3d
+        self.extLst = extLst
+
+
+class GroupLocking(Serialisable):
+
+    noGrp = Bool(allow_none=True)
+    noUngrp = Bool(allow_none=True)
+    noSelect = Bool(allow_none=True)
+    noRot = Bool(allow_none=True)
+    noChangeAspect = Bool(allow_none=True)
+    noMove = Bool(allow_none=True)
+    noResize = Bool(allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 noGrp=None,
+                 noUngrp=None,
+                 noSelect=None,
+                 noRot=None,
+                 noChangeAspect=None,
+                 noMove=None,
+                 noResize=None,
+                 extLst=None,
+                ):
+        self.noGrp = noGrp
+        self.noUngrp = noUngrp
+        self.noSelect = noSelect
+        self.noRot = noRot
+        self.noChangeAspect = noChangeAspect
+        self.noMove = noMove
+        self.noResize = noResize
+        self.extLst = extLst
+
+
+class NonVisualGroupDrawingShapeProps(Serialisable):
+
+    grpSpLocks = Typed(expected_type=GroupLocking, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 grpSpLocks=None,
+                 extLst=None,
+                ):
+        self.grpSpLocks = grpSpLocks
+        self.extLst = extLst
+
+
+class NonVisualDrawingProps(Serialisable):
+
+    tagname = "cNvPr"
+
+    id = Integer()
+    name = String()
+    descr = String(allow_none=True)
+    hidden = Bool(allow_none=True)
+    title = String(allow_none=True)
+    hlinkClick = Typed(expected_type=Hyperlink, allow_none=True)
+    hlinkHover = Typed(expected_type=Hyperlink, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 id=None,
+                 name=None,
+                 descr=None,
+                 hidden=None,
+                 title=None,
+                 hlinkClick=None,
+                 hlinkHover=None,
+                 extLst=None,
+                ):
+        self.id = id
+        self.name = name
+        self.descr = descr
+        self.hidden = hidden
+        self.title = title
+        self.hlinkClick = hlinkClick
+        self.hlinkHover = hlinkHover
+        self.extLst = extLst
+
+
+class NonVisualGroupShape(Serialisable):
+
+    cNvPr = Typed(expected_type=NonVisualDrawingProps, )
+    cNvGrpSpPr = Typed(expected_type=NonVisualGroupDrawingShapeProps, )
+
+    def __init__(self,
+                 cNvPr=None,
+                 cNvGrpSpPr=None,
+                ):
+        self.cNvPr = cNvPr
+        self.cNvGrpSpPr = cNvGrpSpPr
+
+
+class GroupShape(Serialisable):
+
+    nvGrpSpPr = Typed(expected_type=NonVisualGroupShape, )
+    grpSpPr = Typed(expected_type=GroupShapeProperties, )
+
+    def __init__(self,
+                 nvGrpSpPr=None,
+                 grpSpPr=None,
+                ):
+        self.nvGrpSpPr = nvGrpSpPr
+        self.grpSpPr = grpSpPr
+
+
+class GraphicFrameLocking(Serialisable):
+
+    noGrp = Bool(allow_none=True)
+    noDrilldown = Bool(allow_none=True)
+    noSelect = Bool(allow_none=True)
+    noChangeAspect = Bool(allow_none=True)
+    noMove = Bool(allow_none=True)
+    noResize = Bool(allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 noGrp=None,
+                 noDrilldown=None,
+                 noSelect=None,
+                 noChangeAspect=None,
+                 noMove=None,
+                 noResize=None,
+                 extLst=None,
+                ):
+        self.noGrp = noGrp
+        self.noDrilldown = noDrilldown
+        self.noSelect = noSelect
+        self.noChangeAspect = noChangeAspect
+        self.noMove = noMove
+        self.noResize = noResize
+        self.extLst = extLst
+
+
+class NonVisualGraphicFrameProperties(Serialisable):
+
+    tagname = "cNvGraphicFramePr"
+
+    graphicFrameLocks = Typed(expected_type=GraphicFrameLocking, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 graphicFrameLocks=None,
+                 extLst=None,
+                ):
+        self.graphicFrameLocks = graphicFrameLocks
+        self.extLst = extLst
+
+
+class NonVisualGraphicFrame(Serialisable):
+
+    tagname = "nvGraphicFramePr"
+
+    cNvPr = Typed(expected_type=NonVisualDrawingProps)
+    cNvGraphicFramePr = Typed(expected_type=NonVisualGraphicFrameProperties)
+
+    __elements__ = ('cNvPr', 'cNvGraphicFramePr')
+
+    def __init__(self,
+                 cNvPr=None,
+                 cNvGraphicFramePr=None,
+                ):
+        if cNvPr is None:
+            cNvPr = NonVisualDrawingProps(id=0, name="Chart 0")
+        self.cNvPr = cNvPr
+        if cNvGraphicFramePr is None:
+            cNvGraphicFramePr = NonVisualGraphicFrameProperties()
+        self.cNvGraphicFramePr = cNvGraphicFramePr
+
+
+class ChartRelation(Serialisable):
+
+    tagname = "chart"
+    namespace = CHART_NS
+
+    id = Relation()
+
+    def __init__(self, id):
+        self.id = id
+
+
+class GraphicData(Serialisable):
+
+    tagname = "graphicData"
+    namespace = DRAWING_NS
+
+    uri = String()
+    chart = Typed(expected_type=ChartRelation, allow_none=True)
+
+
+    def __init__(self,
+                 uri=CHART_NS,
+                 chart=None,
+                ):
+        self.uri = uri
+        self.chart = None
+
+
+class GraphicObject(Serialisable):
+
+    tagname = "graphic"
+    namespace = DRAWING_NS
+
+    graphicData = Typed(expected_type=GraphicData)
+
+    def __init__(self,
+                 graphicData=None,
+                ):
+        if graphicData is None:
+            graphicData = GraphicData()
+        self.graphicData = graphicData
+
+
+class GraphicFrame(Serialisable):
+
+    tagname = "graphicFrame"
+
+    nvGraphicFramePr = Typed(expected_type=NonVisualGraphicFrame)
+    xfrm = Typed(expected_type=Transform2D)
+    graphic = Typed(expected_type=GraphicObject)
+    macro = String(allow_none=True)
+    fPublished = Bool(allow_none=True)
+
+    __elements__ = ('nvGraphicFramePr', 'xfrm', 'graphic', 'macro', 'fPublished')
+
+    def __init__(self,
+                 nvGraphicFramePr=None,
+                 xfrm=None,
+                 graphic=None,
+                 macro=None,
+                 fPublished=None,
+                 ):
+        if nvGraphicFramePr is None:
+            nvGraphicFramePr = NonVisualGraphicFrame()
+        self.nvGraphicFramePr = nvGraphicFramePr
+        if xfrm is None:
+            xfrm = Transform2D()
+        self.xfrm = xfrm
+        if graphic is None:
+            graphic = GraphicObject()
+        self.graphic = graphic
+        self.macro = macro
+        self.fPublished = fPublished
+
+
+class Connection(Serialisable):
+
+    id = Integer()
+    idx = Integer()
+
+    def __init__(self,
+                 id=None,
+                 idx=None,
+                ):
+        self.id = id
+        self.idx = idx
+
+
+class ConnectorLocking(Serialisable):
+
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 extLst=None,
+                ):
+        self.extLst = extLst
+
+
+class NonVisualConnectorProperties(Serialisable):
+
+    cxnSpLocks = Typed(expected_type=ConnectorLocking, allow_none=True)
+    stCxn = Typed(expected_type=Connection, allow_none=True)
+    endCxn = Typed(expected_type=Connection, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 cxnSpLocks=None,
+                 stCxn=None,
+                 endCxn=None,
+                 extLst=None,
+                ):
+        self.cxnSpLocks = cxnSpLocks
+        self.stCxn = stCxn
+        self.endCxn = endCxn
+        self.extLst = extLst
+
+
+class ConnectorNonVisual(Serialisable):
+
+    cNvPr = Typed(expected_type=NonVisualDrawingProps, )
+    cNvCxnSpPr = Typed(expected_type=NonVisualConnectorProperties, )
+
+    def __init__(self,
+                 cNvPr=None,
+                 cNvCxnSpPr=None,
+                ):
+        self.cNvPr = cNvPr
+        self.cNvCxnSpPr = cNvCxnSpPr
+
+
+class Connector(Serialisable):
+
+    macro = String(allow_none=True)
+    fPublished = Bool(allow_none=True)
+    nvCxnSpPr = Typed(expected_type=ConnectorNonVisual, )
+    spPr = Typed(expected_type=ShapeProperties, )
+    style = Typed(expected_type=ShapeStyle, allow_none=True)
+
+    def __init__(self,
+                 macro=None,
+                 fPublished=None,
+                 nvCxnSpPr=None,
+                 spPr=None,
+                 style=None,
+                ):
+        self.macro = macro
+        self.fPublished = fPublished
+        self.nvCxnSpPr = nvCxnSpPr
+        self.spPr = spPr
+        self.style = style
+
+
+class PictureLocking(Serialisable):
+
+    tagname = "picLocks"
+    namespace = DRAWING_NS
+
+    #Using attribute group AG_Locking
+    noCrop = Bool(allow_none=True)
+    noGrp = Bool(allow_none=True)
+    noSelect = Bool(allow_none=True)
+    noRot = Bool(allow_none=True)
+    noChangeAspect = Bool(allow_none=True)
+    noMove = Bool(allow_none=True)
+    noResize = Bool(allow_none=True)
+    noEditPoints = Bool(allow_none=True)
+    noAdjustHandles = Bool(allow_none=True)
+    noChangeArrowheads = Bool(allow_none=True)
+    noChangeShapeType = Bool(allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    __elements__ = ()
+
+    def __init__(self,
+                 noCrop=None,
+                 noGrp=None,
+                 noSelect=None,
+                 noRot=None,
+                 noChangeAspect=None,
+                 noMove=None,
+                 noResize=None,
+                 noEditPoints=None,
+                 noAdjustHandles=None,
+                 noChangeArrowheads=None,
+                 noChangeShapeType=None,
+                 extLst=None,
+                ):
+        self.noCrop = noCrop
+        self.noGrp = noGrp
+        self.noSelect = noSelect
+        self.noRot = noRot
+        self.noChangeAspect = noChangeAspect
+        self.noMove = noMove
+        self.noResize = noResize
+        self.noEditPoints = noEditPoints
+        self.noAdjustHandles = noAdjustHandles
+        self.noChangeArrowheads = noChangeArrowheads
+        self.noChangeShapeType = noChangeShapeType
+
+
+class NonVisualPictureProperties(Serialisable):
+
+    tagname = "cNvPicPr"
+
+    preferRelativeResize = Bool(allow_none=True)
+    picLocks = Typed(expected_type=PictureLocking, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    __elements__ = ("picLocks",)
+
+    def __init__(self,
+                 preferRelativeResize=None,
+                 picLocks=None,
+                 extLst=None,
+                ):
+        self.preferRelativeResize = preferRelativeResize
+        self.picLocks = picLocks
+
+
+class PictureNonVisual(Serialisable):
+
+    tagname = "nvPicPr"
+
+    cNvPr = Typed(expected_type=NonVisualDrawingProps, )
+    cNvPicPr = Typed(expected_type=NonVisualPictureProperties, )
+
+    __elements__ = ("cNvPr", "cNvPicPr")
+
+    def __init__(self,
+                 cNvPr=None,
+                 cNvPicPr=None,
+                ):
+        if cNvPr is None:
+            cNvPr = NonVisualDrawingProps(id=0, name="Image 1", descr="Name of file")
+        self.cNvPr = cNvPr
+        if cNvPicPr is None:
+            cNvPicPr = NonVisualPictureProperties()
+        self.cNvPicPr = cNvPicPr
+
+
+class PictureFrame(Serialisable):
+
+    tagname = "pic"
+
+    macro = String(allow_none=True)
+    fPublished = Bool(allow_none=True)
+    nvPicPr = Typed(expected_type=PictureNonVisual, )
+    blipFill = Typed(expected_type=BlipFillProperties, )
+    spPr = Typed(expected_type=ShapeProperties, )
+    style = Typed(expected_type=ShapeStyle, allow_none=True)
+
+    __elements__ = ("nvPicPr", "blipFill", "spPr", "style")
+
+    def __init__(self,
+                 macro=None,
+                 fPublished=None,
+                 nvPicPr=None,
+                 blipFill=None,
+                 spPr=None,
+                 style=None,
+                ):
+        self.macro = macro
+        self.fPublished = fPublished
+        if nvPicPr is None:
+            nvPicPr = PictureNonVisual()
+        self.nvPicPr = nvPicPr
+        if blipFill is None:
+            blipFill = BlipFillProperties()
+        self.blipFill = blipFill
+        if spPr is None:
+            spPr = ShapeProperties()
+        self.spPr = spPr
+        self.style = style

+ 82 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/image.py

@@ -0,0 +1,82 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.cell import column_index_from_string
+from openpyxl.xml.constants import PACKAGE_IMAGES
+
+from .drawing import Drawing
+
+
+def bounding_box(bw, bh, w, h):
+    """
+    Returns a tuple (new_width, new_height) which has the property
+    that it fits within box_width and box_height and has (close to)
+    the same aspect ratio as the original size
+    """
+    new_width, new_height = w, h
+    if bw and new_width > bw:
+        new_width = bw
+        new_height = new_width / (float(w) / h)
+    if bh and new_height > bh:
+        new_height = bh
+        new_width = new_height * (float(w) / h)
+    return (new_width, new_height)
+
+
+def _import_image(img):
+    try:
+        try:
+            import Image as PILImage
+        except ImportError:
+            from PIL import Image as PILImage
+    except ImportError:
+        raise ImportError('You must install PIL to fetch image objects')
+
+    if not isinstance(img, PILImage.Image):
+        img = PILImage.open(img)
+
+    return img
+
+
+class Image(object):
+    """ Raw Image class """
+
+    _id = 1
+
+    def __init__(self, img, coordinates=((0, 0), (1, 1)), size=(None, None),
+                 nochangeaspect=True, nochangearrowheads=True):
+
+        self.image = _import_image(img)
+        self.nochangeaspect = nochangeaspect
+        self.nochangearrowheads = nochangearrowheads
+
+        # the containing drawing
+        self.drawing = Drawing()
+        self.drawing.coordinates = coordinates
+
+        newsize = bounding_box(size[0], size[1],
+                               self.image.size[0], self.image.size[1])
+        size = newsize
+        self.drawing.width = size[0]
+        self.drawing.height = size[1]
+
+    def anchor(self, cell, anchortype="absolute"):
+        """ anchors the image to the given cell
+            optional parameter anchortype supports 'absolute' or 'oneCell'"""
+        self.drawing.anchortype = anchortype
+        if anchortype == "absolute":
+            self.drawing.left, self.drawing.top = cell.anchor
+            return ((cell.column, cell.row),
+                    cell.parent.point_pos(self.drawing.top + self.drawing.height,
+                                          self.drawing.left + self.drawing.width))
+        elif anchortype == "oneCell":
+            self.drawing.anchorcol = column_index_from_string(cell.column) - 1
+            self.drawing.anchorrow = cell.row - 1
+            return ((self.drawing.anchorcol, self.drawing.anchorrow), None)
+        else:
+            raise ValueError("unknown anchortype %s" % anchortype)
+
+
+    @property
+    def _path(self):
+        return PACKAGE_IMAGES + '/image{0}.png'.format(self._id)

+ 164 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/line.py

@@ -0,0 +1,164 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Float,
+    Integer,
+    Bool,
+    MinMax,
+    Set,
+    NoneSet,
+    String,
+    Alias,
+    Sequence
+)
+from openpyxl.descriptors.excel import Coordinate, Percentage
+
+from openpyxl.descriptors.nested import (
+    NoneSet,
+    NestedSet,
+    NestedNoneSet,
+    EmptyTag,
+)
+from openpyxl.compat import safe_string
+from openpyxl.xml.constants import DRAWING_NS
+from openpyxl.xml.functions import Element
+
+from .colors import ColorChoiceDescriptor
+from .fill import GradientFillProperties, PatternFillProperties
+from openpyxl.descriptors.excel import ExtensionList as OfficeArtExtensionList
+
+"""
+Line elements from drawing main schema
+"""
+
+class LineEndProperties(Serialisable):
+
+    tagname = "end"
+    namespace = DRAWING_NS
+
+    type = NoneSet(values=(['none', 'triangle', 'stealth', 'diamond', 'oval', 'arrow']))
+    w = NoneSet(values=(['sm', 'med', 'lg']))
+    len = NoneSet(values=(['sm', 'med', 'lg']))
+
+    def __init__(self,
+                 type=None,
+                 w=None,
+                 len=None,
+                ):
+        self.type = type
+        self.w = w
+        self.len = len
+
+
+class DashStop(Serialisable):
+
+    tagname = "ds"
+    namespace = DRAWING_NS
+
+    d = Integer()
+    length = Alias('d')
+    sp = Integer()
+    space = Alias('sp')
+
+    def __init__(self,
+                 d=0,
+                 sp=0,
+                ):
+        self.d = d
+        self.sp = sp
+
+
+class DashStopList(Serialisable):
+
+    ds = Sequence(expected_type=DashStop, allow_none=True)
+
+    def __init__(self,
+                 ds=None,
+                ):
+        self.ds = ds
+
+
+class LineJoinMiterProperties(Serialisable):
+
+    tagname = "miter"
+    namespace = DRAWING_NS
+
+    lim = Integer(allow_none=True)
+
+    def __init__(self,
+                 lim=None,
+                ):
+        self.lim = lim
+
+
+class LineProperties(Serialisable):
+
+    tagname = "ln"
+    namespace = DRAWING_NS
+
+    w = MinMax(min=0, max=20116800, allow_none=True) # EMU
+    width = Alias('w')
+    cap = NoneSet(values=(['rnd', 'sq', 'flat']))
+    cmpd = NoneSet(values=(['sng', 'dbl', 'thickThin', 'thinThick', 'tri']))
+    algn = NoneSet(values=(['ctr', 'in']))
+
+    noFill = EmptyTag()
+    solidFill = ColorChoiceDescriptor()
+    gradFill = Typed(expected_type=GradientFillProperties, allow_none=True)
+    pattFill = Typed(expected_type=PatternFillProperties, allow_none=True)
+
+    prstDash = NestedNoneSet(values=(['solid', 'dot', 'dash', 'lgDash', 'dashDot',
+                       'lgDashDot', 'lgDashDotDot', 'sysDash', 'sysDot', 'sysDashDot',
+                       'sysDashDotDot']), namespace=namespace)
+
+    custDash = Typed(expected_type=DashStop, allow_none=True)
+
+    round = EmptyTag()
+    bevel = EmptyTag()
+    miter = Typed(expected_type=LineJoinMiterProperties, allow_none=True)
+
+    headEnd = Typed(expected_type=LineEndProperties, allow_none=True)
+    tailEnd = Typed(expected_type=LineEndProperties, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    __elements__ = ('noFill', 'solidFill', 'gradFill', 'pattFill',
+                    'prstDash', 'custDash', 'round', 'bevel', 'mitre', 'headEnd', 'tailEnd')
+
+    def __init__(self,
+                 w=None,
+                 cap=None,
+                 cmpd=None,
+                 algn=None,
+                 noFill=None,
+                 solidFill=None,
+                 gradFill=None,
+                 pattFill=None,
+                 prstDash=None,
+                 custDash=None,
+                 round=None,
+                 bevel=None,
+                 mitre=None,
+                 headEnd=None,
+                 tailEnd=None,
+                 extLst=None,
+                ):
+        self.w = w
+        self.cap = cap
+        self.cmpd = cmpd
+        self.algn = algn
+        self.noFill = noFill
+        self.solidFill = solidFill
+        self.gradFill = gradFill
+        self.pattFill = pattFill
+        if prstDash is None:
+            prstDash = "solid"
+        self.prstDash = prstDash
+        self.custDash = custDash
+        self.round = round
+        self.bevel = bevel
+        self.mitre = bevel
+        self.headEnd = headEnd
+        self.tailEnd = tailEnd

+ 416 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/shape.py

@@ -0,0 +1,416 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.styles.colors import Color, BLACK, WHITE
+
+from openpyxl.utils.units import (
+    pixels_to_EMU,
+    EMU_to_pixels,
+    short_color,
+)
+
+from openpyxl.compat import deprecated
+from openpyxl.xml.functions import Element, SubElement, tostring
+from openpyxl.xml.constants import (
+    DRAWING_NS,
+    SHEET_DRAWING_NS,
+    CHART_NS,
+    CHART_DRAWING_NS,
+    PKG_REL_NS
+)
+from openpyxl.compat.strings import safe_string
+
+
+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"
+    '''
+
+    @deprecated("Chart Drawings need a complete rewrite")
+    def __init__(self,
+                 chart,
+                 coordinates=((0, 0), (1, 1)),
+                 text=None,
+                 scheme="accent1"):
+        self.chart = chart
+        self.coordinates = coordinates  # in axis units
+        self.text = text
+        self.scheme = scheme
+        self.style = Shape.RECT
+        self.border_width = 0
+        self.border_color = BLACK  # "F3B3C5"
+        self.color = WHITE
+        self.text_color = BLACK
+
+    @property
+    def border_color(self):
+        return self._border_color
+
+    @border_color.setter
+    def border_color(self, color):
+        self._border_color = short_color(color)
+
+    @property
+    def color(self):
+        return self._color
+
+    @color.setter
+    def color(self, color):
+        self._color = short_color(color)
+
+    @property
+    def text_color(self):
+        return self._text_color
+
+    @text_color.setter
+    def text_color(self, color):
+        self._text_color = short_color(color)
+
+    @property
+    def border_width(self):
+        return self._border_width
+
+    @border_width.setter
+    def border_width(self, w):
+        self._border_width = w
+
+    @property
+    def coordinates(self):
+        """Return coordindates in axis units"""
+        return self._coordinates
+
+    @coordinates.setter
+    def coordinates(self, coords):
+        """ set shape coordinates in percentages (left, top, right, bottom)
+        """
+        # this needs refactoring to reflect changes in charts
+        self.axis_coordinates = coords
+        (x1, y1), (x2, y2) = coords # bottom left, top right
+        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)
+
+        # 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
+
+        self._coordinates = (
+            self._norm_pct(x_start), self._norm_pct(y_start),
+            self._norm_pct(x_end), self._norm_pct(y_end)
+        )
+
+    @staticmethod
+    def _norm_pct(pct):
+        """ force shapes to appear by truncating too large sizes """
+        if pct > 1:
+            return 1
+        elif pct < 0:
+            return 0
+        return pct
+
+
+class ShapeWriter(object):
+    """ one file per shape """
+
+    def __init__(self, shapes):
+
+        self._shapes = shapes
+
+    def write(self, shape_id):
+
+        root = Element('{%s}userShapes' % CHART_NS)
+
+        for shape in self._shapes:
+            anchor = SubElement(root, '{%s}relSizeAnchor' % CHART_DRAWING_NS)
+
+            xstart, ystart, xend, yend = shape.coordinates
+
+            _from = SubElement(anchor, '{%s}from' % CHART_DRAWING_NS)
+            SubElement(_from, '{%s}x' % CHART_DRAWING_NS).text = str(xstart)
+            SubElement(_from, '{%s}y' % CHART_DRAWING_NS).text = str(ystart)
+
+            _to = SubElement(anchor, '{%s}to' % CHART_DRAWING_NS)
+            SubElement(_to, '{%s}x' % CHART_DRAWING_NS).text = str(xend)
+            SubElement(_to, '{%s}y' % CHART_DRAWING_NS).text = str(yend)
+
+            sp = SubElement(anchor, '{%s}sp' % CHART_DRAWING_NS, {'macro':'', 'textlink':''})
+            nvspr = SubElement(sp, '{%s}nvSpPr' % CHART_DRAWING_NS)
+            SubElement(nvspr, '{%s}cNvPr' % CHART_DRAWING_NS, {'id':str(shape_id), 'name':'shape %s' % shape_id})
+            SubElement(nvspr, '{%s}cNvSpPr' % CHART_DRAWING_NS)
+
+            sppr = SubElement(sp, '{%s}spPr' % CHART_DRAWING_NS)
+            frm = SubElement(sppr, '{%s}xfrm' % DRAWING_NS,)
+            # no transformation
+            SubElement(frm, '{%s}off' % DRAWING_NS, {'x':'0', 'y':'0'})
+            SubElement(frm, '{%s}ext' % DRAWING_NS, {'cx':'0', 'cy':'0'})
+
+            prstgeom = SubElement(sppr, '{%s}prstGeom' % DRAWING_NS, {'prst':str(shape.style)})
+            SubElement(prstgeom, '{%s}avLst' % DRAWING_NS)
+
+            fill = SubElement(sppr, '{%s}solidFill' % DRAWING_NS, )
+            SubElement(fill, '{%s}srgbClr' % DRAWING_NS, {'val':shape.color})
+
+            border = SubElement(sppr, '{%s}ln' % DRAWING_NS, {'w':str(shape._border_width)})
+            sf = SubElement(border, '{%s}solidFill' % DRAWING_NS)
+            SubElement(sf, '{%s}srgbClr' % DRAWING_NS, {'val':shape.border_color})
+
+            self._write_style(sp)
+            self._write_text(sp, shape)
+
+            shape_id += 1
+
+        return tostring(root)
+
+    def _write_text(self, node, shape):
+        """ write text in the shape """
+
+        tx_body = SubElement(node, '{%s}txBody' % CHART_DRAWING_NS)
+        SubElement(tx_body, '{%s}bodyPr' % DRAWING_NS, {'vertOverflow':'clip'})
+        SubElement(tx_body, '{%s}lstStyle' % DRAWING_NS)
+        p = SubElement(tx_body, '{%s}p' % DRAWING_NS)
+        if shape.text:
+            r = SubElement(p, '{%s}r' % DRAWING_NS)
+            rpr = SubElement(r, '{%s}rPr' % DRAWING_NS, {'lang':'en-US'})
+            fill = SubElement(rpr, '{%s}solidFill' % DRAWING_NS)
+            SubElement(fill, '{%s}srgbClr' % DRAWING_NS, {'val':shape.text_color})
+
+            SubElement(r, '{%s}t' % DRAWING_NS).text = shape.text
+        else:
+            SubElement(p, '{%s}endParaRPr' % DRAWING_NS, {'lang':'en-US'})
+
+    def _write_style(self, node):
+        """ write style theme """
+
+        style = SubElement(node, '{%s}style' % CHART_DRAWING_NS)
+
+        ln_ref = SubElement(style, '{%s}lnRef' % DRAWING_NS, {'idx':'2'})
+        scheme_clr = SubElement(ln_ref, '{%s}schemeClr' % DRAWING_NS, {'val':'accent1'})
+        SubElement(scheme_clr, '{%s}shade' % DRAWING_NS, {'val':'50000'})
+
+        fill_ref = SubElement(style, '{%s}fillRef' % DRAWING_NS, {'idx':'1'})
+        SubElement(fill_ref, '{%s}schemeClr' % DRAWING_NS, {'val':'accent1'})
+
+        effect_ref = SubElement(style, '{%s}effectRef' % DRAWING_NS, {'idx':'0'})
+        SubElement(effect_ref, '{%s}schemeClr' % DRAWING_NS, {'val':'accent1'})
+
+        font_ref = SubElement(style, '{%s}fontRef' % DRAWING_NS, {'idx':'minor'})
+        SubElement(font_ref, '{%s}schemeClr' % DRAWING_NS, {'val':'lt1'})

+ 537 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/shapes.py

@@ -0,0 +1,537 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Float,
+    Integer,
+    Bool,
+    MinMax,
+    Set,
+    NoneSet,
+    String,
+    Alias,
+)
+from openpyxl.descriptors.excel import Coordinate, Percentage
+
+from openpyxl.descriptors.nested import (
+    EmptyTag
+    )
+
+from openpyxl.descriptors.excel import ExtensionList as OfficeArtExtensionList
+from .colors import ColorChoiceDescriptor
+from .fill import (
+    GradientFillProperties,
+    BlipFillProperties,
+    PatternFillProperties,
+    )
+from .line import LineProperties
+
+from openpyxl.styles.colors import Color
+from openpyxl.xml.constants import DRAWING_NS
+
+
+class Point2D(Serialisable):
+
+    x = Coordinate()
+    y = Coordinate()
+
+    def __init__(self,
+                 x=None,
+                 y=None,
+                ):
+        self.x = x
+        self.y = y
+
+
+class PositiveSize2D(Serialisable):
+
+    """
+    Dimensions in EMUs
+    """
+
+    cx = Integer()
+    width = Alias('cx')
+    cy = Integer()
+    height = Alias('cy')
+
+    def __init__(self,
+                 cx=None,
+                 cy=None,
+                ):
+        self.cx = cx
+        self.cy = cy
+
+
+class Transform2D(Serialisable):
+
+    tagname = "xfrm"
+
+    rot = Integer(allow_none=True)
+    flipH = Bool(allow_none=True)
+    flipV = Bool(allow_none=True)
+    off = Typed(expected_type=Point2D, allow_none=True)
+    ext = Typed(expected_type=PositiveSize2D, allow_none=True)
+
+    __elements__ = ('off', 'ext')
+
+    def __init__(self,
+                 rot=None,
+                 flipH=None,
+                 flipV=None,
+                 off=None,
+                 ext=None,
+                ):
+        self.rot = rot
+        self.flipH = flipH
+        self.flipV = flipV
+        self.off = off
+        self.ext = ext
+
+
+class SphereCoords(Serialisable):
+
+    lat = Typed(expected_type=Integer)
+    lon = Typed(expected_type=Integer)
+    rev = Typed(expected_type=Integer)
+
+    def __init__(self,
+                 lat=None,
+                 lon=None,
+                 rev=None,
+                ):
+        self.lat = lat
+        self.lon = lon
+        self.rev = rev
+
+
+class Camera(Serialisable):
+
+    prst = Typed(expected_type=Set(values=(['legacyObliqueTopLeft',
+                                            'legacyObliqueTop', 'legacyObliqueTopRight', 'legacyObliqueLeft',
+                                            'legacyObliqueFront', 'legacyObliqueRight', 'legacyObliqueBottomLeft',
+                                            'legacyObliqueBottom', 'legacyObliqueBottomRight',
+                                            'legacyPerspectiveTopLeft', 'legacyPerspectiveTop',
+                                            'legacyPerspectiveTopRight', 'legacyPerspectiveLeft',
+                                            'legacyPerspectiveFront', 'legacyPerspectiveRight',
+                                            'legacyPerspectiveBottomLeft', 'legacyPerspectiveBottom',
+                                            'legacyPerspectiveBottomRight', 'orthographicFront', 'isometricTopUp',
+                                            'isometricTopDown', 'isometricBottomUp', 'isometricBottomDown',
+                                            'isometricLeftUp', 'isometricLeftDown', 'isometricRightUp',
+                                            'isometricRightDown', 'isometricOffAxis1Left', 'isometricOffAxis1Right',
+                                            'isometricOffAxis1Top', 'isometricOffAxis2Left',
+                                            'isometricOffAxis2Right', 'isometricOffAxis2Top',
+                                            'isometricOffAxis3Left', 'isometricOffAxis3Right',
+                                            'isometricOffAxis3Bottom', 'isometricOffAxis4Left',
+                                            'isometricOffAxis4Right', 'isometricOffAxis4Bottom', 'obliqueTopLeft',
+                                            'obliqueTop', 'obliqueTopRight', 'obliqueLeft', 'obliqueRight',
+                                            'obliqueBottomLeft', 'obliqueBottom', 'obliqueBottomRight',
+                                            'perspectiveFront', 'perspectiveLeft', 'perspectiveRight',
+                                            'perspectiveAbove', 'perspectiveBelow', 'perspectiveAboveLeftFacing',
+                                            'perspectiveAboveRightFacing', 'perspectiveContrastingLeftFacing',
+                                            'perspectiveContrastingRightFacing', 'perspectiveHeroicLeftFacing',
+                                            'perspectiveHeroicRightFacing', 'perspectiveHeroicExtremeLeftFacing',
+                                            'perspectiveHeroicExtremeRightFacing', 'perspectiveRelaxed',
+                                            'perspectiveRelaxedModerately'])))
+    fov = Typed(expected_type=Integer)
+    zoom = Typed(expected_type=Percentage, allow_none=True)
+    rot = Typed(expected_type=SphereCoords, allow_none=True)
+
+    def __init__(self,
+                 prst=None,
+                 fov=None,
+                 zoom=None,
+                 rot=None,
+                ):
+        self.prst = prst
+        self.fov = fov
+        self.zoom = zoom
+        self.rot = rot
+
+
+class LightRig(Serialisable):
+
+    rig = Typed(expected_type=Set(values=(['legacyFlat1', 'legacyFlat2',
+                                           'legacyFlat3', 'legacyFlat4', 'legacyNormal1', 'legacyNormal2',
+                                           'legacyNormal3', 'legacyNormal4', 'legacyHarsh1', 'legacyHarsh2',
+                                           'legacyHarsh3', 'legacyHarsh4', 'threePt', 'balanced', 'soft', 'harsh',
+                                           'flood', 'contrasting', 'morning', 'sunrise', 'sunset', 'chilly',
+                                           'freezing', 'flat', 'twoPt', 'glow', 'brightRoom'])))
+    dir = Typed(expected_type=Set(values=(['tl', 't', 'tr', 'l', 'r', 'bl', 'b', 'br'])))
+    rot = Typed(expected_type=SphereCoords, allow_none=True)
+
+    def __init__(self,
+                 rig=None,
+                 dir=None,
+                 rot=None,
+                ):
+        self.rig = rig
+        self.dir = dir
+        self.rot = rot
+
+
+class Vector3D(Serialisable):
+
+    dx = Typed(expected_type=Coordinate, )
+    dy = Typed(expected_type=Coordinate, )
+    dz = Typed(expected_type=Coordinate, )
+
+    def __init__(self,
+                 dx=None,
+                 dy=None,
+                 dz=None,
+                ):
+        self.dx = dx
+        self.dy = dy
+        self.dz = dz
+
+
+class Point3D(Serialisable):
+
+    x = Typed(expected_type=Coordinate, )
+    y = Typed(expected_type=Coordinate, )
+    z = Typed(expected_type=Coordinate, )
+
+    def __init__(self,
+                 x=None,
+                 y=None,
+                 z=None,
+                ):
+        self.x = x
+        self.y = y
+        self.z = z
+
+
+class Backdrop(Serialisable):
+
+    anchor = Typed(expected_type=Point3D, )
+    norm = Typed(expected_type=Vector3D, )
+    up = Typed(expected_type=Vector3D, )
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 anchor=None,
+                 norm=None,
+                 up=None,
+                 extLst=None,
+                ):
+        self.anchor = anchor
+        self.norm = norm
+        self.up = up
+        self.extLst = extLst
+
+
+class Scene3D(Serialisable):
+
+    camera = Typed(expected_type=Camera, )
+    lightRig = Typed(expected_type=LightRig, )
+    backdrop = Typed(expected_type=Backdrop, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 camera=None,
+                 lightRig=None,
+                 backdrop=None,
+                 extLst=None,
+                ):
+        self.camera = camera
+        self.lightRig = lightRig
+        self.backdrop = backdrop
+        self.extLst = extLst
+
+
+class Bevel(Serialisable):
+
+    w = Typed(expected_type=Integer())
+    h = Typed(expected_type=Integer())
+    prst = Typed(expected_type=Set(values=(['relaxedInset', 'circle',
+                                            'slope', 'cross', 'angle', 'softRound', 'convex', 'coolSlant', 'divot',
+                                            'riblet', 'hardEdge', 'artDeco'])))
+
+    def __init__(self,
+                 w=None,
+                 h=None,
+                 prst=None,
+                ):
+        self.w = w
+        self.h = h
+        self.prst = prst
+
+
+class Shape3D(Serialisable):
+
+    z = Typed(expected_type=Coordinate, allow_none=True)
+    extrusionH = Typed(expected_type=Integer())
+    contourW = Typed(expected_type=Integer())
+    prstMaterial = Typed(expected_type=Set(values=(['legacyMatte',
+                                                    'legacyPlastic', 'legacyMetal', 'legacyWireframe', 'matte', 'plastic',
+                                                    'metal', 'warmMatte', 'translucentPowder', 'powder', 'dkEdge',
+                                                    'softEdge', 'clear', 'flat', 'softmetal'])))
+    bevelT = Typed(expected_type=Bevel, allow_none=True)
+    bevelB = Typed(expected_type=Bevel, allow_none=True)
+    extrusionClr = Typed(expected_type=Color, allow_none=True)
+    contourClr = Typed(expected_type=Color, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 z=None,
+                 extrusionH=None,
+                 contourW=None,
+                 prstMaterial=None,
+                 bevelT=None,
+                 bevelB=None,
+                 extrusionClr=None,
+                 contourClr=None,
+                 extLst=None,
+                ):
+        self.z = z
+        self.extrusionH = extrusionH
+        self.contourW = contourW
+        self.prstMaterial = prstMaterial
+        self.bevelT = bevelT
+        self.bevelB = bevelB
+        self.extrusionClr = extrusionClr
+        self.contourClr = contourClr
+        self.extLst = extLst
+
+
+class Path2D(Serialisable):
+
+    w = Float()
+    h = Float()
+    fill = NoneSet(values=(['norm', 'lighten', 'lightenLess', 'darken', 'darkenLess']))
+    stroke = Bool(allow_none=True)
+    extrusionOk = Bool(allow_none=True)
+
+    def __init__(self,
+                 w=None,
+                 h=None,
+                 fill=None,
+                 stroke=None,
+                 extrusionOk=None,
+                ):
+        self.w = w
+        self.h = h
+        self.fill = fill
+        self.stroke = stroke
+        self.extrusionOk = extrusionOk
+
+
+class Path2DList(Serialisable):
+
+    path = Typed(expected_type=Path2D, allow_none=True)
+
+    def __init__(self,
+                 path=None,
+                ):
+        self.path = path
+
+
+class GeomRect(Serialisable):
+
+    l = Coordinate()
+    t = Coordinate()
+    r = Coordinate()
+    b = Coordinate()
+
+    def __init__(self,
+                 l=None,
+                 t=None,
+                 r=None,
+                 b=None,
+                ):
+        self.l = l
+        self.t = t
+        self.r = r
+        self.b = b
+
+
+class AdjPoint2D(Serialisable):
+
+    x = Coordinate()
+    y = Coordinate()
+
+    def __init__(self,
+                 x=None,
+                 y=None,
+                ):
+        self.x = x
+        self.y = y
+
+
+class ConnectionSite(Serialisable):
+
+    ang = MinMax(min=0, max=360) # guess work, can also be a name
+    pos = Typed(expected_type=AdjPoint2D, )
+
+    def __init__(self,
+                 ang=None,
+                 pos=None,
+                ):
+        self.ang = ang
+        self.pos = pos
+
+
+class ConnectionSiteList(Serialisable):
+
+    cxn = Typed(expected_type=ConnectionSite, allow_none=True)
+
+    def __init__(self,
+                 cxn=None,
+                ):
+        self.cxn = cxn
+
+
+class AdjustHandleList(Serialisable):
+
+    pass
+
+class GeomGuide(Serialisable):
+
+    name = String()
+    fmla = String()
+
+    def __init__(self,
+                 name=None,
+                 fmla=None,
+                ):
+        self.name = name
+        self.fmla = fmla
+
+
+class GeomGuideList(Serialisable):
+
+    gd = Typed(expected_type=GeomGuide, allow_none=True)
+
+    def __init__(self,
+                 gd=None,
+                ):
+        self.gd = gd
+
+
+class CustomGeometry2D(Serialisable):
+
+    avLst = Typed(expected_type=GeomGuideList, allow_none=True)
+    gdLst = Typed(expected_type=GeomGuideList, allow_none=True)
+    ahLst = Typed(expected_type=AdjustHandleList, allow_none=True)
+    cxnLst = Typed(expected_type=ConnectionSiteList, allow_none=True)
+    rect = Typed(expected_type=GeomRect, allow_none=True)
+    pathLst = Typed(expected_type=Path2DList, )
+
+    def __init__(self,
+                 avLst=None,
+                 gdLst=None,
+                 ahLst=None,
+                 cxnLst=None,
+                 rect=None,
+                 pathLst=None,
+                ):
+        self.avLst = avLst
+        self.gdLst = gdLst
+        self.ahLst = ahLst
+        self.cxnLst = cxnLst
+        self.rect = rect
+        self.pathLst = pathLst
+
+
+class PresetGeometry2D(Serialisable):
+
+    namespace = DRAWING_NS
+
+    prst = Set(values=(
+        ['line', 'lineInv', 'triangle', 'rtTriangle', 'rect',
+         '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']))
+    avLst = Typed(expected_type=GeomGuideList, allow_none=True)
+
+    def __init__(self,
+                 prst=None,
+                 avLst=None,
+                ):
+        self.prst = prst
+        self.avLst = avLst
+
+
+class FontReference(Serialisable):
+
+    idx = NoneSet(values=(['major', 'minor']))
+
+    def __init__(self,
+                 idx=None,
+                ):
+        self.idx = idx
+
+
+class StyleMatrixReference(Serialisable):
+
+    idx = Integer()
+
+    def __init__(self,
+                 idx=None,
+                ):
+        self.idx = idx
+
+
+class ShapeStyle(Serialisable):
+
+    lnRef = Typed(expected_type=StyleMatrixReference, )
+    fillRef = Typed(expected_type=StyleMatrixReference, )
+    effectRef = Typed(expected_type=StyleMatrixReference, )
+    fontRef = Typed(expected_type=FontReference, )
+
+    def __init__(self,
+                 lnRef=None,
+                 fillRef=None,
+                 effectRef=None,
+                 fontRef=None,
+                ):
+        self.lnRef = lnRef
+        self.fillRef = fillRef
+        self.effectRef = effectRef
+        self.fontRef = fontRef

+ 298 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/spreadsheet_drawing.py

@@ -0,0 +1,298 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Bool,
+    NoneSet,
+    Integer,
+    Sequence,
+)
+from openpyxl.descriptors.nested import (
+    NestedText,
+    NestedNoneSet,
+)
+from openpyxl.descriptors.excel import Relation
+
+from openpyxl.packaging.relationship import Relationship
+from openpyxl.utils import coordinate_to_tuple
+from openpyxl.utils.units import cm_to_EMU
+from openpyxl.drawing.image import Image
+
+from openpyxl.xml.constants import SHEET_DRAWING_NS, PKG_REL_NS
+from openpyxl.xml.functions import Element
+
+from openpyxl.chart._chart import ChartBase
+from .shapes import (
+    Point2D,
+    PositiveSize2D,
+    PresetGeometry2D,
+)
+from .fill import Blip
+from .graphic import (
+    GroupShape,
+    GraphicFrame,
+    Connector,
+    PictureFrame,
+    ChartRelation,
+    )
+
+
+class AnchorClientData(Serialisable):
+
+    fLocksWithSheet = Bool(allow_none=True)
+    fPrintsWithSheet = Bool(allow_none=True)
+
+    def __init__(self,
+                 fLocksWithSheet=None,
+                 fPrintsWithSheet=None,
+                 ):
+        self.fLocksWithSheet = fLocksWithSheet
+        self.fPrintsWithSheet = fPrintsWithSheet
+
+
+class AnchorMarker(Serialisable):
+
+    tagname = "marker"
+
+    col = NestedText(expected_type=int)
+    colOff = NestedText(expected_type=int)
+    row = NestedText(expected_type=int)
+    rowOff = NestedText(expected_type=int)
+
+    def __init__(self,
+                 col=0,
+                 colOff=0,
+                 row=0,
+                 rowOff=0,
+                 ):
+        self.col = col
+        self.colOff = colOff
+        self.row = row
+        self.rowOff = rowOff
+
+
+class _AnchorBase(Serialisable):
+
+    #one of
+    sp = NestedNoneSet(values=(['cone', 'coneToMax', 'box', 'cylinder', 'pyramid', 'pyramidToMax']))
+    grpSp = Typed(expected_type=GroupShape, allow_none=True)
+    graphicFrame = Typed(expected_type=GraphicFrame, allow_none=True)
+    cxnSp = Typed(expected_type=Connector, allow_none=True)
+    pic = Typed(expected_type=PictureFrame, allow_none=True)
+    contentPart = Relation()
+
+    clientData = Typed(expected_type=AnchorClientData)
+
+    __elements__ = ('sp', 'grpSp', 'graphicFrame',
+                    'cxnSp', 'pic', 'contentPart', 'clientData')
+
+    def __init__(self,
+                 clientData=None,
+                 sp=None,
+                 grpSp=None,
+                 graphicFrame=None,
+                 cxnSp=None,
+                 pic=None,
+                 contentPart=None
+                 ):
+        if clientData is None:
+            clientData = AnchorClientData()
+        self.clientData = clientData
+        self.sp = sp
+        self.grpSp = grpSp
+        self.graphicFrame = graphicFrame
+        self.cxnSp = cxnSp
+        self.pic = pic
+        self.contentPart = contentPart
+
+
+class AbsoluteAnchor(_AnchorBase):
+
+    tagname = "absoluteAnchor"
+
+    pos = Typed(expected_type=Point2D)
+    ext = Typed(expected_type=PositiveSize2D)
+
+    sp = _AnchorBase.sp
+    grpSp = _AnchorBase.grpSp
+    graphicFrame = _AnchorBase.graphicFrame
+    cxnSp = _AnchorBase.cxnSp
+    pic = _AnchorBase.pic
+    contentPart = _AnchorBase.contentPart
+    clientData = _AnchorBase.clientData
+
+    __elements__ = ('pos', 'ext') + _AnchorBase.__elements__
+
+    def __init__(self,
+                 pos=None,
+                 ext=None,
+                 **kw
+                ):
+        if pos is None:
+            pos = Point2D(0, 0)
+        self.pos = pos
+        if ext is None:
+            ext = PositiveSize2D(0, 0)
+        self.ext = ext
+        super(AbsoluteAnchor, self).__init__(**kw)
+
+
+class OneCellAnchor(_AnchorBase):
+
+    tagname = "oneCellAnchor"
+
+    _from = Typed(expected_type=AnchorMarker)
+    ext = Typed(expected_type=PositiveSize2D)
+
+    sp = _AnchorBase.sp
+    grpSp = _AnchorBase.grpSp
+    graphicFrame = _AnchorBase.graphicFrame
+    cxnSp = _AnchorBase.cxnSp
+    pic = _AnchorBase.pic
+    contentPart = _AnchorBase.contentPart
+    clientData = _AnchorBase.clientData
+
+    __elements__ = ('_from', 'ext') + _AnchorBase.__elements__
+
+
+    def __init__(self,
+                 _from=None,
+                 ext=None,
+                 **kw
+                ):
+        if _from is None:
+            _from = AnchorMarker()
+        self._from = _from
+        if ext is None:
+            ext = PositiveSize2D(0, 0)
+        self.ext = ext
+        super(OneCellAnchor, self).__init__(**kw)
+
+
+class TwoCellAnchor(_AnchorBase):
+
+    tagname = "twoCellAnchor"
+
+    editAs = NoneSet(values=(['twoCell', 'oneCell', 'absolute']))
+    _from = Typed(expected_type=AnchorMarker)
+    to = Typed(expected_type=AnchorMarker)
+
+    sp = _AnchorBase.sp
+    grpSp = _AnchorBase.grpSp
+    graphicFrame = _AnchorBase.graphicFrame
+    cxnSp = _AnchorBase.cxnSp
+    pic = _AnchorBase.pic
+    contentPart = _AnchorBase.contentPart
+    clientData = _AnchorBase.clientData
+
+    __elements__ = ('_from', 'to') + _AnchorBase.__elements__
+
+    def __init__(self,
+                 editAs=None,
+                 _from=None,
+                 to=None,
+                 **kw
+                 ):
+        self.editAs = editAs
+        if _from is None:
+            _from = AnchorMarker()
+        self._from = _from
+        if to is None:
+            to = AnchorMarker()
+        self.to = to
+        super(TwoCellAnchor, self).__init__(**kw)
+
+
+class SpreadsheetDrawing(Serialisable):
+
+    tagname = "wsDr"
+
+    twoCellAnchor = Sequence(expected_type=TwoCellAnchor, allow_none=True)
+    oneCellAnchor = Sequence(expected_type=OneCellAnchor, allow_none=True)
+    absoluteAnchor = Sequence(expected_type=AbsoluteAnchor, allow_none=True)
+
+    __elements__ = ("twoCellAnchor", "oneCellAnchor", "absoluteAnchor")
+
+    def __init__(self,
+                 twoCellAnchor=(),
+                 oneCellAnchor=(),
+                 absoluteAnchor=(),
+                 ):
+        self.twoCellAnchor = twoCellAnchor
+        self.oneCellAnchor = oneCellAnchor
+        self.absoluteAnchor = absoluteAnchor
+        self.charts = []
+        self.images = []
+        self._rels = []
+
+
+    def __hash__(self):
+        """
+        Just need to check for identity
+        """
+        return id(self)
+
+
+    def _write(self):
+        """
+        create required structure and the serialise
+        """
+        anchors = []
+        for idx, obj in enumerate(self.charts + self.images, 1):
+            if isinstance(obj, ChartBase):
+                rel = Relationship(type="chart", target='../charts/chart%s.xml' % obj._id)
+                row, col = coordinate_to_tuple(obj.anchor)
+                anchor = OneCellAnchor()
+                anchor._from.row = row -1
+                anchor._from.col = col -1
+                anchor.ext.width = cm_to_EMU(obj.width)
+                anchor.ext.height = cm_to_EMU(obj.height)
+                anchor.graphicFrame = self._chart_frame(idx)
+            elif isinstance(obj, Image):
+                rel = Relationship(type="image", target='../media/image%s.png' % obj._id)
+                anchor = obj.drawing.anchor
+                anchor.pic = self._picture_frame(idx)
+
+            anchors.append(anchor)
+            self._rels.append(rel)
+
+        self.oneCellAnchor = anchors
+
+        tree = self.to_tree()
+        tree.set('xmlns', SHEET_DRAWING_NS)
+        return tree
+
+
+    def _chart_frame(self, idx):
+        chart_rel = ChartRelation("rId%s" % idx)
+        frame = GraphicFrame()
+        nv = frame.nvGraphicFramePr.cNvPr
+        nv.id = idx
+        nv.name = "Chart {0}".format(idx)
+        frame.graphic.graphicData.chart = chart_rel
+        return frame
+
+
+    def _picture_frame(self, idx):
+        pic = PictureFrame()
+        pic.nvPicPr.cNvPr.descr = "Picture"
+        pic.nvPicPr.cNvPr.id = idx
+        pic.nvPicPr.cNvPr.name = "Image {0}".format(idx)
+
+        pic.blipFill.blip = Blip()
+        pic.blipFill.blip.embed = "rId{0}".format(idx)
+        pic.blipFill.blip.cstate = "print"
+
+        pic.spPr.prstGeom = PresetGeometry2D(prst="rect")
+        pic.spPr.ln = None
+        return pic
+
+
+    def _write_rels(self):
+        root = Element("Relationships", xmlns=PKG_REL_NS)
+        for idx, rel in enumerate(self._rels, 1):
+            rel.id = "rId{0}".format(idx)
+            root.append(rel.to_tree())
+        return root

+ 702 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/drawing/text.py

@@ -0,0 +1,702 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.compat import unicode
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Alias,
+    Typed,
+    Set,
+    NoneSet,
+    Sequence,
+    String,
+    Bool,
+    MinMax,
+    Integer
+)
+from openpyxl.descriptors.excel import (
+    HexBinary,
+    TextPoint,
+    Coordinate,
+    ExtensionList
+)
+from openpyxl.descriptors.nested import (
+    NestedInteger,
+    NestedString,
+    NestedText,
+    NestedValue,
+    EmptyTag
+)
+from openpyxl.xml.constants import DRAWING_NS
+
+
+from .colors import ColorChoiceDescriptor
+from .effect import *
+from .fill import *
+from .shapes import (
+    LineProperties,
+    Color,
+    Scene3D
+)
+
+from openpyxl.descriptors.excel import ExtensionList as OfficeArtExtensionList
+
+
+class EmbeddedWAVAudioFile(Serialisable):
+
+    name = Typed(expected_type=String, allow_none=True)
+
+    def __init__(self,
+                 name=None,
+                ):
+        self.name = name
+
+
+class Hyperlink(Serialisable):
+
+    invalidUrl = Typed(expected_type=String, allow_none=True)
+    action = Typed(expected_type=String, allow_none=True)
+    tgtFrame = Typed(expected_type=String, allow_none=True)
+    tooltip = Typed(expected_type=String, allow_none=True)
+    history = Typed(expected_type=Bool, allow_none=True)
+    highlightClick = Typed(expected_type=Bool, allow_none=True)
+    endSnd = Typed(expected_type=Bool, allow_none=True)
+    snd = Typed(expected_type=EmbeddedWAVAudioFile, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    def __init__(self,
+                 invalidUrl=None,
+                 action=None,
+                 tgtFrame=None,
+                 tooltip=None,
+                 history=None,
+                 highlightClick=None,
+                 endSnd=None,
+                 snd=None,
+                 extLst=None,
+                ):
+        self.invalidUrl = invalidUrl
+        self.action = action
+        self.tgtFrame = tgtFrame
+        self.tooltip = tooltip
+        self.history = history
+        self.highlightClick = highlightClick
+        self.endSnd = endSnd
+        self.snd = snd
+        self.extLst = extLst
+
+
+class Font(Serialisable):
+
+    tagname = "latin"
+    namespace = DRAWING_NS
+
+    typeface = String()
+    panose = Typed(expected_type=HexBinary, allow_none=True)
+    pitchFamily = Typed(expected_type=MinMax, allow_none=True)
+    charset = Typed(expected_type=MinMax, allow_none=True)
+
+    def __init__(self,
+                 typeface=None,
+                 panose=None,
+                 pitchFamily=None,
+                 charset=None,
+                ):
+        self.typeface = typeface
+        self.panose = panose
+        self.pitchFamily = pitchFamily
+        self.charset = charset
+
+
+class CharacterProperties(Serialisable):
+
+    tagname = "defRPr"
+    namespace = DRAWING_NS
+
+    kumimoji = Bool(allow_none=True)
+    lang = String(allow_none=True)
+    altLang = String(allow_none=True)
+    sz = Integer()
+    b = Bool(allow_none=True)
+    i = Bool(allow_none=True)
+    u = NoneSet(values=(['words', 'sng', 'dbl', 'heavy', 'dotted',
+                         'dottedHeavy', 'dash', 'dashHeavy', 'dashLong', 'dashLongHeavy',
+                         'dotDash', 'dotDashHeavy', 'dotDotDash', 'dotDotDashHeavy', 'wavy',
+                         'wavyHeavy', 'wavyDbl']))
+    strike = NoneSet(values=(['noStrike', 'sngStrike', 'dblStrike']))
+    kern = Integer(allow_none=True)
+    cap = NoneSet(values=(['small', 'all']))
+    spc = Integer(allow_none=True)
+    normalizeH = Bool(allow_none=True)
+    baseline = Integer(allow_none=True)
+    noProof = Bool(allow_none=True)
+    dirty = Bool(allow_none=True)
+    err = Bool(allow_none=True)
+    smtClean = Bool(allow_none=True)
+    smtId = Integer(allow_none=True)
+    bmk = String(allow_none=True)
+    ln = Typed(expected_type=LineProperties, allow_none=True)
+    highlight = Typed(expected_type=Color, allow_none=True)
+    latin = Typed(expected_type=Font, allow_none=True)
+    ea = Typed(expected_type=Font, allow_none=True)
+    cs = Typed(expected_type=Font, allow_none=True)
+    sym = Typed(expected_type=Font, allow_none=True)
+    hlinkClick = Typed(expected_type=Hyperlink, allow_none=True)
+    hlinkMouseOver = Typed(expected_type=Hyperlink, allow_none=True)
+    rtl = Bool(nested=True, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+    # uses element group EG_FillProperties
+    noFill = EmptyTag(namespace=DRAWING_NS)
+    solidFill = ColorChoiceDescriptor()
+    gradFill = Typed(expected_type=GradientFillProperties, allow_none=True)
+    blipFill = Typed(expected_type=BlipFillProperties, allow_none=True)
+    pattFill = Typed(expected_type=PatternFillProperties, allow_none=True)
+    grpFill = EmptyTag(namespace=DRAWING_NS)
+    # uses element group EG_EffectProperties
+    effectLst = Typed(expected_type=EffectList, allow_none=True)
+    effectDag = Typed(expected_type=EffectContainer, allow_none=True)
+    # uses element group EG_TextUnderlineLine
+    uLnTx = EmptyTag()
+    uLn = Typed(expected_type=LineProperties, allow_none=True)
+    # uses element group EG_TextUnderlineFill
+    uFillTx = EmptyTag()
+    uFill = EmptyTag()
+
+    __elements__ = ('ln', 'highlight', 'latin', 'ea', 'cs', 'sym',
+                    'hlinkClick', 'hlinkMouseOver', 'rtl', 'noFill', 'solidFill', 'gradFill',
+                    'blipFill', 'pattFill', 'grpFill', 'effectLst', 'effectDag', 'uLnTx',
+                    'uLn', 'uFillTx', 'uFill')
+
+    def __init__(self,
+                 kumimoji=None,
+                 lang=None,
+                 altLang=None,
+                 sz=None,
+                 b=None,
+                 i=None,
+                 u=None,
+                 strike=None,
+                 kern=None,
+                 cap=None,
+                 spc=None,
+                 normalizeH=None,
+                 baseline=None,
+                 noProof=None,
+                 dirty=None,
+                 err=None,
+                 smtClean=None,
+                 smtId=None,
+                 bmk=None,
+                 ln=None,
+                 highlight=None,
+                 latin=None,
+                 ea=None,
+                 cs=None,
+                 sym=None,
+                 hlinkClick=None,
+                 hlinkMouseOver=None,
+                 rtl=None,
+                 extLst=None,
+                 noFill=None,
+                 solidFill=None,
+                 gradFill=None,
+                 blipFill=None,
+                 pattFill=None,
+                 grpFill=None,
+                 effectLst=None,
+                 effectDag=None,
+                 uLnTx=None,
+                 uLn=None,
+                 uFillTx=None,
+                 uFill=None,
+                ):
+        self.kumimoji = kumimoji
+        self.lang = lang
+        self.altLang = altLang
+        self.sz = sz
+        self.b = b
+        self.i = i
+        self.u = u
+        self.strike = strike
+        self.kern = kern
+        self.cap = cap
+        self.spc = spc
+        self.normalizeH = normalizeH
+        self.baseline = baseline
+        self.noProof = noProof
+        self.dirty = dirty
+        self.err = err
+        self.smtClean = smtClean
+        self.smtId = smtId
+        self.bmk = bmk
+        self.ln = ln
+        self.highlight = highlight
+        self.latin = latin
+        self.ea = ea
+        self.cs = cs
+        self.sym = sym
+        self.hlinkClick = hlinkClick
+        self.hlinkMouseOver = hlinkMouseOver
+        self.rtl = rtl
+        self.noFill = noFill
+        self.solidFill = solidFill
+        self.gradFill = gradFill
+        self.blipFill = blipFill
+        self.pattFill = pattFill
+        self.grpFill = grpFill
+        self.effectLst = effectLst
+        self.effectDag = effectDag
+        self.uLnTx = uLnTx
+        self.uLn = uLn
+        self.uFillTx = uFillTx
+        self.uFill = uFill
+
+
+class TabStop(Serialisable):
+
+    pos = Typed(expected_type=Coordinate, allow_none=True)
+    algn = Typed(expected_type=Set(values=(['l', 'ctr', 'r', 'dec'])))
+
+    def __init__(self,
+                 pos=None,
+                 algn=None,
+                ):
+        self.pos = pos
+        self.algn = algn
+
+
+class TabStopList(Serialisable):
+
+    tab = Typed(expected_type=TabStop, allow_none=True)
+
+    def __init__(self,
+                 tab=None,
+                ):
+        self.tab = tab
+
+
+class Spacing(Serialisable):
+
+    spcPct = NestedInteger()
+    spcPts = NestedInteger()
+
+    __elements__ = ('spcPct', 'spcPts')
+
+    def __init__(self,
+                 spcPct=None,
+                 spcPts=None,
+                 ):
+        self.spcPct = spcPct
+        self.spcPts = spcPts
+
+
+class AutonumberBullet(Serialisable):
+
+    type = Set(values=(['alphaLcParenBoth', 'alphaUcParenBoth',
+                        'alphaLcParenR', 'alphaUcParenR', 'alphaLcPeriod', 'alphaUcPeriod',
+                        'arabicParenBoth', 'arabicParenR', 'arabicPeriod', 'arabicPlain',
+                        'romanLcParenBoth', 'romanUcParenBoth', 'romanLcParenR', 'romanUcParenR',
+                        'romanLcPeriod', 'romanUcPeriod', 'circleNumDbPlain',
+                        'circleNumWdBlackPlain', 'circleNumWdWhitePlain', 'arabicDbPeriod',
+                        'arabicDbPlain', 'ea1ChsPeriod', 'ea1ChsPlain', 'ea1ChtPeriod',
+                        'ea1ChtPlain', 'ea1JpnChsDbPeriod', 'ea1JpnKorPlain', 'ea1JpnKorPeriod',
+                        'arabic1Minus', 'arabic2Minus', 'hebrew2Minus', 'thaiAlphaPeriod',
+                        'thaiAlphaParenR', 'thaiAlphaParenBoth', 'thaiNumPeriod',
+                        'thaiNumParenR', 'thaiNumParenBoth', 'hindiAlphaPeriod',
+                        'hindiNumPeriod', 'hindiNumParenR', 'hindiAlpha1Period']))
+    startAt = Integer()
+
+    def __init__(self,
+                 type=None,
+                 startAt=None,
+                ):
+        self.type = type
+        self.startAt = startAt
+
+
+class ParagraphProperties(Serialisable):
+
+    tagname = "pPr"
+    namespace = DRAWING_NS
+
+    marL = Integer(allow_none=True)
+    marR = Integer(allow_none=True)
+    lvl = Integer(allow_none=True)
+    indent = Integer(allow_none=True)
+    algn = NoneSet(values=(['l', 'ctr', 'r', 'just', 'justLow', 'dist', 'thaiDist']))
+    defTabSz = Integer(expected_type=Coordinate, allow_none=True)
+    rtl = Bool(allow_none=True)
+    eaLnBrk = Bool(allow_none=True)
+    fontAlgn = NoneSet(values=(['auto', 't', 'ctr', 'base', 'b']))
+    latinLnBrk = Bool(allow_none=True)
+    hangingPunct = Bool(allow_none=True)
+
+    # uses element group EG_TextBulletColor
+    # uses element group EG_TextBulletSize
+    # uses element group EG_TextBulletTypeface
+    # uses element group EG_TextBullet
+    lnSpc = Typed(expected_type=Spacing, allow_none=True)
+    spcBef = Typed(expected_type=Spacing, allow_none=True)
+    spcAft = Typed(expected_type=Spacing, allow_none=True)
+    tabLst = Typed(expected_type=TabStopList, allow_none=True)
+    defRPr = Typed(expected_type=CharacterProperties, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+    buClrTx = EmptyTag()
+    buClr = Typed(expected_type=Color, allow_none=True)
+    buSzTx = EmptyTag()
+    buSzPct = NestedInteger(allow_none=True)
+    buSzPts = NestedInteger(allow_none=True)
+    buFontTx = EmptyTag()
+    buFont = Typed(expected_type=Font, allow_none=True)
+    buNone = EmptyTag()
+    buAutoNum = EmptyTag()
+    buChar = NestedValue(expected_type=unicode, attribute="char", allow_none=True)
+    buBlip = NestedValue(expected_type=Blip, attribute="blip", allow_none=True)
+
+    __elements__ = ('lnSpc', 'spcBef', 'spcAft', 'tabLst', 'defRPr',
+                    'buClrTx', 'buClr', 'buSzTx', 'buSzPct', 'buSzPts', 'buFontTx', 'buFont',
+                    'buNone', 'buAutoNum', 'buChar', 'buBlip')
+
+    def __init__(self,
+                 marL=None,
+                 marR=None,
+                 lvl=None,
+                 indent=None,
+                 algn=None,
+                 defTabSz=None,
+                 rtl=None,
+                 eaLnBrk=None,
+                 fontAlgn=None,
+                 latinLnBrk=None,
+                 hangingPunct=None,
+                 lnSpc=None,
+                 spcBef=None,
+                 spcAft=None,
+                 tabLst=None,
+                 defRPr=None,
+                 extLst=None,
+                 buClrTx=None,
+                 buClr=None,
+                 buSzTx=None,
+                 buSzPct=None,
+                 buSzPts=None,
+                 buFontTx=None,
+                 buFont=None,
+                 buNone=None,
+                 buAutoNum=None,
+                 buChar=None,
+                 buBlip=None,
+                 ):
+        self.marL = marL
+        self.marR = marR
+        self.lvl = lvl
+        self.indent = indent
+        self.algn = algn
+        self.defTabSz = defTabSz
+        self.rtl = rtl
+        self.eaLnBrk = eaLnBrk
+        self.fontAlgn = fontAlgn
+        self.latinLnBrk = latinLnBrk
+        self.hangingPunct = hangingPunct
+        self.lnSpc = lnSpc
+        self.spcBef = spcBef
+        self.spcAft = spcAft
+        self.tabLst = tabLst
+        self.defRPr = defRPr
+        self.buClrTx = buClrTx
+        self.buClr = buClr
+        self.buSzTx = buSzTx
+        self.buSzPct = buSzPct
+        self.buSzPts = buSzPts
+        self.buFontTx = buFontTx
+        self.buFont = buFont
+        self.buNone = buNone
+        self.buAutoNum = buAutoNum
+        self.buChar = buChar
+        self.buBlip = buBlip
+        self.defRPr = defRPr
+
+
+class ListStyle(Serialisable):
+
+    tagname = "lstStyle"
+    namespace = DRAWING_NS
+
+    defPPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    lvl1pPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    lvl2pPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    lvl3pPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    lvl4pPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    lvl5pPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    lvl6pPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    lvl7pPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    lvl8pPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    lvl9pPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+
+    __elements__ = ("defPPr", "lvl1pPr", "lvl2pPr", "lvl3pPr", "lvl4pPr",
+                    "lvl5pPr", "lvl6pPr", "lvl7pPr", "lvl8pPr", "lvl9pPr")
+
+    def __init__(self,
+                 defPPr=None,
+                 lvl1pPr=None,
+                 lvl2pPr=None,
+                 lvl3pPr=None,
+                 lvl4pPr=None,
+                 lvl5pPr=None,
+                 lvl6pPr=None,
+                 lvl7pPr=None,
+                 lvl8pPr=None,
+                 lvl9pPr=None,
+                 extLst=None,
+                ):
+        self.defPPr = defPPr
+        self.lvl1pPr = lvl1pPr
+        self.lvl2pPr = lvl2pPr
+        self.lvl3pPr = lvl3pPr
+        self.lvl4pPr = lvl4pPr
+        self.lvl5pPr = lvl5pPr
+        self.lvl6pPr = lvl6pPr
+        self.lvl7pPr = lvl7pPr
+        self.lvl8pPr = lvl8pPr
+        self.lvl9pPr = lvl9pPr
+
+
+class RegularTextRun(Serialisable):
+
+    tagname = "r"
+    namespace = DRAWING_NS
+
+    rPr = Typed(expected_type=CharacterProperties, allow_none=True)
+    properties = Alias("rPr")
+    t = NestedText(expected_type=unicode, allow_none=True)
+    value = Alias("t")
+
+    __elements__ = ('rPr', 't')
+
+    def __init__(self,
+                 rPr=None,
+                 t=None,
+                ):
+        self.rPr = rPr
+        self.t = t
+
+
+class LineBreak(Serialisable):
+
+    rPr = Typed(expected_type=CharacterProperties, allow_none=True)
+
+    __elements__ = ('rPr',)
+
+    def __init__(self,
+                 rPr=None,
+                ):
+        self.rPr = rPr
+
+
+class TextField(Serialisable):
+
+    id = String()
+    type = String(allow_none=True)
+    rPr = Typed(expected_type=CharacterProperties, allow_none=True)
+    pPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    t = Typed(expected_type=String, allow_none=True)
+
+    __elements__ = ('rPr', 'pPr')
+
+    def __init__(self,
+                 id=None,
+                 type=None,
+                 rPr=None,
+                 pPr=None,
+                 t=None,
+                ):
+        self.id = id
+        self.type = type
+        self.rPr = rPr
+        self.pPr = pPr
+        self.t = t
+
+
+class Paragraph(Serialisable):
+
+    tagname = "p"
+    namespace = DRAWING_NS
+
+    # uses element group EG_TextRun
+    pPr = Typed(expected_type=ParagraphProperties, allow_none=True)
+    properties = Alias("pPr")
+    endParaRPr = Typed(expected_type=CharacterProperties, allow_none=True)
+    r = Typed(expected_type=RegularTextRun, allow_none=True)
+    text = Alias('r')
+    br = Typed(expected_type=LineBreak, allow_none=True)
+    fld = Typed(expected_type=TextField, allow_none=True)
+
+    __elements__ = ('pPr', 'endParaRPr', 'r', 'br', 'fld')
+
+    def __init__(self,
+                 pPr=None,
+                 endParaRPr=None,
+                 r=None,
+                 br=None,
+                 fld=None,
+                 ):
+        self.pPr = pPr
+        self.endParaRPr = endParaRPr
+        if r is None:
+            r = RegularTextRun()
+        self.r = r
+        self.br = br
+        self.fld = fld
+
+
+class GeomGuide(Serialisable):
+
+    name = Typed(expected_type=String())
+    fmla = Typed(expected_type=String())
+
+    def __init__(self,
+                 name=None,
+                 fmla=None,
+                ):
+        self.name = name
+        self.fmla = fmla
+
+
+class GeomGuideList(Serialisable):
+
+    gd = Sequence(expected_type=GeomGuide, allow_none=True)
+
+    def __init__(self,
+                 gd=None,
+                ):
+        self.gd = gd
+
+
+class PresetTextShape(Serialisable):
+
+    prst = Typed(expected_type=Set(values=(
+        ['textNoShape', 'textPlain','textStop', 'textTriangle', 'textTriangleInverted', 'textChevron',
+         'textChevronInverted', 'textRingInside', 'textRingOutside', 'textArchUp',
+         'textArchDown', 'textCircle', 'textButton', 'textArchUpPour',
+         'textArchDownPour', 'textCirclePour', 'textButtonPour', 'textCurveUp',
+         'textCurveDown', 'textCanUp', 'textCanDown', 'textWave1', 'textWave2',
+         'textDoubleWave1', 'textWave4', 'textInflate', 'textDeflate',
+         'textInflateBottom', 'textDeflateBottom', 'textInflateTop',
+         'textDeflateTop', 'textDeflateInflate', 'textDeflateInflateDeflate',
+         'textFadeRight', 'textFadeLeft', 'textFadeUp', 'textFadeDown',
+         'textSlantUp', 'textSlantDown', 'textCascadeUp', 'textCascadeDown'
+         ]
+    )))
+    avLst = Typed(expected_type=GeomGuideList, allow_none=True)
+
+    def __init__(self,
+                 prst=None,
+                 avLst=None,
+                ):
+        self.prst = prst
+        self.avLst = avLst
+
+
+class TextNormalAutofit(Serialisable):
+
+    fontScale = Integer()
+    lnSpcReduction = Integer()
+
+    def __init__(self,
+                 fontScale=None,
+                 lnSpcReduction=None,
+                ):
+        self.fontScale = fontScale
+        self.lnSpcReduction = lnSpcReduction
+
+
+class RichTextProperties(Serialisable):
+
+    tagname = "bodyPr"
+    namespace = DRAWING_NS
+
+    rot = Integer(allow_none=True)
+    spcFirstLastPara = Bool(allow_none=True)
+    vertOverflow = NoneSet(values=(['overflow', 'ellipsis', 'clip']))
+    horzOverflow = NoneSet(values=(['overflow', 'clip']))
+    vert = NoneSet(values=(['horz', 'vert', 'vert270', 'wordArtVert',
+                            'eaVert', 'mongolianVert', 'wordArtVertRtl']))
+    wrap = NoneSet(values=(['none', 'square']))
+    lIns = Integer(allow_none=True)
+    tIns = Integer(allow_none=True)
+    rIns = Integer(allow_none=True)
+    bIns = Integer(allow_none=True)
+    numCol = Integer(allow_none=True)
+    spcCol = Integer(allow_none=True)
+    rtlCol = Bool(allow_none=True)
+    fromWordArt = Bool(allow_none=True)
+    anchor = NoneSet(values=(['t', 'ctr', 'b', 'just', 'dist']))
+    anchorCtr = Bool(allow_none=True)
+    forceAA = Bool(allow_none=True)
+    upright = Bool(allow_none=True)
+    compatLnSpc = Bool(allow_none=True)
+    prstTxWarp = Typed(expected_type=PresetTextShape, allow_none=True)
+    scene3d = Typed(expected_type=Scene3D, allow_none=True)
+    extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
+    noAutofit = EmptyTag()
+    normAutofit = EmptyTag()
+    spAutoFit = EmptyTag()
+    flatTx = NestedInteger(attribute="z", allow_none=True)
+
+    __elements__ = ('prstTxWarp', 'scene3d', 'noAutofit', 'normAutofit', 'spAutoFit')
+
+    def __init__(self,
+                 rot=None,
+                 spcFirstLastPara=None,
+                 vertOverflow=None,
+                 horzOverflow=None,
+                 vert=None,
+                 wrap=None,
+                 lIns=None,
+                 tIns=None,
+                 rIns=None,
+                 bIns=None,
+                 numCol=None,
+                 spcCol=None,
+                 rtlCol=None,
+                 fromWordArt=None,
+                 anchor=None,
+                 anchorCtr=None,
+                 forceAA=None,
+                 upright=None,
+                 compatLnSpc=None,
+                 prstTxWarp=None,
+                 scene3d=None,
+                 extLst=None,
+                 noAutofit=None,
+                 normAutofit=None,
+                 spAutoFit=None,
+                 flatTx=None,
+                ):
+        self.rot = rot
+        self.spcFirstLastPara = spcFirstLastPara
+        self.vertOverflow = vertOverflow
+        self.horzOverflow = horzOverflow
+        self.vert = vert
+        self.wrap = wrap
+        self.lIns = lIns
+        self.tIns = tIns
+        self.rIns = rIns
+        self.bIns = bIns
+        self.numCol = numCol
+        self.spcCol = spcCol
+        self.rtlCol = rtlCol
+        self.fromWordArt = fromWordArt
+        self.anchor = anchor
+        self.anchorCtr = anchorCtr
+        self.forceAA = forceAA
+        self.upright = upright
+        self.compatLnSpc = compatLnSpc
+        self.prstTxWarp = prstTxWarp
+        self.scene3d = scene3d
+        self.noAutofit = noAutofit
+        self.normAutofit = normAutofit
+        self.spAutoFit = spAutoFit
+        self.flatTx = flatTx

+ 5 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formatting/__init__.py

@@ -0,0 +1,5 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from .formatting import ConditionalFormatting
+from .rule import Rule

+ 50 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formatting/formatting.py

@@ -0,0 +1,50 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.compat import iteritems, OrderedDict, deprecated
+from openpyxl.styles.differential import DifferentialStyle
+from .rule import Rule
+
+
+def unpack_rules(cfRules):
+    for key, rules in iteritems(cfRules):
+        for idx,rule in enumerate(rules):
+            yield (key, idx, rule.priority)
+
+
+class ConditionalFormatting(object):
+    """Conditional formatting rules."""
+
+    def __init__(self):
+        self.cf_rules = OrderedDict()
+        self.max_priority = 0
+
+    def add(self, range_string, cfRule):
+        """Add a rule such as ColorScaleRule, FormulaRule or CellIsRule
+
+         The priority will be added automatically.
+        """
+        if not isinstance(cfRule, Rule):
+            raise ValueError("Only instances of openpyxl.formatting.rule.Rule may be added")
+        rule = cfRule
+        self.max_priority += 1
+        rule.priority = self.max_priority
+
+        self.cf_rules.setdefault(range_string, []).append(rule)
+
+
+    def _fix_priorities(self):
+        rules = unpack_rules(self.cf_rules)
+        rules = sorted(rules, key=lambda x: x[2])
+        for idx, (key, rule_no, prio) in enumerate(rules, 1):
+            self.cf_rules[key][rule_no].priority = idx
+        self.max_priority = len(rules)
+
+
+    @deprecated("Always use Rule objects")
+    def update(self, cfRules):
+        pass
+
+    @deprecated("Conditionl Formats are saved automatically")
+    def setDxfStyles(self, wb):
+        pass

+ 274 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formatting/rule.py

@@ -0,0 +1,274 @@
+from __future__ import absolute_import
+# copyright openpyxl 2010-2015
+
+from openpyxl.compat import basestring
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    String,
+    Sequence,
+    Bool,
+    Float,
+    NoneSet,
+    Set,
+    Integer,)
+from openpyxl.descriptors.excel import HexBinary
+from openpyxl.styles.colors import Color, ColorDescriptor
+from openpyxl.styles.differential import DifferentialStyle
+
+
+class ExtensionList(Serialisable):
+
+    pass
+
+
+class FormatObject(Serialisable):
+
+    tagname = "cfvo"
+
+    type = Set(values=(['num', 'percent', 'max', 'min', 'formula', 'percentile']))
+    val = Integer(allow_none=True)
+    gte = Bool(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    def __init__(self,
+                 type,
+                 val=None,
+                 gte=None,
+                 extLst=None,
+                ):
+        self.type = type
+        self.val = val
+        self.gte = gte
+        self.extLst = extLst
+
+
+class RuleType(Serialisable):
+
+    cfvo = Sequence(expected_type=FormatObject)
+
+
+class IconSet(RuleType):
+
+    tagname = "iconSet"
+
+    iconSet = NoneSet(values=(['3Arrows', '3ArrowsGray', '3Flags',
+                           '3TrafficLights1', '3TrafficLights2', '3Signs', '3Symbols', '3Symbols2',
+                           '4Arrows', '4ArrowsGray', '4RedToBlack', '4Rating', '4TrafficLights',
+                           '5Arrows', '5ArrowsGray', '5Rating', '5Quarters']))
+    showValue = Bool(allow_none=True)
+    percent = Bool(allow_none=True)
+    reverse = Bool(allow_none=True)
+
+    __elements__ = ("cfvo",)
+
+    def __init__(self,
+                 iconSet=None,
+                 showValue=None,
+                 percent=None,
+                 reverse=None,
+                 cfvo=None,
+                ):
+        self.iconSet = iconSet
+        self.showValue = showValue
+        self.percent = percent
+        self.reverse = reverse
+        self.cfvo = cfvo
+
+
+class DataBar(RuleType):
+
+    tagname = "dataBar"
+
+    minLength = Integer(allow_none=True)
+    maxLength = Integer(allow_none=True)
+    showValue = Bool(allow_none=True)
+    color = ColorDescriptor()
+
+    __elements__ = ('cfvo', 'color')
+
+    def __init__(self,
+                 minLength=None,
+                 maxLength=None,
+                 showValue=None,
+                 cfvo=None,
+                 color=None,
+                ):
+        self.minLength = minLength
+        self.maxLength = maxLength
+        self.showValue = showValue
+        self.cfvo = cfvo
+        self.color = color
+
+
+class ColorScale(RuleType):
+
+    tagname = "colorScale"
+
+    color = Sequence(expected_type=Color)
+
+    __elements__ = ('cfvo', 'color')
+
+    def __init__(self,
+                 cfvo=None,
+                 color=None,
+                ):
+        self.cfvo = cfvo
+        self.color = color
+
+
+class Rule(Serialisable):
+
+    tagname = "cfRule"
+
+    type = Set(values=(['expression', 'cellIs', 'colorScale', 'dataBar',
+                        'iconSet', 'top10', 'uniqueValues', 'duplicateValues', 'containsText',
+                        'notContainsText', 'beginsWith', 'endsWith', 'containsBlanks',
+                        'notContainsBlanks', 'containsErrors', 'notContainsErrors', 'timePeriod',
+                        'aboveAverage']))
+    dxfId = Integer(allow_none=True)
+    priority = Integer()
+    stopIfTrue = Bool(allow_none=True)
+    aboveAverage = Bool(allow_none=True)
+    percent = Bool(allow_none=True)
+    bottom = Bool(allow_none=True)
+    operator = NoneSet(values=(['lessThan', 'lessThanOrEqual', 'equal',
+                            'notEqual', 'greaterThanOrEqual', 'greaterThan', 'between', 'notBetween',
+                            'containsText', 'notContains', 'beginsWith', 'endsWith']))
+    text = String(allow_none=True)
+    timePeriod = NoneSet(values=(['today', 'yesterday', 'tomorrow', 'last7Days',
+                              'thisMonth', 'lastMonth', 'nextMonth', 'thisWeek', 'lastWeek',
+                              'nextWeek']))
+    rank = Integer(allow_none=True)
+    stdDev = Integer(allow_none=True)
+    equalAverage = Bool(allow_none=True)
+    formula = Sequence(expected_type=basestring)
+    colorScale = Typed(expected_type=ColorScale, allow_none=True)
+    dataBar = Typed(expected_type=DataBar, allow_none=True)
+    iconSet = Typed(expected_type=IconSet, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+    dxf = Typed(expected_type=DifferentialStyle, allow_none=True)
+
+    __elements__ = ('colorScale', 'dataBar', 'extLst', 'iconSet', 'formula')
+
+    def __init__(self,
+                 type,
+                 dxfId=None,
+                 priority=0,
+                 stopIfTrue=None,
+                 aboveAverage=None,
+                 percent=None,
+                 bottom=None,
+                 operator=None,
+                 text=None,
+                 timePeriod=None,
+                 rank=None,
+                 stdDev=None,
+                 equalAverage=None,
+                 formula=[],
+                 colorScale=None,
+                 dataBar=None,
+                 iconSet=None,
+                 extLst=None,
+                 dxf=None,
+                ):
+        self.type = type
+        self.dxfId = dxfId
+        self.priority = priority
+        self.stopIfTrue = stopIfTrue
+        self.aboveAverage = aboveAverage
+        self.percent = percent
+        self.bottom = bottom
+        self.operator = operator
+        self.text = text
+        self.timePeriod = timePeriod
+        self.rank = rank
+        self.stdDev = stdDev
+        self.equalAverage = equalAverage
+        self.formula = formula
+        self.colorScale = colorScale
+        self.dataBar = dataBar
+        self.iconSet = iconSet
+        self.extLst = extLst
+        self.dxf = dxf
+
+
+def ColorScaleRule(start_type=None,
+                 start_value=None,
+                 start_color=None,
+                 mid_type=None,
+                 mid_value=None,
+                 mid_color=None,
+                 end_type=None,
+                 end_value=None,
+                 end_color=None):
+
+    """Backwards compatibility"""
+    formats = []
+    if start_type is not None:
+        formats.append(FormatObject(type=start_type, val=start_value))
+    if mid_type is not None:
+        formats.append(FormatObject(type=mid_type, val=mid_value))
+    if end_type is not None:
+        formats.append(FormatObject(type=end_type, val=end_value))
+    colors = []
+    for v in (start_color, mid_color, end_color):
+        if v is not None:
+            if not isinstance(v, Color):
+                v = Color(v)
+            colors.append(v)
+    cs = ColorScale(cfvo=formats, color=colors)
+    rule = Rule(type="colorScale", colorScale=cs)
+    return rule
+
+
+def FormulaRule(formula=None, stopIfTrue=None, font=None, border=None,
+                fill=None):
+    """
+    Conditional formatting with custom differential style
+    """
+    rule = Rule(type="expression", formula=formula, stopIfTrue=stopIfTrue)
+    rule.dxf =  DifferentialStyle(font=font, border=border, fill=fill)
+    return rule
+
+
+def CellIsRule(operator=None, formula=None, stopIfTrue=None, font=None, border=None, fill=None):
+    """
+    Conditional formatting rule based on cell contents.
+    """
+    # Excel doesn't use >, >=, etc, but allow for ease of python development
+    expand = {">": "greaterThan", ">=": "greaterThanOrEqual", "<": "lessThan", "<=": "lessThanOrEqual",
+              "=": "equal", "==": "equal", "!=": "notEqual"}
+
+    operator = expand.get(operator, operator)
+
+    rule = Rule(type='cellIs', operator=operator, formula=formula, stopIfTrue=stopIfTrue)
+    rule.dxf = DifferentialStyle(font=font, border=border, fill=fill)
+
+    return rule
+
+
+def IconSetRule(icon_style=None, type=None, values=None, showValue=None, percent=None, reverse=None):
+    """
+    Convenience function for creating icon set rules
+    """
+    cfvo = []
+    for val in values:
+        cfvo.append(FormatObject(type, val))
+    icon_set = IconSet(iconSet=icon_style, cfvo=cfvo, showValue=showValue,
+                       percent=percent, reverse=reverse)
+    rule = Rule(type='iconSet', iconSet=icon_set)
+
+    return rule
+
+
+def DataBarRule(start_type=None, start_value=None, end_type=None,
+                end_value=None, color=None, showValue=None, minLength=None, maxLength=None):
+    start = FormatObject(start_type, start_value)
+    end = FormatObject(end_type, end_value)
+    data_bar = DataBar(cfvo=[start, end], color=color, showValue=showValue,
+                       minLength=minLength, maxLength=maxLength)
+    rule = Rule(type='dataBar', dataBar=data_bar)
+
+    return rule

+ 4 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formula/__init__.py

@@ -0,0 +1,4 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from .tokenizer import Tokenizer

+ 431 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formula/tokenizer.py

@@ -0,0 +1,431 @@
+"""
+This module contains a tokenizer for Excel formulae.
+
+The tokenizer is based on the Javascript tokenizer found at
+http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html written by Eric
+Bachtal
+"""
+
+import re
+
+
+class TokenizerError(Exception):
+    "Base class for all Tokenizer errors."
+
+
+class Tokenizer(object):
+
+    """
+    A tokenizer for Excel worksheet formulae.
+
+    Converts a unicode string representing an Excel formula (in A1 notation)
+    into a sequence of `Token` objects.
+
+    `formula`: The unicode string to tokenize
+
+    Tokenizer defines a method `.parse()` to parse the formula into tokens,
+    which can then be accessed through the `.items` attribute.
+
+    """
+
+    SN_RE = re.compile("^[1-9](\\.[0-9]+)?E$")  # Scientific notation
+    WSPACE_RE = re.compile(" +")
+    STRING_REGEXES = {
+        # Inside a string, all characters are treated as literals, except for
+        # the quote character used to start the string. That character, when
+        # doubled is treated as a single character in the string. If an
+        # unmatched quote appears, the string is terminated.
+        '"': re.compile('"(?:[^"]*"")*[^"]*"(?!")'),
+        "'": re.compile("'(?:[^']*'')*[^']*'(?!')"),
+    }
+    ERROR_CODES = ("#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?",
+                   "#NUM!", "#N/A")
+    TOKEN_ENDERS = ',;}) +-*/^&=><%'  # Each of these characters, marks the
+                                       # end of an operand token
+
+    def __init__(self, formula):
+        self.formula = formula
+        self.items = []
+        self.token_stack = []  # Used to keep track of arrays, functions, and
+                               # parentheses
+        self.offset = 0  # How many chars have we read
+        self.token = []  # Used to build up token values char by char
+
+    def parse(self):
+        "Populate self.items with the tokens from the formula."
+        if not self.formula:
+            return
+        elif self.formula[0] == '=':
+            self.offset += 1
+        else:
+            self.items.append(Token(self.formula, Token.LITERAL))
+            return
+        consumers = (
+            ('"\'', self.parse_string),
+            ('[', self.parse_brackets),
+            ('#', self.parse_error),
+            (' ', self.parse_whitespace),
+            ('+-*/^&=><%', self.parse_operator),
+            ('{(', self.parse_opener),
+            (')}', self.parse_closer),
+            (';,', self.parse_separator),
+        )
+        dispatcher = {}  # maps chars to the specific parsing function
+        for chars, consumer in consumers:
+            dispatcher.update(dict.fromkeys(chars, consumer))
+        while self.offset < len(self.formula):
+            if self.check_scientific_notation():  # May consume one character
+                continue
+            curr_char = self.formula[self.offset]
+            if curr_char in self.TOKEN_ENDERS:
+                self.save_token()
+            if curr_char in dispatcher:
+                self.offset += dispatcher[curr_char]()
+            else:
+                # TODO: this can probably be sped up using a regex to get to
+                # the next interesting character
+                self.token.append(curr_char)
+                self.offset += 1
+        self.save_token()
+
+    def parse_string(self):
+        """
+        Parse a "-delimited string or '-delimited link.
+
+        The offset must be pointing to either a single quote ("'") or double
+        quote ('"') character. The strings are parsed according to Excel
+        rules where to escape the delimiter you just double it up. E.g.,
+        "abc""def" in Excel is parsed as 'abc"def' in Python.
+
+        Returns the number of characters matched. (Does not update
+        self.offset)
+
+        """
+        self.assert_empty_token()
+        delim = self.formula[self.offset]
+        assert delim in ('"', "'")
+        regex = self.STRING_REGEXES[delim]
+        match = regex.match(self.formula[self.offset:])
+        if match is None:
+            subtype = "string" if delim == '"' else 'link'
+            raise TokenizerError(
+                "Reached end of formula while parsing %s in %s" %
+                (subtype, self.formula))
+        match = match.group(0)
+        if delim == '"':
+            self.items.append(Token.make_operand(match))
+        else:
+            self.token.append(match)
+        return len(match)
+
+    def parse_brackets(self):
+        """
+        Consume all the text between square brackets [].
+
+        Returns the number of characters matched. (Does not update
+        self.offset)
+
+        """
+        assert self.formula[self.offset] == '['
+        right = self.formula.find(']', self.offset) + 1
+        if right == 0:
+            raise TokenizerError(
+                "Encountered unmatched '[' in %s" % self.formula)
+        self.token.append(self.formula[self.offset: right])
+        return right - self.offset
+
+    def parse_error(self):
+        """
+        Consume the text following a '#' as an error.
+
+        Looks for a match in self.ERROR_CODES and returns the number of
+        characters matched. (Does not update self.offset)
+
+        """
+        self.assert_empty_token()
+        assert self.formula[self.offset] == '#'
+        subformula = self.formula[self.offset:]
+        for err in self.ERROR_CODES:
+            if subformula.startswith(err):
+                self.items.append(Token.make_operand(err))
+                return len(err)
+        raise TokenizerError(
+            "Invalid error code at position %d in '%s'" %
+            (self.offset, self.formula))
+
+    def parse_whitespace(self):
+        """
+        Consume a string of consecutive spaces.
+
+        Returns the number of spaces found. (Does not update self.offset).
+
+        """
+        assert self.formula[self.offset] == ' '
+        self.items.append(Token(' ', Token.WSPACE))
+        return self.WSPACE_RE.match(self.formula[self.offset:]).end()
+
+    def parse_operator(self):
+        """
+        Consume the characters constituting an operator.
+
+        Returns the number of charactes consumed. (Does not update
+        self.offset)
+
+        """
+        if self.formula[self.offset:self.offset + 2] in ('>=', '<=', '<>'):
+            self.items.append(Token(
+                self.formula[self.offset:self.offset + 2],
+                Token.OP_IN
+            ))
+            return 2
+        curr_char = self.formula[self.offset]  # guaranteed to be 1 char
+        assert curr_char in '%*/^&=><+-'
+        if curr_char == '%':
+            token = Token('%', Token.OP_POST)
+        elif curr_char in "*/^&=><":
+            token = Token(curr_char, Token.OP_IN)
+        # From here on, curr_char is guaranteed to be in '+-'
+        elif not self.items:
+            token = Token(curr_char, Token.OP_PRE)
+        else:
+            prev = self.items[-1]
+            is_infix = (
+                prev.subtype == Token.CLOSE
+                or prev.type == Token.OP_POST
+                or prev.type == Token.OPERAND
+            )
+            if is_infix:
+                token = Token(curr_char, Token.OP_IN)
+            else:
+                token = Token(curr_char, Token.OP_PRE)
+        self.items.append(token)
+        return 1
+
+    def parse_opener(self):
+        """
+        Consumes a ( or { character.
+
+        Returns the number of charactes consumed. (Does not update
+        self.offset)
+
+        """
+        assert self.formula[self.offset] in ('(', '{')
+        if self.formula[self.offset] == '{':
+            self.assert_empty_token()
+            token = Token.make_subexp("{")
+        elif self.token:
+            token_value = "".join(self.token) + '('
+            del self.token[:]
+            token = Token.make_subexp(token_value)
+        else:
+            token = Token.make_subexp("(")
+        self.items.append(token)
+        self.token_stack.append(token)
+        return 1
+
+    def parse_closer(self):
+        """
+        Consumes a } or ) character.
+
+        Returns the number of charactes consumed. (Does not update
+        self.offset)
+
+        """
+        assert self.formula[self.offset] in (')', '}')
+        token = self.token_stack.pop().get_closer()
+        if token.value != self.formula[self.offset]:
+            raise TokenizerError(
+                "Mismatched ( and { pair in '%s'" % self.formula)
+        self.items.append(token)
+        return 1
+
+    def parse_separator(self):
+        """
+        Consumes a ; or , character.
+
+        Returns the number of charactes consumed. (Does not update
+        self.offset)
+
+        """
+        curr_char = self.formula[self.offset]
+        assert curr_char in (';', ',')
+        if curr_char == ';':
+            token = Token.make_separator(";")
+        else:
+            try:
+                top_type = self.token_stack[-1].type
+            except IndexError:
+                token = Token(",", Token.OP_IN)  # Range Union operator
+            else:
+                if top_type == Token.PAREN:
+                    token = Token(",", Token.OP_IN)  # Range Union operator
+                else:
+                    token = Token.make_separator(",")
+        self.items.append(token)
+        return 1
+
+    def check_scientific_notation(self):
+        """
+        Consumes a + or - character if part of a number in sci. notation.
+
+        Returns True if the character was consumed and self.offset was
+        updated, False otherwise.
+
+        """
+        curr_char = self.formula[self.offset]
+        if (curr_char in '+-'
+                and len(self.token) >= 1
+                and self.SN_RE.match("".join(self.token))):
+            self.token.append(curr_char)
+            self.offset += 1
+            return True
+        return False
+
+    def assert_empty_token(self):
+        """
+        Ensure that there's no token currently being parsed.
+
+        If there are unconsumed token contents, it means we hit an unexpected
+        token transition. In this case, we raise a TokenizerError
+
+        """
+        if self.token:
+            raise TokenizerError(
+                "Unexpected character at position %d in '%s'" %
+                (self.offset, self.formula))
+
+    def save_token(self):
+        """If there's a token being parsed, add it to the item list."""
+        if self.token:
+            self.items.append(Token.make_operand("".join(self.token)))
+            del self.token[:]
+
+    def render(self):
+        "Convert the parsed tokens back to a string."
+        if not self.items:
+            return ""
+        elif self.items[0].type == Token.LITERAL:
+            return self.items[0].value
+        return "=" + "".join(token.value for token in self.items)
+
+
+class Token(object):
+
+    """
+    A token in an Excel formula.
+
+    Tokens have three attributes:
+
+    * `value`: The string value parsed that led to this token
+    * `type`: A string identifying the type of token
+    * `subtype`: A string identifying subtype of the token (optional, and
+                 defaults to "")
+
+    """
+
+    __slots__ = ['value', 'type', 'subtype']
+
+    LITERAL = "LITERAL"
+    OPERAND = "OPERAND"
+    FUNC = "FUNC"
+    ARRAY = "ARRAY"
+    PAREN = "PAREN"
+    SEP = "SEP"
+    OP_PRE = "OPERATOR-PREFIX"
+    OP_IN = "OPERATOR-INFIX"
+    OP_POST = "OPERATOR-POSTFIX"
+    WSPACE = "WHITE-SPACE"
+
+    def __init__(self, value, type_, subtype=""):
+        self.value = value
+        self.type = type_
+        self.subtype = subtype
+
+    # Literal operands:
+    #
+    # Literal operands are always of type 'OPERAND' and can be of subtype
+    # 'TEXT' (for text strings), 'NUMBER' (for all numeric types), 'LOGICAL'
+    # (for TRUE and FALSE), 'ERROR' (for literal error values), or 'RANGE'
+    # (for all range references).
+
+    TEXT = 'TEXT'
+    NUMBER = 'NUMBER'
+    LOGICAL = 'LOGICAL'
+    ERROR = 'ERROR'
+    RANGE = 'RANGE'
+
+    @classmethod
+    def make_operand(cls, value):
+        "Create an operand token."
+        if value.startswith('"'):
+            subtype = cls.TEXT
+        elif value.startswith('#'):
+            subtype = cls.ERROR
+        elif value in ('TRUE', 'FALSE'):
+            subtype = cls.LOGICAL
+        else:
+            try:
+                float(value)
+                subtype = cls.NUMBER
+            except ValueError:
+                subtype = cls.RANGE
+        return cls(value, cls.OPERAND, subtype)
+
+
+    # Subexpresssions
+    #
+    # There are 3 types of `Subexpressions`: functions, array literals, and
+    # parentheticals. Subexpressions have 'OPEN' and 'CLOSE' tokens. 'OPEN'
+    # is used when parsing the initital expression token (i.e., '(' or '{')
+    # and 'CLOSE' is used when parsing the closing expression token ('}' or
+    # ')').
+
+    OPEN = "OPEN"
+    CLOSE = "CLOSE"
+
+    @classmethod
+    def make_subexp(cls, value, func=False):
+        """
+        Create a subexpression token.
+
+        `value`: The value of the token
+        `func`: If True, force the token to be of type FUNC
+
+        """
+        assert value[-1] in ('{', '}', '(', ')')
+        if func:
+            assert re.match('.+\\(|\\)', value)
+            type_ = Token.FUNC
+        elif value in '{}':
+            type_ = Token.ARRAY
+        elif value in '()':
+            type_ = Token.PAREN
+        else:
+            type_ = Token.FUNC
+        subtype = cls.CLOSE if value in ')}' else cls.OPEN
+        return cls(value, type_, subtype)
+
+    def get_closer(self):
+        "Return a closing token that matches this token's type."
+        assert self.type in (self.FUNC, self.ARRAY, self.PAREN)
+        assert self.subtype == self.OPEN
+        value = "}" if self.type == self.ARRAY else ")"
+        return self.make_subexp(value, func=self.type == self.FUNC)
+
+    # Separator tokens
+    #
+    # Argument separators always have type 'SEP' and can have one of two
+    # subtypes: 'ARG', 'ROW'. 'ARG' is used for the ',' token, when used to
+    # delimit either function arguments or array elements. 'ROW' is used for
+    # the ';' token, which is always used to delimit rows in an array
+    # literal.
+
+    ARG = "ARG"
+    ROW = "ROW"
+
+    @classmethod
+    def make_separator(cls, value):
+        "Create a separator token"
+        assert value in (',', ';')
+        subtype = cls.ARG if value == ',' else cls.ROW
+        return cls(value, cls.SEP, subtype)

+ 166 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/formula/translate.py

@@ -0,0 +1,166 @@
+from __future__ import absolute_import
+
+"""
+This module contains code to translate formulae across cells in a worksheet.
+
+The idea is that if A1 has formula "=B1+C1", then translating it to cell A2
+results in formula "=B2+C2". The algorithm relies on the formula tokenizer
+to identify the parts of the formula that need to change.
+
+"""
+
+import re
+from .tokenizer import Tokenizer, Token
+from openpyxl.utils import (coordinate_from_string, column_index_from_string,
+                            get_column_letter)
+
+class TranslatorError(Exception):
+    """
+    Raised when a formula can't be translated across cells.
+
+    This error arises when a formula's references would be translated outside
+    the worksheet's bounds on the top or left. Excel represents these
+    situations with a #REF! literal error. E.g., if the formula at B2 is
+    '=A1', attempting to translate the formula to B1 raises TranslatorError,
+    since there's no cell above A1. Similarly, translating the same formula
+    from B2 to A2 raises TranslatorError, since there's no cell to the left of
+    A1.
+
+    """
+
+
+class Translator(object):
+
+    """
+    Modifies a formula so that it can be translated from one cell to another.
+
+    `formula`: The unicode string to translate. Must include the leading '='
+               character.
+    `origin`: The cell address (in A1 notation) where this formula was
+              defined (excluding the worksheet name).
+
+    """
+
+    def __init__(self, formula, origin):
+        # Excel errors out when a workbook has formulae in R1C1 notation,
+        # regardless of the calcPr:refMode setting, so I'm assuming the
+        # formulae stored in the workbook must be in A1 notation.
+        col, self.row = coordinate_from_string(origin)
+        self.col = column_index_from_string(col)
+        self.tokenizer = Tokenizer(formula)
+
+    def get_tokens(self):
+        "Returns a list with the tokens comprising the formula."
+        self.tokenizer.parse()
+        return self.tokenizer.items
+
+    ROW_RANGE_RE = re.compile(r"(\$?[1-9][0-9]{0,6}):(\$?[1-9][0-9]{0,6})$")
+    COL_RANGE_RE = re.compile(r"(\$?[A-Za-z]{1,3}):(\$?[A-Za-z]{1,3})$")
+    CELL_REF_RE = re.compile(r"(\$?[A-Za-z]{1,3})(\$?[1-9][0-9]{0,6})$")
+
+    @staticmethod
+    def translate_row(row_str, rdelta):
+        """
+        Translate a range row-snippet by the given number of rows.
+        """
+        if row_str.startswith('$'):
+            return row_str
+        else:
+            new_row = int(row_str) + rdelta
+            if new_row <= 0:
+                raise TranslatorError("Formula out of range")
+            return str(new_row)
+
+    @staticmethod
+    def translate_col(col_str, cdelta):
+        """
+        Translate a range col-snippet by the given number of columns
+        """
+        if col_str.startswith('$'):
+            return col_str
+        else:
+            try:
+                return get_column_letter(
+                    column_index_from_string(col_str) + cdelta)
+            except ValueError:
+                raise TranslatorError("Formula out of range")
+
+    @staticmethod
+    def strip_ws_name(range_str):
+        "Splits out the worksheet reference, if any, from a range reference."
+        # This code assumes that named ranges cannot contain any exclamation
+        # marks. Excel refuses to create these (even using VBA), and
+        # complains of a corrupt workbook when there are names with
+        # exclamation marks. The ECMA spec only states that named ranges will
+        # be of `ST_Xstring` type, which in theory allows '!' (char code
+        # 0x21) per http://www.w3.org/TR/xml/#charsets
+        if '!' in range_str:
+            sheet, range_str = range_str.rsplit('!', 1)
+            return sheet + "!", range_str
+        return "", range_str
+
+    @classmethod
+    def translate_range(cls, range_str, rdelta, cdelta):
+        """
+        Translate an A1-style range reference to the destination cell.
+
+        `rdelta`: the row offset to add to the range
+        `cdelta`: the column offset to add to the range
+        `range_str`: an A1-style reference to a range. Potentially includes
+                     the worksheet reference. Could also be a named range.
+
+        """
+        ws_part, range_str = cls.strip_ws_name(range_str)
+        match = cls.ROW_RANGE_RE.match(range_str)  # e.g. `3:4`
+        if match is not None:
+            return (ws_part + cls.translate_row(match.group(1), rdelta) + ":"
+                    + cls.translate_row(match.group(2), rdelta))
+        match = cls.COL_RANGE_RE.match(range_str)  # e.g. `A:BC`
+        if match is not None:
+            return (ws_part + cls.translate_col(match.group(1), cdelta) + ':'
+                    + cls.translate_col(match.group(2), cdelta))
+        if ':' in range_str: # e.g. `A1:B5`
+            # The check is necessarily general because range references can
+            # have one or both endpoints specified by named ranges. I.e.,
+            # `named_range:C2`, `C2:named_range`, and `name1:name2` are all
+            # valid references. Further, Excel allows chaining multiple
+            # colons together (with unclear meaning)
+            return ws_part + ":".join(
+                cls.translate_range(piece, rdelta, cdelta)
+                for piece in range_str.split(':'))
+        match = cls.CELL_REF_RE.match(range_str)
+        if match is None:  # Must be a named range
+            return range_str
+        return (ws_part + cls.translate_col(match.group(1), cdelta)
+                + cls.translate_row(match.group(2), rdelta))
+
+    def translate_formula(self, dest):
+        """
+        Convert the formula into A1 notation.
+
+        The formula is converted into A1 assuming it is assigned to the cell
+        whose address is `dest` (no worksheet name).
+
+        """
+        tokens = self.get_tokens()
+        if not tokens:
+            return ""
+        elif tokens[0].type == Token.LITERAL:
+            return tokens[0].value
+        out = ['=']
+        # per the spec:
+        # A compliant producer or consumer considers a defined name in the
+        # range A1-XFD1048576 to be an error. All other names outside this
+        # range can be defined as names and overrides a cell reference if an
+        # ambiguity exists. (I.18.2.5)
+        dcol, drow = coordinate_from_string(dest)
+        dcol = column_index_from_string(dcol)
+        row_delta = drow - self.row
+        col_delta = dcol - self.col
+        for token in tokens:
+            if token.type == Token.OPERAND and token.subtype == Token.RANGE:
+                out.append(self.translate_range(token.value, row_delta,
+                                                col_delta))
+            else:
+                out.append(token.value)
+        return "".join(out)

+ 3 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/packaging/__init__.py

@@ -0,0 +1,3 @@
+"""
+Stuff related to Office OpenXML packaging: relationships, archive, content types.
+"""

+ 46 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/packaging/relationship.py

@@ -0,0 +1,46 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors import (
+    String,
+    Set,
+    NoneSet,
+    Alias,
+    Sequence
+)
+from openpyxl.descriptors.serialisable import Serialisable
+
+from openpyxl.xml.constants import REL_NS, PKG_REL_NS
+from openpyxl.xml.functions import Element, SubElement, tostring
+
+
+class Relationship(Serialisable):
+    """Represents many kinds of relationships."""
+    # TODO: Use this object for workbook relationships as well as
+    # worksheet relationships
+
+    tagname = "Relationship"
+
+    Type = String()
+    type = Alias('Type')
+    Target = String()
+    target = Alias('Target')
+    TargetMode = String(allow_none=True)
+    targetMode = Alias('TargetMode')
+    Id = String(allow_none=True)
+    id = Alias('Id')
+
+
+    def __init__(self, type, target=None, targetMode=None, id=None):
+        self.type = "%s/%s" % (REL_NS, type)
+        self.target = target
+        self.targetMode = targetMode
+        self.id = id
+
+
+def to_tree(sequence):
+    root = Element("Relationships", xmlns=PKG_REL_NS)
+    for idx, rel in enumerate(sequence, 1):
+        rel.id = "rId{0}".format(idx)
+        root.append(rel.to_tree())
+    return root

+ 11 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/__init__.py

@@ -0,0 +1,11 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+"""Imports for the openpyxl.reader namespace."""
+
+# package imports
+from openpyxl.reader import excel
+from openpyxl.reader import strings
+from openpyxl.reader import style
+from openpyxl.reader import workbook
+from openpyxl.reader import worksheet

+ 54 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/comments.py

@@ -0,0 +1,54 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+
+import os.path
+
+from openpyxl.comments import Comment
+from openpyxl.xml.constants import (
+    PACKAGE_WORKSHEET_RELS,
+    SHEET_MAIN_NS,
+    COMMENTS_NS,
+    PACKAGE_XL,
+    )
+from openpyxl.xml.functions import fromstring, safe_iterator
+
+def _get_author_list(root):
+    author_subtree = root.find('{%s}authors' % SHEET_MAIN_NS)
+    return [author.text for author in author_subtree]
+
+def read_comments(ws, xml_source):
+    """Given a worksheet and the XML of its comments file, assigns comments to cells"""
+    root = fromstring(xml_source)
+    authors = _get_author_list(root)
+    comment_nodes = safe_iterator(root, ('{%s}comment' % SHEET_MAIN_NS))
+    for node in comment_nodes:
+        author = authors[int(node.attrib['authorId'])]
+        cell = node.attrib['ref']
+        text_node = node.find('{%s}text' % SHEET_MAIN_NS)
+        substrs = []
+        for run in text_node.findall('{%s}r' % SHEET_MAIN_NS):
+            runtext = ''.join([t.text for t in run.findall('{%s}t' % SHEET_MAIN_NS)])
+            substrs.append(runtext)
+        comment_text = ''.join(substrs)
+
+        comment = Comment(comment_text, author)
+        ws.cell(coordinate=cell).comment = comment
+
+def get_comments_file(worksheet_path, archive, valid_files):
+    """Returns the XML filename in the archive which contains the comments for
+    the spreadsheet with codename sheet_codename. Returns None if there is no
+    such file"""
+    sheet_codename = os.path.split(worksheet_path)[-1]
+    rels_file = PACKAGE_WORKSHEET_RELS + '/' + sheet_codename + '.rels'
+    if rels_file not in valid_files:
+        return None
+    rels_source = archive.read(rels_file)
+    root = fromstring(rels_source)
+    for i in root:
+        if i.attrib['Type'] == COMMENTS_NS:
+            comments_file = os.path.split(i.attrib['Target'])[-1]
+            comments_file = PACKAGE_XL + '/' + comments_file
+            if comments_file in valid_files:
+                return comments_file
+    return None

+ 254 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/excel.py

@@ -0,0 +1,254 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+"""Read an xlsx file into Python"""
+
+# Python stdlib imports
+from zipfile import ZipFile, ZIP_DEFLATED, BadZipfile
+from sys import exc_info
+from io import BytesIO
+import os.path
+import warnings
+
+# compatibility imports
+from openpyxl.compat import unicode, file
+
+# Allow blanket setting of KEEP_VBA for testing
+try:
+    from ..tests import KEEP_VBA
+except ImportError:
+    KEEP_VBA = False
+
+
+# package imports
+from openpyxl.utils.exceptions import InvalidFileException
+from openpyxl.xml.constants import (
+    ARC_SHARED_STRINGS,
+    ARC_CORE,
+    ARC_WORKBOOK,
+    ARC_STYLE,
+    ARC_THEME,
+    SHARED_STRINGS,
+    EXTERNAL_LINK,
+    XLTM,
+    XLTX,
+)
+
+from openpyxl.workbook import Workbook
+from openpyxl.workbook.names.external import detect_external_links
+from openpyxl.workbook.names.named_range import read_named_ranges
+from .strings import read_string_table
+from .style import read_style_table
+from .workbook import (
+    read_content_types,
+    read_excel_base_date,
+    detect_worksheets,
+    read_rels,
+    read_workbook_code_name,
+    read_workbook_settings,
+)
+from openpyxl.workbook.properties import read_properties, DocumentProperties
+from openpyxl.worksheet.read_only import ReadOnlyWorksheet
+from .worksheet import WorkSheetParser
+from .comments import read_comments, get_comments_file
+# Use exc_info for Python 2 compatibility with "except Exception[,/ as] e"
+
+
+CENTRAL_DIRECTORY_SIGNATURE = b'\x50\x4b\x05\x06'
+SUPPORTED_FORMATS = ('.xlsx', '.xlsm', '.xltx', '.xltm')
+
+
+def repair_central_directory(zipFile, is_file_instance):
+    ''' trims trailing data from the central directory
+    code taken from http://stackoverflow.com/a/7457686/570216, courtesy of Uri Cohen
+    '''
+
+    f = zipFile if is_file_instance else open(zipFile, 'rb+')
+    data = f.read()
+    pos = data.find(CENTRAL_DIRECTORY_SIGNATURE)  # End of central directory signature
+    if (pos > 0):
+        sio = BytesIO(data)
+        sio.seek(pos + 22)  # size of 'ZIP end of central directory record'
+        sio.truncate()
+        sio.seek(0)
+        return sio
+
+    f.seek(0)
+    return f
+
+
+
+def _validate_archive(filename):
+    """
+    Check the file is a valid zipfile
+    """
+    is_file_like = hasattr(filename, 'read')
+
+    if not is_file_like and os.path.isfile(filename):
+        file_format = os.path.splitext(filename)[-1]
+        if file_format not in SUPPORTED_FORMATS:
+            if file_format == '.xls':
+                msg = ('openpyxl does not support the old .xls file format, '
+                       'please use xlrd to read this file, or convert it to '
+                       'the more recent .xlsx file format.')
+            elif file_format == '.xlsb':
+                msg = ('openpyxl does not support binary format .xlsb, '
+                       'please convert this file to .xlsx format if you want '
+                       'to open it with openpyxl')
+            else:
+                msg = ('openpyxl does not support %s file format, '
+                       'please check you can open '
+                       'it with Excel first. '
+                       'Supported formats are: %s') % (file_format,
+                                                       ','.join(SUPPORTED_FORMATS))
+            raise InvalidFileException(msg)
+
+
+    if is_file_like:
+        # fileobject must have been opened with 'rb' flag
+        # it is required by zipfile
+        if getattr(filename, 'encoding', None) is not None:
+            raise IOError("File-object must be opened in binary mode")
+
+    try:
+        archive = ZipFile(filename, 'r', ZIP_DEFLATED)
+    except BadZipfile:
+        f = repair_central_directory(filename, is_file_like)
+        archive = ZipFile(f, 'r', ZIP_DEFLATED)
+    return archive
+
+
+def load_workbook(filename, read_only=False, use_iterators=False, keep_vba=KEEP_VBA, guess_types=False, data_only=False):
+    """Open the given filename and return the workbook
+
+    :param filename: the path to open or a file-like object
+    :type filename: string or a file-like object open in binary mode c.f., :class:`zipfile.ZipFile`
+
+    :param read_only: optimised for reading, content cannot be edited
+    :type read_only: bool
+
+    :param use_iterators: use lazy load for cells
+    :type use_iterators: bool
+
+    :param keep_vba: preseve vba content (this does NOT mean you can use it)
+    :type keep_vba: bool
+
+    :param guess_types: guess cell content type and do not read it from the file
+    :type guess_types: bool
+
+    :param data_only: controls whether cells with formulae have either the formula (default) or the value stored the last time Excel read the sheet
+    :type data_only: bool
+
+    :rtype: :class:`openpyxl.workbook.Workbook`
+
+    .. note::
+
+        When using lazy load, all worksheets will be :class:`openpyxl.worksheet.iter_worksheet.IterableWorksheet`
+        and the returned workbook will be read-only.
+
+    """
+    archive = _validate_archive(filename)
+    read_only = read_only or use_iterators
+
+    wb = Workbook(guess_types=guess_types, data_only=data_only, read_only=read_only)
+
+    if read_only and guess_types:
+        warnings.warn('Data types are not guessed when using iterator reader')
+
+    valid_files = archive.namelist()
+
+    # If are going to preserve the vba then attach a copy of the archive to the
+    # workbook so that is available for the save.
+    if keep_vba:
+        try:
+            f = open(filename, 'rb')
+            s = f.read()
+            f.close()
+        except:
+            pos = filename.tell()
+            filename.seek(0)
+            s = filename.read()
+            filename.seek(pos)
+        wb.vba_archive = ZipFile(BytesIO(s), 'r')
+
+    if read_only:
+        wb._archive = ZipFile(filename)
+
+    # get workbook-level information
+    try:
+        wb.properties = read_properties(archive.read(ARC_CORE))
+    except KeyError:
+        wb.properties = DocumentProperties()
+    wb.active = read_workbook_settings(archive.read(ARC_WORKBOOK)) or 0
+
+    # what content types do we have?
+    cts = dict(read_content_types(archive))
+
+    strings_path = cts.get(SHARED_STRINGS)
+    if strings_path is not None:
+        if strings_path.startswith("/"):
+            strings_path = strings_path[1:]
+        shared_strings = read_string_table(archive.read(strings_path))
+    else:
+        shared_strings = []
+
+    wb.is_template = XLTX in cts or XLTM in cts
+
+    try:
+        wb.loaded_theme = archive.read(ARC_THEME)  # some writers don't output a theme, live with it (fixes #160)
+    except KeyError:
+        assert wb.loaded_theme == None, "even though the theme information is missing there is a theme object ?"
+
+    parsed_styles = read_style_table(archive)
+    if parsed_styles is not None:
+        wb._differential_styles = parsed_styles.differential_styles
+        wb._cell_styles = parsed_styles.cell_styles
+        wb._named_styles = parsed_styles.named_styles
+        wb._colors = parsed_styles.color_index
+        wb._borders = parsed_styles.border_list
+        wb._fonts = parsed_styles.font_list
+        wb._fills = parsed_styles.fill_list
+        wb._number_formats = parsed_styles.number_formats
+        wb._protections = parsed_styles.protections
+        wb._alignments = parsed_styles.alignments
+        wb._colors = parsed_styles.color_index
+
+    wb.excel_base_date = read_excel_base_date(archive)
+
+    # get worksheets
+    wb.worksheets = []  # remove preset worksheet
+    for sheet in detect_worksheets(archive):
+        sheet_name = sheet['title']
+        worksheet_path = sheet['path']
+        if not worksheet_path in valid_files:
+            continue
+
+        if read_only:
+            new_ws = ReadOnlyWorksheet(wb, sheet_name, worksheet_path, None,
+                                       shared_strings)
+            wb._add_sheet(new_ws)
+        else:
+            parser = WorkSheetParser(wb, sheet_name, archive.read(worksheet_path),
+                            shared_strings)
+            parser.parse()
+            new_ws = wb[sheet_name]
+        new_ws.sheet_state = sheet['state']
+
+        if not read_only:
+        # load comments into the worksheet cells
+            comments_file = get_comments_file(worksheet_path, archive, valid_files)
+            if comments_file is not None:
+                read_comments(new_ws, archive.read(comments_file))
+
+    wb._differential_styles = [] # reset
+    wb._named_ranges = list(read_named_ranges(archive.read(ARC_WORKBOOK), wb))
+
+    wb.code_name = read_workbook_code_name(archive.read(ARC_WORKBOOK))
+
+    if EXTERNAL_LINK in cts:
+        rels = read_rels(archive)
+        wb._external_links = list(detect_external_links(rels, archive))
+
+
+    archive.close()
+    return wb

+ 44 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/strings.py

@@ -0,0 +1,44 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+"""Read the shared strings table."""
+
+from openpyxl.compat import unicode
+
+# package imports
+from openpyxl.utils.indexed_list import IndexedList
+from openpyxl.xml.functions import fromstring, safe_iterator
+from openpyxl.xml.constants import SHEET_MAIN_NS, XML_NS
+
+
+def read_string_table(xml_source):
+    """Read in all shared strings in the table"""
+    root = fromstring(text=xml_source)
+    nodes = safe_iterator(root, '{%s}si' % SHEET_MAIN_NS)
+    strings = (get_string(node) for node in nodes)
+    return IndexedList(strings)
+
+
+def get_string(string_index_node):
+    """Read the contents of a specific string index"""
+    rich_nodes = string_index_node.findall('{%s}r' % SHEET_MAIN_NS)
+    if rich_nodes:
+        reconstructed_text = []
+        for rich_node in rich_nodes:
+            partial_text = get_text(rich_node)
+            reconstructed_text.append(partial_text)
+        return unicode(''.join(reconstructed_text))
+    return get_text(string_index_node)
+
+
+def get_text(rich_node):
+    """Read rich text, discarding formatting if not disallowed"""
+    text_node = rich_node.find('{%s}t' % SHEET_MAIN_NS)
+    text = text_node.text or unicode('')
+
+    if text_node.get('{%s}space' % XML_NS) != 'preserve':
+        text = text.strip()
+
+    # fix XML escaping sequence for '_x'
+    text = text.replace('x005F_', '')
+    return unicode(text)

+ 193 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/style.py

@@ -0,0 +1,193 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+"""Read shared style definitions"""
+
+# package imports
+from openpyxl.compat import OrderedDict, zip
+from openpyxl.utils.indexed_list import IndexedList
+from openpyxl.styles import (
+    numbers,
+    Font,
+    Fill,
+    PatternFill,
+    GradientFill,
+    Border,
+    Side,
+    Protection,
+    Alignment,
+    borders,
+)
+from openpyxl.styles.differential import DifferentialStyle
+from openpyxl.styles.colors import COLOR_INDEX, Color
+from openpyxl.styles.styleable import StyleArray
+from openpyxl.styles.named_styles import NamedStyle
+from openpyxl.xml.functions import fromstring, safe_iterator, localname
+from openpyxl.xml.constants import SHEET_MAIN_NS, ARC_STYLE
+from copy import deepcopy
+
+
+class SharedStylesParser(object):
+
+    def __init__(self, xml_source):
+        self.root = fromstring(xml_source)
+        self.cell_styles = IndexedList()
+        self.differential_styles = []
+        self.color_index = COLOR_INDEX
+        self.font_list = IndexedList()
+        self.fill_list = IndexedList()
+        self.border_list = IndexedList()
+        self.alignments = IndexedList([Alignment()])
+        self.protections = IndexedList([Protection()])
+        self.custom_number_formats = {}
+        self.number_formats = IndexedList()
+
+    def parse(self):
+        self.parse_custom_num_formats()
+        self.parse_color_index()
+        self.font_list = IndexedList(self.parse_fonts())
+        self.fill_list = IndexedList(self.parse_fills())
+        self.border_list = IndexedList(self.parse_borders())
+        self.parse_dxfs()
+        self.parse_cell_styles()
+        self.parse_named_styles()
+
+
+    def parse_custom_num_formats(self):
+        """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 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):
+        """Read in the list of indexed colors"""
+        colors =\
+            self.root.findall('{%s}colors/{%s}indexedColors/{%s}rgbColor' %
+                              (SHEET_MAIN_NS, SHEET_MAIN_NS, SHEET_MAIN_NS))
+        if not colors:
+            return
+        self.color_index = IndexedList([node.get('rgb') for node in colors])
+
+
+    def parse_dxfs(self):
+        """Read in the dxfs effects - used by conditional formatting."""
+        for node in self.root.findall("{%s}dxfs/{%s}dxf" % (SHEET_MAIN_NS, SHEET_MAIN_NS) ):
+            self.differential_styles.append(DifferentialStyle.from_tree(node))
+
+
+    def parse_fonts(self):
+        """Read in the fonts"""
+        fonts = self.root.findall('{%s}fonts/{%s}font' % (SHEET_MAIN_NS, SHEET_MAIN_NS))
+        for node in fonts:
+            yield Font.from_tree(node)
+
+
+    def parse_fills(self):
+        """Read in the list of fills"""
+        fills = self.root.findall('{%s}fills/{%s}fill' % (SHEET_MAIN_NS, SHEET_MAIN_NS))
+        for fill in fills:
+            yield Fill.from_tree(fill)
+
+    def parse_borders(self):
+        """Read in the boarders"""
+        borders = self.root.findall('{%s}borders/{%s}border' % (SHEET_MAIN_NS, SHEET_MAIN_NS))
+        for border_node in borders:
+            yield Border.from_tree(border_node)
+
+
+    def parse_named_styles(self):
+        """
+        Extract named styles
+        """
+        node = self.root.find("{%s}cellStyleXfs" % SHEET_MAIN_NS)
+        styles = self._parse_xfs(node)
+
+        names = self._parse_style_names()
+        for style in names.values():
+            _id = styles[style.xfId]
+            style.border = self.border_list[_id.borderId]
+            style.fill = self.fill_list[_id.fillId]
+            style.font = self.font_list[_id.fontId]
+            if _id.alignmentId:
+                style.alignment = self.alignments[_id.alignmentId]
+            if _id.protectionId:
+                style.protection = self.protections[_id.protectionId]
+        self.named_styles = names
+
+
+    def _parse_style_names(self):
+        """
+        Extract style names. There can be duplicates in which case last wins
+        """
+        node = self.root.find("{%s}cellStyles" % SHEET_MAIN_NS)
+        names = {}
+        for _name in node:
+            name = _name.get("name")
+            style = NamedStyle(name=name,
+                               builtinId=_name.get("builtinId"),
+                               hidden=_name.get("hidden")
+                               )
+            style.xfId = int(_name.get("xfId"))
+            names[name] = style
+        return names
+
+
+    def parse_cell_styles(self):
+        """
+        Extract individual cell styles
+        """
+        node = self.root.find('{%s}cellXfs' % SHEET_MAIN_NS)
+        if node is not None:
+            self.cell_styles = self._parse_xfs(node)
+
+
+    def _parse_xfs(self, node):
+        """Read styles from the shared style table"""
+        _style_ids = []
+
+        xfs = safe_iterator(node, '{%s}xf' % SHEET_MAIN_NS)
+        for xf in xfs:
+            style = StyleArray.from_tree(xf)
+
+            al = xf.find('{%s}alignment' % SHEET_MAIN_NS)
+            if al is not None:
+                alignment = Alignment(**al.attrib)
+                style.alignmentId = self.alignments.add(alignment)
+
+            prot = xf.find('{%s}protection' % SHEET_MAIN_NS)
+            if prot is not None:
+                protection = Protection(**prot.attrib)
+                style.protectionId = self.protections.add(protection)
+
+            numFmtId = int(xf.get("numFmtId", 0))
+            # check for custom formats and normalise indices
+
+            if numFmtId in self.custom_number_formats:
+                format_code = self.custom_number_formats[numFmtId]
+                style.numFmtId = self.number_formats.add(format_code) + 164
+
+            _style_ids.append(style)
+        return IndexedList(_style_ids)
+
+
+def read_style_table(archive):
+    if ARC_STYLE in archive.namelist():
+        xml_source = archive.read(ARC_STYLE)
+        p = SharedStylesParser(xml_source)
+        p.parse()
+        return p
+
+
+def bool_attrib(element, attr):
+    """
+    Cast an XML attribute that should be a boolean to a Python equivalent
+    None, 'f', '0' and 'false' all cast to False, everything else to true
+    """
+    value = element.get(attr)
+    if not value or value in ("false", "f", "0"):
+        return False
+    return True

+ 130 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/workbook.py

@@ -0,0 +1,130 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+"""Read in global settings to be maintained by the workbook object."""
+
+# package imports
+from openpyxl.xml.functions import fromstring, safe_iterator
+from openpyxl.xml.constants import (
+    DCORE_NS,
+    COREPROPS_NS,
+    DCTERMS_NS,
+    SHEET_MAIN_NS,
+    CONTYPES_NS,
+    PKG_REL_NS,
+    REL_NS,
+    ARC_CONTENT_TYPES,
+    ARC_WORKBOOK,
+    ARC_WORKBOOK_RELS,
+    WORKSHEET_TYPE,
+    EXTERNAL_LINK,
+)
+from openpyxl.workbook import DocumentProperties
+from openpyxl.utils.datetime  import (
+    CALENDAR_WINDOWS_1900,
+    CALENDAR_MAC_1904
+    )
+from openpyxl.workbook.names.named_range import (
+    NamedRange,
+    NamedValue,
+    split_named_range,
+    refers_to_range,
+    external_range,
+    )
+
+import datetime
+import re
+
+# constants
+VALID_WORKSHEET = WORKSHEET_TYPE
+
+
+def read_excel_base_date(archive):
+    src = archive.read(ARC_WORKBOOK)
+    root = fromstring(src)
+    wbPr = root.find('{%s}workbookPr' % SHEET_MAIN_NS)
+    if wbPr is not None and wbPr.get('date1904') in ('1', 'true'):
+        return CALENDAR_MAC_1904
+    return CALENDAR_WINDOWS_1900
+
+
+def read_content_types(archive):
+    """Read content types."""
+    xml_source = archive.read(ARC_CONTENT_TYPES)
+    root = fromstring(xml_source)
+    contents_root = root.findall('{%s}Override' % CONTYPES_NS)
+    for type in contents_root:
+        yield type.get('ContentType'), type.get('PartName')
+
+
+def read_rels(archive):
+    """Read relationships for a workbook"""
+    xml_source = archive.read(ARC_WORKBOOK_RELS)
+    tree = fromstring(xml_source)
+    for element in safe_iterator(tree, '{%s}Relationship' % PKG_REL_NS):
+        rId = element.get('Id')
+        pth = element.get("Target")
+        typ = element.get('Type')
+        # normalise path
+        if pth.startswith("/xl"):
+            pth = pth.replace("/xl", "xl")
+        elif not pth.startswith("xl") and not pth.startswith(".."):
+            pth = "xl/" + pth
+        yield rId, {'path':pth, 'type':typ}
+
+
+def read_sheets(archive):
+    """Read worksheet titles and ids for a workbook"""
+    xml_source = archive.read(ARC_WORKBOOK)
+    tree = fromstring(xml_source)
+    for element in safe_iterator(tree, '{%s}sheet' % SHEET_MAIN_NS):
+        attrib = element.attrib
+        attrib['id'] = attrib["{%s}id" % REL_NS]
+        del attrib["{%s}id" % REL_NS]
+        if attrib['id']:
+            yield attrib
+
+
+def detect_worksheets(archive):
+    """Return a list of worksheets"""
+    # content types has a list of paths but no titles
+    # workbook has a list of titles and relIds but no paths
+    # workbook_rels has a list of relIds and paths but no titles
+    # rels = {'id':{'title':'', 'path':''} }
+    content_types = read_content_types(archive)
+    valid_sheets = dict((path, ct) for ct, path in content_types if ct == VALID_WORKSHEET)
+    rels = dict(read_rels(archive))
+    for sheet in read_sheets(archive):
+        rel = rels[sheet['id']]
+        rel['title'] = sheet['name']
+        rel['sheet_id'] = sheet['sheetId']
+        rel['state'] = sheet.get('state', 'visible')
+        if ("/" + rel['path'] in valid_sheets
+            or "worksheets" in rel['path']): # fallback in case content type is missing
+            yield rel
+
+
+def detect_external_links(archive):
+    rels = read_rels(archive)
+    for rId, d in rels:
+        if d['type'] == EXTERNAL_LINK:
+            pth = d['path']
+
+
+def read_workbook_code_name(xml_source):
+    tree = fromstring(xml_source)
+
+    pr = tree.find("{%s}workbookPr" % SHEET_MAIN_NS)
+
+    if pr is None:
+        pr = {}
+
+    return pr.get('codeName', 'ThisWorkbook')
+
+
+def read_workbook_settings(xml_source):
+    root = fromstring(xml_source)
+    view = root.find('*/' '{%s}workbookView' % SHEET_MAIN_NS)
+    if view is not None:
+        if 'activeTab' in view.attrib:
+            return int(view.attrib['activeTab'])

+ 326 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/reader/worksheet.py

@@ -0,0 +1,326 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+"""Reader for a single worksheet."""
+from io import BytesIO
+from warnings import warn
+
+# compatibility imports
+from openpyxl.xml.functions import iterparse
+
+# package imports
+from openpyxl.cell import Cell
+from openpyxl.cell.read_only import _cast_number
+from openpyxl.worksheet import Worksheet, ColumnDimension, RowDimension
+from openpyxl.worksheet.page import PageMargins, PrintOptions, PrintPageSetup
+from openpyxl.worksheet.protection import SheetProtection
+from openpyxl.worksheet.views import SheetView
+from openpyxl.worksheet.datavalidation import DataValidation
+from openpyxl.xml.constants import (
+    SHEET_MAIN_NS,
+    REL_NS,
+    EXT_TYPES
+)
+from openpyxl.xml.functions import safe_iterator
+from openpyxl.styles import Color
+from openpyxl.formatting import ConditionalFormatting, Rule
+from openpyxl.formula.translate import Translator
+from openpyxl.worksheet.properties import WorksheetProperties
+from openpyxl.utils import (
+    coordinate_from_string,
+    get_column_letter,
+    column_index_from_string,
+    coordinate_to_tuple,
+    )
+from openpyxl.descriptors.excel import ExtensionList, Extension
+
+
+def _get_xml_iter(xml_source):
+    """
+    Possible inputs: strings, bytes, members of zipfile, temporary file
+    Always return a file like object
+    """
+    if not hasattr(xml_source, 'read'):
+        try:
+            xml_source = xml_source.encode("utf-8")
+        except (AttributeError, UnicodeDecodeError):
+            pass
+        return BytesIO(xml_source)
+    else:
+        try:
+            xml_source.seek(0)
+        except:
+            pass
+        return xml_source
+
+
+class WorkSheetParser(object):
+
+    COL_TAG = '{%s}col' % SHEET_MAIN_NS
+    ROW_TAG = '{%s}row' % SHEET_MAIN_NS
+    CELL_TAG = '{%s}c' % SHEET_MAIN_NS
+    VALUE_TAG = '{%s}v' % SHEET_MAIN_NS
+    FORMULA_TAG = '{%s}f' % SHEET_MAIN_NS
+    MERGE_TAG = '{%s}mergeCell' % SHEET_MAIN_NS
+    INLINE_STRING = "{%s}is/{%s}t" % (SHEET_MAIN_NS, SHEET_MAIN_NS)
+    INLINE_RICHTEXT = "{%s}is/{%s}r/{%s}t" % (SHEET_MAIN_NS, SHEET_MAIN_NS, SHEET_MAIN_NS)
+
+    def __init__(self, wb, title, xml_source, shared_strings):
+        self.ws = wb.create_sheet(title=title)
+        self.source = xml_source
+        self.shared_strings = shared_strings
+        self.guess_types = wb._guess_types
+        self.data_only = wb.data_only
+        self.styles = self.ws.parent._cell_styles
+        self.differential_styles = wb._differential_styles
+        self.keep_vba = wb.vba_archive is not None
+        self.shared_formula_masters = {}  # {si_str: Translator()}
+
+    def parse(self):
+        dispatcher = {
+            '{%s}mergeCells' % SHEET_MAIN_NS: self.parse_merge,
+            '{%s}col' % SHEET_MAIN_NS: self.parse_column_dimensions,
+            '{%s}row' % SHEET_MAIN_NS: self.parse_row_dimensions,
+            '{%s}printOptions' % SHEET_MAIN_NS: self.parse_print_options,
+            '{%s}pageMargins' % SHEET_MAIN_NS: self.parse_margins,
+            '{%s}pageSetup' % SHEET_MAIN_NS: self.parse_page_setup,
+            '{%s}headerFooter' % SHEET_MAIN_NS: self.parse_header_footer,
+            '{%s}conditionalFormatting' % SHEET_MAIN_NS: self.parser_conditional_formatting,
+            '{%s}autoFilter' % SHEET_MAIN_NS: self.parse_auto_filter,
+            '{%s}sheetProtection' % SHEET_MAIN_NS: self.parse_sheet_protection,
+            '{%s}dataValidations' % SHEET_MAIN_NS: self.parse_data_validation,
+            '{%s}sheetPr' % SHEET_MAIN_NS: self.parse_properties,
+            '{%s}legacyDrawing' % SHEET_MAIN_NS: self.parse_legacy_drawing,
+            '{%s}sheetViews' % SHEET_MAIN_NS: self.parse_sheet_views,
+            '{%s}extLst' % SHEET_MAIN_NS: self.parse_extensions,
+                      }
+        tags = dispatcher.keys()
+        stream = _get_xml_iter(self.source)
+        it = iterparse(stream, tag=tags)
+
+        for _, element in it:
+            tag_name = element.tag
+            if tag_name in dispatcher:
+                dispatcher[tag_name](element)
+                element.clear()
+
+        self.ws._current_row = self.ws.max_row
+
+    def parse_cell(self, element):
+        value = element.find(self.VALUE_TAG)
+        if value is not None:
+            value = value.text
+        formula = element.find(self.FORMULA_TAG)
+        data_type = element.get('t', 'n')
+        coordinate = element.get('r')
+        style_id = element.get('s')
+
+        # assign formula to cell value unless only the data is desired
+        if formula is not None and not self.data_only:
+            data_type = 'f'
+            if formula.text:
+                value = "=" + formula.text
+            else:
+                value = "="
+            formula_type = formula.get('t')
+            if formula_type:
+                if formula_type != "shared":
+                    self.ws.formula_attributes[coordinate] = dict(formula.attrib)
+
+                else:
+                    si = formula.get('si')  # Shared group index for shared formulas
+
+                    # The spec (18.3.1.40) defines shared formulae in
+                    # terms of the following:
+                    #
+                    # `master`: "The first formula in a group of shared
+                    #            formulas"
+                    # `ref`: "Range of cells which the formula applies
+                    #        to." It's a required attribute on the master
+                    #        cell, forbidden otherwise.
+                    # `shared cell`: "A cell is shared only when si is
+                    #                 used and t is `shared`."
+                    #
+                    # Whether to use the cell's given formula or the
+                    # master's depends on whether the cell is shared,
+                    # whether it's in the ref, and whether it defines its
+                    # own formula, as follows:
+                    #
+                    #  Shared?   Has formula? | In ref    Not in ref
+                    # ========= ==============|======== ===============
+                    #   Yes          Yes      | master   impl. defined
+                    #    No          Yes      |  own         own
+                    #   Yes           No      | master   impl. defined
+                    #    No           No      |  ??          N/A
+                    #
+                    # The ?? is because the spec is silent on this issue,
+                    # though my inference is that the cell does not
+                    # receive a formula at all.
+                    #
+                    # For this implementation, we are using the master
+                    # formula in the two "impl. defined" cases and no
+                    # formula in the "??" case. This choice of
+                    # implementation allows us to disregard the `ref`
+                    # parameter altogether, and does not require
+                    # computing expressions like `C5 in A1:D6`.
+                    # Presumably, Excel does not generate spreadsheets
+                    # with such contradictions.
+                    if si in self.shared_formula_masters:
+                        trans = self.shared_formula_masters[si]
+                        value = trans.translate_formula(coordinate)
+                    else:
+                        self.shared_formula_masters[si] = Translator(value, coordinate)
+
+
+        style_array = None
+        if style_id is not None:
+            style_id = int(style_id)
+            style_array = self.styles[style_id]
+
+        row, column = coordinate_to_tuple(coordinate)
+        cell = Cell(self.ws, row=row, col_idx=column, style_array=style_array)
+        self.ws._cells[(row, column)] = cell
+
+        if value is not None:
+            if data_type == 'n':
+                value = _cast_number(value)
+            elif data_type == 'b':
+                value = bool(int(value))
+            elif data_type == 's':
+                value = self.shared_strings[int(value)]
+            elif data_type == 'str':
+                data_type = 's'
+
+        else:
+            if data_type == 'inlineStr':
+                data_type = 's'
+                child = element.find(self.INLINE_STRING)
+                if child is None:
+                    child = element.find(self.INLINE_RICHTEXT)
+                if child is not None:
+                    value = child.text
+
+        if self.guess_types or value is None:
+            cell.value = value
+        else:
+            cell._value=value
+            cell.data_type=data_type
+
+
+    def parse_merge(self, element):
+        for mergeCell in safe_iterator(element, ('{%s}mergeCell' % SHEET_MAIN_NS)):
+            self.ws.merge_cells(mergeCell.get('ref'))
+
+    def parse_column_dimensions(self, col):
+        attrs = dict(col.attrib)
+        column = get_column_letter(int(attrs['min']))
+        attrs['index'] = column
+        if 'style' in attrs:
+            attrs['style'] = self.styles[int(attrs['style'])]
+        dim = ColumnDimension(self.ws, **attrs)
+        self.ws.column_dimensions[column] = dim
+
+
+    def parse_row_dimensions(self, row):
+        attrs = dict(row.attrib)
+        keys = set(attrs)
+        for key in keys:
+            if key == "s":
+                attrs['s'] = self.styles[int(attrs['s'])]
+            elif key.startswith('{'):
+                del attrs[key]
+
+
+        keys = set(attrs)
+        if keys != set(['r', 'spans']) and keys != set(['r']):
+            # don't create dimension objects unless they have relevant information
+            dim = RowDimension(self.ws, **attrs)
+            self.ws.row_dimensions[dim.index] = dim
+
+        for cell in safe_iterator(row, self.CELL_TAG):
+            self.parse_cell(cell)
+
+
+    def parse_print_options(self, element):
+        self.ws.print_options = PrintOptions.from_tree(element)
+
+    def parse_margins(self, element):
+        self.page_margins = PageMargins.from_tree(element)
+
+    def parse_page_setup(self, element):
+        self.ws.page_setup = PrintPageSetup.from_tree(element)
+
+    def parse_header_footer(self, element):
+        oddHeader = element.find('{%s}oddHeader' % SHEET_MAIN_NS)
+        if oddHeader is not None and oddHeader.text is not None:
+            self.ws.header_footer.setHeader(oddHeader.text)
+        oddFooter = element.find('{%s}oddFooter' % SHEET_MAIN_NS)
+        if oddFooter is not None and oddFooter.text is not None:
+            self.ws.header_footer.setFooter(oddFooter.text)
+
+
+    def parser_conditional_formatting(self, element):
+        range_string = element.get('sqref')
+        cfRules = element.findall('{%s}cfRule' % SHEET_MAIN_NS)
+        self.ws.conditional_formatting.cf_rules[range_string] = []
+        for node in cfRules:
+            rule = Rule.from_tree(node)
+            if rule.dxfId is not None:
+                rule.dxf = self.differential_styles[rule.dxfId]
+            self.ws.conditional_formatting.cf_rules[range_string].append(rule)
+
+
+    def parse_auto_filter(self, element):
+        self.ws.auto_filter.ref = element.get("ref")
+        for fc in safe_iterator(element, '{%s}filterColumn' % SHEET_MAIN_NS):
+            filters = fc.find('{%s}filters' % SHEET_MAIN_NS)
+            if filters is None:
+                continue
+            vals = [f.get("val") for f in safe_iterator(filters, '{%s}filter' % SHEET_MAIN_NS)]
+            blank = filters.get("blank")
+            self.ws.auto_filter.add_filter_column(fc.get("colId"), vals, blank=blank)
+        for sc in safe_iterator(element, '{%s}sortCondition' % SHEET_MAIN_NS):
+            self.ws.auto_filter.add_sort_condition(sc.get("ref"), sc.get("descending"))
+
+    def parse_sheet_protection(self, element):
+        self.ws.protection = SheetProtection.from_tree(element)
+        password = element.get("password")
+        if password is not None:
+            self.ws.protection.set_password(password, True)
+
+    def parse_data_validation(self, element):
+        for node in safe_iterator(element, "{%s}dataValidation" % SHEET_MAIN_NS):
+            dv = DataValidation.from_tree(node)
+            self.ws._data_validations.append(dv)
+
+
+    def parse_properties(self, element):
+        self.ws.sheet_properties = WorksheetProperties.from_tree(element)
+
+
+    def parse_legacy_drawing(self, element):
+        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):
+        for el in element.findall("{%s}sheetView" % SHEET_MAIN_NS):
+            # according to the specification the last view wins
+            pass
+        self.ws.sheet_view = SheetView.from_tree(el)
+
+
+    def parse_extensions(self, element):
+        extLst = ExtensionList.from_tree(element)
+        for e in extLst.ext:
+            ext_type = EXT_TYPES.get(e.uri.upper(), "Unknown")
+            msg = "{0} extension is not supported and will be removed".format(ext_type)
+            warn(msg)
+
+
+def fast_parse(xml_source, parent, sheet_title, shared_strings):
+    parser = WorkSheetParser(parent, sheet_title, xml_source, shared_strings)
+    parser.parse()
+    return parser.ws

+ 63 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/__init__.py

@@ -0,0 +1,63 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors import Typed
+from openpyxl.compat import deprecated
+
+from .alignment import Alignment
+from .borders import Border, Side
+from .colors import Color
+from .fills import PatternFill, GradientFill, Fill
+from .fonts import Font
+from .hashable import HashableObject
+from .numbers import NumberFormatDescriptor, is_date_format, is_builtin
+from .protection import Protection
+from .proxy import StyleProxy
+
+
+class Style(HashableObject):
+    """Style object containing all formatting details."""
+    __fields__ = ('font',
+                  'fill',
+                  'border',
+                  'alignment',
+                  'number_format',
+                  'protection')
+    __base__ = True
+
+    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)
+
+    def __init__(self,
+                 font=Font(),
+                 fill=PatternFill(),
+                 border=Border(),
+                 alignment=Alignment(),
+                 number_format=None,
+                 protection=Protection()
+                 ):
+        self.font = font
+        self.fill = fill
+        self.border = border
+        self.alignment = alignment
+        self.number_format = number_format
+        self.protection = 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()

+ 73 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/alignment.py

@@ -0,0 +1,73 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.compat import safe_string
+
+from openpyxl.descriptors import Bool, MinMax, Min, Alias, NoneSet
+
+from .hashable import HashableObject
+
+horizontal_alignments = (
+    "general", "left", "center", "right", "fill", "justify", "centerContinuous",
+    "distributed", )
+vertical_aligments = (
+    "top", "center", "bottom", "justify", "distributed",
+)
+
+class Alignment(HashableObject):
+    """Alignment options for use in styles."""
+
+    tagname = "alignment"
+
+    __fields__ = ('horizontal',
+                  'vertical',
+                  'textRotation',
+                  'wrapText',
+                  'shrinkToFit',
+                  'indent',
+                  'relativeIndent',
+                  'justifyLastLine',
+                  'readingOrder',
+                  )
+    horizontal = NoneSet(values=horizontal_alignments)
+    vertical = NoneSet(values=vertical_aligments)
+    textRotation = NoneSet(values=range(181))
+    textRotation.values.add(255)
+    text_rotation = Alias('textRotation')
+    wrapText = Bool(allow_none=True)
+    wrap_text = Alias('wrapText')
+    shrinkToFit = Bool(allow_none=True)
+    shrink_to_fit = Alias('shrinkToFit')
+    indent = Min(min=0)
+    relativeIndent = Min(min=0)
+    justifyLastLine = Bool(allow_none=True)
+    readingOrder = Min(min=0)
+
+    def __init__(self, horizontal=None, vertical=None,
+                 textRotation=0, wrapText=None, shrinkToFit=None, indent=0, relativeIndent=0,
+                 justifyLastLine=None, readingOrder=0, text_rotation=None,
+                 wrap_text=None, shrink_to_fit=None, mergeCell=None):
+        self.horizontal = horizontal
+        self.vertical = vertical
+        self.indent = indent
+        self.relativeIndent = relativeIndent
+        self.justifyLastLine = justifyLastLine
+        self.readingOrder = readingOrder
+        if text_rotation is not None:
+            textRotation = text_rotation
+        if textRotation is not None:
+            self.textRotation = int(textRotation)
+        if wrap_text is not None:
+            wrapText = wrap_text
+        self.wrapText = wrapText
+        if shrink_to_fit is not None:
+            shrinkToFit = shrink_to_fit
+        self.shrinkToFit = shrinkToFit
+        # mergeCell is vestigial
+
+
+    def __iter__(self):
+        for attr in self.__attrs__:
+            value = getattr(self, attr)
+            if value is not None and value != 0:
+                yield attr, safe_string(value)

+ 107 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/borders.py

@@ -0,0 +1,107 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.compat import safe_string
+from openpyxl.descriptors import NoneSet, Typed, Bool, Alias
+
+from .colors import ColorDescriptor
+from .hashable import HashableObject
+
+
+BORDER_NONE = None
+BORDER_DASHDOT = 'dashDot'
+BORDER_DASHDOTDOT = 'dashDotDot'
+BORDER_DASHED = 'dashed'
+BORDER_DOTTED = 'dotted'
+BORDER_DOUBLE = 'double'
+BORDER_HAIR = 'hair'
+BORDER_MEDIUM = 'medium'
+BORDER_MEDIUMDASHDOT = 'mediumDashDot'
+BORDER_MEDIUMDASHDOTDOT = 'mediumDashDotDot'
+BORDER_MEDIUMDASHED = 'mediumDashed'
+BORDER_SLANTDASHDOT = 'slantDashDot'
+BORDER_THICK = 'thick'
+BORDER_THIN = 'thin'
+
+
+class Side(HashableObject):
+
+    """Border options for use in styles.
+    Caution: if you do not specify a border_style, other attributes will
+    have no effect !"""
+
+    __fields__ = ('style',
+                  'color')
+
+    color = ColorDescriptor(allow_none=True)
+    style = NoneSet(values=('dashDot','dashDotDot', 'dashed','dotted',
+                            'double','hair', 'medium', 'mediumDashDot', 'mediumDashDotDot',
+                            'mediumDashed', 'slantDashDot', 'thick', 'thin')
+                    )
+    border_style = Alias('style')
+
+    def __init__(self, style=None, color=None, border_style=None):
+        if border_style is not None:
+            style = border_style
+        self.style = style
+        self.color = color
+
+
+class Border(HashableObject):
+    """Border positioning for use in styles."""
+
+    tagname = "border"
+
+    __fields__ = ('left',
+                  'right',
+                  'top',
+                  'bottom',
+                  'diagonal',
+                  'diagonal_direction',
+                  'vertical',
+                  'horizontal')
+    __elements__ = ('start', 'end', 'left', 'right', 'top', 'bottom',
+                    'diagonal', 'vertical', 'horizontal')
+
+    # child elements
+    start = Typed(expected_type=Side, allow_none=True)
+    end = Typed(expected_type=Side, allow_none=True)
+    left = Typed(expected_type=Side, allow_none=True)
+    right = Typed(expected_type=Side, allow_none=True)
+    top = Typed(expected_type=Side, allow_none=True)
+    bottom = Typed(expected_type=Side)
+    diagonal = Typed(expected_type=Side, allow_none=True)
+    vertical = Typed(expected_type=Side, allow_none=True)
+    horizontal = Typed(expected_type=Side, allow_none=True)
+    # attributes
+    outline = Bool()
+    diagonalUp = Bool()
+    diagonalDown = Bool()
+
+    def __init__(self, left=Side(), right=Side(), top=Side(),
+                 bottom=Side(), diagonal=Side(), diagonal_direction=None,
+                 vertical=None, horizontal=None, diagonalUp=False, diagonalDown=False,
+                 outline=True, start=None, end=None):
+        self.left = left
+        self.right = right
+        self.top = top
+        self.bottom = bottom
+        self.diagonal = diagonal
+        self.vertical = vertical
+        self.horizontal = horizontal
+        self.diagonal_direction = diagonal_direction
+        self.diagonalUp = diagonalUp
+        self.diagonalDown = diagonalDown
+        self.outline = outline
+        self.start = start
+        self.end = end
+
+    def __iter__(self):
+        for attr in self.__attrs__:
+            value = getattr(self, attr)
+            if value and attr != "outline":
+                yield attr, value
+            elif attr == "outline" and not value:
+                yield attr, value
+
+DEFAULT_BORDER = Border()

+ 119 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/colors.py

@@ -0,0 +1,119 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+import re
+from openpyxl.compat import safe_string, basestring
+from openpyxl.descriptors import Descriptor, Typed
+
+from .hashable import HashableObject
+from openpyxl.descriptors import String, Bool, MinMax, Integer
+
+# Default Color Index as per 18.8.27 of ECMA Part 4
+COLOR_INDEX = (
+    '00000000', '00FFFFFF', '00FF0000', '0000FF00', '000000FF', #0-4
+    '00FFFF00', '00FF00FF', '0000FFFF', '00000000', '00FFFFFF', #5-9
+    '00FF0000', '0000FF00', '000000FF', '00FFFF00', '00FF00FF', #10-14
+    '0000FFFF', '00800000', '00008000', '00000080', '00808000', #15-19
+    '00800080', '00008080', '00C0C0C0', '00808080', '009999FF', #20-24
+    '00993366', '00FFFFCC', '00CCFFFF', '00660066', '00FF8080', #25-29
+    '000066CC', '00CCCCFF', '00000080', '00FF00FF', '00FFFF00', #30-34
+    '0000FFFF', '00800080', '00800000', '00008080', '000000FF', #35-39
+    '0000CCFF', '00CCFFFF', '00CCFFCC', '00FFFF99', '0099CCFF', #40-44
+    '00FF99CC', '00CC99FF', '00FFCC99', '003366FF', '0033CCCC', #45-49
+    '0099CC00', '00FFCC00', '00FF9900', '00FF6600', '00666699', #50-54
+    '00969696', '00003366', '00339966', '00003300', '00333300', #55-59
+    '00993300', '00993366', '00333399', '00333333', 'System Foreground', 'System Background' #60-64
+)
+
+BLACK = COLOR_INDEX[0]
+WHITE = COLOR_INDEX[1]
+RED = COLOR_INDEX[2]
+DARKRED = COLOR_INDEX[8]
+BLUE = COLOR_INDEX[4]
+DARKBLUE = COLOR_INDEX[10]
+GREEN = COLOR_INDEX[3]
+DARKGREEN = COLOR_INDEX[9]
+YELLOW = COLOR_INDEX[5]
+DARKYELLOW = COLOR_INDEX[19]
+
+
+aRGB_REGEX = re.compile("^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6})$")
+
+
+class RGB(Typed):
+    """
+    Descriptor for aRGB values
+    If not supplied alpha is 00
+    """
+
+    expected_type = basestring
+
+    def __set__(self, instance, value):
+        m = aRGB_REGEX.match(value)
+        if m is None:
+            raise ValueError("Colors must be aRGB hex values")
+        if len(value) == 6:
+            value = "00" + value
+        super(RGB, self).__set__(instance, value)
+
+
+class Color(HashableObject):
+    """Named colors for use in styles."""
+
+    tagname = "color"
+
+    rgb = RGB()
+    indexed = Integer()
+    auto = Bool()
+    theme = Integer()
+    tint = MinMax(min=-1, max=1, expected_type=float)
+    type = String()
+
+    __fields__ = ('rgb', 'indexed', 'auto', 'theme', 'tint', 'type')
+
+    def __init__(self, rgb=BLACK, indexed=None, auto=None, theme=None, tint=0.0, index=None, type='rgb'):
+        if index is not None:
+            indexed = index
+        if indexed is not None:
+            self.type = 'indexed'
+            self.indexed = indexed
+        elif theme is not None:
+            self.type = 'theme'
+            self.theme = theme
+        elif auto is not None:
+            self.type = 'auto'
+            self.auto = auto
+        else:
+            self.rgb = rgb
+            self.type = 'rgb'
+        self.tint = tint
+
+    @property
+    def value(self):
+        return getattr(self, self.type)
+
+    @value.setter
+    def value(self, value):
+        setattr(self, self.type, value)
+
+    def __iter__(self):
+        attrs = [(self.type, self.value)]
+        if self.tint != 0:
+            attrs.append(('tint', self.tint))
+        for k, v in attrs:
+            yield k, safe_string(v)
+
+    @property
+    def index(self):
+        # legacy
+        return self.value
+
+
+class ColorDescriptor(Typed):
+
+    expected_type = Color
+
+    def __set__(self, instance, value):
+        if isinstance(value, basestring):
+            value = Color(rgb=value)
+        super(ColorDescriptor, self).__set__(instance, value)

+ 62 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/differential.py

@@ -0,0 +1,62 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors import Integer, String, Typed
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.styles import (
+    Font,
+    Fill,
+    GradientFill,
+    PatternFill,
+    Border,
+    Alignment,
+    Protection,
+    HashableObject
+    )
+
+from openpyxl.xml.functions import localname, Element
+
+
+class NumFmt(Serialisable):
+
+    numFmtId = Integer()
+    formatCode = String()
+
+    def __init__(self,
+                 numFmtId=None,
+                 formatCode=None,
+                ):
+        self.numFmtId = numFmtId
+        self.formatCode = formatCode
+
+
+class DifferentialStyle(HashableObject):
+
+    tagname = "dxf"
+
+    __elements__ = ("font", "numFmt", "fill", "alignment", "border", "protection")
+    __fields__ = __elements__
+
+    font = Typed(expected_type=Font, allow_none=True)
+    numFmt = Typed(expected_type=NumFmt, allow_none=True)
+    fill = Typed(expected_type=Fill, allow_none=True)
+    alignment = Typed(expected_type=Alignment, allow_none=True)
+    border = Typed(expected_type=Border, allow_none=True)
+    protection = Typed(expected_type=Protection, allow_none=True)
+
+    def __init__(self,
+                 font=None,
+                 numFmt=None,
+                 fill=None,
+                 alignment=None,
+                 border=None,
+                 protection=None,
+                 extLst=None,
+                ):
+        self.font = font
+        self.numFmt = numFmt
+        self.fill = fill
+        self.alignment = alignment
+        self.border = border
+        self.protection = protection
+        self.extLst = extLst

+ 174 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/fills.py

@@ -0,0 +1,174 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors import Float, Set, Alias, NoneSet
+from openpyxl.descriptors.nested import NestedSequence
+from openpyxl.compat import safe_string
+
+from .colors import ColorDescriptor, Color
+from .hashable import HashableObject
+
+from openpyxl.xml.functions import Element, localname, safe_iterator
+from openpyxl.xml.constants import SHEET_MAIN_NS
+
+
+FILL_NONE = 'none'
+FILL_SOLID = 'solid'
+FILL_PATTERN_DARKDOWN = 'darkDown'
+FILL_PATTERN_DARKGRAY = 'darkGray'
+FILL_PATTERN_DARKGRID = 'darkGrid'
+FILL_PATTERN_DARKHORIZONTAL = 'darkHorizontal'
+FILL_PATTERN_DARKTRELLIS = 'darkTrellis'
+FILL_PATTERN_DARKUP = 'darkUp'
+FILL_PATTERN_DARKVERTICAL = 'darkVertical'
+FILL_PATTERN_GRAY0625 = 'gray0625'
+FILL_PATTERN_GRAY125 = 'gray125'
+FILL_PATTERN_LIGHTDOWN = 'lightDown'
+FILL_PATTERN_LIGHTGRAY = 'lightGray'
+FILL_PATTERN_LIGHTGRID = 'lightGrid'
+FILL_PATTERN_LIGHTHORIZONTAL = 'lightHorizontal'
+FILL_PATTERN_LIGHTTRELLIS = 'lightTrellis'
+FILL_PATTERN_LIGHTUP = 'lightUp'
+FILL_PATTERN_LIGHTVERTICAL = 'lightVertical'
+FILL_PATTERN_MEDIUMGRAY = 'mediumGray'
+
+fills = (FILL_SOLID, FILL_PATTERN_DARKDOWN, FILL_PATTERN_DARKGRAY,
+         FILL_PATTERN_DARKGRID, FILL_PATTERN_DARKHORIZONTAL, FILL_PATTERN_DARKTRELLIS,
+         FILL_PATTERN_DARKUP, FILL_PATTERN_DARKVERTICAL, FILL_PATTERN_GRAY0625,
+         FILL_PATTERN_GRAY125, FILL_PATTERN_LIGHTDOWN, FILL_PATTERN_LIGHTGRAY,
+         FILL_PATTERN_LIGHTGRID, FILL_PATTERN_LIGHTHORIZONTAL,
+         FILL_PATTERN_LIGHTTRELLIS, FILL_PATTERN_LIGHTUP, FILL_PATTERN_LIGHTVERTICAL,
+         FILL_PATTERN_MEDIUMGRAY)
+
+
+class Fill(HashableObject):
+
+    """Base class"""
+
+    tagname = "fill"
+
+    @classmethod
+    def from_tree(cls, el):
+        children = [c for c in el]
+        if not children:
+            return
+        child = children[0]
+        if "patternFill" in child.tag:
+            return PatternFill._from_tree(child)
+        else:
+            return GradientFill._from_tree(child)
+
+
+class PatternFill(Fill):
+    """Area fill patterns for use in styles.
+    Caution: if you do not specify a fill_type, other attributes will have
+    no effect !"""
+
+    tagname = "patternFill"
+
+    __fields__ = ('patternType',
+                  'fgColor',
+                  'bgColor')
+
+    __elements__ = ('fgColor', 'bgColor')
+
+    patternType = NoneSet(values=fills)
+    fill_type = Alias("patternType")
+    fgColor = ColorDescriptor()
+    start_color = Alias("fgColor")
+    bgColor = ColorDescriptor()
+    end_color = Alias("bgColor")
+
+    def __init__(self, patternType=None, fgColor=Color(), bgColor=Color(),
+                 fill_type=None, start_color=None, end_color=None):
+        if fill_type is not None:
+            patternType = fill_type
+        self.patternType = patternType
+        if start_color is not None:
+            fgColor = start_color
+        self.fgColor = fgColor
+        if end_color is not None:
+            bgColor = end_color
+        self.bgColor = bgColor
+
+    @classmethod
+    def _from_tree(cls, el):
+        attrib = dict(el.attrib)
+        for child in el:
+            desc = localname(child)
+            attrib[desc] = Color.from_tree(child)
+        return cls(**attrib)
+
+
+    def to_tree(self, tagname=None):
+        parent = Element("fill")
+        el = Element(self.tagname)
+        if self.patternType is not None:
+            el.set('patternType', self.patternType)
+        for c in self.__elements__:
+            value = getattr(self, c)
+            if value != Color():
+                el.append(value.to_tree(c))
+        parent.append(el)
+        return parent
+
+
+DEFAULT_EMPTY_FILL = PatternFill()
+DEFAULT_GRAY_FILL = PatternFill(patternType='gray125')
+
+
+def _serialise_stop(tagname, sequence, namespace=None):
+    for idx, color in enumerate(sequence):
+        stop = Element("stop", position=str(idx))
+        stop.append(color.to_tree())
+        yield stop
+
+
+class GradientFill(Fill):
+
+    tagname = "gradientFill"
+
+
+    __fields__ = ('type', 'degree', 'left', 'right', 'top', 'bottom', 'stop')
+    type = Set(values=('linear', 'path'))
+    fill_type = Alias("type")
+    degree = Float()
+    left = Float()
+    right = Float()
+    top = Float()
+    bottom = Float()
+    stop = NestedSequence(expected_type=Color, to_tree=_serialise_stop)
+
+
+    def __init__(self, type="linear", degree=0, left=0, right=0, top=0,
+                 bottom=0, stop=(), fill_type=None):
+        self.degree = degree
+        self.left = left
+        self.right = right
+        self.top = top
+        self.bottom = bottom
+        self.stop = stop
+        if fill_type is not None:
+            type = fill_type
+        self.type = type
+
+
+    def __iter__(self):
+        for attr in self.__attrs__:
+            value = getattr(self, attr)
+            if value:
+                yield attr, safe_string(value)
+
+
+    @classmethod
+    def _from_tree(cls, node):
+        colors = []
+        for color in safe_iterator(node, "{%s}color" % SHEET_MAIN_NS):
+            colors.append(Color.from_tree(color))
+        return cls(stop=colors, **node.attrib)
+
+    def to_tree(self, tagname=None, namespace=None):
+        parent = Element("fill")
+        el = super(GradientFill, self).to_tree()
+        parent.append(el)
+        return parent

+ 101 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/fonts.py

@@ -0,0 +1,101 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+
+from openpyxl.descriptors import Alias
+
+from openpyxl.descriptors.nested import (
+    NestedValue,
+    NestedBool,
+    NestedNoneSet,
+    NestedMinMax,
+    NestedString,
+    NestedInteger,
+    NestedFloat,
+)
+from .hashable import HashableObject
+from .colors import ColorDescriptor, BLACK
+
+from openpyxl.compat import safe_string
+from openpyxl.xml.functions import Element, SubElement
+
+
+def _no_value(tagname, value, namespace=None):
+    if value:
+        return Element(tagname, val=safe_string(value))
+
+
+class Font(HashableObject):
+    """Font options used in styles."""
+
+    UNDERLINE_DOUBLE = 'double'
+    UNDERLINE_DOUBLE_ACCOUNTING = 'doubleAccounting'
+    UNDERLINE_SINGLE = 'single'
+    UNDERLINE_SINGLE_ACCOUNTING = 'singleAccounting'
+
+    name = NestedString()
+    charset = NestedInteger(allow_none=True)
+    family = NestedMinMax(min=0, max=14)
+    sz = NestedFloat()
+    size = Alias("sz")
+    b = NestedBool(to_tree=_no_value)
+    bold = Alias("b")
+    i = NestedBool(to_tree=_no_value)
+    italic = Alias("i")
+    strike = NestedBool(to_tree=_no_value)
+    strikethrough = Alias("strike")
+    outline = NestedBool(to_tree=_no_value)
+    shadow = NestedBool(to_tree=_no_value)
+    condense = NestedBool(to_tree=_no_value)
+    extend = NestedBool(to_tree=_no_value)
+    u = NestedNoneSet(values=('single', 'double', 'singleAccounting',
+                             'doubleAccounting'))
+    underline = Alias("u")
+    vertAlign = NestedNoneSet(values=('superscript', 'subscript', 'baseline'))
+    color = ColorDescriptor()
+    scheme = NestedNoneSet(values=("major", "minor"))
+
+    tagname = "font"
+
+    __elements__ = ('name', 'charset', 'family', 'b', 'i', 'strike', 'outline',
+                  'shadow', 'condense', 'color', 'extend', 'sz', 'u', 'vertAlign',
+                  'scheme')
+
+    __fields__ = __elements__
+
+
+    def __init__(self, name='Calibri', sz=11, b=False, i=False, charset=None,
+                 u=None, strike=False, color=BLACK, scheme=None, family=2, size=None,
+                 bold=None, italic=None, strikethrough=None, underline=None,
+                 vertAlign=None, outline=False, shadow=False, condense=False,
+                 extend=False):
+        self.name = name
+        self.family = family
+        if size is not None:
+            sz = size
+        self.sz = sz
+        if bold is not None:
+            b = bold
+        self.b = b
+        if italic is not None:
+            i = italic
+        self.i = i
+        if underline is not None:
+            u = underline
+        self.u = u
+        if strikethrough is not None:
+            strike = strikethrough
+        self.strike = strike
+        self.color = color
+        self.vertAlign = vertAlign
+        self.charset = charset
+        self.outline = outline
+        self.shadow = shadow
+        self.condense = condense
+        self.extend = extend
+        self.scheme = scheme
+
+
+from . colors import Color
+
+DEFAULT_FONT = Font(color=Color(theme=1), scheme="minor")

+ 86 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/hashable.py

@@ -0,0 +1,86 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+
+import inspect
+from openpyxl.compat import unicode, basestring, safe_string, zip
+from openpyxl.descriptors import Descriptor
+from openpyxl.descriptors.serialisable import Serialisable
+
+
+BASE_TYPES = (str, unicode, float, int)
+
+
+class HashableObject(Serialisable):
+    """Define how to hash property classes."""
+    __fields__ = ()
+    __base__ = False
+    _key = None
+
+    @property
+    def __defaults__(self):
+        spec = inspect.getargspec(self.__class__.__init__)
+        return dict(zip(spec.args[1:], spec.defaults))
+
+    def copy(self, **kwargs):
+        current = dict([(x, getattr(self, x)) for x in self.__fields__])
+        current.update(kwargs)
+        return self.__class__(**current)
+
+    def __print__(self, defaults=False):
+        if defaults:
+            print_func = str
+        else:
+            print_func = repr
+        pieces = []
+        default_values = self.__defaults__
+        for k in self.__fields__:
+            value = getattr(self, k)
+            if not defaults and value == default_values[k]:
+                continue
+            if isinstance(value, basestring):
+                print_func = repr  # keep quotes around strings
+            pieces.append('%s=%s' % (k, print_func(value)))
+        if pieces or self.__base__:
+            return '%s(%s)' % (self.__class__.__name__, ', '.join(pieces))
+        else:
+            return ''
+
+    def __repr__(self):
+        return self.__print__(defaults=False)
+
+    def __str__(self):
+        return self.__print__(defaults=True)
+
+    @property
+    def key(self):
+        """Use a tuple of fields as the basis for a key"""
+        if self._key is None:
+            self._key = hash(tuple(getattr(self, x) for x in self.__fields__))
+        return self._key
+
+    def __hash__(self):
+        return self.key
+
+    def __eq__(self, other):
+        if other.__class__ == self.__class__:
+            return self.key == other.key
+        return self.key == other
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __add__(self, other):
+        vals = {}
+        for attr in self.__fields__:
+            vals[attr] = getattr(self, attr) or getattr(other, attr)
+        return self.__class__(**vals)
+
+    def __sub__(self, other):
+        vals = {}
+        if (self is other) or (self == other):
+            return
+        for attr in self.__fields__:
+            if not getattr(other, attr) and getattr(self, attr):
+                vals[attr] = getattr(self, attr)
+        return self.__class__(**vals)

+ 94 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/named_styles.py

@@ -0,0 +1,94 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+
+from openpyxl.compat import safe_string
+
+from openpyxl.descriptors import (
+    Strict,
+    Typed,
+    Integer,
+    Bool,
+)
+from .fills import PatternFill, Fill
+from . fonts import Font, DEFAULT_FONT
+from . borders import Border
+from . alignment import Alignment
+from . numbers import NumberFormatDescriptor
+from . protection import Protection
+
+
+class NamedStyle(Strict):
+
+    """
+    Named and editable styles
+    """
+
+    font = Typed(expected_type=Font)
+    fill = Typed(expected_type=Fill)
+    border = Typed(expected_type=Border)
+    alignment = Typed(expected_type=Alignment)
+    number_format = NumberFormatDescriptor()
+    protection = Typed(expected_type=Protection)
+    builtinId = Integer(allow_none=True)
+    hidden = Bool(allow_none=True)
+
+    __fields__ = ("name", "font", "fill", "border", "number_format", "alignment", "protection")
+
+    def __init__(self,
+                 name="Normal",
+                 font=Font(),
+                 fill=PatternFill(),
+                 border=Border(),
+                 alignment=Alignment(),
+                 number_format=None,
+                 protection=Protection(),
+                 builtinId=0,
+                 hidden=False,
+                 ):
+        self.name = name
+        self.font = font
+        self.fill = fill
+        self.border = border
+        self.alignment = alignment
+        self.number_format = number_format
+        self.protection = protection
+        self.builtinId = builtinId
+        self.hidden = hidden
+
+
+    def _make_key(self):
+        """Use a tuple of fields as the basis for a key"""
+        self._key = hash(tuple(getattr(self, x) for x in self.__fields__))
+
+    def __hash__(self):
+        if not hasattr(self, '_key'):
+            self._make_key()
+        return self._key
+
+
+    def __eq__(self, other):
+        if isinstance(other, self.__class__):
+            if not hasattr(self, '_key'):
+                self._make_key()
+            if not hasattr(other, '_key'):
+                other._make_key()
+            return self._key == other._key
+
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __repr__(self):
+        pieces = []
+        for k in self.__fields__:
+            value = getattr(self, k)
+            pieces.append('%s=%s' % (k, repr(value)))
+        return '%s(%s)' % (self.__class__.__name__, ', '.join(pieces))
+
+
+    def __iter__(self):
+        for key in ('name', 'builtinId', 'hidden', 'xfId'):
+            value = getattr(self, key, None)
+            if value is not None:
+                yield key, safe_string(value)

+ 120 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/numbers.py

@@ -0,0 +1,120 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+import re
+
+from openpyxl.descriptors import String
+from .hashable import HashableObject
+
+BUILTIN_FORMATS = {
+    0: 'General',
+    1: '0',
+    2: '0.00',
+    3: '#,##0',
+    4: '#,##0.00',
+    5: '"$"#,##0_);("$"#,##0)',
+    6: '"$"#,##0_);[Red]("$"#,##0)',
+    7: '"$"#,##0.00_);("$"#,##0.00)',
+    8: '"$"#,##0.00_);[Red]("$"#,##0.00)',
+    9: '0%',
+    10: '0.00%',
+    11: '0.00E+00',
+    12: '# ?/?',
+    13: '# ??/??',
+    14: 'mm-dd-yy',
+    15: 'd-mmm-yy',
+    16: 'd-mmm',
+    17: 'mmm-yy',
+    18: 'h:mm AM/PM',
+    19: 'h:mm:ss AM/PM',
+    20: 'h:mm',
+    21: 'h:mm:ss',
+    22: 'm/d/yy h:mm',
+
+    37: '#,##0_);(#,##0)',
+    38: '#,##0_);[Red](#,##0)',
+    39: '#,##0.00_);(#,##0.00)',
+    40: '#,##0.00_);[Red](#,##0.00)',
+
+    41: '_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)',
+    42: '_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)',
+    43: '_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)',
+
+    44: '_("$"* #,##0.00_)_("$"* \(#,##0.00\)_("$"* "-"??_)_(@_)',
+    45: 'mm:ss',
+    46: '[h]:mm:ss',
+    47: 'mmss.0',
+    48: '##0.0E+0',
+    49: '@', }
+
+BUILTIN_FORMATS_REVERSE = dict(
+        [(value, key) for key, value in BUILTIN_FORMATS.items()])
+
+FORMAT_GENERAL = BUILTIN_FORMATS[0]
+FORMAT_TEXT = BUILTIN_FORMATS[49]
+FORMAT_NUMBER = BUILTIN_FORMATS[1]
+FORMAT_NUMBER_00 = BUILTIN_FORMATS[2]
+FORMAT_NUMBER_COMMA_SEPARATED1 = BUILTIN_FORMATS[4]
+FORMAT_NUMBER_COMMA_SEPARATED2 = '#,##0.00_-'
+FORMAT_PERCENTAGE = BUILTIN_FORMATS[9]
+FORMAT_PERCENTAGE_00 = BUILTIN_FORMATS[10]
+FORMAT_DATE_YYYYMMDD2 = 'yyyy-mm-dd'
+FORMAT_DATE_YYMMDD = 'yy-mm-dd'
+FORMAT_DATE_DDMMYY = 'dd/mm/yy'
+FORMAT_DATE_DMYSLASH = 'd/m/y'
+FORMAT_DATE_DMYMINUS = 'd-m-y'
+FORMAT_DATE_DMMINUS = 'd-m'
+FORMAT_DATE_MYMINUS = 'm-y'
+FORMAT_DATE_XLSX14 = BUILTIN_FORMATS[14]
+FORMAT_DATE_XLSX15 = BUILTIN_FORMATS[15]
+FORMAT_DATE_XLSX16 = BUILTIN_FORMATS[16]
+FORMAT_DATE_XLSX17 = BUILTIN_FORMATS[17]
+FORMAT_DATE_XLSX22 = BUILTIN_FORMATS[22]
+FORMAT_DATE_DATETIME = 'yyyy-mm-dd h:mm:ss'
+FORMAT_DATE_TIME1 = BUILTIN_FORMATS[18]
+FORMAT_DATE_TIME2 = BUILTIN_FORMATS[19]
+FORMAT_DATE_TIME3 = BUILTIN_FORMATS[20]
+FORMAT_DATE_TIME4 = BUILTIN_FORMATS[21]
+FORMAT_DATE_TIME5 = BUILTIN_FORMATS[45]
+FORMAT_DATE_TIME6 = BUILTIN_FORMATS[21]
+FORMAT_DATE_TIME7 = 'i:s.S'
+FORMAT_DATE_TIME8 = 'h:mm:ss@'
+FORMAT_DATE_TIMEDELTA = '[hh]:mm:ss'
+FORMAT_DATE_YYMMDDSLASH = 'yy/mm/dd@'
+FORMAT_CURRENCY_USD_SIMPLE = '"$"#,##0.00_-'
+FORMAT_CURRENCY_USD = '$#,##0_-'
+FORMAT_CURRENCY_EUR_SIMPLE = '[$EUR ]#,##0.00_-'
+
+
+DATE_INDICATORS = 'dmyhs'
+BAD_DATE_RE = re.compile(r'((?<=\[)|").*[dmhys]+.*(\]|")', re.UNICODE)
+
+def is_date_format(fmt):
+    if fmt is None:
+        return False
+    fmt = fmt.lower()
+    if any([x in fmt for x in DATE_INDICATORS]):
+        return not BAD_DATE_RE.search(fmt)
+    return False
+
+
+def is_builtin(fmt):
+    return fmt in BUILTIN_FORMATS.values()
+
+
+def builtin_format_code(index):
+    """Return one of the standard format codes by index."""
+    return BUILTIN_FORMATS[index]
+
+
+def builtin_format_id(fmt):
+    """Return the id of a standard style."""
+    return BUILTIN_FORMATS_REVERSE.get(fmt)
+
+
+class NumberFormatDescriptor(String):
+
+    def __set__(self, instance, value):
+        if value is None:
+            value = FORMAT_GENERAL
+        super(NumberFormatDescriptor, self).__set__(instance, value)

+ 21 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/protection.py

@@ -0,0 +1,21 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.descriptors import Bool
+
+from .hashable import HashableObject
+
+
+class Protection(HashableObject):
+    """Protection options for use in styles."""
+
+    tagname = "protection"
+
+    __fields__ = ('locked',
+                  'hidden')
+    locked = Bool()
+    hidden = Bool()
+
+    def __init__(self, locked=True, hidden=False):
+        self.locked = locked
+        self.hidden = hidden

+ 47 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/proxy.py

@@ -0,0 +1,47 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from openpyxl.utils.indexed_list import IndexedList
+
+from .numbers import BUILTIN_FORMATS, BUILTIN_FORMATS_REVERSE
+
+
+class StyleProxy(object):
+    """
+    Proxy formatting objects so that they cannot be altered
+    """
+
+    __slots__ = ('__target')
+
+    def __init__(self, target):
+        if not hasattr(target, 'copy'):
+            raise TypeError("Proxied objects must have a copy method.")
+        self.__target = target
+
+
+    def __repr__(self):
+        return repr(self.__target)
+
+
+    def __getattr__(self, attr):
+        return getattr(self.__target, attr)
+
+
+    def __setattr__(self, attr, value):
+        if attr != "_StyleProxy__target":
+            raise AttributeError("Style objects are immutable and cannot be changed."
+                                 "Reassign the style with a copy")
+        super(StyleProxy, self).__setattr__(attr, value)
+
+
+    def copy(self, **kw):
+        """Return a copy of the proxied object. Keyword args will be passed through"""
+        return self.__target.copy(**kw)
+
+
+    def __eq__(self, other):
+        return self.__target == other
+
+
+    def __ne__(self, other):
+        return not self == other

+ 208 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/styles/styleable.py

@@ -0,0 +1,208 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from array import array
+from warnings import warn
+
+from openpyxl.compat import safe_string
+from openpyxl.xml.functions import Element
+
+from openpyxl.utils.indexed_list import IndexedList
+from .numbers import BUILTIN_FORMATS, BUILTIN_FORMATS_REVERSE
+from .proxy import StyleProxy
+from . import Style
+
+
+class StyleDescriptor(object):
+
+    def __init__(self, collection, key):
+        self.collection = collection
+        self.key = key
+
+    def __set__(self, instance, value):
+        coll = getattr(instance.parent.parent, self.collection)
+        if not getattr(instance, "_style"):
+            instance._style = StyleArray()
+        setattr(instance._style, self.key, coll.add(value))
+
+
+    def __get__(self, instance, cls):
+        coll = getattr(instance.parent.parent, self.collection)
+        if not getattr(instance, "_style"):
+            instance._style = StyleArray()
+        idx =  getattr(instance._style, self.key)
+        return StyleProxy(coll[idx])
+
+
+class NumberFormatDescriptor(object):
+
+    key = "numFmtId"
+    collection = '_number_formats'
+
+    def __set__(self, instance, value):
+        coll = getattr(instance.parent.parent, self.collection)
+        if value in BUILTIN_FORMATS_REVERSE:
+            idx = BUILTIN_FORMATS_REVERSE[value]
+        else:
+            idx = coll.add(value) + 164
+        if not getattr(instance, "_style"):
+            instance._style = StyleArray()
+        setattr(instance._style, self.key, idx)
+
+
+    def __get__(self, instance, cls):
+        if not getattr(instance, "_style"):
+            instance._style = StyleArray()
+        idx = getattr(instance._style, self.key)
+        if idx < 164:
+            return BUILTIN_FORMATS.get(idx, "General")
+        coll = getattr(instance.parent.parent, self.collection)
+        return coll[idx - 164]
+
+
+class ArrayDescriptor(object):
+
+    def __init__(self, key):
+        self.key = key
+
+    def __get__(self, instance, cls):
+        return instance[self.key]
+
+    def __set__(self, instance, value):
+        instance[self.key] = value
+
+
+class StyleArray(array):
+    """
+    Simplified named tuple with an array
+    """
+
+    __slots__ = ()
+    tagname = 'xf'
+
+    fontId = ArrayDescriptor(0)
+    fillId = ArrayDescriptor(1)
+    borderId = ArrayDescriptor(2)
+    numFmtId = ArrayDescriptor(3)
+    protectionId = ArrayDescriptor(4)
+    alignmentId = ArrayDescriptor(5)
+    pivotButton = ArrayDescriptor(6)
+    quotePrefix = ArrayDescriptor(7)
+    xfId = ArrayDescriptor(8)
+
+    __attrs__ = ("fontId", "fillId", "borderId", "numFmtId", "protectionId",
+                 "alignmentId", "pivotButton", "quotePrefix", "xfId")
+
+    def __new__(cls, args=[0]*9):
+        return array.__new__(cls, 'i', args)
+
+
+    def __hash__(self):
+        return hash(tuple(self))
+
+
+    @classmethod
+    def from_tree(cls, node):
+        self = cls()
+        for k, v in node.attrib.items():
+            if k in cls.__attrs__:
+                setattr(self, k, int(v))
+        return self
+
+
+    @property
+    def applyAlignment(self):
+        return self.alignmentId != 0
+
+
+    @property
+    def applyProtection(self):
+        return self.protectionId != 0
+
+
+    def to_tree(self):
+        """
+        Alignment and protection objects are implemented as child elements.
+        This is a completely different API to other format objects. :-/
+        """
+        attrs = {}
+        for key in self.__attrs__ + ('applyProtection', 'applyAlignment'):
+            value = getattr(self, key)
+            if key in ('alignmentId', 'protectionId'):
+                continue
+            elif key in ('quotePrefix', 'pivotButton', 'applyProtection', 'applyAlignment') and not value:
+                continue
+            attrs[key] = value
+        attrs = dict((k, safe_string(v)) for k,v in attrs.items())
+        return Element(self.tagname, attrs)
+
+
+class StyleableObject(object):
+    """
+    Base class for styleble objects implementing proxy and lookup functions
+    """
+
+    font = StyleDescriptor('_fonts', "fontId")
+    fill = StyleDescriptor('_fills', "fillId")
+    border = StyleDescriptor('_borders', "borderId")
+    number_format = NumberFormatDescriptor()
+    protection = StyleDescriptor('_protections', "protectionId")
+    alignment = StyleDescriptor('_alignments', "alignmentId")
+
+    __slots__ = ('parent', '_style')
+
+    def __init__(self, sheet, style_array=None):
+        self.parent = sheet
+        if style_array is not None:
+            style_array = StyleArray(style_array)
+        self._style = style_array
+
+
+    @property
+    def style_id(self):
+        if self._style is None:
+            self._style = StyleArray()
+        return self.parent.parent._cell_styles.add(self._style)
+
+    @property
+    def has_style(self):
+        if self._style is None:
+            return False
+        return any(self._style)
+
+    #legacy
+    @property
+    def style(self):
+        warn("Use formatting objects such as font directly")
+        return Style(
+            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()
+        )
+
+    #legacy
+    @style.setter
+    def style(self, value):
+        warn("Use formatting objects such as font directly")
+        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
+
+    @property
+    def pivotButton(self):
+        if self._style is None:
+            return False
+        return bool(self._style[6])
+
+
+    @property
+    def quotePrefix(self):
+        if self._style is None:
+            return False
+        return bool(self._style[7])

+ 183 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/utils/__init__.py

@@ -0,0 +1,183 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+"""
+Collection of utilities used within the package and also available for client code
+"""
+
+import datetime
+import re
+
+from .formulas import FORMULAE
+from openpyxl.compat import basestring
+from openpyxl.utils.exceptions import CellCoordinatesException
+
+# constants
+COORD_RE = re.compile('^[$]?([A-Z]+)[$]?(\d+)$')
+RANGE_EXPR = """
+[$]?(?P<min_col>[A-Z]+)
+[$]?(?P<min_row>\d+)
+(:[$]?(?P<max_col>[A-Z]+)
+[$]?(?P<max_row>\d+))?
+"""
+ABSOLUTE_RE = re.compile('^' + RANGE_EXPR +'$', re.VERBOSE)
+SHEETRANGE_RE = re.compile("""
+^(('(?P<quoted>([^']|'')*)')|(?P<notquoted>[^']*))!
+(?P<cells>{0})$""".format(RANGE_EXPR), re.VERBOSE)
+
+
+def get_column_interval(start, end):
+    if isinstance(start, basestring):
+        start = column_index_from_string(start)
+    if isinstance(end, basestring):
+        end = column_index_from_string(end)
+    return [get_column_letter(x) for x in range(start, end + 1)]
+
+
+def coordinate_from_string(coord_string):
+    """Convert a coordinate string like 'B12' to a tuple ('B', 12)"""
+    match = COORD_RE.match(coord_string.upper())
+    if not match:
+        msg = 'Invalid cell coordinates (%s)' % coord_string
+        raise CellCoordinatesException(msg)
+    column, row = match.groups()
+    row = int(row)
+    if not row:
+        msg = "There is no row 0 (%s)" % coord_string
+        raise CellCoordinatesException(msg)
+    return (column, row)
+
+
+def absolute_coordinate(coord_string):
+    """Convert a coordinate to an absolute coordinate string (B12 -> $B$12)"""
+    m = ABSOLUTE_RE.match(coord_string.upper())
+    if m:
+        parts = m.groups()
+        if all(parts[-2:]):
+            return '$%s$%s:$%s$%s' % (parts[0], parts[1], parts[3], parts[4])
+        else:
+            return '$%s$%s' % (parts[0], parts[1])
+    else:
+        return coord_string
+
+def _get_column_letter(col_idx):
+    """Convert a column number into a column letter (3 -> 'C')
+
+    Right shift the column col_idx by 26 to find column letters in reverse
+    order.  These numbers are 1-based, and can be converted to ASCII
+    ordinals by adding 64.
+
+    """
+    # these indicies corrospond to A -> ZZZ and include all allowed
+    # columns
+    if not 1 <= col_idx <= 18278:
+        raise ValueError("Invalid column index {0}".format(col_idx))
+    letters = []
+    while col_idx > 0:
+        col_idx, remainder = divmod(col_idx, 26)
+        # check for exact division and borrow if needed
+        if remainder == 0:
+            remainder = 26
+            col_idx -= 1
+        letters.append(chr(remainder+64))
+    return ''.join(reversed(letters))
+
+
+_COL_STRING_CACHE = {}
+_STRING_COL_CACHE = {}
+for i in range(1, 18279):
+    col = _get_column_letter(i)
+    _STRING_COL_CACHE[i] = col
+    _COL_STRING_CACHE[col] = i
+
+
+def get_column_letter(idx,):
+    """Convert a column index into a column letter
+    (3 -> 'C')
+    """
+    try:
+        return _STRING_COL_CACHE[idx]
+    except KeyError:
+        raise ValueError("Invalid column index {0}".format(idx))
+
+
+def column_index_from_string(str_col):
+    """Convert a column name into a numerical index
+    ('A' -> 1)
+    """
+    # we use a function argument to get indexed name lookup
+    try:
+        return _COL_STRING_CACHE[str_col.upper()]
+    except KeyError:
+        raise ValueError("{0} is not a valid column name".format(str_col))
+
+
+def range_boundaries(range_string):
+    """
+    Convert a range string into a tuple of boundaries:
+    (min_col, min_row, max_col, max_row)
+    Cell coordinates will be converted into a range with the cell at both end
+    """
+    m = ABSOLUTE_RE.match(range_string)
+    min_col, min_row, sep, max_col, max_row = m.groups()
+    min_col = column_index_from_string(min_col)
+    min_row = int(min_row)
+
+    if max_col is None or max_row is None:
+        max_col = min_col
+        max_row = min_row
+    else:
+        max_col = column_index_from_string(max_col)
+        max_row = int(max_row)
+
+    return min_col, min_row, max_col, max_row
+
+
+def rows_from_range(range_string):
+    """
+    Get individual addresses for every cell in a range.
+    Yields one row at a time.
+    """
+    min_col, min_row, max_col, max_row = range_boundaries(range_string)
+    for row in range(min_row, max_row+1):
+        yield tuple('%s%d' % (get_column_letter(col), row)
+                    for col in range(min_col, max_col+1))
+
+
+def cols_from_range(range_string):
+    """
+    Get individual addresses for every cell in a range.
+    Yields one row at a time.
+    """
+    min_col, min_row, max_col, max_row = range_boundaries(range_string)
+    for col in range(min_col, max_col+1):
+        yield tuple('%s%d' % (get_column_letter(col), row)
+                    for row in range(min_row, max_row+1))
+
+
+def coordinate_to_tuple(coordinate):
+    """
+    Convert an Excel style coordinate to (row, colum) tuple
+    """
+    col, row = coordinate_from_string(coordinate)
+    return row, _COL_STRING_CACHE[col]
+
+
+def range_to_tuple(range_string):
+    """
+    Convert a worksheet range to the sheetname and maximum and minimum
+    coordinate indices
+    """
+    m = SHEETRANGE_RE.match(range_string)
+    if m is None:
+        raise ValueError("Value must be of the form sheetname!A1:E4")
+    sheetname = m.group("quoted") or m.group("notquoted")
+    cells = m.group("cells")
+    boundaries = range_boundaries(cells)
+    return sheetname, boundaries
+
+
+def quote_sheetname(sheetname):
+    if " " in sheetname:
+        sheetname = "'{0}'".format(sheetname)
+    return sheetname

+ 27 - 0
desktop/core/ext-py/openpyxl-2.3.0-b2/openpyxl/utils/bound_dictionary.py

@@ -0,0 +1,27 @@
+from __future__ import absolute_import
+# Copyright (c) 2010-2015 openpyxl
+
+from collections import defaultdict
+
+
+class BoundDictionary(defaultdict):
+    """
+    A default dictionary where elements are tightly coupled.
+
+    The factory method is responsible for binding the parent object to the child.
+
+    If a reference attribute is assigned then child objects will have the key assigned to this.
+
+    Otherwise it's just a defaultdict.
+    """
+
+    def __init__(self, reference=None, *args, **kw):
+        self.reference = reference
+        super(BoundDictionary, self).__init__(*args, **kw)
+
+
+    def __getitem__(self, key):
+        value = super(BoundDictionary, self).__getitem__(key)
+        if self.reference is not None:
+            setattr(value, self.reference, key)
+        return value

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно