├── .gitignore ├── LICENSE ├── README.md ├── public ├── alfred_buffer.webp ├── logo-dark.webp ├── logo-light.webp ├── normal_search.webp ├── rename_params.webp ├── rename_xlsx_selection.webp └── universal_action.webp ├── src ├── .vscode │ └── settings.json ├── getfilenames_run.py ├── icon.png ├── icons │ ├── info.webp │ ├── ok.webp │ ├── return.webp │ ├── shield.webp │ ├── time.webp │ └── xlsx.webp ├── info.plist ├── lib │ ├── et_xmlfile-1.1.0.dist-info │ │ ├── AUTHORS.txt │ │ ├── INSTALLER │ │ ├── LICENCE.rst │ │ ├── METADATA │ │ ├── RECORD │ │ ├── WHEEL │ │ └── top_level.txt │ ├── et_xmlfile-2.0.0.dist-info │ │ ├── AUTHORS.txt │ │ ├── INSTALLER │ │ ├── LICENCE.python │ │ ├── LICENCE.rst │ │ ├── METADATA │ │ ├── RECORD │ │ ├── WHEEL │ │ └── top_level.txt │ ├── et_xmlfile │ │ ├── __init__.py │ │ ├── incremental_tree.py │ │ └── xmlfile.py │ ├── openpyxl-3.1.2.dist-info │ │ ├── INSTALLER │ │ ├── LICENCE.rst │ │ ├── METADATA │ │ ├── RECORD │ │ ├── REQUESTED │ │ ├── WHEEL │ │ └── top_level.txt │ ├── openpyxl-3.1.5.dist-info │ │ ├── INSTALLER │ │ ├── LICENCE.rst │ │ ├── METADATA │ │ ├── RECORD │ │ ├── REQUESTED │ │ ├── WHEEL │ │ └── top_level.txt │ └── openpyxl │ │ ├── __init__.py │ │ ├── _constants.py │ │ ├── cell │ │ ├── __init__.py │ │ ├── _writer.py │ │ ├── cell.py │ │ ├── read_only.py │ │ ├── rich_text.py │ │ └── text.py │ │ ├── chart │ │ ├── _3d.py │ │ ├── __init__.py │ │ ├── _chart.py │ │ ├── area_chart.py │ │ ├── axis.py │ │ ├── bar_chart.py │ │ ├── bubble_chart.py │ │ ├── chartspace.py │ │ ├── data_source.py │ │ ├── descriptors.py │ │ ├── error_bar.py │ │ ├── label.py │ │ ├── layout.py │ │ ├── legend.py │ │ ├── line_chart.py │ │ ├── marker.py │ │ ├── picture.py │ │ ├── pie_chart.py │ │ ├── pivot.py │ │ ├── plotarea.py │ │ ├── print_settings.py │ │ ├── radar_chart.py │ │ ├── reader.py │ │ ├── reference.py │ │ ├── scatter_chart.py │ │ ├── series.py │ │ ├── series_factory.py │ │ ├── shapes.py │ │ ├── stock_chart.py │ │ ├── surface_chart.py │ │ ├── text.py │ │ ├── title.py │ │ ├── trendline.py │ │ └── updown_bars.py │ │ ├── chartsheet │ │ ├── __init__.py │ │ ├── chartsheet.py │ │ ├── custom.py │ │ ├── properties.py │ │ ├── protection.py │ │ ├── publish.py │ │ ├── relation.py │ │ └── views.py │ │ ├── comments │ │ ├── __init__.py │ │ ├── author.py │ │ ├── comment_sheet.py │ │ ├── comments.py │ │ └── shape_writer.py │ │ ├── compat │ │ ├── __init__.py │ │ ├── abc.py │ │ ├── numbers.py │ │ ├── product.py │ │ ├── singleton.py │ │ └── strings.py │ │ ├── descriptors │ │ ├── __init__.py │ │ ├── base.py │ │ ├── container.py │ │ ├── excel.py │ │ ├── namespace.py │ │ ├── nested.py │ │ ├── sequence.py │ │ ├── serialisable.py │ │ └── slots.py │ │ ├── drawing │ │ ├── __init__.py │ │ ├── colors.py │ │ ├── connector.py │ │ ├── drawing.py │ │ ├── effect.py │ │ ├── fill.py │ │ ├── geometry.py │ │ ├── graphic.py │ │ ├── image.py │ │ ├── line.py │ │ ├── picture.py │ │ ├── properties.py │ │ ├── relation.py │ │ ├── spreadsheet_drawing.py │ │ ├── text.py │ │ └── xdr.py │ │ ├── formatting │ │ ├── __init__.py │ │ ├── formatting.py │ │ └── rule.py │ │ ├── formula │ │ ├── __init__.py │ │ ├── tokenizer.py │ │ └── translate.py │ │ ├── packaging │ │ ├── __init__.py │ │ ├── core.py │ │ ├── custom.py │ │ ├── extended.py │ │ ├── interface.py │ │ ├── manifest.py │ │ ├── relationship.py │ │ └── workbook.py │ │ ├── pivot │ │ ├── __init__.py │ │ ├── cache.py │ │ ├── fields.py │ │ ├── record.py │ │ └── table.py │ │ ├── reader │ │ ├── __init__.py │ │ ├── drawings.py │ │ ├── excel.py │ │ ├── strings.py │ │ └── workbook.py │ │ ├── styles │ │ ├── __init__.py │ │ ├── alignment.py │ │ ├── borders.py │ │ ├── builtins.py │ │ ├── cell_style.py │ │ ├── colors.py │ │ ├── differential.py │ │ ├── fills.py │ │ ├── fonts.py │ │ ├── named_styles.py │ │ ├── numbers.py │ │ ├── protection.py │ │ ├── proxy.py │ │ ├── styleable.py │ │ ├── stylesheet.py │ │ └── table.py │ │ ├── utils │ │ ├── __init__.py │ │ ├── bound_dictionary.py │ │ ├── cell.py │ │ ├── dataframe.py │ │ ├── datetime.py │ │ ├── escape.py │ │ ├── exceptions.py │ │ ├── formulas.py │ │ ├── indexed_list.py │ │ ├── inference.py │ │ ├── protection.py │ │ └── units.py │ │ ├── workbook │ │ ├── __init__.py │ │ ├── _writer.py │ │ ├── child.py │ │ ├── defined_name.py │ │ ├── external_link │ │ │ ├── __init__.py │ │ │ └── external.py │ │ ├── external_reference.py │ │ ├── function_group.py │ │ ├── properties.py │ │ ├── protection.py │ │ ├── smart_tags.py │ │ ├── views.py │ │ ├── web.py │ │ └── workbook.py │ │ ├── worksheet │ │ ├── __init__.py │ │ ├── _read_only.py │ │ ├── _reader.py │ │ ├── _write_only.py │ │ ├── _writer.py │ │ ├── cell_range.py │ │ ├── cell_watch.py │ │ ├── controls.py │ │ ├── copier.py │ │ ├── custom.py │ │ ├── datavalidation.py │ │ ├── dimensions.py │ │ ├── drawing.py │ │ ├── errors.py │ │ ├── filters.py │ │ ├── formula.py │ │ ├── header_footer.py │ │ ├── hyperlink.py │ │ ├── merge.py │ │ ├── ole.py │ │ ├── page.py │ │ ├── pagebreak.py │ │ ├── picture.py │ │ ├── print_settings.py │ │ ├── properties.py │ │ ├── protection.py │ │ ├── related.py │ │ ├── scenario.py │ │ ├── smart_tag.py │ │ ├── table.py │ │ ├── views.py │ │ └── worksheet.py │ │ ├── writer │ │ ├── __init__.py │ │ ├── excel.py │ │ └── theme.py │ │ └── xml │ │ ├── __init__.py │ │ ├── constants.py │ │ └── functions.py ├── model.xlsx ├── notificator ├── renamefiles_entry.py ├── renamefiles_run.py └── utils.py └── update.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | **/.DS_Store 3 | **/__pycache__ 4 | src/prefs.plist -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-present Benjamin Oddou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /public/alfred_buffer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/public/alfred_buffer.webp -------------------------------------------------------------------------------- /public/logo-dark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/public/logo-dark.webp -------------------------------------------------------------------------------- /public/logo-light.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/public/logo-light.webp -------------------------------------------------------------------------------- /public/normal_search.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/public/normal_search.webp -------------------------------------------------------------------------------- /public/rename_params.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/public/rename_params.webp -------------------------------------------------------------------------------- /public/rename_xlsx_selection.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/public/rename_xlsx_selection.webp -------------------------------------------------------------------------------- /public/universal_action.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/public/universal_action.webp -------------------------------------------------------------------------------- /src/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.analysis.extraPaths": [ 3 | "./lib" 4 | ], 5 | "editor.formatOnSave": true 6 | } -------------------------------------------------------------------------------- /src/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/src/icon.png -------------------------------------------------------------------------------- /src/icons/info.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/src/icons/info.webp -------------------------------------------------------------------------------- /src/icons/ok.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/src/icons/ok.webp -------------------------------------------------------------------------------- /src/icons/return.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/src/icons/return.webp -------------------------------------------------------------------------------- /src/icons/shield.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/src/icons/shield.webp -------------------------------------------------------------------------------- /src/icons/time.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/src/icons/time.webp -------------------------------------------------------------------------------- /src/icons/xlsx.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/src/icons/xlsx.webp -------------------------------------------------------------------------------- /src/lib/et_xmlfile-1.1.0.dist-info/AUTHORS.txt: -------------------------------------------------------------------------------- 1 | The authors in alphabetical order 2 | 3 | * Charlie Clark 4 | * Elias Rabel -------------------------------------------------------------------------------- /src/lib/et_xmlfile-1.1.0.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-1.1.0.dist-info/LICENCE.rst: -------------------------------------------------------------------------------- 1 | This software is under the MIT Licence 2 | ====================================== 3 | 4 | Copyright (c) 2010 openpyxl 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | Odict implementation in openpyxl/writer/odict.py uses the following licence: 26 | 27 | Copyright (c) 2001-2011 Python Software Foundation 28 | 2011 Raymond Hettinger 29 | License: PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 30 | See http://www.opensource.org/licenses/Python-2.0 for full terms 31 | Note: backport changes by Raymond were originally distributed under MIT 32 | license, but since the original license for Python is more 33 | restrictive than MIT, code cannot be released under its terms and 34 | still adheres to the limitations of Python license. 35 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-1.1.0.dist-info/METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: et-xmlfile 3 | Version: 1.1.0 4 | Summary: An implementation of lxml.xmlfile for the standard library 5 | Home-page: https://foss.heptapod.net/openpyxl/et_xmlfile 6 | Author: See ATUHORS.txt 7 | Author-email: charlie.clark@clark-consulting.eu 8 | License: MIT 9 | Platform: UNKNOWN 10 | Classifier: Development Status :: 5 - Production/Stable 11 | Classifier: Operating System :: MacOS :: MacOS X 12 | Classifier: Operating System :: Microsoft :: Windows 13 | Classifier: Operating System :: POSIX 14 | Classifier: License :: OSI Approved :: MIT License 15 | Classifier: Programming Language :: Python 16 | Classifier: Programming Language :: Python :: 3.6 17 | Classifier: Programming Language :: Python :: 3.7 18 | Classifier: Programming Language :: Python :: 3.8 19 | Classifier: Programming Language :: Python :: 3.9 20 | Requires-Python: >=3.6 21 | 22 | et_xmfile 23 | ========= 24 | 25 | et_xmlfile is a low memory library for creating large XML files. 26 | 27 | It is based upon the `xmlfile module from lxml `_ with the aim of allowing code to be developed that will work with both libraries. It was developed initially for the openpyxl project but is now a standalone module. 28 | 29 | The code was written by Elias Rabel as part of the `Python Düsseldorf `_ openpyxl sprint in September 2014. 30 | 31 | 32 | Note on performance 33 | ------------------- 34 | 35 | The code was not developed with performance in mind but turned out to be faster than the existing SAX-based implementation but is significantly slower than lxml's xmlfile. There is one area where an optimisation for lxml will negatively affect the performance of et_xmfile and that is when using the `.element()` method on an xmlfile context manager. It is, therefore, recommended not to use this, though the method is provided for code compatibility. 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-1.1.0.dist-info/RECORD: -------------------------------------------------------------------------------- 1 | et_xmlfile-1.1.0.dist-info/AUTHORS.txt,sha256=Y6mQLe0ywXMVP7WVFrZgEW3CqhIv-plM1CaOtdtBuXs,64 2 | et_xmlfile-1.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 3 | et_xmlfile-1.1.0.dist-info/LICENCE.rst,sha256=r-YrNgzcqB-43m7kt2ENodhsORd3qAx6y20RRVxTxCk,1694 4 | et_xmlfile-1.1.0.dist-info/METADATA,sha256=B5hV5UW4GqmWGgwAW44C2ofZZEmV0MRnTEU98kzcUGw,1775 5 | et_xmlfile-1.1.0.dist-info/RECORD,, 6 | et_xmlfile-1.1.0.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 7 | et_xmlfile-1.1.0.dist-info/top_level.txt,sha256=34-74d5NNARgTsPxCMta5o28XpBNmSN0iCZhtmx2Fk8,11 8 | et_xmlfile/__init__.py,sha256=-oTKwE6upIG2gOmnOc4KLgV-pKbBwy-zhQfizbmCruQ,269 9 | et_xmlfile/__pycache__/__init__.cpython-311.pyc,, 10 | et_xmlfile/__pycache__/xmlfile.cpython-311.pyc,, 11 | et_xmlfile/xmlfile.py,sha256=_h20RRb3ptDZ6xXoxMU_Wrx8rG6UZsg0TS7HEOrotzg,3204 12 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-1.1.0.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: bdist_wheel (0.36.2) 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | 6 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-1.1.0.dist-info/top_level.txt: -------------------------------------------------------------------------------- 1 | et_xmlfile 2 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-2.0.0.dist-info/AUTHORS.txt: -------------------------------------------------------------------------------- 1 | The authors in alphabetical order 2 | 3 | * Charlie Clark 4 | * Daniel Hillier 5 | * Elias Rabel 6 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-2.0.0.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-2.0.0.dist-info/LICENCE.rst: -------------------------------------------------------------------------------- 1 | This software is under the MIT Licence 2 | ====================================== 3 | 4 | Copyright (c) 2010 openpyxl 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-2.0.0.dist-info/METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: et_xmlfile 3 | Version: 2.0.0 4 | Summary: An implementation of lxml.xmlfile for the standard library 5 | Home-page: https://foss.heptapod.net/openpyxl/et_xmlfile 6 | Author: See AUTHORS.txt 7 | Author-email: charlie.clark@clark-consulting.eu 8 | License: MIT 9 | Project-URL: Documentation, https://openpyxl.pages.heptapod.net/et_xmlfile/ 10 | Project-URL: Source, https://foss.heptapod.net/openpyxl/et_xmlfile 11 | Project-URL: Tracker, https://foss.heptapod.net/openpyxl/et_xmfile/-/issues 12 | Classifier: Development Status :: 5 - Production/Stable 13 | Classifier: Operating System :: MacOS :: MacOS X 14 | Classifier: Operating System :: Microsoft :: Windows 15 | Classifier: Operating System :: POSIX 16 | Classifier: License :: OSI Approved :: MIT License 17 | Classifier: Programming Language :: Python 18 | Classifier: Programming Language :: Python :: 3.8 19 | Classifier: Programming Language :: Python :: 3.9 20 | Classifier: Programming Language :: Python :: 3.10 21 | Classifier: Programming Language :: Python :: 3.11 22 | Classifier: Programming Language :: Python :: 3.12 23 | Classifier: Programming Language :: Python :: 3.13 24 | Requires-Python: >=3.8 25 | License-File: LICENCE.python 26 | License-File: LICENCE.rst 27 | License-File: AUTHORS.txt 28 | 29 | .. image:: https://foss.heptapod.net/openpyxl/et_xmlfile/badges/branch/default/coverage.svg 30 | :target: https://coveralls.io/bitbucket/openpyxl/et_xmlfile?branch=default 31 | :alt: coverage status 32 | 33 | et_xmfile 34 | ========= 35 | 36 | XML can use lots of memory, and et_xmlfile is a low memory library for creating large XML files 37 | And, although the standard library already includes an incremental parser, `iterparse` it has no equivalent when writing XML. Once an element has been added to the tree, it is written to 38 | the file or stream and the memory is then cleared. 39 | 40 | This module is based upon the `xmlfile module from lxml `_ with the aim of allowing code to be developed that will work with both libraries. 41 | It was developed initially for the openpyxl project, but is now a standalone module. 42 | 43 | The code was written by Elias Rabel as part of the `Python Düsseldorf `_ openpyxl sprint in September 2014. 44 | 45 | Proper support for incremental writing was provided by Daniel Hillier in 2024 46 | 47 | Note on performance 48 | ------------------- 49 | 50 | The code was not developed with performance in mind, but turned out to be faster than the existing SAX-based implementation but is generally slower than lxml's xmlfile. 51 | There is one area where an optimisation for lxml may negatively affect the performance of et_xmfile and that is when using the `.element()` method on the xmlfile context manager. It is, therefore, recommended simply to create Elements write these directly, as in the sample code. 52 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-2.0.0.dist-info/RECORD: -------------------------------------------------------------------------------- 1 | et_xmlfile-2.0.0.dist-info/AUTHORS.txt,sha256=fwOAKepUY2Bd0ieNMACZo4G86ekN2oPMqyBCNGtsgQc,82 2 | et_xmlfile-2.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 3 | et_xmlfile-2.0.0.dist-info/LICENCE.python,sha256=TM2q68D0S4NyDsA5m7erMprc4GfdYvc8VTWi3AViirI,14688 4 | et_xmlfile-2.0.0.dist-info/LICENCE.rst,sha256=DIS7QvXTZ-Xr-fwt3jWxYUHfXuD9wYklCFi8bFVg9p4,1131 5 | et_xmlfile-2.0.0.dist-info/METADATA,sha256=DpfX6pCe0PvgPYi8i29YZ3zuGwe9M1PONhzSQFkVIE4,2711 6 | et_xmlfile-2.0.0.dist-info/RECORD,, 7 | et_xmlfile-2.0.0.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91 8 | et_xmlfile-2.0.0.dist-info/top_level.txt,sha256=34-74d5NNARgTsPxCMta5o28XpBNmSN0iCZhtmx2Fk8,11 9 | et_xmlfile/__init__.py,sha256=AQ4_2cNUEyUHlHo-Y3Gd6-8S_6eyKd55jYO4eh23UHw,228 10 | et_xmlfile/__pycache__/__init__.cpython-313.pyc,, 11 | et_xmlfile/__pycache__/incremental_tree.cpython-313.pyc,, 12 | et_xmlfile/__pycache__/xmlfile.cpython-313.pyc,, 13 | et_xmlfile/incremental_tree.py,sha256=lX4VStfzUNK0jtrVsvshPENu7E_zQirglkyRtzGDwEg,34534 14 | et_xmlfile/xmlfile.py,sha256=6QdxBq2P0Cf35R-oyXjLl5wOItfJJ4Yy6AlIF9RX7Bg,4886 15 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-2.0.0.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: setuptools (72.2.0) 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | 6 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile-2.0.0.dist-info/top_level.txt: -------------------------------------------------------------------------------- 1 | et_xmlfile 2 | -------------------------------------------------------------------------------- /src/lib/et_xmlfile/__init__.py: -------------------------------------------------------------------------------- 1 | from .xmlfile import xmlfile 2 | 3 | # constants 4 | __version__ = '2.0.0' 5 | __author__ = 'See AUTHORS.txt' 6 | __license__ = 'MIT' 7 | __author_email__ = 'charlie.clark@clark-consulting.eu' 8 | __url__ = 'https://foss.heptapod.net/openpyxl/et_xmlfile' 9 | -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.2.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.2.dist-info/LICENCE.rst: -------------------------------------------------------------------------------- 1 | This software is under the MIT Licence 2 | ====================================== 3 | 4 | Copyright (c) 2010 openpyxl 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.2.dist-info/METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: openpyxl 3 | Version: 3.1.2 4 | Summary: A Python library to read/write Excel 2010 xlsx/xlsm files 5 | Home-page: https://openpyxl.readthedocs.io 6 | Author: See AUTHORS 7 | Author-email: charlie.clark@clark-consulting.eu 8 | License: MIT 9 | Project-URL: Documentation, https://openpyxl.readthedocs.io/en/stable/ 10 | Project-URL: Source, https://foss.heptapod.net/openpyxl/openpyxl 11 | Project-URL: Tracker, https://foss.heptapod.net/openpyxl/openpyxl/-/issues 12 | Classifier: Development Status :: 5 - Production/Stable 13 | Classifier: Operating System :: MacOS :: MacOS X 14 | Classifier: Operating System :: Microsoft :: Windows 15 | Classifier: Operating System :: POSIX 16 | Classifier: License :: OSI Approved :: MIT License 17 | Classifier: Programming Language :: Python 18 | Classifier: Programming Language :: Python :: 3.6 19 | Classifier: Programming Language :: Python :: 3.7 20 | Classifier: Programming Language :: Python :: 3.8 21 | Classifier: Programming Language :: Python :: 3.9 22 | Classifier: Programming Language :: Python :: 3.10 23 | Classifier: Programming Language :: Python :: 3.11 24 | Requires-Python: >=3.6 25 | License-File: LICENCE.rst 26 | Requires-Dist: et-xmlfile 27 | 28 | .. image:: https://coveralls.io/repos/bitbucket/openpyxl/openpyxl/badge.svg?branch=default 29 | :target: https://coveralls.io/bitbucket/openpyxl/openpyxl?branch=default 30 | :alt: coverage status 31 | 32 | Introduction 33 | ------------ 34 | 35 | openpyxl is a Python library to read/write Excel 2010 xlsx/xlsm/xltx/xltm files. 36 | 37 | It was born from lack of existing library to read/write natively from Python 38 | the Office Open XML format. 39 | 40 | All kudos to the PHPExcel team as openpyxl was initially based on PHPExcel. 41 | 42 | 43 | Security 44 | -------- 45 | 46 | By default openpyxl does not guard against quadratic blowup or billion laughs 47 | xml attacks. To guard against these attacks install defusedxml. 48 | 49 | Mailing List 50 | ------------ 51 | 52 | The user list can be found on http://groups.google.com/group/openpyxl-users 53 | 54 | 55 | Sample code:: 56 | 57 | from openpyxl import Workbook 58 | wb = Workbook() 59 | 60 | # grab the active worksheet 61 | ws = wb.active 62 | 63 | # Data can be assigned directly to cells 64 | ws['A1'] = 42 65 | 66 | # Rows can also be appended 67 | ws.append([1, 2, 3]) 68 | 69 | # Python types will automatically be converted 70 | import datetime 71 | ws['A2'] = datetime.datetime.now() 72 | 73 | # Save the file 74 | wb.save("sample.xlsx") 75 | 76 | 77 | Documentation 78 | ------------- 79 | 80 | The documentation is at: https://openpyxl.readthedocs.io 81 | 82 | * installation methods 83 | * code examples 84 | * instructions for contributing 85 | 86 | Release notes: https://openpyxl.readthedocs.io/en/stable/changes.html 87 | -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.2.dist-info/REQUESTED: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/src/lib/openpyxl-3.1.2.dist-info/REQUESTED -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.2.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: bdist_wheel (0.37.0) 3 | Root-Is-Purelib: true 4 | Tag: py2-none-any 5 | Tag: py3-none-any 6 | 7 | -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.2.dist-info/top_level.txt: -------------------------------------------------------------------------------- 1 | openpyxl 2 | -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.5.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.5.dist-info/LICENCE.rst: -------------------------------------------------------------------------------- 1 | This software is under the MIT Licence 2 | ====================================== 3 | 4 | Copyright (c) 2010 openpyxl 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.5.dist-info/METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: openpyxl 3 | Version: 3.1.5 4 | Summary: A Python library to read/write Excel 2010 xlsx/xlsm files 5 | Home-page: https://openpyxl.readthedocs.io 6 | Author: See AUTHORS 7 | Author-email: charlie.clark@clark-consulting.eu 8 | License: MIT 9 | Project-URL: Documentation, https://openpyxl.readthedocs.io/en/stable/ 10 | Project-URL: Source, https://foss.heptapod.net/openpyxl/openpyxl 11 | Project-URL: Tracker, https://foss.heptapod.net/openpyxl/openpyxl/-/issues 12 | Classifier: Development Status :: 5 - Production/Stable 13 | Classifier: Operating System :: MacOS :: MacOS X 14 | Classifier: Operating System :: Microsoft :: Windows 15 | Classifier: Operating System :: POSIX 16 | Classifier: License :: OSI Approved :: MIT License 17 | Classifier: Programming Language :: Python 18 | Classifier: Programming Language :: Python :: 3.6 19 | Classifier: Programming Language :: Python :: 3.7 20 | Classifier: Programming Language :: Python :: 3.8 21 | Classifier: Programming Language :: Python :: 3.9 22 | Classifier: Programming Language :: Python :: 3.10 23 | Classifier: Programming Language :: Python :: 3.11 24 | Requires-Python: >=3.8 25 | License-File: LICENCE.rst 26 | Requires-Dist: et-xmlfile 27 | 28 | .. image:: https://coveralls.io/repos/bitbucket/openpyxl/openpyxl/badge.svg?branch=default 29 | :target: https://coveralls.io/bitbucket/openpyxl/openpyxl?branch=default 30 | :alt: coverage status 31 | 32 | Introduction 33 | ------------ 34 | 35 | openpyxl is a Python library to read/write Excel 2010 xlsx/xlsm/xltx/xltm files. 36 | 37 | It was born from lack of existing library to read/write natively from Python 38 | the Office Open XML format. 39 | 40 | All kudos to the PHPExcel team as openpyxl was initially based on PHPExcel. 41 | 42 | 43 | Security 44 | -------- 45 | 46 | By default openpyxl does not guard against quadratic blowup or billion laughs 47 | xml attacks. To guard against these attacks install defusedxml. 48 | 49 | Mailing List 50 | ------------ 51 | 52 | The user list can be found on http://groups.google.com/group/openpyxl-users 53 | 54 | 55 | Sample code:: 56 | 57 | from openpyxl import Workbook 58 | wb = Workbook() 59 | 60 | # grab the active worksheet 61 | ws = wb.active 62 | 63 | # Data can be assigned directly to cells 64 | ws['A1'] = 42 65 | 66 | # Rows can also be appended 67 | ws.append([1, 2, 3]) 68 | 69 | # Python types will automatically be converted 70 | import datetime 71 | ws['A2'] = datetime.datetime.now() 72 | 73 | # Save the file 74 | wb.save("sample.xlsx") 75 | 76 | 77 | Documentation 78 | ------------- 79 | 80 | The documentation is at: https://openpyxl.readthedocs.io 81 | 82 | * installation methods 83 | * code examples 84 | * instructions for contributing 85 | 86 | Release notes: https://openpyxl.readthedocs.io/en/stable/changes.html 87 | -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.5.dist-info/REQUESTED: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/src/lib/openpyxl-3.1.5.dist-info/REQUESTED -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.5.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: bdist_wheel (0.43.0) 3 | Root-Is-Purelib: true 4 | Tag: py2-none-any 5 | Tag: py3-none-any 6 | 7 | -------------------------------------------------------------------------------- /src/lib/openpyxl-3.1.5.dist-info/top_level.txt: -------------------------------------------------------------------------------- 1 | openpyxl 2 | -------------------------------------------------------------------------------- /src/lib/openpyxl/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | DEBUG = False 4 | 5 | from openpyxl.compat.numbers import NUMPY 6 | from openpyxl.xml import DEFUSEDXML, LXML 7 | from openpyxl.workbook import Workbook 8 | from openpyxl.reader.excel import load_workbook as open 9 | from openpyxl.reader.excel import load_workbook 10 | import openpyxl._constants as constants 11 | 12 | # Expose constants especially the version number 13 | 14 | __author__ = constants.__author__ 15 | __author_email__ = constants.__author_email__ 16 | __license__ = constants.__license__ 17 | __maintainer_email__ = constants.__maintainer_email__ 18 | __url__ = constants.__url__ 19 | __version__ = constants.__version__ 20 | -------------------------------------------------------------------------------- /src/lib/openpyxl/_constants.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | """ 4 | Package metadata 5 | """ 6 | 7 | __author__ = "See AUTHORS" 8 | __author_email__ = "charlie.clark@clark-consulting.eu" 9 | __license__ = "MIT" 10 | __maintainer_email__ = "openpyxl-users@googlegroups.com" 11 | __url__ = "https://openpyxl.readthedocs.io" 12 | __version__ = "3.1.5" 13 | __python__ = "3.8" 14 | -------------------------------------------------------------------------------- /src/lib/openpyxl/cell/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from .cell import Cell, WriteOnlyCell, MergedCell 4 | from .read_only import ReadOnlyCell 5 | -------------------------------------------------------------------------------- /src/lib/openpyxl/cell/read_only.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.cell import Cell 4 | from openpyxl.utils import get_column_letter 5 | from openpyxl.utils.datetime import from_excel 6 | from openpyxl.styles import is_date_format 7 | from openpyxl.styles.numbers import BUILTIN_FORMATS, BUILTIN_FORMATS_MAX_SIZE 8 | 9 | 10 | class ReadOnlyCell: 11 | 12 | __slots__ = ('parent', 'row', 'column', '_value', 'data_type', '_style_id') 13 | 14 | def __init__(self, sheet, row, column, value, data_type='n', style_id=0): 15 | self.parent = sheet 16 | self._value = None 17 | self.row = row 18 | self.column = column 19 | self.data_type = data_type 20 | self.value = value 21 | self._style_id = style_id 22 | 23 | 24 | def __eq__(self, other): 25 | for a in self.__slots__: 26 | if getattr(self, a) != getattr(other, a): 27 | return 28 | return True 29 | 30 | def __ne__(self, other): 31 | return not self.__eq__(other) 32 | 33 | 34 | def __repr__(self): 35 | return "".format(self.parent.title, self.coordinate) 36 | 37 | 38 | @property 39 | def coordinate(self): 40 | column = get_column_letter(self.column) 41 | return "{1}{0}".format(self.row, column) 42 | 43 | 44 | @property 45 | def coordinate(self): 46 | return Cell.coordinate.__get__(self) 47 | 48 | 49 | @property 50 | def column_letter(self): 51 | return Cell.column_letter.__get__(self) 52 | 53 | 54 | @property 55 | def style_array(self): 56 | return self.parent.parent._cell_styles[self._style_id] 57 | 58 | 59 | @property 60 | def has_style(self): 61 | return self._style_id != 0 62 | 63 | 64 | @property 65 | def number_format(self): 66 | _id = self.style_array.numFmtId 67 | if _id < BUILTIN_FORMATS_MAX_SIZE: 68 | return BUILTIN_FORMATS.get(_id, "General") 69 | else: 70 | return self.parent.parent._number_formats[ 71 | _id - BUILTIN_FORMATS_MAX_SIZE] 72 | 73 | @property 74 | def font(self): 75 | _id = self.style_array.fontId 76 | return self.parent.parent._fonts[_id] 77 | 78 | @property 79 | def fill(self): 80 | _id = self.style_array.fillId 81 | return self.parent.parent._fills[_id] 82 | 83 | @property 84 | def border(self): 85 | _id = self.style_array.borderId 86 | return self.parent.parent._borders[_id] 87 | 88 | @property 89 | def alignment(self): 90 | _id = self.style_array.alignmentId 91 | return self.parent.parent._alignments[_id] 92 | 93 | @property 94 | def protection(self): 95 | _id = self.style_array.protectionId 96 | return self.parent.parent._protections[_id] 97 | 98 | 99 | @property 100 | def is_date(self): 101 | return Cell.is_date.__get__(self) 102 | 103 | 104 | @property 105 | def internal_value(self): 106 | return self._value 107 | 108 | @property 109 | def value(self): 110 | return self._value 111 | 112 | @value.setter 113 | def value(self, value): 114 | if self._value is not None: 115 | raise AttributeError("Cell is read only") 116 | self._value = value 117 | 118 | 119 | class EmptyCell: 120 | 121 | __slots__ = () 122 | 123 | value = None 124 | is_date = False 125 | font = None 126 | border = None 127 | fill = None 128 | number_format = None 129 | alignment = None 130 | data_type = 'n' 131 | 132 | 133 | def __repr__(self): 134 | return "" 135 | 136 | EMPTY_CELL = EmptyCell() 137 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/_3d.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors import Typed, Alias 4 | from openpyxl.descriptors.serialisable import Serialisable 5 | from openpyxl.descriptors.nested import ( 6 | NestedBool, 7 | NestedInteger, 8 | NestedMinMax, 9 | ) 10 | from openpyxl.descriptors.excel import ExtensionList 11 | from .marker import PictureOptions 12 | from .shapes import GraphicalProperties 13 | 14 | 15 | class View3D(Serialisable): 16 | 17 | tagname = "view3D" 18 | 19 | rotX = NestedMinMax(min=-90, max=90, allow_none=True) 20 | x_rotation = Alias('rotX') 21 | hPercent = NestedMinMax(min=5, max=500, allow_none=True) 22 | height_percent = Alias('hPercent') 23 | rotY = NestedInteger(min=-90, max=90, allow_none=True) 24 | y_rotation = Alias('rotY') 25 | depthPercent = NestedInteger(allow_none=True) 26 | rAngAx = NestedBool(allow_none=True) 27 | right_angle_axes = Alias('rAngAx') 28 | perspective = NestedInteger(allow_none=True) 29 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 30 | 31 | __elements__ = ('rotX', 'hPercent', 'rotY', 'depthPercent', 'rAngAx', 32 | 'perspective',) 33 | 34 | def __init__(self, 35 | rotX=15, 36 | hPercent=None, 37 | rotY=20, 38 | depthPercent=None, 39 | rAngAx=True, 40 | perspective=None, 41 | extLst=None, 42 | ): 43 | self.rotX = rotX 44 | self.hPercent = hPercent 45 | self.rotY = rotY 46 | self.depthPercent = depthPercent 47 | self.rAngAx = rAngAx 48 | self.perspective = perspective 49 | 50 | 51 | class Surface(Serialisable): 52 | 53 | tagname = "surface" 54 | 55 | thickness = NestedInteger(allow_none=True) 56 | spPr = Typed(expected_type=GraphicalProperties, allow_none=True) 57 | graphicalProperties = Alias('spPr') 58 | pictureOptions = Typed(expected_type=PictureOptions, allow_none=True) 59 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 60 | 61 | __elements__ = ('thickness', 'spPr', 'pictureOptions',) 62 | 63 | def __init__(self, 64 | thickness=None, 65 | spPr=None, 66 | pictureOptions=None, 67 | extLst=None, 68 | ): 69 | self.thickness = thickness 70 | self.spPr = spPr 71 | self.pictureOptions = pictureOptions 72 | 73 | 74 | class _3DBase(Serialisable): 75 | 76 | """ 77 | Base class for 3D charts 78 | """ 79 | 80 | tagname = "ChartBase" 81 | 82 | view3D = Typed(expected_type=View3D, allow_none=True) 83 | floor = Typed(expected_type=Surface, allow_none=True) 84 | sideWall = Typed(expected_type=Surface, allow_none=True) 85 | backWall = Typed(expected_type=Surface, allow_none=True) 86 | 87 | def __init__(self, 88 | view3D=None, 89 | floor=None, 90 | sideWall=None, 91 | backWall=None, 92 | ): 93 | if view3D is None: 94 | view3D = View3D() 95 | self.view3D = view3D 96 | if floor is None: 97 | floor = Surface() 98 | self.floor = floor 99 | if sideWall is None: 100 | sideWall = Surface() 101 | self.sideWall = sideWall 102 | if backWall is None: 103 | backWall = Surface() 104 | self.backWall = backWall 105 | super(_3DBase, self).__init__() 106 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from .area_chart import AreaChart, AreaChart3D 4 | from .bar_chart import BarChart, BarChart3D 5 | from .bubble_chart import BubbleChart 6 | from .line_chart import LineChart, LineChart3D 7 | from .pie_chart import ( 8 | PieChart, 9 | PieChart3D, 10 | DoughnutChart, 11 | ProjectedPieChart 12 | ) 13 | from .radar_chart import RadarChart 14 | from .scatter_chart import ScatterChart 15 | from .stock_chart import StockChart 16 | from .surface_chart import SurfaceChart, SurfaceChart3D 17 | 18 | from .series_factory import SeriesFactory as Series 19 | from .reference import Reference 20 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/area_chart.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Set, 7 | Bool, 8 | Integer, 9 | Sequence, 10 | Alias, 11 | ) 12 | 13 | from openpyxl.descriptors.excel import ExtensionList 14 | from openpyxl.descriptors.nested import ( 15 | NestedMinMax, 16 | NestedSet, 17 | NestedBool, 18 | ) 19 | 20 | from ._chart import ChartBase 21 | from .descriptors import NestedGapAmount 22 | from .axis import TextAxis, NumericAxis, SeriesAxis, ChartLines 23 | from .label import DataLabelList 24 | from .series import Series 25 | 26 | 27 | class _AreaChartBase(ChartBase): 28 | 29 | grouping = NestedSet(values=(['percentStacked', 'standard', 'stacked'])) 30 | varyColors = NestedBool(nested=True, allow_none=True) 31 | ser = Sequence(expected_type=Series, allow_none=True) 32 | dLbls = Typed(expected_type=DataLabelList, allow_none=True) 33 | dataLabels = Alias("dLbls") 34 | dropLines = Typed(expected_type=ChartLines, allow_none=True) 35 | 36 | _series_type = "area" 37 | 38 | __elements__ = ('grouping', 'varyColors', 'ser', 'dLbls', 'dropLines') 39 | 40 | def __init__(self, 41 | grouping="standard", 42 | varyColors=None, 43 | ser=(), 44 | dLbls=None, 45 | dropLines=None, 46 | ): 47 | self.grouping = grouping 48 | self.varyColors = varyColors 49 | self.ser = ser 50 | self.dLbls = dLbls 51 | self.dropLines = dropLines 52 | super().__init__() 53 | 54 | 55 | class AreaChart(_AreaChartBase): 56 | 57 | tagname = "areaChart" 58 | 59 | grouping = _AreaChartBase.grouping 60 | varyColors = _AreaChartBase.varyColors 61 | ser = _AreaChartBase.ser 62 | dLbls = _AreaChartBase.dLbls 63 | dropLines = _AreaChartBase.dropLines 64 | 65 | # chart properties actually used by containing classes 66 | x_axis = Typed(expected_type=TextAxis) 67 | y_axis = Typed(expected_type=NumericAxis) 68 | 69 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 70 | 71 | __elements__ = _AreaChartBase.__elements__ + ('axId',) 72 | 73 | def __init__(self, 74 | axId=None, 75 | extLst=None, 76 | **kw 77 | ): 78 | self.x_axis = TextAxis() 79 | self.y_axis = NumericAxis() 80 | super().__init__(**kw) 81 | 82 | 83 | class AreaChart3D(AreaChart): 84 | 85 | tagname = "area3DChart" 86 | 87 | grouping = _AreaChartBase.grouping 88 | varyColors = _AreaChartBase.varyColors 89 | ser = _AreaChartBase.ser 90 | dLbls = _AreaChartBase.dLbls 91 | dropLines = _AreaChartBase.dropLines 92 | 93 | gapDepth = NestedGapAmount() 94 | 95 | x_axis = Typed(expected_type=TextAxis) 96 | y_axis = Typed(expected_type=NumericAxis) 97 | z_axis = Typed(expected_type=SeriesAxis, allow_none=True) 98 | 99 | __elements__ = AreaChart.__elements__ + ('gapDepth', ) 100 | 101 | def __init__(self, gapDepth=None, **kw): 102 | self.gapDepth = gapDepth 103 | super(AreaChart3D, self).__init__(**kw) 104 | self.x_axis = TextAxis() 105 | self.y_axis = NumericAxis() 106 | self.z_axis = SeriesAxis() 107 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/bubble_chart.py: -------------------------------------------------------------------------------- 1 | #Autogenerated schema 2 | from openpyxl.descriptors.serialisable import Serialisable 3 | from openpyxl.descriptors import ( 4 | Typed, 5 | Set, 6 | MinMax, 7 | Bool, 8 | Integer, 9 | Alias, 10 | Sequence, 11 | ) 12 | from openpyxl.descriptors.excel import ExtensionList 13 | from openpyxl.descriptors.nested import ( 14 | NestedNoneSet, 15 | NestedMinMax, 16 | NestedBool, 17 | ) 18 | 19 | from ._chart import ChartBase 20 | from .axis import TextAxis, NumericAxis 21 | from .series import XYSeries 22 | from .label import DataLabelList 23 | 24 | 25 | class BubbleChart(ChartBase): 26 | 27 | tagname = "bubbleChart" 28 | 29 | varyColors = NestedBool(allow_none=True) 30 | ser = Sequence(expected_type=XYSeries, allow_none=True) 31 | dLbls = Typed(expected_type=DataLabelList, allow_none=True) 32 | dataLabels = Alias("dLbls") 33 | bubble3D = NestedBool(allow_none=True) 34 | bubbleScale = NestedMinMax(min=0, max=300, allow_none=True) 35 | showNegBubbles = NestedBool(allow_none=True) 36 | sizeRepresents = NestedNoneSet(values=(['area', 'w'])) 37 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 38 | 39 | x_axis = Typed(expected_type=NumericAxis) 40 | y_axis = Typed(expected_type=NumericAxis) 41 | 42 | _series_type = "bubble" 43 | 44 | __elements__ = ('varyColors', 'ser', 'dLbls', 'bubble3D', 'bubbleScale', 45 | 'showNegBubbles', 'sizeRepresents', 'axId') 46 | 47 | def __init__(self, 48 | varyColors=None, 49 | ser=(), 50 | dLbls=None, 51 | bubble3D=None, 52 | bubbleScale=None, 53 | showNegBubbles=None, 54 | sizeRepresents=None, 55 | extLst=None, 56 | **kw 57 | ): 58 | self.varyColors = varyColors 59 | self.ser = ser 60 | self.dLbls = dLbls 61 | self.bubble3D = bubble3D 62 | self.bubbleScale = bubbleScale 63 | self.showNegBubbles = showNegBubbles 64 | self.sizeRepresents = sizeRepresents 65 | self.x_axis = NumericAxis(axId=10, crossAx=20) 66 | self.y_axis = NumericAxis(axId=20, crossAx=10) 67 | super().__init__(**kw) 68 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/descriptors.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | 5 | from openpyxl.descriptors.nested import ( 6 | NestedMinMax 7 | ) 8 | 9 | from openpyxl.descriptors import Typed 10 | 11 | from .data_source import NumFmt 12 | 13 | """ 14 | Utility descriptors for the chart module. 15 | For convenience but also clarity. 16 | """ 17 | 18 | class NestedGapAmount(NestedMinMax): 19 | 20 | allow_none = True 21 | min = 0 22 | max = 500 23 | 24 | 25 | class NestedOverlap(NestedMinMax): 26 | 27 | allow_none = True 28 | min = -100 29 | max = 100 30 | 31 | 32 | class NumberFormatDescriptor(Typed): 33 | """ 34 | Allow direct assignment of format code 35 | """ 36 | 37 | expected_type = NumFmt 38 | allow_none = True 39 | 40 | def __set__(self, instance, value): 41 | if isinstance(value, str): 42 | value = NumFmt(value) 43 | super().__set__(instance, value) 44 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/error_bar.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Float, 7 | Set, 8 | Alias 9 | ) 10 | 11 | from openpyxl.descriptors.excel import ExtensionList 12 | from openpyxl.descriptors.nested import ( 13 | NestedNoneSet, 14 | NestedSet, 15 | NestedBool, 16 | NestedFloat, 17 | ) 18 | 19 | from .data_source import NumDataSource 20 | from .shapes import GraphicalProperties 21 | 22 | 23 | class ErrorBars(Serialisable): 24 | 25 | tagname = "errBars" 26 | 27 | errDir = NestedNoneSet(values=(['x', 'y'])) 28 | direction = Alias("errDir") 29 | errBarType = NestedSet(values=(['both', 'minus', 'plus'])) 30 | style = Alias("errBarType") 31 | errValType = NestedSet(values=(['cust', 'fixedVal', 'percentage', 'stdDev', 'stdErr'])) 32 | size = Alias("errValType") 33 | noEndCap = NestedBool(nested=True, allow_none=True) 34 | plus = Typed(expected_type=NumDataSource, allow_none=True) 35 | minus = Typed(expected_type=NumDataSource, allow_none=True) 36 | val = NestedFloat(allow_none=True) 37 | spPr = Typed(expected_type=GraphicalProperties, allow_none=True) 38 | graphicalProperties = Alias("spPr") 39 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 40 | 41 | __elements__ = ('errDir','errBarType', 'errValType', 'noEndCap','minus', 'plus', 'val', 'spPr') 42 | 43 | 44 | def __init__(self, 45 | errDir=None, 46 | errBarType="both", 47 | errValType="fixedVal", 48 | noEndCap=None, 49 | plus=None, 50 | minus=None, 51 | val=None, 52 | spPr=None, 53 | extLst=None, 54 | ): 55 | self.errDir = errDir 56 | self.errBarType = errBarType 57 | self.errValType = errValType 58 | self.noEndCap = noEndCap 59 | self.plus = plus 60 | self.minus = minus 61 | self.val = val 62 | self.spPr = spPr 63 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/layout.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | NoneSet, 6 | Float, 7 | Typed, 8 | Alias, 9 | ) 10 | 11 | from openpyxl.descriptors.excel import ExtensionList 12 | from openpyxl.descriptors.nested import ( 13 | NestedNoneSet, 14 | NestedSet, 15 | NestedMinMax, 16 | ) 17 | 18 | class ManualLayout(Serialisable): 19 | 20 | tagname = "manualLayout" 21 | 22 | layoutTarget = NestedNoneSet(values=(['inner', 'outer'])) 23 | xMode = NestedNoneSet(values=(['edge', 'factor'])) 24 | yMode = NestedNoneSet(values=(['edge', 'factor'])) 25 | wMode = NestedSet(values=(['edge', 'factor'])) 26 | hMode = NestedSet(values=(['edge', 'factor'])) 27 | x = NestedMinMax(min=-1, max=1, allow_none=True) 28 | y = NestedMinMax(min=-1, max=1, allow_none=True) 29 | w = NestedMinMax(min=0, max=1, allow_none=True) 30 | width = Alias('w') 31 | h = NestedMinMax(min=0, max=1, allow_none=True) 32 | height = Alias('h') 33 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 34 | 35 | __elements__ = ('layoutTarget', 'xMode', 'yMode', 'wMode', 'hMode', 'x', 36 | 'y', 'w', 'h') 37 | 38 | def __init__(self, 39 | layoutTarget=None, 40 | xMode=None, 41 | yMode=None, 42 | wMode="factor", 43 | hMode="factor", 44 | x=None, 45 | y=None, 46 | w=None, 47 | h=None, 48 | extLst=None, 49 | ): 50 | self.layoutTarget = layoutTarget 51 | self.xMode = xMode 52 | self.yMode = yMode 53 | self.wMode = wMode 54 | self.hMode = hMode 55 | self.x = x 56 | self.y = y 57 | self.w = w 58 | self.h = h 59 | 60 | 61 | class Layout(Serialisable): 62 | 63 | tagname = "layout" 64 | 65 | manualLayout = Typed(expected_type=ManualLayout, allow_none=True) 66 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 67 | 68 | __elements__ = ('manualLayout',) 69 | 70 | def __init__(self, 71 | manualLayout=None, 72 | extLst=None, 73 | ): 74 | self.manualLayout = manualLayout 75 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/legend.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Integer, 7 | Alias, 8 | Sequence, 9 | ) 10 | from openpyxl.descriptors.excel import ExtensionList 11 | from openpyxl.descriptors.nested import ( 12 | NestedBool, 13 | NestedSet, 14 | NestedInteger 15 | ) 16 | 17 | from .layout import Layout 18 | from .shapes import GraphicalProperties 19 | from .text import RichText 20 | 21 | 22 | class LegendEntry(Serialisable): 23 | 24 | tagname = "legendEntry" 25 | 26 | idx = NestedInteger() 27 | delete = NestedBool() 28 | txPr = Typed(expected_type=RichText, allow_none=True) 29 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 30 | 31 | __elements__ = ('idx', 'delete', 'txPr') 32 | 33 | def __init__(self, 34 | idx=0, 35 | delete=False, 36 | txPr=None, 37 | extLst=None, 38 | ): 39 | self.idx = idx 40 | self.delete = delete 41 | self.txPr = txPr 42 | 43 | 44 | class Legend(Serialisable): 45 | 46 | tagname = "legend" 47 | 48 | legendPos = NestedSet(values=(['b', 'tr', 'l', 'r', 't'])) 49 | position = Alias('legendPos') 50 | legendEntry = Sequence(expected_type=LegendEntry) 51 | layout = Typed(expected_type=Layout, allow_none=True) 52 | overlay = NestedBool(allow_none=True) 53 | spPr = Typed(expected_type=GraphicalProperties, allow_none=True) 54 | graphicalProperties = Alias('spPr') 55 | txPr = Typed(expected_type=RichText, allow_none=True) 56 | textProperties = Alias('txPr') 57 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 58 | 59 | __elements__ = ('legendPos', 'legendEntry', 'layout', 'overlay', 'spPr', 'txPr',) 60 | 61 | def __init__(self, 62 | legendPos="r", 63 | legendEntry=(), 64 | layout=None, 65 | overlay=None, 66 | spPr=None, 67 | txPr=None, 68 | extLst=None, 69 | ): 70 | self.legendPos = legendPos 71 | self.legendEntry = legendEntry 72 | self.layout = layout 73 | self.overlay = overlay 74 | self.spPr = spPr 75 | self.txPr = txPr 76 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/marker.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Alias, 7 | ) 8 | 9 | from openpyxl.descriptors.excel import( 10 | ExtensionList, 11 | _explicit_none, 12 | ) 13 | 14 | from openpyxl.descriptors.nested import ( 15 | NestedBool, 16 | NestedInteger, 17 | NestedMinMax, 18 | NestedNoneSet, 19 | ) 20 | 21 | from .layout import Layout 22 | from .picture import PictureOptions 23 | from .shapes import * 24 | from .text import * 25 | from .error_bar import * 26 | 27 | 28 | class Marker(Serialisable): 29 | 30 | tagname = "marker" 31 | 32 | symbol = NestedNoneSet(values=(['circle', 'dash', 'diamond', 'dot', 'picture', 33 | 'plus', 'square', 'star', 'triangle', 'x', 'auto']), 34 | to_tree=_explicit_none) 35 | size = NestedMinMax(min=2, max=72, allow_none=True) 36 | spPr = Typed(expected_type=GraphicalProperties, allow_none=True) 37 | graphicalProperties = Alias('spPr') 38 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 39 | 40 | __elements__ = ('symbol', 'size', 'spPr') 41 | 42 | def __init__(self, 43 | symbol=None, 44 | size=None, 45 | spPr=None, 46 | extLst=None, 47 | ): 48 | self.symbol = symbol 49 | self.size = size 50 | if spPr is None: 51 | spPr = GraphicalProperties() 52 | self.spPr = spPr 53 | 54 | 55 | class DataPoint(Serialisable): 56 | 57 | tagname = "dPt" 58 | 59 | idx = NestedInteger() 60 | invertIfNegative = NestedBool(allow_none=True) 61 | marker = Typed(expected_type=Marker, allow_none=True) 62 | bubble3D = NestedBool(allow_none=True) 63 | explosion = NestedInteger(allow_none=True) 64 | spPr = Typed(expected_type=GraphicalProperties, allow_none=True) 65 | graphicalProperties = Alias('spPr') 66 | pictureOptions = Typed(expected_type=PictureOptions, allow_none=True) 67 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 68 | 69 | __elements__ = ('idx', 'invertIfNegative', 'marker', 'bubble3D', 70 | 'explosion', 'spPr', 'pictureOptions') 71 | 72 | def __init__(self, 73 | idx=None, 74 | invertIfNegative=None, 75 | marker=None, 76 | bubble3D=None, 77 | explosion=None, 78 | spPr=None, 79 | pictureOptions=None, 80 | extLst=None, 81 | ): 82 | self.idx = idx 83 | self.invertIfNegative = invertIfNegative 84 | self.marker = marker 85 | self.bubble3D = bubble3D 86 | self.explosion = explosion 87 | if spPr is None: 88 | spPr = GraphicalProperties() 89 | self.spPr = spPr 90 | self.pictureOptions = pictureOptions 91 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/picture.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | 5 | from openpyxl.descriptors.nested import ( 6 | NestedBool, 7 | NestedFloat, 8 | NestedMinMax, 9 | NestedNoneSet, 10 | ) 11 | 12 | class PictureOptions(Serialisable): 13 | 14 | tagname = "pictureOptions" 15 | 16 | applyToFront = NestedBool(allow_none=True, nested=True) 17 | applyToSides = NestedBool(allow_none=True, nested=True) 18 | applyToEnd = NestedBool(allow_none=True, nested=True) 19 | pictureFormat = NestedNoneSet(values=(['stretch', 'stack', 'stackScale']), nested=True) 20 | pictureStackUnit = NestedFloat(allow_none=True, nested=True) 21 | 22 | __elements__ = ('applyToFront', 'applyToSides', 'applyToEnd', 'pictureFormat', 'pictureStackUnit') 23 | 24 | def __init__(self, 25 | applyToFront=None, 26 | applyToSides=None, 27 | applyToEnd=None, 28 | pictureFormat=None, 29 | pictureStackUnit=None, 30 | ): 31 | self.applyToFront = applyToFront 32 | self.applyToSides = applyToSides 33 | self.applyToEnd = applyToEnd 34 | self.pictureFormat = pictureFormat 35 | self.pictureStackUnit = pictureStackUnit 36 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/pivot.py: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (c) 2010-2024 openpyxl 3 | 4 | from openpyxl.descriptors.serialisable import Serialisable 5 | from openpyxl.descriptors import ( 6 | Alias, 7 | Typed, 8 | ) 9 | from openpyxl.descriptors.nested import NestedInteger, NestedText 10 | from openpyxl.descriptors.excel import ExtensionList 11 | 12 | from .label import DataLabel 13 | from .marker import Marker 14 | from .shapes import GraphicalProperties 15 | from .text import RichText 16 | 17 | 18 | class PivotSource(Serialisable): 19 | 20 | tagname = "pivotSource" 21 | 22 | name = NestedText(expected_type=str) 23 | fmtId = NestedInteger(expected_type=int) 24 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 25 | 26 | __elements__ = ('name', 'fmtId') 27 | 28 | def __init__(self, 29 | name=None, 30 | fmtId=None, 31 | extLst=None, 32 | ): 33 | self.name = name 34 | self.fmtId = fmtId 35 | 36 | 37 | class PivotFormat(Serialisable): 38 | 39 | tagname = "pivotFmt" 40 | 41 | idx = NestedInteger(nested=True) 42 | spPr = Typed(expected_type=GraphicalProperties, allow_none=True) 43 | graphicalProperties = Alias("spPr") 44 | txPr = Typed(expected_type=RichText, allow_none=True) 45 | TextBody = Alias("txPr") 46 | marker = Typed(expected_type=Marker, allow_none=True) 47 | dLbl = Typed(expected_type=DataLabel, allow_none=True) 48 | DataLabel = Alias("dLbl") 49 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 50 | 51 | __elements__ = ('idx', 'spPr', 'txPr', 'marker', 'dLbl') 52 | 53 | def __init__(self, 54 | idx=0, 55 | spPr=None, 56 | txPr=None, 57 | marker=None, 58 | dLbl=None, 59 | extLst=None, 60 | ): 61 | self.idx = idx 62 | self.spPr = spPr 63 | self.txPr = txPr 64 | self.marker = marker 65 | self.dLbl = dLbl 66 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/print_settings.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Float, 6 | Typed, 7 | Alias, 8 | ) 9 | 10 | from openpyxl.worksheet.page import PrintPageSetup 11 | from openpyxl.worksheet.header_footer import HeaderFooter 12 | 13 | 14 | class PageMargins(Serialisable): 15 | """ 16 | Identical to openpyxl.worksheet.page.Pagemargins but element names are different :-/ 17 | """ 18 | tagname = "pageMargins" 19 | 20 | l = Float() 21 | left = Alias('l') 22 | r = Float() 23 | right = Alias('r') 24 | t = Float() 25 | top = Alias('t') 26 | b = Float() 27 | bottom = Alias('b') 28 | header = Float() 29 | footer = Float() 30 | 31 | def __init__(self, l=0.75, r=0.75, t=1, b=1, header=0.5, footer=0.5): 32 | self.l = l 33 | self.r = r 34 | self.t = t 35 | self.b = b 36 | self.header = header 37 | self.footer = footer 38 | 39 | 40 | class PrintSettings(Serialisable): 41 | 42 | tagname = "printSettings" 43 | 44 | headerFooter = Typed(expected_type=HeaderFooter, allow_none=True) 45 | pageMargins = Typed(expected_type=PageMargins, allow_none=True) 46 | pageSetup = Typed(expected_type=PrintPageSetup, allow_none=True) 47 | 48 | __elements__ = ("headerFooter", "pageMargins", "pageMargins") 49 | 50 | def __init__(self, 51 | headerFooter=None, 52 | pageMargins=None, 53 | pageSetup=None, 54 | ): 55 | self.headerFooter = headerFooter 56 | self.pageMargins = pageMargins 57 | self.pageSetup = pageSetup 58 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/radar_chart.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Sequence, 6 | Typed, 7 | Alias, 8 | ) 9 | from openpyxl.descriptors.excel import ExtensionList 10 | from openpyxl.descriptors.nested import ( 11 | NestedBool, 12 | NestedInteger, 13 | NestedSet 14 | ) 15 | 16 | from ._chart import ChartBase 17 | from .axis import TextAxis, NumericAxis 18 | from .series import Series 19 | from .label import DataLabelList 20 | 21 | 22 | class RadarChart(ChartBase): 23 | 24 | tagname = "radarChart" 25 | 26 | radarStyle = NestedSet(values=(['standard', 'marker', 'filled'])) 27 | type = Alias("radarStyle") 28 | varyColors = NestedBool(nested=True, allow_none=True) 29 | ser = Sequence(expected_type=Series, allow_none=True) 30 | dLbls = Typed(expected_type=DataLabelList, allow_none=True) 31 | dataLabels = Alias("dLbls") 32 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 33 | 34 | _series_type = "radar" 35 | 36 | x_axis = Typed(expected_type=TextAxis) 37 | y_axis = Typed(expected_type=NumericAxis) 38 | 39 | __elements__ = ('radarStyle', 'varyColors', 'ser', 'dLbls', 'axId') 40 | 41 | def __init__(self, 42 | radarStyle="standard", 43 | varyColors=None, 44 | ser=(), 45 | dLbls=None, 46 | extLst=None, 47 | **kw 48 | ): 49 | self.radarStyle = radarStyle 50 | self.varyColors = varyColors 51 | self.ser = ser 52 | self.dLbls = dLbls 53 | self.x_axis = TextAxis() 54 | self.y_axis = NumericAxis() 55 | super().__init__(**kw) 56 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/reader.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | """ 4 | Read a chart 5 | """ 6 | 7 | def read_chart(chartspace): 8 | cs = chartspace 9 | plot = cs.chart.plotArea 10 | 11 | chart = plot._charts[0] 12 | chart._charts = plot._charts 13 | 14 | chart.title = cs.chart.title 15 | chart.display_blanks = cs.chart.dispBlanksAs 16 | chart.visible_cells_only = cs.chart.plotVisOnly 17 | chart.layout = plot.layout 18 | chart.legend = cs.chart.legend 19 | 20 | # 3d attributes 21 | chart.floor = cs.chart.floor 22 | chart.sideWall = cs.chart.sideWall 23 | chart.backWall = cs.chart.backWall 24 | chart.pivotSource = cs.pivotSource 25 | chart.pivotFormats = cs.chart.pivotFmts 26 | chart.idx_base = min((s.idx for s in chart.series), default=0) 27 | chart._reindex() 28 | 29 | # Border, fill, etc. 30 | chart.graphical_properties = cs.graphical_properties 31 | 32 | return chart 33 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/reference.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from itertools import chain 4 | 5 | from openpyxl.descriptors.serialisable import Serialisable 6 | from openpyxl.descriptors import ( 7 | MinMax, 8 | Typed, 9 | String, 10 | Strict, 11 | ) 12 | from openpyxl.worksheet.worksheet import Worksheet 13 | from openpyxl.utils import ( 14 | get_column_letter, 15 | range_to_tuple, 16 | quote_sheetname 17 | ) 18 | 19 | 20 | class DummyWorksheet: 21 | 22 | 23 | def __init__(self, title): 24 | self.title = title 25 | 26 | 27 | class Reference(Strict): 28 | 29 | """ 30 | Normalise cell range references 31 | """ 32 | 33 | min_row = MinMax(min=1, max=1000000, expected_type=int) 34 | max_row = MinMax(min=1, max=1000000, expected_type=int) 35 | min_col = MinMax(min=1, max=16384, expected_type=int) 36 | max_col = MinMax(min=1, max=16384, expected_type=int) 37 | range_string = String(allow_none=True) 38 | 39 | def __init__(self, 40 | worksheet=None, 41 | min_col=None, 42 | min_row=None, 43 | max_col=None, 44 | max_row=None, 45 | range_string=None 46 | ): 47 | if range_string is not None: 48 | sheetname, boundaries = range_to_tuple(range_string) 49 | min_col, min_row, max_col, max_row = boundaries 50 | worksheet = DummyWorksheet(sheetname) 51 | 52 | self.worksheet = worksheet 53 | self.min_col = min_col 54 | self.min_row = min_row 55 | if max_col is None: 56 | max_col = min_col 57 | self.max_col = max_col 58 | if max_row is None: 59 | max_row = min_row 60 | self.max_row = max_row 61 | 62 | 63 | def __repr__(self): 64 | return str(self) 65 | 66 | 67 | def __str__(self): 68 | fmt = u"{0}!${1}${2}:${3}${4}" 69 | if (self.min_col == self.max_col 70 | and self.min_row == self.max_row): 71 | fmt = u"{0}!${1}${2}" 72 | return fmt.format(self.sheetname, 73 | get_column_letter(self.min_col), self.min_row, 74 | get_column_letter(self.max_col), self.max_row 75 | ) 76 | 77 | 78 | __str__ = __str__ 79 | 80 | 81 | 82 | def __len__(self): 83 | if self.min_row == self.max_row: 84 | return 1 + self.max_col - self.min_col 85 | return 1 + self.max_row - self.min_row 86 | 87 | 88 | def __eq__(self, other): 89 | return str(self) == str(other) 90 | 91 | 92 | @property 93 | def rows(self): 94 | """ 95 | Return all rows in the range 96 | """ 97 | for row in range(self.min_row, self.max_row+1): 98 | yield Reference(self.worksheet, self.min_col, row, self.max_col, row) 99 | 100 | 101 | @property 102 | def cols(self): 103 | """ 104 | Return all columns in the range 105 | """ 106 | for col in range(self.min_col, self.max_col+1): 107 | yield Reference(self.worksheet, col, self.min_row, col, self.max_row) 108 | 109 | 110 | def pop(self): 111 | """ 112 | Return and remove the first cell 113 | """ 114 | cell = "{0}{1}".format(get_column_letter(self.min_col), self.min_row) 115 | if self.min_row == self.max_row: 116 | self.min_col += 1 117 | else: 118 | self.min_row += 1 119 | return cell 120 | 121 | 122 | @property 123 | def sheetname(self): 124 | return quote_sheetname(self.worksheet.title) 125 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/scatter_chart.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Sequence, 7 | Alias 8 | ) 9 | from openpyxl.descriptors.excel import ExtensionList 10 | from openpyxl.descriptors.nested import ( 11 | NestedNoneSet, 12 | NestedBool, 13 | ) 14 | 15 | from ._chart import ChartBase 16 | from .axis import NumericAxis, TextAxis 17 | from .series import XYSeries 18 | from .label import DataLabelList 19 | 20 | 21 | class ScatterChart(ChartBase): 22 | 23 | tagname = "scatterChart" 24 | 25 | scatterStyle = NestedNoneSet(values=(['line', 'lineMarker', 'marker', 'smooth', 'smoothMarker'])) 26 | varyColors = NestedBool(allow_none=True) 27 | ser = Sequence(expected_type=XYSeries, allow_none=True) 28 | dLbls = Typed(expected_type=DataLabelList, allow_none=True) 29 | dataLabels = Alias("dLbls") 30 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 31 | 32 | x_axis = Typed(expected_type=(NumericAxis, TextAxis)) 33 | y_axis = Typed(expected_type=NumericAxis) 34 | 35 | _series_type = "scatter" 36 | 37 | __elements__ = ('scatterStyle', 'varyColors', 'ser', 'dLbls', 'axId',) 38 | 39 | def __init__(self, 40 | scatterStyle=None, 41 | varyColors=None, 42 | ser=(), 43 | dLbls=None, 44 | extLst=None, 45 | **kw 46 | ): 47 | self.scatterStyle = scatterStyle 48 | self.varyColors = varyColors 49 | self.ser = ser 50 | self.dLbls = dLbls 51 | self.x_axis = NumericAxis(axId=10, crossAx=20) 52 | self.y_axis = NumericAxis(axId=20, crossAx=10) 53 | super().__init__(**kw) 54 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/series_factory.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from .data_source import NumDataSource, NumRef, AxDataSource 4 | from .reference import Reference 5 | from .series import Series, XYSeries, SeriesLabel, StrRef 6 | from openpyxl.utils import rows_from_range, quote_sheetname 7 | 8 | 9 | def SeriesFactory(values, xvalues=None, zvalues=None, title=None, title_from_data=False): 10 | """ 11 | Convenience Factory for creating chart data series. 12 | """ 13 | 14 | if not isinstance(values, Reference): 15 | values = Reference(range_string=values) 16 | 17 | if title_from_data: 18 | cell = values.pop() 19 | title = u"{0}!{1}".format(values.sheetname, cell) 20 | title = SeriesLabel(strRef=StrRef(title)) 21 | elif title is not None: 22 | title = SeriesLabel(v=title) 23 | 24 | source = NumDataSource(numRef=NumRef(f=values)) 25 | if xvalues is not None: 26 | if not isinstance(xvalues, Reference): 27 | xvalues = Reference(range_string=xvalues) 28 | series = XYSeries() 29 | series.yVal = source 30 | series.xVal = AxDataSource(numRef=NumRef(f=xvalues)) 31 | if zvalues is not None: 32 | if not isinstance(zvalues, Reference): 33 | zvalues = Reference(range_string=zvalues) 34 | series.zVal = NumDataSource(NumRef(f=zvalues)) 35 | else: 36 | series = Series() 37 | series.val = source 38 | 39 | if title is not None: 40 | series.title = title 41 | return series 42 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/shapes.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Alias 7 | ) 8 | from openpyxl.descriptors.nested import ( 9 | EmptyTag 10 | ) 11 | from openpyxl.drawing.colors import ColorChoiceDescriptor 12 | from openpyxl.drawing.fill import * 13 | from openpyxl.drawing.line import LineProperties 14 | from openpyxl.drawing.geometry import ( 15 | Shape3D, 16 | Scene3D, 17 | Transform2D, 18 | CustomGeometry2D, 19 | PresetGeometry2D, 20 | ) 21 | 22 | 23 | class GraphicalProperties(Serialisable): 24 | 25 | """ 26 | Somewhat vaguely 21.2.2.197 says this: 27 | 28 | This element specifies the formatting for the parent chart element. The 29 | custGeom, prstGeom, scene3d, and xfrm elements are not supported. The 30 | bwMode attribute is not supported. 31 | 32 | This doesn't leave much. And the element is used in different places. 33 | """ 34 | 35 | tagname = "spPr" 36 | 37 | bwMode = NoneSet(values=(['clr', 'auto', 'gray', 'ltGray', 'invGray', 38 | 'grayWhite', 'blackGray', 'blackWhite', 'black', 'white', 'hidden'] 39 | ) 40 | ) 41 | 42 | xfrm = Typed(expected_type=Transform2D, allow_none=True) 43 | transform = Alias('xfrm') 44 | custGeom = Typed(expected_type=CustomGeometry2D, allow_none=True) # either or 45 | prstGeom = Typed(expected_type=PresetGeometry2D, allow_none=True) 46 | 47 | # fills one of 48 | noFill = EmptyTag(namespace=DRAWING_NS) 49 | solidFill = ColorChoiceDescriptor() 50 | gradFill = Typed(expected_type=GradientFillProperties, allow_none=True) 51 | pattFill = Typed(expected_type=PatternFillProperties, allow_none=True) 52 | 53 | ln = Typed(expected_type=LineProperties, allow_none=True) 54 | line = Alias('ln') 55 | scene3d = Typed(expected_type=Scene3D, allow_none=True) 56 | sp3d = Typed(expected_type=Shape3D, allow_none=True) 57 | shape3D = Alias('sp3d') 58 | extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True) 59 | 60 | __elements__ = ('xfrm', 'prstGeom', 'noFill', 'solidFill', 'gradFill', 'pattFill', 61 | 'ln', 'scene3d', 'sp3d') 62 | 63 | def __init__(self, 64 | bwMode=None, 65 | xfrm=None, 66 | noFill=None, 67 | solidFill=None, 68 | gradFill=None, 69 | pattFill=None, 70 | ln=None, 71 | scene3d=None, 72 | custGeom=None, 73 | prstGeom=None, 74 | sp3d=None, 75 | extLst=None, 76 | ): 77 | self.bwMode = bwMode 78 | self.xfrm = xfrm 79 | self.noFill = noFill 80 | self.solidFill = solidFill 81 | self.gradFill = gradFill 82 | self.pattFill = pattFill 83 | if ln is None: 84 | ln = LineProperties() 85 | self.ln = ln 86 | self.custGeom = custGeom 87 | self.prstGeom = prstGeom 88 | self.scene3d = scene3d 89 | self.sp3d = sp3d 90 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/stock_chart.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Sequence, 7 | Alias, 8 | ) 9 | from openpyxl.descriptors.excel import ExtensionList 10 | 11 | from ._chart import ChartBase 12 | from .axis import TextAxis, NumericAxis, ChartLines 13 | from .updown_bars import UpDownBars 14 | from .label import DataLabelList 15 | from .series import Series 16 | 17 | 18 | class StockChart(ChartBase): 19 | 20 | tagname = "stockChart" 21 | 22 | ser = Sequence(expected_type=Series) #min 3, max4 23 | dLbls = Typed(expected_type=DataLabelList, allow_none=True) 24 | dataLabels = Alias('dLbls') 25 | dropLines = Typed(expected_type=ChartLines, allow_none=True) 26 | hiLowLines = Typed(expected_type=ChartLines, allow_none=True) 27 | upDownBars = Typed(expected_type=UpDownBars, allow_none=True) 28 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 29 | 30 | x_axis = Typed(expected_type=TextAxis) 31 | y_axis = Typed(expected_type=NumericAxis) 32 | 33 | _series_type = "line" 34 | 35 | __elements__ = ('ser', 'dLbls', 'dropLines', 'hiLowLines', 'upDownBars', 36 | 'axId') 37 | 38 | def __init__(self, 39 | ser=(), 40 | dLbls=None, 41 | dropLines=None, 42 | hiLowLines=None, 43 | upDownBars=None, 44 | extLst=None, 45 | **kw 46 | ): 47 | self.ser = ser 48 | self.dLbls = dLbls 49 | self.dropLines = dropLines 50 | self.hiLowLines = hiLowLines 51 | self.upDownBars = upDownBars 52 | self.x_axis = TextAxis() 53 | self.y_axis = NumericAxis() 54 | super().__init__(**kw) 55 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/surface_chart.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Integer, 7 | Bool, 8 | Alias, 9 | Sequence, 10 | ) 11 | from openpyxl.descriptors.excel import ExtensionList 12 | from openpyxl.descriptors.nested import ( 13 | NestedInteger, 14 | NestedBool, 15 | ) 16 | 17 | from ._chart import ChartBase 18 | from ._3d import _3DBase 19 | from .axis import TextAxis, NumericAxis, SeriesAxis 20 | from .shapes import GraphicalProperties 21 | from .series import Series 22 | 23 | 24 | class BandFormat(Serialisable): 25 | 26 | tagname = "bandFmt" 27 | 28 | idx = NestedInteger() 29 | spPr = Typed(expected_type=GraphicalProperties, allow_none=True) 30 | graphicalProperties = Alias("spPr") 31 | 32 | __elements__ = ('idx', 'spPr') 33 | 34 | def __init__(self, 35 | idx=0, 36 | spPr=None, 37 | ): 38 | self.idx = idx 39 | self.spPr = spPr 40 | 41 | 42 | class BandFormatList(Serialisable): 43 | 44 | tagname = "bandFmts" 45 | 46 | bandFmt = Sequence(expected_type=BandFormat, allow_none=True) 47 | 48 | __elements__ = ('bandFmt',) 49 | 50 | def __init__(self, 51 | bandFmt=(), 52 | ): 53 | self.bandFmt = bandFmt 54 | 55 | 56 | class _SurfaceChartBase(ChartBase): 57 | 58 | wireframe = NestedBool(allow_none=True) 59 | ser = Sequence(expected_type=Series, allow_none=True) 60 | bandFmts = Typed(expected_type=BandFormatList, allow_none=True) 61 | 62 | _series_type = "surface" 63 | 64 | __elements__ = ('wireframe', 'ser', 'bandFmts') 65 | 66 | def __init__(self, 67 | wireframe=None, 68 | ser=(), 69 | bandFmts=None, 70 | **kw 71 | ): 72 | self.wireframe = wireframe 73 | self.ser = ser 74 | self.bandFmts = bandFmts 75 | super().__init__(**kw) 76 | 77 | 78 | class SurfaceChart3D(_SurfaceChartBase, _3DBase): 79 | 80 | tagname = "surface3DChart" 81 | 82 | wireframe = _SurfaceChartBase.wireframe 83 | ser = _SurfaceChartBase.ser 84 | bandFmts = _SurfaceChartBase.bandFmts 85 | 86 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 87 | 88 | x_axis = Typed(expected_type=TextAxis) 89 | y_axis = Typed(expected_type=NumericAxis) 90 | z_axis = Typed(expected_type=SeriesAxis) 91 | 92 | __elements__ = _SurfaceChartBase.__elements__ + ('axId',) 93 | 94 | def __init__(self, **kw): 95 | self.x_axis = TextAxis() 96 | self.y_axis = NumericAxis() 97 | self.z_axis = SeriesAxis() 98 | super(SurfaceChart3D, self).__init__(**kw) 99 | 100 | 101 | class SurfaceChart(SurfaceChart3D): 102 | 103 | tagname = "surfaceChart" 104 | 105 | wireframe = _SurfaceChartBase.wireframe 106 | ser = _SurfaceChartBase.ser 107 | bandFmts = _SurfaceChartBase.bandFmts 108 | 109 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 110 | 111 | __elements__ = SurfaceChart3D.__elements__ 112 | 113 | def __init__(self, **kw): 114 | super().__init__(**kw) 115 | self.y_axis.delete = True 116 | self.view3D.x_rotation = 90 117 | self.view3D.y_rotation = 0 118 | self.view3D.perspective = False 119 | self.view3D.right_angle_axes = False 120 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/text.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | from openpyxl.descriptors.serialisable import Serialisable 3 | from openpyxl.descriptors import ( 4 | Typed, 5 | Alias, 6 | Sequence, 7 | ) 8 | 9 | 10 | from openpyxl.drawing.text import ( 11 | RichTextProperties, 12 | ListStyle, 13 | Paragraph, 14 | ) 15 | 16 | from .data_source import StrRef 17 | 18 | 19 | class RichText(Serialisable): 20 | 21 | """ 22 | From the specification: 21.2.2.216 23 | 24 | This element specifies text formatting. The lstStyle element is not supported. 25 | """ 26 | 27 | tagname = "rich" 28 | 29 | bodyPr = Typed(expected_type=RichTextProperties) 30 | properties = Alias("bodyPr") 31 | lstStyle = Typed(expected_type=ListStyle, allow_none=True) 32 | p = Sequence(expected_type=Paragraph) 33 | paragraphs = Alias('p') 34 | 35 | __elements__ = ("bodyPr", "lstStyle", "p") 36 | 37 | def __init__(self, 38 | bodyPr=None, 39 | lstStyle=None, 40 | p=None, 41 | ): 42 | if bodyPr is None: 43 | bodyPr = RichTextProperties() 44 | self.bodyPr = bodyPr 45 | self.lstStyle = lstStyle 46 | if p is None: 47 | p = [Paragraph()] 48 | self.p = p 49 | 50 | 51 | class Text(Serialisable): 52 | 53 | """ 54 | The value can be either a cell reference or a text element 55 | If both are present then the reference will be used. 56 | """ 57 | 58 | tagname = "tx" 59 | 60 | strRef = Typed(expected_type=StrRef, allow_none=True) 61 | rich = Typed(expected_type=RichText, allow_none=True) 62 | 63 | __elements__ = ("strRef", "rich") 64 | 65 | def __init__(self, 66 | strRef=None, 67 | rich=None 68 | ): 69 | self.strRef = strRef 70 | if rich is None: 71 | rich = RichText() 72 | self.rich = rich 73 | 74 | 75 | def to_tree(self, tagname=None, idx=None, namespace=None): 76 | if self.strRef and self.rich: 77 | self.rich = None # can only have one 78 | return super().to_tree(tagname, idx, namespace) 79 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/title.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Alias, 7 | ) 8 | 9 | from openpyxl.descriptors.excel import ExtensionList 10 | from openpyxl.descriptors.nested import NestedBool 11 | 12 | from .text import Text, RichText 13 | from .layout import Layout 14 | from .shapes import GraphicalProperties 15 | 16 | from openpyxl.drawing.text import ( 17 | Paragraph, 18 | RegularTextRun, 19 | LineBreak, 20 | ParagraphProperties, 21 | CharacterProperties, 22 | ) 23 | 24 | 25 | class Title(Serialisable): 26 | tagname = "title" 27 | 28 | tx = Typed(expected_type=Text, allow_none=True) 29 | text = Alias('tx') 30 | layout = Typed(expected_type=Layout, allow_none=True) 31 | overlay = NestedBool(allow_none=True) 32 | spPr = Typed(expected_type=GraphicalProperties, allow_none=True) 33 | graphicalProperties = Alias('spPr') 34 | txPr = Typed(expected_type=RichText, allow_none=True) 35 | body = Alias('txPr') 36 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 37 | 38 | __elements__ = ('tx', 'layout', 'overlay', 'spPr', 'txPr') 39 | 40 | def __init__(self, 41 | tx=None, 42 | layout=None, 43 | overlay=None, 44 | spPr=None, 45 | txPr=None, 46 | extLst=None, 47 | ): 48 | if tx is None: 49 | tx = Text() 50 | self.tx = tx 51 | self.layout = layout 52 | self.overlay = overlay 53 | self.spPr = spPr 54 | self.txPr = txPr 55 | 56 | 57 | 58 | def title_maker(text): 59 | title = Title() 60 | paraprops = ParagraphProperties() 61 | paraprops.defRPr = CharacterProperties() 62 | paras = [Paragraph(r=[RegularTextRun(t=s)], pPr=paraprops) for s in text.split("\n")] 63 | 64 | title.tx.rich.paragraphs = paras 65 | return title 66 | 67 | 68 | class TitleDescriptor(Typed): 69 | 70 | expected_type = Title 71 | allow_none = True 72 | 73 | def __set__(self, instance, value): 74 | if isinstance(value, str): 75 | value = title_maker(value) 76 | super().__set__(instance, value) 77 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/trendline.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | String, 7 | Alias 8 | ) 9 | from openpyxl.descriptors.excel import ExtensionList 10 | from openpyxl.descriptors.nested import ( 11 | NestedBool, 12 | NestedInteger, 13 | NestedFloat, 14 | NestedSet 15 | ) 16 | 17 | from .data_source import NumFmt 18 | from .shapes import GraphicalProperties 19 | from .text import RichText, Text 20 | from .layout import Layout 21 | 22 | 23 | class TrendlineLabel(Serialisable): 24 | 25 | tagname = "trendlineLbl" 26 | 27 | layout = Typed(expected_type=Layout, allow_none=True) 28 | tx = Typed(expected_type=Text, allow_none=True) 29 | numFmt = Typed(expected_type=NumFmt, allow_none=True) 30 | spPr = Typed(expected_type=GraphicalProperties, allow_none=True) 31 | graphicalProperties = Alias("spPr") 32 | txPr = Typed(expected_type=RichText, allow_none=True) 33 | textProperties = Alias("txPr") 34 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 35 | 36 | __elements__ = ('layout', 'tx', 'numFmt', 'spPr', 'txPr') 37 | 38 | def __init__(self, 39 | layout=None, 40 | tx=None, 41 | numFmt=None, 42 | spPr=None, 43 | txPr=None, 44 | extLst=None, 45 | ): 46 | self.layout = layout 47 | self.tx = tx 48 | self.numFmt = numFmt 49 | self.spPr = spPr 50 | self.txPr = txPr 51 | 52 | 53 | class Trendline(Serialisable): 54 | 55 | tagname = "trendline" 56 | 57 | name = String(allow_none=True) 58 | spPr = Typed(expected_type=GraphicalProperties, allow_none=True) 59 | graphicalProperties = Alias('spPr') 60 | trendlineType = NestedSet(values=(['exp', 'linear', 'log', 'movingAvg', 'poly', 'power'])) 61 | order = NestedInteger(allow_none=True) 62 | period = NestedInteger(allow_none=True) 63 | forward = NestedFloat(allow_none=True) 64 | backward = NestedFloat(allow_none=True) 65 | intercept = NestedFloat(allow_none=True) 66 | dispRSqr = NestedBool(allow_none=True) 67 | dispEq = NestedBool(allow_none=True) 68 | trendlineLbl = Typed(expected_type=TrendlineLabel, allow_none=True) 69 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 70 | 71 | __elements__ = ('spPr', 'trendlineType', 'order', 'period', 'forward', 72 | 'backward', 'intercept', 'dispRSqr', 'dispEq', 'trendlineLbl') 73 | 74 | def __init__(self, 75 | name=None, 76 | spPr=None, 77 | trendlineType='linear', 78 | order=None, 79 | period=None, 80 | forward=None, 81 | backward=None, 82 | intercept=None, 83 | dispRSqr=None, 84 | dispEq=None, 85 | trendlineLbl=None, 86 | extLst=None, 87 | ): 88 | self.name = name 89 | self.spPr = spPr 90 | self.trendlineType = trendlineType 91 | self.order = order 92 | self.period = period 93 | self.forward = forward 94 | self.backward = backward 95 | self.intercept = intercept 96 | self.dispRSqr = dispRSqr 97 | self.dispEq = dispEq 98 | self.trendlineLbl = trendlineLbl 99 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chart/updown_bars.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import Typed 5 | from openpyxl.descriptors.excel import ExtensionList 6 | 7 | from .shapes import GraphicalProperties 8 | from .axis import ChartLines 9 | from .descriptors import NestedGapAmount 10 | 11 | 12 | class UpDownBars(Serialisable): 13 | 14 | tagname = "upbars" 15 | 16 | gapWidth = NestedGapAmount() 17 | upBars = Typed(expected_type=ChartLines, allow_none=True) 18 | downBars = Typed(expected_type=ChartLines, allow_none=True) 19 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 20 | 21 | __elements__ = ('gapWidth', 'upBars', 'downBars') 22 | 23 | def __init__(self, 24 | gapWidth=150, 25 | upBars=None, 26 | downBars=None, 27 | extLst=None, 28 | ): 29 | self.gapWidth = gapWidth 30 | self.upBars = upBars 31 | self.downBars = downBars 32 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chartsheet/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from .chartsheet import Chartsheet 4 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chartsheet/custom.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.worksheet.header_footer import HeaderFooter 4 | 5 | from openpyxl.descriptors import ( 6 | Bool, 7 | Integer, 8 | Set, 9 | Typed, 10 | Sequence 11 | ) 12 | from openpyxl.descriptors.excel import Guid 13 | from openpyxl.descriptors.serialisable import Serialisable 14 | from openpyxl.worksheet.page import ( 15 | PageMargins, 16 | PrintPageSetup 17 | ) 18 | 19 | 20 | class CustomChartsheetView(Serialisable): 21 | tagname = "customSheetView" 22 | 23 | guid = Guid() 24 | scale = Integer() 25 | state = Set(values=(['visible', 'hidden', 'veryHidden'])) 26 | zoomToFit = Bool(allow_none=True) 27 | pageMargins = Typed(expected_type=PageMargins, allow_none=True) 28 | pageSetup = Typed(expected_type=PrintPageSetup, allow_none=True) 29 | headerFooter = Typed(expected_type=HeaderFooter, allow_none=True) 30 | 31 | __elements__ = ('pageMargins', 'pageSetup', 'headerFooter') 32 | 33 | def __init__(self, 34 | guid=None, 35 | scale=None, 36 | state='visible', 37 | zoomToFit=None, 38 | pageMargins=None, 39 | pageSetup=None, 40 | headerFooter=None, 41 | ): 42 | self.guid = guid 43 | self.scale = scale 44 | self.state = state 45 | self.zoomToFit = zoomToFit 46 | self.pageMargins = pageMargins 47 | self.pageSetup = pageSetup 48 | self.headerFooter = headerFooter 49 | 50 | 51 | class CustomChartsheetViews(Serialisable): 52 | tagname = "customSheetViews" 53 | 54 | customSheetView = Sequence(expected_type=CustomChartsheetView, allow_none=True) 55 | 56 | __elements__ = ('customSheetView',) 57 | 58 | def __init__(self, 59 | customSheetView=None, 60 | ): 61 | self.customSheetView = customSheetView 62 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chartsheet/properties.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors import ( 4 | Bool, 5 | String, 6 | Typed 7 | ) 8 | from openpyxl.descriptors.serialisable import Serialisable 9 | from openpyxl.styles import Color 10 | 11 | 12 | class ChartsheetProperties(Serialisable): 13 | tagname = "sheetPr" 14 | 15 | published = Bool(allow_none=True) 16 | codeName = String(allow_none=True) 17 | tabColor = Typed(expected_type=Color, allow_none=True) 18 | 19 | __elements__ = ('tabColor',) 20 | 21 | def __init__(self, 22 | published=None, 23 | codeName=None, 24 | tabColor=None, 25 | ): 26 | self.published = published 27 | self.codeName = codeName 28 | self.tabColor = tabColor 29 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chartsheet/protection.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | from openpyxl.descriptors import (Bool, Integer, String) 4 | from openpyxl.descriptors.excel import Base64Binary 5 | from openpyxl.descriptors.serialisable import Serialisable 6 | 7 | from openpyxl.worksheet.protection import ( 8 | hash_password, 9 | _Protected 10 | ) 11 | 12 | 13 | class ChartsheetProtection(Serialisable, _Protected): 14 | tagname = "sheetProtection" 15 | 16 | algorithmName = String(allow_none=True) 17 | hashValue = Base64Binary(allow_none=True) 18 | saltValue = Base64Binary(allow_none=True) 19 | spinCount = Integer(allow_none=True) 20 | content = Bool(allow_none=True) 21 | objects = Bool(allow_none=True) 22 | 23 | __attrs__ = ("content", "objects", "password", "hashValue", "spinCount", "saltValue", "algorithmName") 24 | 25 | def __init__(self, 26 | content=None, 27 | objects=None, 28 | hashValue=None, 29 | spinCount=None, 30 | saltValue=None, 31 | algorithmName=None, 32 | password=None, 33 | ): 34 | self.content = content 35 | self.objects = objects 36 | self.hashValue = hashValue 37 | self.spinCount = spinCount 38 | self.saltValue = saltValue 39 | self.algorithmName = algorithmName 40 | if password is not None: 41 | self.password = password 42 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chartsheet/publish.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors import ( 4 | Bool, 5 | Integer, 6 | String, 7 | Set, 8 | Sequence 9 | ) 10 | from openpyxl.descriptors.serialisable import Serialisable 11 | 12 | 13 | class WebPublishItem(Serialisable): 14 | tagname = "webPublishItem" 15 | 16 | id = Integer() 17 | divId = String() 18 | sourceType = Set(values=(['sheet', 'printArea', 'autoFilter', 'range', 'chart', 'pivotTable', 'query', 'label'])) 19 | sourceRef = String() 20 | sourceObject = String(allow_none=True) 21 | destinationFile = String() 22 | title = String(allow_none=True) 23 | autoRepublish = Bool(allow_none=True) 24 | 25 | def __init__(self, 26 | id=None, 27 | divId=None, 28 | sourceType=None, 29 | sourceRef=None, 30 | sourceObject=None, 31 | destinationFile=None, 32 | title=None, 33 | autoRepublish=None, 34 | ): 35 | self.id = id 36 | self.divId = divId 37 | self.sourceType = sourceType 38 | self.sourceRef = sourceRef 39 | self.sourceObject = sourceObject 40 | self.destinationFile = destinationFile 41 | self.title = title 42 | self.autoRepublish = autoRepublish 43 | 44 | 45 | class WebPublishItems(Serialisable): 46 | tagname = "WebPublishItems" 47 | 48 | count = Integer(allow_none=True) 49 | webPublishItem = Sequence(expected_type=WebPublishItem, ) 50 | 51 | __elements__ = ('webPublishItem',) 52 | 53 | def __init__(self, 54 | count=None, 55 | webPublishItem=None, 56 | ): 57 | self.count = len(webPublishItem) 58 | self.webPublishItem = webPublishItem 59 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chartsheet/relation.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors import ( 4 | Integer, 5 | Alias 6 | ) 7 | from openpyxl.descriptors.excel import Relation 8 | from openpyxl.descriptors.serialisable import Serialisable 9 | 10 | 11 | class SheetBackgroundPicture(Serialisable): 12 | tagname = "picture" 13 | id = Relation() 14 | 15 | def __init__(self, id): 16 | self.id = id 17 | 18 | 19 | class DrawingHF(Serialisable): 20 | id = Relation() 21 | lho = Integer(allow_none=True) 22 | leftHeaderOddPages = Alias('lho') 23 | lhe = Integer(allow_none=True) 24 | leftHeaderEvenPages = Alias('lhe') 25 | lhf = Integer(allow_none=True) 26 | leftHeaderFirstPage = Alias('lhf') 27 | cho = Integer(allow_none=True) 28 | centerHeaderOddPages = Alias('cho') 29 | che = Integer(allow_none=True) 30 | centerHeaderEvenPages = Alias('che') 31 | chf = Integer(allow_none=True) 32 | centerHeaderFirstPage = Alias('chf') 33 | rho = Integer(allow_none=True) 34 | rightHeaderOddPages = Alias('rho') 35 | rhe = Integer(allow_none=True) 36 | rightHeaderEvenPages = Alias('rhe') 37 | rhf = Integer(allow_none=True) 38 | rightHeaderFirstPage = Alias('rhf') 39 | lfo = Integer(allow_none=True) 40 | leftFooterOddPages = Alias('lfo') 41 | lfe = Integer(allow_none=True) 42 | leftFooterEvenPages = Alias('lfe') 43 | lff = Integer(allow_none=True) 44 | leftFooterFirstPage = Alias('lff') 45 | cfo = Integer(allow_none=True) 46 | centerFooterOddPages = Alias('cfo') 47 | cfe = Integer(allow_none=True) 48 | centerFooterEvenPages = Alias('cfe') 49 | cff = Integer(allow_none=True) 50 | centerFooterFirstPage = Alias('cff') 51 | rfo = Integer(allow_none=True) 52 | rightFooterOddPages = Alias('rfo') 53 | rfe = Integer(allow_none=True) 54 | rightFooterEvenPages = Alias('rfe') 55 | rff = Integer(allow_none=True) 56 | rightFooterFirstPage = Alias('rff') 57 | 58 | def __init__(self, 59 | id=None, 60 | lho=None, 61 | lhe=None, 62 | lhf=None, 63 | cho=None, 64 | che=None, 65 | chf=None, 66 | rho=None, 67 | rhe=None, 68 | rhf=None, 69 | lfo=None, 70 | lfe=None, 71 | lff=None, 72 | cfo=None, 73 | cfe=None, 74 | cff=None, 75 | rfo=None, 76 | rfe=None, 77 | rff=None, 78 | ): 79 | self.id = id 80 | self.lho = lho 81 | self.lhe = lhe 82 | self.lhf = lhf 83 | self.cho = cho 84 | self.che = che 85 | self.chf = chf 86 | self.rho = rho 87 | self.rhe = rhe 88 | self.rhf = rhf 89 | self.lfo = lfo 90 | self.lfe = lfe 91 | self.lff = lff 92 | self.cfo = cfo 93 | self.cfe = cfe 94 | self.cff = cff 95 | self.rfo = rfo 96 | self.rfe = rfe 97 | self.rff = rff 98 | -------------------------------------------------------------------------------- /src/lib/openpyxl/chartsheet/views.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors import ( 4 | Bool, 5 | Integer, 6 | Typed, 7 | Sequence 8 | ) 9 | from openpyxl.descriptors.excel import ExtensionList 10 | from openpyxl.descriptors.serialisable import Serialisable 11 | 12 | 13 | class ChartsheetView(Serialisable): 14 | tagname = "sheetView" 15 | 16 | tabSelected = Bool(allow_none=True) 17 | zoomScale = Integer(allow_none=True) 18 | workbookViewId = Integer() 19 | zoomToFit = Bool(allow_none=True) 20 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 21 | 22 | __elements__ = () 23 | 24 | def __init__(self, 25 | tabSelected=None, 26 | zoomScale=None, 27 | workbookViewId=0, 28 | zoomToFit=True, 29 | extLst=None, 30 | ): 31 | self.tabSelected = tabSelected 32 | self.zoomScale = zoomScale 33 | self.workbookViewId = workbookViewId 34 | self.zoomToFit = zoomToFit 35 | 36 | 37 | class ChartsheetViewList(Serialisable): 38 | tagname = "sheetViews" 39 | 40 | sheetView = Sequence(expected_type=ChartsheetView, ) 41 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 42 | 43 | __elements__ = ('sheetView',) 44 | 45 | def __init__(self, 46 | sheetView=None, 47 | extLst=None, 48 | ): 49 | if sheetView is None: 50 | sheetView = [ChartsheetView()] 51 | self.sheetView = sheetView 52 | -------------------------------------------------------------------------------- /src/lib/openpyxl/comments/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | from .comments import Comment 5 | -------------------------------------------------------------------------------- /src/lib/openpyxl/comments/author.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | from openpyxl.descriptors.serialisable import Serialisable 5 | from openpyxl.descriptors import ( 6 | Sequence, 7 | Alias 8 | ) 9 | 10 | 11 | class AuthorList(Serialisable): 12 | 13 | tagname = "authors" 14 | 15 | author = Sequence(expected_type=str) 16 | authors = Alias("author") 17 | 18 | def __init__(self, 19 | author=(), 20 | ): 21 | self.author = author 22 | -------------------------------------------------------------------------------- /src/lib/openpyxl/comments/comments.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | class Comment: 5 | 6 | _parent = None 7 | 8 | def __init__(self, text, author, height=79, width=144): 9 | self.content = text 10 | self.author = author 11 | self.height = height 12 | self.width = width 13 | 14 | 15 | @property 16 | def parent(self): 17 | return self._parent 18 | 19 | 20 | def __eq__(self, other): 21 | return ( 22 | self.content == other.content 23 | and self.author == other.author 24 | ) 25 | 26 | def __repr__(self): 27 | return "Comment: {0} by {1}".format(self.content, self.author) 28 | 29 | 30 | def __copy__(self): 31 | """Create a detached copy of this comment.""" 32 | clone = self.__class__(self.content, self.author, self.height, self.width) 33 | return clone 34 | 35 | 36 | def bind(self, cell): 37 | """ 38 | Bind comment to a particular cell 39 | """ 40 | if cell is not None and self._parent is not None and self._parent != cell: 41 | fmt = "Comment already assigned to {0} in worksheet {1}. Cannot assign a comment to more than one cell" 42 | raise AttributeError(fmt.format(cell.coordinate, cell.parent.title)) 43 | self._parent = cell 44 | 45 | 46 | def unbind(self): 47 | """ 48 | Unbind a comment from a cell 49 | """ 50 | self._parent = None 51 | 52 | 53 | @property 54 | def text(self): 55 | """ 56 | Any comment text stripped of all formatting. 57 | """ 58 | return self.content 59 | 60 | @text.setter 61 | def text(self, value): 62 | self.content = value 63 | -------------------------------------------------------------------------------- /src/lib/openpyxl/compat/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from .numbers import NUMERIC_TYPES 4 | from .strings import safe_string 5 | 6 | import warnings 7 | from functools import wraps 8 | import inspect 9 | 10 | 11 | class DummyCode: 12 | 13 | pass 14 | 15 | 16 | # from https://github.com/tantale/deprecated/blob/master/deprecated/__init__.py 17 | # with an enhancement to update docstrings of deprecated functions 18 | string_types = (type(b''), type(u'')) 19 | def deprecated(reason): 20 | 21 | if isinstance(reason, string_types): 22 | 23 | def decorator(func1): 24 | 25 | if inspect.isclass(func1): 26 | fmt1 = "Call to deprecated class {name} ({reason})." 27 | else: 28 | fmt1 = "Call to deprecated function {name} ({reason})." 29 | 30 | @wraps(func1) 31 | def new_func1(*args, **kwargs): 32 | #warnings.simplefilter('default', DeprecationWarning) 33 | warnings.warn( 34 | fmt1.format(name=func1.__name__, reason=reason), 35 | category=DeprecationWarning, 36 | stacklevel=2 37 | ) 38 | return func1(*args, **kwargs) 39 | 40 | # Enhance docstring with a deprecation note 41 | deprecationNote = "\n\n.. note::\n Deprecated: " + reason 42 | if new_func1.__doc__: 43 | new_func1.__doc__ += deprecationNote 44 | else: 45 | new_func1.__doc__ = deprecationNote 46 | return new_func1 47 | 48 | return decorator 49 | 50 | elif inspect.isclass(reason) or inspect.isfunction(reason): 51 | raise TypeError("Reason for deprecation must be supplied") 52 | 53 | else: 54 | raise TypeError(repr(type(reason))) 55 | -------------------------------------------------------------------------------- /src/lib/openpyxl/compat/abc.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | try: 5 | from abc import ABC 6 | except ImportError: 7 | from abc import ABCMeta 8 | ABC = ABCMeta('ABC', (object, ), {}) 9 | -------------------------------------------------------------------------------- /src/lib/openpyxl/compat/numbers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from decimal import Decimal 4 | 5 | NUMERIC_TYPES = (int, float, Decimal) 6 | 7 | 8 | try: 9 | import numpy 10 | NUMPY = True 11 | except ImportError: 12 | NUMPY = False 13 | 14 | 15 | if NUMPY: 16 | NUMERIC_TYPES = NUMERIC_TYPES + (numpy.short, 17 | numpy.ushort, 18 | numpy.intc, 19 | numpy.uintc, 20 | numpy.int_, 21 | numpy.uint, 22 | numpy.longlong, 23 | numpy.ulonglong, 24 | numpy.half, 25 | numpy.float16, 26 | numpy.single, 27 | numpy.double, 28 | numpy.longdouble, 29 | numpy.int8, 30 | numpy.int16, 31 | numpy.int32, 32 | numpy.int64, 33 | numpy.uint8, 34 | numpy.uint16, 35 | numpy.uint32, 36 | numpy.uint64, 37 | numpy.intp, 38 | numpy.uintp, 39 | numpy.float32, 40 | numpy.float64, 41 | numpy.bool_, 42 | numpy.floating, 43 | numpy.integer) 44 | -------------------------------------------------------------------------------- /src/lib/openpyxl/compat/product.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | """ 4 | math.prod equivalent for < Python 3.8 5 | """ 6 | 7 | import functools 8 | import operator 9 | 10 | def product(sequence): 11 | return functools.reduce(operator.mul, sequence) 12 | 13 | 14 | try: 15 | from math import prod 16 | except ImportError: 17 | prod = product 18 | -------------------------------------------------------------------------------- /src/lib/openpyxl/compat/singleton.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | import weakref 4 | 5 | 6 | class Singleton(type): 7 | """ 8 | Singleton metaclass 9 | Based on Python Cookbook 3rd Edition Recipe 9.13 10 | Only one instance of a class can exist. Does not work with __slots__ 11 | """ 12 | 13 | def __init__(self, *args, **kw): 14 | super().__init__(*args, **kw) 15 | self.__instance = None 16 | 17 | def __call__(self, *args, **kw): 18 | if self.__instance is None: 19 | self.__instance = super().__call__(*args, **kw) 20 | return self.__instance 21 | 22 | 23 | class Cached(type): 24 | """ 25 | Caching metaclass 26 | Child classes will only create new instances of themselves if 27 | one doesn't already exist. Does not work with __slots__ 28 | """ 29 | 30 | def __init__(self, *args, **kw): 31 | super().__init__(*args, **kw) 32 | self.__cache = weakref.WeakValueDictionary() 33 | 34 | def __call__(self, *args): 35 | if args in self.__cache: 36 | return self.__cache[args] 37 | 38 | obj = super().__call__(*args) 39 | self.__cache[args] = obj 40 | return obj 41 | -------------------------------------------------------------------------------- /src/lib/openpyxl/compat/strings.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from datetime import datetime 4 | from math import isnan, isinf 5 | import sys 6 | 7 | VER = sys.version_info 8 | 9 | from .numbers import NUMERIC_TYPES 10 | 11 | 12 | def safe_string(value): 13 | """Safely and consistently format numeric values""" 14 | if isinstance(value, NUMERIC_TYPES): 15 | if isnan(value) or isinf(value): 16 | value = "" 17 | else: 18 | value = "%.16g" % value 19 | elif value is None: 20 | value = "none" 21 | elif isinstance(value, datetime): 22 | value = value.isoformat() 23 | elif not isinstance(value, str): 24 | value = str(value) 25 | return value 26 | -------------------------------------------------------------------------------- /src/lib/openpyxl/descriptors/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from .base import * 4 | from .sequence import Sequence 5 | 6 | 7 | class MetaStrict(type): 8 | 9 | def __new__(cls, clsname, bases, methods): 10 | for k, v in methods.items(): 11 | if isinstance(v, Descriptor): 12 | v.name = k 13 | return type.__new__(cls, clsname, bases, methods) 14 | 15 | 16 | class Strict(metaclass=MetaStrict): 17 | 18 | pass 19 | 20 | 21 | class MetaSerialisable(type): 22 | 23 | def __new__(cls, clsname, bases, methods): 24 | attrs = [] 25 | nested = [] 26 | elements = [] 27 | namespaced = [] 28 | for k, v in methods.items(): 29 | if isinstance(v, Descriptor): 30 | ns= getattr(v, 'namespace', None) 31 | if ns: 32 | namespaced.append((k, "{%s}%s" % (ns, k))) 33 | if getattr(v, 'nested', False): 34 | nested.append(k) 35 | elements.append(k) 36 | elif isinstance(v, Sequence): 37 | elements.append(k) 38 | elif isinstance(v, Typed): 39 | if hasattr(v.expected_type, 'to_tree'): 40 | elements.append(k) 41 | elif isinstance(v.expected_type, tuple): 42 | if any((hasattr(el, "to_tree") for el in v.expected_type)): 43 | # don't bind elements as attrs 44 | continue 45 | else: 46 | attrs.append(k) 47 | else: 48 | if not isinstance(v, Alias): 49 | attrs.append(k) 50 | 51 | if methods.get('__attrs__') is None: 52 | methods['__attrs__'] = tuple(attrs) 53 | methods['__namespaced__'] = tuple(namespaced) 54 | if methods.get('__nested__') is None: 55 | methods['__nested__'] = tuple(sorted(nested)) 56 | if methods.get('__elements__') is None: 57 | methods['__elements__'] = tuple(sorted(elements)) 58 | return MetaStrict.__new__(cls, clsname, bases, methods) 59 | -------------------------------------------------------------------------------- /src/lib/openpyxl/descriptors/container.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | """ 4 | Utility list for top level containers that contain one type of element 5 | 6 | Provides the necessary API to read and write XML 7 | """ 8 | 9 | from openpyxl.xml.functions import Element 10 | 11 | 12 | class ElementList(list): 13 | 14 | 15 | @property 16 | def tagname(self): 17 | raise NotImplementedError 18 | 19 | 20 | @property 21 | def expected_type(self): 22 | raise NotImplementedError 23 | 24 | 25 | @classmethod 26 | def from_tree(cls, tree): 27 | l = [cls.expected_type.from_tree(el) for el in tree] 28 | return cls(l) 29 | 30 | 31 | def to_tree(self): 32 | container = Element(self.tagname) 33 | for el in self: 34 | container.append(el.to_tree()) 35 | return container 36 | 37 | 38 | def append(self, value): 39 | if not isinstance(value, self.expected_type): 40 | raise TypeError(f"Value must of type {self.expected_type} {type(value)} provided") 41 | super().append(value) 42 | -------------------------------------------------------------------------------- /src/lib/openpyxl/descriptors/excel.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | """ 4 | Excel specific descriptors 5 | """ 6 | 7 | from openpyxl.xml.constants import REL_NS 8 | from openpyxl.compat import safe_string 9 | from openpyxl.xml.functions import Element 10 | 11 | from . import ( 12 | MatchPattern, 13 | MinMax, 14 | Integer, 15 | String, 16 | Sequence, 17 | ) 18 | from .serialisable import Serialisable 19 | 20 | 21 | class HexBinary(MatchPattern): 22 | 23 | pattern = "[0-9a-fA-F]+$" 24 | 25 | 26 | class UniversalMeasure(MatchPattern): 27 | 28 | pattern = r"[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)" 29 | 30 | 31 | class TextPoint(MinMax): 32 | """ 33 | Size in hundredths of points. 34 | In theory other units of measurement can be used but these are unbounded 35 | """ 36 | expected_type = int 37 | 38 | min = -400000 39 | max = 400000 40 | 41 | 42 | Coordinate = Integer 43 | 44 | 45 | class Percentage(MinMax): 46 | 47 | pattern = r"((100)|([0-9][0-9]?))(\.[0-9][0-9]?)?%" # strict 48 | min = -1000000 49 | max = 1000000 50 | 51 | def __set__(self, instance, value): 52 | if isinstance(value, str) and "%" in value: 53 | value = value.replace("%", "") 54 | value = int(float(value) * 1000) 55 | super().__set__(instance, value) 56 | 57 | 58 | class Extension(Serialisable): 59 | 60 | uri = String() 61 | 62 | def __init__(self, 63 | uri=None, 64 | ): 65 | self.uri = uri 66 | 67 | 68 | class ExtensionList(Serialisable): 69 | 70 | ext = Sequence(expected_type=Extension) 71 | 72 | def __init__(self, 73 | ext=(), 74 | ): 75 | self.ext = ext 76 | 77 | 78 | class Relation(String): 79 | 80 | namespace = REL_NS 81 | allow_none = True 82 | 83 | 84 | class Base64Binary(MatchPattern): 85 | # http://www.w3.org/TR/xmlschema11-2/#nt-Base64Binary 86 | pattern = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$" 87 | 88 | 89 | class Guid(MatchPattern): 90 | # https://msdn.microsoft.com/en-us/library/dd946381(v=office.12).aspx 91 | pattern = r"{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}" 92 | 93 | 94 | class CellRange(MatchPattern): 95 | 96 | pattern = r"^[$]?([A-Za-z]{1,3})[$]?(\d+)(:[$]?([A-Za-z]{1,3})[$]?(\d+)?)?$|^[A-Za-z]{1,3}:[A-Za-z]{1,3}$" 97 | allow_none = True 98 | 99 | def __set__(self, instance, value): 100 | 101 | if value is not None: 102 | value = value.upper() 103 | super().__set__(instance, value) 104 | 105 | 106 | def _explicit_none(tagname, value, namespace=None): 107 | """ 108 | Override serialisation because explicit none required 109 | """ 110 | if namespace is not None: 111 | tagname = "{%s}%s" % (namespace, tagname) 112 | return Element(tagname, val=safe_string(value)) 113 | -------------------------------------------------------------------------------- /src/lib/openpyxl/descriptors/namespace.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | def namespaced(obj, tagname, namespace=None): 5 | """ 6 | Utility to create a namespaced tag for an object 7 | """ 8 | 9 | namespace = getattr(obj, "namespace", None) or namespace 10 | if namespace is not None: 11 | tagname = "{%s}%s" % (namespace, tagname) 12 | return tagname 13 | -------------------------------------------------------------------------------- /src/lib/openpyxl/descriptors/nested.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | """ 4 | Generic serialisable classes 5 | """ 6 | from .base import ( 7 | Convertible, 8 | Bool, 9 | Descriptor, 10 | NoneSet, 11 | MinMax, 12 | Set, 13 | Float, 14 | Integer, 15 | String, 16 | ) 17 | from openpyxl.compat import safe_string 18 | from openpyxl.xml.functions import Element, localname, whitespace 19 | 20 | 21 | class Nested(Descriptor): 22 | 23 | nested = True 24 | attribute = "val" 25 | 26 | def __set__(self, instance, value): 27 | if hasattr(value, "tag"): 28 | tag = localname(value) 29 | if tag != self.name: 30 | raise ValueError("Tag does not match attribute") 31 | 32 | value = self.from_tree(value) 33 | super().__set__(instance, value) 34 | 35 | 36 | def from_tree(self, node): 37 | return node.get(self.attribute) 38 | 39 | 40 | def to_tree(self, tagname=None, value=None, namespace=None): 41 | namespace = getattr(self, "namespace", namespace) 42 | if value is not None: 43 | if namespace is not None: 44 | tagname = "{%s}%s" % (namespace, tagname) 45 | value = safe_string(value) 46 | return Element(tagname, {self.attribute:value}) 47 | 48 | 49 | class NestedValue(Nested, Convertible): 50 | """ 51 | Nested tag storing the value on the 'val' attribute 52 | """ 53 | pass 54 | 55 | 56 | class NestedText(NestedValue): 57 | """ 58 | Represents any nested tag with the value as the contents of the tag 59 | """ 60 | 61 | 62 | def from_tree(self, node): 63 | return node.text 64 | 65 | 66 | def to_tree(self, tagname=None, value=None, namespace=None): 67 | namespace = getattr(self, "namespace", namespace) 68 | if value is not None: 69 | if namespace is not None: 70 | tagname = "{%s}%s" % (namespace, tagname) 71 | el = Element(tagname) 72 | el.text = safe_string(value) 73 | whitespace(el) 74 | return el 75 | 76 | 77 | class NestedFloat(NestedValue, Float): 78 | 79 | pass 80 | 81 | 82 | class NestedInteger(NestedValue, Integer): 83 | 84 | pass 85 | 86 | 87 | class NestedString(NestedValue, String): 88 | 89 | pass 90 | 91 | 92 | class NestedBool(NestedValue, Bool): 93 | 94 | 95 | def from_tree(self, node): 96 | return node.get("val", True) 97 | 98 | 99 | class NestedNoneSet(Nested, NoneSet): 100 | 101 | pass 102 | 103 | 104 | class NestedSet(Nested, Set): 105 | 106 | pass 107 | 108 | 109 | class NestedMinMax(Nested, MinMax): 110 | 111 | pass 112 | 113 | 114 | class EmptyTag(Nested, Bool): 115 | 116 | """ 117 | Boolean if a tag exists or not. 118 | """ 119 | 120 | def from_tree(self, node): 121 | return True 122 | 123 | 124 | def to_tree(self, tagname=None, value=None, namespace=None): 125 | if value: 126 | namespace = getattr(self, "namespace", namespace) 127 | if namespace is not None: 128 | tagname = "{%s}%s" % (namespace, tagname) 129 | return Element(tagname) 130 | -------------------------------------------------------------------------------- /src/lib/openpyxl/descriptors/sequence.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.compat import safe_string 4 | from openpyxl.xml.functions import Element 5 | from openpyxl.utils.indexed_list import IndexedList 6 | 7 | from .base import Descriptor, Alias, _convert 8 | from .namespace import namespaced 9 | 10 | 11 | class Sequence(Descriptor): 12 | """ 13 | A sequence (list or tuple) that may only contain objects of the declared 14 | type 15 | """ 16 | 17 | expected_type = type(None) 18 | seq_types = (list, tuple) 19 | idx_base = 0 20 | unique = False 21 | container = list 22 | 23 | 24 | def __set__(self, instance, seq): 25 | if not isinstance(seq, self.seq_types): 26 | raise TypeError("Value must be a sequence") 27 | seq = self.container(_convert(self.expected_type, value) for value in seq) 28 | if self.unique: 29 | seq = IndexedList(seq) 30 | 31 | super().__set__(instance, seq) 32 | 33 | 34 | def to_tree(self, tagname, obj, namespace=None): 35 | """ 36 | Convert the sequence represented by the descriptor to an XML element 37 | """ 38 | for idx, v in enumerate(obj, self.idx_base): 39 | if hasattr(v, "to_tree"): 40 | el = v.to_tree(tagname, idx) 41 | else: 42 | tagname = namespaced(obj, tagname, namespace) 43 | el = Element(tagname) 44 | el.text = safe_string(v) 45 | yield el 46 | 47 | 48 | class UniqueSequence(Sequence): 49 | """ 50 | Use a set to keep values unique 51 | """ 52 | seq_types = (list, tuple, set) 53 | container = set 54 | 55 | 56 | class ValueSequence(Sequence): 57 | """ 58 | A sequence of primitive types that are stored as a single attribute. 59 | "val" is the default attribute 60 | """ 61 | 62 | attribute = "val" 63 | 64 | 65 | def to_tree(self, tagname, obj, namespace=None): 66 | tagname = namespaced(self, tagname, namespace) 67 | for v in obj: 68 | yield Element(tagname, {self.attribute:safe_string(v)}) 69 | 70 | 71 | def from_tree(self, node): 72 | 73 | return node.get(self.attribute) 74 | 75 | 76 | class NestedSequence(Sequence): 77 | """ 78 | Wrap a sequence in an containing object 79 | """ 80 | 81 | count = False 82 | 83 | def to_tree(self, tagname, obj, namespace=None): 84 | tagname = namespaced(self, tagname, namespace) 85 | container = Element(tagname) 86 | if self.count: 87 | container.set('count', str(len(obj))) 88 | for v in obj: 89 | container.append(v.to_tree()) 90 | return container 91 | 92 | 93 | def from_tree(self, node): 94 | return [self.expected_type.from_tree(el) for el in node] 95 | 96 | 97 | class MultiSequence(Sequence): 98 | """ 99 | Sequences can contain objects with different tags 100 | """ 101 | 102 | def __set__(self, instance, seq): 103 | if not isinstance(seq, (tuple, list)): 104 | raise ValueError("Value must be a sequence") 105 | seq = list(seq) 106 | Descriptor.__set__(self, instance, seq) 107 | 108 | 109 | def to_tree(self, tagname, obj, namespace=None): 110 | """ 111 | Convert the sequence represented by the descriptor to an XML element 112 | """ 113 | for v in obj: 114 | el = v.to_tree(namespace=namespace) 115 | yield el 116 | 117 | 118 | class MultiSequencePart(Alias): 119 | """ 120 | Allow a multisequence to be built up from parts 121 | 122 | Excluded from the instance __elements__ or __attrs__ as is effectively an Alias 123 | """ 124 | 125 | def __init__(self, expected_type, store): 126 | self.expected_type = expected_type 127 | self.store = store 128 | 129 | 130 | def __set__(self, instance, value): 131 | value = _convert(self.expected_type, value) 132 | instance.__dict__[self.store].append(value) 133 | 134 | 135 | def __get__(self, instance, cls): 136 | return self 137 | -------------------------------------------------------------------------------- /src/lib/openpyxl/descriptors/slots.py: -------------------------------------------------------------------------------- 1 | # Metaclass for mixing slots and descriptors 2 | # From "Programming in Python 3" by Mark Summerfield Ch.8 p. 383 3 | 4 | class AutoSlotProperties(type): 5 | 6 | def __new__(mcl, classname, bases, dictionary): 7 | slots = list(dictionary.get("__slots__", [])) 8 | for getter_name in [key for key in dictionary if key.startswith("get_")]: 9 | name = getter_name 10 | slots.append("__" + name) 11 | getter = dictionary.pop(getter_name) 12 | setter = dictionary.get(setter_name, None) 13 | if (setter is not None 14 | and isinstance(setter, collections.Callable)): 15 | del dictionary[setter_name] 16 | dictionary[name] = property(getter. setter) 17 | dictionary["__slots__"] = tuple(slots) 18 | return super().__new__(mcl, classname, bases, dictionary) 19 | -------------------------------------------------------------------------------- /src/lib/openpyxl/drawing/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | from .drawing import Drawing 5 | -------------------------------------------------------------------------------- /src/lib/openpyxl/drawing/drawing.py: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (c) 2010-2024 openpyxl 3 | 4 | import math 5 | 6 | from openpyxl.utils.units import pixels_to_EMU 7 | 8 | 9 | class Drawing: 10 | """ a drawing object - eg container for shapes or charts 11 | we assume user specifies dimensions in pixels; units are 12 | converted to EMU in the drawing part 13 | """ 14 | 15 | count = 0 16 | 17 | def __init__(self): 18 | 19 | self.name = '' 20 | self.description = '' 21 | self.coordinates = ((1, 2), (16, 8)) 22 | self.left = 0 23 | self.top = 0 24 | self._width = 21 # default in px 25 | self._height = 192 #default in px 26 | self.resize_proportional = False 27 | self.rotation = 0 28 | self.anchortype = "absolute" 29 | self.anchorcol = 0 # left cell 30 | self.anchorrow = 0 # top row 31 | 32 | 33 | @property 34 | def width(self): 35 | return self._width 36 | 37 | 38 | @width.setter 39 | def width(self, w): 40 | if self.resize_proportional and w: 41 | ratio = self._height / self._width 42 | self._height = round(ratio * w) 43 | self._width = w 44 | 45 | 46 | @property 47 | def height(self): 48 | return self._height 49 | 50 | 51 | @height.setter 52 | def height(self, h): 53 | if self.resize_proportional and h: 54 | ratio = self._width / self._height 55 | self._width = round(ratio * h) 56 | self._height = h 57 | 58 | 59 | def set_dimension(self, w=0, h=0): 60 | 61 | xratio = w / self._width 62 | yratio = h / self._height 63 | 64 | if self.resize_proportional and w and h: 65 | if (xratio * self._height) < h: 66 | self._height = math.ceil(xratio * self._height) 67 | self._width = w 68 | else: 69 | self._width = math.ceil(yratio * self._width) 70 | self._height = h 71 | 72 | 73 | @property 74 | def anchor(self): 75 | from .spreadsheet_drawing import ( 76 | OneCellAnchor, 77 | TwoCellAnchor, 78 | AbsoluteAnchor) 79 | if self.anchortype == "absolute": 80 | anchor = AbsoluteAnchor() 81 | anchor.pos.x = pixels_to_EMU(self.left) 82 | anchor.pos.y = pixels_to_EMU(self.top) 83 | 84 | elif self.anchortype == "oneCell": 85 | anchor = OneCellAnchor() 86 | anchor._from.col = self.anchorcol 87 | anchor._from.row = self.anchorrow 88 | 89 | anchor.ext.width = pixels_to_EMU(self._width) 90 | anchor.ext.height = pixels_to_EMU(self._height) 91 | 92 | return anchor 93 | -------------------------------------------------------------------------------- /src/lib/openpyxl/drawing/image.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from io import BytesIO 4 | 5 | try: 6 | from PIL import Image as PILImage 7 | except ImportError: 8 | PILImage = False 9 | 10 | 11 | def _import_image(img): 12 | if not PILImage: 13 | raise ImportError('You must install Pillow to fetch image objects') 14 | 15 | if not isinstance(img, PILImage.Image): 16 | img = PILImage.open(img) 17 | 18 | return img 19 | 20 | 21 | class Image: 22 | """Image in a spreadsheet""" 23 | 24 | _id = 1 25 | _path = "/xl/media/image{0}.{1}" 26 | anchor = "A1" 27 | 28 | def __init__(self, img): 29 | 30 | self.ref = img 31 | mark_to_close = isinstance(img, str) 32 | image = _import_image(img) 33 | self.width, self.height = image.size 34 | 35 | try: 36 | self.format = image.format.lower() 37 | except AttributeError: 38 | self.format = "png" 39 | if mark_to_close: 40 | # PIL instances created for metadata should be closed. 41 | image.close() 42 | 43 | 44 | def _data(self): 45 | """ 46 | Return image data, convert to supported types if necessary 47 | """ 48 | img = _import_image(self.ref) 49 | # don't convert these file formats 50 | if self.format in ['gif', 'jpeg', 'png']: 51 | img.fp.seek(0) 52 | fp = img.fp 53 | else: 54 | fp = BytesIO() 55 | img.save(fp, format="png") 56 | fp.seek(0) 57 | 58 | data = fp.read() 59 | fp.close() 60 | return data 61 | 62 | 63 | @property 64 | def path(self): 65 | return self._path.format(self._id, self.format) 66 | -------------------------------------------------------------------------------- /src/lib/openpyxl/drawing/relation.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.xml.constants import CHART_NS 4 | 5 | from openpyxl.descriptors.serialisable import Serialisable 6 | from openpyxl.descriptors.excel import Relation 7 | 8 | 9 | class ChartRelation(Serialisable): 10 | 11 | tagname = "chart" 12 | namespace = CHART_NS 13 | 14 | id = Relation() 15 | 16 | def __init__(self, id): 17 | self.id = id 18 | -------------------------------------------------------------------------------- /src/lib/openpyxl/drawing/xdr.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | """ 4 | Spreadsheet Drawing has some copies of Drawing ML elements 5 | """ 6 | 7 | from .geometry import Point2D, PositiveSize2D, Transform2D 8 | 9 | 10 | class XDRPoint2D(Point2D): 11 | 12 | namespace = None 13 | x = Point2D.x 14 | y = Point2D.y 15 | 16 | 17 | class XDRPositiveSize2D(PositiveSize2D): 18 | 19 | namespace = None 20 | cx = PositiveSize2D.cx 21 | cy = PositiveSize2D.cy 22 | 23 | 24 | class XDRTransform2D(Transform2D): 25 | 26 | namespace = None 27 | rot = Transform2D.rot 28 | flipH = Transform2D.flipH 29 | flipV = Transform2D.flipV 30 | off = Transform2D.off 31 | ext = Transform2D.ext 32 | chOff = Transform2D.chOff 33 | chExt = Transform2D.chExt 34 | -------------------------------------------------------------------------------- /src/lib/openpyxl/formatting/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from .rule import Rule 4 | -------------------------------------------------------------------------------- /src/lib/openpyxl/formatting/formatting.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from collections import OrderedDict 4 | 5 | from openpyxl.descriptors import ( 6 | Bool, 7 | Sequence, 8 | Alias, 9 | Convertible, 10 | ) 11 | from openpyxl.descriptors.serialisable import Serialisable 12 | 13 | from .rule import Rule 14 | 15 | from openpyxl.worksheet.cell_range import MultiCellRange 16 | 17 | class ConditionalFormatting(Serialisable): 18 | 19 | tagname = "conditionalFormatting" 20 | 21 | sqref = Convertible(expected_type=MultiCellRange) 22 | cells = Alias("sqref") 23 | pivot = Bool(allow_none=True) 24 | cfRule = Sequence(expected_type=Rule) 25 | rules = Alias("cfRule") 26 | 27 | 28 | def __init__(self, sqref=(), pivot=None, cfRule=(), extLst=None): 29 | self.sqref = sqref 30 | self.pivot = pivot 31 | self.cfRule = cfRule 32 | 33 | 34 | def __eq__(self, other): 35 | if not isinstance(other, self.__class__): 36 | return False 37 | return self.sqref == other.sqref 38 | 39 | 40 | def __hash__(self): 41 | return hash(self.sqref) 42 | 43 | 44 | def __repr__(self): 45 | return "<{cls} {cells}>".format(cls=self.__class__.__name__, cells=self.sqref) 46 | 47 | 48 | def __contains__(self, coord): 49 | """ 50 | Check whether a certain cell is affected by the formatting 51 | """ 52 | return coord in self.sqref 53 | 54 | 55 | class ConditionalFormattingList: 56 | """Conditional formatting rules.""" 57 | 58 | 59 | def __init__(self): 60 | self._cf_rules = OrderedDict() 61 | self.max_priority = 0 62 | 63 | 64 | def add(self, range_string, cfRule): 65 | """Add a rule such as ColorScaleRule, FormulaRule or CellIsRule 66 | 67 | The priority will be added automatically. 68 | """ 69 | cf = range_string 70 | if isinstance(range_string, str): 71 | cf = ConditionalFormatting(range_string) 72 | if not isinstance(cfRule, Rule): 73 | raise ValueError("Only instances of openpyxl.formatting.rule.Rule may be added") 74 | rule = cfRule 75 | self.max_priority += 1 76 | if not rule.priority: 77 | rule.priority = self.max_priority 78 | 79 | self._cf_rules.setdefault(cf, []).append(rule) 80 | 81 | 82 | def __bool__(self): 83 | return bool(self._cf_rules) 84 | 85 | 86 | def __len__(self): 87 | return len(self._cf_rules) 88 | 89 | 90 | def __iter__(self): 91 | for cf, rules in self._cf_rules.items(): 92 | cf.rules = rules 93 | yield cf 94 | 95 | 96 | def __getitem__(self, key): 97 | """ 98 | Get the rules for a cell range 99 | """ 100 | if isinstance(key, str): 101 | key = ConditionalFormatting(sqref=key) 102 | return self._cf_rules[key] 103 | 104 | 105 | def __delitem__(self, key): 106 | key = ConditionalFormatting(sqref=key) 107 | del self._cf_rules[key] 108 | 109 | 110 | def __setitem__(self, key, rule): 111 | """ 112 | Add a rule for a cell range 113 | """ 114 | self.add(key, rule) 115 | -------------------------------------------------------------------------------- /src/lib/openpyxl/formula/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from .tokenizer import Tokenizer 4 | -------------------------------------------------------------------------------- /src/lib/openpyxl/packaging/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Stuff related to Office OpenXML packaging: relationships, archive, content types. 3 | """ 4 | -------------------------------------------------------------------------------- /src/lib/openpyxl/packaging/interface.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from abc import abstractproperty 4 | from openpyxl.compat.abc import ABC 5 | 6 | 7 | class ISerialisableFile(ABC): 8 | 9 | """ 10 | Interface for Serialisable classes that represent files in the archive 11 | """ 12 | 13 | 14 | @abstractproperty 15 | def id(self): 16 | """ 17 | Object id making it unique 18 | """ 19 | pass 20 | 21 | 22 | @abstractproperty 23 | def _path(self): 24 | """ 25 | File path in the archive 26 | """ 27 | pass 28 | 29 | 30 | @abstractproperty 31 | def _namespace(self): 32 | """ 33 | Qualified namespace when serialised 34 | """ 35 | pass 36 | 37 | 38 | @abstractproperty 39 | def _type(self): 40 | """ 41 | The content type for the manifest 42 | """ 43 | 44 | 45 | @abstractproperty 46 | def _rel_type(self): 47 | """ 48 | The content type for relationships 49 | """ 50 | 51 | 52 | @abstractproperty 53 | def _rel_id(self): 54 | """ 55 | Links object with parent 56 | """ 57 | -------------------------------------------------------------------------------- /src/lib/openpyxl/pivot/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | -------------------------------------------------------------------------------- /src/lib/openpyxl/pivot/record.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Integer, 7 | Sequence, 8 | ) 9 | from openpyxl.descriptors.sequence import ( 10 | MultiSequence, 11 | MultiSequencePart, 12 | ) 13 | from openpyxl.descriptors.excel import ExtensionList 14 | from openpyxl.descriptors.nested import ( 15 | NestedInteger, 16 | NestedBool, 17 | ) 18 | 19 | from openpyxl.xml.constants import SHEET_MAIN_NS 20 | from openpyxl.xml.functions import tostring 21 | 22 | from .fields import ( 23 | Boolean, 24 | Error, 25 | Missing, 26 | Number, 27 | Text, 28 | TupleList, 29 | DateTimeField, 30 | Index, 31 | ) 32 | 33 | 34 | class Record(Serialisable): 35 | 36 | tagname = "r" 37 | 38 | _fields = MultiSequence() 39 | m = MultiSequencePart(expected_type=Missing, store="_fields") 40 | n = MultiSequencePart(expected_type=Number, store="_fields") 41 | b = MultiSequencePart(expected_type=Boolean, store="_fields") 42 | e = MultiSequencePart(expected_type=Error, store="_fields") 43 | s = MultiSequencePart(expected_type=Text, store="_fields") 44 | d = MultiSequencePart(expected_type=DateTimeField, store="_fields") 45 | x = MultiSequencePart(expected_type=Index, store="_fields") 46 | 47 | 48 | def __init__(self, 49 | _fields=(), 50 | m=None, 51 | n=None, 52 | b=None, 53 | e=None, 54 | s=None, 55 | d=None, 56 | x=None, 57 | ): 58 | self._fields = _fields 59 | 60 | 61 | class RecordList(Serialisable): 62 | 63 | mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml" 64 | rel_type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheRecords" 65 | _id = 1 66 | _path = "/xl/pivotCache/pivotCacheRecords{0}.xml" 67 | 68 | tagname ="pivotCacheRecords" 69 | 70 | r = Sequence(expected_type=Record, allow_none=True) 71 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 72 | 73 | __elements__ = ('r', ) 74 | __attrs__ = ('count', ) 75 | 76 | def __init__(self, 77 | count=None, 78 | r=(), 79 | extLst=None, 80 | ): 81 | self.r = r 82 | self.extLst = extLst 83 | 84 | 85 | @property 86 | def count(self): 87 | return len(self.r) 88 | 89 | 90 | def to_tree(self): 91 | tree = super().to_tree() 92 | tree.set("xmlns", SHEET_MAIN_NS) 93 | return tree 94 | 95 | 96 | @property 97 | def path(self): 98 | return self._path.format(self._id) 99 | 100 | 101 | def _write(self, archive, manifest): 102 | """ 103 | Write to zipfile and update manifest 104 | """ 105 | xml = tostring(self.to_tree()) 106 | archive.writestr(self.path[1:], xml) 107 | manifest.append(self) 108 | 109 | 110 | def _write_rels(self, archive, manifest): 111 | pass 112 | -------------------------------------------------------------------------------- /src/lib/openpyxl/reader/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | -------------------------------------------------------------------------------- /src/lib/openpyxl/reader/drawings.py: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (c) 2010-2024 openpyxl 3 | 4 | 5 | from io import BytesIO 6 | from warnings import warn 7 | 8 | from openpyxl.xml.functions import fromstring 9 | from openpyxl.xml.constants import IMAGE_NS 10 | from openpyxl.packaging.relationship import ( 11 | get_rel, 12 | get_rels_path, 13 | get_dependents, 14 | ) 15 | from openpyxl.drawing.spreadsheet_drawing import SpreadsheetDrawing 16 | from openpyxl.drawing.image import Image, PILImage 17 | from openpyxl.chart.chartspace import ChartSpace 18 | from openpyxl.chart.reader import read_chart 19 | 20 | 21 | def find_images(archive, path): 22 | """ 23 | Given the path to a drawing file extract charts and images 24 | 25 | Ignore errors due to unsupported parts of DrawingML 26 | """ 27 | 28 | src = archive.read(path) 29 | tree = fromstring(src) 30 | try: 31 | drawing = SpreadsheetDrawing.from_tree(tree) 32 | except TypeError: 33 | warn("DrawingML support is incomplete and limited to charts and images only. Shapes and drawings will be lost.") 34 | return [], [] 35 | 36 | rels_path = get_rels_path(path) 37 | deps = [] 38 | if rels_path in archive.namelist(): 39 | deps = get_dependents(archive, rels_path) 40 | 41 | charts = [] 42 | for rel in drawing._chart_rels: 43 | try: 44 | cs = get_rel(archive, deps, rel.id, ChartSpace) 45 | except TypeError as e: 46 | warn(f"Unable to read chart {rel.id} from {path} {e}") 47 | continue 48 | chart = read_chart(cs) 49 | chart.anchor = rel.anchor 50 | charts.append(chart) 51 | 52 | images = [] 53 | if not PILImage: # Pillow not installed, drop images 54 | return charts, images 55 | 56 | for rel in drawing._blip_rels: 57 | dep = deps.get(rel.embed) 58 | if dep.Type == IMAGE_NS: 59 | try: 60 | image = Image(BytesIO(archive.read(dep.target))) 61 | except OSError: 62 | msg = "The image {0} will be removed because it cannot be read".format(dep.target) 63 | warn(msg) 64 | continue 65 | if image.format.upper() == "WMF": # cannot save 66 | msg = "{0} image format is not supported so the image is being dropped".format(image.format) 67 | warn(msg) 68 | continue 69 | image.anchor = rel.anchor 70 | images.append(image) 71 | return charts, images 72 | -------------------------------------------------------------------------------- /src/lib/openpyxl/reader/strings.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.cell.text import Text 4 | 5 | from openpyxl.xml.functions import iterparse 6 | from openpyxl.xml.constants import SHEET_MAIN_NS 7 | from openpyxl.cell.rich_text import CellRichText 8 | 9 | 10 | def read_string_table(xml_source): 11 | """Read in all shared strings in the table""" 12 | 13 | strings = [] 14 | STRING_TAG = '{%s}si' % SHEET_MAIN_NS 15 | 16 | for _, node in iterparse(xml_source): 17 | if node.tag == STRING_TAG: 18 | text = Text.from_tree(node).content 19 | text = text.replace('x005F_', '') 20 | node.clear() 21 | 22 | strings.append(text) 23 | 24 | return strings 25 | 26 | 27 | def read_rich_text(xml_source): 28 | """Read in all shared strings in the table""" 29 | 30 | strings = [] 31 | STRING_TAG = '{%s}si' % SHEET_MAIN_NS 32 | 33 | for _, node in iterparse(xml_source): 34 | if node.tag == STRING_TAG: 35 | text = CellRichText.from_tree(node) 36 | if len(text) == 0: 37 | text = '' 38 | elif len(text) == 1 and isinstance(text[0], str): 39 | text = text[0] 40 | node.clear() 41 | 42 | strings.append(text) 43 | 44 | return strings 45 | -------------------------------------------------------------------------------- /src/lib/openpyxl/styles/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | from .alignment import Alignment 5 | from .borders import Border, Side 6 | from .colors import Color 7 | from .fills import PatternFill, GradientFill, Fill 8 | from .fonts import Font, DEFAULT_FONT 9 | from .numbers import NumberFormatDescriptor, is_date_format, is_builtin 10 | from .protection import Protection 11 | from .named_styles import NamedStyle 12 | -------------------------------------------------------------------------------- /src/lib/openpyxl/styles/alignment.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.compat import safe_string 4 | 5 | from openpyxl.descriptors import Bool, MinMax, Min, Alias, NoneSet 6 | from openpyxl.descriptors.serialisable import Serialisable 7 | 8 | 9 | horizontal_alignments = ( 10 | "general", "left", "center", "right", "fill", "justify", "centerContinuous", 11 | "distributed", ) 12 | vertical_aligments = ( 13 | "top", "center", "bottom", "justify", "distributed", 14 | ) 15 | 16 | class Alignment(Serialisable): 17 | """Alignment options for use in styles.""" 18 | 19 | tagname = "alignment" 20 | 21 | horizontal = NoneSet(values=horizontal_alignments) 22 | vertical = NoneSet(values=vertical_aligments) 23 | textRotation = NoneSet(values=range(181)) 24 | textRotation.values.add(255) 25 | text_rotation = Alias('textRotation') 26 | wrapText = Bool(allow_none=True) 27 | wrap_text = Alias('wrapText') 28 | shrinkToFit = Bool(allow_none=True) 29 | shrink_to_fit = Alias('shrinkToFit') 30 | indent = MinMax(min=0, max=255) 31 | relativeIndent = MinMax(min=-255, max=255) 32 | justifyLastLine = Bool(allow_none=True) 33 | readingOrder = Min(min=0) 34 | 35 | def __init__(self, horizontal=None, vertical=None, 36 | textRotation=0, wrapText=None, shrinkToFit=None, indent=0, relativeIndent=0, 37 | justifyLastLine=None, readingOrder=0, text_rotation=None, 38 | wrap_text=None, shrink_to_fit=None, mergeCell=None): 39 | self.horizontal = horizontal 40 | self.vertical = vertical 41 | self.indent = indent 42 | self.relativeIndent = relativeIndent 43 | self.justifyLastLine = justifyLastLine 44 | self.readingOrder = readingOrder 45 | if text_rotation is not None: 46 | textRotation = text_rotation 47 | if textRotation is not None: 48 | self.textRotation = int(textRotation) 49 | if wrap_text is not None: 50 | wrapText = wrap_text 51 | self.wrapText = wrapText 52 | if shrink_to_fit is not None: 53 | shrinkToFit = shrink_to_fit 54 | self.shrinkToFit = shrinkToFit 55 | # mergeCell is vestigial 56 | 57 | 58 | def __iter__(self): 59 | for attr in self.__attrs__: 60 | value = getattr(self, attr) 61 | if value is not None and value != 0: 62 | yield attr, safe_string(value) 63 | -------------------------------------------------------------------------------- /src/lib/openpyxl/styles/borders.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.compat import safe_string 4 | from openpyxl.descriptors import ( 5 | NoneSet, 6 | Typed, 7 | Bool, 8 | Alias, 9 | Sequence, 10 | Integer, 11 | ) 12 | from openpyxl.descriptors.serialisable import Serialisable 13 | 14 | from .colors import ColorDescriptor 15 | 16 | 17 | BORDER_NONE = None 18 | BORDER_DASHDOT = 'dashDot' 19 | BORDER_DASHDOTDOT = 'dashDotDot' 20 | BORDER_DASHED = 'dashed' 21 | BORDER_DOTTED = 'dotted' 22 | BORDER_DOUBLE = 'double' 23 | BORDER_HAIR = 'hair' 24 | BORDER_MEDIUM = 'medium' 25 | BORDER_MEDIUMDASHDOT = 'mediumDashDot' 26 | BORDER_MEDIUMDASHDOTDOT = 'mediumDashDotDot' 27 | BORDER_MEDIUMDASHED = 'mediumDashed' 28 | BORDER_SLANTDASHDOT = 'slantDashDot' 29 | BORDER_THICK = 'thick' 30 | BORDER_THIN = 'thin' 31 | 32 | 33 | class Side(Serialisable): 34 | 35 | """Border options for use in styles. 36 | Caution: if you do not specify a border_style, other attributes will 37 | have no effect !""" 38 | 39 | 40 | color = ColorDescriptor(allow_none=True) 41 | style = NoneSet(values=('dashDot','dashDotDot', 'dashed','dotted', 42 | 'double','hair', 'medium', 'mediumDashDot', 'mediumDashDotDot', 43 | 'mediumDashed', 'slantDashDot', 'thick', 'thin') 44 | ) 45 | border_style = Alias('style') 46 | 47 | def __init__(self, style=None, color=None, border_style=None): 48 | if border_style is not None: 49 | style = border_style 50 | self.style = style 51 | self.color = color 52 | 53 | 54 | class Border(Serialisable): 55 | """Border positioning for use in styles.""" 56 | 57 | tagname = "border" 58 | 59 | __elements__ = ('start', 'end', 'left', 'right', 'top', 'bottom', 60 | 'diagonal', 'vertical', 'horizontal') 61 | 62 | # child elements 63 | start = Typed(expected_type=Side, allow_none=True) 64 | end = Typed(expected_type=Side, allow_none=True) 65 | left = Typed(expected_type=Side, allow_none=True) 66 | right = Typed(expected_type=Side, allow_none=True) 67 | top = Typed(expected_type=Side, allow_none=True) 68 | bottom = Typed(expected_type=Side, allow_none=True) 69 | diagonal = Typed(expected_type=Side, allow_none=True) 70 | vertical = Typed(expected_type=Side, allow_none=True) 71 | horizontal = Typed(expected_type=Side, allow_none=True) 72 | # attributes 73 | outline = Bool() 74 | diagonalUp = Bool() 75 | diagonalDown = Bool() 76 | 77 | def __init__(self, left=None, right=None, top=None, 78 | bottom=None, diagonal=None, diagonal_direction=None, 79 | vertical=None, horizontal=None, diagonalUp=False, diagonalDown=False, 80 | outline=True, start=None, end=None): 81 | self.left = left 82 | self.right = right 83 | self.top = top 84 | self.bottom = bottom 85 | self.diagonal = diagonal 86 | self.vertical = vertical 87 | self.horizontal = horizontal 88 | self.diagonal_direction = diagonal_direction 89 | self.diagonalUp = diagonalUp 90 | self.diagonalDown = diagonalDown 91 | self.outline = outline 92 | self.start = start 93 | self.end = end 94 | 95 | def __iter__(self): 96 | for attr in self.__attrs__: 97 | value = getattr(self, attr) 98 | if value and attr != "outline": 99 | yield attr, safe_string(value) 100 | elif attr == "outline" and not value: 101 | yield attr, safe_string(value) 102 | 103 | DEFAULT_BORDER = Border(left=Side(), right=Side(), top=Side(), bottom=Side(), diagonal=Side()) 104 | -------------------------------------------------------------------------------- /src/lib/openpyxl/styles/differential.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors import ( 4 | Typed, 5 | Sequence, 6 | Alias, 7 | ) 8 | from openpyxl.descriptors.serialisable import Serialisable 9 | from openpyxl.styles import ( 10 | Font, 11 | Fill, 12 | Border, 13 | Alignment, 14 | Protection, 15 | ) 16 | from .numbers import NumberFormat 17 | 18 | 19 | class DifferentialStyle(Serialisable): 20 | 21 | tagname = "dxf" 22 | 23 | __elements__ = ("font", "numFmt", "fill", "alignment", "border", "protection") 24 | 25 | font = Typed(expected_type=Font, allow_none=True) 26 | numFmt = Typed(expected_type=NumberFormat, allow_none=True) 27 | fill = Typed(expected_type=Fill, allow_none=True) 28 | alignment = Typed(expected_type=Alignment, allow_none=True) 29 | border = Typed(expected_type=Border, allow_none=True) 30 | protection = Typed(expected_type=Protection, allow_none=True) 31 | 32 | def __init__(self, 33 | font=None, 34 | numFmt=None, 35 | fill=None, 36 | alignment=None, 37 | border=None, 38 | protection=None, 39 | extLst=None, 40 | ): 41 | self.font = font 42 | self.numFmt = numFmt 43 | self.fill = fill 44 | self.alignment = alignment 45 | self.border = border 46 | self.protection = protection 47 | self.extLst = extLst 48 | 49 | 50 | class DifferentialStyleList(Serialisable): 51 | """ 52 | Dedupable container for differential styles. 53 | """ 54 | 55 | tagname = "dxfs" 56 | 57 | dxf = Sequence(expected_type=DifferentialStyle) 58 | styles = Alias("dxf") 59 | __attrs__ = ("count",) 60 | 61 | 62 | def __init__(self, dxf=(), count=None): 63 | self.dxf = dxf 64 | 65 | 66 | def append(self, dxf): 67 | """ 68 | Check to see whether style already exists and append it if does not. 69 | """ 70 | if not isinstance(dxf, DifferentialStyle): 71 | raise TypeError('expected ' + str(DifferentialStyle)) 72 | if dxf in self.styles: 73 | return 74 | self.styles.append(dxf) 75 | 76 | 77 | def add(self, dxf): 78 | """ 79 | Add a differential style and return its index 80 | """ 81 | self.append(dxf) 82 | return self.styles.index(dxf) 83 | 84 | 85 | def __bool__(self): 86 | return bool(self.styles) 87 | 88 | 89 | def __getitem__(self, idx): 90 | return self.styles[idx] 91 | 92 | 93 | @property 94 | def count(self): 95 | return len(self.dxf) 96 | -------------------------------------------------------------------------------- /src/lib/openpyxl/styles/fonts.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | from openpyxl.descriptors import ( 5 | Alias, 6 | Sequence, 7 | Integer 8 | ) 9 | from openpyxl.descriptors.serialisable import Serialisable 10 | 11 | from openpyxl.descriptors.nested import ( 12 | NestedValue, 13 | NestedBool, 14 | NestedNoneSet, 15 | NestedMinMax, 16 | NestedString, 17 | NestedInteger, 18 | NestedFloat, 19 | ) 20 | from .colors import ColorDescriptor, Color, BLACK 21 | 22 | from openpyxl.compat import safe_string 23 | from openpyxl.xml.functions import Element, SubElement 24 | from openpyxl.xml.constants import SHEET_MAIN_NS 25 | 26 | 27 | def _no_value(tagname, value, namespace=None): 28 | if value: 29 | return Element(tagname, val=safe_string(value)) 30 | 31 | 32 | class Font(Serialisable): 33 | """Font options used in styles.""" 34 | 35 | UNDERLINE_DOUBLE = 'double' 36 | UNDERLINE_DOUBLE_ACCOUNTING = 'doubleAccounting' 37 | UNDERLINE_SINGLE = 'single' 38 | UNDERLINE_SINGLE_ACCOUNTING = 'singleAccounting' 39 | 40 | name = NestedString(allow_none=True) 41 | charset = NestedInteger(allow_none=True) 42 | family = NestedMinMax(min=0, max=14, allow_none=True) 43 | sz = NestedFloat(allow_none=True) 44 | size = Alias("sz") 45 | b = NestedBool(to_tree=_no_value) 46 | bold = Alias("b") 47 | i = NestedBool(to_tree=_no_value) 48 | italic = Alias("i") 49 | strike = NestedBool(allow_none=True) 50 | strikethrough = Alias("strike") 51 | outline = NestedBool(allow_none=True) 52 | shadow = NestedBool(allow_none=True) 53 | condense = NestedBool(allow_none=True) 54 | extend = NestedBool(allow_none=True) 55 | u = NestedNoneSet(values=('single', 'double', 'singleAccounting', 56 | 'doubleAccounting')) 57 | underline = Alias("u") 58 | vertAlign = NestedNoneSet(values=('superscript', 'subscript', 'baseline')) 59 | color = ColorDescriptor(allow_none=True) 60 | scheme = NestedNoneSet(values=("major", "minor")) 61 | 62 | tagname = "font" 63 | 64 | __elements__ = ('name', 'charset', 'family', 'b', 'i', 'strike', 'outline', 65 | 'shadow', 'condense', 'color', 'extend', 'sz', 'u', 'vertAlign', 66 | 'scheme') 67 | 68 | 69 | def __init__(self, name=None, sz=None, b=None, i=None, charset=None, 70 | u=None, strike=None, color=None, scheme=None, family=None, size=None, 71 | bold=None, italic=None, strikethrough=None, underline=None, 72 | vertAlign=None, outline=None, shadow=None, condense=None, 73 | extend=None): 74 | self.name = name 75 | self.family = family 76 | if size is not None: 77 | sz = size 78 | self.sz = sz 79 | if bold is not None: 80 | b = bold 81 | self.b = b 82 | if italic is not None: 83 | i = italic 84 | self.i = i 85 | if underline is not None: 86 | u = underline 87 | self.u = u 88 | if strikethrough is not None: 89 | strike = strikethrough 90 | self.strike = strike 91 | self.color = color 92 | self.vertAlign = vertAlign 93 | self.charset = charset 94 | self.outline = outline 95 | self.shadow = shadow 96 | self.condense = condense 97 | self.extend = extend 98 | self.scheme = scheme 99 | 100 | 101 | @classmethod 102 | def from_tree(cls, node): 103 | """ 104 | Set default value for underline if child element is present 105 | """ 106 | underline = node.find("{%s}u" % SHEET_MAIN_NS) 107 | if underline is not None and underline.get('val') is None: 108 | underline.set("val", "single") 109 | return super().from_tree(node) 110 | 111 | 112 | DEFAULT_FONT = Font(name="Calibri", sz=11, family=2, b=False, i=False, 113 | color=Color(theme=1), scheme="minor") 114 | -------------------------------------------------------------------------------- /src/lib/openpyxl/styles/protection.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors import Bool 4 | from openpyxl.descriptors.serialisable import Serialisable 5 | 6 | 7 | class Protection(Serialisable): 8 | """Protection options for use in styles.""" 9 | 10 | tagname = "protection" 11 | 12 | locked = Bool() 13 | hidden = Bool() 14 | 15 | def __init__(self, locked=True, hidden=False): 16 | self.locked = locked 17 | self.hidden = hidden 18 | -------------------------------------------------------------------------------- /src/lib/openpyxl/styles/proxy.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from copy import copy 4 | 5 | from openpyxl.compat import deprecated 6 | 7 | 8 | class StyleProxy: 9 | """ 10 | Proxy formatting objects so that they cannot be altered 11 | """ 12 | 13 | __slots__ = ('__target') 14 | 15 | def __init__(self, target): 16 | self.__target = target 17 | 18 | 19 | def __repr__(self): 20 | return repr(self.__target) 21 | 22 | 23 | def __getattr__(self, attr): 24 | return getattr(self.__target, attr) 25 | 26 | 27 | def __setattr__(self, attr, value): 28 | if attr != "_StyleProxy__target": 29 | raise AttributeError("Style objects are immutable and cannot be changed." 30 | "Reassign the style with a copy") 31 | super().__setattr__(attr, value) 32 | 33 | 34 | def __copy__(self): 35 | """ 36 | Return a copy of the proxied object. 37 | """ 38 | return copy(self.__target) 39 | 40 | 41 | def __add__(self, other): 42 | """ 43 | Add proxied object to another instance and return the combined object 44 | """ 45 | return self.__target + other 46 | 47 | 48 | @deprecated("Use copy(obj) or cell.obj = cell.obj + other") 49 | def copy(self, **kw): 50 | """Return a copy of the proxied object. Keyword args will be passed through""" 51 | cp = copy(self.__target) 52 | for k, v in kw.items(): 53 | setattr(cp, k, v) 54 | return cp 55 | 56 | 57 | def __eq__(self, other): 58 | return self.__target == other 59 | 60 | 61 | def __ne__(self, other): 62 | return not self == other 63 | -------------------------------------------------------------------------------- /src/lib/openpyxl/styles/table.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Float, 7 | Bool, 8 | Set, 9 | Integer, 10 | NoneSet, 11 | String, 12 | Sequence 13 | ) 14 | 15 | from .colors import Color 16 | 17 | 18 | class TableStyleElement(Serialisable): 19 | 20 | tagname = "tableStyleElement" 21 | 22 | type = Set(values=(['wholeTable', 'headerRow', 'totalRow', 'firstColumn', 23 | 'lastColumn', 'firstRowStripe', 'secondRowStripe', 'firstColumnStripe', 24 | 'secondColumnStripe', 'firstHeaderCell', 'lastHeaderCell', 25 | 'firstTotalCell', 'lastTotalCell', 'firstSubtotalColumn', 26 | 'secondSubtotalColumn', 'thirdSubtotalColumn', 'firstSubtotalRow', 27 | 'secondSubtotalRow', 'thirdSubtotalRow', 'blankRow', 28 | 'firstColumnSubheading', 'secondColumnSubheading', 29 | 'thirdColumnSubheading', 'firstRowSubheading', 'secondRowSubheading', 30 | 'thirdRowSubheading', 'pageFieldLabels', 'pageFieldValues'])) 31 | size = Integer(allow_none=True) 32 | dxfId = Integer(allow_none=True) 33 | 34 | def __init__(self, 35 | type=None, 36 | size=None, 37 | dxfId=None, 38 | ): 39 | self.type = type 40 | self.size = size 41 | self.dxfId = dxfId 42 | 43 | 44 | class TableStyle(Serialisable): 45 | 46 | tagname = "tableStyle" 47 | 48 | name = String() 49 | pivot = Bool(allow_none=True) 50 | table = Bool(allow_none=True) 51 | count = Integer(allow_none=True) 52 | tableStyleElement = Sequence(expected_type=TableStyleElement, allow_none=True) 53 | 54 | __elements__ = ('tableStyleElement',) 55 | 56 | def __init__(self, 57 | name=None, 58 | pivot=None, 59 | table=None, 60 | count=None, 61 | tableStyleElement=(), 62 | ): 63 | self.name = name 64 | self.pivot = pivot 65 | self.table = table 66 | self.count = count 67 | self.tableStyleElement = tableStyleElement 68 | 69 | 70 | class TableStyleList(Serialisable): 71 | 72 | tagname = "tableStyles" 73 | 74 | defaultTableStyle = String(allow_none=True) 75 | defaultPivotStyle = String(allow_none=True) 76 | tableStyle = Sequence(expected_type=TableStyle, allow_none=True) 77 | 78 | __elements__ = ('tableStyle',) 79 | __attrs__ = ("count", "defaultTableStyle", "defaultPivotStyle") 80 | 81 | def __init__(self, 82 | count=None, 83 | defaultTableStyle="TableStyleMedium9", 84 | defaultPivotStyle="PivotStyleLight16", 85 | tableStyle=(), 86 | ): 87 | self.defaultTableStyle = defaultTableStyle 88 | self.defaultPivotStyle = defaultPivotStyle 89 | self.tableStyle = tableStyle 90 | 91 | 92 | @property 93 | def count(self): 94 | return len(self.tableStyle) 95 | -------------------------------------------------------------------------------- /src/lib/openpyxl/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | from .cell import ( 5 | absolute_coordinate, 6 | cols_from_range, 7 | column_index_from_string, 8 | coordinate_to_tuple, 9 | get_column_letter, 10 | get_column_interval, 11 | quote_sheetname, 12 | range_boundaries, 13 | range_to_tuple, 14 | rows_from_range, 15 | ) 16 | 17 | from .formulas import FORMULAE 18 | -------------------------------------------------------------------------------- /src/lib/openpyxl/utils/bound_dictionary.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from collections import defaultdict 4 | 5 | 6 | class BoundDictionary(defaultdict): 7 | """ 8 | A default dictionary where elements are tightly coupled. 9 | 10 | The factory method is responsible for binding the parent object to the child. 11 | 12 | If a reference attribute is assigned then child objects will have the key assigned to this. 13 | 14 | Otherwise it's just a defaultdict. 15 | """ 16 | 17 | def __init__(self, reference=None, *args, **kw): 18 | self.reference = reference 19 | super().__init__(*args, **kw) 20 | 21 | 22 | def __getitem__(self, key): 23 | value = super().__getitem__(key) 24 | if self.reference is not None: 25 | setattr(value, self.reference, key) 26 | return value 27 | -------------------------------------------------------------------------------- /src/lib/openpyxl/utils/dataframe.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from itertools import accumulate 4 | import operator 5 | import numpy 6 | from openpyxl.compat.product import prod 7 | 8 | 9 | def dataframe_to_rows(df, index=True, header=True): 10 | """ 11 | Convert a Pandas dataframe into something suitable for passing into a worksheet. 12 | If index is True then the index will be included, starting one row below the header. 13 | If header is True then column headers will be included starting one column to the right. 14 | Formatting should be done by client code. 15 | """ 16 | from pandas import Timestamp 17 | 18 | if header: 19 | if df.columns.nlevels > 1: 20 | rows = expand_index(df.columns, header) 21 | else: 22 | rows = [list(df.columns.values)] 23 | for row in rows: 24 | n = [] 25 | for v in row: 26 | if isinstance(v, numpy.datetime64): 27 | v = Timestamp(v) 28 | n.append(v) 29 | row = n 30 | if index: 31 | row = [None]*df.index.nlevels + row 32 | yield row 33 | 34 | if index: 35 | yield df.index.names 36 | 37 | expanded = ([v] for v in df.index) 38 | if df.index.nlevels > 1: 39 | expanded = expand_index(df.index) 40 | 41 | # Using the expanded index is preferable to df.itertuples(index=True) so that we have 'None' inserted where applicable 42 | for (df_index, row) in zip(expanded, df.itertuples(index=False)): 43 | row = list(row) 44 | if index: 45 | row = df_index + row 46 | yield row 47 | 48 | 49 | def expand_index(index, header=False): 50 | """ 51 | Expand axis or column Multiindex 52 | For columns use header = True 53 | For axes use header = False (default) 54 | """ 55 | 56 | # For each element of the index, zip the members with the previous row 57 | # If the 2 elements of the zipped list do not match, we can insert the new value into the row 58 | # or if an earlier member was different, all later members should be added to the row 59 | values = list(index.values) 60 | previous_value = [None] * len(values[0]) 61 | result = [] 62 | 63 | for value in values: 64 | row = [None] * len(value) 65 | 66 | # Once there's a difference in member of an index with the prior index, we need to store all subsequent members in the row 67 | prior_change = False 68 | for idx, (current_index_member, previous_index_member) in enumerate(zip(value, previous_value)): 69 | 70 | if current_index_member != previous_index_member or prior_change: 71 | row[idx] = current_index_member 72 | prior_change = True 73 | 74 | previous_value = value 75 | 76 | # If this is for a row index, we're already returning a row so just yield 77 | if not header: 78 | yield row 79 | else: 80 | result.append(row) 81 | 82 | # If it's for a header, we need to transpose to get it in row order 83 | # Example: result = [['A', 'A'], [None, 'B']] -> [['A', None], ['A', 'B']] 84 | if header: 85 | result = numpy.array(result).transpose().tolist() 86 | for row in result: 87 | yield row 88 | -------------------------------------------------------------------------------- /src/lib/openpyxl/utils/escape.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | """ 4 | OOXML has non-standard escaping for characters < \031 5 | """ 6 | 7 | import re 8 | 9 | 10 | def escape(value): 11 | r""" 12 | Convert ASCII < 31 to OOXML: \n == _x + hex(ord(\n)) + _ 13 | """ 14 | 15 | CHAR_REGEX = re.compile(r"[\001-\031]") 16 | 17 | def _sub(match): 18 | """ 19 | Callback to escape chars 20 | """ 21 | return "_x{:0>4x}_".format(ord(match.group(0))) 22 | 23 | return CHAR_REGEX.sub(_sub, value) 24 | 25 | 26 | def unescape(value): 27 | r""" 28 | Convert escaped strings to ASCIII: _x000a_ == \n 29 | """ 30 | 31 | 32 | ESCAPED_REGEX = re.compile("_x([0-9A-Fa-f]{4})_") 33 | 34 | def _sub(match): 35 | """ 36 | Callback to unescape chars 37 | """ 38 | return chr(int(match.group(1), 16)) 39 | 40 | if "_x" in value: 41 | value = ESCAPED_REGEX.sub(_sub, value) 42 | 43 | return value 44 | -------------------------------------------------------------------------------- /src/lib/openpyxl/utils/exceptions.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | """Definitions for openpyxl shared exception classes.""" 5 | 6 | 7 | class CellCoordinatesException(Exception): 8 | """Error for converting between numeric and A1-style cell references.""" 9 | 10 | 11 | class IllegalCharacterError(Exception): 12 | """The data submitted which cannot be used directly in Excel files. It 13 | must be removed or escaped.""" 14 | 15 | 16 | class NamedRangeException(Exception): 17 | """Error for badly formatted named ranges.""" 18 | 19 | 20 | class SheetTitleException(Exception): 21 | """Error for bad sheet names.""" 22 | 23 | 24 | class InvalidFileException(Exception): 25 | """Error for trying to open a non-ooxml file.""" 26 | 27 | 28 | class ReadOnlyWorkbookException(Exception): 29 | """Error for trying to modify a read-only workbook""" 30 | 31 | 32 | class WorkbookAlreadySaved(Exception): 33 | """Error when attempting to perform operations on a dump workbook 34 | while it has already been dumped once""" 35 | -------------------------------------------------------------------------------- /src/lib/openpyxl/utils/indexed_list.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | class IndexedList(list): 5 | """ 6 | List with optimised access by value 7 | Based on Alex Martelli's recipe 8 | 9 | http://code.activestate.com/recipes/52303-the-auxiliary-dictionary-idiom-for-sequences-with-/ 10 | """ 11 | 12 | _dict = {} 13 | 14 | def __init__(self, iterable=None): 15 | self.clean = True 16 | self._dict = {} 17 | if iterable is not None: 18 | self.clean = False 19 | for idx, val in enumerate(iterable): 20 | self._dict[val] = idx 21 | list.append(self, val) 22 | 23 | def _rebuild_dict(self): 24 | self._dict = {} 25 | idx = 0 26 | for value in self: 27 | if value not in self._dict: 28 | self._dict[value] = idx 29 | idx += 1 30 | self.clean = True 31 | 32 | def __contains__(self, value): 33 | if not self.clean: 34 | self._rebuild_dict() 35 | return value in self._dict 36 | 37 | def index(self, value): 38 | if value in self: 39 | return self._dict[value] 40 | raise ValueError 41 | 42 | def append(self, value): 43 | if value not in self._dict: 44 | self._dict[value] = len(self) 45 | list.append(self, value) 46 | 47 | def add(self, value): 48 | self.append(value) 49 | return self._dict[value] 50 | -------------------------------------------------------------------------------- /src/lib/openpyxl/utils/inference.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | """ 4 | Type inference functions 5 | """ 6 | import datetime 7 | import re 8 | 9 | from openpyxl.styles import numbers 10 | 11 | PERCENT_REGEX = re.compile(r'^(?P\-?[0-9]*\.?[0-9]*\s?)\%$') 12 | TIME_REGEX = re.compile(r""" 13 | ^(?: # HH:MM and HH:MM:SS 14 | (?P[0-1]{0,1}[0-9]{2}): 15 | (?P[0-5][0-9]):? 16 | (?P[0-5][0-9])?$) 17 | | 18 | ^(?: # MM:SS. 19 | ([0-5][0-9]): 20 | ([0-5][0-9])?\. 21 | (?P\d{1,6})) 22 | """, re.VERBOSE) 23 | NUMBER_REGEX = re.compile(r'^-?([\d]|[\d]+\.[\d]*|\.[\d]+|[1-9][\d]+\.?[\d]*)((E|e)[-+]?[\d]+)?$') 24 | 25 | 26 | def cast_numeric(value): 27 | """Explicitly convert a string to a numeric value""" 28 | if NUMBER_REGEX.match(value): 29 | try: 30 | return int(value) 31 | except ValueError: 32 | return float(value) 33 | 34 | 35 | def cast_percentage(value): 36 | """Explicitly convert a string to numeric value and format as a 37 | percentage""" 38 | match = PERCENT_REGEX.match(value) 39 | if match: 40 | return float(match.group('number')) / 100 41 | 42 | 43 | 44 | def cast_time(value): 45 | """Explicitly convert a string to a number and format as datetime or 46 | time""" 47 | match = TIME_REGEX.match(value) 48 | if match: 49 | if match.group("microsecond") is not None: 50 | value = value[:12] 51 | pattern = "%M:%S.%f" 52 | #fmt = numbers.FORMAT_DATE_TIME5 53 | elif match.group('second') is None: 54 | #fmt = numbers.FORMAT_DATE_TIME3 55 | pattern = "%H:%M" 56 | else: 57 | pattern = "%H:%M:%S" 58 | #fmt = numbers.FORMAT_DATE_TIME6 59 | value = datetime.datetime.strptime(value, pattern) 60 | return value.time() 61 | -------------------------------------------------------------------------------- /src/lib/openpyxl/utils/protection.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | def hash_password(plaintext_password=''): 5 | """ 6 | Create a password hash from a given string for protecting a worksheet 7 | only. This will not work for encrypting a workbook. 8 | 9 | This method is based on the algorithm provided by 10 | Daniel Rentz of OpenOffice and the PEAR package 11 | Spreadsheet_Excel_Writer by Xavier Noguer . 12 | See also http://blogs.msdn.com/b/ericwhite/archive/2008/02/23/the-legacy-hashing-algorithm-in-open-xml.aspx 13 | """ 14 | password = 0x0000 15 | for idx, char in enumerate(plaintext_password, 1): 16 | value = ord(char) << idx 17 | rotated_bits = value >> 15 18 | value &= 0x7fff 19 | password ^= (value | rotated_bits) 20 | password ^= len(plaintext_password) 21 | password ^= 0xCE4B 22 | return str(hex(password)).upper()[2:] 23 | -------------------------------------------------------------------------------- /src/lib/openpyxl/utils/units.py: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (c) 2010-2024 openpyxl 3 | 4 | import math 5 | 6 | 7 | #constants 8 | 9 | DEFAULT_ROW_HEIGHT = 15. # Default row height measured in point size. 10 | BASE_COL_WIDTH = 8 # in characters 11 | DEFAULT_COLUMN_WIDTH = BASE_COL_WIDTH + 5 12 | # = baseColumnWidth + {margin padding (2 pixels on each side, totalling 4 pixels)} + {gridline (1pixel)} 13 | 14 | 15 | DEFAULT_LEFT_MARGIN = 0.7 # in inches, = right margin 16 | DEFAULT_TOP_MARGIN = 0.7874 # in inches = bottom margin 17 | DEFAULT_HEADER = 0.3 # in inches 18 | 19 | 20 | # Conversion functions 21 | """ 22 | From the ECMA Spec (4th Edition part 1) 23 | Page setup: "Left Page Margin in inches" p. 1647 24 | 25 | Docs from 26 | http://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/ 27 | 28 | See also http://msdn.microsoft.com/en-us/library/dd560821(v=office.12).aspx 29 | 30 | dxa: The main unit in OOXML is a twentieth of a point. Also called twips. 31 | pt: point. In Excel there are 72 points to an inch 32 | hp: half-points are used to specify font sizes. A font-size of 12pt equals 24 half points 33 | pct: Half-points are used to specify font sizes. A font-size of 12pt equals 24 half points 34 | 35 | EMU: English Metric Unit, EMUs are used for coordinates in vector-based 36 | drawings and embedded pictures. One inch equates to 914400 EMUs and a 37 | centimeter is 360000. For bitmaps the default resolution is 96 dpi (known as 38 | PixelsPerInch in Excel). Spec p. 1122 39 | 40 | For radial geometry Excel uses integer units of 1/60000th of a degree. 41 | """ 42 | 43 | 44 | 45 | def inch_to_dxa(value): 46 | """1 inch = 72 * 20 dxa""" 47 | return int(value * 20 * 72) 48 | 49 | def dxa_to_inch(value): 50 | return value / 72 / 20 51 | 52 | 53 | def dxa_to_cm(value): 54 | return 2.54 * dxa_to_inch(value) 55 | 56 | def cm_to_dxa(value): 57 | emu = cm_to_EMU(value) 58 | inch = EMU_to_inch(emu) 59 | return inch_to_dxa(inch) 60 | 61 | 62 | def pixels_to_EMU(value): 63 | """1 pixel = 9525 EMUs""" 64 | return int(value * 9525) 65 | 66 | def EMU_to_pixels(value): 67 | return round(value / 9525) 68 | 69 | 70 | def cm_to_EMU(value): 71 | """1 cm = 360000 EMUs""" 72 | return int(value * 360000) 73 | 74 | def EMU_to_cm(value): 75 | return round(value / 360000, 4) 76 | 77 | 78 | def inch_to_EMU(value): 79 | """1 inch = 914400 EMUs""" 80 | return int(value * 914400) 81 | 82 | def EMU_to_inch(value): 83 | return round(value / 914400, 4) 84 | 85 | 86 | def pixels_to_points(value, dpi=96): 87 | """96 dpi, 72i""" 88 | return value * 72 / dpi 89 | 90 | 91 | def points_to_pixels(value, dpi=96): 92 | return int(math.ceil(value * dpi / 72)) 93 | 94 | 95 | def degrees_to_angle(value): 96 | """1 degree = 60000 angles""" 97 | return int(round(value * 60000)) 98 | 99 | 100 | def angle_to_degrees(value): 101 | return round(value / 60000, 2) 102 | 103 | 104 | def short_color(color): 105 | """ format a color to its short size """ 106 | if len(color) > 6: 107 | return color[2:] 108 | return color 109 | -------------------------------------------------------------------------------- /src/lib/openpyxl/workbook/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | from .workbook import Workbook 5 | -------------------------------------------------------------------------------- /src/lib/openpyxl/workbook/external_link/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from .external import ExternalLink 4 | -------------------------------------------------------------------------------- /src/lib/openpyxl/workbook/external_reference.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Sequence 6 | ) 7 | from openpyxl.descriptors.excel import ( 8 | Relation, 9 | ) 10 | 11 | class ExternalReference(Serialisable): 12 | 13 | tagname = "externalReference" 14 | 15 | id = Relation() 16 | 17 | def __init__(self, id): 18 | self.id = id 19 | -------------------------------------------------------------------------------- /src/lib/openpyxl/workbook/function_group.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Sequence, 6 | String, 7 | Integer, 8 | ) 9 | 10 | class FunctionGroup(Serialisable): 11 | 12 | tagname = "functionGroup" 13 | 14 | name = String() 15 | 16 | def __init__(self, 17 | name=None, 18 | ): 19 | self.name = name 20 | 21 | 22 | class FunctionGroupList(Serialisable): 23 | 24 | tagname = "functionGroups" 25 | 26 | builtInGroupCount = Integer(allow_none=True) 27 | functionGroup = Sequence(expected_type=FunctionGroup, allow_none=True) 28 | 29 | __elements__ = ('functionGroup',) 30 | 31 | def __init__(self, 32 | builtInGroupCount=16, 33 | functionGroup=(), 34 | ): 35 | self.builtInGroupCount = builtInGroupCount 36 | self.functionGroup = functionGroup 37 | -------------------------------------------------------------------------------- /src/lib/openpyxl/workbook/smart_tags.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Sequence, 6 | String, 7 | Bool, 8 | NoneSet, 9 | 10 | ) 11 | 12 | class SmartTag(Serialisable): 13 | 14 | tagname = "smartTagType" 15 | 16 | namespaceUri = String(allow_none=True) 17 | name = String(allow_none=True) 18 | url = String(allow_none=True) 19 | 20 | def __init__(self, 21 | namespaceUri=None, 22 | name=None, 23 | url=None, 24 | ): 25 | self.namespaceUri = namespaceUri 26 | self.name = name 27 | self.url = url 28 | 29 | 30 | class SmartTagList(Serialisable): 31 | 32 | tagname = "smartTagTypes" 33 | 34 | smartTagType = Sequence(expected_type=SmartTag, allow_none=True) 35 | 36 | __elements__ = ('smartTagType',) 37 | 38 | def __init__(self, 39 | smartTagType=(), 40 | ): 41 | self.smartTagType = smartTagType 42 | 43 | 44 | class SmartTagProperties(Serialisable): 45 | 46 | tagname = "smartTagPr" 47 | 48 | embed = Bool(allow_none=True) 49 | show = NoneSet(values=(['all', 'noIndicator'])) 50 | 51 | def __init__(self, 52 | embed=None, 53 | show=None, 54 | ): 55 | self.embed = embed 56 | self.show = show 57 | -------------------------------------------------------------------------------- /src/lib/openpyxl/workbook/web.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Sequence, 7 | String, 8 | Float, 9 | Integer, 10 | Bool, 11 | NoneSet, 12 | ) 13 | 14 | 15 | class WebPublishObject(Serialisable): 16 | 17 | tagname = "webPublishingObject" 18 | 19 | id = Integer() 20 | divId = String() 21 | sourceObject = String(allow_none=True) 22 | destinationFile = String() 23 | title = String(allow_none=True) 24 | autoRepublish = Bool(allow_none=True) 25 | 26 | def __init__(self, 27 | id=None, 28 | divId=None, 29 | sourceObject=None, 30 | destinationFile=None, 31 | title=None, 32 | autoRepublish=None, 33 | ): 34 | self.id = id 35 | self.divId = divId 36 | self.sourceObject = sourceObject 37 | self.destinationFile = destinationFile 38 | self.title = title 39 | self.autoRepublish = autoRepublish 40 | 41 | 42 | class WebPublishObjectList(Serialisable): 43 | 44 | tagname ="webPublishingObjects" 45 | 46 | count = Integer(allow_none=True) 47 | webPublishObject = Sequence(expected_type=WebPublishObject) 48 | 49 | __elements__ = ('webPublishObject',) 50 | 51 | def __init__(self, 52 | count=None, 53 | webPublishObject=(), 54 | ): 55 | self.webPublishObject = webPublishObject 56 | 57 | 58 | @property 59 | def count(self): 60 | return len(self.webPublishObject) 61 | 62 | 63 | class WebPublishing(Serialisable): 64 | 65 | tagname = "webPublishing" 66 | 67 | css = Bool(allow_none=True) 68 | thicket = Bool(allow_none=True) 69 | longFileNames = Bool(allow_none=True) 70 | vml = Bool(allow_none=True) 71 | allowPng = Bool(allow_none=True) 72 | targetScreenSize = NoneSet(values=(['544x376', '640x480', '720x512', '800x600', 73 | '1024x768', '1152x882', '1152x900', '1280x1024', '1600x1200', 74 | '1800x1440', '1920x1200'])) 75 | dpi = Integer(allow_none=True) 76 | codePage = Integer(allow_none=True) 77 | characterSet = String(allow_none=True) 78 | 79 | def __init__(self, 80 | css=None, 81 | thicket=None, 82 | longFileNames=None, 83 | vml=None, 84 | allowPng=None, 85 | targetScreenSize='800x600', 86 | dpi=None, 87 | codePage=None, 88 | characterSet=None, 89 | ): 90 | self.css = css 91 | self.thicket = thicket 92 | self.longFileNames = longFileNames 93 | self.vml = vml 94 | self.allowPng = allowPng 95 | self.targetScreenSize = targetScreenSize 96 | self.dpi = dpi 97 | self.codePage = codePage 98 | self.characterSet = characterSet 99 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/cell_watch.py: -------------------------------------------------------------------------------- 1 | #Autogenerated schema 2 | from openpyxl.descriptors.serialisable import Serialisable 3 | from openpyxl.descriptors import ( 4 | Sequence, 5 | String, 6 | ) 7 | 8 | # could be done using a nestedSequence 9 | 10 | class CellWatch(Serialisable): 11 | 12 | tagname = "cellWatch" 13 | 14 | r = String() 15 | 16 | def __init__(self, 17 | r=None, 18 | ): 19 | self.r = r 20 | 21 | 22 | class CellWatches(Serialisable): 23 | 24 | tagname = "cellWatches" 25 | 26 | cellWatch = Sequence(expected_type=CellWatch) 27 | 28 | __elements__ = ('cellWatch',) 29 | 30 | def __init__(self, 31 | cellWatch=(), 32 | ): 33 | self.cellWatch = cellWatch 34 | 35 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/controls.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Bool, 7 | Integer, 8 | String, 9 | Sequence, 10 | ) 11 | 12 | from openpyxl.descriptors.excel import Relation 13 | from .ole import ObjectAnchor 14 | 15 | 16 | class ControlProperty(Serialisable): 17 | 18 | tagname = "controlPr" 19 | 20 | anchor = Typed(expected_type=ObjectAnchor, ) 21 | locked = Bool(allow_none=True) 22 | defaultSize = Bool(allow_none=True) 23 | _print = Bool(allow_none=True) 24 | disabled = Bool(allow_none=True) 25 | recalcAlways = Bool(allow_none=True) 26 | uiObject = Bool(allow_none=True) 27 | autoFill = Bool(allow_none=True) 28 | autoLine = Bool(allow_none=True) 29 | autoPict = Bool(allow_none=True) 30 | macro = String(allow_none=True) 31 | altText = String(allow_none=True) 32 | linkedCell = String(allow_none=True) 33 | listFillRange = String(allow_none=True) 34 | cf = String(allow_none=True) 35 | id = Relation(allow_none=True) 36 | 37 | __elements__ = ('anchor',) 38 | 39 | def __init__(self, 40 | anchor=None, 41 | locked=True, 42 | defaultSize=True, 43 | _print=True, 44 | disabled=False, 45 | recalcAlways=False, 46 | uiObject=False, 47 | autoFill=True, 48 | autoLine=True, 49 | autoPict=True, 50 | macro=None, 51 | altText=None, 52 | linkedCell=None, 53 | listFillRange=None, 54 | cf='pict', 55 | id=None, 56 | ): 57 | self.anchor = anchor 58 | self.locked = locked 59 | self.defaultSize = defaultSize 60 | self._print = _print 61 | self.disabled = disabled 62 | self.recalcAlways = recalcAlways 63 | self.uiObject = uiObject 64 | self.autoFill = autoFill 65 | self.autoLine = autoLine 66 | self.autoPict = autoPict 67 | self.macro = macro 68 | self.altText = altText 69 | self.linkedCell = linkedCell 70 | self.listFillRange = listFillRange 71 | self.cf = cf 72 | self.id = id 73 | 74 | 75 | class Control(Serialisable): 76 | 77 | tagname = "control" 78 | 79 | controlPr = Typed(expected_type=ControlProperty, allow_none=True) 80 | shapeId = Integer() 81 | name = String(allow_none=True) 82 | 83 | __elements__ = ('controlPr',) 84 | 85 | def __init__(self, 86 | controlPr=None, 87 | shapeId=None, 88 | name=None, 89 | ): 90 | self.controlPr = controlPr 91 | self.shapeId = shapeId 92 | self.name = name 93 | 94 | 95 | class Controls(Serialisable): 96 | 97 | tagname = "controls" 98 | 99 | control = Sequence(expected_type=Control) 100 | 101 | __elements__ = ('control',) 102 | 103 | def __init__(self, 104 | control=(), 105 | ): 106 | self.control = control 107 | 108 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/copier.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | #standard lib imports 4 | from copy import copy 5 | 6 | from .worksheet import Worksheet 7 | 8 | 9 | class WorksheetCopy: 10 | """ 11 | Copy the values, styles, dimensions, merged cells, margins, and 12 | print/page setup from one worksheet to another within the same 13 | workbook. 14 | """ 15 | 16 | def __init__(self, source_worksheet, target_worksheet): 17 | self.source = source_worksheet 18 | self.target = target_worksheet 19 | self._verify_resources() 20 | 21 | 22 | def _verify_resources(self): 23 | 24 | if (not isinstance(self.source, Worksheet) 25 | and not isinstance(self.target, Worksheet)): 26 | raise TypeError("Can only copy worksheets") 27 | 28 | if self.source is self.target: 29 | raise ValueError("Cannot copy a worksheet to itself") 30 | 31 | if self.source.parent != self.target.parent: 32 | raise ValueError('Cannot copy between worksheets from different workbooks') 33 | 34 | 35 | def copy_worksheet(self): 36 | self._copy_cells() 37 | self._copy_dimensions() 38 | 39 | self.target.sheet_format = copy(self.source.sheet_format) 40 | self.target.sheet_properties = copy(self.source.sheet_properties) 41 | self.target.merged_cells = copy(self.source.merged_cells) 42 | self.target.page_margins = copy(self.source.page_margins) 43 | self.target.page_setup = copy(self.source.page_setup) 44 | self.target.print_options = copy(self.source.print_options) 45 | 46 | 47 | def _copy_cells(self): 48 | for (row, col), source_cell in self.source._cells.items(): 49 | target_cell = self.target.cell(column=col, row=row) 50 | 51 | target_cell._value = source_cell._value 52 | target_cell.data_type = source_cell.data_type 53 | 54 | if source_cell.has_style: 55 | target_cell._style = copy(source_cell._style) 56 | 57 | if source_cell.hyperlink: 58 | target_cell._hyperlink = copy(source_cell.hyperlink) 59 | 60 | if source_cell.comment: 61 | target_cell.comment = copy(source_cell.comment) 62 | 63 | 64 | def _copy_dimensions(self): 65 | for attr in ('row_dimensions', 'column_dimensions'): 66 | src = getattr(self.source, attr) 67 | target = getattr(self.target, attr) 68 | for key, dim in src.items(): 69 | target[key] = copy(dim) 70 | target[key].worksheet = self.target 71 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/custom.py: -------------------------------------------------------------------------------- 1 | #Autogenerated schema 2 | from openpyxl.descriptors.serialisable import Serialisable 3 | from openpyxl.descriptors import ( 4 | String, 5 | Sequence, 6 | ) 7 | 8 | # can be done with a nested sequence 9 | 10 | 11 | class CustomProperty(Serialisable): 12 | 13 | tagname = "customProperty" 14 | 15 | name = String() 16 | 17 | def __init__(self, 18 | name=None, 19 | ): 20 | self.name = name 21 | 22 | 23 | class CustomProperties(Serialisable): 24 | 25 | tagname = "customProperties" 26 | 27 | customPr = Sequence(expected_type=CustomProperty) 28 | 29 | __elements__ = ('customPr',) 30 | 31 | def __init__(self, 32 | customPr=(), 33 | ): 34 | self.customPr = customPr 35 | 36 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/drawing.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors.excel import Relation 5 | 6 | 7 | class Drawing(Serialisable): 8 | 9 | tagname = "drawing" 10 | 11 | id = Relation() 12 | 13 | def __init__(self, id=None): 14 | self.id = id 15 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/errors.py: -------------------------------------------------------------------------------- 1 | #Autogenerated schema 2 | from openpyxl.descriptors.serialisable import Serialisable 3 | from openpyxl.descriptors import ( 4 | Typed, 5 | String, 6 | Bool, 7 | Sequence, 8 | ) 9 | from openpyxl.descriptors.excel import CellRange 10 | 11 | 12 | class Extension(Serialisable): 13 | 14 | tagname = "extension" 15 | 16 | uri = String(allow_none=True) 17 | 18 | def __init__(self, 19 | uri=None, 20 | ): 21 | self.uri = uri 22 | 23 | 24 | class ExtensionList(Serialisable): 25 | 26 | tagname = "extensionList" 27 | 28 | # uses element group EG_ExtensionList 29 | ext = Sequence(expected_type=Extension) 30 | 31 | __elements__ = ('ext',) 32 | 33 | def __init__(self, 34 | ext=(), 35 | ): 36 | self.ext = ext 37 | 38 | 39 | class IgnoredError(Serialisable): 40 | 41 | tagname = "ignoredError" 42 | 43 | sqref = CellRange 44 | evalError = Bool(allow_none=True) 45 | twoDigitTextYear = Bool(allow_none=True) 46 | numberStoredAsText = Bool(allow_none=True) 47 | formula = Bool(allow_none=True) 48 | formulaRange = Bool(allow_none=True) 49 | unlockedFormula = Bool(allow_none=True) 50 | emptyCellReference = Bool(allow_none=True) 51 | listDataValidation = Bool(allow_none=True) 52 | calculatedColumn = Bool(allow_none=True) 53 | 54 | def __init__(self, 55 | sqref=None, 56 | evalError=False, 57 | twoDigitTextYear=False, 58 | numberStoredAsText=False, 59 | formula=False, 60 | formulaRange=False, 61 | unlockedFormula=False, 62 | emptyCellReference=False, 63 | listDataValidation=False, 64 | calculatedColumn=False, 65 | ): 66 | self.sqref = sqref 67 | self.evalError = evalError 68 | self.twoDigitTextYear = twoDigitTextYear 69 | self.numberStoredAsText = numberStoredAsText 70 | self.formula = formula 71 | self.formulaRange = formulaRange 72 | self.unlockedFormula = unlockedFormula 73 | self.emptyCellReference = emptyCellReference 74 | self.listDataValidation = listDataValidation 75 | self.calculatedColumn = calculatedColumn 76 | 77 | 78 | class IgnoredErrors(Serialisable): 79 | 80 | tagname = "ignoredErrors" 81 | 82 | ignoredError = Sequence(expected_type=IgnoredError) 83 | extLst = Typed(expected_type=ExtensionList, allow_none=True) 84 | 85 | __elements__ = ('ignoredError', 'extLst') 86 | 87 | def __init__(self, 88 | ignoredError=(), 89 | extLst=None, 90 | ): 91 | self.ignoredError = ignoredError 92 | self.extLst = extLst 93 | 94 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/formula.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.compat import safe_string 4 | 5 | class DataTableFormula: 6 | 7 | 8 | t = "dataTable" 9 | 10 | def __init__(self, 11 | ref, 12 | ca=False, 13 | dt2D=False, 14 | dtr=False, 15 | r1=None, 16 | r2=None, 17 | del1=False, 18 | del2=False, 19 | **kw): 20 | self.ref = ref 21 | self.ca = ca 22 | self.dt2D = dt2D 23 | self.dtr = dtr 24 | self.r1 = r1 25 | self.r2 = r2 26 | self.del1 = del1 27 | self.del2 = del2 28 | 29 | 30 | def __iter__(self): 31 | for k in ["t", "ref", "dt2D", "dtr", "r1", "r2", "del1", "del2", "ca"]: 32 | v = getattr(self, k) 33 | if v: 34 | yield k, safe_string(v) 35 | 36 | 37 | class ArrayFormula: 38 | 39 | t = "array" 40 | 41 | 42 | def __init__(self, ref, text=None): 43 | self.ref = ref 44 | self.text = text 45 | 46 | 47 | def __iter__(self): 48 | for k in ["t", "ref"]: 49 | v = getattr(self, k) 50 | if v: 51 | yield k, safe_string(v) 52 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/hyperlink.py: -------------------------------------------------------------------------------- 1 | from openpyxl.descriptors.serialisable import Serialisable 2 | from openpyxl.descriptors import ( 3 | String, 4 | Sequence, 5 | ) 6 | from openpyxl.descriptors.excel import Relation 7 | 8 | 9 | class Hyperlink(Serialisable): 10 | 11 | tagname = "hyperlink" 12 | 13 | ref = String() 14 | location = String(allow_none=True) 15 | tooltip = String(allow_none=True) 16 | display = String(allow_none=True) 17 | id = Relation() 18 | target = String(allow_none=True) 19 | 20 | __attrs__ = ("ref", "location", "tooltip", "display", "id") 21 | 22 | def __init__(self, 23 | ref=None, 24 | location=None, 25 | tooltip=None, 26 | display=None, 27 | id=None, 28 | target=None, 29 | ): 30 | self.ref = ref 31 | self.location = location 32 | self.tooltip = tooltip 33 | self.display = display 34 | self.id = id 35 | self.target = target 36 | 37 | 38 | class HyperlinkList(Serialisable): 39 | 40 | tagname = "hyperlinks" 41 | 42 | __expected_type = Hyperlink 43 | hyperlink = Sequence(expected_type=__expected_type) 44 | 45 | def __init__(self, hyperlink=()): 46 | self.hyperlink = hyperlink 47 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/ole.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Typed, 6 | Integer, 7 | String, 8 | Set, 9 | Bool, 10 | Sequence, 11 | ) 12 | 13 | from openpyxl.drawing.spreadsheet_drawing import AnchorMarker 14 | from openpyxl.xml.constants import SHEET_DRAWING_NS 15 | 16 | 17 | class ObjectAnchor(Serialisable): 18 | 19 | tagname = "anchor" 20 | 21 | _from = Typed(expected_type=AnchorMarker, namespace=SHEET_DRAWING_NS) 22 | to = Typed(expected_type=AnchorMarker, namespace=SHEET_DRAWING_NS) 23 | moveWithCells = Bool(allow_none=True) 24 | sizeWithCells = Bool(allow_none=True) 25 | z_order = Integer(allow_none=True, hyphenated=True) 26 | 27 | 28 | def __init__(self, 29 | _from=None, 30 | to=None, 31 | moveWithCells=False, 32 | sizeWithCells=False, 33 | z_order=None, 34 | ): 35 | self._from = _from 36 | self.to = to 37 | self.moveWithCells = moveWithCells 38 | self.sizeWithCells = sizeWithCells 39 | self.z_order = z_order 40 | 41 | 42 | class ObjectPr(Serialisable): 43 | 44 | tagname = "objectPr" 45 | 46 | anchor = Typed(expected_type=ObjectAnchor, ) 47 | locked = Bool(allow_none=True) 48 | defaultSize = Bool(allow_none=True) 49 | _print = Bool(allow_none=True) 50 | disabled = Bool(allow_none=True) 51 | uiObject = Bool(allow_none=True) 52 | autoFill = Bool(allow_none=True) 53 | autoLine = Bool(allow_none=True) 54 | autoPict = Bool(allow_none=True) 55 | macro = String() 56 | altText = String(allow_none=True) 57 | dde = Bool(allow_none=True) 58 | 59 | __elements__ = ('anchor',) 60 | 61 | def __init__(self, 62 | anchor=None, 63 | locked=True, 64 | defaultSize=True, 65 | _print=True, 66 | disabled=False, 67 | uiObject=False, 68 | autoFill=True, 69 | autoLine=True, 70 | autoPict=True, 71 | macro=None, 72 | altText=None, 73 | dde=False, 74 | ): 75 | self.anchor = anchor 76 | self.locked = locked 77 | self.defaultSize = defaultSize 78 | self._print = _print 79 | self.disabled = disabled 80 | self.uiObject = uiObject 81 | self.autoFill = autoFill 82 | self.autoLine = autoLine 83 | self.autoPict = autoPict 84 | self.macro = macro 85 | self.altText = altText 86 | self.dde = dde 87 | 88 | 89 | class OleObject(Serialisable): 90 | 91 | tagname = "oleObject" 92 | 93 | objectPr = Typed(expected_type=ObjectPr, allow_none=True) 94 | progId = String(allow_none=True) 95 | dvAspect = Set(values=(['DVASPECT_CONTENT', 'DVASPECT_ICON'])) 96 | link = String(allow_none=True) 97 | oleUpdate = Set(values=(['OLEUPDATE_ALWAYS', 'OLEUPDATE_ONCALL'])) 98 | autoLoad = Bool(allow_none=True) 99 | shapeId = Integer() 100 | 101 | __elements__ = ('objectPr',) 102 | 103 | def __init__(self, 104 | objectPr=None, 105 | progId=None, 106 | dvAspect='DVASPECT_CONTENT', 107 | link=None, 108 | oleUpdate=None, 109 | autoLoad=False, 110 | shapeId=None, 111 | ): 112 | self.objectPr = objectPr 113 | self.progId = progId 114 | self.dvAspect = dvAspect 115 | self.link = link 116 | self.oleUpdate = oleUpdate 117 | self.autoLoad = autoLoad 118 | self.shapeId = shapeId 119 | 120 | 121 | class OleObjects(Serialisable): 122 | 123 | tagname = "oleObjects" 124 | 125 | oleObject = Sequence(expected_type=OleObject) 126 | 127 | __elements__ = ('oleObject',) 128 | 129 | def __init__(self, 130 | oleObject=(), 131 | ): 132 | self.oleObject = oleObject 133 | 134 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/pagebreak.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | Integer, 6 | Bool, 7 | Sequence, 8 | ) 9 | 10 | 11 | class Break(Serialisable): 12 | 13 | tagname = "brk" 14 | 15 | id = Integer(allow_none=True) 16 | min = Integer(allow_none=True) 17 | max = Integer(allow_none=True) 18 | man = Bool(allow_none=True) 19 | pt = Bool(allow_none=True) 20 | 21 | def __init__(self, 22 | id=0, 23 | min=0, 24 | max=16383, 25 | man=True, 26 | pt=None, 27 | ): 28 | self.id = id 29 | self.min = min 30 | self.max = max 31 | self.man = man 32 | self.pt = pt 33 | 34 | 35 | class RowBreak(Serialisable): 36 | 37 | tagname = "rowBreaks" 38 | 39 | count = Integer(allow_none=True) 40 | manualBreakCount = Integer(allow_none=True) 41 | brk = Sequence(expected_type=Break, allow_none=True) 42 | 43 | __elements__ = ('brk',) 44 | __attrs__ = ("count", "manualBreakCount",) 45 | 46 | def __init__(self, 47 | count=None, 48 | manualBreakCount=None, 49 | brk=(), 50 | ): 51 | self.brk = brk 52 | 53 | 54 | def __bool__(self): 55 | return len(self.brk) > 0 56 | 57 | 58 | def __len__(self): 59 | return len(self.brk) 60 | 61 | 62 | @property 63 | def count(self): 64 | return len(self) 65 | 66 | 67 | @property 68 | def manualBreakCount(self): 69 | return len(self) 70 | 71 | 72 | def append(self, brk=None): 73 | """ 74 | Add a page break 75 | """ 76 | vals = list(self.brk) 77 | if not isinstance(brk, Break): 78 | brk = Break(id=self.count+1) 79 | vals.append(brk) 80 | self.brk = vals 81 | 82 | 83 | PageBreak = RowBreak 84 | 85 | 86 | class ColBreak(RowBreak): 87 | 88 | tagname = "colBreaks" 89 | 90 | count = RowBreak.count 91 | manualBreakCount = RowBreak.manualBreakCount 92 | brk = RowBreak.brk 93 | 94 | __attrs__ = RowBreak.__attrs__ 95 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/picture.py: -------------------------------------------------------------------------------- 1 | #Autogenerated schema 2 | from openpyxl.descriptors.serialisable import Serialisable 3 | 4 | # same as related 5 | 6 | class SheetBackgroundPicture(Serialisable): 7 | 8 | tagname = "sheetBackgroundPicture" 9 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/properties.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | """Worksheet Properties""" 4 | 5 | from openpyxl.descriptors.serialisable import Serialisable 6 | from openpyxl.descriptors import String, Bool, Typed 7 | from openpyxl.styles.colors import ColorDescriptor 8 | 9 | 10 | class Outline(Serialisable): 11 | 12 | tagname = "outlinePr" 13 | 14 | applyStyles = Bool(allow_none=True) 15 | summaryBelow = Bool(allow_none=True) 16 | summaryRight = Bool(allow_none=True) 17 | showOutlineSymbols = Bool(allow_none=True) 18 | 19 | 20 | def __init__(self, 21 | applyStyles=None, 22 | summaryBelow=None, 23 | summaryRight=None, 24 | showOutlineSymbols=None 25 | ): 26 | self.applyStyles = applyStyles 27 | self.summaryBelow = summaryBelow 28 | self.summaryRight = summaryRight 29 | self.showOutlineSymbols = showOutlineSymbols 30 | 31 | 32 | class PageSetupProperties(Serialisable): 33 | 34 | tagname = "pageSetUpPr" 35 | 36 | autoPageBreaks = Bool(allow_none=True) 37 | fitToPage = Bool(allow_none=True) 38 | 39 | def __init__(self, autoPageBreaks=None, fitToPage=None): 40 | self.autoPageBreaks = autoPageBreaks 41 | self.fitToPage = fitToPage 42 | 43 | 44 | class WorksheetProperties(Serialisable): 45 | 46 | tagname = "sheetPr" 47 | 48 | codeName = String(allow_none=True) 49 | enableFormatConditionsCalculation = Bool(allow_none=True) 50 | filterMode = Bool(allow_none=True) 51 | published = Bool(allow_none=True) 52 | syncHorizontal = Bool(allow_none=True) 53 | syncRef = String(allow_none=True) 54 | syncVertical = Bool(allow_none=True) 55 | transitionEvaluation = Bool(allow_none=True) 56 | transitionEntry = Bool(allow_none=True) 57 | tabColor = ColorDescriptor(allow_none=True) 58 | outlinePr = Typed(expected_type=Outline, allow_none=True) 59 | pageSetUpPr = Typed(expected_type=PageSetupProperties, allow_none=True) 60 | 61 | __elements__ = ('tabColor', 'outlinePr', 'pageSetUpPr') 62 | 63 | 64 | def __init__(self, 65 | codeName=None, 66 | enableFormatConditionsCalculation=None, 67 | filterMode=None, 68 | published=None, 69 | syncHorizontal=None, 70 | syncRef=None, 71 | syncVertical=None, 72 | transitionEvaluation=None, 73 | transitionEntry=None, 74 | tabColor=None, 75 | outlinePr=None, 76 | pageSetUpPr=None 77 | ): 78 | """ Attributes """ 79 | self.codeName = codeName 80 | self.enableFormatConditionsCalculation = enableFormatConditionsCalculation 81 | self.filterMode = filterMode 82 | self.published = published 83 | self.syncHorizontal = syncHorizontal 84 | self.syncRef = syncRef 85 | self.syncVertical = syncVertical 86 | self.transitionEvaluation = transitionEvaluation 87 | self.transitionEntry = transitionEntry 88 | """ Elements """ 89 | self.tabColor = tabColor 90 | if outlinePr is None: 91 | self.outlinePr = Outline(summaryBelow=True, summaryRight=True) 92 | else: 93 | self.outlinePr = outlinePr 94 | 95 | if pageSetUpPr is None: 96 | pageSetUpPr = PageSetupProperties() 97 | self.pageSetUpPr = pageSetUpPr 98 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/related.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors.excel import Relation 5 | 6 | 7 | class Related(Serialisable): 8 | 9 | id = Relation() 10 | 11 | 12 | def __init__(self, id=None): 13 | self.id = id 14 | 15 | 16 | def to_tree(self, tagname, idx=None): 17 | return super().to_tree(tagname) 18 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/scenario.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | from openpyxl.descriptors.serialisable import Serialisable 4 | from openpyxl.descriptors import ( 5 | String, 6 | Integer, 7 | Bool, 8 | Sequence, 9 | Convertible, 10 | ) 11 | from .cell_range import MultiCellRange 12 | 13 | 14 | class InputCells(Serialisable): 15 | 16 | tagname = "inputCells" 17 | 18 | r = String() 19 | deleted = Bool(allow_none=True) 20 | undone = Bool(allow_none=True) 21 | val = String() 22 | numFmtId = Integer(allow_none=True) 23 | 24 | def __init__(self, 25 | r=None, 26 | deleted=False, 27 | undone=False, 28 | val=None, 29 | numFmtId=None, 30 | ): 31 | self.r = r 32 | self.deleted = deleted 33 | self.undone = undone 34 | self.val = val 35 | self.numFmtId = numFmtId 36 | 37 | 38 | class Scenario(Serialisable): 39 | 40 | tagname = "scenario" 41 | 42 | inputCells = Sequence(expected_type=InputCells) 43 | name = String() 44 | locked = Bool(allow_none=True) 45 | hidden = Bool(allow_none=True) 46 | user = String(allow_none=True) 47 | comment = String(allow_none=True) 48 | 49 | __elements__ = ('inputCells',) 50 | __attrs__ = ('name', 'locked', 'hidden', 'user', 'comment', 'count') 51 | 52 | def __init__(self, 53 | inputCells=(), 54 | name=None, 55 | locked=False, 56 | hidden=False, 57 | count=None, 58 | user=None, 59 | comment=None, 60 | ): 61 | self.inputCells = inputCells 62 | self.name = name 63 | self.locked = locked 64 | self.hidden = hidden 65 | self.user = user 66 | self.comment = comment 67 | 68 | 69 | @property 70 | def count(self): 71 | return len(self.inputCells) 72 | 73 | 74 | class ScenarioList(Serialisable): 75 | 76 | tagname = "scenarios" 77 | 78 | scenario = Sequence(expected_type=Scenario) 79 | current = Integer(allow_none=True) 80 | show = Integer(allow_none=True) 81 | sqref = Convertible(expected_type=MultiCellRange, allow_none=True) 82 | 83 | __elements__ = ('scenario',) 84 | 85 | def __init__(self, 86 | scenario=(), 87 | current=None, 88 | show=None, 89 | sqref=None, 90 | ): 91 | self.scenario = scenario 92 | self.current = current 93 | self.show = show 94 | self.sqref = sqref 95 | 96 | 97 | def append(self, scenario): 98 | s = self.scenario 99 | s.append(scenario) 100 | self.scenario = s 101 | 102 | 103 | def __bool__(self): 104 | return bool(self.scenario) 105 | 106 | -------------------------------------------------------------------------------- /src/lib/openpyxl/worksheet/smart_tag.py: -------------------------------------------------------------------------------- 1 | #Autogenerated schema 2 | from openpyxl.descriptors.serialisable import Serialisable 3 | from openpyxl.descriptors import ( 4 | Bool, 5 | Integer, 6 | String, 7 | Sequence, 8 | ) 9 | 10 | 11 | class CellSmartTagPr(Serialisable): 12 | 13 | tagname = "cellSmartTagPr" 14 | 15 | key = String() 16 | val = String() 17 | 18 | def __init__(self, 19 | key=None, 20 | val=None, 21 | ): 22 | self.key = key 23 | self.val = val 24 | 25 | 26 | class CellSmartTag(Serialisable): 27 | 28 | tagname = "cellSmartTag" 29 | 30 | cellSmartTagPr = Sequence(expected_type=CellSmartTagPr) 31 | type = Integer() 32 | deleted = Bool(allow_none=True) 33 | xmlBased = Bool(allow_none=True) 34 | 35 | __elements__ = ('cellSmartTagPr',) 36 | 37 | def __init__(self, 38 | cellSmartTagPr=(), 39 | type=None, 40 | deleted=False, 41 | xmlBased=False, 42 | ): 43 | self.cellSmartTagPr = cellSmartTagPr 44 | self.type = type 45 | self.deleted = deleted 46 | self.xmlBased = xmlBased 47 | 48 | 49 | class CellSmartTags(Serialisable): 50 | 51 | tagname = "cellSmartTags" 52 | 53 | cellSmartTag = Sequence(expected_type=CellSmartTag) 54 | r = String() 55 | 56 | __elements__ = ('cellSmartTag',) 57 | 58 | def __init__(self, 59 | cellSmartTag=(), 60 | r=None, 61 | ): 62 | self.cellSmartTag = cellSmartTag 63 | self.r = r 64 | 65 | 66 | class SmartTags(Serialisable): 67 | 68 | tagname = "smartTags" 69 | 70 | cellSmartTags = Sequence(expected_type=CellSmartTags) 71 | 72 | __elements__ = ('cellSmartTags',) 73 | 74 | def __init__(self, 75 | cellSmartTags=(), 76 | ): 77 | self.cellSmartTags = cellSmartTags 78 | 79 | -------------------------------------------------------------------------------- /src/lib/openpyxl/writer/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | -------------------------------------------------------------------------------- /src/lib/openpyxl/xml/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | 4 | """Collection of XML resources compatible across different Python versions""" 5 | import os 6 | 7 | 8 | def lxml_available(): 9 | try: 10 | from lxml.etree import LXML_VERSION 11 | LXML = LXML_VERSION >= (3, 3, 1, 0) 12 | if not LXML: 13 | import warnings 14 | warnings.warn("The installed version of lxml is too old to be used with openpyxl") 15 | return False # we have it, but too old 16 | else: 17 | return True # we have it, and recent enough 18 | except ImportError: 19 | return False # we don't even have it 20 | 21 | 22 | def lxml_env_set(): 23 | return os.environ.get("OPENPYXL_LXML", "True") == "True" 24 | 25 | 26 | LXML = lxml_available() and lxml_env_set() 27 | 28 | 29 | def defusedxml_available(): 30 | try: 31 | import defusedxml # noqa 32 | except ImportError: 33 | return False 34 | else: 35 | return True 36 | 37 | 38 | def defusedxml_env_set(): 39 | return os.environ.get("OPENPYXL_DEFUSEDXML", "True") == "True" 40 | 41 | 42 | DEFUSEDXML = defusedxml_available() and defusedxml_env_set() 43 | -------------------------------------------------------------------------------- /src/lib/openpyxl/xml/functions.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 openpyxl 2 | 3 | """ 4 | XML compatibility functions 5 | """ 6 | 7 | # Python stdlib imports 8 | import re 9 | from functools import partial 10 | 11 | from openpyxl import DEFUSEDXML, LXML 12 | 13 | if LXML is True: 14 | from lxml.etree import ( 15 | Element, 16 | SubElement, 17 | register_namespace, 18 | QName, 19 | xmlfile, 20 | XMLParser, 21 | ) 22 | from lxml.etree import fromstring, tostring 23 | # do not resolve entities 24 | safe_parser = XMLParser(resolve_entities=False) 25 | fromstring = partial(fromstring, parser=safe_parser) 26 | 27 | else: 28 | from xml.etree.ElementTree import ( 29 | Element, 30 | SubElement, 31 | fromstring, 32 | tostring, 33 | QName, 34 | register_namespace 35 | ) 36 | from et_xmlfile import xmlfile 37 | if DEFUSEDXML is True: 38 | from defusedxml.ElementTree import fromstring 39 | 40 | from xml.etree.ElementTree import iterparse 41 | if DEFUSEDXML is True: 42 | from defusedxml.ElementTree import iterparse 43 | 44 | from openpyxl.xml.constants import ( 45 | CHART_NS, 46 | DRAWING_NS, 47 | SHEET_DRAWING_NS, 48 | CHART_DRAWING_NS, 49 | SHEET_MAIN_NS, 50 | REL_NS, 51 | VTYPES_NS, 52 | COREPROPS_NS, 53 | CUSTPROPS_NS, 54 | DCTERMS_NS, 55 | DCTERMS_PREFIX, 56 | XML_NS 57 | ) 58 | 59 | register_namespace(DCTERMS_PREFIX, DCTERMS_NS) 60 | register_namespace('dcmitype', 'http://purl.org/dc/dcmitype/') 61 | register_namespace('cp', COREPROPS_NS) 62 | register_namespace('c', CHART_NS) 63 | register_namespace('a', DRAWING_NS) 64 | register_namespace('s', SHEET_MAIN_NS) 65 | register_namespace('r', REL_NS) 66 | register_namespace('vt', VTYPES_NS) 67 | register_namespace('xdr', SHEET_DRAWING_NS) 68 | register_namespace('cdr', CHART_DRAWING_NS) 69 | register_namespace('xml', XML_NS) 70 | register_namespace('cust', CUSTPROPS_NS) 71 | 72 | 73 | tostring = partial(tostring, encoding="utf-8") 74 | 75 | NS_REGEX = re.compile("({(?P.*)})?(?P.*)") 76 | 77 | def localname(node): 78 | if callable(node.tag): 79 | return "comment" 80 | m = NS_REGEX.match(node.tag) 81 | return m.group('localname') 82 | 83 | 84 | def whitespace(node): 85 | stripped = node.text.strip() 86 | if stripped and node.text != stripped: 87 | node.set("{%s}space" % XML_NS, "preserve") 88 | -------------------------------------------------------------------------------- /src/model.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-file-explorer/cb14d6fce746232bc7bf4c98bb9cc2ca74be2e90/src/model.xlsx -------------------------------------------------------------------------------- /src/renamefiles_run.py: -------------------------------------------------------------------------------- 1 | import os 2 | import datetime 3 | import logging 4 | from utils import display_notification, safe_guard, reverse_dir, data_folder, load_workbook, workflow_action 5 | 6 | _path, _name = os.environ['split2'].split('ǀ') 7 | 8 | wb = load_workbook(filePath=_path, read_only=True) 9 | 10 | original_paths = [] 11 | output_paths = [] 12 | log_name = f'{_name}_{datetime.datetime.now().strftime("%d-%m-%Y_%H:%M:%S")}.log' 13 | log_path = os.path.join(data_folder, log_name) 14 | error_flag = False 15 | 16 | for ws in wb: 17 | for row in ws.iter_rows(min_row=2, max_col=4, values_only=True): 18 | original_path = f'{row[0]}/{row[1]}{row[2]}' 19 | if f'{row[3]}' != 'None' and (not safe_guard or (safe_guard and os.path.splitext(f'{row[3]}')[1].casefold() == f'{row[2]}'.casefold())): 20 | output_path = f'{row[0]}/{row[3]}' 21 | else: 22 | output_path = '' 23 | original_paths.append(original_path) 24 | output_paths.append(output_path) 25 | 26 | logging.basicConfig(filename=log_path, level=logging.INFO) 27 | 28 | for old_name, new_name in zip(original_paths, output_paths): 29 | if old_name and new_name: 30 | if not reverse_dir: 31 | try: 32 | os.rename(old_name, new_name) 33 | logging.info(f'✅ Renaming successful: {old_name} ⇒ {new_name}') 34 | except Exception as e: 35 | logging.info(f'🚨 Error renaming {old_name} ⇒ {new_name}: {e}') 36 | error_flag = True 37 | elif reverse_dir: 38 | try: 39 | os.rename(new_name, old_name) 40 | logging.info(f'✅ Renaming successful: {new_name} ⇒ {old_name}') 41 | except Exception as e: 42 | logging.info(f'🚨 Error renaming {new_name} ⇒ {old_name}: {e}') 43 | error_flag = True 44 | 45 | if workflow_action == '_notif': 46 | if error_flag: 47 | display_notification('⚠️ Warning !', 'One or more files weren\'t renamed correctly. Check the logs') 48 | else: 49 | display_notification('✅ Success !', 'All files were successfully renamed') 50 | else: 51 | print(f'{workflow_action};{log_path}', end='') -------------------------------------------------------------------------------- /src/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import math 4 | sys.path.insert(0, './lib') 5 | import openpyxl 6 | 7 | # Workflow variables 8 | data_folder = os.path.expanduser('~/Library/Application Support/Alfred/Workflow Data/com.benjamino.file_explorer') 9 | depth = 1 10 | workflow_action = '_open' 11 | reject_regex = '' 12 | safe_guard = True if os.environ['safe_guard'] == '1' else False 13 | reverse_dir = True if os.environ['reverse_dir'] == '1' else False 14 | max_rows = 1048575 15 | sound = 'Submarine' 16 | 17 | default_list = [ 18 | { 19 | 'title': 'data_folder', 20 | }, 21 | { 22 | 'title': 'depth', 23 | 'func': int 24 | }, 25 | { 26 | 'title': 'workflow_action', 27 | }, 28 | { 29 | 'title': 'reject_regex', 30 | }, 31 | { 32 | 'title': 'max_rows', 33 | 'func': int 34 | }, 35 | { 36 | 'title': 'sound', 37 | } 38 | ] 39 | 40 | for obj in default_list: 41 | try: 42 | value = os.environ.get(obj.get('title')) 43 | if not value and obj.get('title') not in ['sound', 'workflow_action', 'reject_regex']: 44 | value = globals()[obj.get('title')] 45 | function = obj.get('func') 46 | globals()[obj.get('title')] = function(value) if function else value 47 | except ValueError: 48 | pass 49 | 50 | # Notification builder 51 | def display_notification(title: str, message: str): 52 | # Escape double quotes in title and message 53 | title = title.replace('"', '\\"') 54 | message = message.replace('"', '\\"') 55 | os.system(f'"{os.getcwd()}/notificator" --message "{message}" --title "{title}" --sound "{sound}"') 56 | 57 | 58 | def get_size_string(size, decimals=2): 59 | size_name = ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB') 60 | i = int(math.floor(math.log(size, 1024))) 61 | p = math.pow(1024, i) 62 | s = round(size / p, decimals) 63 | return f'{s} {size_name[i]}' 64 | 65 | def load_workbook(filePath: str, read_only: bool=False): 66 | if read_only: 67 | return openpyxl.load_workbook(filePath, read_only=True, data_only=True) 68 | else: 69 | return openpyxl.load_workbook(filePath, data_only=True) -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Install platform agnostic version of openpyxl (put the script inside the workflow folder) 4 | mkdir -p lib 5 | pip3 install openpyxl -t lib --upgrade --------------------------------------------------------------------------------