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,8 +1,21 @@
1
- from typing import TypedDict, List
2
-
1
+ from typing import TypedDict
3
2
 
4
3
  # === Transform Schema YAML Types ===
5
4
 
5
+
6
+ class BasicFilterYaml(TypedDict, total=False):
7
+ field: str
8
+ operator: str
9
+ value: str
10
+ value2: str # For BETWEEN operator
11
+
12
+
13
+ class FilterInputYaml(TypedDict, total=False):
14
+ mode: str # "basic" or "advanced"
15
+ basic_filter: BasicFilterYaml
16
+ advanced_filter: str
17
+
18
+
6
19
  class SelectInputYaml(TypedDict, total=False):
7
20
  old_name: str
8
21
  new_name: str
@@ -11,7 +24,7 @@ class SelectInputYaml(TypedDict, total=False):
11
24
 
12
25
 
13
26
  class JoinInputsYaml(TypedDict):
14
- select: List[SelectInputYaml]
27
+ select: list[SelectInputYaml]
15
28
 
16
29
 
17
30
  class JoinMapYaml(TypedDict):
@@ -20,7 +33,7 @@ class JoinMapYaml(TypedDict):
20
33
 
21
34
 
22
35
  class JoinInputYaml(TypedDict):
23
- join_mapping: List[JoinMapYaml]
36
+ join_mapping: list[JoinMapYaml]
24
37
  left_select: JoinInputsYaml
25
38
  right_select: JoinInputsYaml
26
39
  how: str
@@ -42,7 +55,7 @@ class FuzzyMappingYaml(TypedDict, total=False):
42
55
 
43
56
 
44
57
  class FuzzyMatchInputYaml(TypedDict):
45
- join_mapping: List[FuzzyMappingYaml]
58
+ join_mapping: list[FuzzyMappingYaml]
46
59
  left_select: JoinInputsYaml
47
60
  right_select: JoinInputsYaml
48
61
  how: str
@@ -51,20 +64,21 @@ class FuzzyMatchInputYaml(TypedDict):
51
64
 
52
65
  # === Input Schema YAML Types ===
53
66
 
67
+
54
68
  class OutputSettingsYaml(TypedDict, total=False):
55
69
  name: str
56
70
  directory: str
57
71
  file_type: str
58
72
  write_mode: str
59
73
  abs_file_path: str
60
- fields: List[str]
74
+ fields: list[str]
61
75
  table_settings: dict
62
76
 
63
77
 
64
78
  class NodeSelectYaml(TypedDict):
65
79
  cache_results: bool
66
80
  keep_missing: bool
67
- select_input: List[SelectInputYaml]
81
+ select_input: list[SelectInputYaml]
68
82
  sorted_by: str
69
83
 
70
84
 
@@ -1,34 +1,138 @@
1
+ import base64
1
2
 
2
3
  from cryptography.fernet import Fernet
4
+ from cryptography.hazmat.primitives import hashes
5
+ from cryptography.hazmat.primitives.kdf.hkdf import HKDF
6
+ from fastapi.exceptions import HTTPException
7
+ from pydantic import SecretStr
3
8
  from sqlalchemy import and_
4
9
  from sqlalchemy.orm import Session
10
+
11
+ from flowfile_core.auth.models import SecretInput
12
+ from flowfile_core.auth.secrets import get_master_key
5
13
  from flowfile_core.database import models as db_models
6
14
  from flowfile_core.database.connection import get_db_context
7
- from flowfile_core.auth.secrets import get_master_key
8
- from pydantic import SecretStr
9
- from flowfile_core.auth.models import SecretInput
10
- from fastapi.exceptions import HTTPException
11
15
 
