aioopenpyxl 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aioopenpyxl-0.1.0/LICENSE +21 -0
- aioopenpyxl-0.1.0/PKG-INFO +164 -0
- aioopenpyxl-0.1.0/README.md +128 -0
- aioopenpyxl-0.1.0/pyproject.toml +104 -0
- aioopenpyxl-0.1.0/pyproject.toml.orig +87 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/__init__.py +108 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/_base.py +104 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/_compat.py +71 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/_errors.py +26 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/_executor.py +539 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/_generated.py +870 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/_reader.py +141 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/_workbook.py +257 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/_worksheet.py +821 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/cell/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/cell/cell.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/cell/read_only.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/cell/rich_text.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/cell/text.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/area_chart.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/axis.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/bar_chart.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/bubble_chart.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/chartspace.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/data_source.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/descriptors.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/error_bar.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/label.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/layout.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/legend.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/line_chart.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/marker.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/picture.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/pie_chart.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/pivot.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/plotarea.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/print_settings.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/radar_chart.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/reader.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/reference.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/scatter_chart.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/series.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/series_factory.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/shapes.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/stock_chart.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/surface_chart.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/text.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/title.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/trendline.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chart/updown_bars.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/chartsheet.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/custom.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/properties.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/protection.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/publish.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/relation.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/views.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/comments/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/comments/author.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/comments/comment_sheet.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/comments/comments.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/comments/shape_writer.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/compat/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/compat/abc.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/compat/numbers.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/compat/product.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/compat/singleton.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/compat/strings.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/base.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/container.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/excel.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/namespace.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/nested.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/sequence.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/serialisable.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/slots.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/colors.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/connector.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/drawing.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/effect.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/fill.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/geometry.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/graphic.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/image.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/line.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/picture.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/properties.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/relation.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/spreadsheet_drawing.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/text.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/xdr.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/formatting/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/formatting/formatting.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/formatting/rule.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/formula/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/formula/tokenizer.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/formula/translate.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/core.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/custom.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/extended.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/interface.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/manifest.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/relationship.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/workbook.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/pivot/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/pivot/cache.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/pivot/fields.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/pivot/record.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/pivot/table.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/py.typed +0 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/reader/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/reader/drawings.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/reader/excel.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/reader/strings.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/reader/workbook.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/alignment.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/borders.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/builtins.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/cell_style.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/colors.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/differential.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/fills.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/fonts.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/named_styles.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/numbers.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/protection.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/proxy.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/styleable.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/stylesheet.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/styles/table.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/bound_dictionary.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/cell.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/dataframe.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/datetime.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/escape.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/exceptions.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/formulas.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/indexed_list.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/inference.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/protection.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/utils/units.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/child.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/defined_name.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/external_link/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/external_link/external.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/external_reference.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/function_group.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/properties.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/protection.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/smart_tags.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/views.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/web.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/workbook.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/cell_range.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/cell_watch.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/controls.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/copier.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/custom.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/datavalidation.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/dimensions.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/drawing.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/errors.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/filters.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/formula.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/header_footer.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/hyperlink.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/merge.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/ole.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/page.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/pagebreak.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/picture.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/print_settings.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/properties.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/protection.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/related.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/scenario.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/smart_tag.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/table.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/views.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/worksheet.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/writer/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/writer/excel.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/writer/theme.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/xml/__init__.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/xml/constants.pyi +4 -0
- aioopenpyxl-0.1.0/src/aioopenpyxl/xml/functions.pyi +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 yamaaaaaa31
|
|
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.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aioopenpyxl
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Asynchronous wrapper around openpyxl for asyncio and trio, built on anyio
|
|
5
|
+
Keywords: openpyxl,asyncio,trio,anyio,excel,xlsx,async
|
|
6
|
+
Author: yamaaaaaa31
|
|
7
|
+
Author-email: yamaaaaaa31 <143375737+yamaaaaaa31@users.noreply.github.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Framework :: AsyncIO
|
|
12
|
+
Classifier: Framework :: AnyIO
|
|
13
|
+
Classifier: Framework :: Trio
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
|
|
23
|
+
Classifier: Topic :: Office/Business :: Financial :: Spreadsheet
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Dist: anyio>=4.5
|
|
26
|
+
Requires-Dist: openpyxl>=3.1
|
|
27
|
+
Requires-Dist: types-openpyxl>=3.1.5.20250506
|
|
28
|
+
Requires-Dist: typing-extensions>=4.5
|
|
29
|
+
Requires-Python: >=3.10
|
|
30
|
+
Project-URL: Homepage, https://github.com/yamaaaaaa31/aioopenpyxl
|
|
31
|
+
Project-URL: Documentation, https://github.com/yamaaaaaa31/aioopenpyxl#readme
|
|
32
|
+
Project-URL: Repository, https://github.com/yamaaaaaa31/aioopenpyxl
|
|
33
|
+
Project-URL: Issues, https://github.com/yamaaaaaa31/aioopenpyxl/issues
|
|
34
|
+
Project-URL: Changelog, https://github.com/yamaaaaaa31/aioopenpyxl/blob/main/CHANGELOG.md
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# aioopenpyxl
|
|
38
|
+
|
|
39
|
+
[](https://github.com/yamaaaaaa31/aioopenpyxl/actions/workflows/ci.yml)
|
|
40
|
+
[](https://pypi.org/project/aioopenpyxl/)
|
|
41
|
+
[](https://pypi.org/project/aioopenpyxl/)
|
|
42
|
+
[](LICENSE)
|
|
43
|
+
|
|
44
|
+
Asynchronous wrapper around [openpyxl](https://openpyxl.readthedocs.io/) with the complete
|
|
45
|
+
openpyxl API surface, built on [anyio](https://anyio.readthedocs.io/) so it works on **asyncio
|
|
46
|
+
and trio** alike. openpyxl is synchronous, CPU-bound and not thread-safe: calling it on the event
|
|
47
|
+
loop stalls every other request, and merely moving it to a thread lets a second coroutine corrupt
|
|
48
|
+
the file silently. aioopenpyxl runs the operations that can block in worker threads, serialises
|
|
49
|
+
all work on one workbook, and makes synchronous access to a workbook a thread currently owns
|
|
50
|
+
raise instead of racing. It is an independent project, not affiliated with or endorsed by
|
|
51
|
+
openpyxl; please report problems with this wrapper here.
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
uv add aioopenpyxl # or: pip install aioopenpyxl
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Python 3.10 or newer (including the free-threaded 3.14t build); depends on `anyio`, `openpyxl`,
|
|
60
|
+
`types-openpyxl` and `typing_extensions`.
|
|
61
|
+
|
|
62
|
+
## Quick start
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import aioopenpyxl
|
|
66
|
+
|
|
67
|
+
async with aioopenpyxl.load_workbook("data.xlsx", read_only=True) as wb: # read, off the loop
|
|
68
|
+
ws = wb.active
|
|
69
|
+
async for row in ws.iter_rows(values_only=True):
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
wb = aioopenpyxl.Workbook() # same signature as openpyxl.Workbook(write_only=..., iso_dates=...)
|
|
73
|
+
ws = wb.active
|
|
74
|
+
ws["A1"] = "header" # in-memory: forwarded directly, no thread hop
|
|
75
|
+
await ws.append_rows(rows) # whole batch in one thread hop
|
|
76
|
+
await wb.save("output.xlsx") # off the event loop
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def fill(raw_ws): # bulk in-memory work: plain openpyxl code, one hop, workbook locked meanwhile
|
|
80
|
+
for i, item in enumerate(items, start=2):
|
|
81
|
+
raw_ws.cell(i, 1, item.name)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
await ws.run(fill)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Wrap an openpyxl workbook you already have with `aioopenpyxl.Workbook.wrap(existing_workbook)`.
|
|
88
|
+
`Workbook` is a real class: `isinstance`, annotations and subclassing work as with
|
|
89
|
+
`openpyxl.Workbook`, and a subclass can keep attributes of its own.
|
|
90
|
+
|
|
91
|
+
## What runs where
|
|
92
|
+
|
|
93
|
+
| Operation | Where | Why |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| `await load_workbook(...)`, `await load_workbook_bytes(data)`, `await wb.save(...)`, `await wb.to_bytes()`, `await wb.close()` | worker thread | real I/O, XML parsing / writing |
|
|
96
|
+
| `async for row in ws.iter_rows(..., chunk_size=1024, prefetch=0)`, `ws.rows`, `ws.values`, `ws.columns`, `async for row in ws` | worker thread, one hop per `chunk_size` rows; with `prefetch=N` the thread parses `N` chunks ahead | read-only sheets parse XML lazily |
|
|
97
|
+
| `await ws.read_rows(...)`, `await ws.fetch(key)`, `await ws.calculate_dimension()` | worker thread, one hop | coarse-grained reads |
|
|
98
|
+
| `await ws.append_rows(rows)` | worker thread, one hop | bulk insert |
|
|
99
|
+
| `await ws.append(row)` | inline for regular sheets, thread for write-only sheets | write-only sheets spool to a temp file |
|
|
100
|
+
| `await wb.run(fn)`, `await ws.run(fn)` | worker thread, one hop | *your* bulk in-memory work |
|
|
101
|
+
| `ws["A1"]`, `ws.cell()`, `ws.title`, `ws.merge_cells()`, `ws.insert_rows()`, `wb.create_sheet()`, styles, dimensions ... | inline on the event loop | in-memory operations |
|
|
102
|
+
| `ws["A1"]`, `ws.cell()` on a **read-only** sheet | raises `BlockingCallError` | openpyxl would parse XML on the event loop; use `fetch` / `read_rows` / `run` |
|
|
103
|
+
|
|
104
|
+
Keep `chunk_size` at 256 or more (each chunk is one thread round trip); for large exports use
|
|
105
|
+
`Workbook(write_only=True)` with `append_rows`. The internals are explained in [docs/design.md](docs/design.md).
|
|
106
|
+
|
|
107
|
+
## Rules of the road
|
|
108
|
+
|
|
109
|
+
- **A thread owns the workbook while an `await` is pending.** Synchronous access meanwhile
|
|
110
|
+
(`ws.cell(...)`, `wb.sheetnames`, even `repr(wb)`) raises `WorkbookBusyError`; await first or
|
|
111
|
+
move the work into `run(...)`.
|
|
112
|
+
- **Inside a `prefetch>0` loop, never await the same workbook.** The loop holds the semaphore, so
|
|
113
|
+
`await ws.run(...)` or a second `async for` from the body hangs rather than erroring. Use
|
|
114
|
+
`contextlib.aclosing(...)` around the iterator when you may leave such a loop early.
|
|
115
|
+
- **Read-only sheets have no synchronous cell access.** `ws["A1"]` / `ws.cell()` raise
|
|
116
|
+
`BlockingCallError`; use `await ws.fetch(key)`, `await ws.read_rows(...)` or `run`.
|
|
117
|
+
- **Cancellation waits for the thread**, including native `Task.cancel()` / `asyncio.timeout`;
|
|
118
|
+
it takes effect at the next checkpoint, and `async with` always closes the workbook.
|
|
119
|
+
- **`import aioopenpyxl as openpyxl` keeps the helpers synchronous.** `aioopenpyxl.styles`,
|
|
120
|
+
`aioopenpyxl.workbook.Workbook` ... are openpyxl's own modules; only the top-level `Workbook`,
|
|
121
|
+
`load_workbook` and `open` are asynchronous.
|
|
122
|
+
- **The guard covers the wrappers, not the objects they hand out.** A `Cell` from `ws["A1"]`,
|
|
123
|
+
a `Font`, a `ColumnDimension` or `cell.parent` is a plain openpyxl object; mutating it while an
|
|
124
|
+
`await` on the same workbook is pending races with the thread. Finish or await the operation
|
|
125
|
+
first, or do such edits inside `run(...)`.
|
|
126
|
+
- **`wb.wrapped` / `ws.wrapped` are unguarded**: the raw openpyxl objects, no busy check. Keep
|
|
127
|
+
blocking calls on them inside `run(...)`.
|
|
128
|
+
|
|
129
|
+
## Differences from openpyxl
|
|
130
|
+
|
|
131
|
+
| openpyxl | aioopenpyxl |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| `load_workbook(...)` | `await load_workbook(...)` or `async with load_workbook(...) as wb` |
|
|
134
|
+
| `wb.save(f)`, `wb.close()` | `await wb.save(f)`, `await wb.to_bytes()`, `await wb.close()` |
|
|
135
|
+
| `for row in ws.iter_rows()` / `ws.rows` / `ws.values` / `for row in ws` | `async for` versions (chunked); `iter_rows` / `iter_cols` gain `chunk_size=` and `prefetch=` |
|
|
136
|
+
| `ws.append(row)` | `await ws.append(row)`; plus `await ws.append_rows(rows)` |
|
|
137
|
+
| `ws["A1"]` on a read-only sheet | `BlockingCallError`; use `await ws.fetch("A1")` |
|
|
138
|
+
| – | `await ws.read_rows(...)`, `await x.run(fn)`, `x.wrapped`, `limiter=` |
|
|
139
|
+
|
|
140
|
+
Every other public member is forwarded with its typed openpyxl signature; the full table and the
|
|
141
|
+
typing, sub-module and subclass rules are in [docs/compatibility.md](docs/compatibility.md).
|
|
142
|
+
|
|
143
|
+
## Development
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
uv sync && uv run pytest -q # both backends, random order
|
|
147
|
+
uv run ruff check . && uv run ruff format --check .
|
|
148
|
+
uv run ty check src tests && uv run mypy
|
|
149
|
+
uv run python tools/gen_proxies.py && uv run ruff format src/aioopenpyxl/ # after an openpyxl / stubs bump
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the workflow and [CHANGELOG.md](CHANGELOG.md) for history.
|
|
153
|
+
|
|
154
|
+
## Acknowledgements
|
|
155
|
+
|
|
156
|
+
All the real work is done by [openpyxl](https://openpyxl.readthedocs.io/) (MIT), which this
|
|
157
|
+
package depends on rather than vendors. The typed forwarders and `.pyi` shims are generated from
|
|
158
|
+
the [types-openpyxl](https://pypi.org/project/types-openpyxl/) stubs maintained in
|
|
159
|
+
[typeshed](https://github.com/python/typeshed) (Apache-2.0); concurrency primitives come from
|
|
160
|
+
[anyio](https://anyio.readthedocs.io/) (MIT).
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
[MIT](LICENSE). openpyxl, typeshed and anyio remain under their own licenses.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# aioopenpyxl
|
|
2
|
+
|
|
3
|
+
[](https://github.com/yamaaaaaa31/aioopenpyxl/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/aioopenpyxl/)
|
|
5
|
+
[](https://pypi.org/project/aioopenpyxl/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
Asynchronous wrapper around [openpyxl](https://openpyxl.readthedocs.io/) with the complete
|
|
9
|
+
openpyxl API surface, built on [anyio](https://anyio.readthedocs.io/) so it works on **asyncio
|
|
10
|
+
and trio** alike. openpyxl is synchronous, CPU-bound and not thread-safe: calling it on the event
|
|
11
|
+
loop stalls every other request, and merely moving it to a thread lets a second coroutine corrupt
|
|
12
|
+
the file silently. aioopenpyxl runs the operations that can block in worker threads, serialises
|
|
13
|
+
all work on one workbook, and makes synchronous access to a workbook a thread currently owns
|
|
14
|
+
raise instead of racing. It is an independent project, not affiliated with or endorsed by
|
|
15
|
+
openpyxl; please report problems with this wrapper here.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
uv add aioopenpyxl # or: pip install aioopenpyxl
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Python 3.10 or newer (including the free-threaded 3.14t build); depends on `anyio`, `openpyxl`,
|
|
24
|
+
`types-openpyxl` and `typing_extensions`.
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import aioopenpyxl
|
|
30
|
+
|
|
31
|
+
async with aioopenpyxl.load_workbook("data.xlsx", read_only=True) as wb: # read, off the loop
|
|
32
|
+
ws = wb.active
|
|
33
|
+
async for row in ws.iter_rows(values_only=True):
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
wb = aioopenpyxl.Workbook() # same signature as openpyxl.Workbook(write_only=..., iso_dates=...)
|
|
37
|
+
ws = wb.active
|
|
38
|
+
ws["A1"] = "header" # in-memory: forwarded directly, no thread hop
|
|
39
|
+
await ws.append_rows(rows) # whole batch in one thread hop
|
|
40
|
+
await wb.save("output.xlsx") # off the event loop
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def fill(raw_ws): # bulk in-memory work: plain openpyxl code, one hop, workbook locked meanwhile
|
|
44
|
+
for i, item in enumerate(items, start=2):
|
|
45
|
+
raw_ws.cell(i, 1, item.name)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
await ws.run(fill)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Wrap an openpyxl workbook you already have with `aioopenpyxl.Workbook.wrap(existing_workbook)`.
|
|
52
|
+
`Workbook` is a real class: `isinstance`, annotations and subclassing work as with
|
|
53
|
+
`openpyxl.Workbook`, and a subclass can keep attributes of its own.
|
|
54
|
+
|
|
55
|
+
## What runs where
|
|
56
|
+
|
|
57
|
+
| Operation | Where | Why |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| `await load_workbook(...)`, `await load_workbook_bytes(data)`, `await wb.save(...)`, `await wb.to_bytes()`, `await wb.close()` | worker thread | real I/O, XML parsing / writing |
|
|
60
|
+
| `async for row in ws.iter_rows(..., chunk_size=1024, prefetch=0)`, `ws.rows`, `ws.values`, `ws.columns`, `async for row in ws` | worker thread, one hop per `chunk_size` rows; with `prefetch=N` the thread parses `N` chunks ahead | read-only sheets parse XML lazily |
|
|
61
|
+
| `await ws.read_rows(...)`, `await ws.fetch(key)`, `await ws.calculate_dimension()` | worker thread, one hop | coarse-grained reads |
|
|
62
|
+
| `await ws.append_rows(rows)` | worker thread, one hop | bulk insert |
|
|
63
|
+
| `await ws.append(row)` | inline for regular sheets, thread for write-only sheets | write-only sheets spool to a temp file |
|
|
64
|
+
| `await wb.run(fn)`, `await ws.run(fn)` | worker thread, one hop | *your* bulk in-memory work |
|
|
65
|
+
| `ws["A1"]`, `ws.cell()`, `ws.title`, `ws.merge_cells()`, `ws.insert_rows()`, `wb.create_sheet()`, styles, dimensions ... | inline on the event loop | in-memory operations |
|
|
66
|
+
| `ws["A1"]`, `ws.cell()` on a **read-only** sheet | raises `BlockingCallError` | openpyxl would parse XML on the event loop; use `fetch` / `read_rows` / `run` |
|
|
67
|
+
|
|
68
|
+
Keep `chunk_size` at 256 or more (each chunk is one thread round trip); for large exports use
|
|
69
|
+
`Workbook(write_only=True)` with `append_rows`. The internals are explained in [docs/design.md](docs/design.md).
|
|
70
|
+
|
|
71
|
+
## Rules of the road
|
|
72
|
+
|
|
73
|
+
- **A thread owns the workbook while an `await` is pending.** Synchronous access meanwhile
|
|
74
|
+
(`ws.cell(...)`, `wb.sheetnames`, even `repr(wb)`) raises `WorkbookBusyError`; await first or
|
|
75
|
+
move the work into `run(...)`.
|
|
76
|
+
- **Inside a `prefetch>0` loop, never await the same workbook.** The loop holds the semaphore, so
|
|
77
|
+
`await ws.run(...)` or a second `async for` from the body hangs rather than erroring. Use
|
|
78
|
+
`contextlib.aclosing(...)` around the iterator when you may leave such a loop early.
|
|
79
|
+
- **Read-only sheets have no synchronous cell access.** `ws["A1"]` / `ws.cell()` raise
|
|
80
|
+
`BlockingCallError`; use `await ws.fetch(key)`, `await ws.read_rows(...)` or `run`.
|
|
81
|
+
- **Cancellation waits for the thread**, including native `Task.cancel()` / `asyncio.timeout`;
|
|
82
|
+
it takes effect at the next checkpoint, and `async with` always closes the workbook.
|
|
83
|
+
- **`import aioopenpyxl as openpyxl` keeps the helpers synchronous.** `aioopenpyxl.styles`,
|
|
84
|
+
`aioopenpyxl.workbook.Workbook` ... are openpyxl's own modules; only the top-level `Workbook`,
|
|
85
|
+
`load_workbook` and `open` are asynchronous.
|
|
86
|
+
- **The guard covers the wrappers, not the objects they hand out.** A `Cell` from `ws["A1"]`,
|
|
87
|
+
a `Font`, a `ColumnDimension` or `cell.parent` is a plain openpyxl object; mutating it while an
|
|
88
|
+
`await` on the same workbook is pending races with the thread. Finish or await the operation
|
|
89
|
+
first, or do such edits inside `run(...)`.
|
|
90
|
+
- **`wb.wrapped` / `ws.wrapped` are unguarded**: the raw openpyxl objects, no busy check. Keep
|
|
91
|
+
blocking calls on them inside `run(...)`.
|
|
92
|
+
|
|
93
|
+
## Differences from openpyxl
|
|
94
|
+
|
|
95
|
+
| openpyxl | aioopenpyxl |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `load_workbook(...)` | `await load_workbook(...)` or `async with load_workbook(...) as wb` |
|
|
98
|
+
| `wb.save(f)`, `wb.close()` | `await wb.save(f)`, `await wb.to_bytes()`, `await wb.close()` |
|
|
99
|
+
| `for row in ws.iter_rows()` / `ws.rows` / `ws.values` / `for row in ws` | `async for` versions (chunked); `iter_rows` / `iter_cols` gain `chunk_size=` and `prefetch=` |
|
|
100
|
+
| `ws.append(row)` | `await ws.append(row)`; plus `await ws.append_rows(rows)` |
|
|
101
|
+
| `ws["A1"]` on a read-only sheet | `BlockingCallError`; use `await ws.fetch("A1")` |
|
|
102
|
+
| – | `await ws.read_rows(...)`, `await x.run(fn)`, `x.wrapped`, `limiter=` |
|
|
103
|
+
|
|
104
|
+
Every other public member is forwarded with its typed openpyxl signature; the full table and the
|
|
105
|
+
typing, sub-module and subclass rules are in [docs/compatibility.md](docs/compatibility.md).
|
|
106
|
+
|
|
107
|
+
## Development
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
uv sync && uv run pytest -q # both backends, random order
|
|
111
|
+
uv run ruff check . && uv run ruff format --check .
|
|
112
|
+
uv run ty check src tests && uv run mypy
|
|
113
|
+
uv run python tools/gen_proxies.py && uv run ruff format src/aioopenpyxl/ # after an openpyxl / stubs bump
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the workflow and [CHANGELOG.md](CHANGELOG.md) for history.
|
|
117
|
+
|
|
118
|
+
## Acknowledgements
|
|
119
|
+
|
|
120
|
+
All the real work is done by [openpyxl](https://openpyxl.readthedocs.io/) (MIT), which this
|
|
121
|
+
package depends on rather than vendors. The typed forwarders and `.pyi` shims are generated from
|
|
122
|
+
the [types-openpyxl](https://pypi.org/project/types-openpyxl/) stubs maintained in
|
|
123
|
+
[typeshed](https://github.com/python/typeshed) (Apache-2.0); concurrency primitives come from
|
|
124
|
+
[anyio](https://anyio.readthedocs.io/) (MIT).
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
[MIT](LICENSE). openpyxl, typeshed and anyio remain under their own licenses.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "aioopenpyxl"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Asynchronous wrapper around openpyxl for asyncio and trio, built on anyio"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
keywords = [
|
|
10
|
+
"openpyxl",
|
|
11
|
+
"asyncio",
|
|
12
|
+
"trio",
|
|
13
|
+
"anyio",
|
|
14
|
+
"excel",
|
|
15
|
+
"xlsx",
|
|
16
|
+
"async",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 3 - Alpha",
|
|
20
|
+
"Framework :: AsyncIO",
|
|
21
|
+
"Framework :: AnyIO",
|
|
22
|
+
"Framework :: Trio",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Programming Language :: Python :: 3.13",
|
|
30
|
+
"Programming Language :: Python :: 3.14",
|
|
31
|
+
"Programming Language :: Python :: Free Threading :: 3 - Stable",
|
|
32
|
+
"Topic :: Office/Business :: Financial :: Spreadsheet",
|
|
33
|
+
"Typing :: Typed",
|
|
34
|
+
]
|
|
35
|
+
dependencies = [
|
|
36
|
+
"anyio>=4.5",
|
|
37
|
+
"openpyxl>=3.1",
|
|
38
|
+
"types-openpyxl>=3.1.5.20250506",
|
|
39
|
+
"typing_extensions>=4.5",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[[project.authors]]
|
|
43
|
+
name = "yamaaaaaa31"
|
|
44
|
+
email = "143375737+yamaaaaaa31@users.noreply.github.com"
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Homepage = "https://github.com/yamaaaaaa31/aioopenpyxl"
|
|
48
|
+
Documentation = "https://github.com/yamaaaaaa31/aioopenpyxl#readme"
|
|
49
|
+
Repository = "https://github.com/yamaaaaaa31/aioopenpyxl"
|
|
50
|
+
Issues = "https://github.com/yamaaaaaa31/aioopenpyxl/issues"
|
|
51
|
+
Changelog = "https://github.com/yamaaaaaa31/aioopenpyxl/blob/main/CHANGELOG.md"
|
|
52
|
+
|
|
53
|
+
[dependency-groups]
|
|
54
|
+
dev = [
|
|
55
|
+
"pytest>=8",
|
|
56
|
+
"pytest-timeout>=2.3",
|
|
57
|
+
"pytest-randomly>=3.15",
|
|
58
|
+
"trio>=0.27",
|
|
59
|
+
"ruff>=0.9",
|
|
60
|
+
"ty>=0.0.1",
|
|
61
|
+
"mypy>=1.10",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[build-system]
|
|
65
|
+
requires = ["uv_build>=0.12.19,<0.13.0"]
|
|
66
|
+
build-backend = "uv_build"
|
|
67
|
+
|
|
68
|
+
[tool.pytest.ini_options]
|
|
69
|
+
testpaths = ["tests"]
|
|
70
|
+
timeout = 60
|
|
71
|
+
filterwarnings = ["error"]
|
|
72
|
+
|
|
73
|
+
[tool.ruff]
|
|
74
|
+
line-length = 100
|
|
75
|
+
target-version = "py310"
|
|
76
|
+
|
|
77
|
+
[tool.ruff.lint]
|
|
78
|
+
select = [
|
|
79
|
+
"E",
|
|
80
|
+
"F",
|
|
81
|
+
"I",
|
|
82
|
+
"UP",
|
|
83
|
+
"B",
|
|
84
|
+
"ASYNC",
|
|
85
|
+
"RUF",
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
[tool.ruff.lint.per-file-ignores]
|
|
89
|
+
"*.pyi" = [
|
|
90
|
+
"F401",
|
|
91
|
+
"F403",
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
[tool.ty.environment]
|
|
95
|
+
python-version = "3.10"
|
|
96
|
+
|
|
97
|
+
[tool.mypy]
|
|
98
|
+
python_version = "3.10"
|
|
99
|
+
files = [
|
|
100
|
+
"src",
|
|
101
|
+
"tests",
|
|
102
|
+
]
|
|
103
|
+
strict = false
|
|
104
|
+
warn_unused_ignores = true
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "aioopenpyxl"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Asynchronous wrapper around openpyxl for asyncio and trio, built on anyio"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "yamaaaaaa31", email = "143375737+yamaaaaaa31@users.noreply.github.com" }
|
|
10
|
+
]
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
keywords = ["openpyxl", "asyncio", "trio", "anyio", "excel", "xlsx", "async"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 3 - Alpha",
|
|
15
|
+
"Framework :: AsyncIO",
|
|
16
|
+
"Framework :: AnyIO",
|
|
17
|
+
"Framework :: Trio",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Programming Language :: Python :: 3.14",
|
|
26
|
+
"Programming Language :: Python :: Free Threading :: 3 - Stable",
|
|
27
|
+
"Topic :: Office/Business :: Financial :: Spreadsheet",
|
|
28
|
+
"Typing :: Typed",
|
|
29
|
+
]
|
|
30
|
+
dependencies = [
|
|
31
|
+
# anyio.Lock(fast_acquire=True) needs 4.5
|
|
32
|
+
"anyio>=4.5",
|
|
33
|
+
"openpyxl>=3.1",
|
|
34
|
+
# The generated public signatures reference stub-only names from types-openpyxl
|
|
35
|
+
# (_CellGetValue, _CellSetValue, _VisibilityType, _SerialisableTreeElement ...);
|
|
36
|
+
# 3.1.5.20250506 is the first release that defines all of them.
|
|
37
|
+
"types-openpyxl>=3.1.5.20250506",
|
|
38
|
+
# The generator re-emits @deprecated
|
|
39
|
+
"typing_extensions>=4.5",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Homepage = "https://github.com/yamaaaaaa31/aioopenpyxl"
|
|
44
|
+
Documentation = "https://github.com/yamaaaaaa31/aioopenpyxl#readme"
|
|
45
|
+
Repository = "https://github.com/yamaaaaaa31/aioopenpyxl"
|
|
46
|
+
Issues = "https://github.com/yamaaaaaa31/aioopenpyxl/issues"
|
|
47
|
+
Changelog = "https://github.com/yamaaaaaa31/aioopenpyxl/blob/main/CHANGELOG.md"
|
|
48
|
+
|
|
49
|
+
[dependency-groups]
|
|
50
|
+
dev = [
|
|
51
|
+
"pytest>=8",
|
|
52
|
+
"pytest-timeout>=2.3",
|
|
53
|
+
"pytest-randomly>=3.15",
|
|
54
|
+
"trio>=0.27",
|
|
55
|
+
"ruff>=0.9",
|
|
56
|
+
"ty>=0.0.1",
|
|
57
|
+
"mypy>=1.10",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[build-system]
|
|
61
|
+
requires = ["uv_build>=0.12.19,<0.13.0"]
|
|
62
|
+
build-backend = "uv_build"
|
|
63
|
+
|
|
64
|
+
[tool.pytest.ini_options]
|
|
65
|
+
testpaths = ["tests"]
|
|
66
|
+
timeout = 60
|
|
67
|
+
filterwarnings = ["error"]
|
|
68
|
+
|
|
69
|
+
[tool.ruff]
|
|
70
|
+
line-length = 100
|
|
71
|
+
target-version = "py310"
|
|
72
|
+
|
|
73
|
+
[tool.ruff.lint]
|
|
74
|
+
select = ["E", "F", "I", "UP", "B", "ASYNC", "RUF"]
|
|
75
|
+
|
|
76
|
+
[tool.ruff.lint.per-file-ignores]
|
|
77
|
+
# Generated `.pyi` shims consist of `from openpyxl.x import *` only
|
|
78
|
+
"*.pyi" = ["F401", "F403"]
|
|
79
|
+
|
|
80
|
+
[tool.ty.environment]
|
|
81
|
+
python-version = "3.10"
|
|
82
|
+
|
|
83
|
+
[tool.mypy]
|
|
84
|
+
python_version = "3.10"
|
|
85
|
+
files = ["src", "tests"]
|
|
86
|
+
strict = false
|
|
87
|
+
warn_unused_ignores = true
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""aioopenpyxl -- asynchronous wrapper around openpyxl.
|
|
2
|
+
|
|
3
|
+
import aioopenpyxl
|
|
4
|
+
|
|
5
|
+
async with aioopenpyxl.load_workbook("data.xlsx", read_only=True) as wb:
|
|
6
|
+
ws = wb.active
|
|
7
|
+
async for row in ws.iter_rows(values_only=True):
|
|
8
|
+
...
|
|
9
|
+
|
|
10
|
+
wb = aioopenpyxl.Workbook()
|
|
11
|
+
ws = wb.active
|
|
12
|
+
ws["A1"] = "header" # in-memory: forwarded directly
|
|
13
|
+
await ws.append_rows(rows) # one thread hop for the whole batch
|
|
14
|
+
await wb.save("output.xlsx") # off the event loop
|
|
15
|
+
|
|
16
|
+
Built on anyio: works on asyncio and trio alike.
|
|
17
|
+
|
|
18
|
+
:class:`Workbook` is a class (``AsyncWorkbook`` is a backwards-compatible
|
|
19
|
+
alias), so it works in annotations and ``isinstance`` checks and has the same
|
|
20
|
+
constructor signature as ``openpyxl.Workbook``; :meth:`Workbook.wrap` wraps an
|
|
21
|
+
existing openpyxl workbook. Every public openpyxl member is available on the
|
|
22
|
+
wrappers. Blocking calls (loading, saving, parsing rows of read-only sheets,
|
|
23
|
+
spooling rows of write-only sheets, ``run(...)``) execute in a worker thread
|
|
24
|
+
and are serialised per workbook; while one is in flight, synchronous access
|
|
25
|
+
raises :class:`WorkbookBusyError` instead of racing.
|
|
26
|
+
|
|
27
|
+
``import aioopenpyxl as openpyxl`` is supported as a migration path: the
|
|
28
|
+
top-level ``Workbook`` / ``load_workbook`` / ``open`` are the *async* wrappers
|
|
29
|
+
(``save``/``close``/``load`` must be awaited), while openpyxl's sub-packages
|
|
30
|
+
(``aioopenpyxl.styles``, ``aioopenpyxl.utils`` ...) and its module-level
|
|
31
|
+
constants (``LXML``, ``DEBUG`` ...) are the very same objects as openpyxl's.
|
|
32
|
+
Note that ``aioopenpyxl.workbook.Workbook`` and
|
|
33
|
+
``aioopenpyxl.reader.excel.load_workbook`` are therefore the *synchronous*
|
|
34
|
+
openpyxl originals; only the top-level names are asynchronous.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
from __future__ import annotations
|
|
38
|
+
|
|
39
|
+
import sys
|
|
40
|
+
from typing import TYPE_CHECKING, Any
|
|
41
|
+
|
|
42
|
+
# Module-level constants openpyxl exposes; re-exported explicitly so that
|
|
43
|
+
# static analysis sees them (the ``__getattr__`` fallback below is runtime only).
|
|
44
|
+
from openpyxl import (
|
|
45
|
+
DEBUG,
|
|
46
|
+
DEFUSEDXML,
|
|
47
|
+
LXML,
|
|
48
|
+
NUMPY,
|
|
49
|
+
__author__,
|
|
50
|
+
__author_email__,
|
|
51
|
+
__license__,
|
|
52
|
+
__maintainer_email__,
|
|
53
|
+
__url__,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
from ._compat import install_module_aliases
|
|
57
|
+
from ._errors import BlockingCallError, WorkbookBusyError
|
|
58
|
+
from ._executor import Runner, run_sync
|
|
59
|
+
from ._reader import LoadWorkbookContextManager, load_workbook, load_workbook_bytes
|
|
60
|
+
from ._workbook import AsyncWorkbook, Workbook
|
|
61
|
+
from ._worksheet import DEFAULT_CHUNK_SIZE, AsyncChartsheet, AsyncWorksheet
|
|
62
|
+
|
|
63
|
+
#: aioopenpyxl's own version (not openpyxl's).
|
|
64
|
+
__version__ = "0.1.0"
|
|
65
|
+
|
|
66
|
+
#: Alias mirroring ``openpyxl.open``.
|
|
67
|
+
open = load_workbook
|
|
68
|
+
|
|
69
|
+
__all__ = [
|
|
70
|
+
"DEBUG",
|
|
71
|
+
"DEFAULT_CHUNK_SIZE",
|
|
72
|
+
"DEFUSEDXML",
|
|
73
|
+
"LXML",
|
|
74
|
+
"NUMPY",
|
|
75
|
+
"AsyncChartsheet",
|
|
76
|
+
"AsyncWorkbook",
|
|
77
|
+
"AsyncWorksheet",
|
|
78
|
+
"BlockingCallError",
|
|
79
|
+
"LoadWorkbookContextManager",
|
|
80
|
+
"Runner",
|
|
81
|
+
"Workbook",
|
|
82
|
+
"WorkbookBusyError",
|
|
83
|
+
"__author__",
|
|
84
|
+
"__author_email__",
|
|
85
|
+
"__license__",
|
|
86
|
+
"__maintainer_email__",
|
|
87
|
+
"__url__",
|
|
88
|
+
"__version__",
|
|
89
|
+
"load_workbook",
|
|
90
|
+
"load_workbook_bytes",
|
|
91
|
+
"open",
|
|
92
|
+
"run_sync",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
install_module_aliases(sys.modules[__name__])
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
if not TYPE_CHECKING:
|
|
99
|
+
# Runtime-only safety net for anything openpyxl may add at module level in
|
|
100
|
+
# a future release. Hidden from type checkers so that a typo on
|
|
101
|
+
# ``aioopenpyxl.<name>`` is reported instead of silently becoming ``Any``.
|
|
102
|
+
def __getattr__(name: str) -> Any:
|
|
103
|
+
import openpyxl as _openpyxl
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
return getattr(_openpyxl, name)
|
|
107
|
+
except AttributeError:
|
|
108
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from None
|