Flowfile 0.5.6__py3-none-any.whl → 0.6.1__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 (256) hide show
  1. flowfile/api.py +8 -6
  2. flowfile/web/static/assets/{AdminView-c2c7942b.js → AdminView-C4K1DdHI.js} +28 -33
  3. flowfile/web/static/assets/{CloudConnectionView-7a3042c6.js → CloudConnectionView-BZbPvPUL.js} +39 -50
  4. flowfile/web/static/assets/{CloudStorageReader-24c54524.css → CloudStorageReader-BDByiqPI.css} +25 -25
  5. flowfile/web/static/assets/{CloudStorageReader-709c4037.js → CloudStorageReader-DLVukNJ7.js} +30 -35
  6. flowfile/web/static/assets/{CloudStorageWriter-604c51a8.js → CloudStorageWriter-Bfi-C1QW.js} +32 -37
  7. flowfile/web/static/assets/{CloudStorageWriter-60547855.css → CloudStorageWriter-y8jL8yjG.css} +24 -24
  8. flowfile/web/static/assets/{ColumnActionInput-d63d6746.js → ColumnActionInput-BpiCApw9.js} +7 -12
  9. flowfile/web/static/assets/{ColumnSelector-0c8cd1cd.js → ColumnSelector-CEAwedI7.js} +1 -2
  10. flowfile/web/static/assets/ContextMenu-CdojQu0w.js +9 -0
  11. flowfile/web/static/assets/ContextMenu-D12mhsy1.js +9 -0
  12. flowfile/web/static/assets/ContextMenu-EWUR98va.js +9 -0
  13. flowfile/web/static/assets/{ContextMenu.vue_vue_type_script_setup_true_lang-774c517c.js → ContextMenu.vue_vue_type_script_setup_true_lang-I4rXXd6G.js} +4 -5
  14. flowfile/web/static/assets/{CrossJoin-38e5b99a.js → CrossJoin-BOFfxkJO.js} +19 -18
  15. flowfile/web/static/assets/{CrossJoin-71b4cc10.css → CrossJoin-Cmbyt9im.css} +18 -18
  16. flowfile/web/static/assets/{CustomNode-76e8f3f5.js → CustomNode-Bhpezobq.js} +12 -17
  17. flowfile/web/static/assets/{DatabaseConnectionSettings-38155669.js → DatabaseConnectionSettings-Dw3bSJKB.js} +10 -11
  18. flowfile/web/static/assets/{DatabaseReader-5bf8c75b.css → DatabaseReader-D6pUNUCs.css} +21 -21
  19. flowfile/web/static/assets/{DatabaseReader-2e549c8f.js → DatabaseReader-m87ghlw0.js} +36 -34
  20. flowfile/web/static/assets/{DatabaseView-dc877c29.js → DatabaseView-CisSAtpe.js} +30 -38
  21. flowfile/web/static/assets/{DatabaseWriter-ffb91864.js → DatabaseWriter-Bbj9JLdL.js} +33 -35
  22. flowfile/web/static/assets/{DatabaseWriter-bdcf2c8b.css → DatabaseWriter-RBqdFLj8.css} +17 -17
  23. flowfile/web/static/assets/{DesignerView-a4466dab.js → DesignerView-DemDevTQ.js} +1752 -2054
  24. flowfile/web/static/assets/{DesignerView-71d4e9a1.css → DesignerView-Dm6OzlIc.css} +209 -168
  25. flowfile/web/static/assets/{DocumentationView-979afc84.js → DocumentationView-BrC1ZR3H.js} +3 -4
  26. flowfile/web/static/assets/{ExploreData-e4b92aaf.js → ExploreData-BMKcDuRb.js} +8 -10
  27. flowfile/web/static/assets/{ExternalSource-d08e7227.js → ExternalSource-BXrNNS-f.js} +40 -42
  28. flowfile/web/static/assets/{ExternalSource-7ac7373f.css → ExternalSource-NB6WVl5R.css} +14 -14
  29. flowfile/web/static/assets/{Filter-7add806d.js → Filter-C2MjsN6P.js} +36 -33
  30. flowfile/web/static/assets/{Filter-7494ea97.css → Filter-DCMGGuGC.css} +9 -9
  31. flowfile/web/static/assets/{Formula-53d58c43.css → Formula-BYafbDj8.css} +4 -4
  32. flowfile/web/static/assets/{Formula-36ab24d2.js → Formula-ufuy4mVD.js} +27 -26
  33. flowfile/web/static/assets/{FuzzyMatch-ad6361d6.css → FuzzyMatch-BGJAwgd0.css} +42 -42
  34. flowfile/web/static/assets/{FuzzyMatch-cc01bb04.js → FuzzyMatch-BOHODq3h.js} +36 -38
  35. flowfile/web/static/assets/{GraphSolver-4fb98f3b.js → GraphSolver-B6ZzpNGO.js} +23 -21
  36. flowfile/web/static/assets/{GraphSolver-4b4d7db9.css → GraphSolver-DFN83sj3.css} +4 -4
  37. flowfile/web/static/assets/{GroupBy-b3c8f429.js → GroupBy-B9BRNcfe.js} +30 -29
  38. flowfile/web/static/assets/{Sort-4abb7fae.css → GroupBy-x4ooP5np.css} +1 -1
  39. flowfile/web/static/assets/Join-Bx_g5bZz.css +118 -0
  40. flowfile/web/static/assets/{Join-096b7b26.js → Join-DsBEy1IH.js} +48 -43
  41. flowfile/web/static/assets/{LoginView-c33a246a.js → LoginView-Ct0rhdcO.js} +1 -2
  42. flowfile/web/static/assets/{ManualInput-39111f19.css → ManualInput-DlZmtMdt.css} +48 -48
  43. flowfile/web/static/assets/{ManualInput-7307e9b1.js → ManualInput-bC4BUgnG.js} +40 -41
  44. flowfile/web/static/assets/{MultiSelect-14822c48.js → MultiSelect-DIQ8PuTC.js} +2 -2
  45. flowfile/web/static/assets/{MultiSelect.vue_vue_type_script_setup_true_lang-90c4d340.js → MultiSelect.vue_vue_type_script_setup_true_lang-BefHfqTI.js} +1 -1
  46. flowfile/web/static/assets/{NodeDesigner-5036c392.js → NodeDesigner-D39yzr2k.js} +178 -208
  47. flowfile/web/static/assets/{NodeDesigner-94cd4dd3.css → NodeDesigner-R0l6sYyY.css} +76 -76
  48. flowfile/web/static/assets/{NumericInput-15cf3b72.js → NumericInput-DMSX3oOr.js} +2 -2
  49. flowfile/web/static/assets/{NumericInput.vue_vue_type_script_setup_true_lang-91e679d7.js → NumericInput.vue_vue_type_script_setup_true_lang-d0YlVHAl.js} +1 -1
  50. flowfile/web/static/assets/{Output-1f8ed42c.js → Output-D0VoXGcW.js} +26 -34
  51. flowfile/web/static/assets/{Output-692dd25d.css → Output-DsmglIDy.css} +5 -5
  52. flowfile/web/static/assets/{Pivot-0e153f4e.js → Pivot-BnMB4sEe.js} +26 -26
  53. flowfile/web/static/assets/{Pivot-0eda81b4.css → Pivot-qKTyWxop.css} +4 -4
  54. flowfile/web/static/assets/{PivotValidation-81ec2a33.js → PivotValidation-B2lWvugt.js} +7 -9
  55. flowfile/web/static/assets/{PivotValidation-5a4f7c79.js → PivotValidation-BPlhRjpL.js} +7 -9
  56. flowfile/web/static/assets/{PolarsCode-a39f15ac.js → PolarsCode-5h0tHnWR.js} +22 -20
  57. flowfile/web/static/assets/{PopOver-ddcfe4f6.js → PopOver-BHpt5rsj.js} +5 -9
  58. flowfile/web/static/assets/{PopOver-d96599db.css → PopOver-CyYM4-rV.css} +1 -1
  59. flowfile/web/static/assets/{Read-90f366bc.css → Read-DJxkrTb_.css} +10 -10
  60. flowfile/web/static/assets/Read-TsLEFh3B.js +227 -0
  61. flowfile/web/static/assets/{RecordCount-e9048ccd.js → RecordCount-DkVixq9v.js} +18 -17
  62. flowfile/web/static/assets/{RecordId-ad02521d.js → RecordId-C2UEGlCf.js} +42 -39
  63. flowfile/web/static/assets/{SQLQueryComponent-2eeecf0b.js → SQLQueryComponent-Dr5KMoD3.js} +2 -3
  64. flowfile/web/static/assets/{Sample-9a68c23d.js → Sample-Cb3eQNmd.js} +30 -30
  65. flowfile/web/static/assets/{SecretSelector-2429f35a.js → SecretSelector-De2L2bSx.js} +3 -4
  66. flowfile/web/static/assets/{SecretsView-c6afc915.js → SecretsView-CheC9BPV.js} +13 -16
  67. flowfile/web/static/assets/{Select-fcd002b6.js → Select-CI8TloRs.js} +41 -36
  68. flowfile/web/static/assets/{SettingsSection-5ce15962.js → SettingsSection-B39ulIiI.js} +1 -2
  69. flowfile/web/static/assets/{SettingsSection-c6b1362c.js → SettingsSection-BiCc7S9h.js} +1 -2
  70. flowfile/web/static/assets/{SettingsSection-cebb91d5.js → SettingsSection-CITK_R7o.js} +2 -3
  71. flowfile/web/static/assets/{SettingsSection-26fe48d4.css → SettingsSection-D2GgY-Aq.css} +4 -4
  72. flowfile/web/static/assets/{SetupView-2d12e01f.js → SetupView-C1aXRDvp.js} +1 -2
  73. flowfile/web/static/assets/{SingleSelect-b67de4eb.js → SingleSelect-Kr_hz90m.js} +2 -2
  74. flowfile/web/static/assets/{SingleSelect.vue_vue_type_script_setup_true_lang-eedb70eb.js → SingleSelect.vue_vue_type_script_setup_true_lang-Rxht5Z5N.js} +1 -1
  75. flowfile/web/static/assets/{SliderInput-fd8134ac.js → SliderInput-CLqpCxCb.js} +1 -2
  76. flowfile/web/static/assets/{GroupBy-5792782d.css → Sort-BIt2kc_p.css} +1 -1
  77. flowfile/web/static/assets/{Sort-c005a573.js → Sort-Dnw_J6Qi.js} +25 -25
  78. flowfile/web/static/assets/{TextInput-1bb31dab.js → TextInput-wdlunIZC.js} +2 -2
  79. flowfile/web/static/assets/{TextInput.vue_vue_type_script_setup_true_lang-a51fe730.js → TextInput.vue_vue_type_script_setup_true_lang-Bcj3ywzv.js} +1 -1
  80. flowfile/web/static/assets/{TextToRows-4f363753.js → TextToRows-BhtyGWPq.js} +42 -49
  81. flowfile/web/static/assets/{TextToRows-12afb4f4.css → TextToRows-DivDOLDx.css} +9 -9
  82. flowfile/web/static/assets/{ToggleSwitch-ca0f2e5e.js → ToggleSwitch-B-6WzfFf.js} +2 -2
  83. flowfile/web/static/assets/{ToggleSwitch.vue_vue_type_script_setup_true_lang-49aa41d8.js → ToggleSwitch.vue_vue_type_script_setup_true_lang-Cj8LqT-b.js} +1 -1
  84. flowfile/web/static/assets/{UnavailableFields-f6147968.js → UnavailableFields-Yf6XSqFB.js} +2 -3
  85. flowfile/web/static/assets/{Union-c65f17b7.js → Union-CwpjeKYC.js} +20 -23
  86. flowfile/web/static/assets/{Unpivot-b6ad6427.css → Union-DQJcpp3-.css} +6 -6
  87. flowfile/web/static/assets/{Unique-a1d96fb2.js → Unique-25v3urqH.js} +75 -74
  88. flowfile/web/static/assets/{Union-d6a8d7d5.css → Unpivot-Deqh1gtI.css} +6 -6
  89. flowfile/web/static/assets/{Unpivot-c2657ff3.js → Unpivot-sYcTTXrq.js} +34 -27
  90. flowfile/web/static/assets/{UnpivotValidation-28e29a3b.js → UnpivotValidation-C5DDEKY2.js} +5 -7
  91. flowfile/web/static/assets/VueGraphicWalker-B8l1_Z92.js +131 -0
  92. flowfile/web/static/assets/VueGraphicWalker-Da_1-3me.css +21 -0
  93. flowfile/web/static/assets/{api-df48ec50.js → api-C0LvF-0C.js} +1 -1
  94. flowfile/web/static/assets/{api-ee542cf7.js → api-DaC83EO_.js} +1 -1
  95. flowfile/web/static/assets/client-C8Ygr6Gb.js +42 -0
  96. flowfile/web/static/assets/{dropDown-7576a76a.js → dropDown-D5YXaPRR.js} +7 -12
  97. flowfile/web/static/assets/{fullEditor-7583bef5.js → fullEditor-BVYnWm05.js} +300 -18
  98. flowfile/web/static/assets/genericNodeSettings-2wAu-QKn.css +75 -0
  99. flowfile/web/static/assets/genericNodeSettings-BBtW_Cpz.js +590 -0
  100. flowfile/web/static/assets/{VueGraphicWalker-2fc3ddd4.js → graphic-walker.es-VrK6vdGE.js} +92305 -89751
  101. flowfile/web/static/assets/index-BCJxPfM5.js +6693 -0
  102. flowfile/web/static/assets/{index-057d770d.js → index-CHPMUR0d.js} +150 -170
  103. flowfile/web/static/assets/index-DPkoZWq8.js +32 -0
  104. flowfile/web/static/assets/index-DnW_KC_I.js +277 -0
  105. flowfile/web/static/assets/index-UFXyfirV.css +10797 -0
  106. flowfile/web/static/assets/index-bcuE0Z0p.js +87456 -0
  107. flowfile/web/static/assets/{node.types-2c15bb7e.js → node.types-Dl4gtSW9.js} +2 -2
  108. flowfile/web/static/assets/{outputCsv-c492b15e.js → outputCsv-BELuBiJZ.js} +1 -2
  109. flowfile/web/static/assets/outputCsv-CdGkv-fN.css +2581 -0
  110. flowfile/web/static/assets/{outputExcel-13bfa10f.js → outputExcel-D0TTNM79.js} +1 -2
  111. flowfile/web/static/assets/{outputParquet-9be1523a.js → outputParquet-Cz9EbRHj.js} +1 -2
  112. flowfile/web/static/assets/{readCsv-5a49a8c9.js → readCsv-7bd3kUMI.js} +1 -2
  113. flowfile/web/static/assets/{readExcel-27c30ad8.js → readExcel-Cq8CCwIv.js} +3 -4
  114. flowfile/web/static/assets/{readParquet-c5244ad5.css → readParquet-CRDmBrsp.css} +4 -4
  115. flowfile/web/static/assets/{readParquet-446bde68.js → readParquet-DjR4mRaj.js} +4 -5
  116. flowfile/web/static/assets/{secrets.api-34431884.js → secrets.api-C9o2KE5V.js} +1 -1
  117. flowfile/web/static/assets/{selectDynamic-5754a2b1.js → selectDynamic-Bl5FVsME.js} +5 -7
  118. flowfile/web/static/assets/useNodeSettings-dMS9zmh_.js +69 -0
  119. flowfile/web/static/assets/{vue-codemirror.esm-8f46fb36.js → vue-codemirror.esm-CwaYwln0.js} +3469 -3064
  120. flowfile/web/static/assets/{vue-content-loader.es-808fe33a.js → vue-content-loader.es-CMoRXo7N.js} +3 -3
  121. flowfile/web/static/index.html +2 -3
  122. {flowfile-0.5.6.dist-info → flowfile-0.6.1.dist-info}/METADATA +2 -1
  123. flowfile-0.6.1.dist-info/RECORD +417 -0
  124. {flowfile-0.5.6.dist-info → flowfile-0.6.1.dist-info}/WHEEL +1 -1
  125. flowfile_core/auth/password.py +1 -0
  126. flowfile_core/database/init_db.py +7 -5
  127. flowfile_core/fileExplorer/funcs.py +2 -2
  128. flowfile_core/flowfile/code_generator/code_generator.py +13 -11
  129. flowfile_core/flowfile/filter_expressions.py +327 -0
  130. flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +61 -59
  131. flowfile_core/flowfile/flow_data_engine/flow_file_column/type_registry.py +3 -29
  132. flowfile_core/flowfile/flow_data_engine/flow_file_column/utils.py +45 -14
  133. flowfile_core/flowfile/flow_data_engine/subprocess_operations/models.py +20 -3
  134. flowfile_core/flowfile/flow_data_engine/subprocess_operations/streaming.py +206 -0
  135. flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +146 -24
  136. flowfile_core/flowfile/flow_graph.py +504 -190
  137. flowfile_core/flowfile/flow_node/__init__.py +32 -0
  138. flowfile_core/flowfile/flow_node/executor.py +404 -0
  139. flowfile_core/flowfile/flow_node/flow_node.py +207 -106
  140. flowfile_core/flowfile/flow_node/models.py +40 -0
  141. flowfile_core/flowfile/flow_node/output_field_config_applier.py +217 -0
  142. flowfile_core/flowfile/flow_node/schema_utils.py +78 -0
  143. flowfile_core/flowfile/flow_node/state.py +155 -0
  144. flowfile_core/flowfile/history_manager.py +401 -0
  145. flowfile_core/flowfile/manage/compatibility_enhancements.py +9 -0
  146. flowfile_core/flowfile/manage/io_flowfile.py +3 -1
  147. flowfile_core/flowfile/sources/external_sources/sql_source/models.py +20 -4
  148. flowfile_core/flowfile/util/execution_orderer.py +89 -36
  149. flowfile_core/routes/auth.py +8 -9
  150. flowfile_core/routes/routes.py +320 -101
  151. flowfile_core/routes/user_defined_components.py +18 -16
  152. flowfile_core/schemas/history_schema.py +220 -0
  153. flowfile_core/schemas/input_schema.py +130 -6
  154. flowfile_core/schemas/schemas.py +9 -0
  155. flowfile_core/schemas/transform_schema.py +27 -5
  156. flowfile_core/schemas/yaml_types.py +23 -5
  157. flowfile_frame/adding_expr.py +18 -126
  158. flowfile_frame/callable_utils.py +261 -0
  159. flowfile_frame/database/connection_manager.py +0 -1
  160. flowfile_frame/expr.py +8 -4
  161. flowfile_frame/flow_frame.py +41 -41
  162. flowfile_frame/lazy.py +3 -12
  163. flowfile_frame/lazy_methods.py +5 -64
  164. flowfile_frame/utils.py +13 -32
  165. flowfile_worker/funcs.py +6 -4
  166. flowfile_worker/main.py +2 -0
  167. flowfile_worker/models.py +31 -11
  168. flowfile_worker/routes.py +60 -35
  169. flowfile_worker/spawner.py +7 -1
  170. flowfile_worker/streaming.py +335 -0
  171. flowfile/web/static/assets/ContextMenu-366bf1b4.js +0 -9
  172. flowfile/web/static/assets/ContextMenu-85cf5b44.js +0 -9
  173. flowfile/web/static/assets/ContextMenu-9d28ae6d.js +0 -9
  174. flowfile/web/static/assets/Join-28b5e18f.css +0 -109
  175. flowfile/web/static/assets/Read-39b63932.js +0 -222
  176. flowfile/web/static/assets/VueGraphicWalker-430f0b86.css +0 -6
  177. flowfile/web/static/assets/database_reader-ce1e55f3.svg +0 -24
  178. flowfile/web/static/assets/database_writer-b4ad0753.svg +0 -23
  179. flowfile/web/static/assets/element-icons-9c88a535.woff +0 -0
  180. flowfile/web/static/assets/element-icons-de5eb258.ttf +0 -0
  181. flowfile/web/static/assets/genericNodeSettings-0155288b.js +0 -136
  182. flowfile/web/static/assets/genericNodeSettings-3b2507ea.css +0 -46
  183. flowfile/web/static/assets/index-aeec439d.js +0 -38
  184. flowfile/web/static/assets/index-ca6799de.js +0 -62760
  185. flowfile/web/static/assets/index-d60c9dd4.css +0 -10777
  186. flowfile/web/static/assets/nodeInput-d478b9ac.js +0 -2
  187. flowfile/web/static/assets/outputCsv-cc84e09f.css +0 -2499
  188. flowfile-0.5.6.dist-info/RECORD +0 -407
  189. /flowfile/web/static/assets/{AdminView-f53bad23.css → AdminView-B2Dthl3u.css} +0 -0
  190. /flowfile/web/static/assets/{CloudConnectionView-cf85f943.css → CloudConnectionView-BdFYGWV7.css} +0 -0
  191. /flowfile/web/static/assets/{ColumnActionInput-c44b7aee.css → ColumnActionInput-dCasSIC9.css} +0 -0
  192. /flowfile/web/static/assets/{ColumnSelector-371637fb.css → ColumnSelector-j6sEOjo1.css} +0 -0
  193. /flowfile/web/static/assets/{CustomNode-edb9b939.css → CustomNode-VPlajG0j.css} +0 -0
  194. /flowfile/web/static/assets/{DatabaseConnectionSettings-c20a1e16.css → DatabaseConnectionSettings-B78hXYgu.css} +0 -0
  195. /flowfile/web/static/assets/{DatabaseView-6655afd6.css → DatabaseView-B-_adk1s.css} +0 -0
  196. /flowfile/web/static/assets/{DocumentationView-9ea6e871.css → DocumentationView-CL7iipFL.css} +0 -0
  197. /flowfile/web/static/assets/{ExploreData-10c5acc8.css → ExploreData-DHjv0Plr.css} +0 -0
  198. /flowfile/web/static/assets/{LoginView-d325d632.css → LoginView-DN1BXY3e.css} +0 -0
  199. /flowfile/web/static/assets/{PivotValidation-0e905b1a.css → PivotValidation-DK-FARWe.css} +0 -0
  200. /flowfile/web/static/assets/{PivotValidation-41b57ad6.css → PivotValidation-FUa9F47u.css} +0 -0
  201. /flowfile/web/static/assets/{PolarsCode-2b1f1f23.css → PolarsCode-G-gRSrSc.css} +0 -0
  202. /flowfile/web/static/assets/{SQLQueryComponent-edb90b98.css → SQLQueryComponent-oAbWw0r-.css} +0 -0
  203. /flowfile/web/static/assets/{SecretSelector-6329f743.css → SecretSelector-CJSadIZx.css} +0 -0
  204. /flowfile/web/static/assets/{SecretsView-aa291340.css → SecretsView-DbzIRAba.css} +0 -0
  205. /flowfile/web/static/assets/{SettingsSection-8f980839.css → SettingsSection-BGcJnH6q.css} +0 -0
  206. /flowfile/web/static/assets/{SettingsSection-07fbbc39.css → SettingsSection-DDWn_EGW.css} +0 -0
  207. /flowfile/web/static/assets/{SetupView-ec26f76a.css → SetupView-CI1nd-5Z.css} +0 -0
  208. /flowfile/web/static/assets/{SliderInput-f2e4f23c.css → SliderInput-BRk-q_Dk.css} +0 -0
  209. /flowfile/web/static/assets/{UnavailableFields-394a1f78.css → UnavailableFields-DRKDImKe.css} +0 -0
  210. /flowfile/web/static/assets/{Unique-2b705521.css → Unique-Absb0aON.css} +0 -0
  211. /flowfile/web/static/assets/{UnpivotValidation-d5ca3b7b.css → UnpivotValidation-DSBkFgS-.css} +0 -0
  212. /flowfile/web/static/assets/{airbyte-292aa232.png → airbyte-W0xvIXwZ.png} +0 -0
  213. /flowfile/web/static/assets/{cloud_storage_reader-aa1415d6.png → cloud_storage_reader-3GpSCk90.png} +0 -0
  214. /flowfile/web/static/assets/{cross_join-d30c0290.png → cross_join-B0qpgYoV.png} +0 -0
  215. /flowfile/web/static/assets/{dropDown-1d6acbd9.css → dropDown-CE0VF5_P.css} +0 -0
  216. /flowfile/web/static/assets/{explore_data-8a0a2861.png → explore_data-tX6olPPL.png} +0 -0
  217. /flowfile/web/static/assets/{fa-brands-400-808443ae.ttf → fa-brands-400-D1LuMI3I.ttf} +0 -0
  218. /flowfile/web/static/assets/{fa-brands-400-d7236a19.woff2 → fa-brands-400-D_cYUPeE.woff2} +0 -0
  219. /flowfile/web/static/assets/{fa-regular-400-e3456d12.woff2 → fa-regular-400-BjRzuEpd.woff2} +0 -0
  220. /flowfile/web/static/assets/{fa-regular-400-54cf6086.ttf → fa-regular-400-DZaxPHgR.ttf} +0 -0
  221. /flowfile/web/static/assets/{fa-solid-900-aa759986.woff2 → fa-solid-900-CTAAxXor.woff2} +0 -0
  222. /flowfile/web/static/assets/{fa-solid-900-d2f05935.ttf → fa-solid-900-D0aA9rwL.ttf} +0 -0
  223. /flowfile/web/static/assets/{fa-v4compatibility-0ce9033c.woff2 → fa-v4compatibility-C9RhG_FT.woff2} +0 -0
  224. /flowfile/web/static/assets/{fa-v4compatibility-30f6abf6.ttf → fa-v4compatibility-CCth-dXg.ttf} +0 -0
  225. /flowfile/web/static/assets/{filter-d7708bda.png → filter-WRdZyUOw.png} +0 -0
  226. /flowfile/web/static/assets/{formula-eeeb1611.png → formula-CgM7uHVI.png} +0 -0
  227. /flowfile/web/static/assets/{fullEditor-fe9f7e18.css → fullEditor-CmDI7T9F.css} +0 -0
  228. /flowfile/web/static/assets/{fuzzy_match-40c161b2.png → fuzzy_match-Yon3k5Tc.png} +0 -0
  229. /flowfile/web/static/assets/{graph_solver-8b7888b8.png → graph_solver-BlMrBttD.png} +0 -0
  230. /flowfile/web/static/assets/{group_by-80561fc3.png → group_by-Gici0CSS.png} +0 -0
  231. /flowfile/web/static/assets/{input_data-ab2eb678.png → input_data-BRdGecLc.png} +0 -0
  232. /flowfile/web/static/assets/{join-349043ae.png → join-BITWRu73.png} +0 -0
  233. /flowfile/web/static/assets/{manual_input-ae98f31d.png → manual_input-CFvo_EUS.png} +0 -0
  234. /flowfile/web/static/assets/{old_join-5d0eb604.png → old_join-B9bkpPqv.png} +0 -0
  235. /flowfile/web/static/assets/{output-06ec0371.png → output-Dp7-ZpC4.png} +0 -0
  236. /flowfile/web/static/assets/{outputExcel-f5d272b2.css → outputExcel-CKgRe2iT.css} +0 -0
  237. /flowfile/web/static/assets/{outputParquet-54597c3c.css → outputParquet-d7j407cK.css} +0 -0
  238. /flowfile/web/static/assets/{pivot-9660df51.png → pivot-DSxKhNlD.png} +0 -0
  239. /flowfile/web/static/assets/{polars_code-05ce5dc6.png → polars_code-DxiztZ1c.png} +0 -0
  240. /flowfile/web/static/assets/{readCsv-3bfac4c3.css → readCsv-BG-1Jilp.css} +0 -0
  241. /flowfile/web/static/assets/{readExcel-3db6b763.css → readExcel-DBQXKPtC.css} +0 -0
  242. /flowfile/web/static/assets/{record_count-dab44eb5.png → record_count-DCeaLtpS.png} +0 -0
  243. /flowfile/web/static/assets/{record_id-0b15856b.png → record_id-FeUjyIFh.png} +0 -0
  244. /flowfile/web/static/assets/{sample-693a88b5.png → sample-DeqfRiB-.png} +0 -0
  245. /flowfile/web/static/assets/{select-b0d0437a.png → select-D4JjbdjS.png} +0 -0
  246. /flowfile/web/static/assets/{selectDynamic-f2fb394f.css → selectDynamic-CjeTPUUo.css} +0 -0
  247. /flowfile/web/static/assets/{sort-2aa579f0.png → sort-DGwUG9WS.png} +0 -0
  248. /flowfile/web/static/assets/{summarize-2a099231.png → summarize-DFaNHpfp.png} +0 -0
  249. /flowfile/web/static/assets/{text_to_rows-859b29ea.png → text_to_rows-BdiAewrN.png} +0 -0
  250. /flowfile/web/static/assets/{union-2d8609f4.png → union-DCK-LSMq.png} +0 -0
  251. /flowfile/web/static/assets/{unique-1958b98a.png → unique-CdP3zZIq.png} +0 -0
  252. /flowfile/web/static/assets/{unpivot-d3cb4b5b.png → unpivot-CHttrEt8.png} +0 -0
  253. /flowfile/web/static/assets/{user-defined-icon-0ae16c90.png → user-defined-icon-BcIp2Vzo.png} +0 -0
  254. /flowfile/web/static/assets/{view-7a0f0be1.png → view-DUSRwjvq.png} +0 -0
  255. {flowfile-0.5.6.dist-info → flowfile-0.6.1.dist-info}/entry_points.txt +0 -0
  256. {flowfile-0.5.6.dist-info → flowfile-0.6.1.dist-info}/licenses/LICENSE +0 -0
