Flowfile 0.5.1__py3-none-any.whl → 0.5.4__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 (346) hide show
  1. build_backends/main.py +25 -22
  2. build_backends/main_prd.py +10 -19
  3. flowfile/__init__.py +194 -74
  4. flowfile/__main__.py +10 -7
  5. flowfile/api.py +51 -57
  6. flowfile/web/__init__.py +14 -9
  7. flowfile/web/static/assets/AdminView-f53bad23.css +129 -0
  8. flowfile/web/static/assets/AdminView-f9847d67.js +713 -0
  9. flowfile/web/static/assets/CloudConnectionView-cf85f943.css +72 -0
  10. flowfile/web/static/assets/{CloudConnectionManager-0dfba9f2.js → CloudConnectionView-faace55b.js} +11 -11
  11. flowfile/web/static/assets/{CloudStorageReader-29d14fcc.css → CloudStorageReader-24c54524.css} +27 -27
  12. flowfile/web/static/assets/{CloudStorageReader-d5b1b6c9.js → CloudStorageReader-d86ecaa7.js} +10 -8
  13. flowfile/web/static/assets/{CloudStorageWriter-00d87aad.js → CloudStorageWriter-0f4d9a44.js} +10 -8
  14. flowfile/web/static/assets/{CloudStorageWriter-b0ee067f.css → CloudStorageWriter-60547855.css} +26 -26
  15. flowfile/web/static/assets/ColumnActionInput-c44b7aee.css +159 -0
  16. flowfile/web/static/assets/ColumnActionInput-f4189ae0.js +330 -0
  17. flowfile/web/static/assets/{ColumnSelector-47996a16.css → ColumnSelector-371637fb.css} +2 -2
  18. flowfile/web/static/assets/{ColumnSelector-4685e75d.js → ColumnSelector-e66b33da.js} +3 -5
  19. flowfile/web/static/assets/ContextMenu-49463352.js +9 -0
  20. flowfile/web/static/assets/ContextMenu-dd5f3f25.js +9 -0
  21. flowfile/web/static/assets/ContextMenu-f709b884.js +9 -0
  22. flowfile/web/static/assets/ContextMenu.vue_vue_type_script_setup_true_lang-a1bd6314.js +59 -0
  23. flowfile/web/static/assets/{CrossJoin-702a3edd.js → CrossJoin-24694b8f.js} +12 -10
  24. flowfile/web/static/assets/{CrossJoin-1119d18e.css → CrossJoin-71b4cc10.css} +20 -20
  25. flowfile/web/static/assets/{CustomNode-b1519993.js → CustomNode-569d45ff.js} +43 -24
  26. flowfile/web/static/assets/CustomNode-edb9b939.css +42 -0
  27. flowfile/web/static/assets/{DatabaseConnectionSettings-0c04b2e5.css → DatabaseConnectionSettings-c20a1e16.css} +23 -21
  28. flowfile/web/static/assets/{DatabaseConnectionSettings-6f3e4ea5.js → DatabaseConnectionSettings-cfc08938.js} +5 -4
  29. flowfile/web/static/assets/{DatabaseReader-ae61773c.css → DatabaseReader-5bf8c75b.css} +41 -46
  30. flowfile/web/static/assets/{DatabaseReader-d38c7295.js → DatabaseReader-701feabb.js} +25 -15
  31. flowfile/web/static/assets/{DatabaseManager-cf5ef661.js → DatabaseView-0482e5b5.js} +11 -11
  32. flowfile/web/static/assets/DatabaseView-6655afd6.css +57 -0
  33. flowfile/web/static/assets/{DatabaseWriter-b04ef46a.js → DatabaseWriter-16721989.js} +17 -10
  34. flowfile/web/static/assets/{DatabaseWriter-2f570e53.css → DatabaseWriter-bdcf2c8b.css} +29 -27
  35. flowfile/web/static/assets/{designer-8da3ba3a.css → DesignerView-49abb835.css} +783 -663
  36. flowfile/web/static/assets/{designer-9633482a.js → DesignerView-f64749fb.js} +1292 -3253
  37. flowfile/web/static/assets/{documentation-ca400224.js → DocumentationView-61bd2990.js} +5 -5
  38. flowfile/web/static/assets/{documentation-12216a74.css → DocumentationView-9ea6e871.css} +9 -9
  39. flowfile/web/static/assets/{ExploreData-2d0cf4db.css → ExploreData-10c5acc8.css} +13 -12
  40. flowfile/web/static/assets/{ExploreData-5fa10ed8.js → ExploreData-e2735b13.js} +18 -9
  41. flowfile/web/static/assets/{ExternalSource-d39af878.js → ExternalSource-2535c3b2.js} +9 -7
  42. flowfile/web/static/assets/{ExternalSource-e37b6275.css → ExternalSource-7ac7373f.css} +20 -20
  43. flowfile/web/static/assets/Filter-2cdbc93c.js +287 -0
  44. flowfile/web/static/assets/Filter-7494ea97.css +48 -0
  45. flowfile/web/static/assets/{Formula-bb96803d.css → Formula-53d58c43.css} +7 -7
  46. flowfile/web/static/assets/{Formula-6b04fb1d.js → Formula-fcda3c2c.js} +13 -11
  47. flowfile/web/static/assets/{FuzzyMatch-1010f966.css → FuzzyMatch-ad6361d6.css} +68 -69
  48. flowfile/web/static/assets/{FuzzyMatch-999521f4.js → FuzzyMatch-f8d3b7d3.js} +12 -10
  49. flowfile/web/static/assets/{Pivot-cf333e3d.css → GraphSolver-4b4d7db9.css} +5 -5
  50. flowfile/web/static/assets/{GraphSolver-17dd2198.js → GraphSolver-72eaa695.js} +14 -12
  51. flowfile/web/static/assets/GroupBy-5792782d.css +9 -0
  52. flowfile/web/static/assets/{GroupBy-6b039e18.js → GroupBy-8aa0598b.js} +9 -7
  53. flowfile/web/static/assets/{Join-fd79b451.css → Join-28b5e18f.css} +22 -22
  54. flowfile/web/static/assets/{Join-24d0f113.js → Join-e40f0ffa.js} +13 -11
  55. flowfile/web/static/assets/LoginView-5111c9ae.js +134 -0
  56. flowfile/web/static/assets/LoginView-d325d632.css +172 -0
  57. flowfile/web/static/assets/ManualInput-3702e677.css +293 -0
  58. flowfile/web/static/assets/{ManualInput-34639209.js → ManualInput-9b6f3224.js} +170 -116
  59. flowfile/web/static/assets/{MultiSelect-0e8724a3.js → MultiSelect-ef28e19e.js} +2 -2
  60. flowfile/web/static/assets/{MultiSelect.vue_vue_type_script_setup_true_lang-b0e538c2.js → MultiSelect.vue_vue_type_script_setup_true_lang-83b3bbfd.js} +1 -1
  61. flowfile/web/static/assets/NodeDesigner-94cd4dd3.css +1429 -0
  62. flowfile/web/static/assets/NodeDesigner-d2b7ee2b.js +2712 -0
  63. flowfile/web/static/assets/{NumericInput-3d63a470.js → NumericInput-1d789794.js} +2 -2
  64. flowfile/web/static/assets/{NumericInput.vue_vue_type_script_setup_true_lang-e0edeccc.js → NumericInput.vue_vue_type_script_setup_true_lang-7775f83e.js} +5 -2
  65. flowfile/web/static/assets/Output-692dd25d.css +37 -0
  66. flowfile/web/static/assets/{Output-edea9802.js → Output-cefef801.js} +14 -10
  67. flowfile/web/static/assets/{GraphSolver-f0cb7bfb.css → Pivot-0eda81b4.css} +5 -5
  68. flowfile/web/static/assets/{Pivot-61d19301.js → Pivot-bab1b75b.js} +12 -10
  69. flowfile/web/static/assets/PivotValidation-0e905b1a.css +13 -0
  70. flowfile/web/static/assets/PivotValidation-41b57ad6.css +13 -0
  71. flowfile/web/static/assets/{PivotValidation-f97fec5b.js → PivotValidation-e7941f91.js} +3 -3
  72. flowfile/web/static/assets/{PivotValidation-de9f43fe.js → PivotValidation-fba09336.js} +3 -3
  73. flowfile/web/static/assets/{PolarsCode-650322d1.css → PolarsCode-2b1f1f23.css} +4 -4
  74. flowfile/web/static/assets/{PolarsCode-bc3c9984.js → PolarsCode-740e40fa.js} +18 -9
  75. flowfile/web/static/assets/PopOver-862d7e28.js +939 -0
  76. flowfile/web/static/assets/PopOver-d96599db.css +33 -0
  77. flowfile/web/static/assets/{Read-64a3f259.js → Read-225cc63f.js} +16 -12
  78. flowfile/web/static/assets/{Read-e808b239.css → Read-90f366bc.css} +15 -15
  79. flowfile/web/static/assets/{RecordCount-3d5039be.js → RecordCount-ffc71eca.js} +6 -4
  80. flowfile/web/static/assets/{RecordId-597510e0.js → RecordId-a70bb8df.js} +9 -7
  81. flowfile/web/static/assets/{SQLQueryComponent-df51adbe.js → SQLQueryComponent-15a421f5.js} +3 -3
  82. flowfile/web/static/assets/SQLQueryComponent-edb90b98.css +29 -0
  83. flowfile/web/static/assets/{Sample-4be0a507.js → Sample-6c26afc7.js} +6 -4
  84. flowfile/web/static/assets/SecretSelector-6329f743.css +43 -0
  85. flowfile/web/static/assets/SecretSelector-ceed9496.js +113 -0
  86. flowfile/web/static/assets/{SecretManager-4839be57.js → SecretsView-214d255a.js} +35 -36
  87. flowfile/web/static/assets/SecretsView-aa291340.css +38 -0
  88. flowfile/web/static/assets/{Select-9b72f201.js → Select-8fc29999.js} +9 -7
  89. flowfile/web/static/assets/{SettingsSection-71e6b7e3.css → SettingsSection-07fbbc39.css} +4 -4
  90. flowfile/web/static/assets/{SettingsSection-5c696bee.css → SettingsSection-26fe48d4.css} +4 -4
  91. flowfile/web/static/assets/{SettingsSection-7ded385d.js → SettingsSection-3f70e4c3.js} +3 -3
  92. flowfile/web/static/assets/{SettingsSection-f0f75a42.js → SettingsSection-83090218.js} +3 -3
  93. flowfile/web/static/assets/{SettingsSection-2e4d03c4.css → SettingsSection-8f980839.css} +4 -4
  94. flowfile/web/static/assets/{SettingsSection-e1e9c953.js → SettingsSection-9f0d1725.js} +3 -3
  95. flowfile/web/static/assets/SetupView-3fa0aa03.js +160 -0
  96. flowfile/web/static/assets/SetupView-e2da3442.css +230 -0
  97. flowfile/web/static/assets/{SingleSelect-6c777aac.js → SingleSelect-a4a568cb.js} +2 -2
  98. flowfile/web/static/assets/{SingleSelect.vue_vue_type_script_setup_true_lang-33e3ff9b.js → SingleSelect.vue_vue_type_script_setup_true_lang-c8ebdd33.js} +1 -1
  99. flowfile/web/static/assets/{SliderInput-7cb93e62.js → SliderInput-be533e71.js} +7 -4
  100. flowfile/web/static/assets/SliderInput-f2e4f23c.css +4 -0
  101. flowfile/web/static/assets/{Sort-6cbde21a.js → Sort-154dad81.js} +9 -7
  102. flowfile/web/static/assets/Sort-4abb7fae.css +9 -0
  103. flowfile/web/static/assets/{TextInput-d9a40c11.js → TextInput-454e2bda.js} +2 -2
  104. flowfile/web/static/assets/{TextInput.vue_vue_type_script_setup_true_lang-5896c375.js → TextInput.vue_vue_type_script_setup_true_lang-e86510d0.js} +5 -2
  105. flowfile/web/static/assets/{TextToRows-5d2c1190.css → TextToRows-12afb4f4.css} +10 -10
  106. flowfile/web/static/assets/{TextToRows-c4fcbf4d.js → TextToRows-ea73433d.js} +11 -10
  107. flowfile/web/static/assets/{ToggleSwitch-4ef91d19.js → ToggleSwitch-9d7b30f1.js} +2 -2
  108. flowfile/web/static/assets/{ToggleSwitch.vue_vue_type_script_setup_true_lang-38478c20.js → ToggleSwitch.vue_vue_type_script_setup_true_lang-00f2580e.js} +1 -1
  109. flowfile/web/static/assets/{UnavailableFields-5edd5322.css → UnavailableFields-394a1f78.css} +14 -14
  110. flowfile/web/static/assets/{UnavailableFields-a03f512c.js → UnavailableFields-b72a2c72.js} +4 -4
  111. flowfile/web/static/assets/{Union-bfe9b996.js → Union-1e44f263.js} +8 -6
  112. flowfile/web/static/assets/{Union-af6c3d9b.css → Union-d6a8d7d5.css} +7 -7
  113. flowfile/web/static/assets/Unique-2b705521.css +3 -0
  114. flowfile/web/static/assets/{Unique-5d023a27.js → Unique-a3bc6d0a.js} +13 -10
  115. flowfile/web/static/assets/{Unpivot-1e422df3.css → Unpivot-b6ad6427.css} +7 -7
  116. flowfile/web/static/assets/{Unpivot-91cc5354.js → Unpivot-e27935fc.js} +11 -9
  117. flowfile/web/static/assets/{UnpivotValidation-7ee2de44.js → UnpivotValidation-72497680.js} +3 -3
  118. flowfile/web/static/assets/UnpivotValidation-d5ca3b7b.css +13 -0
  119. flowfile/web/static/assets/{VueGraphicWalker-ed5ab88b.css → VueGraphicWalker-430f0b86.css} +1 -1
  120. flowfile/web/static/assets/{VueGraphicWalker-e51b9924.js → VueGraphicWalker-d9ab70a3.js} +4 -4
  121. flowfile/web/static/assets/{api-cf1221f0.js → api-a2102880.js} +1 -1
  122. flowfile/web/static/assets/{api-c1bad5ca.js → api-f75042b0.js} +1 -1
  123. flowfile/web/static/assets/{dropDown-35135ba8.css → dropDown-1d6acbd9.css} +41 -41
  124. flowfile/web/static/assets/{dropDown-614b998d.js → dropDown-2798a109.js} +3 -3
  125. flowfile/web/static/assets/{fullEditor-f7971590.js → fullEditor-cf7d7d93.js} +11 -10
  126. flowfile/web/static/assets/{fullEditor-178376bb.css → fullEditor-fe9f7e18.css} +77 -65
  127. flowfile/web/static/assets/{genericNodeSettings-4fe5f36b.js → genericNodeSettings-14eac1c3.js} +5 -5
  128. flowfile/web/static/assets/{genericNodeSettings-924759c7.css → genericNodeSettings-3b2507ea.css} +10 -10
  129. flowfile/web/static/assets/{index-5429bbf8.js → index-387a6f18.js} +41806 -40958
  130. flowfile/web/static/assets/index-6b367bb5.js +38 -0
  131. flowfile/web/static/assets/{index-50508d4d.css → index-e96ab018.css} +2184 -569
  132. flowfile/web/static/assets/index-f0a6e5a5.js +2696 -0
  133. flowfile/web/static/assets/node.types-2c15bb7e.js +82 -0
  134. flowfile/web/static/assets/nodeInput-ed2ae8d7.js +2 -0
  135. flowfile/web/static/assets/{outputCsv-076b85ab.js → outputCsv-3c1757e8.js} +3 -3
  136. flowfile/web/static/assets/outputCsv-b9a072af.css +2499 -0
  137. flowfile/web/static/assets/{outputExcel-0fd17dbe.js → outputExcel-686e1f48.js} +3 -3
  138. flowfile/web/static/assets/{outputExcel-b41305c0.css → outputExcel-f5d272b2.css} +26 -26
  139. flowfile/web/static/assets/outputParquet-54597c3c.css +4 -0
  140. flowfile/web/static/assets/{outputParquet-b61e0847.js → outputParquet-df28faa7.js} +4 -4
  141. flowfile/web/static/assets/{readCsv-c767cb37.css → readCsv-3bfac4c3.css} +15 -15
  142. flowfile/web/static/assets/{readCsv-a8bb8b61.js → readCsv-e37eee21.js} +3 -3
  143. flowfile/web/static/assets/{readExcel-806d2826.css → readExcel-3db6b763.css} +13 -13
  144. flowfile/web/static/assets/{readExcel-67b4aee0.js → readExcel-a13f14bb.js} +5 -5
  145. flowfile/web/static/assets/{readParquet-92ce1dbc.js → readParquet-344cf746.js} +3 -3
  146. flowfile/web/static/assets/{readParquet-48c81530.css → readParquet-c5244ad5.css} +4 -4
  147. flowfile/web/static/assets/secrets.api-ae198c5c.js +65 -0
  148. flowfile/web/static/assets/{selectDynamic-92e25ee3.js → selectDynamic-6b4b0767.js} +5 -5
  149. flowfile/web/static/assets/{selectDynamic-aa913ff4.css → selectDynamic-f2fb394f.css} +21 -20
  150. flowfile/web/static/assets/{vue-codemirror.esm-41b0e0d7.js → vue-codemirror.esm-31ba0e0b.js} +31 -640
  151. flowfile/web/static/assets/{vue-content-loader.es-2c8e608f.js → vue-content-loader.es-4469c8ff.js} +1 -1
  152. flowfile/web/static/index.html +2 -2
  153. {flowfile-0.5.1.dist-info → flowfile-0.5.4.dist-info}/METADATA +3 -4
  154. flowfile-0.5.4.dist-info/RECORD +407 -0
  155. flowfile_core/__init__.py +13 -6
  156. flowfile_core/auth/jwt.py +51 -16
  157. flowfile_core/auth/models.py +32 -7
  158. flowfile_core/auth/password.py +89 -0
  159. flowfile_core/auth/secrets.py +64 -19
  160. flowfile_core/configs/__init__.py +9 -7
  161. flowfile_core/configs/flow_logger.py +15 -14
  162. flowfile_core/configs/node_store/__init__.py +72 -4
  163. flowfile_core/configs/node_store/nodes.py +155 -172
  164. flowfile_core/configs/node_store/user_defined_node_registry.py +108 -27
  165. flowfile_core/configs/settings.py +28 -15
  166. flowfile_core/database/connection.py +7 -6
  167. flowfile_core/database/init_db.py +96 -2
  168. flowfile_core/database/models.py +3 -1
  169. flowfile_core/fileExplorer/__init__.py +17 -0
  170. flowfile_core/fileExplorer/funcs.py +145 -57
  171. flowfile_core/fileExplorer/utils.py +10 -11
  172. flowfile_core/flowfile/_extensions/real_time_interface.py +10 -8
  173. flowfile_core/flowfile/analytics/analytics_processor.py +26 -24
  174. flowfile_core/flowfile/analytics/graphic_walker.py +11 -12
  175. flowfile_core/flowfile/analytics/utils.py +1 -1
  176. flowfile_core/flowfile/code_generator/__init__.py +11 -0
  177. flowfile_core/flowfile/code_generator/code_generator.py +706 -247
  178. flowfile_core/flowfile/connection_manager/_connection_manager.py +6 -5
  179. flowfile_core/flowfile/connection_manager/models.py +1 -1
  180. flowfile_core/flowfile/database_connection_manager/db_connections.py +60 -44
  181. flowfile_core/flowfile/database_connection_manager/models.py +1 -1
  182. flowfile_core/flowfile/extensions.py +17 -12
  183. flowfile_core/flowfile/flow_data_engine/cloud_storage_reader.py +34 -32
  184. flowfile_core/flowfile/flow_data_engine/create/funcs.py +115 -83
  185. flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +493 -423
  186. flowfile_core/flowfile/flow_data_engine/flow_file_column/interface.py +2 -2
  187. flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +92 -52
  188. flowfile_core/flowfile/flow_data_engine/flow_file_column/polars_type.py +12 -11
  189. flowfile_core/flowfile/flow_data_engine/flow_file_column/type_registry.py +6 -6
  190. flowfile_core/flowfile/flow_data_engine/flow_file_column/utils.py +26 -30
  191. flowfile_core/flowfile/flow_data_engine/fuzzy_matching/prepare_for_fuzzy_match.py +31 -20
  192. flowfile_core/flowfile/flow_data_engine/join/__init__.py +1 -1
  193. flowfile_core/flowfile/flow_data_engine/join/utils.py +11 -9
  194. flowfile_core/flowfile/flow_data_engine/join/verify_integrity.py +14 -15
  195. flowfile_core/flowfile/flow_data_engine/pivot_table.py +5 -7
  196. flowfile_core/flowfile/flow_data_engine/polars_code_parser.py +95 -82
  197. flowfile_core/flowfile/flow_data_engine/read_excel_tables.py +66 -65
  198. flowfile_core/flowfile/flow_data_engine/sample_data.py +27 -21
  199. flowfile_core/flowfile/flow_data_engine/subprocess_operations/__init__.py +1 -1
  200. flowfile_core/flowfile/flow_data_engine/subprocess_operations/models.py +13 -11
  201. flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +190 -127
  202. flowfile_core/flowfile/flow_data_engine/threaded_processes.py +8 -8
  203. flowfile_core/flowfile/flow_data_engine/utils.py +99 -67
  204. flowfile_core/flowfile/flow_graph.py +920 -571
  205. flowfile_core/flowfile/flow_graph_utils.py +31 -49
  206. flowfile_core/flowfile/flow_node/flow_node.py +379 -258
  207. flowfile_core/flowfile/flow_node/models.py +53 -41
  208. flowfile_core/flowfile/flow_node/schema_callback.py +14 -19
  209. flowfile_core/flowfile/graph_tree/graph_tree.py +41 -41
  210. flowfile_core/flowfile/handler.py +80 -30
  211. flowfile_core/flowfile/manage/compatibility_enhancements.py +209 -126
  212. flowfile_core/flowfile/manage/io_flowfile.py +54 -57
  213. flowfile_core/flowfile/node_designer/__init__.py +19 -13
  214. flowfile_core/flowfile/node_designer/_type_registry.py +34 -37
  215. flowfile_core/flowfile/node_designer/custom_node.py +162 -36
  216. flowfile_core/flowfile/node_designer/ui_components.py +278 -34
  217. flowfile_core/flowfile/schema_callbacks.py +71 -51
  218. flowfile_core/flowfile/setting_generator/__init__.py +0 -1
  219. flowfile_core/flowfile/setting_generator/setting_generator.py +6 -5
  220. flowfile_core/flowfile/setting_generator/settings.py +64 -53
  221. flowfile_core/flowfile/sources/external_sources/base_class.py +12 -10
  222. flowfile_core/flowfile/sources/external_sources/custom_external_sources/external_source.py +27 -17
  223. flowfile_core/flowfile/sources/external_sources/custom_external_sources/sample_users.py +9 -9
  224. flowfile_core/flowfile/sources/external_sources/factory.py +0 -1
  225. flowfile_core/flowfile/sources/external_sources/sql_source/models.py +45 -31
  226. flowfile_core/flowfile/sources/external_sources/sql_source/sql_source.py +198 -73
  227. flowfile_core/flowfile/sources/external_sources/sql_source/utils.py +250 -196
  228. flowfile_core/flowfile/util/calculate_layout.py +9 -13
  229. flowfile_core/flowfile/util/execution_orderer.py +25 -17
  230. flowfile_core/flowfile/util/node_skipper.py +4 -4
  231. flowfile_core/flowfile/utils.py +19 -21
  232. flowfile_core/main.py +26 -19
  233. flowfile_core/routes/auth.py +284 -11
  234. flowfile_core/routes/cloud_connections.py +25 -25
  235. flowfile_core/routes/logs.py +21 -29
  236. flowfile_core/routes/public.py +46 -4
  237. flowfile_core/routes/routes.py +70 -34
  238. flowfile_core/routes/secrets.py +25 -27
  239. flowfile_core/routes/user_defined_components.py +483 -4
  240. flowfile_core/run_lock.py +0 -1
  241. flowfile_core/schemas/__init__.py +4 -6
  242. flowfile_core/schemas/analysis_schemas/graphic_walker_schemas.py +55 -55
  243. flowfile_core/schemas/cloud_storage_schemas.py +96 -66
  244. flowfile_core/schemas/input_schema.py +231 -144
  245. flowfile_core/schemas/output_model.py +49 -34
  246. flowfile_core/schemas/schemas.py +116 -89
  247. flowfile_core/schemas/transform_schema.py +518 -263
  248. flowfile_core/schemas/yaml_types.py +21 -7
  249. flowfile_core/secret_manager/secret_manager.py +123 -18
  250. flowfile_core/types.py +29 -9
  251. flowfile_core/utils/arrow_reader.py +7 -6
  252. flowfile_core/utils/excel_file_manager.py +3 -3
  253. flowfile_core/utils/fileManager.py +7 -7
  254. flowfile_core/utils/fl_executor.py +8 -10
  255. flowfile_core/utils/utils.py +4 -4
  256. flowfile_core/utils/validate_setup.py +5 -4
  257. flowfile_frame/__init__.py +117 -51
  258. flowfile_frame/adapters.py +2 -9
  259. flowfile_frame/adding_expr.py +73 -32
  260. flowfile_frame/cloud_storage/frame_helpers.py +27 -23
  261. flowfile_frame/cloud_storage/secret_manager.py +12 -26
  262. flowfile_frame/config.py +2 -5
  263. flowfile_frame/database/__init__.py +36 -0
  264. flowfile_frame/database/connection_manager.py +205 -0
  265. flowfile_frame/database/frame_helpers.py +249 -0
  266. flowfile_frame/expr.py +311 -218
  267. flowfile_frame/expr.pyi +160 -159
  268. flowfile_frame/expr_name.py +23 -23
  269. flowfile_frame/flow_frame.py +571 -476
  270. flowfile_frame/flow_frame.pyi +123 -104
  271. flowfile_frame/flow_frame_methods.py +227 -246
  272. flowfile_frame/group_frame.py +50 -20
  273. flowfile_frame/join.py +2 -2
  274. flowfile_frame/lazy.py +129 -87
  275. flowfile_frame/lazy_methods.py +83 -30
  276. flowfile_frame/list_name_space.py +55 -50
  277. flowfile_frame/selectors.py +148 -68
  278. flowfile_frame/series.py +9 -7
  279. flowfile_frame/utils.py +19 -21
  280. flowfile_worker/__init__.py +12 -7
  281. flowfile_worker/configs.py +41 -33
  282. flowfile_worker/create/__init__.py +14 -9
  283. flowfile_worker/create/funcs.py +114 -77
  284. flowfile_worker/create/models.py +46 -43
  285. flowfile_worker/create/pl_types.py +14 -15
  286. flowfile_worker/create/read_excel_tables.py +34 -41
  287. flowfile_worker/create/utils.py +22 -19
  288. flowfile_worker/external_sources/s3_source/main.py +18 -51
  289. flowfile_worker/external_sources/s3_source/models.py +34 -27
  290. flowfile_worker/external_sources/sql_source/main.py +8 -5
  291. flowfile_worker/external_sources/sql_source/models.py +13 -9
  292. flowfile_worker/flow_logger.py +10 -8
  293. flowfile_worker/funcs.py +214 -155
  294. flowfile_worker/main.py +11 -17
  295. flowfile_worker/models.py +35 -28
  296. flowfile_worker/process_manager.py +2 -3
  297. flowfile_worker/routes.py +121 -90
  298. flowfile_worker/secrets.py +114 -21
  299. flowfile_worker/spawner.py +89 -54
  300. flowfile_worker/utils.py +3 -2
  301. shared/__init__.py +2 -7
  302. shared/storage_config.py +25 -13
  303. test_utils/postgres/commands.py +3 -2
  304. test_utils/postgres/fixtures.py +9 -9
  305. test_utils/s3/commands.py +1 -1
  306. test_utils/s3/data_generator.py +3 -4
  307. test_utils/s3/demo_data_generator.py +4 -7
  308. test_utils/s3/fixtures.py +7 -5
  309. tools/migrate/__init__.py +1 -1
  310. tools/migrate/__main__.py +16 -29
  311. tools/migrate/legacy_schemas.py +251 -190
  312. tools/migrate/migrate.py +193 -181
  313. tools/migrate/tests/conftest.py +1 -3
  314. tools/migrate/tests/test_migrate.py +36 -41
  315. tools/migrate/tests/test_migration_e2e.py +28 -29
  316. tools/migrate/tests/test_node_migrations.py +50 -20
  317. flowfile/web/static/assets/CloudConnectionManager-2dfdce2f.css +0 -86
  318. flowfile/web/static/assets/ContextMenu-23e909da.js +0 -41
  319. flowfile/web/static/assets/ContextMenu-4c74eef1.css +0 -26
  320. flowfile/web/static/assets/ContextMenu-63cfa99b.css +0 -26
  321. flowfile/web/static/assets/ContextMenu-70ae0c79.js +0 -41
  322. flowfile/web/static/assets/ContextMenu-c13f91d0.css +0 -26
  323. flowfile/web/static/assets/ContextMenu-f149cf7c.js +0 -41
  324. flowfile/web/static/assets/CustomNode-74a37f74.css +0 -32
  325. flowfile/web/static/assets/DatabaseManager-30fa27e5.css +0 -64
  326. flowfile/web/static/assets/Filter-9b6d08db.js +0 -164
  327. flowfile/web/static/assets/Filter-f62091b3.css +0 -20
  328. flowfile/web/static/assets/GroupBy-b9505323.css +0 -51
  329. flowfile/web/static/assets/ManualInput-3246a08d.css +0 -96
  330. flowfile/web/static/assets/Output-283fe388.css +0 -37
  331. flowfile/web/static/assets/PivotValidation-891ddfb0.css +0 -13
  332. flowfile/web/static/assets/PivotValidation-c46cd420.css +0 -13
  333. flowfile/web/static/assets/SQLQueryComponent-36cef432.css +0 -27
  334. flowfile/web/static/assets/SliderInput-b8fb6a8c.css +0 -4
  335. flowfile/web/static/assets/Sort-3643d625.css +0 -51
  336. flowfile/web/static/assets/Unique-f9fb0809.css +0 -51
  337. flowfile/web/static/assets/UnpivotValidation-0d240eeb.css +0 -13
  338. flowfile/web/static/assets/nodeInput-5d0d6b79.js +0 -41
  339. flowfile/web/static/assets/outputCsv-9cc59e0b.css +0 -2499
  340. flowfile/web/static/assets/outputParquet-cf8cf3f2.css +0 -4
  341. flowfile/web/static/assets/secretApi-68435402.js +0 -46
  342. flowfile/web/static/assets/vue-codemirror-bccfde04.css +0 -32
  343. flowfile-0.5.1.dist-info/RECORD +0 -388
  344. {flowfile-0.5.1.dist-info → flowfile-0.5.4.dist-info}/WHEEL +0 -0
  345. {flowfile-0.5.1.dist-info → flowfile-0.5.4.dist-info}/entry_points.txt +0 -0
  346. {flowfile-0.5.1.dist-info → flowfile-0.5.4.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,10 @@
1
- from typing import Dict, List, Any
1
+ from typing import Any
2
+
2
3
  from flowfile_core.flowfile.connection_manager.models import Connection
3
4
 
4
5
 
5
6
  class ConnectionManager:
6
- connections: Dict[str, Dict[str, Connection]]
7
+ connections: dict[str, dict[str, Connection]]
7
8
 
8
9
  def add_connection(self, connection_group: str, connection_name: str, connection: Connection):
9
10
  existing_connections_in_group = self.connections.get(connection_group)
@@ -34,15 +35,15 @@ class ConnectionManager:
34
35
  self.raise_if_connection_does_not_exist(connection_group, connection_name)
35
36
  self.connections[connection_group][connection_name] = connection
36
37
 
37
- def insert_settings_raw(self, connection_group: str, connection_name: str, settings: Dict[str, Any]):
38
+ def insert_settings_raw(self, connection_group: str, connection_name: str, settings: dict[str, Any]):
38
39
  connection = Connection(group=connection_group, name=connection_name, config_setting=settings)
39
40
  self.add_connection(connection_group, connection_name, connection)
40
41
 
41
- def connection_groups(self) -> List[str]:
42
+ def connection_groups(self) -> list[str]:
42
43
  return list(self.connections.keys())
43
44
 
44
45
  def get_available_connections_in_group(self, group_name: str):
45
46
  connection_group = self.connections.get(group_name)
46
47
  if connection_group is None:
47
48
  return []
48
- return list(connection_group.keys())
49
+ return list(connection_group.keys())
@@ -1,5 +1,5 @@
1
- from typing import Any
2
1
  from dataclasses import dataclass
2
+ from typing import Any
3
3
 
4
4
 
5
5
  @dataclass
@@ -1,10 +1,12 @@
1
- from flowfile_core.schemas.input_schema import FullDatabaseConnection, FullDatabaseConnectionInterface
2
- from flowfile_core.schemas.cloud_storage_schemas import FullCloudStorageConnection, FullCloudStorageConnectionInterface
3
1
  from sqlalchemy.orm import Session
4
- from flowfile_core.database.models import (DatabaseConnection as DBConnectionModel, Secret,
5
- CloudStorageConnection as DBCloudStorageConnection)
6
- from flowfile_core.secret_manager.secret_manager import store_secret, SecretInput, decrypt_secret
2
+
7
3
  from flowfile_core.database.connection import get_db_context
4
+ from flowfile_core.database.models import CloudStorageConnection as DBCloudStorageConnection
5
+ from flowfile_core.database.models import DatabaseConnection as DBConnectionModel
6
+ from flowfile_core.database.models import Secret
7
+ from flowfile_core.schemas.cloud_storage_schemas import FullCloudStorageConnection, FullCloudStorageConnectionInterface
8
+ from flowfile_core.schemas.input_schema import FullDatabaseConnection, FullDatabaseConnectionInterface
9
+ from flowfile_core.secret_manager.secret_manager import SecretInput, decrypt_secret, store_secret
8
10
 
9
11
 
10
12
  def store_database_connection(db: Session, connection: FullDatabaseConnection, user_id: int) -> DBConnectionModel:
@@ -32,7 +34,7 @@ def store_database_connection(db: Session, connection: FullDatabaseConnection, u
32
34
  username=connection.username,
33
35
  password_id=password_id,
34
36
  ssl_enabled=connection.ssl_enabled,
35
- user_id=user_id
37
+ user_id=user_id,
36
38
  )
37
39
 
38
40
  # Add and commit the new connection to the database
@@ -47,10 +49,11 @@ def get_database_connection(db: Session, connection_name: str, user_id: int) ->
47
49
  """
48
50
  Get a database connection by its name and user ID.
49
51
  """
50
- db_connection = db.query(DBConnectionModel).filter(
51
- DBConnectionModel.connection_name == connection_name,
52
- DBConnectionModel.user_id == user_id
53
- ).first()
52
+ db_connection = (
53
+ db.query(DBConnectionModel)
54
+ .filter(DBConnectionModel.connection_name == connection_name, DBConnectionModel.user_id == user_id)
55
+ .first()
56
+ )
54
57
 
55
58
  return db_connection
56
59
 
@@ -59,10 +62,13 @@ def get_cloud_connection(db: Session, connection_name: str, user_id: int) -> DBC
59
62
  """
60
63
  Get a cloud storage connection by its name and user ID.
61
64
  """
62
- db_connection = db.query(DBCloudStorageConnection).filter(
63
- DBCloudStorageConnection.connection_name == connection_name,
64
- DBCloudStorageConnection.user_id == user_id
65
- ).first()
65
+ db_connection = (
66
+ db.query(DBCloudStorageConnection)
67
+ .filter(
68
+ DBCloudStorageConnection.connection_name == connection_name, DBCloudStorageConnection.user_id == user_id
69
+ )
70
+ .first()
71
+ )
66
72
 
67
73
  return db_connection
68
74
 
@@ -87,7 +93,7 @@ def get_database_connection_schema(db: Session, connection_name: str, user_id: i
87
93
  database_type=db_connection.database_type,
88
94
  username=db_connection.username,
89
95
  password=password_secret.encrypted_value,
90
- ssl_enabled=db_connection.ssl_enabled
96
+ ssl_enabled=db_connection.ssl_enabled,
91
97
  )
92
98
 
93
99
  return None
@@ -116,10 +122,11 @@ def delete_database_connection(db: Session, connection_name: str, user_id: int)
116
122
  """
117
123
  Delete a database connection by its name and user ID.
118
124
  """
119
- db_connection = db.query(DBConnectionModel).filter(
120
- DBConnectionModel.connection_name == connection_name,
121
- DBConnectionModel.user_id == user_id
122
- ).first()
125
+ db_connection = (
126
+ db.query(DBConnectionModel)
127
+ .filter(DBConnectionModel.connection_name == connection_name, DBConnectionModel.user_id == user_id)
128
+ .first()
129
+ )
123
130
 
124
131
  if db_connection:
125
132
  db.delete(db_connection)
@@ -131,7 +138,8 @@ def delete_database_connection(db: Session, connection_name: str, user_id: int)
131
138
 
132
139
 
133
140
  def database_connection_interface_from_db_connection(
134
- db_connection: DBConnectionModel) -> FullDatabaseConnectionInterface:
141
+ db_connection: DBConnectionModel,
142
+ ) -> FullDatabaseConnectionInterface:
135
143
  """
136
144
  Convert a database connection from the database model to the interface model.
137
145
  """
