pyOpenVBA 6.1.3__tar.gz → 6.2.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 (236) hide show
  1. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/PKG-INFO +4 -2
  2. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/README.md +3 -1
  3. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/excel_checklist.csv +72 -7
  4. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/host_completeness.md +3 -3
  5. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/vba_runtime.md +182 -8
  6. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/pyproject.toml +1 -1
  7. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/__init__.py +1 -1
  8. pyopenvba-6.2.0/src/pyopenvba/_relationships.py +90 -0
  9. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_autofill.py +1 -0
  10. pyopenvba-6.2.0/src/pyopenvba/apps/excel/_cell_styles.py +1120 -0
  11. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_clipboard.py +25 -0
  12. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_dimensions.py +2 -0
  13. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_editing.py +4 -1
  14. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_formats.py +73 -23
  15. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_formula_format.py +18 -0
  16. pyopenvba-6.2.0/src/pyopenvba/apps/excel/_hyperlinks.py +553 -0
  17. pyopenvba-6.2.0/src/pyopenvba/apps/excel/_hyperlinks_file.py +280 -0
  18. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_io.py +58 -27
  19. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_model.py +113 -0
  20. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_protection.py +7 -1
  21. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_row_formats.py +4 -0
  22. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_sheet_copy.py +5 -1
  23. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_sort.py +5 -0
  24. pyopenvba-6.2.0/src/pyopenvba/apps/excel/_styles.py +1404 -0
  25. pyopenvba-6.2.0/src/pyopenvba/apps/excel/_text_columns.py +428 -0
  26. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_typing.py +233 -69
  27. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_runtime.py +3 -0
  28. pyopenvba-6.1.3/src/pyopenvba/apps/excel/_styles.py +0 -862
  29. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/.gitignore +0 -0
  30. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/LICENSE.md +0 -0
  31. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/architecture.md +0 -0
  32. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/ms-ovba-implementation-guide_v2.md +0 -0
  33. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/power_query.md +0 -0
  34. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/research/access_complex/README.md +0 -0
  35. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/research/access_designs/README.md +0 -0
  36. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/research/access_macros/README.md +0 -0
  37. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/research/access_write/README.md +0 -0
  38. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/research/pcode/README.md +0 -0
  39. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/docs/roadmap.md +0 -0
  40. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/__main__.py +0 -0
  41. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_a1.py +0 -0
  42. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_deflate.py +0 -0
  43. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_host.py +0 -0
  44. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_new_project.py +0 -0
  45. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_oforms_pages.py +0 -0
  46. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_oforms_records.py +0 -0
  47. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_package_signature.py +0 -0
  48. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_ppt_container.py +0 -0
  49. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_references.py +0 -0
  50. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/__init__.py +0 -0
  51. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/blank_files/blank_database.accdb +0 -0
  52. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/blank_files/blank_database_module.accdb +0 -0
  53. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/blank_files/blank_document.docm +0 -0
  54. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/blank_files/blank_excel_addin.xlam +0 -0
  55. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/blank_files/blank_presentation.pptm +0 -0
  56. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/blank_files/blank_workbook.xlsb +0 -0
  57. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/blank_files/blank_workbook.xlsm +0 -0
  58. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/blank_files/blank_workbook.xlsx +0 -0
  59. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/blank_files/engine_skeleton.accdb +0 -0
  60. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/blank_files/engine_skeleton.mdb +0 -0
  61. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/designs/form.blob +0 -0
  62. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/designs/form.lvprop +0 -0
  63. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/designs/form.propdata +0 -0
  64. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/designs/form.prototypes +0 -0
  65. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/designs/form.typeinfo +0 -0
  66. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/designs/report.blob +0 -0
  67. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/designs/report.lvprop +0 -0
  68. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/designs/report.propdata +0 -0
  69. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/designs/report.prototypes +0 -0
  70. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_templates/designs/report.typeinfo +0 -0
  71. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/_xml.py +0 -0
  72. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/__init__.py +0 -0
  73. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_alloc.py +0 -0
  74. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_btree.py +0 -0
  75. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_collation.py +0 -0
  76. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_collation_general_legacy.py +0 -0
  77. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_compact.py +0 -0
  78. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_complex.py +0 -0
  79. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_datapage.py +0 -0
  80. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_ddl.py +0 -0
  81. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_designs.py +0 -0
  82. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_facade.py +0 -0
  83. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_format.py +0 -0
  84. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_index.py +0 -0
  85. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_lval.py +0 -0
  86. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_macros.py +0 -0
  87. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_pages.py +0 -0
  88. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_props.py +0 -0
  89. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_queries.py +0 -0
  90. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_rows.py +0 -0
  91. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_schema.py +0 -0
  92. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_sql.py +0 -0
  93. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_storage.py +0 -0
  94. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_tdef.py +0 -0
  95. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_validate.py +0 -0
  96. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/_vba.py +0 -0
  97. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access/database.py +0 -0
  98. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/access_read.py +0 -0
  99. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/__init__.py +0 -0
  100. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/__init__.py +0 -0
  101. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_arrays.py +0 -0
  102. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_autofilter.py +0 -0
  103. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_bridge.py +0 -0
  104. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_calc.py +0 -0
  105. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_control_refs.py +0 -0
  106. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_controls.py +0 -0
  107. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_copy_names.py +0 -0
  108. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_duplicates.py +0 -0
  109. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_dynamic_file.py +0 -0
  110. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_engine_book.py +0 -0
  111. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_evaluate.py +0 -0
  112. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_events.py +0 -0
  113. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_find.py +0 -0
  114. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_font_rows.py +0 -0
  115. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_merges.py +0 -0
  116. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_named_api.py +0 -0
  117. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_names.py +0 -0
  118. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_notes.py +0 -0
  119. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_notes_file.py +0 -0
  120. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_number_format.py +0 -0
  121. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_radios.py +0 -0
  122. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_refresh.py +0 -0
  123. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_region.py +0 -0
  124. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_shape_api.py +0 -0
  125. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_shapes.py +0 -0
  126. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_shared.py +0 -0
  127. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_sheet_move.py +0 -0
  128. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_special_cells.py +0 -0
  129. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_spills.py +0 -0
  130. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_table_edits.py +0 -0
  131. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_tables.py +0 -0
  132. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_validation.py +0 -0
  133. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_visible.py +0 -0
  134. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_windows.py +0 -0
  135. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/excel/_worksheet_functions.py +0 -0
  136. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/powerpoint/__init__.py +0 -0
  137. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/powerpoint/_bridge.py +0 -0
  138. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/powerpoint/_io.py +0 -0
  139. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/powerpoint/_model.py +0 -0
  140. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/word/__init__.py +0 -0
  141. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/word/_bridge.py +0 -0
  142. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/word/_io.py +0 -0
  143. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/apps/word/_model.py +0 -0
  144. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/cfb.py +0 -0
  145. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/excel.py +0 -0
  146. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/exceptions.py +0 -0
  147. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/forms.py +0 -0
  148. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/__init__.py +0 -0
  149. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_arity.py +0 -0
  150. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/__init__.py +0 -0
  151. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/catalog.py +0 -0
  152. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/cells.py +0 -0
  153. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/collate.py +0 -0
  154. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/dates.py +0 -0
  155. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/evaluator.py +0 -0
  156. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/__init__.py +0 -0
  157. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/aggregate.py +0 -0
  158. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/arithmetic.py +0 -0
  159. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/arrays.py +0 -0
  160. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/common.py +0 -0
  161. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/conditional.py +0 -0
  162. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/database.py +0 -0
  163. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/dates.py +0 -0
  164. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/distributions.py +0 -0
  165. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/engineering.py +0 -0
  166. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/financial.py +0 -0
  167. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/information.py +0 -0
  168. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/lambdas.py +0 -0
  169. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/logical.py +0 -0
  170. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/lookup.py +0 -0
  171. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/matrix.py +0 -0
  172. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/statistics.py +0 -0
  173. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/subtotal.py +0 -0
  174. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/functions/text.py +0 -0
  175. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/host.py +0 -0
  176. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/lexer.py +0 -0
  177. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/nodes.py +0 -0
  178. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/numbers.py +0 -0
  179. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/parser.py +0 -0
  180. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/precise.py +0 -0
  181. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/reference.py +0 -0
  182. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/registry.py +0 -0
  183. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/special.py +0 -0
  184. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_calc/values.py +0 -0
  185. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_deep.py +0 -0
  186. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_display.py +0 -0
  187. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_formula2.py +0 -0
  188. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_inventory.py +0 -0
  189. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_parse.py +0 -0
  190. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_prefixes.py +0 -0
  191. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_r1c1.py +0 -0
  192. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_spell.py +0 -0
  193. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_structured.py +0 -0
  194. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/formula/_values.py +0 -0
  195. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/__init__.py +0 -0
  196. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_ast.py +0 -0
  197. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_constants_data.py +0 -0
  198. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_intrinsics.py +0 -0
  199. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_inventory.py +0 -0
  200. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_inventory_data.py +0 -0
  201. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_lex.py +0 -0
  202. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_objects.py +0 -0
  203. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_parse.py +0 -0
  204. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_preprocess.py +0 -0
  205. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_scripting.py +0 -0
  206. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/interpreter/_values.py +0 -0
  207. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/mlang/__init__.py +0 -0
  208. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/mlang/_eval.py +0 -0
  209. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/mlang/_inventory.py +0 -0
  210. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/mlang/_inventory_data.py +0 -0
  211. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/mlang/_library.py +0 -0
  212. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/mlang/_parse.py +0 -0
  213. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/mlang/_values.py +0 -0
  214. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerpoint.py +0 -0
  215. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerquery/__init__.py +0 -0
  216. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerquery/_binary.py +0 -0
  217. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerquery/_files.py +0 -0
  218. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerquery/_mashup.py +0 -0
  219. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerquery/_metadata.py +0 -0
  220. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerquery/_opc.py +0 -0
  221. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerquery/_package.py +0 -0
  222. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerquery/_refresh.py +0 -0
  223. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerquery/_section.py +0 -0
  224. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerquery/_sheets.py +0 -0
  225. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/powerquery/workbook.py +0 -0
  226. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/shapes/__init__.py +0 -0
  227. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/shapes/_docx.py +0 -0
  228. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/shapes/_docx_text.py +0 -0
  229. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/shapes/_drawingml.py +0 -0
  230. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/shapes/_pptx.py +0 -0
  231. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/shapes/_values.py +0 -0
  232. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/shapes/_xlsx.py +0 -0
  233. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/vba.py +0 -0
  234. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/vba_pcode.py +0 -0
  235. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/src/pyopenvba/word.py +0 -0
  236. {pyopenvba-6.1.3 → pyopenvba-6.2.0}/tests/fuzz_corpus/README.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyOpenVBA
3
- Version: 6.1.3
3
+ Version: 6.2.0
4
4
  Summary: Read and write VBA macros and Excel Power Query in pure Python, no dependencies.
5
5
  Project-URL: Homepage, https://github.com/WilliamSmithEdward/pyOpenVBA
6
6
  Project-URL: Repository, https://github.com/WilliamSmithEdward/pyOpenVBA
@@ -746,7 +746,9 @@ it, and a save adds only the stylesheet entries the file lacks, spelled
746
746
  as Excel spells them. Formatting whole rows, whole columns or the whole
747
747
  sheet keeps the row, column and sheet formats Excel keeps, with the
748
748
  cells Excel makes where they cross, and saves them as Excel does. Named
749
- cell styles and conditional formats are not implemented yet.
749
+ cell styles (`Range.Style`, `Workbook.Styles` and the `Style` object)
750
+ and hyperlinks (`Hyperlinks.Add` and the `Hyperlink` object) behave and
751
+ save as Excel's do. Conditional formats are not implemented yet.
750
752
 
751
753
  Row heights, column widths and hidden rows and columns behave as they do
752
754
  in Excel on a 96-DPI display, the one the model emulates: `RowHeight = 20`
@@ -709,7 +709,9 @@ it, and a save adds only the stylesheet entries the file lacks, spelled
709
709
  as Excel spells them. Formatting whole rows, whole columns or the whole
710
710
  sheet keeps the row, column and sheet formats Excel keeps, with the
711
711
  cells Excel makes where they cross, and saves them as Excel does. Named
712
- cell styles and conditional formats are not implemented yet.
712
+ cell styles (`Range.Style`, `Workbook.Styles` and the `Style` object)
713
+ and hyperlinks (`Hyperlinks.Add` and the `Hyperlink` object) behave and
714
+ save as Excel's do. Conditional formats are not implemented yet.
713
715
 
714
716
  Row heights, column widths and hidden rows and columns behave as they do
715
717
  in Excel on a 96-DPI display, the one the model emulates: `RowHeight = 20`
@@ -432,7 +432,7 @@ Font,Strikethrough,property,As Variant,,VERIFIED,tests/fixtures/range_format.jso
432
432
  Font,Subscript,property,As Variant,,VERIFIED,tests/fixtures/range_format.json; tests/fixtures/format/formats_answers.json; tests/test_live_excel_model_gate.py,
433
433
  Font,Superscript,property,As Variant,,VERIFIED,tests/fixtures/range_format.json; tests/fixtures/format/formats_answers.json; tests/test_live_excel_model_gate.py,
434
434
  Font,ThemeColor,property,As Variant,,VERIFIED,tests/fixtures/range_format.json; tests/fixtures/format/formats_answers.json; tests/test_live_excel_model_gate.py,
435
- Font,ThemeFont,property,As XlThemeFont,,MISSING,,
435
+ Font,ThemeFont,property,As XlThemeFont,,PARTIAL,tests/fixtures/cell_styles/style_changes.json,Read; setting it on a range reports unsupported.
436
436
  Font,TintAndShade,property,As Variant,,VERIFIED,tests/fixtures/range_format.json; tests/fixtures/format/formats_answers.json; tests/test_live_excel_model_gate.py,
437
437
  Font,Underline,property,As Variant,,PARTIAL,tests/fixtures/range_format.json; tests/fixtures/format/formats_answers.json; tests/test_live_excel_model_gate.py,"Values other than the five styles, True, False and 3 report unsupported."
438
438
  GroupShapes,_Default,method,_Default(Index As Variant) As Shape,,MISSING,,
@@ -443,6 +443,31 @@ GroupShapes,Creator,"property, read-only",As XlCreator,,MISSING,,
443
443
  GroupShapes,Item,method,Item(Index As Variant) As Shape,,UNASSESSED,,
444
444
  GroupShapes,Parent,"property, read-only",As Object,,MISSING,,
445
445
  GroupShapes,Range,"property, read-only",As ShapeRange,,MISSING,,