@@ -4,7 +4,7 @@ import inspect
4
4
  import os
5
5
  import re
6
6
  from collections.abc import Iterable, Iterator, Mapping
7
- from typing import Any, Literal, Optional, Union, get_args, get_origin
7
+ from typing import Any, Literal, Union, get_args, get_origin
8
8
 
9
9
  import polars as pl
10
10
  from pl_fuzzy_frame_match import FuzzyMapping
@@ -239,7 +239,7 @@ class FlowFrame:
239
239
  node_id: int | None = None,
240
240
  parent_node_id: int | None = None,
241
241
  **kwargs, # Accept and ignore any other kwargs for API compatibility
242
- ) -> "FlowFrame":
242
+ ) -> FlowFrame:
243
243
  """
244
244
  Unified constructor for FlowFrame.
245
245
 
@@ -384,7 +384,7 @@ class FlowFrame:
384
384
  multithreaded: bool = True,
385
385
  maintain_order: bool = False,
386
386
  description: str | None = None,
387
- ) -> "FlowFrame":
387
+ ) -> FlowFrame:
388
388
  """
389
389
  Sort the dataframe by the given columns.
390
390
  """
@@ -469,7 +469,7 @@ class FlowFrame:
469
469
  unique_raw_definitions = list(dict.fromkeys(collected_raw_definitions)) # Order-preserving unique
470
470
  definitions_section = "\n\n".join(unique_raw_definitions)
471
471
  final_code_for_node = (
472
- definitions_section + "\\#─────SPLIT─────\n\n" + f"output_df = {polars_operation_code}"
472
+ definitions_section + "\n#─────SPLIT─────\n\n" + f"output_df = {polars_operation_code}"
473
473
  )
474
474
  else:
475
475
  final_code_for_node = polars_operation_code
@@ -615,7 +615,7 @@ class FlowFrame:
615
615
  coalesce: bool = None,
616
616
  maintain_order: Literal[None, "left", "right", "left_right", "right_left"] = None,
617
617
  description: str = None,
618
- ) -> "FlowFrame":
618
+ ) -> FlowFrame:
619
619
  """