@@ -142,7 +150,7 @@ def database_connection_interface_from_db_connection(
142
150
  host=db_connection.host,
143
151
  port=db_connection.port,
144
152
  database=db_connection.database,
145
- ssl_enabled=db_connection.ssl_enabled
153
+ ssl_enabled=db_connection.ssl_enabled,
146
154
  )
147
155
 
148
156
 
@@ -151,9 +159,7 @@ def get_all_database_connections_interface(db: Session, user_id: int) -> list[Fu
151
159
  Get all database connections for a user.
152
160
  """
153
161
  # Get the raw query results
154
- query_results = db.query(DBConnectionModel).filter(
155
- DBConnectionModel.user_id == user_id
156
- ).all()
162
+ query_results = db.query(DBConnectionModel).filter(DBConnectionModel.user_id == user_id).all()
157
163
 
158
164
  # Convert with explicit type assertion
159
165
  result = []
@@ -168,7 +174,9 @@ def get_all_database_connections_interface(db: Session, user_id: int) -> list[Fu
168
174
  return result
169
175
 
170
176
 
171
- def store_cloud_connection(db: Session, connection: FullCloudStorageConnection, user_id: int) -> DBCloudStorageConnection:
177
+ def store_cloud_connection(
178
+ db: Session, connection: FullCloudStorageConnection, user_id: int
179
+ ) -> DBCloudStorageConnection:
172
180
  """
173
181
  Placeholder function to store a cloud database connection.
174
182
  This function should be implemented based on specific cloud provider requirements.
@@ -180,20 +188,29 @@ def store_cloud_connection(db: Session, connection: FullCloudStorageConnection,
180
188
  f" Please use a unique connection name or delete the existing connection first."
181
189
  )
182
190
  if connection.aws_secret_access_key is not None:
183
- aws_secret_access_key_ref_id = store_secret(db,
184
- SecretInput(name=connection.connection_name + "_aws_secret_access_key",
185
- value=connection.aws_secret_access_key), user_id).id
191
+ aws_secret_access_key_ref_id = store_secret(
192
+ db,
193
+ SecretInput(
194
+ name=connection.connection_name + "_aws_secret_access_key", value=connection.aws_secret_access_key
195
+ ),
196
+ user_id,
197
+ ).id
186
198
  else:
187
199
  aws_secret_access_key_ref_id = None
188
200
  if connection.azure_client_secret is not None:
189
- azure_client_secret_ref_id = store_secret(db,
190
- SecretInput(name=connection.connection_name + "azure_client_secret",
191
- value=connection.azure_client_secret), user_id).id
201
+ azure_client_secret_ref_id = store_secret(
202
+ db,
203
+ SecretInput(name=connection.connection_name + "azure_client_secret", value=connection.azure_client_secret),
204
+ user_id,
205
+ ).id
192
206
  else:
193
207
  azure_client_secret_ref_id = None
194
208
  if connection.azure_account_key is not None:
195
- azure_account_key_ref_id = store_secret(db, SecretInput(name=connection.connection_name + "azure_account_key",
196
- value=connection.azure_account_key), user_id).id
209
+ azure_account_key_ref_id = store_secret(
210
+ db,
211
+ SecretInput(name=connection.connection_name + "azure_account_key", value=connection.azure_account_key),
212
+ user_id,
213
+ ).id
197
214
  else:
198
215
  azure_account_key_ref_id = None
199
216
 
@@ -202,24 +219,21 @@ def store_cloud_connection(db: Session, connection: FullCloudStorageConnection,
202
219
  storage_type=connection.storage_type,
203
220
  auth_method=connection.auth_method,
204
221
  user_id=user_id,
205
-
206
- # AWS S3 fields
222
+ # AWS S3 fields
207
223
  aws_region=connection.aws_region,
208
224
  aws_access_key_id=connection.aws_access_key_id,
209
225
  aws_role_arn=connection.aws_role_arn,
210
226
  aws_secret_access_key_id=aws_secret_access_key_ref_id,
211
227
  aws_allow_unsafe_html=connection.aws_allow_unsafe_html,
212
-
213
228
  # Azure ADLS fields
214
229
  azure_account_name=connection.azure_account_name,
215
230
  azure_tenant_id=connection.azure_tenant_id,
216
231
  azure_client_id=connection.azure_client_id,
217
232
  azure_account_key_id=azure_account_key_ref_id,
218
233
  azure_client_secret_id=azure_client_secret_ref_id,
219
-
220
234
  # Common fields
221
235
  endpoint_url=connection.endpoint_url,
222
- verify_ssl=connection.verify_ssl
236
+ verify_ssl=connection.verify_ssl,
223
237
  )
224
238
  db.add(db_cloud_connection)
225
239
  db.commit()
@@ -228,7 +242,8 @@ def store_cloud_connection(db: Session, connection: FullCloudStorageConnection,
228
242
 
229
243
 
230
244
  def get_full_cloud_storage_interface_from_db(
231
- db_cloud_connection: DBCloudStorageConnection) -> FullCloudStorageConnectionInterface:
245
+ db_cloud_connection: DBCloudStorageConnection,
246
+ ) -> FullCloudStorageConnectionInterface:
232
247
  """
233
248
  Convert a cloud storage connection from the database model to the interface model.
234
249
  """
@@ -244,7 +259,7 @@ def get_full_cloud_storage_interface_from_db(
244
259
  azure_tenant_id=db_cloud_connection.azure_tenant_id,
245
260
  azure_client_id=db_cloud_connection.azure_client_id,
246
261
  endpoint_url=db_cloud_connection.endpoint_url,
247
- verify_ssl=db_cloud_connection.verify_ssl
262
+ verify_ssl=db_cloud_connection.verify_ssl,
248
263
  )
249
264
 
250
265
 
@@ -291,12 +306,13 @@ def get_cloud_connection_schema(db: Session, connection_name: str, user_id: int)
291
306
  azure_client_id=db_connection.azure_client_id,
292
307
  azure_client_secret=azure_client_secret,
293
308
  endpoint_url=db_connection.endpoint_url,
294
- verify_ssl=db_connection.verify_ssl
309
+ verify_ssl=db_connection.verify_ssl,
295
310
  )
