xlwings-server 1.1.0__py3-none-any.whl

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 (313) hide show
  1. xlwings_server/.env.template +145 -0
  2. xlwings_server/__init__.py +12 -0
  3. xlwings_server/_version.py +34 -0
  4. xlwings_server/auth/__init__.py +0 -0
  5. xlwings_server/auth/custom/__init__.py +26 -0
  6. xlwings_server/auth/entraid/__init__.py +131 -0
  7. xlwings_server/auth/entraid/jwks.py +10 -0
  8. xlwings_server/azure_functions_templates/.funcignore +28 -0
  9. xlwings_server/azure_functions_templates/function_app.py +28 -0
  10. xlwings_server/azure_functions_templates/host.json +22 -0
  11. xlwings_server/azure_functions_templates/local.settings.json +8 -0
  12. xlwings_server/build_utils/__init__.py +9 -0
  13. xlwings_server/build_utils/static_file_hasher.py +212 -0
  14. xlwings_server/cli.py +1592 -0
  15. xlwings_server/config.py +228 -0
  16. xlwings_server/custom_functions/__init__.py +8 -0
  17. xlwings_server/custom_functions/examples.py +177 -0
  18. xlwings_server/custom_scripts/__init__.py +8 -0
  19. xlwings_server/custom_scripts/examples.py +94 -0
  20. xlwings_server/databases.py +19 -0
  21. xlwings_server/dependencies.py +126 -0
  22. xlwings_server/docker_templates/.dockerignore +15 -0
  23. xlwings_server/docker_templates/Dockerfile +60 -0
  24. xlwings_server/docker_templates/docker-compose.yaml +32 -0
  25. xlwings_server/hotreload.py +59 -0
  26. xlwings_server/main.py +242 -0
  27. xlwings_server/models/__init__.py +14 -0
  28. xlwings_server/models/user.py +53 -0
  29. xlwings_server/object_handles.py +142 -0
  30. xlwings_server/routers/__init__.py +0 -0
  31. xlwings_server/routers/manifest.py +82 -0
  32. xlwings_server/routers/root.py +16 -0
  33. xlwings_server/routers/socketio.py +69 -0
  34. xlwings_server/routers/taskpane.py +12 -0
  35. xlwings_server/routers/xlwings.py +197 -0
  36. xlwings_server/security_headers.json +53 -0
  37. xlwings_server/serializers/__init__.py +25 -0
  38. xlwings_server/serializers/default_serializer.py +19 -0
  39. xlwings_server/serializers/dictionary_serializer.py +25 -0
  40. xlwings_server/serializers/framework.py +50 -0
  41. xlwings_server/serializers/numpy_serializer.py +26 -0
  42. xlwings_server/serializers/pandas_serializer.py +95 -0
  43. xlwings_server/static/css/core.css +28 -0
  44. xlwings_server/static/css/style.css +0 -0
  45. xlwings_server/static/images/favicon.png +0 -0
  46. xlwings_server/static/images/xlwings-16.png +0 -0
  47. xlwings_server/static/images/xlwings-32.png +0 -0
  48. xlwings_server/static/images/xlwings-64.png +0 -0
  49. xlwings_server/static/images/xlwings-80.png +0 -0
  50. xlwings_server/static/js/auth.js +13 -0
  51. xlwings_server/static/js/config.js +4 -0
  52. xlwings_server/static/js/core/alpinejs-csp-boilerplate.js +11 -0
  53. xlwings_server/static/js/core/bootstrap-customizations.js +7 -0
  54. xlwings_server/static/js/core/custom-functions-code.js +296 -0
  55. xlwings_server/static/js/core/examples.js +62 -0
  56. xlwings_server/static/js/core/hotreload.js +3 -0
  57. xlwings_server/static/js/core/htmx-handlers.js +86 -0
  58. xlwings_server/static/js/core/officejs-history-fix-part1.js +3 -0
  59. xlwings_server/static/js/core/officejs-history-fix-part2.js +2 -0
  60. xlwings_server/static/js/core/reload-custom-functions.js +79 -0
  61. xlwings_server/static/js/core/socketio-handlers.js +34 -0
  62. xlwings_server/static/js/core/xlwings-alert.js +22 -0
  63. xlwings_server/static/js/core/xlwingsjs/alert.js +85 -0
  64. xlwings_server/static/js/core/xlwingsjs/auth.js +63 -0
  65. xlwings_server/static/js/core/xlwingsjs/sheet-buttons.js +133 -0
  66. xlwings_server/static/js/core/xlwingsjs/utils.js +119 -0
  67. xlwings_server/static/js/core/xlwingsjs/wasm.js +131 -0
  68. xlwings_server/static/js/core/xlwingsjs/xlwings.js +1060 -0
  69. xlwings_server/static/js/main.js +0 -0
  70. xlwings_server/static/js/ribbon.js +17 -0
  71. xlwings_server/static/vendor/@alpinejs/LICENSE +21 -0
  72. xlwings_server/static/vendor/@alpinejs/csp/dist/cdn.min.js +7 -0
  73. xlwings_server/static/vendor/@microsoft/office-js/LICENSE.md +76 -0
  74. xlwings_server/static/vendor/@microsoft/office-js/dist/af-za/office_strings.js +8 -0
  75. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/agaveerrorux.js +18 -0
  76. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/agavedefaulticon32x32.png +0 -0
  77. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/agavedefaulticon96x96.png +0 -0
  78. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/businessbarclose_16x16x32.png +0 -0
  79. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/dropdownarrow_16x16x32.png +0 -0
  80. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/ellipsis_16x16x32.png +0 -0
  81. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/miniinfoblue_16x16x32.png +0 -0
  82. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/moe_default_icon.png +0 -0
  83. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/moe_status_icons.png +0 -0
  84. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/office.png +0 -0
  85. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/images/refresh_16x16x32.png +0 -0
  86. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/index.html +16 -0
  87. xlwings_server/static/vendor/@microsoft/office-js/dist/agaveerrorux/style/agaveerrorux.css +482 -0
  88. xlwings_server/static/vendor/@microsoft/office-js/dist/am-et/office_strings.js +1 -0
  89. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ae/office_strings.js +8 -0
  90. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-bh/office_strings.js +8 -0
  91. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-dz/office_strings.js +8 -0
  92. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-eg/office_strings.js +8 -0
  93. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-iq/office_strings.js +8 -0
  94. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-jo/office_strings.js +8 -0
  95. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-kw/office_strings.js +8 -0
  96. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-lb/office_strings.js +8 -0
  97. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ly/office_strings.js +8 -0
  98. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ma/office_strings.js +8 -0
  99. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-om/office_strings.js +8 -0
  100. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-qa/office_strings.js +8 -0
  101. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-sa/office_strings.js +1 -0
  102. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-sy/office_strings.js +8 -0
  103. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-tn/office_strings.js +8 -0
  104. xlwings_server/static/vendor/@microsoft/office-js/dist/ar-ye/office_strings.js +8 -0
  105. xlwings_server/static/vendor/@microsoft/office-js/dist/ariatelemetry/aria-web-telemetry-2.8.0.min.js +2 -0
  106. xlwings_server/static/vendor/@microsoft/office-js/dist/ariatelemetry/aria-web-telemetry-2.9.0.min.js +2 -0
  107. xlwings_server/static/vendor/@microsoft/office-js/dist/ariatelemetry/aria-web-telemetry.js +1 -0
  108. xlwings_server/static/vendor/@microsoft/office-js/dist/az-latn-az/office_strings.js +8 -0
  109. xlwings_server/static/vendor/@microsoft/office-js/dist/be-by/office_strings.js +8 -0
  110. xlwings_server/static/vendor/@microsoft/office-js/dist/bg-bg/office_strings.js +1 -0
  111. xlwings_server/static/vendor/@microsoft/office-js/dist/bn-in/office_strings.js +1 -0
  112. xlwings_server/static/vendor/@microsoft/office-js/dist/bs-latn-ba/office_strings.js +8 -0
  113. xlwings_server/static/vendor/@microsoft/office-js/dist/ca-es/office_strings.js +1 -0
  114. xlwings_server/static/vendor/@microsoft/office-js/dist/cs-cz/office_strings.js +1 -0
  115. xlwings_server/static/vendor/@microsoft/office-js/dist/cy-gb/office_strings.js +1 -0
  116. xlwings_server/static/vendor/@microsoft/office-js/dist/da-dk/office_strings.js +1 -0
  117. xlwings_server/static/vendor/@microsoft/office-js/dist/de-at/office_strings.js +8 -0
  118. xlwings_server/static/vendor/@microsoft/office-js/dist/de-ch/office_strings.js +8 -0
  119. xlwings_server/static/vendor/@microsoft/office-js/dist/de-de/office_strings.js +1 -0
  120. xlwings_server/static/vendor/@microsoft/office-js/dist/de-li/office_strings.js +8 -0
  121. xlwings_server/static/vendor/@microsoft/office-js/dist/de-lu/office_strings.js +8 -0
  122. xlwings_server/static/vendor/@microsoft/office-js/dist/el-gr/office_strings.js +1 -0
  123. xlwings_server/static/vendor/@microsoft/office-js/dist/en-029/office_strings.js +8 -0
  124. xlwings_server/static/vendor/@microsoft/office-js/dist/en-au/office_strings.js +8 -0
  125. xlwings_server/static/vendor/@microsoft/office-js/dist/en-bz/office_strings.js +8 -0
  126. xlwings_server/static/vendor/@microsoft/office-js/dist/en-ca/office_strings.js +8 -0
  127. xlwings_server/static/vendor/@microsoft/office-js/dist/en-gb/office_strings.js +8 -0
  128. xlwings_server/static/vendor/@microsoft/office-js/dist/en-ie/office_strings.js +8 -0
  129. xlwings_server/static/vendor/@microsoft/office-js/dist/en-in/office_strings.js +8 -0
  130. xlwings_server/static/vendor/@microsoft/office-js/dist/en-jm/office_strings.js +8 -0
  131. xlwings_server/static/vendor/@microsoft/office-js/dist/en-my/office_strings.js +8 -0
  132. xlwings_server/static/vendor/@microsoft/office-js/dist/en-nz/office_strings.js +8 -0
  133. xlwings_server/static/vendor/@microsoft/office-js/dist/en-ph/office_strings.js +8 -0
  134. xlwings_server/static/vendor/@microsoft/office-js/dist/en-sg/office_strings.js +8 -0
  135. xlwings_server/static/vendor/@microsoft/office-js/dist/en-tt/office_strings.js +8 -0
  136. xlwings_server/static/vendor/@microsoft/office-js/dist/en-us/office_strings.js +8 -0
  137. xlwings_server/static/vendor/@microsoft/office-js/dist/en-za/office_strings.js +8 -0
  138. xlwings_server/static/vendor/@microsoft/office-js/dist/en-zw/office_strings.js +8 -0
  139. xlwings_server/static/vendor/@microsoft/office-js/dist/es-ar/office_strings.js +8 -0
  140. xlwings_server/static/vendor/@microsoft/office-js/dist/es-bo/office_strings.js +8 -0
  141. xlwings_server/static/vendor/@microsoft/office-js/dist/es-cl/office_strings.js +8 -0
  142. xlwings_server/static/vendor/@microsoft/office-js/dist/es-co/office_strings.js +8 -0
  143. xlwings_server/static/vendor/@microsoft/office-js/dist/es-cr/office_strings.js +8 -0
  144. xlwings_server/static/vendor/@microsoft/office-js/dist/es-do/office_strings.js +8 -0
  145. xlwings_server/static/vendor/@microsoft/office-js/dist/es-ec/office_strings.js +8 -0
  146. xlwings_server/static/vendor/@microsoft/office-js/dist/es-es/office_strings.js +1 -0
  147. xlwings_server/static/vendor/@microsoft/office-js/dist/es-gt/office_strings.js +8 -0
  148. xlwings_server/static/vendor/@microsoft/office-js/dist/es-hn/office_strings.js +8 -0
  149. xlwings_server/static/vendor/@microsoft/office-js/dist/es-mx/office_strings.js +1 -0
  150. xlwings_server/static/vendor/@microsoft/office-js/dist/es-ni/office_strings.js +8 -0
  151. xlwings_server/static/vendor/@microsoft/office-js/dist/es-pa/office_strings.js +8 -0
  152. xlwings_server/static/vendor/@microsoft/office-js/dist/es-pe/office_strings.js +8 -0
  153. xlwings_server/static/vendor/@microsoft/office-js/dist/es-pr/office_strings.js +8 -0
  154. xlwings_server/static/vendor/@microsoft/office-js/dist/es-py/office_strings.js +8 -0
  155. xlwings_server/static/vendor/@microsoft/office-js/dist/es-sv/office_strings.js +8 -0
  156. xlwings_server/static/vendor/@microsoft/office-js/dist/es-us/office_strings.js +8 -0
  157. xlwings_server/static/vendor/@microsoft/office-js/dist/es-uy/office_strings.js +8 -0
  158. xlwings_server/static/vendor/@microsoft/office-js/dist/es-ve/office_strings.js +8 -0
  159. xlwings_server/static/vendor/@microsoft/office-js/dist/es6-promise.js +5 -0
  160. xlwings_server/static/vendor/@microsoft/office-js/dist/et-ee/office_strings.js +1 -0
  161. xlwings_server/static/vendor/@microsoft/office-js/dist/eu-es/office_strings.js +1 -0
  162. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-15.01.js +11 -0
  163. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-15.02.js +11 -0
  164. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-15.js +11 -0
  165. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-mac-16.00-core.js +11 -0
  166. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-mac-16.00.js +25 -0
  167. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-web-16.00-core.js +11 -0
  168. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-web-16.00.js +25 -0
  169. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-win32-16.00.js +19 -0
  170. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-win32-16.01-core.js +11 -0
  171. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-win32-16.01.js +25 -0
  172. xlwings_server/static/vendor/@microsoft/office-js/dist/excel-winrt-16.00.js +25 -0
  173. xlwings_server/static/vendor/@microsoft/office-js/dist/excelios-15.js +11 -0
  174. xlwings_server/static/vendor/@microsoft/office-js/dist/excelwebapp-15.01.js +11 -0
  175. xlwings_server/static/vendor/@microsoft/office-js/dist/excelwebapp-15.02.js +11 -0
  176. xlwings_server/static/vendor/@microsoft/office-js/dist/excelwebapp-15.js +11 -0
  177. xlwings_server/static/vendor/@microsoft/office-js/dist/fa-ir/office_strings.js +1 -0
  178. xlwings_server/static/vendor/@microsoft/office-js/dist/fi-fi/office_strings.js +1 -0
  179. xlwings_server/static/vendor/@microsoft/office-js/dist/fil-ph/office_strings.js +1 -0
  180. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-be/office_strings.js +8 -0
  181. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-ca/office_strings.js +1 -0
  182. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-ch/office_strings.js +8 -0
  183. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-fr/office_strings.js +1 -0
  184. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-lu/office_strings.js +8 -0
  185. xlwings_server/static/vendor/@microsoft/office-js/dist/fr-mc/office_strings.js +8 -0
  186. xlwings_server/static/vendor/@microsoft/office-js/dist/ga-ie/office_strings.js +8 -0
  187. xlwings_server/static/vendor/@microsoft/office-js/dist/gl-es/office_strings.js +1 -0
  188. xlwings_server/static/vendor/@microsoft/office-js/dist/gu-in/office_strings.js +1 -0
  189. xlwings_server/static/vendor/@microsoft/office-js/dist/he-il/office_strings.js +1 -0
  190. xlwings_server/static/vendor/@microsoft/office-js/dist/hi-in/office_strings.js +1 -0
  191. xlwings_server/static/vendor/@microsoft/office-js/dist/hr-ba/office_strings.js +8 -0
  192. xlwings_server/static/vendor/@microsoft/office-js/dist/hr-hr/office_strings.js +1 -0
  193. xlwings_server/static/vendor/@microsoft/office-js/dist/html2canvas.js +8 -0
  194. xlwings_server/static/vendor/@microsoft/office-js/dist/hu-hu/office_strings.js +1 -0
  195. xlwings_server/static/vendor/@microsoft/office-js/dist/hy-am/office_strings.js +8 -0
  196. xlwings_server/static/vendor/@microsoft/office-js/dist/id-id/office_strings.js +1 -0
  197. xlwings_server/static/vendor/@microsoft/office-js/dist/is-is/office_strings.js +1 -0
  198. xlwings_server/static/vendor/@microsoft/office-js/dist/it-ch/office_strings.js +8 -0
  199. xlwings_server/static/vendor/@microsoft/office-js/dist/it-it/office_strings.js +1 -0
  200. xlwings_server/static/vendor/@microsoft/office-js/dist/ja-jp/office_strings.js +1 -0
  201. xlwings_server/static/vendor/@microsoft/office-js/dist/ka-ge/office_strings.js +8 -0
  202. xlwings_server/static/vendor/@microsoft/office-js/dist/kk-kz/office_strings.js +1 -0
  203. xlwings_server/static/vendor/@microsoft/office-js/dist/km-kh/office_strings.js +8 -0
  204. xlwings_server/static/vendor/@microsoft/office-js/dist/kn-in/office_strings.js +1 -0
  205. xlwings_server/static/vendor/@microsoft/office-js/dist/ko-kr/office_strings.js +1 -0
  206. xlwings_server/static/vendor/@microsoft/office-js/dist/lb-lu/office_strings.js +8 -0
  207. xlwings_server/static/vendor/@microsoft/office-js/dist/lo-la/office_strings.js +1 -0
  208. xlwings_server/static/vendor/@microsoft/office-js/dist/lt-lt/office_strings.js +1 -0
  209. xlwings_server/static/vendor/@microsoft/office-js/dist/lv-lv/office_strings.js +1 -0
  210. xlwings_server/static/vendor/@microsoft/office-js/dist/mk-mk/office_strings.js +8 -0
  211. xlwings_server/static/vendor/@microsoft/office-js/dist/ml-in/office_strings.js +1 -0
  212. xlwings_server/static/vendor/@microsoft/office-js/dist/mn-mn/office_strings.js +8 -0
  213. xlwings_server/static/vendor/@microsoft/office-js/dist/mr-in/office_strings.js +1 -0
  214. xlwings_server/static/vendor/@microsoft/office-js/dist/ms-bn/office_strings.js +8 -0
  215. xlwings_server/static/vendor/@microsoft/office-js/dist/ms-my/office_strings.js +1 -0
  216. xlwings_server/static/vendor/@microsoft/office-js/dist/mt-mt/office_strings.js +8 -0
  217. xlwings_server/static/vendor/@microsoft/office-js/dist/nb-no/office_strings.js +1 -0
  218. xlwings_server/static/vendor/@microsoft/office-js/dist/ne-np/office_strings.js +8 -0
  219. xlwings_server/static/vendor/@microsoft/office-js/dist/nl-be/office_strings.js +8 -0
  220. xlwings_server/static/vendor/@microsoft/office-js/dist/nl-nl/office_strings.js +1 -0
  221. xlwings_server/static/vendor/@microsoft/office-js/dist/nn-no/office_strings.js +1 -0
  222. xlwings_server/static/vendor/@microsoft/office-js/dist/o15apptofilemappingtable.js +11 -0
  223. xlwings_server/static/vendor/@microsoft/office-js/dist/office-vsdoc.js +28596 -0
  224. xlwings_server/static/vendor/@microsoft/office-js/dist/office.js +84 -0
  225. xlwings_server/static/vendor/@microsoft/office-js/dist/pl-pl/office_strings.js +1 -0
  226. xlwings_server/static/vendor/@microsoft/office-js/dist/pt-br/office_strings.js +1 -0
  227. xlwings_server/static/vendor/@microsoft/office-js/dist/pt-pt/office_strings.js +1 -0
  228. xlwings_server/static/vendor/@microsoft/office-js/dist/ro-ro/office_strings.js +1 -0
  229. xlwings_server/static/vendor/@microsoft/office-js/dist/ru-ru/office_strings.js +1 -0
  230. xlwings_server/static/vendor/@microsoft/office-js/dist/si-lk/office_strings.js +8 -0
  231. xlwings_server/static/vendor/@microsoft/office-js/dist/sk-sk/office_strings.js +1 -0
  232. xlwings_server/static/vendor/@microsoft/office-js/dist/sl-si/office_strings.js +1 -0
  233. xlwings_server/static/vendor/@microsoft/office-js/dist/sq-al/office_strings.js +8 -0
  234. xlwings_server/static/vendor/@microsoft/office-js/dist/sr-cyrl-cs/office_strings.js +1 -0
  235. xlwings_server/static/vendor/@microsoft/office-js/dist/sr-cyrl-rs/office_strings.js +1 -0
  236. xlwings_server/static/vendor/@microsoft/office-js/dist/sr-latn-cs/office_strings.js +1 -0
  237. xlwings_server/static/vendor/@microsoft/office-js/dist/sr-latn-rs/office_strings.js +1 -0
  238. xlwings_server/static/vendor/@microsoft/office-js/dist/sv-fi/office_strings.js +8 -0
  239. xlwings_server/static/vendor/@microsoft/office-js/dist/sv-se/office_strings.js +1 -0
  240. xlwings_server/static/vendor/@microsoft/office-js/dist/sw-ke/office_strings.js +1 -0
  241. xlwings_server/static/vendor/@microsoft/office-js/dist/ta-in/office_strings.js +1 -0
  242. xlwings_server/static/vendor/@microsoft/office-js/dist/te-in/office_strings.js +1 -0
  243. xlwings_server/static/vendor/@microsoft/office-js/dist/telemetry/oteljs.js +1 -0
  244. xlwings_server/static/vendor/@microsoft/office-js/dist/telemetry/oteljs_agave.js +1 -0
  245. xlwings_server/static/vendor/@microsoft/office-js/dist/th-th/office_strings.js +1 -0
  246. xlwings_server/static/vendor/@microsoft/office-js/dist/tr-tr/office_strings.js +1 -0
  247. xlwings_server/static/vendor/@microsoft/office-js/dist/uk-ua/office_strings.js +1 -0
  248. xlwings_server/static/vendor/@microsoft/office-js/dist/ur-pk/office_strings.js +1 -0
  249. xlwings_server/static/vendor/@microsoft/office-js/dist/vi-vn/office_strings.js +1 -0
  250. xlwings_server/static/vendor/@microsoft/office-js/dist/webauth/webauth.browserauth.js +77 -0
  251. xlwings_server/static/vendor/@microsoft/office-js/dist/webauth/webauth.implicit.js +35 -0
  252. xlwings_server/static/vendor/@microsoft/office-js/dist/zh-cn/office_strings.js +1 -0
  253. xlwings_server/static/vendor/@microsoft/office-js/dist/zh-hk/office_strings.js +8 -0
  254. xlwings_server/static/vendor/@microsoft/office-js/dist/zh-mo/office_strings.js +8 -0
  255. xlwings_server/static/vendor/@microsoft/office-js/dist/zh-sg/office_strings.js +8 -0
  256. xlwings_server/static/vendor/@microsoft/office-js/dist/zh-tw/office_strings.js +1 -0
  257. xlwings_server/static/vendor/axios/dist/axios.min.js +3 -0
  258. xlwings_server/static/vendor/axios/dist/axios.min.js.map +1 -0
  259. xlwings_server/static/vendor/bootstrap/LICENSE +21 -0
  260. xlwings_server/static/vendor/bootstrap/dist/js/bootstrap.bundle.min.js +7 -0
  261. xlwings_server/static/vendor/bootstrap/dist/js/bootstrap.bundle.min.js.map +1 -0
  262. xlwings_server/static/vendor/bootstrap-xlwings/dist/bootstrap-xlwings.min.css +12 -0
  263. xlwings_server/static/vendor/bootstrap-xlwings/dist/bootstrap-xlwings.min.css.map +1 -0
  264. xlwings_server/static/vendor/htmx-ext-head-support/head-support.js +144 -0
  265. xlwings_server/static/vendor/htmx-ext-loading-states/loading-states.js +184 -0
  266. xlwings_server/static/vendor/htmx.org/LICENSE +13 -0
  267. xlwings_server/static/vendor/htmx.org/dist/htmx.min.js +1 -0
  268. xlwings_server/static/vendor/socket.io/LICENSE +22 -0
  269. xlwings_server/static/vendor/socket.io/client-dist/socket.io.min.js +7 -0
  270. xlwings_server/static/vendor/socket.io/client-dist/socket.io.min.js.map +1 -0
  271. xlwings_server/templates/_book.html +8 -0
  272. xlwings_server/templates/alert_base.html +16 -0
  273. xlwings_server/templates/base.html +117 -0
  274. xlwings_server/templates/examples/alpine/README.md +26 -0
  275. xlwings_server/templates/examples/alpine/taskpane.html +47 -0
  276. xlwings_server/templates/examples/auth/README.md +38 -0
  277. xlwings_server/templates/examples/auth/protected.html +8 -0
  278. xlwings_server/templates/examples/auth/public.html +11 -0
  279. xlwings_server/templates/examples/excel_object_model/README.md +49 -0
  280. xlwings_server/templates/examples/excel_object_model/add_name_form.html +27 -0
  281. xlwings_server/templates/examples/hello_world/README.md +9 -0
  282. xlwings_server/templates/examples/hello_world/taskpane_hello.html +24 -0
  283. xlwings_server/templates/examples/htmx_form/README.md +44 -0
  284. xlwings_server/templates/examples/htmx_form/_greeting.html +6 -0
  285. xlwings_server/templates/examples/htmx_form/taskpane_htmx_form.html +21 -0
  286. xlwings_server/templates/examples/live_form_validation/README.md +60 -0
  287. xlwings_server/templates/examples/live_form_validation/add_name_form.html +33 -0
  288. xlwings_server/templates/examples/multi_app/README.md +34 -0
  289. xlwings_server/templates/examples/multi_app/taskpane1.html +7 -0
  290. xlwings_server/templates/examples/multi_app/taskpane2.html +7 -0
  291. xlwings_server/templates/examples/multi_app/taskpane_loader.html +5 -0
  292. xlwings_server/templates/examples/navigation/README.md +28 -0
  293. xlwings_server/templates/examples/navigation/_navigation.html +16 -0
  294. xlwings_server/templates/examples/navigation/taskpane_one.html +8 -0
  295. xlwings_server/templates/examples/navigation/taskpane_three.html +8 -0
  296. xlwings_server/templates/examples/navigation/taskpane_two.html +8 -0
  297. xlwings_server/templates/examples/pictures/README.md +42 -0
  298. xlwings_server/templates/examples/pictures/_picture.html +4 -0
  299. xlwings_server/templates/examples/pictures/taskpane_pictures.html +26 -0
  300. xlwings_server/templates/manifest.xml +155 -0
  301. xlwings_server/templates/taskpane.html +1 -0
  302. xlwings_server/templates/xlwings_alert.html +27 -0
  303. xlwings_server/templates.py +61 -0
  304. xlwings_server/utils.py +32 -0
  305. xlwings_server/wasm/__init__.py +0 -0
  306. xlwings_server/wasm/config.py +24 -0
  307. xlwings_server/wasm/main.py +236 -0
  308. xlwings_server/wasm/requirements.txt +5 -0
  309. xlwings_server-1.1.0.dist-info/METADATA +61 -0
  310. xlwings_server-1.1.0.dist-info/RECORD +313 -0
  311. xlwings_server-1.1.0.dist-info/WHEEL +4 -0
  312. xlwings_server-1.1.0.dist-info/entry_points.txt +2 -0
  313. xlwings_server-1.1.0.dist-info/licenses/LICENSE.md +223 -0