620
620
  Add a join operation to the Logical Plan.
621
621
 
@@ -714,7 +714,7 @@ class FlowFrame:
714
714
  and suffix == "_right"
715
715
  )
716
716
 
717
- def _ensure_same_graph(self, other: "FlowFrame") -> None:
717
+ def _ensure_same_graph(self, other: FlowFrame) -> None:
718
718
  """Ensure both FlowFrames are in the same graph, combining if necessary."""
719
719
  if self.flow_graph.flow_id != other.flow_graph.flow_id:
720
720
  combined_graph, node_mappings = combine_flow_graphs_with_mapping(self.flow_graph, other.flow_graph)
@@ -754,7 +754,7 @@ class FlowFrame:
754
754
 
755
755
  def _execute_polars_code_join(
756
756
  self,
757
- other: "FlowFrame",
757
+ other: FlowFrame,
758
758
  new_node_id: int,
759
759
  on: list[str | Column] | str | Column,
760
760
  left_on: list[str | Column] | str | Column,
@@ -768,7 +768,7 @@ class FlowFrame:
768
768
  coalesce: bool,
769
769
  maintain_order: Literal[None, "left", "right", "left_right", "right_left"],
770
770
  description: str,
771
- ) -> "FlowFrame":
771
+ ) -> FlowFrame:
772
772
  """Execute join using Polars code approach."""