446
+ Hyperlink,Address,property,As String,,PARTIAL,tests/fixtures/hyperlinks/hyperlinks.json; tests/test_live_excel_model_gate.py,"Kept as Excel tidies it -- an http, https or ftp address's scheme and host in lower case, its path resolved, a # splitting off the subaddress -- for the kinds of address measured; saved with a DOS path relative to the workbook's folder. Setting it keeps the subaddress unless the new address has a # of its own."
447
+ Hyperlink,AddToFavorites,method,AddToFavorites(),,EXCLUDED,,Adds the address to the browser's favourites.
448
+ Hyperlink,Application,"property, read-only",As Application,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,
449
+ Hyperlink,CreateNewDocument,method,"CreateNewDocument(Filename As String, EditNow As Boolean, Overwrite As Boolean)",,EXCLUDED,,Creates and opens a document of another application.
450
+ Hyperlink,Creator,"property, read-only",As XlCreator,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,
451
+ Hyperlink,Delete,method,Delete(),,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,"Its cells go back to the default format, merges kept. On a protected sheet a locked cell keeps its link, error 1004."
452
+ Hyperlink,EmailSubject,property,As String,,PARTIAL,tests/fixtures/hyperlinks/hyperlinks.json,"The subject of a mailto address, which setting it writes in, in place of one it names, or takes out; """" for no address; another address fails. Set on a link with no address, which leaves Excel refusing every change after it, it reports unsupported."
453
+ Hyperlink,Follow,method,"Follow([NewWindow As Variant], [AddHistory As Variant], [ExtraInfo As Variant], [Method As Variant], [HeaderInfo As Variant])",,EXCLUDED,,Opens the address in another application.
454
+ Hyperlink,Name,"property, read-only",As String,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,"The text to show it was given, or ""address - subaddress"", which follows a new address; read from a file without a display, its cell's text. Setting it is error 450."
455
+ Hyperlink,Parent,"property, read-only",As Object,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,Its cells.
456
+ Hyperlink,Range,"property, read-only",As Range,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,
457
+ Hyperlink,ScreenTip,property,As String,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json; tests/test_live_excel_model_gate.py,
458
+ Hyperlink,Shape,"property, read-only",As Shape,,PARTIAL,tests/fixtures/hyperlinks/hyperlinks.json,Error 1004 for a link on cells; a link on a shape is not implemented.
459
+ Hyperlink,SubAddress,property,As String,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json; tests/test_live_excel_model_gate.py,Setting it takes the address away.
460
+ Hyperlink,TextToDisplay,property,As String,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json; tests/test_live_excel_model_gate.py,"The text the first cell holds, """" for a number or a formula; setting it writes the first cell and names the link, """" doing nothing."
461
+ Hyperlink,Type,"property, read-only",As Long,,PARTIAL,tests/fixtures/hyperlinks/hyperlinks.json,0 for a link on cells; a link on a shape is not implemented.
462
+ Hyperlinks,_Default,"property, read-only",As Hyperlink,,MISSING,,
463
+ Hyperlinks,_NewEnum,"property, read-only",As IUnknown,,MISSING,,
464
+ Hyperlinks,Add,method,"Add(Anchor As Object, Address As String, [SubAddress As Variant], [ScreenTip As Variant], [TextToDisplay As Variant]) As Object",,PARTIAL,tests/fixtures/hyperlinks/hyperlinks.json; tests/test_live_excel_model_gate.py,"A link on each area of the anchor, the last answered; over the very cells of a link it takes that link's place. The cells take the Hyperlink style, and the first the text to show or, when empty, the address. SubAddress, ScreenTip and TextToDisplay not strings are error 5. A protected sheet needs AllowInsertingHyperlinks and unlocked cells. A shape anchor reports unsupported."
465
+ Hyperlinks,Application,"property, read-only",As Application,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,
466
+ Hyperlinks,Count,"property, read-only",As Long,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,
467
+ Hyperlinks,Creator,"property, read-only",As XlCreator,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,
468
+ Hyperlinks,Delete,method,Delete(),,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,"Every link the collection holds goes, its cells back to the default format."
469
+ Hyperlinks,Item,"property, read-only",As Hyperlink,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,"By place in the sheet's order or by name; 0, past the last and an unknown name are error 9."
470
+ Hyperlinks,Parent,"property, read-only",As Object,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,"The worksheet, a range's collection's too."
446
471
  Interior,Application,"property, read-only",As Application,,UNASSESSED,,
447
472
  Interior,Color,property,As Variant,,PARTIAL,tests/fixtures/range_format.json; tests/fixtures/format/formats_answers.json; tests/test_live_excel_model_gate.py,A gradient fill reports unsupported.
448
473
  Interior,ColorIndex,property,As Variant,,PARTIAL,tests/fixtures/range_format.json; tests/fixtures/format/formats_answers.json; tests/test_live_excel_model_gate.py,A gradient fill reports unsupported.
@@ -631,7 +656,7 @@ Range,Clear,method,Clear() As Variant,,PARTIAL,tests/fixtures/excel_model/probes
631
656
  Range,ClearComments,method,ClearComments(),,VERIFIED,tests/fixtures/excel_model/probes.txt,
632
657
  Range,ClearContents,method,ClearContents([RemoveControls As Variant]) As Variant,no RemoveControls,PARTIAL,tests/fixtures/excel_model/probes.txt; tests/fixtures/row_formats/row_formats.json; tests/fixtures/autofilter_edits.json,"An emptied cell in the format its row or column gives it goes. On a filtered sheet only the visible cells clear, and clearing a filter's whole header row turns the filter off."
633
658
  Range,ClearFormats,method,ClearFormats() As Variant,,VERIFIED,tests/fixtures/range_format.json; tests/fixtures/format/formats_answers.json; tests/test_live_excel_model_gate.py; tests/fixtures/row_formats/row_formats.json; tests/fixtures/autofilter_edits.json,"Whole rows and columns lose their own formats, and positions a column's or row's format still reaches get a cell in the default format. On a filtered sheet only the visible cells, and clearing a filter's whole header row turns the filter off."
634
- Range,ClearHyperlinks,method,ClearHyperlinks(),,MISSING,,
659
+ Range,ClearHyperlinks,method,ClearHyperlinks(),,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,The links the range holds go; their cells keep their formats.
635
660
  Range,ClearNotes,method,ClearNotes() As Variant,,VERIFIED,tests/fixtures/excel_model/probes.txt,The same as ClearComments.
636
661
  Range,ClearOutline,method,ClearOutline() As Variant,,MISSING,,
637
662
  Range,Column,"property, read-only",As Long,,PARTIAL,tests/fixtures/excel_model/probes.txt,
@@ -697,7 +722,7 @@ Range,HasSpill,"property, read-only",As Variant,,VERIFIED,tests/fixtures/dynamic
697
722
  Range,Height,"property, read-only",As Variant,,PARTIAL,tests/fixtures/dimensions.json; tests/fixtures/dimensions/dimensions_answers.json; tests/fixtures/font_rows.json,"A row grows with its fonts from a measured table of eleven families; one resting on another font, a mix of tables, super- or subscript, or wrapped or turned text keeps its file's height until it changes, then reports unsupported."
698
723
  Range,Hidden,property,As Variant,,PARTIAL,tests/fixtures/dimensions.json; tests/fixtures/dimensions/dimensions_answers.json; tests/fixtures/autofilter_edits.json,"Hiding every row, or rows down to the last one, makes hidden the sheet's default as Excel does; a block that stops short of the last row is hidden row by row, and whether Excel switches over for a large one was not measured. On a filtered sheet a block with shown rows reaches only those, so showing it does nothing; showing columns there over hidden ones reports itself unsupported."
699
724
  Range,HorizontalAlignment,property,As Variant,,VERIFIED,tests/fixtures/range_format.json; tests/fixtures/format/formats_answers.json; tests/test_live_excel_model_gate.py,
700
- Range,Hyperlinks,"property, read-only",As Hyperlinks,,MISSING,,
725
+ Range,Hyperlinks,"property, read-only",As Hyperlinks,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json,"The links inside one of its areas, and for one area the link it lies in."
701
726
  Range,ID,property,As String,,MISSING,,
702
727
  Range,IndentLevel,property,As Variant,,VERIFIED,tests/fixtures/range_format.json; tests/fixtures/format/formats_answers.json; tests/test_live_excel_model_gate.py,
703
728
  Range,Insert,method,"Insert([Shift As Variant], [CopyOrigin As Variant]) As Variant",,PARTIAL,tests/fixtures/range_edit.json; tests/fixtures/excel_model/probes.txt; tests/fixtures/row_formats/row_formats.json; tests/fixtures/autofilter_edits.json; tests/fixtures/cell_shifts.json,"Whole rows and columns rewrite references, and a new row or column takes the formats beside it. Cells shifted down or right rewrite references as Excel does and take the formats above or to the left; with no Shift a range taller than it is wide shifts right. Sheets with merges or shapes and several areas of cells report unsupported. Shifting cells on a sheet whose rows or columns carry formats, and CopyOrigin:=xlFormatFromRightOrBelow, report unsupported. On a filtered sheet whole rows go in as many as the range shows, at its top, and inserting cells is error 1004."
@@ -778,13 +803,13 @@ Range,Speak,method,"Speak([SpeakDirection As Variant], [SpeakFormulas As Variant
778
803
  Range,SpecialCells,method,"SpecialCells(Type As XlCellType, [Value As Variant]) As Range",,PARTIAL,tests/fixtures/special_cells.json; tests/fixtures/excel_model/probes.txt,"Constants and formulas by kind, blanks, the last cell, visible cells and the cells with notes, split into areas as Excel splits them; validation and conditional formats report themselves unsupported."
779
804
  Range,SpillingToRange,"property, read-only",As Range,,VERIFIED,tests/fixtures/dynamic_arrays.json,The block a dynamic-array formula in the first cell spilled into; Nothing for any other cell.
780
805
  Range,SpillParent,"property, read-only",As Range,,VERIFIED,tests/fixtures/dynamic_arrays.json,The cell of the dynamic-array formula whose answer spilled over the first cell; Nothing where none did.
781
- Range,Style,property,As Variant,,MISSING,,
806
+ Range,Style,property,As Variant,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,"The cells' style, Nothing where they differ; set by name in any case or by Style object, the parts the style includes replaced and the rest kept. Error 450 for any other name or value, and on a protected sheet unless AllowFormattingCells."
782
807
  Range,SubscribeTo,method,"SubscribeTo(Edition As String, [Format As XlSubscribeToFormat]) As Variant",,MISSING,,
783
808
  Range,Subtotal,method,"Subtotal(GroupBy As Long, Function As XlConsolidationFunction, TotalList As Variant, [Replace As Variant], [PageBreaks As Variant], [SummaryBelowData As XlSummaryRow]) As Variant",,MISSING,,
784
809
  Range,Summary,"property, read-only",As Variant,,MISSING,,
785
810
  Range,Table,method,"Table([RowInput As Variant], [ColumnInput As Variant]) As Variant",,MISSING,,
786
811
  Range,Text,"property, read-only",As Variant,,PARTIAL,tests/fixtures/excel_model/probes.txt; tests/fixtures/number_formats.json; tests/fixtures/number_spelling.json; tests/fixtures/value_typing.json,"Excel's number formats on a US English system, in a column wide enough for the value; a value a format cannot show fills the column with #. A * fill reports itself unsupported, and a value too wide for its column, which Excel cuts to # or fewer digits, is not modelled."
787
- Range,TextToColumns,method,"TextToColumns([Destination As Variant], [DataType As XlTextParsingType], [TextQualifier As XlTextQualifier], [ConsecutiveDelimiter As Variant], [Tab As Variant], [Semicolon As Variant], [Comma As Variant], [Space As Variant], [Other As Variant], [OtherChar As Variant], [FieldInfo As Variant], [DecimalSeparator As Variant], [ThousandsSeparator As Variant], [TrailingMinusNumbers As Variant]) As Variant",,MISSING,,
812
+ Range,TextToColumns,method,"TextToColumns([Destination As Variant], [DataType As XlTextParsingType], [TextQualifier As XlTextQualifier], [ConsecutiveDelimiter As Variant], [Tab As Variant], [Semicolon As Variant], [Comma As Variant], [Space As Variant], [Other As Variant], [OtherChar As Variant], [FieldInfo As Variant], [DecimalSeparator As Variant], [ThousandsSeparator As Variant], [TrailingMinusNumbers As Variant]) As Variant",,PARTIAL,tests/fixtures/text_to_columns.json,"Delimited and fixed width, every delimiter, runs of them, qualifiers, typing, FieldInfo's kinds and how each date order reads a field, separators, a trailing minus and a destination as Excel does them. FieldInfo pairs that do not number the columns 1, 2, 3 in order, a column of formulas and a sheet with merged cells report themselves unsupported; an omitted argument takes its default, whether Excel carries one over from an earlier call not being measured."
788
813
  Range,TogglePythonMarshalMode,method,TogglePythonMarshalMode([MarshalMode As Variant]),,MISSING,,
789
814
  Range,Top,"property, read-only",As Variant,,PARTIAL,tests/fixtures/dimensions.json; tests/fixtures/dimensions/dimensions_answers.json; tests/fixtures/font_rows.json,"A row grows with its fonts from a measured table of eleven families; one resting on another font, a mix of tables, super- or subscript, or wrapped or turned text keeps its file's height until it changes, then reports unsupported."
790
815
  Range,Ungroup,method,Ungroup() As Variant,,MISSING,,
@@ -1031,6 +1056,46 @@ SortFields,Count,"property, read-only",As Long,,VERIFIED,tests/fixtures/sort.jso
1031
1056
  SortFields,Creator,"property, read-only",As XlCreator,,MISSING,,
1032
1057
  SortFields,Item,"property, read-only",As SortField,,UNASSESSED,,
1033
1058
  SortFields,Parent,"property, read-only",As Object,,MISSING,,
1059
+ Style,_Default,"property, read-only",As String,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,
1060
+ Style,AddIndent,property,As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set; each cell that follows the style follows it while the style includes the part.
1061
+ Style,Application,"property, read-only",As Application,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,
1062
+ Style,Borders,"property, read-only",As Borders,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,"xlLeft, xlRight, xlTop and xlBottom, and 1 to 4, are its edges and 5 and 6 its diagonals, set as a range's are; Borders(7) to Borders(12) read -4142 and 2 where edge 1 to 6 has a line in the automatic colour, else Null, and setting one does nothing. A property set on the collection sets all six; one read reports unsupported."
1063
+ Style,BuiltIn,"property, read-only",As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,"Setting it is error 450, as in Excel."
1064
+ Style,Creator,"property, read-only",As XlCreator,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,
1065
+ Style,Delete,method,Delete() As Variant,,PARTIAL,tests/fixtures/cell_styles/style_changes.json,"Its cells go to Normal, every part they did not set themselves following Normal from then on; a built-in style stays in the file, hidden. Normal is error 1004, as is a workbook with a protected sheet."
1066
+ Style,Font,"property, read-only",As Font,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,"Read and set as a range's are; Superscript and Subscript read False while the style leaves its font out. Normal's font takes colours and strikethrough; its size, face, bold, italic and underline, which the sheets' geometry rests on, report unsupported."
1067
+ Style,FormulaHidden,property,As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set; each cell that follows the style follows it while the style includes the part.
1068
+ Style,HorizontalAlignment,property,As XlHAlign,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set; each cell that follows the style follows it while the style includes the part.
1069
+ Style,IncludeAlignment,property,As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set: a part included again reaches the cells that took it from the style; one left out stays with them as it is.
1070
+ Style,IncludeBorder,property,As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set: a part included again reaches the cells that took it from the style; one left out stays with them as it is.
1071
+ Style,IncludeFont,property,As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set: a part included again reaches the cells that took it from the style; one left out stays with them as it is.
1072
+ Style,IncludeNumber,property,As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set: a part included again reaches the cells that took it from the style; one left out stays with them as it is.
1073
+ Style,IncludePatterns,property,As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set: a part included again reaches the cells that took it from the style; one left out stays with them as it is.
1074
+ Style,IncludeProtection,property,As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set: a part included again reaches the cells that took it from the style; one left out stays with them as it is.
1075
+ Style,IndentLevel,property,As Long,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,"Null unless aligned left, right or distributed and not turned. Read and set; each cell that follows the style follows it while the style includes the part."
1076
+ Style,Interior,"property, read-only",As Interior,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,"Read and set as a range's are, but its automatic pattern colour stays white or black, as it is, where a cell's turns black."
1077
+ Style,Locked,property,As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set; each cell that follows the style follows it while the style includes the part.
1078
+ Style,MergeCells,property,As Variant,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,"Error 1004, as Excel's is."
1079
+ Style,Name,"property, read-only",As String,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,"Setting it is error 450, as in Excel."
1080
+ Style,NameLocal,"property, read-only",As String,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,"Setting it is error 1004, as in Excel."
1081
+ Style,NumberFormat,property,As String,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set; each cell that follows the style follows it while the style includes the part.
1082
+ Style,NumberFormatLocal,property,As String,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set; each cell that follows the style follows it while the style includes the part.
1083
+ Style,Orientation,property,As XlOrientation,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set; each cell that follows the style follows it while the style includes the part.
1084
+ Style,Parent,"property, read-only",As Object,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,
1085
+ Style,ReadingOrder,property,As Long,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set; each cell that follows the style follows it while the style includes the part.
1086
+ Style,ShrinkToFit,property,As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set; each cell that follows the style follows it while the style includes the part.
1087
+ Style,Value,"property, read-only",As String,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,"Setting it is error 450, as in Excel."
1088
+ Style,VerticalAlignment,property,As XlVAlign,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set; each cell that follows the style follows it while the style includes the part.
1089
+ Style,WrapText,property,As Boolean,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,Read and set; each cell that follows the style follows it while the style includes the part.
1090
+ Styles,_Default,"property, read-only",As Style,,MISSING,,
1091
+ Styles,_NewEnum,"property, read-only",As IUnknown,,MISSING,,
1092
+ Styles,Add,method,"Add(Name As String, [BasedOn As Variant]) As Style",,PARTIAL,tests/fixtures/cell_styles/cell_styles.json; tests/fixtures/cell_styles/style_changes.json,"A copy of Normal, or of the first cell of BasedOn without the parts its cells do not share. A name with no characters (Excel's Style 1) reports unsupported."
1093
+ Styles,Application,"property, read-only",As Application,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,
1094
+ Styles,Count,"property, read-only",As Long,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,
1095
+ Styles,Creator,"property, read-only",As XlCreator,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,
1096
+ Styles,Item,"property, read-only",As Style,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,By name in any case or by place in the sorted list.
1097
+ Styles,Merge,method,Merge(Workbook As Variant) As Variant,,PARTIAL,tests/fixtures/cell_styles/style_changes.json,"A style named as one here takes its place, keeping this workbook's spelling, and reaches the cells that follow it; the rest come in the order their names sort. A workbook with another theme, a Normal that differs and a built-in style this workbook deleted report unsupported."
1098
+ Styles,Parent,"property, read-only",As Object,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,
1034
1099
  TextFrame,Application,"property, read-only",As Application,,MISSING,,
1035
1100
  TextFrame,AutoMargins,property,As Boolean,,MISSING,,
1036
1101
  TextFrame,AutoSize,property,As Boolean,no setter,UNASSESSED,,
@@ -1366,7 +1431,7 @@ Workbook,ShowPivotTableFieldList,property,As Boolean,,MISSING,,
1366
1431
  Workbook,Signatures,"property, read-only",As SignatureSet,,MISSING,,
1367
1432
  Workbook,SlicerCaches,"property, read-only",As SlicerCaches,,MISSING,,
1368
1433
  Workbook,SmartDocument,"property, read-only",As SmartDocument,,MISSING,,
1369
- Workbook,Styles,"property, read-only",As Styles,,MISSING,,
1434
+ Workbook,Styles,"property, read-only",As Styles,,PARTIAL,tests/fixtures/cell_styles/cell_styles.json,"Excel's 47 built-in styles and every one the file or a macro adds, in the order Windows word sort puts their names."
1370
1435
  Workbook,Sync,event,Sync(SyncEventType As MsoSyncEventType),,MISSING,,
1371
1436
  Workbook,TableStyles,"property, read-only",As TableStyles,,MISSING,,
1372
1437
  Workbook,TemplateRemoveExtData,property,As Boolean,,MISSING,,
@@ -1466,7 +1531,7 @@ Worksheet,ExportAsFixedFormat,method,"ExportAsFixedFormat(Type As XlFixedFormatT
1466
1531
  Worksheet,FilterMode,"property, read-only",As Boolean,,PARTIAL,tests/fixtures/autofilter.json; tests/fixtures/autofilter_file/autofilter_file.json; tests/test_live_excel_model_gate.py,
1467
1532
  Worksheet,FollowHyperlink,event,FollowHyperlink(Target As Hyperlink),,MISSING,,
1468
1533
  Worksheet,HPageBreaks,"property, read-only",As HPageBreaks,,MISSING,,
1469
- Worksheet,Hyperlinks,"property, read-only",As Hyperlinks,,MISSING,,
1534
+ Worksheet,Hyperlinks,"property, read-only",As Hyperlinks,,VERIFIED,tests/fixtures/hyperlinks/hyperlinks.json; tests/test_live_excel_model_gate.py,"In the order they were added, a link replaced keeping its place."
1470
1535
  Worksheet,Index,"property, read-only",As Long,,PARTIAL,tests/fixtures/excel_model/probes.txt,
1471
1536
  Worksheet,LensGalleryRenderComplete,event,LensGalleryRenderComplete(),,MISSING,,
1472
1537
  Worksheet,ListObjects,"property, read-only",As ListObjects,,PARTIAL,tests/fixtures/tables/tables.json,"The sheet's tables, read from a file or made by ListObjects.Add."
@@ -138,12 +138,12 @@ entry tracked explicitly.
138
138
  | VBA projects and forms | In-scope MS-OVBA gates, designer round trips and live file gates exist; shared library-reference add/remove operations pass native Excel/Word/PowerPoint checks and Access persistence tests | Reconcile every operation with its format and protection/signing limits; distinguish form design from form runtime; linked VBA-project creation and arbitrary library runtime resolution remain separate gaps |
139
139
  | VBA language and runtime | Measured semantics, classes, errors and control flow exist; every constant of VBA's own type library, the colour, key-code and system-colour modules included, typed as declared; Scripting.Dictionary in memory, its key matching measured | Audit complete syntax, type system, lifetime, references and intrinsics; track file I/O, external calls and known typing gaps explicitly |
140
140
  | Application, workbooks and sheets | Core collections, cells, names and queries exist; sheet protection -- Protect, Unprotect, the Protection object and every edit a protected sheet refuses a macro, with Excel's own errors -- follows 168 live cases, and is saved and read as Excel saves and reads it, SHA-512 and legacy passwords included, over 13 files and a live gate; workbook protection -- Protect, Unprotect and the sheet changes a protected structure refuses -- follows 41 cases and 5 files, with a live gate; windows -- ActiveWindow, Windows, Goto, each sheet's zoom, view, display settings, scrolling, frozen panes and selection, the tabs and the window order -- follow 113 live workbooks, saved and read as Excel saves and reads them | Map all reference members; identify stubs, missing collections and incomplete arguments; allowed edit ranges and copying or moving sheets between workbooks while one is protected; a split that is not frozen, which Excel keeps in twips of the window; NewWindow, hidden windows and a window's size and state |
141
- | Ranges and editing | Values, formulas, areas and basic movement exist; written values are typed as Excel types them, with the formats typing brings, prefix characters, Text cells and Value/Value2 types, pinned by 3,947 live writes and a saved workbook; formulas a macro writes are spelled as Excel spells them over 120 live formulas; NumberFormat codes round-trip Excel's spelling on both sides; Range.Text, TEXT and WorksheetFunction.Text follow Excel's number-format engine over 156 live codes and 28 values, and round times as Excel does over 152 times on the half second; CurrentRegion and End pass 34 live layouts, FillDown/Up/Right/Left 16 and SpecialCells 18; single-area Find/FindNext/FindPrevious pass 48 native cases; Replace passes 80 live layouts and the formula-bar text of 20 numbers in 26 formats; the clipboard's Copy, Cut, Paste and PasteSpecial pass 49; Range.Sort and the Sort object pass 58, in Excel's order for ASCII text over 583 values; AutoFill passes 208 layouts and 520 columns, its series of numbers, dates, times, text and names to the last digit; RemoveDuplicates passes 98; AutoFilter passes 113 layouts, reads and writes 41 filters as Excel saves them, and passes a live gate; edits on a filtered sheet -- writes, formats, clears, fills, copies, sorts, deletes and inserts, and the filter following rows and columns -- match 190 of 195 live layouts, the other 5 reporting themselves unsupported (two-dimensional arrays over several areas); SUBTOTAL passes 31 live layouts over hidden, filtered and nested rows and references that functions and operators give; every edit above meets sheet protection as Excel's does; Cut moves the references that overlap it as Excel does over 24 live layouts; cell shifts -- Insert and Delete with a Shift or none -- move references, names, the filter's range and formats as Excel does over 47 live layouts; merged-range geometry/value operations pass 21 native cases and four persistence gates; FormulaR1C1 scalar and array writes/reads pass 27 native cases and five persistence gates; A1 Formula array writes share the implementation and pass 15 native cases plus four persistence gates | Complete multi-area/comment/format/MatchByte searches, complex across/multi-area merges and merge formatting; Range.Text with a `*` fill and in columns too narrow for a value (both need text widths in pixels); audit insertion, deletion, copying, sorting and filtering |
141
+ | Ranges and editing | Values, formulas, areas and basic movement exist; written values are typed as Excel types them, with the formats typing brings, prefix characters, Text cells and Value/Value2 types, pinned by 4,902 live writes and a saved workbook; formulas a macro writes are spelled as Excel spells them over 120 live formulas; NumberFormat codes round-trip Excel's spelling on both sides; Range.Text, TEXT and WorksheetFunction.Text follow Excel's number-format engine over 156 live codes and 28 values, and round times as Excel does over 152 times on the half second; CurrentRegion and End pass 34 live layouts, FillDown/Up/Right/Left 16 and SpecialCells 18; single-area Find/FindNext/FindPrevious pass 48 native cases; Replace passes 80 live layouts and the formula-bar text of 20 numbers in 26 formats; the clipboard's Copy, Cut, Paste and PasteSpecial pass 49; Range.Sort and the Sort object pass 58, in Excel's order for ASCII text over 583 values; AutoFill passes 208 layouts and 520 columns, its series of numbers, dates, times, text and names to the last digit; RemoveDuplicates passes 98; TextToColumns passes 54 of 57 live cases of delimiters, qualifiers, typing, FieldInfo and its six date orders, separators and fixed widths, the other 3, FieldInfo pairs out of order, reporting themselves unsupported; Range.Range passes 29 live probes and a space-separated intersection 5; AutoFilter passes 113 layouts, reads and writes 41 filters as Excel saves them, and passes a live gate; edits on a filtered sheet -- writes, formats, clears, fills, copies, sorts, deletes and inserts, and the filter following rows and columns -- match 190 of 195 live layouts, the other 5 reporting themselves unsupported (two-dimensional arrays over several areas); SUBTOTAL passes 31 live layouts over hidden, filtered and nested rows and references that functions and operators give; every edit above meets sheet protection as Excel's does; Cut moves the references that overlap it as Excel does over 24 live layouts; cell shifts -- Insert and Delete with a Shift or none -- move references, names, the filter's range and formats as Excel does over 47 live layouts; merged-range geometry/value operations pass 21 native cases and four persistence gates; FormulaR1C1 scalar and array writes/reads pass 27 native cases and five persistence gates; A1 Formula array writes share the implementation and pass 15 native cases plus four persistence gates | Complete multi-area/comment/format/MatchByte searches, complex across/multi-area merges and merge formatting; Range.Text with a `*` fill and in columns too narrow for a value (both need text widths in pixels); typing a space before a month's name and a time, or digits after AM or PM and a point, which Excel misreads into numbers; audit insertion, deletion, copying, sorting and filtering |
142
142
  | Named ranges | Workbook/worksheet CRUD, validation, scope precedence, rename/retarget/delete, visibility/comments and Python snapshots share one implementation; 19 native cases and three persistence gates | Active-cell-relative name semantics, locale translation, Excel 4 macro metadata and arbitrary named-formula evaluation remain incomplete |
143
143
  | Multiple workbooks and sheet copying | Add/open/activate/close; VBA sheet Copy/Move before/after or into a new book, matching native held-object invalidation on cross-book moves; inter-book range copies import used names and aliases with reuse/rename/error policies, backed by native probes and persistence gates | External workbook links, independent VBA projects, sheet-copy/move name conflicts, relative/other-sheet name imports, transferred drawings/controls, sheet modules and advanced worksheet metadata remain incomplete |
144
144
  | Structural edits | Whole-row/column insertion/deletion and formula/name reference updates pass 12 native cases and four persistence gates; occupied-edge insertion is atomic | Partial-cell reference rewriting, relative name context, merges/shapes, formatting inheritance/CopyOrigin and table/validation/chart metadata updates remain incomplete |
145
145
  | Range copying | Explicit-destination copies pass 17 native cases and five persistence gates: overlap, blanks, repeated blocks, formulas, cross-sheet copying and measured formatting | Merged-cell and multi-area copies, destinations larger than 1,048,576 cells, clipboard/paste behavior and full formatting fidelity remain incomplete |
146
- | Formatting and layout | Cell formats are complete for Font, Interior, Borders, alignment, protection, NumberFormat and ClearFormats: 161 live probes, an Excel-authored workbook read back value for value, the border storage rules, a live gate for model-written formats, and a stylesheet Excel's for the same edits except one font-order quirk. Row heights, column widths and hidden rows and columns follow Excel on a 96-DPI display: 185 live probes, Excel-authored and foreign files read back, the saved XML Excel's, and a live gate. Rows grow with their fonts from a 25,662-row table measured for eleven font families in four styles, beside the Normal font and alone on a row. Row, column and sheet-wide formats follow Excel: 149 live probes, Excel's saved workbook read back, 16 foreign files read and written back as Excel does, the model's saved XML Excel's, and a live gate. Medium, thick and double borders make rows taller as Excel's do, 39 more probes in the same fixture. Data validation reads, adds, changes, deletes and checks rules as Excel does, each rule moving with inserts and deletes, splitting round a delete or a Clear and carried by a copy, over 39 live workbooks and the dataValidations element Excel saves | Named cell styles (`Range.Style`, `Styles`), conditional formatting and page setup; a validation list read from another sheet, which Excel keeps in the worksheet's x14 extension; cell shifts (`Insert`/`Delete` with `Shift`) on sheets with row or column formats; rows mixing fonts from different tables, unmeasured fonts, super/subscript and wrapped or turned text; a thick border along a hidden row; column AutoFit; Normal fonts other than Aptos Narrow 11 and Calibri 11 |
146
+ | Formatting and layout | Cell formats are complete for Font, Interior, Borders, alignment, protection, NumberFormat and ClearFormats: 161 live probes, an Excel-authored workbook read back value for value, the border storage rules, a live gate for model-written formats, and the stylesheet Excel writes for the same edits, entry for entry. Row heights, column widths and hidden rows and columns follow Excel on a 96-DPI display: 185 live probes, Excel-authored and foreign files read back, the saved XML Excel's, and a live gate. Rows grow with their fonts from a 25,662-row table measured for eleven font families in four styles, beside the Normal font and alone on a row. Row, column and sheet-wide formats follow Excel: 149 live probes, Excel's saved workbook read back, 16 foreign files read and written back as Excel does, the model's saved XML Excel's, and a live gate. Medium, thick and double borders make rows taller as Excel's do, 39 more probes in the same fixture. Data validation reads, adds, changes, deletes and checks rules as Excel does, each rule moving with inserts and deletes, splitting round a delete or a Clear and carried by a copy, over 39 live workbooks and the dataValidations element Excel saves. Named cell styles -- `Range.Style`, `Styles` with `Add` and `Merge`, and the `Style` object's properties, read, set and deleted -- answer as Excel's do over 11,147 live reads and 6,459 more of styles a macro changes, deletes and merges: the 47 built-in styles given to cells in both orders, styles over formats and formats over styles, which cells follow a changed style, Normal's font, protected sheets; the stylesheet Excel writes for them, in the order its tables hold what a session made, under two themes and after a reopen, over 45 saved workbooks, files holding entries nothing uses, entries twice and custom formats out of order among them, and a live gate opens ten of the model's in Excel, which reads them as its own; an edge two cells' styles both draw reads as Excel reads it over 415 pairs | Normal's font size, face, bold, italic and underline, which the sheets' geometry rests on; a style of a workbook that is not the active one, which Excel changes in the active workbook; conditional formatting and page setup; a validation list read from another sheet, which Excel keeps in the worksheet's x14 extension; cell shifts (`Insert`/`Delete` with `Shift`) on sheets with row or column formats; rows mixing fonts from different tables, unmeasured fonts, super/subscript and wrapped or turned text; a thick border along a hidden row; column AutoFit; Normal fonts other than Aptos Narrow 11 and Calibri 11 |
147
147
  | Tables and structured references | Power Query reads workbook tables and writes load targets; ListObjects reads a file's tables and makes new ones as Excel does -- headers, generated column names, the header row put in, the name and style -- with ListObject, ListColumns and ListRows answering, and saves them in the parts Excel writes, over 8 live workbooks and 15 live questions; a table read from a file keeps its part until it changes, and whole rows inserted or deleted through it carry it. Structured references are read, spelled, saved and worked out as Excel does over 80 live formulas and a 50-name character sweep: this row, special items, spans, escapes, the table's name left out inside it, a column read as this row's cell where one value is wanted, Range and Evaluate, AutoFill along the columns, and renaming a table or its columns through every formula. The totals row shows and hides as Excel does over 20 live workbooks, with its default label and function, every TotalsCalculation, and labels, SUBTOTALs and formulas written into it. ListRows.Add and Delete, ListColumns.Add and Delete, Resize and Delete, calculated columns, and a table growing over what a macro writes beside it, with the references it stretches, match 28 live workbooks and 21 live writes | Unlist, which turns the table style into cell formats; a copy or fill beside a table, which puts a table row in first; whole columns inserted or deleted through a table; the dxf a calculated column made from one cell brings; and a header holding a carriage return, which VBA reads as a line feed |
148
148
  | Formulas and calculation | Cells are worked out by pyOfficeEditor's engine, 493 of Excel's 525 functions, which comes to what Excel cached for all 10,958 formulas of its corpus over the model's workbook; formula parser, dependency invalidation and manual mode exist; a formula's last sum set to zero when it cancels, comparisons to fifteen digits and lookups to the bit follow Excel over 1,788 live pairs of doubles; defined names that stand for a formula work out where they are used, as array formulas; a range or array where one value is wanted is cut to the formula's row or column or run item by item, SUMPRODUCT, INDEX, ROWS and COLUMNS work their arguments out as arrays, and a value where a function reads cells is refused, as 232 live formulas show and as each of the engine's 493 functions measured there does, 15 of them taken; a call with too few or too many arguments, a LET's or a LAMBDA's name that is none, and a formula past Excel's limits on text, brackets, calls, signs and length are refused, over 14,377 live formulas, every function with 25 counts of arguments; a running total 3000 rows down and the deepest formulas Excel takes work out as Excel does; a formula written in the other notation, `Formula = "=R[-1]C+1"` or `FormulaR1C1 = "=A1"`, reads as Excel reads it, over 79 live formulas; LET's and LAMBDA's names, those looking like cells among them, and LAMBDA's optional parameters read, work out and save as Excel's do, over 24 live formulas; a formula written to a General cell takes the number format Excel gives it, over 111 live cases; `FormulaArray`, `HasArray` and `CurrentArray` follow Excel over 78 live cases, array formulas saved and read as Excel does; the range operator, intersections, unions and INDEX, OFFSET, INDIRECT, CHOOSE, IF, IFS, SWITCH and XLOOKUP as references follow Excel over 45 live formulas, and INDEX with one index into rows and columns and a `+` before a reference over 26 more; `Formula2` and `Formula2R1C1` read a legacy formula with Excel's `@` over 2100 live formulas, every function in every way it takes an argument; an `@` or a call of SINGLE written through `Formula`, `Formula2`, `FormulaR1C1` or `Value` is kept, left out, read back and saved as Excel does, over 274 live writes and a saved workbook; dynamic arrays spill, grow, shrink and are #SPILL! where something is in the way, with `HasSpill`, `SpillParent`, `SpillingToRange`, `A1#` and their file format, over 42 live cases, 18 expressions and two saved workbooks | Complete function and argument coverage, spills and structural edits (sort, insert and delete through a spill), copying part of an array formula, relative R1C1 in INDIRECT and unions for functions beyond the aggregates, errors, circular/iterative calculation, cached-value persistence and names with relative references |
149
149
  | VBA WorksheetFunction and Evaluate | WorksheetFunction.X and the late-bound Application.X call the cell formula engine for the 388 WorksheetFunction members it has, with arguments, answers and errors converted as 160 live calls made both ways show; Evaluate, `[...]` and Worksheet.Evaluate work out expressions through the same engine as Excel does over 91 live cases: a Range for cells, blocks whole, error values, ROW() as an array of one | The WorksheetFunction members the engine lacks: the cube functions, WEBSERVICE, STOCKHISTORY and the like; the members registered with the engine checked through VBA one by one |
@@ -152,7 +152,7 @@ entry tracked explicitly.
152
152
  | Charts | Existing chart parts can be preserved and shapes identified | Audit chart objects, creation, series, axes, formatting, data links and round trips |
153
153
  | Pivots, caches and data model | Unmodelled content is preserved in existing files | Inventory and implement headless operations; preservation alone is not runtime support |
154
154
  | Power Query | Packaging, M evaluation, local refresh and sheet load targets exist | Complete language/library conformance, data types, errors, query dependency behavior, connectors and refresh settings |
155
- | Other workbook features | Coverage varies and needs classification; notes, which VBA calls comments, are added, read, edited, moved with their cells, copied and saved as Excel does, over 89 live probes and a saved workbook of every kind of note, its parts written byte for byte | Inventory names, links, threaded comments, hyperlinks, protection, metadata, embedded objects, connections and remaining reference/file features; a note's box a macro moves or resizes, and notes under Sort and RemoveDuplicates |
155
+ | Other workbook features | Coverage varies and needs classification; notes, which VBA calls comments, are added, read, edited, moved with their cells, copied and saved as Excel does, over 89 live probes and a saved workbook of every kind of note, its parts written byte for byte. Hyperlinks are added, read, set, taken away, moved, copied, pasted, cut, sorted and saved as Excel does, with the Hyperlink style and the HYPERLINK function's, over 26 sections of live Excel and 21 workbooks it saved, their links, relationships, cell styles and stylesheets matched, and a live gate opens the model's in Excel, which reads them as its own; a part's relationships come in Excel's order, from the hash Office places their ids by, over every count to 160 and 17 larger ones up to 65,530 | Inventory names, links, threaded comments, protection, metadata, embedded objects, connections and remaining reference/file features; a note's box a macro moves or resizes, and notes under Sort and RemoveDuplicates; a hyperlink on a shape, EmailSubject on a link with no address, Follow, a paste of links turned or from several areas, and the relationship order of a part with more than 65,536 |
156
156
  | Fidelity and release verification | Offline tests, live gates, language matrix and cross-platform CI exist | Add real-world mixed-feature cases, malformed/foreign-author packages and scale tests; require live evidence for new persisted behavior |
157
157
 
158
158
  ## Execution order within Excel
@@ -572,6 +572,49 @@ does (`tests/fixtures/remove_duplicates.json`, 98 layouts).
572
572
  merged cells, row and column formats, and a destination that runs on
573
573
  in two directions at once report themselves unsupported.
574
574
 
575
+ **Text to columns.** `Range.TextToColumns` splits a column of text as
576
+ Excel does (`tests/fixtures/text_to_columns.json`, 57 cases).
577
+
578
+ * Only a range of one column splits; more is error 1004. Each line splits
579
+ at any of the delimiters asked for, OtherChar giving only its first
580
+ character, and with none asked for it stays whole. ConsecutiveDelimiter
581
+ reads a run of them as one, though a field in quotes, `""` included, is
582
+ a field of its own. A field in the text qualifier, a double quote
583
+ unless TextQualifier asks for a single one or none, keeps the
584
+ delimiters in it and reads a doubled qualifier as one.
585
+ * Every row of the block is written across the widest line: a field that
586
+ is empty, or that a shorter line lacks, clears its cell and leaves its
587
+ format. A number or a blank in the source column stays as it is. A
588
+ Destination moves the block's corner, on the source's sheet whichever
589
+ sheet it names.
590
+ * A field is typed as typing a cell types it, into a number, a date, a
591
+ time, TRUE or an error, with the format typing brings where the cell's
592
+ own is General. A format of the cell's own stays, and a cell formatted
593
+ Text still takes the number. A field starting with `=` is a formula.
594
+ `5-` is text unless TrailingMinusNumbers is True, `-0` is 0, and a
595
+ number past Excel's largest stays text. DecimalSeparator and
596
+ ThousandsSeparator read numbers written with other separators.
597
+ * FieldInfo gives the columns, in order, a kind: xlTextFormat keeps the
598
+ field as it is and formats the cell Text, a date order reads the field
599
+ as that order's date, and xlSkipColumn drops the column. With DataType
600
+ xlFixedWidth each line is cut where the pairs start, counted from 0.
601
+ * A date column fills its day, month and year in its order from runs of
602
+ digits split at `/`, `-`, `.` or a space, a run of separators counting
603
+ as one: two digits to a day or a month and four to a year, the rest
604
+ spilling into the next part, so `5/2020` in an MDY column is 20 May
605
+ 2020. A month's name fills a month. A run of digits with no separator
606
+ is cut by its length: four digits two and two, five with one for the
607
+ month, six two each, eight at the parts' widths. Three parts make an
608
+ m/d/yyyy date if they are one. Two go by a fixed table, not the
609
+ letters' order: DMY, YMD and YDM read a day and its month, else a year
610
+ and its month; MDY, MYD and DYM a month and its day, else a month and
611
+ its year; a day read so falls in the current year. A field the column
612
+ reads no date in is typed as a General column types it.
613
+ * FieldInfo pairs that do not number the columns 1, 2, 3 in order, a
614
+ column holding formulas and a sheet with merged cells report
615
+ themselves unsupported. An omitted argument takes its default; whether
616
+ Excel carries one over from an earlier call is not measured.
617
+
575
618
  **The clipboard.** `Range.Copy` and `Range.Cut` with no destination put
576
619
  the range on the clipboard, and `Application.CutCopyMode` reads 1 after
577
620
  a copy, 2 after a cut and 0 once it is cleared; setting it to False
@@ -740,10 +783,9 @@ protection properties, `NumberFormat` and `ClearFormats` read and write a
740
783
  cell's format the way Excel does; 161 probes of live Excel pin the
741
784
  answers (`tests/fixtures/range_format.json`). A workbook's `styles.xml`
742
785
  is read into one format per cell, so a file Excel formatted reads back
743
- exactly as Excel reads it, and a save appends only the entries the file
744
- lacks, spelled as Excel spells them: for the same edits the stylesheet
745
- comes out byte for byte as Excel's, except that Excel writes a red font
746
- first whenever one is used.
786
+ exactly as Excel reads it, and a save writes the stylesheet the way Excel
787
+ writes it (see **The stylesheet** below): for the same edits it comes out
788
+ byte for byte as Excel's (`tests/fixtures/format/formats.xlsx`).
747
789
 
748
790
  * A property read over several cells answers the shared value or Null.
749
791
  Colours compare as colours, and a mixed `Interior.Color` or
@@ -763,6 +805,12 @@ first whenever one is used.
763
805
  neighbour's copy. An inside border is written on both cells, and one
764
806
  that only one of them stored comes out in the automatic colour, which
765
807
  the file writes `auto="1"`.
808
+ * Cell styles can leave both cells drawing the edge between them, and
809
+ then the stronger line style shows -- double, thick, medium, the
810
+ medium dashes, slanted dash-dot, thin, dashed, dotted, dash-dot,
811
+ dash-dot-dot, hair -- and between two of one style the darker colour,
812
+ by 2R + 5G + B, as 415 pairs of cells in live Excel show
813
+ (`tests/fixtures/cell_styles/shared_edges.json`).
766
814
  * `LineStyle` and `Weight` pair into the thirteen line styles the file
767
815
  has; a style keeps the current weight when the pair exists and takes
768
816
  its own default otherwise.
@@ -770,22 +818,103 @@ first whenever one is used.
770
818
  left-aligned, and choosing an alignment that cannot be indented drops
771
819
  the indent. `ClearFormats` unmerges.
772
820
 
773
- `Range.Style`, the `Styles` collection and conditional formats are not
774
- implemented yet; the operation checklist, `docs/excel_checklist.csv`,
775
- records each member's status.
821
+ **Cell styles.** `Range.Style`, the `Styles` collection and the `Style`
822
+ object answer as Excel's do over 11,147 reads in live Excel
823
+ (`tests/fixtures/cell_styles/cell_styles.json`), and styles a macro
824
+ changes, deletes and merges over 6,459 more (`style_changes.json`, made
825
+ by `scripts/measure_style_changes.py`). The 45 workbooks Excel saved on
826
+ the way are written the same by the model, entry for entry.
827
+
828
+ * A new workbook lists Excel's 47 built-in styles, and its file holds
829
+ only Normal until a cell uses another. Styles are listed in the order
830
+ Windows word sort puts their names, and a name finds its style in any
831
+ case.
832
+ * Giving a range a style replaces the parts of its cells' formats the
833
+ style includes -- `IncludeNumber`, `IncludeFont`, `IncludeAlignment`,
834
+ `IncludeBorder`, `IncludePatterns`, `IncludeProtection` -- and keeps
835
+ the rest; a border the style includes replaces all four sides. A range
836
+ whose cells have different styles answers Nothing. Anything but the
837
+ name of a style or a `Style` is error 450, and so is a protected sheet
838
+ that does not allow formatting cells.
839
+ * `Styles.Add` copies Normal, or the first cell of `BasedOn`, leaving out
840
+ the parts the range's cells do not share.
841
+ * A style's properties set as a range's do. The style changes, and each
842
+ cell, row and column format that did not set the part itself follows,
843
+ while the style includes the part; including a part again brings the
844
+ style's part back to them. A built-in style a macro touches, even to
845
+ set what it was, is written `customBuiltin`.
846
+ * Normal's font is the file's first font, which every format in it points
847
+ at, so a change to it reaches cells of any style that did not set their
848
+ font. The model takes its colours and strikethrough, and reports its
849
+ size, face, bold, italic and underline unsupported: the sheets' column
850
+ widths and row heights rest on them.
851
+ * A style's `Borders` are its edges by `xlLeft`, `xlRight`, `xlTop` and
852
+ `xlBottom` and its diagonals by 5 and 6; `Borders(7)` to `Borders(12)`
853
+ read -4142 and 2 where the edge in that turn has a line in the
854
+ automatic colour, else Null, and setting one does nothing. A style's
855
+ automatic pattern colour stays white or black, where a cell's turns
856
+ black. `Superscript` and `Subscript` read False while the style leaves
857
+ its font out, and `IndentLevel` is Null unless the style aligns left,
858
+ right or distributed and does not turn its text.
859
+ * `Style.Delete` moves its cells to Normal, each part they did not set
860
+ themselves following Normal from then on; a built-in style stays in
861
+ the file, hidden, a held `Style` of it is error 424, and Normal is
862
+ error 1004. `Styles.Merge` brings another workbook's styles in: one
863
+ named as one here takes its place and reaches the cells that follow
864
+ it, keeping this workbook's spelling, and the rest come in the order
865
+ their names sort.
866
+ * A protected sheet in the workbook makes a change or a delete error
867
+ 1004, whatever the protection allows. A macro that changes a style of
868
+ a workbook that is not the active one changes the active workbook's
869
+ style of that name in Excel; the model reports that unsupported.
870
+ * A save writes a built-in style while a cell uses it, a macro changed
871
+ it or deleted it, and every style a macro added: after the file's own,
872
+ the built-in ones in Excel's order and then the rest in the order they
873
+ were made, each in the theme's fonts.
874
+
875
+ **The stylesheet.** Excel keeps a workbook's number formats, fonts,
876
+ fills, borders, cell styles and cell xfs as tables in the order they
877
+ came -- the file's own, then the parts of its built-in styles, then what
878
+ the session made -- and a save writes the ones in use in that order and
879
+ leaves the rest out. The model keeps the same tables
880
+ (`tests/fixtures/cell_styles/order.xlsx`).
881
+
882
+ * A new part equal to a built-in style's takes that style's place: a red
883
+ font, which Warning Text has, comes ahead of the fonts a macro made
884
+ before it.
885
+ * A custom number format takes its id when it is made, and a save leaves
886
+ a gap where one was made and then dropped. Opening a file numbers its
887
+ custom formats from 164 in the order it lists them.
888
+ * A cell xf changes in place when its style changes, and two that come
889
+ to say the same stay apart. Opening a file, Excel works each xf's apply
890
+ flags out afresh and takes an xf that then points at what an earlier
891
+ one points at as that one; a font the file holds twice stays two.
892
+ * A save that follows no change to a format leaves the stylesheet as the
893
+ file had it, as it leaves a sheet no macro wrote to.
894
+
895
+ Conditional formats are not implemented yet; the operation checklist,
896
+ `docs/excel_checklist.csv`, records each member's status.
776
897
 
777
898
  **Typing.** A string written through `Value`, `Value2`, `Formula` or an
778
899
  array is typed the way Excel types what someone enters in a cell, and a
779
900
  Date or Currency a macro computes brings a format of its own. 3,723
780
901
  writes in live Excel pin the rules (`tests/fixtures/value_typing.json`,
781
902
  `tests/fixtures/typing_formats.json`), with 49 more in a workbook Excel
782
- saved (`tests/fixtures/typing/`).
903
+ saved (`tests/fixtures/typing/`) and 911 dates and times in
904
+ `tests/fixtures/typed_dates.json`.
783
905
 
784
906
  * `"5%"` is 0.05 in the 0% format, `"$1,000.50"` a dollar amount,
785
907
  `"1e3"` scientific, `"1 3/16"` a fraction, `"12:30:45.5"` a time to the
786
908
  tenth of a second, and `"1/2"` the second of January this year. Dates
787
909
  run month first on Excel's own calendar, which has a 29 February 1900,
788
910
  from 1900 to 9999; a date that does not exist stays text.
911
+ * A month's name may stand before or after its day, parted from it by a
912
+ slash, a dash, a space or nothing, and a date and a time may come
913
+ either way round, with numbers after them read past. A space before a
914
+ date or a time keeps it text, except before a day and a month's name.
915
+ Excel misreads a space before a month's name and a time, and digits
916
+ after AM or PM and a point, into numbers; those report themselves
917
+ unsupported.
789
918
  * A cell keeps its own format unless it is General, or one of Excel's
790
919
  built-in currency, accounting, percent, scientific, fraction, date and
791
920
  time formats and the typed value is of another kind; a number with
@@ -1209,6 +1338,48 @@ a workbook Excel saved opens with its notes and saves them back as they
1209
1338
  came. Sorting or removing duplicates over a note, and threaded comments,
1210
1339
  report themselves unsupported.
1211
1340
 
1341
+ **Hyperlinks.** `Worksheet.Hyperlinks`, `Range.Hyperlinks`,
1342
+ `Range.ClearHyperlinks` and the `Hyperlink` object answer as Excel's do
1343
+ (`tests/fixtures/hyperlinks/`, 26 sections of live Excel and the 21
1344
+ workbooks it saved along the way; `_hyperlinks`, `_hyperlinks_file`).
1345
+ `Hyperlinks.Add` puts a link on each area of its anchor and answers the
1346
+ last; one over the very cells of a link takes that link's place in the
1347
+ list, one over any other cells goes at the end, overlapping or not. The
1348
+ anchor's cells take the style named Hyperlink, the built-in one made the
1349
+ first time among the styles a session makes, and the first cell the
1350
+ text to show or, when it is empty, the address, a number staying a
1351
+ number. An address is kept as Excel tidies it: spaces round it and tabs
1352
+ in it dropped, a `#` splitting off the subaddress, an http, https or ftp
1353
+ address's scheme and host in lower case, its path's `.` and `..`
1354
+ resolved and its escapes of letters, digits and spaces undone; `file:///C:/x`
1355
+ becomes `C:\x`. A link is named by the text to show it was given, or by
1356
+ "address - subaddress", which follows a new address; one read from a
1357
+ file without a display is named by its cell's text until a new address
1358
+ names it. `TextToDisplay` reads the first cell's text, "" for a number or
1359
+ a formula. Setting `SubAddress` takes the address away, and `Address`
1360
+ keeps the subaddress unless the new one has a `#` of its own.
1361
+ `EmailSubject` is a mailto address's subject, which setting it writes in.
1362
+ A range's collection holds the links inside one of its areas, and for a
1363
+ range of one area the link it lies in; `Clear`, `ClearContents`, an empty
1364
+ value, `ClearHyperlinks` and a copy landing on them take those links
1365
+ away, and `Delete` takes them with their cells' formats, merges kept. A
1366
+ copy or a paste of everything brings the links it meets over the cells it
1367
+ copies, a cut moves them in place, inserts and deletes move them as they
1368
+ move a reference, a sort moves a link one line high with its line, and a
1369
+ copy of the sheet has them all. On a protected sheet a link needs
1370
+ AllowInsertingHyperlinks and unlocked cells. A formula whose first
1371
+ function is HYPERLINK gives its cells the Hyperlink style. A save writes
1372
+ the hyperlinks element as Excel does, with a display where the name is
1373
+ not the text the cell holds, and each address as a relationship's
1374
+ target, escaped as Excel escapes it, a DOS path relative to the
1375
+ workbook's folder; the relationships number the links first, and a
1376
+ part's relationships come in the order Office lists them, a table
1377
+ placing each id by its characters in base 101 through a step of C's
1378
+ `rand()` (`pyopenvba._relationships`, measured to 65,530). A link on a shape,
1379
+ `EmailSubject` set on a link with no address -- which leaves Excel
1380
+ refusing every change after it -- and `Follow` report themselves
1381
+ unsupported.
1382
+
1212
1383
  **Windows and sheet views.** `ActiveWindow`, `Windows`,
1213
1384
  `Workbook.Windows` and `Goto` behave as Excel does with its window shown
1214
1385
  (`tests/fixtures/windows/`, 113 workbooks). Each sheet has its own view,
@@ -1418,6 +1589,9 @@ macros, which the model does not write.
1418
1589
  | `apps/excel/_dimensions.py` | Row heights, column widths and hidden rows and columns, on a 96-DPI display |
1419
1590
  | `apps/excel/_row_formats.py` | Formats a whole row, a whole column or the whole sheet carries, and how a change spreads |
1420
1591
  | `apps/excel/_font_rows.py` | How tall each measured font makes a row, baked from `tests/fixtures/font_rows.json` |
1592
+ | `apps/excel/_hyperlinks.py` | A sheet's hyperlinks, as a macro reaches them, and what edits do to them |
1593
+ | `apps/excel/_hyperlinks_file.py` | Hyperlink addresses as Excel keeps and saves them, and the sheet's hyperlinks element |
1594
+ | `_relationships.py` | The order Office writes a part's relationships in |
1421
1595
  | `apps/word/` | Word's object model, its bridge and its file |
1422
1596
  | `apps/powerpoint/` | PowerPoint's, the same three |
1423
1597
  | `shapes/_values.py` | What a shape is, in all three hosts' words |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pyOpenVBA"
7
- version = "6.1.3"
7
+ version = "6.2.0"
8
8
  description = "Read and write VBA macros and Excel Power Query in pure Python, no dependencies."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -293,4 +293,4 @@ def push_power_query(
293
293
  """
