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.
Files changed (195) hide show
  1. aioopenpyxl-0.1.0/LICENSE +21 -0
  2. aioopenpyxl-0.1.0/PKG-INFO +164 -0
  3. aioopenpyxl-0.1.0/README.md +128 -0
  4. aioopenpyxl-0.1.0/pyproject.toml +104 -0
  5. aioopenpyxl-0.1.0/pyproject.toml.orig +87 -0
  6. aioopenpyxl-0.1.0/src/aioopenpyxl/__init__.py +108 -0
  7. aioopenpyxl-0.1.0/src/aioopenpyxl/_base.py +104 -0
  8. aioopenpyxl-0.1.0/src/aioopenpyxl/_compat.py +71 -0
  9. aioopenpyxl-0.1.0/src/aioopenpyxl/_errors.py +26 -0
  10. aioopenpyxl-0.1.0/src/aioopenpyxl/_executor.py +539 -0
  11. aioopenpyxl-0.1.0/src/aioopenpyxl/_generated.py +870 -0
  12. aioopenpyxl-0.1.0/src/aioopenpyxl/_reader.py +141 -0
  13. aioopenpyxl-0.1.0/src/aioopenpyxl/_workbook.py +257 -0
  14. aioopenpyxl-0.1.0/src/aioopenpyxl/_worksheet.py +821 -0
  15. aioopenpyxl-0.1.0/src/aioopenpyxl/cell/__init__.pyi +4 -0
  16. aioopenpyxl-0.1.0/src/aioopenpyxl/cell/cell.pyi +4 -0
  17. aioopenpyxl-0.1.0/src/aioopenpyxl/cell/read_only.pyi +4 -0
  18. aioopenpyxl-0.1.0/src/aioopenpyxl/cell/rich_text.pyi +4 -0
  19. aioopenpyxl-0.1.0/src/aioopenpyxl/cell/text.pyi +4 -0
  20. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/__init__.pyi +4 -0
  21. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/area_chart.pyi +4 -0
  22. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/axis.pyi +4 -0
  23. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/bar_chart.pyi +4 -0
  24. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/bubble_chart.pyi +4 -0
  25. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/chartspace.pyi +4 -0
  26. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/data_source.pyi +4 -0
  27. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/descriptors.pyi +4 -0
  28. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/error_bar.pyi +4 -0
  29. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/label.pyi +4 -0
  30. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/layout.pyi +4 -0
  31. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/legend.pyi +4 -0
  32. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/line_chart.pyi +4 -0
  33. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/marker.pyi +4 -0
  34. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/picture.pyi +4 -0
  35. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/pie_chart.pyi +4 -0
  36. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/pivot.pyi +4 -0
  37. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/plotarea.pyi +4 -0
  38. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/print_settings.pyi +4 -0
  39. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/radar_chart.pyi +4 -0
  40. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/reader.pyi +4 -0
  41. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/reference.pyi +4 -0
  42. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/scatter_chart.pyi +4 -0
  43. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/series.pyi +4 -0
  44. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/series_factory.pyi +4 -0
  45. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/shapes.pyi +4 -0
  46. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/stock_chart.pyi +4 -0
  47. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/surface_chart.pyi +4 -0
  48. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/text.pyi +4 -0
  49. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/title.pyi +4 -0
  50. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/trendline.pyi +4 -0
  51. aioopenpyxl-0.1.0/src/aioopenpyxl/chart/updown_bars.pyi +4 -0
  52. aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/__init__.pyi +4 -0
  53. aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/chartsheet.pyi +4 -0
  54. aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/custom.pyi +4 -0
  55. aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/properties.pyi +4 -0
  56. aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/protection.pyi +4 -0
  57. aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/publish.pyi +4 -0
  58. aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/relation.pyi +4 -0
  59. aioopenpyxl-0.1.0/src/aioopenpyxl/chartsheet/views.pyi +4 -0
  60. aioopenpyxl-0.1.0/src/aioopenpyxl/comments/__init__.pyi +4 -0
  61. aioopenpyxl-0.1.0/src/aioopenpyxl/comments/author.pyi +4 -0
  62. aioopenpyxl-0.1.0/src/aioopenpyxl/comments/comment_sheet.pyi +4 -0
  63. aioopenpyxl-0.1.0/src/aioopenpyxl/comments/comments.pyi +4 -0
  64. aioopenpyxl-0.1.0/src/aioopenpyxl/comments/shape_writer.pyi +4 -0
  65. aioopenpyxl-0.1.0/src/aioopenpyxl/compat/__init__.pyi +4 -0
  66. aioopenpyxl-0.1.0/src/aioopenpyxl/compat/abc.pyi +4 -0
  67. aioopenpyxl-0.1.0/src/aioopenpyxl/compat/numbers.pyi +4 -0
  68. aioopenpyxl-0.1.0/src/aioopenpyxl/compat/product.pyi +4 -0
  69. aioopenpyxl-0.1.0/src/aioopenpyxl/compat/singleton.pyi +4 -0
  70. aioopenpyxl-0.1.0/src/aioopenpyxl/compat/strings.pyi +4 -0
  71. aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/__init__.pyi +4 -0
  72. aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/base.pyi +4 -0
  73. aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/container.pyi +4 -0
  74. aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/excel.pyi +4 -0
  75. aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/namespace.pyi +4 -0
  76. aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/nested.pyi +4 -0
  77. aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/sequence.pyi +4 -0
  78. aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/serialisable.pyi +4 -0
  79. aioopenpyxl-0.1.0/src/aioopenpyxl/descriptors/slots.pyi +4 -0
  80. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/__init__.pyi +4 -0
  81. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/colors.pyi +4 -0
  82. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/connector.pyi +4 -0
  83. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/drawing.pyi +4 -0
  84. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/effect.pyi +4 -0
  85. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/fill.pyi +4 -0
  86. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/geometry.pyi +4 -0
  87. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/graphic.pyi +4 -0
  88. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/image.pyi +4 -0
  89. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/line.pyi +4 -0
  90. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/picture.pyi +4 -0
  91. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/properties.pyi +4 -0
  92. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/relation.pyi +4 -0
  93. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/spreadsheet_drawing.pyi +4 -0
  94. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/text.pyi +4 -0
  95. aioopenpyxl-0.1.0/src/aioopenpyxl/drawing/xdr.pyi +4 -0
  96. aioopenpyxl-0.1.0/src/aioopenpyxl/formatting/__init__.pyi +4 -0
  97. aioopenpyxl-0.1.0/src/aioopenpyxl/formatting/formatting.pyi +4 -0
  98. aioopenpyxl-0.1.0/src/aioopenpyxl/formatting/rule.pyi +4 -0
  99. aioopenpyxl-0.1.0/src/aioopenpyxl/formula/__init__.pyi +4 -0
  100. aioopenpyxl-0.1.0/src/aioopenpyxl/formula/tokenizer.pyi +4 -0
  101. aioopenpyxl-0.1.0/src/aioopenpyxl/formula/translate.pyi +4 -0
  102. aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/__init__.pyi +4 -0
  103. aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/core.pyi +4 -0
  104. aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/custom.pyi +4 -0
  105. aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/extended.pyi +4 -0
  106. aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/interface.pyi +4 -0
  107. aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/manifest.pyi +4 -0
  108. aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/relationship.pyi +4 -0
  109. aioopenpyxl-0.1.0/src/aioopenpyxl/packaging/workbook.pyi +4 -0
  110. aioopenpyxl-0.1.0/src/aioopenpyxl/pivot/__init__.pyi +4 -0
  111. aioopenpyxl-0.1.0/src/aioopenpyxl/pivot/cache.pyi +4 -0
  112. aioopenpyxl-0.1.0/src/aioopenpyxl/pivot/fields.pyi +4 -0
  113. aioopenpyxl-0.1.0/src/aioopenpyxl/pivot/record.pyi +4 -0
  114. aioopenpyxl-0.1.0/src/aioopenpyxl/pivot/table.pyi +4 -0
  115. aioopenpyxl-0.1.0/src/aioopenpyxl/py.typed +0 -0
  116. aioopenpyxl-0.1.0/src/aioopenpyxl/reader/__init__.pyi +4 -0
  117. aioopenpyxl-0.1.0/src/aioopenpyxl/reader/drawings.pyi +4 -0
  118. aioopenpyxl-0.1.0/src/aioopenpyxl/reader/excel.pyi +4 -0
  119. aioopenpyxl-0.1.0/src/aioopenpyxl/reader/strings.pyi +4 -0
  120. aioopenpyxl-0.1.0/src/aioopenpyxl/reader/workbook.pyi +4 -0
  121. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/__init__.pyi +4 -0
  122. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/alignment.pyi +4 -0
  123. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/borders.pyi +4 -0
  124. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/builtins.pyi +4 -0
  125. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/cell_style.pyi +4 -0
  126. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/colors.pyi +4 -0
  127. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/differential.pyi +4 -0
  128. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/fills.pyi +4 -0
  129. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/fonts.pyi +4 -0
  130. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/named_styles.pyi +4 -0
  131. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/numbers.pyi +4 -0
  132. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/protection.pyi +4 -0
  133. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/proxy.pyi +4 -0
  134. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/styleable.pyi +4 -0
  135. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/stylesheet.pyi +4 -0
  136. aioopenpyxl-0.1.0/src/aioopenpyxl/styles/table.pyi +4 -0
  137. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/__init__.pyi +4 -0
  138. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/bound_dictionary.pyi +4 -0
  139. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/cell.pyi +4 -0
  140. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/dataframe.pyi +4 -0
  141. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/datetime.pyi +4 -0
  142. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/escape.pyi +4 -0
  143. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/exceptions.pyi +4 -0
  144. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/formulas.pyi +4 -0
  145. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/indexed_list.pyi +4 -0
  146. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/inference.pyi +4 -0
  147. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/protection.pyi +4 -0
  148. aioopenpyxl-0.1.0/src/aioopenpyxl/utils/units.pyi +4 -0
  149. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/__init__.pyi +4 -0
  150. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/child.pyi +4 -0
  151. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/defined_name.pyi +4 -0
  152. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/external_link/__init__.pyi +4 -0
  153. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/external_link/external.pyi +4 -0
  154. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/external_reference.pyi +4 -0
  155. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/function_group.pyi +4 -0
  156. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/properties.pyi +4 -0
  157. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/protection.pyi +4 -0
  158. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/smart_tags.pyi +4 -0
  159. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/views.pyi +4 -0
  160. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/web.pyi +4 -0
  161. aioopenpyxl-0.1.0/src/aioopenpyxl/workbook/workbook.pyi +4 -0
  162. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/__init__.pyi +4 -0
  163. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/cell_range.pyi +4 -0
  164. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/cell_watch.pyi +4 -0
  165. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/controls.pyi +4 -0
  166. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/copier.pyi +4 -0
  167. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/custom.pyi +4 -0
  168. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/datavalidation.pyi +4 -0
  169. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/dimensions.pyi +4 -0
  170. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/drawing.pyi +4 -0
  171. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/errors.pyi +4 -0
  172. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/filters.pyi +4 -0
  173. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/formula.pyi +4 -0
  174. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/header_footer.pyi +4 -0
  175. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/hyperlink.pyi +4 -0
  176. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/merge.pyi +4 -0
  177. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/ole.pyi +4 -0
  178. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/page.pyi +4 -0
  179. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/pagebreak.pyi +4 -0
  180. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/picture.pyi +4 -0
  181. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/print_settings.pyi +4 -0
  182. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/properties.pyi +4 -0
  183. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/protection.pyi +4 -0
  184. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/related.pyi +4 -0
  185. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/scenario.pyi +4 -0
  186. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/smart_tag.pyi +4 -0
  187. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/table.pyi +4 -0
  188. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/views.pyi +4 -0
  189. aioopenpyxl-0.1.0/src/aioopenpyxl/worksheet/worksheet.pyi +4 -0
  190. aioopenpyxl-0.1.0/src/aioopenpyxl/writer/__init__.pyi +4 -0
  191. aioopenpyxl-0.1.0/src/aioopenpyxl/writer/excel.pyi +4 -0
  192. aioopenpyxl-0.1.0/src/aioopenpyxl/writer/theme.pyi +4 -0
  193. aioopenpyxl-0.1.0/src/aioopenpyxl/xml/__init__.pyi +4 -0
  194. aioopenpyxl-0.1.0/src/aioopenpyxl/xml/constants.pyi +4 -0
  195. 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
+ [![CI](https://github.com/yamaaaaaa31/aioopenpyxl/actions/workflows/ci.yml/badge.svg)](https://github.com/yamaaaaaa31/aioopenpyxl/actions/workflows/ci.yml)
40
+ [![PyPI](https://img.shields.io/pypi/v/aioopenpyxl.svg)](https://pypi.org/project/aioopenpyxl/)
41
+ [![Python versions](https://img.shields.io/pypi/pyversions/aioopenpyxl.svg)](https://pypi.org/project/aioopenpyxl/)
42
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](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
+ [![CI](https://github.com/yamaaaaaa31/aioopenpyxl/actions/workflows/ci.yml/badge.svg)](https://github.com/yamaaaaaa31/aioopenpyxl/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/aioopenpyxl.svg)](https://pypi.org/project/aioopenpyxl/)
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/aioopenpyxl.svg)](https://pypi.org/project/aioopenpyxl/)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](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