773
773
  # Build the code arguments
774
774
  code_kwargs = self._build_polars_join_kwargs(
@@ -843,12 +843,12 @@ class FlowFrame:
843
843
 
844
844
  def _execute_native_join(
845
845
  self,
846
- other: "FlowFrame",
846
+ other: FlowFrame,
847
847
  new_node_id: int,
848
848
  join_mappings: list | None,
849
849
  how: str,
850
850
  description: str,
851
- ) -> "FlowFrame":
851
+ ) -> FlowFrame:
852
852
  """Execute join using native FlowFile join nodes."""
853
853
  # Create select inputs for both frames
854
854
 
@@ -896,9 +896,9 @@ class FlowFrame:
896
896
  def _add_cross_join_node(
897
897
  self,
898
898
  new_node_id: int,
899
- join_input: "transform_schema.CrossJoinInput",
899
+ join_input: transform_schema.CrossJoinInput,
900
900
  description: str,
901
- other: "FlowFrame",
901
+ other: FlowFrame,
902
902
  ) -> None:
903
903
  """Add a cross join node to the graph."""
904
904
  cross_join_settings = input_schema.NodeCrossJoin(
@@ -916,9 +916,9 @@ class FlowFrame:
916
916
  def _add_regular_join_node(
917
917
  self,
918
918
  new_node_id: int,
919
- join_input: "transform_schema.JoinInput",
919
+ join_input: transform_schema.JoinInput,
920
920
  description: str,
921
- other: "FlowFrame",
921
+ other: FlowFrame,
922
922
  ) -> None:
923
923
  """Add a regular join node to the graph."""
924
924
  join_settings = input_schema.NodeJoin(
@@ -935,7 +935,7 @@ class FlowFrame:
935
935
  )
936
936
  self.flow_graph.add_join(join_settings)
937
937
 
938
- def _add_number_of_records(self, new_node_id: int, description: str = None) -> "FlowFrame":
938
+ def _add_number_of_records(self, new_node_id: int, description: str = None) -> FlowFrame:
939
939
  node_number_of_records = input_schema.NodeRecordCount(
940
940
  flow_id=self.flow_graph.flow_id,
941
941
  node_id=new_node_id,
@@ -948,7 +948,7 @@ class FlowFrame:
948
948
  self.flow_graph.add_record_count(node_number_of_records)
949
949
  return self._create_child_frame(new_node_id)
950
950
 
951
- def rename(self, mapping: Mapping[str, str], *, strict: bool = True, description: str = None) -> "FlowFrame":
951
+ def rename(self, mapping: Mapping[str, str], *, strict: bool = True, description: str = None) -> FlowFrame:
952
952
  """Rename columns based on a mapping or function."""
953
953
  return self.select(
954
954
  [col(old_name).alias(new_name) for old_name, new_name in mapping.items()],
@@ -958,7 +958,7 @@ class FlowFrame:
958
958
 
959
959
  def select(
960
960
  self, *columns: str | Expr | Selector, description: str | None = None, _keep_missing: bool = False
961
- ) -> "FlowFrame":
961
+ ) -> FlowFrame:
962
962
  """
963
963
  Select columns from the frame.
964
964
  """
@@ -1041,7 +1041,7 @@ class FlowFrame:
1041
1041
  unique_raw_definitions = list(dict.fromkeys(collected_raw_definitions))
1042
1042
  definitions_section = "\n\n".join(unique_raw_definitions)
1043
1043
  final_code_for_node = (
1044
- definitions_section + "\\#─────SPLIT─────\n\n" + f"output_df = {polars_operation_code}"
1044
+ definitions_section + "\n#─────SPLIT─────\n\n" + f"output_df = {polars_operation_code}"
1045
1045
  )
1046
1046
  else:
1047
1047
  final_code_for_node = polars_operation_code
@@ -1068,7 +1068,7 @@ class FlowFrame:
1068
1068
  flowfile_formula: str | None = None,
1069
1069
  description: str | None = None,
1070
1070
  **constraints: Any,
1071
- ) -> "FlowFrame":
1071
+ ) -> FlowFrame:
1072
1072
  """
1073
1073
  Filter rows based on a predicate.
1074
1074
  """