296
311
 
297
312
 
298
313
  def cloud_connection_interface_from_db_connection(
299
- db_connection: DBCloudStorageConnection) -> FullCloudStorageConnectionInterface:
314
+ db_connection: DBCloudStorageConnection,
315
+ ) -> FullCloudStorageConnectionInterface:
300
316
  """
301
317
  Converts a DBCloudStorageConnection model to a FullCloudStorageConnectionInterface model,
302
318
  which safely exposes non-sensitive data.
@@ -313,7 +329,7 @@ def cloud_connection_interface_from_db_connection(
313
329
  azure_tenant_id=db_connection.azure_tenant_id,
314
330
  azure_client_id=db_connection.azure_client_id,
315
331
  endpoint_url=db_connection.endpoint_url,
316
- verify_ssl=db_connection.verify_ssl
332
+ verify_ssl=db_connection.verify_ssl,
317
333
  )
318
334
 
319
335
 
@@ -339,7 +355,7 @@ def delete_cloud_connection(db: Session, connection_name: str, user_id: int) ->
339
355
  db_connection.aws_session_token_id,
340
356
  db_connection.azure_account_key_id,
341
357
  db_connection.azure_client_secret_id,
342
- db_connection.azure_sas_token_id
358
+ db_connection.azure_sas_token_id,
343
359
  ]
344
360
  # Filter out None values
345
361
  secret_ids_to_delete = [id for id in secret_ids_to_delete if id is not None]
@@ -12,4 +12,4 @@ class DatabaseConnectionOutput(BaseModel):
12
12
  password: str | None = None # Password can be None if not stored in the database
13
13
  ssl_mode: str | None = None # SSL mode can be None if not applicable
14
14
  created_at: str
15
- updated_at: str
15
+ updated_at: str
@@ -1,10 +1,11 @@
1
+ from functools import lru_cache
2
+
3
+ import polars as pl
4
+
1
5
  from flowfile_core.flowfile._extensions.real_time_interface import get_realtime_func_results
2
6
  from flowfile_core.flowfile.flow_node.flow_node import FlowNode
3
7
  from flowfile_core.schemas.output_model import InstantFuncResult
4
8
  from flowfile_core.utils.arrow_reader import read_top_n
5
- import pyarrow as pa
6
- import polars as pl
7
- from functools import lru_cache
8
9
 
9
10
 
10
11
  @lru_cache(maxsize=16)
@@ -14,23 +15,27 @@ def get_first_row(arrow_path: str) -> pl.DataFrame:
14
15
 
15
16
  def get_instant_func_results(node_step: FlowNode, func_string: str) -> InstantFuncResult:
16
17
  if len(node_step.main_input) == 0:
17
- return InstantFuncResult(result='No input data connected, so cannot evaluate the result', success=None)
18
+ return InstantFuncResult(result="No input data connected, so cannot evaluate the result", success=None)
18
19
  node_input = node_step.main_input[0]
19
20
  try:
20
- if node_input.node_stats.has_run_with_current_setup and node_input.is_setup and node_input.results.example_data_path:
21
+ if (
22
+ node_input.node_stats.has_run_with_current_setup
23
+ and node_input.is_setup
24
+ and node_input.results.example_data_path
25
+ ):
21
26
  df = get_first_row(node_input.results.example_data_path)
22
27
  else:
23
28
  df = node_input.get_predicted_resulting_data().data_frame.collect()
24
29
  except:
25
- return InstantFuncResult(result='Could not get data from previous step', success=None)
30
+ return InstantFuncResult(result="Could not get data from previous step", success=None)
26
31
  try:
27
- real_time_result = get_realtime_func_results(df=df,
28
- func_string=func_string)
29
- if node_step.name == 'filter' and not real_time_result.is_filterable_result():
30
- return InstantFuncResult(result='Result is not filterable,'
31
- ' make sure the function results in a true or false output', success=False)
32
+ real_time_result = get_realtime_func_results(df=df, func_string=func_string)
33
+ if node_step.name == "filter" and not real_time_result.is_filterable_result():
34
+ return InstantFuncResult(
35
+ result="Result is not filterable," " make sure the function results in a true or false output",
36
+ success=False,
37
+ )
32
38
  r = InstantFuncResult(result=real_time_result.readable_result, success=real_time_result.success)
33
39
  except Exception as e:
34
40
  r = InstantFuncResult(result=str(e), success=False)
35
41
  return r
36
-
@@ -1,12 +1,15 @@
1
+ from collections.abc import Callable
2
+ from typing import Any, Literal
3
+
1
4
  import boto3
2
5
  from botocore.exceptions import ClientError
3
- from typing import Optional, Dict, Any, Callable, Literal
4
6
 
5
7
  from flowfile_core.schemas.cloud_storage_schemas import FullCloudStorageConnection
6
8
 
7
9
 
8
- def create_storage_options_from_boto_credentials(profile_name: Optional[str],
9
- region_name: Optional[str] = None) -> Dict[str, Any]:
10
+ def create_storage_options_from_boto_credentials(
11
+ profile_name: str | None, region_name: str | None = None
12
+ ) -> dict[str, Any]:
10
13
  """