16
+ # Version identifier for key derivation scheme (allows future migrations)
17
+ KEY_DERIVATION_VERSION = b"flowfile-secrets-v1"
18
+
19
+ # Encrypted secret format: $ffsec$1${user_id}${fernet_token}
20
+ # This embeds the user_id so the worker can derive the correct key
21
+ SECRET_FORMAT_PREFIX = "$ffsec$1$"
22
+
23
+
24
+ def derive_user_key(user_id: int) -> bytes:
25
+ """
26
+ Derive a user-specific encryption key from the master key using HKDF.
27
+
28
+ This provides cryptographic isolation between users - each user's secrets
29
+ are encrypted with a unique key derived from the master key.
30
+
31
+ Args:
32
+ user_id: The unique identifier for the user
33
+
34
+ Returns:
35
+ bytes: A 32-byte URL-safe base64-encoded key suitable for Fernet
36
+ """
37
+ master_key = get_master_key().encode()
38
+
39
+ # Use HKDF to derive a user-specific key
40
+ hkdf = HKDF(
41
+ algorithm=hashes.SHA256(),
42
+ length=32, # Fernet requires 32 bytes
43
+ salt=KEY_DERIVATION_VERSION, # Static salt is fine for key derivation
44
+ info=f"user-{user_id}".encode(), # User-specific context
45
+ )
46
+
47
+ # Derive raw key material and encode for Fernet
48
+ derived_key = hkdf.derive(master_key)
49
+ return base64.urlsafe_b64encode(derived_key)
12
50
 
13
- def encrypt_secret(secret_value):
14
- """Encrypt a secret value using the master key."""
51
+
52
+ def _encrypt_with_master_key(secret_value: str) -> str:
53
+ """Legacy encryption using master key directly (for backward compatibility)."""
15
54
  key = get_master_key().encode()
16
55
  f = Fernet(key)
17
56
  return f.encrypt(secret_value.encode()).decode()
18
57
 
19
58
 
20
- def decrypt_secret(encrypted_value) -> SecretStr:
21
- """Decrypt an encrypted value using the master key."""
59
+ def _decrypt_with_master_key(encrypted_value: str) -> SecretStr:
60
+ """Legacy decryption using master key directly (for backward compatibility)."""
22
61
  key = get_master_key().encode()
23
62
  f = Fernet(key)
24
63
  return SecretStr(f.decrypt(encrypted_value.encode()).decode())
25
64
 
26
65
 
27
- def get_encrypted_secret(current_user_id: int, secret_name: str) -> str|None:
66
+ def encrypt_secret(secret_value: str, user_id: int) -> str:
67
+ """
68
+ Encrypt a secret value using a user-specific derived key.
69
+
70
+ The encrypted format embeds the user_id so it can be decrypted
71
+ without knowing the user context (e.g., by the worker service).
72
+
73
+ Format: $ffsec$1${user_id}${fernet_token}
74
+
75
+ Args:
76
+ secret_value: The plaintext secret to encrypt
77
+ user_id: The user ID to derive the encryption key for
78
+
79
+ Returns:
80
+ str: The encrypted value with embedded user_id
81
+ """
82
+ key = derive_user_key(user_id)
83
+ f = Fernet(key)
84
+ fernet_token = f.encrypt(secret_value.encode()).decode()
85
+ return f"{SECRET_FORMAT_PREFIX}{user_id}${fernet_token}"
86
+
87
+
88
+ def decrypt_secret(encrypted_value: str, user_id: int | None = None) -> SecretStr:
89
+ """
90
+ Decrypt an encrypted value.
91
+
92
+ Supports both new format (with embedded user_id) and legacy format.
93
+ - New format: $ffsec$1${user_id}${fernet_token} - user_id extracted automatically
94
+ - Legacy format: raw Fernet token - requires user_id parameter or uses master key
95
+
96
+ Args:
97
+ encrypted_value: The encrypted secret
98
+ user_id: Optional user ID (required for legacy secrets, ignored for new format)
99
+
100
+ Returns:
101
+ SecretStr: The decrypted value wrapped in SecretStr
102
+ """
103
+ # Check for new versioned format with embedded user_id
104
+ if encrypted_value.startswith(SECRET_FORMAT_PREFIX):
105
+ # Parse: $ffsec$1${user_id}${fernet_token}
106
+ remainder = encrypted_value[len(SECRET_FORMAT_PREFIX):]
107
+ parts = remainder.split("$", 1)
108
+ if len(parts) != 2:
109
+ raise ValueError("Invalid encrypted secret format")
110
+
111
+ embedded_user_id = int(parts[0])
112
+ fernet_token = parts[1]
113
+
114
+ key = derive_user_key(embedded_user_id)
115
+ f = Fernet(key)
116
+ return SecretStr(f.decrypt(fernet_token.encode()).decode())
117
+
118
+ # Legacy format - use provided user_id or fall back to master key
119
+ if user_id is not None:
120
+ key = derive_user_key(user_id)
121
+ f = Fernet(key)
122
+ return SecretStr(f.decrypt(encrypted_value.encode()).decode())
123
+
124
+ # Fall back to master key for legacy secrets without user context
125
+ return _decrypt_with_master_key(encrypted_value)
126
+
127
+
128
+ def get_encrypted_secret(current_user_id: int, secret_name: str) -> str | None:
28
129
  with get_db_context() as db:
29
130
  user_id = current_user_id
30
- db_secret = db.query(db_models.Secret).filter(and_(db_models.Secret.user_id == user_id,
31
- db_models.Secret.name == secret_name)).first()
131
+ db_secret = (
132
+ db.query(db_models.Secret)
133
+ .filter(and_(db_models.Secret.user_id == user_id, db_models.Secret.name == secret_name))
134
+ .first()
135
+ )
32
136
  if db_secret:
33
137
  return db_secret.encrypted_value
34
138
  else:
@@ -36,14 +140,14 @@ def get_encrypted_secret(current_user_id: int, secret_name: str) -> str|None:
36
140
 
37
141
 
38
142
  def store_secret(db: Session, secret: SecretInput, user_id: int) -> db_models.Secret:
39
- encrypted_value = encrypt_secret(secret.value.get_secret_value())
143
+ encrypted_value = encrypt_secret(secret.value.get_secret_value(), user_id)
40
144
 
41
145
  # Store in database
42
146
  db_secret = db_models.Secret(
43
147
  name=secret.name,
44
148
  encrypted_value=encrypted_value,
45
- iv="", # Not used with Fernet
46
- user_id=user_id
149
+ iv="", # Legacy field, not used with current encryption
150
+ user_id=user_id,
47
151
  )
48
152
  db.add(db_secret)
49
153
  db.commit()
@@ -52,10 +156,11 @@ def store_secret(db: Session, secret: SecretInput, user_id: int) -> db_models.Se
52
156
 
53
157
 
54
158
  def delete_secret(db: Session, secret_name: str, user_id: int) -> None:
55
- db_secret = db.query(db_models.Secret).filter(
56
- db_models.Secret.user_id == user_id,
57
- db_models.Secret.name == secret_name
58
- ).first()
159
+ db_secret = (
160
+ db.query(db_models.Secret)
161
+ .filter(db_models.Secret.user_id == user_id, db_models.Secret.name == secret_name)
162
+ .first()
163
+ )
59
164
 
60
165
  if not db_secret:
61
166
  raise HTTPException(status_code=404, detail="Secret not found")