@@ -1125,7 +1125,7 @@ class FlowFrame:
1125
1125
  unique_raw_definitions = list(dict.fromkeys(collected_raw_definitions)) # Order-preserving unique
1126
1126
  definitions_section = "\n\n".join(unique_raw_definitions)
1127
1127
  final_code_for_node = (
1128
- definitions_section + "\\#─────SPLIT─────\n\n" + f"output_df = {polars_operation_code}"
1128
+ definitions_section + "\n#─────SPLIT─────\n\n" + f"output_df = {polars_operation_code}"
1129
1129
  )
1130
1130
  else:
1131
1131
  final_code_for_node = polars_operation_code
@@ -1184,7 +1184,7 @@ class FlowFrame:
1184
1184
  description: str = None,
1185
1185
  convert_to_absolute_path: bool = True,
1186
1186
  **kwargs: Any,
1187
- ) -> "FlowFrame":
1187
+ ) -> FlowFrame:
1188
1188
  """
1189
1189
  Write the data to a Parquet file. Creates a standard Output node if only
1190
1190
  'path' and standard options are provided. Falls back to a Polars Code node
@@ -1275,7 +1275,7 @@ class FlowFrame:
1275
1275
  description: str = None,
1276
1276
  convert_to_absolute_path: bool = True,
1277
1277
  **kwargs: Any,
1278
- ) -> "FlowFrame":
1278
+ ) -> FlowFrame:
1279
1279
  new_node_id = generate_node_id()
1280
1280
  is_path_input = isinstance(file, (str, os.PathLike))
1281
1281
  if isinstance(file, os.PathLike):
@@ -1346,7 +1346,7 @@ class FlowFrame:
1346
1346
  connection_name: str | None = None,
1347
1347
  compression: Literal["snappy", "gzip", "brotli", "lz4", "zstd"] = "snappy",
1348
1348
  description: str | None = None,
1349
- ) -> "FlowFrame":
1349
+ ) -> FlowFrame:
1350
1350
  """