11
14
  Create a storage options dictionary from AWS credentials using a boto3 profile.
12
15
  This is the most robust way to handle profile-based authentication as it
@@ -45,7 +48,7 @@ class CloudStorageReader:
45
48
  """Helper class to handle different cloud storage authentication methods and read operations."""
46
49
 
47
50
  @staticmethod
48
- def get_storage_options(connection: FullCloudStorageConnection) -> Dict[str, Any]:
51
+ def get_storage_options(connection: FullCloudStorageConnection) -> dict[str, Any]:
49
52
  """
50
53
  Build storage options dict based on the connection type and auth method.
51
54
 
@@ -65,13 +68,12 @@ class CloudStorageReader:
65
68
  raise ValueError(f"Unsupported storage type: {connection.storage_type}")
66
69
 
67
70
  @staticmethod
68
- def _get_s3_storage_options(connection: 'FullCloudStorageConnection') -> Dict[str, Any]:
71
+ def _get_s3_storage_options(connection: "FullCloudStorageConnection") -> dict[str, Any]:
69
72
  """Build S3-specific storage options."""
70
73
  auth_method = connection.auth_method
71
74
  if auth_method == "aws-cli":
72
75
  return create_storage_options_from_boto_credentials(
73
- profile_name=connection.connection_name,
74
- region_name=connection.aws_region
76
+ profile_name=connection.connection_name, region_name=connection.aws_region
75
77
  )
76
78
 
77
79
  storage_options = {}
@@ -81,7 +83,7 @@ class CloudStorageReader:
81
83
  storage_options["endpoint_url"] = connection.endpoint_url
82
84
  if not connection.verify_ssl:
83
85
  storage_options["verify"] = "False"
84
- if connection.aws_allow_unsafe_html: # Note: Polars uses aws_allow_http
86
+ if connection.aws_allow_unsafe_html: # Note: Polars uses aws_allow_http
85
87
  storage_options["aws_allow_http"] = "true"
86
88
 
87
89
  if auth_method == "access_key":
@@ -92,20 +94,20 @@ class CloudStorageReader:
92
94
 
93
95
  elif auth_method == "iam_role":
94
96
  # Correctly implement IAM role assumption using boto3 STS client.
95
- sts_client = boto3.client('sts', region_name=connection.aws_region)
97
+ sts_client = boto3.client("sts", region_name=connection.aws_region)
96
98
  assumed_role_object = sts_client.assume_role(
97
99
  RoleArn=connection.aws_role_arn,
98
- RoleSessionName="PolarsCloudStorageReaderSession" # A descriptive session name
100
+ RoleSessionName="PolarsCloudStorageReaderSession", # A descriptive session name
99
101
  )
100
- credentials = assumed_role_object['Credentials']
101
- storage_options["aws_access_key_id"] = credentials['AccessKeyId']
102
- storage_options["aws_secret_access_key"] = credentials['SecretAccessKey']
103
- storage_options["aws_session_token"] = credentials['SessionToken']
102
+ credentials = assumed_role_object["Credentials"]
103
+ storage_options["aws_access_key_id"] = credentials["AccessKeyId"]
104
+ storage_options["aws_secret_access_key"] = credentials["SecretAccessKey"]
105
+ storage_options["aws_session_token"] = credentials["SessionToken"]
104
106
 
105
107
  return storage_options
106
108
 
107
109
  @staticmethod
108
- def _get_adls_storage_options(connection: 'FullCloudStorageConnection') -> Dict[str, Any]:
110
+ def _get_adls_storage_options(connection: "FullCloudStorageConnection") -> dict[str, Any]:
109
111
  """Build Azure ADLS-specific storage options."""
110
112
  storage_options = {}
111
113
 
@@ -133,14 +135,14 @@ class CloudStorageReader:
133
135
  return storage_options
134
136
 
135
137
  @staticmethod
136
- def _get_gcs_storage_options(connection: 'FullCloudStorageConnection') -> Dict[str, Any]:
138
+ def _get_gcs_storage_options(connection: "FullCloudStorageConnection") -> dict[str, Any]:
137
139
  """Build GCS-specific storage options."""
138
140
  # GCS typically uses service account authentication
139
141
  # Implementation would depend on how credentials are stored
140
142
  return {}
141
143
 
142
144
  @staticmethod
143
- def get_credential_provider(connection: 'FullCloudStorageConnection') -> Optional[Callable]:
145
+ def get_credential_provider(connection: "FullCloudStorageConnection") -> Callable | None:
144
146
  """