294
294
  return _push_queries(src_dir, workbook, out=out, encoding=encoding, remove_missing=remove_missing)
295
295
 
296
- __version__ = "6.1.3"
296
+ __version__ = "6.2.0"
@@ -0,0 +1,90 @@
1
+ """The order Office writes a part's relationships in.
2
+
3
+ Excel, and PowerPoint with it, writes each ``.rels`` part in the order a
4
+ linear-hashing table keyed by the relationship ids iterates. Measured by
5
+ saving sheets holding every count of hyperlinks from 1 to 160 and larger
6
+ counts up to 65,530, the most a sheet holds, one relationship each
7
+ (scripts/measure_relationship_order.py):
8
+
9
+ - An id's hash is its characters read as a number in base 101, the
10
+ textbook string hash, put through one step of C's rand() generator:
11
+ (h * 1103515245 + 12345) >> 16, in 32 bits.
12
+ - The table starts with 8 buckets. Before an insert that would put more
13
+ than 4 ids per bucket it splits one bucket, p, the next in turn, into p
14
+ and p + L (L the buckets before this round of splits began), the ids
15
+ whose next hash bit is set moving to the new bucket, in their order. An
16
+ id's bucket is its hash mod L, or mod 2L while that is below the split
17
+ pointer.
18
+ - It is read bucket by bucket, each bucket's ids in the order they went
19
+ in; Office puts them in as rId1, rId2 and so on.
20
+
21
+ This reproduces all 177 measured orders, and each part Office wrote in the
22
+ tests' fixtures. They reach 16,384 buckets, the hash's low 14 bits; a
23
+ part of more than 65,536 relationships, whose order they cannot vouch
24
+ for, keeps the order it has, as does one whose ids are not all rId and a
25
+ number.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import math
31
+ import re
32
+ from typing import Final
33
+
34
+ #: The buckets the table starts with, and the ids per bucket past which it splits one.
35
+ _START: Final = 8
36
+ _LOAD: Final = 4
37
+ #: The most relationships a part can hold for the order to be the measured one: 16,384 buckets.
38
+ _MOST: Final = 65536
39
+ _RELATIONSHIP = re.compile(r"<Relationship\b[^>]*?(?:/>|>\s*</Relationship>)")
40
+ #: An id Office numbers: rId and a number, written as a number is, with no leading zero.
41
+ _ID = re.compile(r'\bId="rId(0|[1-9]\d*)"')
42
+
43
+
44
+ def id_hash(identifier: str) -> int:
45
+ """The hash Office's table places a relationship id by: base 101, then a step of C's rand() generator."""
46
+ h = 0
47
+ for character in identifier:
48
+ h = (h * 101 + ord(character)) & 0xFFFFFFFF
49
+ return ((h * 1103515245 + 12345) & 0xFFFFFFFF) >> 16
50
+
51
+
52
+ def bucket_order(numbers: list[int]) -> list[int] | None:
53
+ """The ids rId<number>, by their numbers, in the order Office writes them; None where the order is not
54
+ known."""
55
+ if not numbers or len(numbers) > _MOST or any(number < 0 for number in numbers):
56
+ return None
57
+ buckets = max(_START, math.ceil(len(numbers) / _LOAD))
58
+ level = _START
59
+ while level * 2 <= buckets:
60
+ level *= 2
61
+ split = buckets - level
62
+
63
+ def bucket(number: int) -> int:
64
+ hashed = id_hash(f"rId{number}")
65
+ home = hashed % level
66
+ return hashed % (2 * level) if home < split else home
67
+
68
+ return sorted(numbers, key=lambda number: (bucket(number), number))
69
+
70
+
71
+ def in_office_order(text: str) -> str:
72
+ """A ``.rels`` part with its relationships in the order Office writes them, where the order is known."""
73
+ elements = _RELATIONSHIP.findall(text)
74
+ numbers: list[int] = []
75
+ for element in elements:
76
+ found = _ID.search(element)
77
+ if found is None:
78
+ return text
79
+ numbers.append(int(found.group(1)))
80
+ if len(set(numbers)) != len(numbers):
81
+ return text
82
+ order = bucket_order(numbers)
83
+ if order is None:
84
+ return text
85
+ by_number = dict(zip(numbers, elements, strict=True))
86
+ start = text.find(elements[0])
87
+ end = text.rfind(elements[-1]) + len(elements[-1])
88
+ if start < 0 or "".join(elements) != text[start:end]:
89
+ return text
90
+ return text[:start] + "".join(by_number[number] for number in order) + text[end:]