1351
1351
  Write the data frame to cloud storage in Parquet format.
1352
1352
 
@@ -1380,7 +1380,7 @@ class FlowFrame:
1380
1380
  delimiter: str = ";",
1381
1381
  encoding: CsvEncoding = "utf8",
1382
1382
  description: str | None = None,
1383
- ) -> "FlowFrame":
1383
+ ) -> FlowFrame:
1384
1384
  """
1385
1385
  Write the data frame to cloud storage in CSV format.
1386
1386
 
@@ -1415,7 +1415,7 @@ class FlowFrame:
1415
1415
  connection_name: str | None = None,
1416
1416
  write_mode: Literal["overwrite", "append"] = "overwrite",
1417
1417
  description: str | None = None,
1418
- ) -> "FlowFrame":
1418
+ ) -> FlowFrame:
1419
1419
  """
1420
1420
  Write the data frame to cloud storage in Delta Lake format.
1421
1421
 
@@ -1445,7 +1445,7 @@ class FlowFrame:
1445
1445
  path: str,
1446
1446
  connection_name: str | None = None,
1447
1447
  description: str | None = None,
1448
- ) -> "FlowFrame":
1448
+ ) -> FlowFrame:
1449
1449
  """
1450
1450
  Write the data frame to cloud storage in JSON format.
1451
1451
 
@@ -1523,7 +1523,7 @@ class FlowFrame:
1523
1523
  return self.data.collect(*args, **kwargs)
1524
1524
  return self.data
1525
1525
 
1526
- def _with_flowfile_formula(self, flowfile_formula: str, output_column_name, description: str = None) -> "FlowFrame":
1526
+ def _with_flowfile_formula(self, flowfile_formula: str, output_column_name, description: str = None) -> FlowFrame:
1527
1527
  new_node_id = generate_node_id()
1528
1528
  function_settings = input_schema.NodeFormula(
1529
1529
  flow_id=self.flow_graph.flow_id,
@@ -1552,7 +1552,7 @@ class FlowFrame:
1552
1552
  def limit(self, n: int, description: str = None):
1553
1553
  return self.head(n, description)
1554
1554
 
1555
- def cache(self) -> "FlowFrame":
1555
+ def cache(self) -> FlowFrame:
1556
1556
  setting_input = self.get_node_settings().setting_input
1557
1557
  setting_input.cache_results = True
1558
1558
  self.data.cache()
@@ -1572,7 +1572,7 @@ class FlowFrame:
1572
1572
  sort_columns: bool = False,
1573
1573
  separator: str = "_",
1574
1574
  description: str = None,
1575
- ) -> "FlowFrame":
1575
+ ) -> FlowFrame:
1576
1576
  """
1577
1577
  Pivot a DataFrame from long to wide format.
1578
1578
 
@@ -1694,7 +1694,7 @@ class FlowFrame:
1694
1694
  variable_name: str = "variable",
1695
1695
  value_name: str = "value",
1696
1696
  description: str = None,
1697
- ) -> "FlowFrame":
1697
+ ) -> FlowFrame:
1698
1698
  """
1699
1699
  Unpivot a DataFrame from wide to long format.
1700
1700
 
@@ -1795,12 +1795,12 @@ class FlowFrame:
1795
1795
 
1796
1796
  def concat(
1797
1797
  self,
1798
- other: "FlowFrame" | list["FlowFrame"],
1798
+ other: FlowFrame | list[FlowFrame],
1799
1799
  how: str = "vertical",
1800
1800
  rechunk: bool = False,
1801
1801
  parallel: bool = True,
1802
1802
  description: str = None,
1803
- ) -> "FlowFrame":
1803
+ ) -> FlowFrame:
1804
1804
  """
1805
1805
  Combine multiple FlowFrames into a single FlowFrame.
1806
1806
 
@@ -1913,7 +1913,7 @@ class FlowFrame:
1913
1913
 
1914
1914
  def _detect_cum_count_record_id(
1915
1915
  self, expr: Any, new_node_id: int, description: str | None = None
1916
- ) -> tuple[bool, Optional["FlowFrame"]]:
1916
+ ) -> tuple[bool, FlowFrame | None]:
1917
1917
  """
1918
1918
  Detect if the expression is a cum_count operation and use record_id if possible.
1919
1919
 
@@ -2032,7 +2032,7 @@ class FlowFrame:
2032
2032
  output_column_names: list[str] | None = None,
2033
2033
  description: str | None = None,
2034
2034
  **named_exprs: Expr | Any, # Allow Any for implicit lit conversion
2035
- ) -> "FlowFrame":
2035
+ ) -> FlowFrame:
2036
2036
  """
2037
2037
  Add or replace columns in the DataFrame.
2038
2038
  """
@@ -2110,7 +2110,7 @@ class FlowFrame:
2110
2110
  else:
2111
2111
  raise ValueError("Either exprs/named_exprs or flowfile_formulas with output_column_names must be provided")
2112
2112
 
2113
- def with_row_index(self, name: str = "index", offset: int = 0, description: str = None) -> "FlowFrame":
2113
+ def with_row_index(self, name: str = "index", offset: int = 0, description: str = None) -> FlowFrame:
2114
2114
  """
2115
2115
  Add a row index as the first column in the DataFrame.
2116
2116
 
@@ -2166,7 +2166,7 @@ class FlowFrame:
2166
2166
  columns: str | Column | Iterable[str | Column],
2167
2167
  *more_columns: str | Column,
2168
2168
  description: str = None,
2169
- ) -> "FlowFrame":
2169
+ ) -> FlowFrame:
2170
2170
  """
2171
2171
  Explode the dataframe to long format by exploding the given columns.
2172
2172
 
@@ -2219,10 +2219,10 @@ class FlowFrame:
2219
2219
 
2220
2220
  def fuzzy_match(
2221
2221
  self,
2222
- other: "FlowFrame",
2222
+ other: FlowFrame,
2223
2223
  fuzzy_mappings: list[FuzzyMapping],
2224
2224
  description: str = None,
2225
- ) -> "FlowFrame":
2225
+ ) -> FlowFrame:
2226
2226
  self._ensure_same_graph(other)
2227
2227
 
2228
2228
  # Step 3: Generate new node ID
@@ -2253,7 +2253,7 @@ class FlowFrame:
2253
2253
  delimiter: str = None,
2254
2254
  split_by_column: str = None,
2255
2255
  description: str = None,
2256
- ) -> "FlowFrame":
2256
+ ) -> FlowFrame:
2257
2257
  """