145
147
  Get a credential provider function if needed for the authentication method.
146
148
 
@@ -165,7 +167,7 @@ class CloudStorageReader:
165
167
  return None
166
168
 
167
169
 
168
- def get_first_file_from_s3_dir(source: str, storage_options: Dict[str, Any] = None) -> str:
170
+ def get_first_file_from_s3_dir(source: str, storage_options: dict[str, Any] = None) -> str:
169
171
  """
170
172
  Get the first parquet file from an S3 directory path.
171
173
 
@@ -188,7 +190,7 @@ def get_first_file_from_s3_dir(source: str, storage_options: Dict[str, Any] = No
188
190
  ClientError
189
191
  If S3 access fails
190
192
  """
191
- if not source.startswith('s3://'):
193
+ if not source.startswith("s3://"):
192
194
  raise ValueError("Source must be a valid S3 URI starting with 's3://'")
193
195
  bucket_name, prefix = _parse_s3_path(source)
194
196
  file_extension = _get_file_extension(source)
@@ -211,39 +213,39 @@ def _get_file_extension(source: str) -> str:
211
213
 
212
214
  def _parse_s3_path(source: str) -> tuple[str, str]:
213
215
  """Parse S3 URI into bucket name and prefix."""
214
- path_parts = source[5:].split('/', 1) # Remove 's3://'
216
+ path_parts = source[5:].split("/", 1) # Remove 's3://'
215
217
  bucket_name = path_parts[0]