@@ -0,0 +1,228 @@
1
+ import logging
2
+ import os
3
+ import sys
4
+ import warnings
5
+ from importlib.metadata import version as get_package_version
6
+ from pathlib import Path
7
+ from typing import Any, Literal
8
+
9
+ from pydantic import UUID4, computed_field
10
+ from pydantic_settings import (
11
+ BaseSettings,
12
+ PydanticBaseSettingsSource,
13
+ PyprojectTomlConfigSettingsSource,
14
+ SettingsConfigDict,
15
+ )
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ # Set before xlwings is imported elsewhere in the application
20
+ os.environ["XLWINGS_ON_SERVER"] = "true"
21
+
22
+ # Get project directory from environment (set by CLI)
23
+ # Falls back to current working directory if not set (for backward compatibility)
24
+ PROJECT_DIR = Path(os.getenv("XLWINGS_PROJECT_DIR", Path.cwd()))
25
+
26
+ # Get package directory - must be calculated before any sys.path manipulation
27
+ # Use __file__ which points to the actual config.py location (in site-packages after install)
28
+ PACKAGE_DIR = Path(__file__).parent.resolve()
29
+
30
+ # Setup sys.path for user overrides
31
+ # This is also done in main.py, but we need it here too because config.py
32
+ # can be imported directly (e.g., from custom_functions) before main.py runs
33
+ if str(PROJECT_DIR) not in sys.path:
34
+ sys.path.insert(0, str(PROJECT_DIR))
35
+
36
+ # Settings prefix used for environment variables (required)
37
+ # and pyproject.toml keys (optional)
38
+ ENV_PREFIX = "XLWINGS_"
39
+
40
+
41
+ class CaseInsensitivePyprojectTomlSource(PyprojectTomlConfigSettingsSource):
42
+ """
43
+ PyprojectToml source that handles case-insensitive keys and strips ENV_PREFIX.
44
+ E.g., allows 'environment', 'ENVIRONMENT', 'XLWINGS_ENVIRONMENT', etc. to all work.
45
+ """
46
+
47
+ def __call__(self) -> dict[str, Any]:
48
+ config = super().__call__()
49
+ normalized = {}
50
+ prefix_lower = ENV_PREFIX.lower()
51
+ for k, v in config.items():
52
+ # Convert to lowercase
53
+ key = k.lower()
54
+ # Strip prefix if present (e.g., "xlwings_")
55
+ if key.startswith(prefix_lower):
56
+ key = key[len(prefix_lower) :]
57
+ normalized[key] = v
58
+ return normalized
59
+
60
+
61
+ class Settings(BaseSettings):
62
+ """
63
+ xlwings Server settings with support for multiple configuration sources.
64
+
65
+ Configuration priority (highest to lowest):
66
+ 1. Environment variables (XLWINGS_*)
67
+ 2. .env file
68
+ 3. pyproject.toml [tool.xlwings_server] section
69
+ 4. Default values defined in this class
70
+
71
+ See .env.template for detailed documentation of all settings.
72
+ """
73
+
74
+ def __init__(self, **values):
75
+ super().__init__(**values)
76
+ if self.public_addin_store is not None:
77
+ warnings.warn(
78
+ "The 'XLWINGS_PUBLIC_ADDIN_STORE' field is deprecated and will be removed in "
79
+ "future versions. Use 'XLWINGS_CDN_OFFICEJS' instead.",
80
+ DeprecationWarning,
81
+ )
82
+ self.cdn_officejs = self.public_addin_store
83
+
84
+ model_config = SettingsConfigDict(
85
+ env_prefix=ENV_PREFIX,
86
+ env_file=os.getenv("DOTENV_PATH", PROJECT_DIR / ".env"),
87
+ extra="ignore",
88
+ pyproject_toml_table_header=("tool", "xlwings_server"),
89
+ )
90
+
91
+ @classmethod
92
+ def settings_customise_sources(
93
+ cls,
94
+ settings_cls: type[BaseSettings],
95
+ init_settings: PydanticBaseSettingsSource,
96
+ env_settings: PydanticBaseSettingsSource,
97
+ dotenv_settings: PydanticBaseSettingsSource,
98
+ file_secret_settings: PydanticBaseSettingsSource,
99
+ ) -> tuple[PydanticBaseSettingsSource, ...]:
100
+ """
101
+ Define the sources and their priority order.
102
+ Priority (highest to lowest):
103
+ 1. init_settings - arguments passed to Settings()
104
+ 2. env_settings - environment variables
105
+ 3. dotenv_settings - .env file
106
+ 4. pyproject.toml - [tool.xlwings_server] section
107
+ 5. file_secret_settings - secret files
108
+ """
109
+ # CaseInsensitivePyprojectTomlSource looks in PROJECT_DIR for pyproject.toml
110
+ pyproject_path = PROJECT_DIR / "pyproject.toml"
111
+ return (
112
+ init_settings,
113
+ env_settings,
114
+ dotenv_settings,
115
+ CaseInsensitivePyprojectTomlSource(
116
+ settings_cls, pyproject_path if pyproject_path.exists() else None
117
+ ),
118
+ file_secret_settings,
119
+ )
120
+
121
+ add_security_headers: bool = True
122
+ auth_providers: list[str] | None = []
123
+ auth_required_roles: list[str] | None = []
124
+ auth_entraid_client_id: str | None = None
125
+ auth_entraid_tenant_id: str | None = None
126
+ auth_entraid_multitenant: bool = False
127
+ app_path: str = ""
128
+ base_dir: Path = Path(__file__).resolve().parent
129
+ object_cache_url: str | None = None
130
+ object_cache_expire_at: str | None = "0 12 * * sat"
131
+ object_cache_enable_compression: bool = True
132
+ cors_allow_origins: list[str] = []
133
+ custom_functions_max_retries: int = 3
134
+ custom_functions_retry_codes: list[int] = [500, 502, 504]
135
+ custom_headers: dict[str, str] = {}
136
+ date_format: str | None = None
137
+ taskpane_html: str = "taskpane.html"
138
+ enable_alpinejs_csp: bool = True
139
+ enable_bootstrap: bool = True
140
+ enable_examples: bool = False
141
+ enable_excel_online: bool = True
142
+ enable_hotreload: bool = True
143
+ enable_htmx: bool = True
144
+ enable_socketio: bool = True
145
+ enable_tests: bool = False
146
+ enable_wasm: bool = False
147
+ environment: Literal["dev", "qa", "uat", "staging", "prod"] = "prod"
148
+ functions_namespace: str = "XLWINGS"
149
+ hostname: str | None = None
150
+ is_official_lite_addin: bool | None = False
151
+ cdn_pyodide: bool = True
152
+ cdn_officejs: bool = False
153
+ log_level: str = "INFO"
154
+ # Manifest UUIDs - loaded from pyproject.toml [tool.xlwings_server] or defaults
155
+ # Run 'xlwings-server init' to generate unique UUIDs in pyproject.toml
156
+ manifest_id_dev: UUID4 = "0a856eb1-91ab-4f38-b757-23fbe1f73130"
157
+ manifest_id_qa: UUID4 = "9cda34b1-af68-4dc6-b97c-e63ef6284671"
158
+ manifest_id_uat: UUID4 = "70428e53-8113-421c-8fe2-9b74fcb94ee5"
159
+ manifest_id_staging: UUID4 = "34041f4f-9cb4-4830-afb5-db44b2a70e0e"
160
+ manifest_id_prod: UUID4 = "4f342d85-3a49-41cb-90a5-37b1f2219040"
161
+ project_name: str = "xlwings Server"
162
+ public_addin_store: bool | None = None # Deprecated. Use cdn_officejs instead.
163
+ request_timeout: int | None = 300 # in seconds
164
+ secret_key: str | None = None
165
+ socketio_message_queue_url: str | None = None
166
+ socketio_server_app: bool = False
167
+ static_url_path: str = "/static"
168
+ license_key: str | None = ""
169
+ xlwings_version: str = get_package_version("xlwings")
170
+
171
+ @computed_field
172
+ @property
173
+ def jsconfig(self) -> dict:
174
+ return {
175
+ "appPath": self.app_path,
176
+ "authProviders": self.auth_providers,
177
+ "customFunctionsMaxRetries": self.custom_functions_max_retries,
178
+ "customFunctionsRetryCodes": self.custom_functions_retry_codes,
179
+ "environment": self.environment,
180
+ "isOfficialLiteAddin": self.is_official_lite_addin,
181
+ "onWasm": self.enable_wasm,
182
+ "requestTimeout": self.request_timeout,
183
+ "xlwingsVersion": self.xlwings_version,
184
+ }
185
+
186
+ @computed_field
187
+ @property
188
+ def project_dir(self) -> Path:
189
+ """Project directory - location of user's custom files"""
190
+ return PROJECT_DIR
191
+
192
+ @computed_field
193
+ @property
194
+ def package_dir(self) -> Path:
195
+ """Package directory - location of xlwings-server package files"""
196
+ return PACKAGE_DIR
197
+
198
+
199
+ # Try to import Settings from project directory (user override)
200
+ # Fall back to package Settings if not found
201
+ def _create_settings() -> Settings:
202
+ """Create settings instance, checking for project-level config override"""
203
+ try:
204
+ config_file = PROJECT_DIR / "config.py"
205
+ if config_file.exists():
206
+ # Import Settings from project config
207
+ import importlib
208
+
209
+ config_module = importlib.import_module("config")
210
+ if hasattr(config_module, "Settings"):
211
+ ProjectSettings = config_module.Settings
212
+ logger.info("Loaded settings from project config.py")
213
+ return ProjectSettings()
214
+ except Exception as e:
215
+ logger.debug(f"No project config.py found or failed to load: {e}")
216
+
217
+ # No project config or import failed, use package Settings
218
+ return Settings()
219
+
220
+
221
+ settings = _create_settings()
222
+
223
+ # TODO: refactor once xlwings offers a runtime config
224
+ if settings.license_key and not os.getenv("XLWINGS_LICENSE_KEY"):
225
+ os.environ["XLWINGS_LICENSE_KEY"] = settings.license_key
226
+
227
+ if settings.date_format:
228
+ os.environ["XLWINGS_DATE_FORMAT"] = settings.date_format
@@ -0,0 +1,8 @@
1
+ try:
2
+ from xlwings_server.config import settings
3
+ except ImportError:
4
+ # xlwings Wasm
5
+ from config import settings
6
+
7
+ if settings.enable_examples:
8
+ from .examples import *
@@ -0,0 +1,177 @@
1
+ """
2
+ Make sure to import the desired functions under __init__.py, e.g.:
3
+ from .example import *
4
+ """
5
+
6
+ import asyncio
7
+ import datetime as dt
8
+ import sys
9
+ from pathlib import Path
10
+ from typing import Annotated
11
+
12
+ import numpy as np
13
+ import pandas as pd
14
+ from xlwings.server import arg, func, ret
15
+
16
+ from . import settings
17
+
18
+ if not settings.enable_wasm:
19
+ # Try to import custom_scripts from project directory first (CLI/Azure mode)
20
+ # Fall back to package location (tests/package mode)
21
+ try:
22
+ import custom_scripts
23
+ except ModuleNotFoundError:
24
+ import xlwings_server.custom_scripts as custom_scripts
25
+
26
+ from xlwings.constants import ObjectHandleIcons
27
+ from xlwings.ext.sql import _sql
28
+
29
+ from xlwings_server import utils
30
+ from xlwings_server.models import CurrentUser
31
+
32
+
33
+ # 1) This is the most basic custom function -- it only requires the @func decorator.
34
+ @func
35
+ def hello(name):
36
+ return f"Hello {name}!"
37
+
38
+
39
+ # 2) Returning a pandas DataFrame and function documentation
40
+ # The function's doc string will turn up in the Function Wizard together with the
41
+ # doc strings from the arg decorators. The sample also shows how to suppress the index
42
+ # of a DataFrame via the ret decorator.
43
+ @func
44
+ @arg("rows", doc="The number of rows in the returned array.")
45
+ @arg("cols", doc="The number of columns in the returned array.")
46
+ def standard_normal(rows, cols):
47
+ """Returns an array of standard normally distributed pseudo random numbers"""
48
+ rng = np.random.default_rng()
49
+ matrix = rng.standard_normal(size=(rows, cols))
50
+ date_rng = pd.date_range(start=dt.datetime(2025, 6, 15), periods=rows, freq="D")
51
+ df = pd.DataFrame(
52
+ matrix, columns=[f"col{i+1}" for i in range(matrix.shape[1])], index=date_rng
53
+ )
54
+ return df
55
+
56
+
57
+ # 3) Reading a pandas DataFrames
58
+ @func
59
+ @arg("df", pd.DataFrame)
60
+ def correl(df):
61
+ """Like CORREL, but it works on whole matrices instead of just 2 arrays."""
62
+ return df.corr()
63
+
64
+
65
+ # 4) Type hints: this is the same example as 3), but using type hints instead of
66
+ # decorators. You could also use type hints and decorators together. In this sample, we
67
+ # are storing the Annotated type hint outside of the function, so it is easy to reuse.
68
+ Df = Annotated[pd.DataFrame, {"index": True}]
69
+
70
+
71
+ @func
72
+ def correl2(df: Df):
73
+ """Like CORREL, but it works on whole matrices instead of just 2 arrays."""
74
+ return df.corr()
75
+
76
+
77
+ if not settings.enable_wasm:
78
+ # 5) Object handles: This returns an object handle to a DataFrame that is generated on
79
+ # the backend. You can change the `text` and `icon` via annotated type hint or via ret
80
+ # decorator.
81
+ @func
82
+ async def get_df() -> object:
83
+ """Returns an object handle to the Excel cell (for production, this requires
84
+ XLWINGS_OBJECT_CACHE_URL)."""
85
+ return pd.DataFrame(
86
+ {"A": [1, 2, 3, 4, 5], "B": [10, 8, 6, 4, 2], "C": [10, 9, 8, 7, 6]}
87
+ )
88
+
89
+ # 6) Object handles: demonstrating the use of the "icon" and "text" options. Instead
90
+ # of using the ret decorator, you could also use an annotated type hint like so:
91
+ # -> Annotated[object, {"icon": ObjectHandleIcons.table, "text": "healthexp"}]
92
+ @func
93
+ @ret(icon=ObjectHandleIcons.table, text="healthexp")
94
+ async def get_healthexp(
95
+ csv_url="https://raw.githubusercontent.com/mwaskom/seaborn-data/master/healthexp.csv",
96
+ ) -> object:
97
+ """Returns an object handle to the Excel cell (for production, this requires
98
+ XLWINGS_OBJECT_CACHE_URL)."""
99
+ return pd.read_csv(csv_url)
100
+
101
+ # 7) Object handles: turn an Excel range into a DataFrame object handle. Using an Excel
102
+ # table as source makes it easy to work with dynamic source ranges. This sample reuses
103
+ # the Df type hint from above to set index=False.
104
+ @func
105
+ async def to_df(df: Df) -> object:
106
+ return df
107
+
108
+ # 8) Object handles: use a pandas DataFrame query by providing a DataFrame via object
109
+ # handle and the query as string: [NAMESPACE].DF_QUERY(A1, "A > B")
110
+ @func
111
+ async def df_query(df: object, query: str) -> Df:
112
+ return df.query(query)
113
+
114
+ # 9) Object handles: Generic function that turns an object handle into Excel values
115
+ @func
116
+ async def view(obj: object, head=None):
117
+ """Converts an object handle to cell values. `head` can be TRUE or an integer, which
118
+ represents the number of rows from the top that you want to see. TRUE returns the
119
+ first 5 rows.
120
+ """
121
+ if head and isinstance(head, bool):
122
+ head = 5
123
+ if isinstance(obj, pd.DataFrame) and head:
124
+ return obj.iloc[:head, :]
125
+ elif isinstance(obj, (list, tuple, np.ndarray)) and head:
126
+ return obj[:head]
127
+ else:
128
+ return obj
129
+
130
+ # 10) Object handles: Clear the object cache manually
131
+ @func
132
+ async def clear_object_cache():
133
+ """Object handle: Clear the object cache manually"""
134
+ await utils.clear_object_cache()
135
+ return "Object cache cleared"
136
+
137
+ # 11) Streaming functions (the modern version of RTD functions)
138
+ @func
139
+ async def streaming_random(rows, cols):
140
+ """Streaming function: must be provided as async generator,
141
+ requires XLWINGS_ENABLE_SOCKETIO=true
142
+ """
143
+ rng = np.random.default_rng()
144
+ while True:
145
+ matrix = rng.standard_normal(size=(rows, cols))
146
+ df = pd.DataFrame(
147
+ matrix, columns=[f"col{i+1}" for i in range(matrix.shape[1])]
148
+ )
149
+ yield df
150
+ await asyncio.sleep(1)
151
+
152
+ # 12) To access the current user object, simply add an argument with the CurrentUser
153
+ # type hint
154
+ @func
155
+ def get_current_user(current_user: CurrentUser):
156
+ return f"{current_user}"
157
+
158
+ # 13) In-Excel SQL: query Excel ranges/tables via SQL (SQLite dialect)
159
+ @func
160
+ @arg("tables", expand="table", ndim=2)
161
+ def sql(query, *tables):
162
+ """In-Excel SQL
163
+ see: https://docs.xlwings.org/en/latest/extensions.html#in-excel-sql"""
164
+ return _sql(query, *tables)
165
+
166
+ # 14) Custom functions with side effects (experimental)
167
+ @func
168
+ async def hello_with_script(name):
169
+ """This function triggers a custom script, requires XLWINGS_ENABLE_SOCKETIO=true"""
170
+ await utils.trigger_script(custom_scripts.hello_world, exclude="MySheet")
171
+ return f"Hello {name}!"
172
+
173
+
174
+ # Unit tests
175
+ if settings.enable_tests:
176
+ sys.path.append(str(Path(__file__).parent.parent.resolve()))
177
+ from tests.e2e_custom_functions import *
@@ -0,0 +1,8 @@
1
+ try:
2
+ from xlwings_server.config import settings
3
+ except ImportError:
4
+ # xlwings Wasm
5
+ from config import settings
6
+
7
+ if settings.enable_examples:
8
+ from .examples import *
@@ -0,0 +1,94 @@
1
+ """
2
+ Make sure to import the desired functions under __init__.py, e.g.:
3
+ from .example import *
4
+ """
5
+
6
+ try:
7
+ import matplotlib.pyplot as plt
8
+ except ImportError:
9
+ plt = None
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ import numpy as np
14
+ import xlwings as xw
15
+ from xlwings.server import script
16
+
17
+ from . import settings
18
+
19
+
20
+ @script
21
+ def hello_world(book: xw.Book):
22
+ sheet = book.sheets.active
23
+ cell = sheet["A1"]
24
+ if cell.value == "Hello package!":
25
+ cell.value = "Bye package!"
26
+ else:
27
+ cell.value = "Hello package!"
28
+
29
+
30
+ @script
31
+ def show_alert(book: xw.Book):
32
+ # callback is optional and only required if you want a JS function to be called
33
+ # when clicking a button. alertCallback is defined in app/static/js/core/examples.js
34
+ book.app.alert(
35
+ "This is an alert!",
36
+ title="xlwings Server Alert",
37
+ buttons="ok_cancel",
38
+ callback="alertCallback",
39
+ )
40
+
41
+
42
+ @script
43
+ def setup_custom_functions(book: xw.Book):
44
+ prefix = f"{settings.functions_namespace}"
45
+ if settings.environment != "prod":
46
+ prefix += f"_{settings.environment}".upper()
47
+ sheet = book.sheets.add()
48
+ sheet["A3"].value = f'={prefix}.HELLO("xlwings")'
49
+ sheet["A5"].value = f"={prefix}.STANDARD_NORMAL(3, 4)"
50
+ sheet["A10"].value = f"={prefix}.CORREL(A5#)"
51
+ if not settings.enable_wasm:
52
+ sheet["A16"].value = f"={prefix}.TO_DF(A5#)"
53
+ sheet["A18"].value = f"={prefix}.GET_HEALTHEXP()"
54
+ sheet[
55
+ "A20"
56
+ ].value = f"""={prefix}.DF_QUERY(A18, "Country == 'Japan' and Year > 2017")"""
57
+ sheet["A25"].value = f"={prefix}.VIEW(A18, 3)"
58
+ sheet["A30"].value = f"={prefix}.STREAMING_RANDOM(3, 4)"
59
+ sheet["A35"].value = f"={prefix}.GET_CURRENT_USER()"
60
+ sheet[
61
+ "A37"
62
+ ].value = f'={prefix}.SQL("SELECT Year, Country FROM a WHERE Spending_USD < 4600", A20#)'
63
+ sheet["A40"].value = f'={prefix}.HELLO_WITH_SCRIPT("xlwings")'
64
+ sheet.activate()
65
+
66
+
67
+ @script
68
+ def show_plot(book: xw.Book):
69
+ """Adopted from
70
+ https://matplotlib.org/stable/plot_types/stats/hexbin.html#sphx-glr-plot-types-stats-hexbin-py
71
+ """
72
+ if not plt:
73
+ raise xw.XlwingsError("You need to install Matplotlib for this example")
74
+ plt.style.use("_mpl-gallery-nogrid")
75
+ rng = np.random.default_rng()
76
+ x = rng.standard_normal(5000)
77
+ y = 1.2 * x + rng.standard_normal(5000) / 3
78
+ fig, ax = plt.subplots()
79
+ ax.hexbin(x, y, gridsize=20)
80
+ ax.set(xlim=(-2, 2), ylim=(-3, 3))
81
+ book.sheets.active.pictures.add(
82
+ fig, anchor=book.sheets.active["A10"], update=True, name="mplot"
83
+ )
84
+
85
+
86
+ @script
87
+ def show_error(book: xw.Book):
88
+ raise xw.XlwingsError("This would be your error message")
89
+
90
+
91
+ # Unit tests
92
+ if settings.enable_tests:
93
+ sys.path.append(str(Path(__file__).parent.parent.resolve()))
94
+ from tests.e2e_custom_scripts import *
@@ -0,0 +1,19 @@
1
+ import redis # TODO: use redis.asyncio when converters can be used async
2
+
3
+ from .config import settings
4
+
5
+ # Redis
6
+ redis_pool = None
7
+ if settings.object_cache_url:
8
+ redis_pool = redis.ConnectionPool.from_url(settings.object_cache_url)
9
+
10
+
11
+ def get_redis_client():
12
+ if redis_pool is None:
13
+ yield None
14
+ else:
15
+ client = redis.Redis.from_pool(redis_pool)
16
+ try:
17
+ yield client
18
+ finally:
19
+ client.close()
@@ -0,0 +1,126 @@
1
+ import importlib
2
+ import json
3
+ import logging
4
+ from typing import Annotated, Union
5
+
6
+ import redis
7
+ import xlwings as xw
8
+ from fastapi import Depends, Form, Header, HTTPException, Request, status
9
+
10
+ from . import models
11
+ from .config import settings
12
+ from .databases import get_redis_client
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ # Book
18
+ async def parse_book_input(
19
+ request: Request,
20
+ form_data: str | None = Form(None, alias="bookData"),
21
+ ) -> dict:
22
+ """Helper dependency to parse either form data (htmx)
23
+ or body (custom scripts & custom functions) -- couldn't make Body() work"""
24
+ if form_data:
25
+ return json.loads(form_data)
26
+ else:
27
+ body_bytes = await request.body()
28
+ if body_bytes:
29
+ body_str = body_bytes.decode("utf-8")
30
+ return json.loads(body_str)
31
+ raise HTTPException(status_code=400, detail="No book data provided")
32
+
33
+
34
+ async def get_book(book_data: dict = Depends(parse_book_input)):
35
+ """Book dependency that returns the calling book and cleans it up again"""
36
+ book = xw.Book(json=book_data)
37
+ try:
38
+ yield book
39
+ finally:
40
+ book.close()
41
+
42
+
43
+ Book = Annotated[xw.Book, Depends(get_book)]
44
+
45
+
46
+ # Users/Auth
47
+ async def authenticate(
48
+ token_string: str = Header(default="", alias="Authorization"),
49
+ auth_provider: Union[str, None] = Header(default=None),
50
+ ):
51
+ if not settings.auth_providers:
52
+ return User(id="n/a", name="Anonymous")
53
+ if len(settings.auth_providers) == 1:
54
+ provider = settings.auth_providers[0]
55
+ elif len(settings.auth_providers) > 1 and not auth_provider:
56
+ raise HTTPException(
57
+ status_code=status.HTTP_400_BAD_REQUEST,
58
+ detail="With multiple auth providers, you need to provide the Auth-Provider header.",
59
+ )
60
+ elif auth_provider not in settings.auth_providers:
61
+ raise HTTPException(
62
+ status_code=status.HTTP_400_BAD_REQUEST,
63
+ detail="Auth-Provider header wasn't found in XLWINGS_AUTH_PROVIDERS setting.",
64
+ )
65
+ else:
66
+ provider = auth_provider
67
+ logger.info(f"Using auth provider {provider}")
68
+ # Validate the provider before import to prevent non-literal-import SAST flagging
69
+ if provider not in settings.auth_providers:
70
+ raise ValueError(f"Unsupported authentication provider: {provider}")
71
+ try:
72
+ # Try to import from project directory first (user override)
73
+ try:
74
+ module = importlib.import_module(f"auth.{provider}")
75
+ except ModuleNotFoundError:
76
+ # Fall back to package location (default implementation)
77
+ module = importlib.import_module(f"xlwings_server.auth.{provider}")
78
+ current_user = await module.validate_token(token_string)
79
+ except (AttributeError, ModuleNotFoundError):
80
+ logger.exception(f"Auth provider '{provider}' implementation missing.")
81
+ raise HTTPException(
82
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
83
+ detail=f"Auth provider '{provider}' implementation missing.",
84
+ )
85
+ return current_user
86
+
87
+
88
+ async def get_user(request: Request, current_user: models.User = Depends(authenticate)):
89
+ # Extract IP address and attach it to the user object
90
+ if "x-forwarded-for" in request.headers:
91
+ ip_address = request.headers["x-forwarded-for"].split(",")[0].strip()
92
+ else:
93
+ ip_address = request.client.host if request.client else None
94
+ current_user.ip_address = ip_address
95
+
96
+ if not settings.auth_providers:
97
+ return current_user
98
+ # RBAC
99
+ has_required_roles = await current_user.has_required_roles(
100
+ settings.auth_required_roles
101
+ )
102
+ if not has_required_roles:
103
+ missing_roles = ", ".join(
104
+ set(settings.auth_required_roles).difference(current_user.roles)
105
+ )
106
+ msg = f"Auth error: Missing roles for {current_user.name}: {missing_roles}"
107
+ logger.warning(msg)
108
+ raise HTTPException(
109
+ status_code=status.HTTP_403_FORBIDDEN,
110
+ detail=msg,
111
+ )
112
+ # Authorization
113
+ if not await current_user.is_authorized():
114
+ msg = f"Auth error: Not authorized for {current_user.name}"
115
+ logger.warning(msg)
116
+ raise HTTPException(
117
+ status_code=status.HTTP_403_FORBIDDEN,
118
+ detail=msg,
119
+ )
120
+ return current_user
121
+
122
+
123
+ User = Annotated[models.User, Depends(get_user)]
124
+
125
+ # Redis
126
+ RedisClient = Annotated[redis.Redis, Depends(get_redis_client)]
@@ -0,0 +1,15 @@
1
+ .git
2
+ .gitignore
3
+ .python-version
4
+ .venv
5
+ .env
6
+ .env.*
7
+ *.pyc
8
+ __pycache__
9
+ *.egg-info
10
+ .DS_Store
11
+ certs/
12
+ README.md
13
+ Dockerfile
14
+ .dockerignore
15
+ *.local.*