2258
2258
  Split text in a column into multiple rows.
2259
2259
 
@@ -2314,12 +2314,12 @@ class FlowFrame:
2314
2314
 
2315
2315
  def unique(
2316
2316
  self,
2317
- subset: Union[str, "Expr", list[Union[str, "Expr"]]] = None,
2317
+ subset: str | Expr | list[str | Expr] = None,
2318
2318
  *,
2319
2319
  keep: Literal["first", "last", "any", "none"] = "any",
2320
2320
  maintain_order: bool = False,
2321
2321
  description: str = None,
2322
- ) -> "FlowFrame":
2322
+ ) -> FlowFrame:
2323
2323
  """
2324
2324
  Drop duplicate rows from this dataframe.
2325
2325
 
flowfile_frame/lazy.py CHANGED
@@ -8,7 +8,7 @@ import polars as pl
8
8
  from flowfile_core.flowfile.flow_graph import FlowGraph
9
9
  from flowfile_frame.expr import Expr
10
10
  from flowfile_frame.flow_frame import FlowFrame, can_be_expr, generate_node_id
11
- from flowfile_frame.utils import _get_function_source
11
+ from flowfile_frame.callable_utils import resolve_callable
12
12
 
13
13
 
14
14
  def _determine_return_type(func_signature: inspect.Signature) -> Literal["FlowFrame", "Expr"]:
@@ -146,17 +146,8 @@ def _process_callable_arg(arg: Any) -> tuple[str, Any, bool, str | None]:
146
146
  Returns:
147
147
  Tuple of (repr_string, processed_arg, convertible_to_code, function_source)
148
148
  """
149
- function_source = None
150
- if hasattr(arg, "__name__") and arg.__name__ != "<lambda>":
151
- # Try to get function source
152
- try:
153
- function_source, _ = _get_function_source(arg)
154
- except:
155
- pass
156
- return arg.__name__, arg, True, function_source
157
- else:
158
- # For lambdas or callables without a proper name
159
- return repr(arg), arg, False, None
149
+ resolved = resolve_callable(arg)
150
+ return resolved.name, arg, resolved.resolved, resolved.source
160
151
 
161
152
 
162
153
  def _process_argument(arg: Any, can_be_expr: bool) -> tuple[str, Any, bool, str | None]:
@@ -1,14 +1,10 @@
1
1
  from collections.abc import Callable
2
2
  from functools import wraps
3
- from typing import TypeVar
4
3
 
5
4
  import polars as pl
6
5
 
6
+ from flowfile_frame.callable_utils import process_callable_args
7
7
  from flowfile_frame.config import logger
8
- from flowfile_frame.utils import _get_function_source
9
-
10
- T = TypeVar("T")
11
- FlowFrameT = TypeVar("FlowFrameT", bound="FlowFrame")
12
8
 