216
- prefix = path_parts[1] if len(path_parts) > 1 else ''
218
+ prefix = path_parts[1] if len(path_parts) > 1 else ""
217
219
  return bucket_name, prefix
218
220
 
219
221
 
220
222
  def _remove_wildcards_from_prefix(prefix: str) -> str:
221
223
  """Remove wildcard patterns from S3 prefix."""
222
- return prefix.split('*')[0]
224
+ return prefix.split("*")[0]
223
225
 
224
226
 
225
- def _create_s3_client(storage_options: Optional[Dict[str, Any]]):
227
+ def _create_s3_client(storage_options: dict[str, Any] | None):
226
228
  """Create boto3 S3 client with optional credentials."""
227
229
  if storage_options is None:
228
- return boto3.client('s3')
230
+ return boto3.client("s3")
229
231
 
230
232
  # Handle both 'aws_region' and 'region_name' keys
231
233
  client_options = storage_options.copy()
232
- if 'aws_region' in client_options:
233
- client_options['region_name'] = client_options.pop('aws_region')
234
+ if "aws_region" in client_options:
235
+ client_options["region_name"] = client_options.pop("aws_region")
234
236
 
235
- return boto3.client('s3', **{k: v for k, v in client_options.items() if k != "aws_allow_http"})
237
+ return boto3.client("s3", **{k: v for k, v in client_options.items() if k != "aws_allow_http"})
236
238
 
237
239
 
238
- def _get_first_file(s3_client, bucket_name: str, base_prefix: str, file_extension: str) -> Dict[Any, Any]:
240
+ def _get_first_file(s3_client, bucket_name: str, base_prefix: str, file_extension: str) -> dict[Any, Any]:
239
241
  """List all parquet files in S3 bucket with given prefix."""
240
242
  try:
241
- paginator = s3_client.get_paginator('list_objects_v2')
243
+ paginator = s3_client.get_paginator("list_objects_v2")
242
244
  pages = paginator.paginate(Bucket=bucket_name, Prefix=base_prefix)
243
245
  for page in pages:
244
- if 'Contents' in page:
245
- for obj in page['Contents']:
246
- if obj['Key'].endswith(f".{file_extension}"):
246
+ if "Contents" in page:
247
+ for obj in page["Contents"]:
248
+ if obj["Key"].endswith(f".{file_extension}"):
247
249
  return obj
248
250
  else:
249
251
  raise ValueError(f"No objects found in s3://{bucket_name}/{base_prefix}")