flowfile_core/types.py CHANGED
@@ -18,22 +18,41 @@ Usage:
18
18
  """
19
19
 
20
20
  from enum import Enum
21
- from typing import List, Literal, Union
22
- import polars as pl
21
+ from typing import Literal, Union
23
22
 
23
+ import polars as pl
24
24
 
25
25
  DataTypeStr = Literal[
26
- "Int8", "Int16", "Int32", "Int64",
27
- "UInt8", "UInt16", "UInt32", "UInt64",
28
- "Float32", "Float64", "Decimal",
26
+ "Int8",
27
+ "Int16",
28
+ "Int32",
29
+ "Int64",
30
+ "UInt8",
31
+ "UInt16",
32
+ "UInt32",
33
+ "UInt64",
34
+ "Float32",
35
+ "Float64",
36
+ "Decimal",
29
37
  "String",
30
- "Date", "Datetime", "Time", "Duration",
31
- "Boolean", "Binary", "List", "Struct", "Array", "Integer", "Double", "Utf8"
38
+ "Date",
39
+ "Datetime",
40
+ "Time",
41
+ "Duration",
42
+ "Boolean",
43
+ "Binary",
44
+ "List",
45
+ "Struct",
46
+ "Array",
47
+ "Integer",
48
+ "Double",
49
+ "Utf8",
32
50
  ]
33
51
 
34
52
 
35
53
  class TypeGroup(str, Enum):
36
54
  """High-level type groups for column selection."""
55
+
37
56
  Numeric = "Numeric"
38
57
  String = "String"
39
58
  Date = "Date"
@@ -51,6 +70,7 @@ class TypeGroup(str, Enum):
51
70
 
52
71
  class DataType(str, Enum):
53
72
  """Specific data types for fine-grained control."""
73
+
54
74
  # Numeric types
55
75
  Int8 = "Int8"
56
76
  Int16 = "Int16"
@@ -150,7 +170,7 @@ TypeSpec = Union[
150
170
  TypeGroup,
151
171
  DataType,
152
172
  str,
153
- List[Union[TypeGroup, DataType, str, type[pl.DataType], pl.DataType]],
173
+ list[TypeGroup | DataType | str | type[pl.DataType] | pl.DataType],
154
174
  type[pl.DataType],
155
- pl.DataType
175
+ pl.DataType,
156
176
  ]
@@ -1,5 +1,7 @@
1
+ from collections.abc import Callable, Iterator
2
+
1
3
  import pyarrow as pa
2
- from typing import List, Iterator, Tuple, Callable
4
+
3
5
  from flowfile_core.configs import logger
4
6
 
5
7
 
@@ -36,7 +38,7 @@ def open_validated_file(file_path: str, n: int) -> pa.OSFile:
36
38
  logger.error(f"Invalid file_path type: {type(file_path)}")
37
39
  raise TypeError("file_path must be a string")
38
40
  try:
39
- file = pa.OSFile(file_path, 'rb')
41
+ file = pa.OSFile(file_path, "rb")
40
42
  logger.info(f"Successfully opened file: {file_path}")
41
43
  return file
42
44
  except FileNotFoundError:
@@ -112,7 +114,7 @@ def iter_batches(reader: pa.ipc.RecordBatchFileReader, n: int, rows_collected: i
112
114
  break
113
115
 
114
116
 
115
- def collect_batches(reader: pa.ipc.RecordBatchFileReader, n: int) -> Tuple[List[pa.RecordBatch], int]:
117
+ def collect_batches(reader: pa.ipc.RecordBatchFileReader, n: int) -> tuple[list[pa.RecordBatch], int]:
116
118
  """
117
119
  Collect record batches from a reader up to a specified number of rows.
118
120
 