13
9
  PASSTHROUGH_METHODS = {
14
10
  "collect",
@@ -114,68 +110,13 @@ def create_lazyframe_method_wrapper(method_name: str, original_method: Callable)
114
110
  logger.debug("Warning, could not create a good node")
115
111
  return self.__class__(getattr(self.data, method_name)(arg.expr for arg in args), flow_graph=self.flow_graph)
116
112
 
117
- # Collect function sources and build representations
118
- function_sources = []
119
- args_representations = []
120
- kwargs_representations = []
121
-
122
- # Process positional arguments
123
- for arg in args:
124
- if callable(arg) and not isinstance(arg, type):
125
- # Try to get function source
126
- try:
127
- source, is_module_level = _get_function_source(arg)
128
- if source and hasattr(arg, "__name__") and arg.__name__ != "<lambda>":
129
- function_sources.append(source)
130
- # Use the function name in the representation
131
- args_representations.append(arg.__name__)
132
- else:
133
- # Fallback to repr if we can't get the source
134
- args_representations.append(repr(arg))
135
- except:
136
- args_representations.append(repr(arg))
137
- else:
138
- args_representations.append(repr(arg))
139
- # Process keyword arguments
140
- for key, value in kwargs.items():
141
- if callable(value) and not isinstance(value, type):
142
- # Try to get function source
143
- try:
144
- source, is_module_level = _get_function_source(value)
145
- if source and hasattr(value, "__name__") and value.__name__ != "<lambda>":
146
- function_sources.append(source)
147
- kwargs_representations.append(f"{key}={value.__name__}")
148
- else:
149
- kwargs_representations.append(f"{key}={repr(value)}")
150
- except:
151
- kwargs_representations.append(f"{key}={repr(value)}")
152
- else:
153
- kwargs_representations.append(f"{key}={repr(value)}")
154
-
155
- # Build parameter string
156
- args_str = ", ".join(args_representations)
157
- kwargs_str = ", ".join(kwargs_representations)
158
-
159
- if args_str and kwargs_str:
160
- params_str = f"{args_str}, {kwargs_str}"
161
- elif args_str:
162
- params_str = args_str
163
- elif kwargs_str:
164
- params_str = kwargs_str
165
- else:
166
- params_str = ""
113
+ processed = process_callable_args(args, kwargs)
167
114
 
168
115
  # Build the code
169
- operation_code = f"input_df.{method_name}({params_str})"
170
-
171
- if function_sources:
172
- unique_sources = []
173
- seen = set()
174
- for source in function_sources:
175
- if source not in seen:
176
- seen.add(source)
177
- unique_sources.append(source)
116
+ operation_code = f"input_df.{method_name}({processed.params_repr})"
178
117
 
118
+ if processed.function_sources:
119
+ unique_sources = list(dict.fromkeys(processed.function_sources))
179
120
  functions_section = "# Function definitions\n" + "\n\n".join(unique_sources)
180
121
  code = functions_section + "\n#─────SPLIT─────\n\noutput_df = " + operation_code
181
122
  else:
flowfile_frame/utils.py CHANGED
@@ -1,5 +1,3 @@
1
- import inspect
2
- import textwrap
3
1
  import uuid
4
2
  from collections.abc import Iterable
5
3
  from typing import Any
@@ -9,6 +7,13 @@ import polars as pl
9
7
  from flowfile_core.flowfile.flow_graph import FlowGraph
10
8
  from flowfile_core.schemas import schemas
11
9
 
10
+ # Re-export for backwards compatibility — canonical home is callable_utils
11
+ from flowfile_frame.callable_utils import ( # noqa: F401
12
+ _extract_lambda_source,
13
+ _get_function_source,
14
+ _is_safely_representable,
15
+ )
16
+
12
17
 
13
18
  def _is_iterable(obj: Any) -> bool:
14
19
  # Avoid treating strings as iterables in this context
@@ -43,35 +48,6 @@ def get_pl_expr_from_expr(expr: Any) -> pl.Expr:
43
48
  return expr.expr
44
49
 
45
50
 
46
- def _get_function_source(func):
47
- """
48
- Get the source code of a function if possible.
49
-
50
- Returns:
51
- tuple: (source_code, is_module_level)
52
- """
53
- try:
54
- # Try to get the source code
55
- source = inspect.getsource(func)
56
-
57
- # Check if it's a lambda
58
- if func.__name__ == "<lambda>":
59
- # Extract just the lambda expression
60
- # This is tricky as getsource returns the entire line
61
- return None, False
62
-
63
- # Check if it's a module-level function
64
- is_module_level = func.__code__.co_flags & 0x10 == 0
65
-
66
- # Dedent the source to remove any indentation
67
- source = textwrap.dedent(source)
68
-
69
- return source, is_module_level
70
- except (OSError, TypeError):
71
- # Can't get source (e.g., built-in function, C extension)
72
- return None, False
73
-
74
-
75
51
  def ensure_inputs_as_iterable(inputs: Any | Iterable[Any]) -> list[Any]:
76
52
  """Convert inputs to list, treating strings as single items."""
77
53
  if inputs is None or (hasattr(inputs, "__len__") and len(inputs) == 0):
@@ -99,7 +75,12 @@ def create_flow_graph(flow_id: int = None) -> FlowGraph:
99
75
  """
100
76
  if flow_id is None:
101
77
  flow_id = _generate_id()
102
- flow_settings = schemas.FlowSettings(flow_id=flow_id, name=f"Flow_{flow_id}", path=f"flow_{flow_id}")
78
+ flow_settings = schemas.FlowSettings(
79
+ flow_id=flow_id,
80
+ name=f"Flow_{flow_id}",
81
+ path=f"flow_{flow_id}",
82
+ track_history=False, # Disable undo/redo history for flowfile_frame
83
+ )
103
84
  flow_graph = FlowGraph(flow_settings=flow_settings)
104
85
  flow_graph.flow_settings.execution_location = (
105
86
  "local" # always create a local frame so that the run time does not attempt to use the flowfile_worker process
flowfile_worker/funcs.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import io
2
2
  import logging
3
3
  import os
4
- from base64 import encodebytes
5
4
  from collections.abc import Callable
6
5
  from logging import Logger
7
6
  from multiprocessing import Array, Queue, Value
@@ -56,7 +55,8 @@ def fuzzy_join_task(
56
55
  lf = pl.scan_ipc(file_path)
57
56
  number_of_records = collect_lazy_frame(lf.select(pl.len()))[0, 0]
58
57
  flowfile_logger.info(f"Number of records after fuzzy match: {number_of_records}")
59
- queue.put(encodebytes(lf.serialize()))
58
+ # Put raw bytes in queue - encoding happens at the transport boundary
59
+ queue.put(lf.serialize())
60
60
 
61
61
 
62
62
  def process_and_cache(
@@ -126,7 +126,8 @@ def store(
126
126
  lf = pl.scan_ipc(file_path)
127
127
  number_of_records = collect_lazy_frame(lf.select(pl.len()))[0, 0]
128
128
  flowfile_logger.info(f"Number of records processed: {number_of_records}")
129
- queue.put(encodebytes(lf.serialize()))
129
+ # Put raw bytes in queue - encoding happens at the transport boundary
130
+ queue.put(lf.serialize())
130
131
 
131
132
 
132
133
  def calculate_schema_logic(
@@ -432,4 +433,5 @@ def generic_task(
432
433
  lf = pl.scan_ipc(file_path)
433
434
  number_of_records = collect_lazy_frame(lf.select(pl.len()))[0, 0]
434
435
  flowfile_logger.info(f"Number of records processed: {number_of_records}")
435
- queue.put(encodebytes(lf.serialize()))
436
+ # Put raw bytes in queue - encoding happens at the transport boundary
437
+ queue.put(lf.serialize())
flowfile_worker/main.py CHANGED
@@ -8,6 +8,7 @@ from fastapi import FastAPI
8
8
  from flowfile_worker import mp_context
9
9
  from flowfile_worker.configs import FLOWFILE_CORE_URI, SERVICE_HOST, SERVICE_PORT, logger
10
10
  from flowfile_worker.routes import router
11
+ from flowfile_worker.streaming import streaming_router
11
12
  from shared.storage_config import storage
12
13
 
13
14
  should_exit = False
@@ -40,6 +41,7 @@ async def shutdown_handler(app: FastAPI):
40
41
 
41
42
  app = FastAPI(lifespan=shutdown_handler)
42
43
  app.include_router(router)
44
+ app.include_router(streaming_router)
43
45
 
44
46
 
45
47
  @app.post("/shutdown")
flowfile_worker/models.py CHANGED
@@ -1,12 +1,28 @@
1
- from base64 import decodebytes
2
- from typing import Any, Literal
1
+ from base64 import b64decode, b64encode
2
+ from typing import Annotated, Any, Literal
3
3
 
4
4
  from pl_fuzzy_frame_match import FuzzyMapping
5
- from pydantic import BaseModel
5
+ from pydantic import BaseModel, BeforeValidator, PlainSerializer
6
6
 
7
7
  from flowfile_worker.external_sources.s3_source.models import CloudStorageWriteSettings
8
8
  from flowfile_worker.external_sources.sql_source.models import DatabaseWriteSettings
9
9
 
10
+
11
+ # Custom type for bytes that serializes to/from base64 string in JSON
12
+ def _decode_bytes(v: Any) -> bytes:
13
+ if isinstance(v, bytes):
14
+ return v
15
+ if isinstance(v, str):
16
+ return b64decode(v)
17
+ raise ValueError(f"Expected bytes or base64 string, got {type(v)}")
18
+
19
+
20
+ Base64Bytes = Annotated[
21
+ bytes,
22
+ BeforeValidator(_decode_bytes),
23
+ PlainSerializer(lambda x: b64encode(x).decode('ascii'), return_type=str),
24
+ ]
25
+
10
26
  OperationType = Literal[
11
27
  "store",
12
28
  "calculate_schema",
@@ -21,12 +37,13 @@ ResultType = Literal["polars", "other"]
21
37
 
22
38
 
23
39
  class PolarsOperation(BaseModel):
24
- operation: bytes
40
+ operation: Base64Bytes # Automatically encodes/decodes base64 for JSON
25
41
  flowfile_flow_id: int | None = 1
26
42
  flowfile_node_id: int | str | None = -1
27
43
 
28
44
  def polars_serializable_object(self):
29
- return decodebytes(self.operation)
45
+ # Operation is raw bytes (auto-decoded from base64 if received as JSON)
46
+ return self.operation
30
47
 
31
48
 
32
49
  class PolarsScript(PolarsOperation):
@@ -40,7 +57,7 @@ class PolarsScriptSample(PolarsScript):
40
57
 
41
58
 
42
59
  class PolarsScriptWrite(BaseModel):
43
- operation: bytes
60
+ operation: Base64Bytes # Automatically encodes/decodes base64 for JSON
44
61
  data_type: str
45
62
  path: str
46
63
  write_mode: str
@@ -50,14 +67,16 @@ class PolarsScriptWrite(BaseModel):
50
67
  flowfile_node_id: int | str | None = -1
51
68
 
52
69
  def polars_serializable_object(self):
53
- return decodebytes(self.operation)
70
+ # Operation is raw bytes (auto-decoded from base64 if received as JSON)
71
+ return self.operation
54
72
 
55
73
 
56
74
  class DatabaseScriptWrite(DatabaseWriteSettings):
57
- operation: bytes
75
+ operation: Base64Bytes # Automatically encodes/decodes base64 for JSON
58
76
 
59
77
  def polars_serializable_object(self):
60
- return decodebytes(self.operation)
78
+ # Operation is raw bytes (auto-decoded from base64 if received as JSON)
79
+ return self.operation
61
80
 
62
81
  def get_database_write_settings(self) -> DatabaseWriteSettings:
63
82
  """
@@ -75,10 +94,11 @@ class DatabaseScriptWrite(DatabaseWriteSettings):
75
94
 
76
95
 
77
96
  class CloudStorageScriptWrite(CloudStorageWriteSettings):
78
- operation: bytes
97
+ operation: Base64Bytes # Automatically encodes/decodes base64 for JSON
79
98
 
80
99
  def polars_serializable_object(self):
81
- return decodebytes(self.operation)
100
+ # Operation is raw bytes (auto-decoded from base64 if received as JSON)
101
+ return self.operation
82
102
 
83
103
  def get_cloud_storage_write_settings(self) -> CloudStorageWriteSettings:
84
104
  """