Flowfile 0.5.4__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.
- flowfile/__main__.py +94 -1
- flowfile/api.py +8 -6
- flowfile/web/static/assets/{AdminView-f9847d67.js → AdminView-C4K1DdHI.js} +28 -33
- flowfile/web/static/assets/{CloudConnectionView-faace55b.js → CloudConnectionView-BZbPvPUL.js} +39 -50
- flowfile/web/static/assets/{CloudStorageReader-24c54524.css → CloudStorageReader-BDByiqPI.css} +25 -25
- flowfile/web/static/assets/{CloudStorageReader-d86ecaa7.js → CloudStorageReader-DLVukNJ7.js} +30 -35
- flowfile/web/static/assets/{CloudStorageWriter-0f4d9a44.js → CloudStorageWriter-Bfi-C1QW.js} +32 -37
- flowfile/web/static/assets/{CloudStorageWriter-60547855.css → CloudStorageWriter-y8jL8yjG.css} +24 -24
- flowfile/web/static/assets/{ColumnActionInput-f4189ae0.js → ColumnActionInput-BpiCApw9.js} +7 -12
- flowfile/web/static/assets/{ColumnSelector-e66b33da.js → ColumnSelector-CEAwedI7.js} +1 -2
- flowfile/web/static/assets/ContextMenu-CdojQu0w.js +9 -0
- flowfile/web/static/assets/ContextMenu-D12mhsy1.js +9 -0
- flowfile/web/static/assets/ContextMenu-EWUR98va.js +9 -0
- flowfile/web/static/assets/{ContextMenu.vue_vue_type_script_setup_true_lang-a1bd6314.js → ContextMenu.vue_vue_type_script_setup_true_lang-I4rXXd6G.js} +4 -5
- flowfile/web/static/assets/{CrossJoin-24694b8f.js → CrossJoin-BOFfxkJO.js} +19 -18
- flowfile/web/static/assets/{CrossJoin-71b4cc10.css → CrossJoin-Cmbyt9im.css} +18 -18
- flowfile/web/static/assets/{CustomNode-569d45ff.js → CustomNode-Bhpezobq.js} +12 -17
- flowfile/web/static/assets/{DatabaseConnectionSettings-cfc08938.js → DatabaseConnectionSettings-Dw3bSJKB.js} +10 -11
- flowfile/web/static/assets/{DatabaseReader-5bf8c75b.css → DatabaseReader-D6pUNUCs.css} +21 -21
- flowfile/web/static/assets/{DatabaseReader-701feabb.js → DatabaseReader-m87ghlw0.js} +36 -34
- flowfile/web/static/assets/{DatabaseView-0482e5b5.js → DatabaseView-CisSAtpe.js} +30 -38
- flowfile/web/static/assets/{DatabaseWriter-16721989.js → DatabaseWriter-Bbj9JLdL.js} +33 -35
- flowfile/web/static/assets/{DatabaseWriter-bdcf2c8b.css → DatabaseWriter-RBqdFLj8.css} +17 -17
- flowfile/web/static/assets/{DesignerView-f64749fb.js → DesignerView-DemDevTQ.js} +1841 -2090
- flowfile/web/static/assets/{DesignerView-49abb835.css → DesignerView-Dm6OzlIc.css} +244 -202
- flowfile/web/static/assets/{DocumentationView-61bd2990.js → DocumentationView-BrC1ZR3H.js} +3 -4
- flowfile/web/static/assets/{ExploreData-e2735b13.js → ExploreData-BMKcDuRb.js} +8 -10
- flowfile/web/static/assets/{ExternalSource-2535c3b2.js → ExternalSource-BXrNNS-f.js} +40 -42
- flowfile/web/static/assets/{ExternalSource-7ac7373f.css → ExternalSource-NB6WVl5R.css} +14 -14
- flowfile/web/static/assets/{Filter-2cdbc93c.js → Filter-C2MjsN6P.js} +36 -33
- flowfile/web/static/assets/{Filter-7494ea97.css → Filter-DCMGGuGC.css} +9 -9
- flowfile/web/static/assets/{Formula-53d58c43.css → Formula-BYafbDj8.css} +4 -4
- flowfile/web/static/assets/{Formula-fcda3c2c.js → Formula-ufuy4mVD.js} +27 -26
- flowfile/web/static/assets/{FuzzyMatch-ad6361d6.css → FuzzyMatch-BGJAwgd0.css} +42 -42
- flowfile/web/static/assets/{FuzzyMatch-f8d3b7d3.js → FuzzyMatch-BOHODq3h.js} +36 -38
- flowfile/web/static/assets/{GraphSolver-72eaa695.js → GraphSolver-B6ZzpNGO.js} +23 -21
- flowfile/web/static/assets/{GraphSolver-4b4d7db9.css → GraphSolver-DFN83sj3.css} +4 -4
- flowfile/web/static/assets/{GroupBy-8aa0598b.js → GroupBy-B9BRNcfe.js} +30 -29
- flowfile/web/static/assets/{Sort-4abb7fae.css → GroupBy-x4ooP5np.css} +1 -1
- flowfile/web/static/assets/Join-Bx_g5bZz.css +118 -0
- flowfile/web/static/assets/{Join-e40f0ffa.js → Join-DsBEy1IH.js} +48 -43
- flowfile/web/static/assets/{LoginView-5111c9ae.js → LoginView-Ct0rhdcO.js} +1 -2
- flowfile/web/static/assets/{ManualInput-3702e677.css → ManualInput-DlZmtMdt.css} +48 -48
- flowfile/web/static/assets/{ManualInput-9b6f3224.js → ManualInput-bC4BUgnG.js} +85 -44
- flowfile/web/static/assets/{MultiSelect-ef28e19e.js → MultiSelect-DIQ8PuTC.js} +2 -2
- flowfile/web/static/assets/{MultiSelect.vue_vue_type_script_setup_true_lang-83b3bbfd.js → MultiSelect.vue_vue_type_script_setup_true_lang-BefHfqTI.js} +1 -1
- flowfile/web/static/assets/{NodeDesigner-d2b7ee2b.js → NodeDesigner-D39yzr2k.js} +178 -208
- flowfile/web/static/assets/{NodeDesigner-94cd4dd3.css → NodeDesigner-R0l6sYyY.css} +76 -76
- flowfile/web/static/assets/{NumericInput-1d789794.js → NumericInput-DMSX3oOr.js} +2 -2
- flowfile/web/static/assets/{NumericInput.vue_vue_type_script_setup_true_lang-7775f83e.js → NumericInput.vue_vue_type_script_setup_true_lang-d0YlVHAl.js} +1 -1
- flowfile/web/static/assets/{Output-cefef801.js → Output-D0VoXGcW.js} +26 -34
- flowfile/web/static/assets/{Output-692dd25d.css → Output-DsmglIDy.css} +5 -5
- flowfile/web/static/assets/{Pivot-bab1b75b.js → Pivot-BnMB4sEe.js} +26 -26
- flowfile/web/static/assets/{Pivot-0eda81b4.css → Pivot-qKTyWxop.css} +4 -4
- flowfile/web/static/assets/{PivotValidation-fba09336.js → PivotValidation-B2lWvugt.js} +7 -9
- flowfile/web/static/assets/{PivotValidation-e7941f91.js → PivotValidation-BPlhRjpL.js} +7 -9
- flowfile/web/static/assets/{PolarsCode-740e40fa.js → PolarsCode-5h0tHnWR.js} +22 -20
- flowfile/web/static/assets/PopOver-BHpt5rsj.js +134 -0
- flowfile/web/static/assets/{PopOver-d96599db.css → PopOver-CyYM4-rV.css} +1 -1
- flowfile/web/static/assets/{Read-90f366bc.css → Read-DJxkrTb_.css} +10 -10
- flowfile/web/static/assets/Read-TsLEFh3B.js +227 -0
- flowfile/web/static/assets/{RecordCount-ffc71eca.js → RecordCount-DkVixq9v.js} +18 -17
- flowfile/web/static/assets/{RecordId-a70bb8df.js → RecordId-C2UEGlCf.js} +42 -39
- flowfile/web/static/assets/{SQLQueryComponent-15a421f5.js → SQLQueryComponent-Dr5KMoD3.js} +2 -3
- flowfile/web/static/assets/{Sample-6c26afc7.js → Sample-Cb3eQNmd.js} +30 -30
- flowfile/web/static/assets/{SecretSelector-ceed9496.js → SecretSelector-De2L2bSx.js} +3 -4
- flowfile/web/static/assets/{SecretsView-214d255a.js → SecretsView-CheC9BPV.js} +13 -16
- flowfile/web/static/assets/{Select-8fc29999.js → Select-CI8TloRs.js} +41 -36
- flowfile/web/static/assets/{SettingsSection-9f0d1725.js → SettingsSection-B39ulIiI.js} +1 -2
- flowfile/web/static/assets/{SettingsSection-83090218.js → SettingsSection-BiCc7S9h.js} +1 -2
- flowfile/web/static/assets/{SettingsSection-3f70e4c3.js → SettingsSection-CITK_R7o.js} +2 -3
- flowfile/web/static/assets/{SettingsSection-26fe48d4.css → SettingsSection-D2GgY-Aq.css} +4 -4
- flowfile/web/static/assets/{SetupView-3fa0aa03.js → SetupView-C1aXRDvp.js} +3 -4
- flowfile/web/static/assets/{SetupView-e2da3442.css → SetupView-CI1nd-5Z.css} +38 -38
- flowfile/web/static/assets/{SingleSelect-a4a568cb.js → SingleSelect-Kr_hz90m.js} +2 -2
- flowfile/web/static/assets/{SingleSelect.vue_vue_type_script_setup_true_lang-c8ebdd33.js → SingleSelect.vue_vue_type_script_setup_true_lang-Rxht5Z5N.js} +1 -1
- flowfile/web/static/assets/{SliderInput-be533e71.js → SliderInput-CLqpCxCb.js} +1 -2
- flowfile/web/static/assets/{GroupBy-5792782d.css → Sort-BIt2kc_p.css} +1 -1
- flowfile/web/static/assets/{Sort-154dad81.js → Sort-Dnw_J6Qi.js} +25 -25
- flowfile/web/static/assets/{TextInput-454e2bda.js → TextInput-wdlunIZC.js} +2 -2
- flowfile/web/static/assets/{TextInput.vue_vue_type_script_setup_true_lang-e86510d0.js → TextInput.vue_vue_type_script_setup_true_lang-Bcj3ywzv.js} +1 -1
- flowfile/web/static/assets/{TextToRows-ea73433d.js → TextToRows-BhtyGWPq.js} +42 -49
- flowfile/web/static/assets/{TextToRows-12afb4f4.css → TextToRows-DivDOLDx.css} +9 -9
- flowfile/web/static/assets/{ToggleSwitch-9d7b30f1.js → ToggleSwitch-B-6WzfFf.js} +2 -2
- flowfile/web/static/assets/{ToggleSwitch.vue_vue_type_script_setup_true_lang-00f2580e.js → ToggleSwitch.vue_vue_type_script_setup_true_lang-Cj8LqT-b.js} +1 -1
- flowfile/web/static/assets/{UnavailableFields-b72a2c72.js → UnavailableFields-Yf6XSqFB.js} +2 -3
- flowfile/web/static/assets/{Union-1e44f263.js → Union-CwpjeKYC.js} +20 -23
- flowfile/web/static/assets/{Unpivot-b6ad6427.css → Union-DQJcpp3-.css} +6 -6
- flowfile/web/static/assets/{Unique-a3bc6d0a.js → Unique-25v3urqH.js} +75 -74
- flowfile/web/static/assets/{Union-d6a8d7d5.css → Unpivot-Deqh1gtI.css} +6 -6
- flowfile/web/static/assets/{Unpivot-e27935fc.js → Unpivot-sYcTTXrq.js} +34 -27
- flowfile/web/static/assets/{UnpivotValidation-72497680.js → UnpivotValidation-C5DDEKY2.js} +5 -7
- flowfile/web/static/assets/VueGraphicWalker-B8l1_Z92.js +131 -0
- flowfile/web/static/assets/VueGraphicWalker-Da_1-3me.css +21 -0
- flowfile/web/static/assets/{api-a2102880.js → api-C0LvF-0C.js} +1 -1
- flowfile/web/static/assets/{api-f75042b0.js → api-DaC83EO_.js} +1 -1
- flowfile/web/static/assets/client-C8Ygr6Gb.js +42 -0
- flowfile/web/static/assets/{dropDown-2798a109.js → dropDown-D5YXaPRR.js} +7 -12
- flowfile/web/static/assets/{fullEditor-cf7d7d93.js → fullEditor-BVYnWm05.js} +300 -18
- flowfile/web/static/assets/genericNodeSettings-2wAu-QKn.css +75 -0
- flowfile/web/static/assets/genericNodeSettings-BBtW_Cpz.js +590 -0
- flowfile/web/static/assets/{VueGraphicWalker-d9ab70a3.js → graphic-walker.es-VrK6vdGE.js} +92305 -89751
- flowfile/web/static/assets/index-BCJxPfM5.js +6693 -0
- flowfile/web/static/assets/{index-f0a6e5a5.js → index-CHPMUR0d.js} +150 -170
- flowfile/web/static/assets/index-DPkoZWq8.js +32 -0
- flowfile/web/static/assets/index-DnW_KC_I.js +277 -0
- flowfile/web/static/assets/index-UFXyfirV.css +10797 -0
- flowfile/web/static/assets/index-bcuE0Z0p.js +87456 -0
- flowfile/web/static/assets/{node.types-2c15bb7e.js → node.types-Dl4gtSW9.js} +2 -2
- flowfile/web/static/assets/{outputCsv-3c1757e8.js → outputCsv-BELuBiJZ.js} +2 -3
- flowfile/web/static/assets/outputCsv-CdGkv-fN.css +2581 -0
- flowfile/web/static/assets/{outputExcel-686e1f48.js → outputExcel-D0TTNM79.js} +1 -2
- flowfile/web/static/assets/{outputParquet-df28faa7.js → outputParquet-Cz9EbRHj.js} +1 -2
- flowfile/web/static/assets/{readCsv-e37eee21.js → readCsv-7bd3kUMI.js} +1 -2
- flowfile/web/static/assets/{readExcel-a13f14bb.js → readExcel-Cq8CCwIv.js} +3 -4
- flowfile/web/static/assets/{readParquet-c5244ad5.css → readParquet-CRDmBrsp.css} +4 -4
- flowfile/web/static/assets/{readParquet-344cf746.js → readParquet-DjR4mRaj.js} +4 -5
- flowfile/web/static/assets/{secrets.api-ae198c5c.js → secrets.api-C9o2KE5V.js} +1 -1
- flowfile/web/static/assets/{selectDynamic-6b4b0767.js → selectDynamic-Bl5FVsME.js} +5 -8
- flowfile/web/static/assets/useNodeSettings-dMS9zmh_.js +69 -0
- flowfile/web/static/assets/{vue-codemirror.esm-31ba0e0b.js → vue-codemirror.esm-CwaYwln0.js} +3469 -3064
- flowfile/web/static/assets/{vue-content-loader.es-4469c8ff.js → vue-content-loader.es-CMoRXo7N.js} +3 -3
- flowfile/web/static/index.html +2 -3
- {flowfile-0.5.4.dist-info → flowfile-0.6.1.dist-info}/METADATA +2 -1
- flowfile-0.6.1.dist-info/RECORD +417 -0
- {flowfile-0.5.4.dist-info → flowfile-0.6.1.dist-info}/WHEEL +1 -1
- flowfile_core/auth/password.py +1 -0
- flowfile_core/database/init_db.py +7 -5
- flowfile_core/fileExplorer/funcs.py +2 -2
- flowfile_core/flowfile/code_generator/code_generator.py +13 -11
- flowfile_core/flowfile/filter_expressions.py +327 -0
- flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +61 -59
- flowfile_core/flowfile/flow_data_engine/flow_file_column/type_registry.py +3 -29
- flowfile_core/flowfile/flow_data_engine/flow_file_column/utils.py +45 -14
- flowfile_core/flowfile/flow_data_engine/subprocess_operations/models.py +20 -3
- flowfile_core/flowfile/flow_data_engine/subprocess_operations/streaming.py +206 -0
- flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +158 -24
- flowfile_core/flowfile/flow_graph.py +504 -190
- flowfile_core/flowfile/flow_node/__init__.py +32 -0
- flowfile_core/flowfile/flow_node/executor.py +404 -0
- flowfile_core/flowfile/flow_node/flow_node.py +207 -106
- flowfile_core/flowfile/flow_node/models.py +40 -0
- flowfile_core/flowfile/flow_node/output_field_config_applier.py +217 -0
- flowfile_core/flowfile/flow_node/schema_utils.py +78 -0
- flowfile_core/flowfile/flow_node/state.py +155 -0
- flowfile_core/flowfile/history_manager.py +401 -0
- flowfile_core/flowfile/manage/compatibility_enhancements.py +9 -0
- flowfile_core/flowfile/manage/io_flowfile.py +3 -1
- flowfile_core/flowfile/sources/external_sources/sql_source/models.py +20 -4
- flowfile_core/flowfile/util/execution_orderer.py +89 -36
- flowfile_core/main.py +2 -4
- flowfile_core/routes/auth.py +8 -9
- flowfile_core/routes/routes.py +320 -101
- flowfile_core/routes/user_defined_components.py +18 -16
- flowfile_core/schemas/history_schema.py +220 -0
- flowfile_core/schemas/input_schema.py +130 -6
- flowfile_core/schemas/schemas.py +9 -0
- flowfile_core/schemas/transform_schema.py +27 -5
- flowfile_core/schemas/yaml_types.py +23 -5
- flowfile_frame/adding_expr.py +18 -126
- flowfile_frame/callable_utils.py +261 -0
- flowfile_frame/database/connection_manager.py +0 -1
- flowfile_frame/expr.py +8 -4
- flowfile_frame/flow_frame.py +41 -41
- flowfile_frame/lazy.py +3 -12
- flowfile_frame/lazy_methods.py +5 -64
- flowfile_frame/utils.py +13 -32
- flowfile_worker/funcs.py +6 -4
- flowfile_worker/main.py +2 -0
- flowfile_worker/models.py +31 -11
- flowfile_worker/routes.py +60 -35
- flowfile_worker/spawner.py +7 -1
- flowfile_worker/streaming.py +335 -0
- flowfile/web/static/assets/ContextMenu-49463352.js +0 -9
- flowfile/web/static/assets/ContextMenu-dd5f3f25.js +0 -9
- flowfile/web/static/assets/ContextMenu-f709b884.js +0 -9
- flowfile/web/static/assets/Join-28b5e18f.css +0 -109
- flowfile/web/static/assets/PopOver-862d7e28.js +0 -939
- flowfile/web/static/assets/Read-225cc63f.js +0 -222
- flowfile/web/static/assets/VueGraphicWalker-430f0b86.css +0 -6
- flowfile/web/static/assets/database_reader-ce1e55f3.svg +0 -24
- flowfile/web/static/assets/database_writer-b4ad0753.svg +0 -23
- flowfile/web/static/assets/element-icons-9c88a535.woff +0 -0
- flowfile/web/static/assets/element-icons-de5eb258.ttf +0 -0
- flowfile/web/static/assets/genericNodeSettings-14eac1c3.js +0 -137
- flowfile/web/static/assets/genericNodeSettings-3b2507ea.css +0 -46
- flowfile/web/static/assets/index-387a6f18.js +0 -60752
- flowfile/web/static/assets/index-6b367bb5.js +0 -38
- flowfile/web/static/assets/index-e96ab018.css +0 -10466
- flowfile/web/static/assets/nodeInput-ed2ae8d7.js +0 -2
- flowfile/web/static/assets/outputCsv-b9a072af.css +0 -2499
- flowfile-0.5.4.dist-info/RECORD +0 -407
- /flowfile/web/static/assets/{AdminView-f53bad23.css → AdminView-B2Dthl3u.css} +0 -0
- /flowfile/web/static/assets/{CloudConnectionView-cf85f943.css → CloudConnectionView-BdFYGWV7.css} +0 -0
- /flowfile/web/static/assets/{ColumnActionInput-c44b7aee.css → ColumnActionInput-dCasSIC9.css} +0 -0
- /flowfile/web/static/assets/{ColumnSelector-371637fb.css → ColumnSelector-j6sEOjo1.css} +0 -0
- /flowfile/web/static/assets/{CustomNode-edb9b939.css → CustomNode-VPlajG0j.css} +0 -0
- /flowfile/web/static/assets/{DatabaseConnectionSettings-c20a1e16.css → DatabaseConnectionSettings-B78hXYgu.css} +0 -0
- /flowfile/web/static/assets/{DatabaseView-6655afd6.css → DatabaseView-B-_adk1s.css} +0 -0
- /flowfile/web/static/assets/{DocumentationView-9ea6e871.css → DocumentationView-CL7iipFL.css} +0 -0
- /flowfile/web/static/assets/{ExploreData-10c5acc8.css → ExploreData-DHjv0Plr.css} +0 -0
- /flowfile/web/static/assets/{LoginView-d325d632.css → LoginView-DN1BXY3e.css} +0 -0
- /flowfile/web/static/assets/{PivotValidation-0e905b1a.css → PivotValidation-DK-FARWe.css} +0 -0
- /flowfile/web/static/assets/{PivotValidation-41b57ad6.css → PivotValidation-FUa9F47u.css} +0 -0
- /flowfile/web/static/assets/{PolarsCode-2b1f1f23.css → PolarsCode-G-gRSrSc.css} +0 -0
- /flowfile/web/static/assets/{SQLQueryComponent-edb90b98.css → SQLQueryComponent-oAbWw0r-.css} +0 -0
- /flowfile/web/static/assets/{SecretSelector-6329f743.css → SecretSelector-CJSadIZx.css} +0 -0
- /flowfile/web/static/assets/{SecretsView-aa291340.css → SecretsView-DbzIRAba.css} +0 -0
- /flowfile/web/static/assets/{SettingsSection-8f980839.css → SettingsSection-BGcJnH6q.css} +0 -0
- /flowfile/web/static/assets/{SettingsSection-07fbbc39.css → SettingsSection-DDWn_EGW.css} +0 -0
- /flowfile/web/static/assets/{SliderInput-f2e4f23c.css → SliderInput-BRk-q_Dk.css} +0 -0
- /flowfile/web/static/assets/{UnavailableFields-394a1f78.css → UnavailableFields-DRKDImKe.css} +0 -0
- /flowfile/web/static/assets/{Unique-2b705521.css → Unique-Absb0aON.css} +0 -0
- /flowfile/web/static/assets/{UnpivotValidation-d5ca3b7b.css → UnpivotValidation-DSBkFgS-.css} +0 -0
- /flowfile/web/static/assets/{airbyte-292aa232.png → airbyte-W0xvIXwZ.png} +0 -0
- /flowfile/web/static/assets/{cloud_storage_reader-aa1415d6.png → cloud_storage_reader-3GpSCk90.png} +0 -0
- /flowfile/web/static/assets/{cross_join-d30c0290.png → cross_join-B0qpgYoV.png} +0 -0
- /flowfile/web/static/assets/{dropDown-1d6acbd9.css → dropDown-CE0VF5_P.css} +0 -0
- /flowfile/web/static/assets/{explore_data-8a0a2861.png → explore_data-tX6olPPL.png} +0 -0
- /flowfile/web/static/assets/{fa-brands-400-808443ae.ttf → fa-brands-400-D1LuMI3I.ttf} +0 -0
- /flowfile/web/static/assets/{fa-brands-400-d7236a19.woff2 → fa-brands-400-D_cYUPeE.woff2} +0 -0
- /flowfile/web/static/assets/{fa-regular-400-e3456d12.woff2 → fa-regular-400-BjRzuEpd.woff2} +0 -0
- /flowfile/web/static/assets/{fa-regular-400-54cf6086.ttf → fa-regular-400-DZaxPHgR.ttf} +0 -0
- /flowfile/web/static/assets/{fa-solid-900-aa759986.woff2 → fa-solid-900-CTAAxXor.woff2} +0 -0
- /flowfile/web/static/assets/{fa-solid-900-d2f05935.ttf → fa-solid-900-D0aA9rwL.ttf} +0 -0
- /flowfile/web/static/assets/{fa-v4compatibility-0ce9033c.woff2 → fa-v4compatibility-C9RhG_FT.woff2} +0 -0
- /flowfile/web/static/assets/{fa-v4compatibility-30f6abf6.ttf → fa-v4compatibility-CCth-dXg.ttf} +0 -0
- /flowfile/web/static/assets/{filter-d7708bda.png → filter-WRdZyUOw.png} +0 -0
- /flowfile/web/static/assets/{formula-eeeb1611.png → formula-CgM7uHVI.png} +0 -0
- /flowfile/web/static/assets/{fullEditor-fe9f7e18.css → fullEditor-CmDI7T9F.css} +0 -0
- /flowfile/web/static/assets/{fuzzy_match-40c161b2.png → fuzzy_match-Yon3k5Tc.png} +0 -0
- /flowfile/web/static/assets/{graph_solver-8b7888b8.png → graph_solver-BlMrBttD.png} +0 -0
- /flowfile/web/static/assets/{group_by-80561fc3.png → group_by-Gici0CSS.png} +0 -0
- /flowfile/web/static/assets/{input_data-ab2eb678.png → input_data-BRdGecLc.png} +0 -0
- /flowfile/web/static/assets/{join-349043ae.png → join-BITWRu73.png} +0 -0
- /flowfile/web/static/assets/{manual_input-ae98f31d.png → manual_input-CFvo_EUS.png} +0 -0
- /flowfile/web/static/assets/{old_join-5d0eb604.png → old_join-B9bkpPqv.png} +0 -0
- /flowfile/web/static/assets/{output-06ec0371.png → output-Dp7-ZpC4.png} +0 -0
- /flowfile/web/static/assets/{outputExcel-f5d272b2.css → outputExcel-CKgRe2iT.css} +0 -0
- /flowfile/web/static/assets/{outputParquet-54597c3c.css → outputParquet-d7j407cK.css} +0 -0
- /flowfile/web/static/assets/{pivot-9660df51.png → pivot-DSxKhNlD.png} +0 -0
- /flowfile/web/static/assets/{polars_code-05ce5dc6.png → polars_code-DxiztZ1c.png} +0 -0
- /flowfile/web/static/assets/{readCsv-3bfac4c3.css → readCsv-BG-1Jilp.css} +0 -0
- /flowfile/web/static/assets/{readExcel-3db6b763.css → readExcel-DBQXKPtC.css} +0 -0
- /flowfile/web/static/assets/{record_count-dab44eb5.png → record_count-DCeaLtpS.png} +0 -0
- /flowfile/web/static/assets/{record_id-0b15856b.png → record_id-FeUjyIFh.png} +0 -0
- /flowfile/web/static/assets/{sample-693a88b5.png → sample-DeqfRiB-.png} +0 -0
- /flowfile/web/static/assets/{select-b0d0437a.png → select-D4JjbdjS.png} +0 -0
- /flowfile/web/static/assets/{selectDynamic-f2fb394f.css → selectDynamic-CjeTPUUo.css} +0 -0
- /flowfile/web/static/assets/{sort-2aa579f0.png → sort-DGwUG9WS.png} +0 -0
- /flowfile/web/static/assets/{summarize-2a099231.png → summarize-DFaNHpfp.png} +0 -0
- /flowfile/web/static/assets/{text_to_rows-859b29ea.png → text_to_rows-BdiAewrN.png} +0 -0
- /flowfile/web/static/assets/{union-2d8609f4.png → union-DCK-LSMq.png} +0 -0
- /flowfile/web/static/assets/{unique-1958b98a.png → unique-CdP3zZIq.png} +0 -0
- /flowfile/web/static/assets/{unpivot-d3cb4b5b.png → unpivot-CHttrEt8.png} +0 -0
- /flowfile/web/static/assets/{user-defined-icon-0ae16c90.png → user-defined-icon-BcIp2Vzo.png} +0 -0
- /flowfile/web/static/assets/{view-7a0f0be1.png → view-DUSRwjvq.png} +0 -0
- {flowfile-0.5.4.dist-info → flowfile-0.6.1.dist-info}/entry_points.txt +0 -0
- {flowfile-0.5.4.dist-info → flowfile-0.6.1.dist-info}/licenses/LICENSE +0 -0
flowfile_frame/flow_frame.py
CHANGED
|
@@ -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,
|
|
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
|
-
) ->
|
|
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
|
-
) ->
|
|
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 + "
|
|
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
|
-
) ->
|
|
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:
|
|
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:
|
|
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
|
-
) ->
|
|
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:
|
|
846
|
+
other: FlowFrame,
|
|
847
847
|
new_node_id: int,
|
|
848
848
|
join_mappings: list | None,
|
|
849
849
|
how: str,
|
|
850
850
|
description: str,
|
|
851
|
-
) ->
|
|
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:
|
|
899
|
+
join_input: transform_schema.CrossJoinInput,
|
|
900
900
|
description: str,
|
|
901
|
-
other:
|
|
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:
|
|
919
|
+
join_input: transform_schema.JoinInput,
|
|
920
920
|
description: str,
|
|
921
|
-
other:
|
|
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) ->
|
|
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) ->
|
|
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
|
-
) ->
|
|
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 + "
|
|
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
|
-
) ->
|
|
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 + "
|
|
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
|
-
) ->
|
|
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
|
-
) ->
|
|
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
|
-
) ->
|
|
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
|
-
) ->
|
|
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
|
-
) ->
|
|
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
|
-
) ->
|
|
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) ->
|
|
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) ->
|
|
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
|
-
) ->
|
|
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
|
-
) ->
|
|
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:
|
|
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
|
-
) ->
|
|
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,
|
|
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
|
-
) ->
|
|
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) ->
|
|
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
|
-
) ->
|
|
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:
|
|
2222
|
+
other: FlowFrame,
|
|
2223
2223
|
fuzzy_mappings: list[FuzzyMapping],
|
|
2224
2224
|
description: str = None,
|
|
2225
|
-
) ->
|
|
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
|
-
) ->
|
|
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:
|
|
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
|
-
) ->
|
|
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.
|
|
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
|
-
|
|
150
|
-
|
|
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]:
|
flowfile_frame/lazy_methods.py
CHANGED
|
@@ -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
|
-
|
|
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}({
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
75
|
+
operation: Base64Bytes # Automatically encodes/decodes base64 for JSON
|
|
58
76
|
|
|
59
77
|
def polars_serializable_object(self):
|
|
60
|
-
|
|
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:
|
|
97
|
+
operation: Base64Bytes # Automatically encodes/decodes base64 for JSON
|
|
79
98
|
|
|
80
99
|
def polars_serializable_object(self):
|
|
81
|
-
|
|
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
|
"""
|