@@ -134,11 +136,10 @@ def collect_batches(reader: pa.ipc.RecordBatchFileReader, n: int) -> Tuple[List[
134
136
  >>> print(f"Collected {row_count} rows in {len(batches)} batches")
135
137
  """
136
138
  logger.debug(f"Collecting batches up to {n} rows")
137
- batches: List[pa.RecordBatch] = []
139
+ batches: list[pa.RecordBatch] = []
138
140
  rows_collected = 0
139
141
 
140
142
  for batch in iter_batches(reader, n, rows_collected):
141
-
142
143
  rows_collected += batch.num_rows
143
144
  logger.debug(f"Collected batch: total rows now {rows_collected}")
144
145
  if rows_collected >= n:
@@ -178,7 +179,7 @@ def read(file_path: str) -> pa.Table:
178
179
  logger.info(f"Reading entire file: {file_path}")
179
180
  with open_validated_file(file_path, 0) as source:
180
181
  reader = create_reader(source)
181
- batches, total_rows = collect_batches(reader, float('inf'))
182
+ batches, total_rows = collect_batches(reader, float("inf"))
182
183
  table = pa.Table.from_batches(batches) # type: ignore
183
184
  logger.info(f"Successfully read {total_rows} rows from {file_path}")
184
185
  return table
@@ -1,13 +1,13 @@
1
1
  import os
2
- import fastexcel
3
- from typing import List
4
2
  from functools import lru_cache
5
3
 
4
+ import fastexcel
5
+
6
6
  from flowfile_core.configs import logger
7
7
 
8
8
 
9
9
  @lru_cache(maxsize=32)
10
- def get_sheet_names(file_path: str) -> List[str] | None:
10
+ def get_sheet_names(file_path: str) -> list[str] | None:
11
11
  if not os.path.exists(file_path):
12
12
  logger.error(f"File does not exist: {file_path}")
13
13
  return
@@ -1,13 +1,13 @@
1
1
  import os
2
- from flowfile_core.schemas.input_schema import NewDirectory, RemoveItem, RemoveItemsInput
3
- from typing import Tuple, Optional
2
+
4
3
  from flowfile_core.configs import logger
4
+ from flowfile_core.schemas.input_schema import NewDirectory, RemoveItem, RemoveItemsInput
5
5
 
6
6
  local_database_connection = None
7
7
 
8
8
 
9
- def create_dir(new_directory: NewDirectory) -> Tuple[bool, Optional[Exception]]:
10
- full_path: str = os.path.join(new_directory.source_path,new_directory.dir_name)
9
+ def create_dir(new_directory: NewDirectory) -> tuple[bool, Exception | None]:
10
+ full_path: str = os.path.join(new_directory.source_path, new_directory.dir_name)
11
11
  try:
12
12
  os.mkdir(full_path)
13
13
  logger.info("Successfully created a new folder")
@@ -16,7 +16,7 @@ def create_dir(new_directory: NewDirectory) -> Tuple[bool, Optional[Exception]]:
16
16
  return False, e
17
17
 
18
18
 
19
- def remove_path(path: str) -> Tuple[bool, Optional[Exception]]:
19
+ def remove_path(path: str) -> tuple[bool, Exception | None]:
20
20
  try:
21
21
  os.remove(path)
22
22
  logger.info(f"Succesfully removed {path}")
@@ -35,11 +35,11 @@ def remove_item(item_to_remove: RemoveItem):
35
35
  os.rmdir(item_to_remove.path)
36
36
 
37
37
 
38
- def remove_paths(remove_items: RemoveItemsInput) -> Tuple[bool, Optional[Exception]]:
38
+ def remove_paths(remove_items: RemoveItemsInput) -> tuple[bool, Exception | None]:
39
39
  try:
40
40
  for path in remove_items.paths:
41
41
  remove_item(path)
42
- logger.info(f'Successfully removed {remove_items.paths}')
42
+ logger.info(f"Successfully removed {remove_items.paths}")
43
43
  return True, None
44
44
  except Exception as e:
45
45
  return False, e
@@ -1,9 +1,9 @@
1
- from flowfile_core.configs import logger
1
+ from functools import wraps
2
2
  from inspect import isfunction
3
+
3
4
  from loky import get_reusable_executor
4
- from functools import wraps
5
- from concurrent.futures import ThreadPoolExecutor
6
- import atexit
5
+
6
+ from flowfile_core.configs import logger
7
7
 
8
8
 
9
9
  # process_executor: Uses loky for process-based parallelism
@@ -13,18 +13,18 @@ def process_executor(wait_on_completion: bool = False, max_workers: int = 12):
13
13
  def executor(f):
14
14
  @wraps(f)
15
15
  def inner(*args, **kwargs):
16
- logger.debug(f'Added task {f.__name__} to a process executor')
17
- logger.debug(f'max_workers: {max_workers}')
16
+ logger.debug(f"Added task {f.__name__} to a process executor")
17
+ logger.debug(f"max_workers: {max_workers}")
18
18
 
19
19
  # Create a new executor with the required number of workers
20
20
  func_executor = get_reusable_executor(max_workers=max_workers, timeout=2, kill_workers=False, reuse=True)
21
21
  r = func_executor.submit(f, *args, **kwargs)
22
22
  if wait_on_completion:
23
23
  result = r.result()
24
- logger.info(f'done executing {f.__name__}')
24
+ logger.info(f"done executing {f.__name__}")
25
25
  return result
26
26
 
27
- logger.info(f'done submitting {f.__name__} to a process executor')
27
+ logger.info(f"done submitting {f.__name__} to a process executor")
28
28
  return r
29
29
 
30
30
  return inner
@@ -34,5 +34,3 @@ def process_executor(wait_on_completion: bool = False, max_workers: int = 12):
34
34
  wait_on_completion = False
35
35
  return executor(f)
36
36
  return executor
37
-
38
-
@@ -1,14 +1,14 @@
1
1
  import re
2
2
  from itertools import chain
3
- from typing import List, Dict
3
+
4
4
 
5
5
  def camel_case_to_snake_case(text: str) -> str:
6
6
  # Use a regular expression to find capital letters and replace them with _ followed by the lowercase letter
7
- transformed_text = re.sub(r'(?<!^)(?=[A-Z])', '_', text).lower()
7
+ transformed_text = re.sub(r"(?<!^)(?=[A-Z])", "_", text).lower()
8
8
  return transformed_text
9
9
 
10
10
 
11
- def ensure_similarity_dicts(datas: List[Dict], respect_order: bool = True):
11
+ def ensure_similarity_dicts(datas: list[dict], respect_order: bool = True):
12
12
  all_cols = (data.keys() for data in datas)
13
13
  if not respect_order:
14
14
  unique_cols = set(chain(*all_cols))
@@ -44,4 +44,4 @@ def standardize_col_dtype(vals):
44
44
  elif int in types and float in types:
45
45
  return vals
46
46
  else:
47
- return [convert_to_string(v) for v in vals]
47
+ return [convert_to_string(v) for v in vals]
@@ -1,11 +1,12 @@
1
1
  """This script runs on run time and checks if all the nodes that are created have a function in the flow_graph as well
2
2
  as have a component in flowfile_frontend"""
3
3
 
4
- from flowfile_core.schemas import input_schema
5
- from flowfile_core.flowfile.flow_graph import FlowGraph
6
- from flowfile_core.configs.node_store import nodes_list, NodeTemplate
7
4
  import inspect
8
5
 
6
+ from flowfile_core.configs.node_store import NodeTemplate, nodes_list
7
+ from flowfile_core.flowfile.flow_graph import FlowGraph
8
+ from flowfile_core.schemas import input_schema
9
+
9
10
 
10
11
  def check_if_node_has_add_function_in_flow_graph(node: NodeTemplate):
11
12
  func_name = "add_" + node.item
@@ -17,7 +18,7 @@ def check_if_node_has_add_function_in_flow_graph(node: NodeTemplate):
17
18
 
18
19
 
19
20
  def check_if_node_has_input_schema_definition(node: NodeTemplate):
20
- if "node"+node.item.replace("_","") not in {k.lower() for k in inspect.getmodule(input_schema).__dict__.keys()}:
21
+ if "node" + node.item.replace("_", "") not in {k.lower() for k in inspect.getmodule(input_schema).__dict__.keys()}:
21
22
  raise ValueError(
22
23
  f"Node {node.name} ({node.item}) does not have a corresponding input schema definition in input_schema.py."
23
24
  "Check if the schema is implemented or if the node item is correct."