Flowfile 0.5.1__py3-none-any.whl → 0.5.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- build_backends/main.py +25 -22
- build_backends/main_prd.py +10 -19
- flowfile/__init__.py +194 -74
- flowfile/__main__.py +10 -7
- flowfile/api.py +51 -57
- flowfile/web/__init__.py +14 -9
- flowfile/web/static/assets/AdminView-f53bad23.css +129 -0
- flowfile/web/static/assets/AdminView-f9847d67.js +713 -0
- flowfile/web/static/assets/CloudConnectionView-cf85f943.css +72 -0
- flowfile/web/static/assets/{CloudConnectionManager-0dfba9f2.js → CloudConnectionView-faace55b.js} +11 -11
- flowfile/web/static/assets/{CloudStorageReader-29d14fcc.css → CloudStorageReader-24c54524.css} +27 -27
- flowfile/web/static/assets/{CloudStorageReader-d5b1b6c9.js → CloudStorageReader-d86ecaa7.js} +10 -8
- flowfile/web/static/assets/{CloudStorageWriter-00d87aad.js → CloudStorageWriter-0f4d9a44.js} +10 -8
- flowfile/web/static/assets/{CloudStorageWriter-b0ee067f.css → CloudStorageWriter-60547855.css} +26 -26
- flowfile/web/static/assets/ColumnActionInput-c44b7aee.css +159 -0
- flowfile/web/static/assets/ColumnActionInput-f4189ae0.js +330 -0
- flowfile/web/static/assets/{ColumnSelector-47996a16.css → ColumnSelector-371637fb.css} +2 -2
- flowfile/web/static/assets/{ColumnSelector-4685e75d.js → ColumnSelector-e66b33da.js} +3 -5
- flowfile/web/static/assets/ContextMenu-49463352.js +9 -0
- flowfile/web/static/assets/ContextMenu-dd5f3f25.js +9 -0
- flowfile/web/static/assets/ContextMenu-f709b884.js +9 -0
- flowfile/web/static/assets/ContextMenu.vue_vue_type_script_setup_true_lang-a1bd6314.js +59 -0
- flowfile/web/static/assets/{CrossJoin-702a3edd.js → CrossJoin-24694b8f.js} +12 -10
- flowfile/web/static/assets/{CrossJoin-1119d18e.css → CrossJoin-71b4cc10.css} +20 -20
- flowfile/web/static/assets/{CustomNode-b1519993.js → CustomNode-569d45ff.js} +43 -24
- flowfile/web/static/assets/CustomNode-edb9b939.css +42 -0
- flowfile/web/static/assets/{DatabaseConnectionSettings-0c04b2e5.css → DatabaseConnectionSettings-c20a1e16.css} +23 -21
- flowfile/web/static/assets/{DatabaseConnectionSettings-6f3e4ea5.js → DatabaseConnectionSettings-cfc08938.js} +5 -4
- flowfile/web/static/assets/{DatabaseReader-ae61773c.css → DatabaseReader-5bf8c75b.css} +41 -46
- flowfile/web/static/assets/{DatabaseReader-d38c7295.js → DatabaseReader-701feabb.js} +25 -15
- flowfile/web/static/assets/{DatabaseManager-cf5ef661.js → DatabaseView-0482e5b5.js} +11 -11
- flowfile/web/static/assets/DatabaseView-6655afd6.css +57 -0
- flowfile/web/static/assets/{DatabaseWriter-b04ef46a.js → DatabaseWriter-16721989.js} +17 -10
- flowfile/web/static/assets/{DatabaseWriter-2f570e53.css → DatabaseWriter-bdcf2c8b.css} +29 -27
- flowfile/web/static/assets/{designer-8da3ba3a.css → DesignerView-49abb835.css} +783 -663
- flowfile/web/static/assets/{designer-9633482a.js → DesignerView-f64749fb.js} +1292 -3253
- flowfile/web/static/assets/{documentation-ca400224.js → DocumentationView-61bd2990.js} +5 -5
- flowfile/web/static/assets/{documentation-12216a74.css → DocumentationView-9ea6e871.css} +9 -9
- flowfile/web/static/assets/{ExploreData-2d0cf4db.css → ExploreData-10c5acc8.css} +13 -12
- flowfile/web/static/assets/{ExploreData-5fa10ed8.js → ExploreData-e2735b13.js} +18 -9
- flowfile/web/static/assets/{ExternalSource-d39af878.js → ExternalSource-2535c3b2.js} +9 -7
- flowfile/web/static/assets/{ExternalSource-e37b6275.css → ExternalSource-7ac7373f.css} +20 -20
- flowfile/web/static/assets/Filter-2cdbc93c.js +287 -0
- flowfile/web/static/assets/Filter-7494ea97.css +48 -0
- flowfile/web/static/assets/{Formula-bb96803d.css → Formula-53d58c43.css} +7 -7
- flowfile/web/static/assets/{Formula-6b04fb1d.js → Formula-fcda3c2c.js} +13 -11
- flowfile/web/static/assets/{FuzzyMatch-1010f966.css → FuzzyMatch-ad6361d6.css} +68 -69
- flowfile/web/static/assets/{FuzzyMatch-999521f4.js → FuzzyMatch-f8d3b7d3.js} +12 -10
- flowfile/web/static/assets/{Pivot-cf333e3d.css → GraphSolver-4b4d7db9.css} +5 -5
- flowfile/web/static/assets/{GraphSolver-17dd2198.js → GraphSolver-72eaa695.js} +14 -12
- flowfile/web/static/assets/GroupBy-5792782d.css +9 -0
- flowfile/web/static/assets/{GroupBy-6b039e18.js → GroupBy-8aa0598b.js} +9 -7
- flowfile/web/static/assets/{Join-fd79b451.css → Join-28b5e18f.css} +22 -22
- flowfile/web/static/assets/{Join-24d0f113.js → Join-e40f0ffa.js} +13 -11
- flowfile/web/static/assets/LoginView-5111c9ae.js +134 -0
- flowfile/web/static/assets/LoginView-d325d632.css +172 -0
- flowfile/web/static/assets/ManualInput-3702e677.css +293 -0
- flowfile/web/static/assets/{ManualInput-34639209.js → ManualInput-9b6f3224.js} +170 -116
- flowfile/web/static/assets/{MultiSelect-0e8724a3.js → MultiSelect-ef28e19e.js} +2 -2
- flowfile/web/static/assets/{MultiSelect.vue_vue_type_script_setup_true_lang-b0e538c2.js → MultiSelect.vue_vue_type_script_setup_true_lang-83b3bbfd.js} +1 -1
- flowfile/web/static/assets/NodeDesigner-94cd4dd3.css +1429 -0
- flowfile/web/static/assets/NodeDesigner-d2b7ee2b.js +2712 -0
- flowfile/web/static/assets/{NumericInput-3d63a470.js → NumericInput-1d789794.js} +2 -2
- flowfile/web/static/assets/{NumericInput.vue_vue_type_script_setup_true_lang-e0edeccc.js → NumericInput.vue_vue_type_script_setup_true_lang-7775f83e.js} +5 -2
- flowfile/web/static/assets/Output-692dd25d.css +37 -0
- flowfile/web/static/assets/{Output-edea9802.js → Output-cefef801.js} +14 -10
- flowfile/web/static/assets/{GraphSolver-f0cb7bfb.css → Pivot-0eda81b4.css} +5 -5
- flowfile/web/static/assets/{Pivot-61d19301.js → Pivot-bab1b75b.js} +12 -10
- flowfile/web/static/assets/PivotValidation-0e905b1a.css +13 -0
- flowfile/web/static/assets/PivotValidation-41b57ad6.css +13 -0
- flowfile/web/static/assets/{PivotValidation-f97fec5b.js → PivotValidation-e7941f91.js} +3 -3
- flowfile/web/static/assets/{PivotValidation-de9f43fe.js → PivotValidation-fba09336.js} +3 -3
- flowfile/web/static/assets/{PolarsCode-650322d1.css → PolarsCode-2b1f1f23.css} +4 -4
- flowfile/web/static/assets/{PolarsCode-bc3c9984.js → PolarsCode-740e40fa.js} +18 -9
- flowfile/web/static/assets/PopOver-862d7e28.js +939 -0
- flowfile/web/static/assets/PopOver-d96599db.css +33 -0
- flowfile/web/static/assets/{Read-64a3f259.js → Read-225cc63f.js} +16 -12
- flowfile/web/static/assets/{Read-e808b239.css → Read-90f366bc.css} +15 -15
- flowfile/web/static/assets/{RecordCount-3d5039be.js → RecordCount-ffc71eca.js} +6 -4
- flowfile/web/static/assets/{RecordId-597510e0.js → RecordId-a70bb8df.js} +9 -7
- flowfile/web/static/assets/{SQLQueryComponent-df51adbe.js → SQLQueryComponent-15a421f5.js} +3 -3
- flowfile/web/static/assets/SQLQueryComponent-edb90b98.css +29 -0
- flowfile/web/static/assets/{Sample-4be0a507.js → Sample-6c26afc7.js} +6 -4
- flowfile/web/static/assets/SecretSelector-6329f743.css +43 -0
- flowfile/web/static/assets/SecretSelector-ceed9496.js +113 -0
- flowfile/web/static/assets/{SecretManager-4839be57.js → SecretsView-214d255a.js} +35 -36
- flowfile/web/static/assets/SecretsView-aa291340.css +38 -0
- flowfile/web/static/assets/{Select-9b72f201.js → Select-8fc29999.js} +9 -7
- flowfile/web/static/assets/{SettingsSection-71e6b7e3.css → SettingsSection-07fbbc39.css} +4 -4
- flowfile/web/static/assets/{SettingsSection-5c696bee.css → SettingsSection-26fe48d4.css} +4 -4
- flowfile/web/static/assets/{SettingsSection-7ded385d.js → SettingsSection-3f70e4c3.js} +3 -3
- flowfile/web/static/assets/{SettingsSection-f0f75a42.js → SettingsSection-83090218.js} +3 -3
- flowfile/web/static/assets/{SettingsSection-2e4d03c4.css → SettingsSection-8f980839.css} +4 -4
- flowfile/web/static/assets/{SettingsSection-e1e9c953.js → SettingsSection-9f0d1725.js} +3 -3
- flowfile/web/static/assets/SetupView-3fa0aa03.js +160 -0
- flowfile/web/static/assets/SetupView-e2da3442.css +230 -0
- flowfile/web/static/assets/{SingleSelect-6c777aac.js → SingleSelect-a4a568cb.js} +2 -2
- flowfile/web/static/assets/{SingleSelect.vue_vue_type_script_setup_true_lang-33e3ff9b.js → SingleSelect.vue_vue_type_script_setup_true_lang-c8ebdd33.js} +1 -1
- flowfile/web/static/assets/{SliderInput-7cb93e62.js → SliderInput-be533e71.js} +7 -4
- flowfile/web/static/assets/SliderInput-f2e4f23c.css +4 -0
- flowfile/web/static/assets/{Sort-6cbde21a.js → Sort-154dad81.js} +9 -7
- flowfile/web/static/assets/Sort-4abb7fae.css +9 -0
- flowfile/web/static/assets/{TextInput-d9a40c11.js → TextInput-454e2bda.js} +2 -2
- flowfile/web/static/assets/{TextInput.vue_vue_type_script_setup_true_lang-5896c375.js → TextInput.vue_vue_type_script_setup_true_lang-e86510d0.js} +5 -2
- flowfile/web/static/assets/{TextToRows-5d2c1190.css → TextToRows-12afb4f4.css} +10 -10
- flowfile/web/static/assets/{TextToRows-c4fcbf4d.js → TextToRows-ea73433d.js} +11 -10
- flowfile/web/static/assets/{ToggleSwitch-4ef91d19.js → ToggleSwitch-9d7b30f1.js} +2 -2
- flowfile/web/static/assets/{ToggleSwitch.vue_vue_type_script_setup_true_lang-38478c20.js → ToggleSwitch.vue_vue_type_script_setup_true_lang-00f2580e.js} +1 -1
- flowfile/web/static/assets/{UnavailableFields-5edd5322.css → UnavailableFields-394a1f78.css} +14 -14
- flowfile/web/static/assets/{UnavailableFields-a03f512c.js → UnavailableFields-b72a2c72.js} +4 -4
- flowfile/web/static/assets/{Union-bfe9b996.js → Union-1e44f263.js} +8 -6
- flowfile/web/static/assets/{Union-af6c3d9b.css → Union-d6a8d7d5.css} +7 -7
- flowfile/web/static/assets/Unique-2b705521.css +3 -0
- flowfile/web/static/assets/{Unique-5d023a27.js → Unique-a3bc6d0a.js} +13 -10
- flowfile/web/static/assets/{Unpivot-1e422df3.css → Unpivot-b6ad6427.css} +7 -7
- flowfile/web/static/assets/{Unpivot-91cc5354.js → Unpivot-e27935fc.js} +11 -9
- flowfile/web/static/assets/{UnpivotValidation-7ee2de44.js → UnpivotValidation-72497680.js} +3 -3
- flowfile/web/static/assets/UnpivotValidation-d5ca3b7b.css +13 -0
- flowfile/web/static/assets/{VueGraphicWalker-ed5ab88b.css → VueGraphicWalker-430f0b86.css} +1 -1
- flowfile/web/static/assets/{VueGraphicWalker-e51b9924.js → VueGraphicWalker-d9ab70a3.js} +4 -4
- flowfile/web/static/assets/{api-cf1221f0.js → api-a2102880.js} +1 -1
- flowfile/web/static/assets/{api-c1bad5ca.js → api-f75042b0.js} +1 -1
- flowfile/web/static/assets/{dropDown-35135ba8.css → dropDown-1d6acbd9.css} +41 -41
- flowfile/web/static/assets/{dropDown-614b998d.js → dropDown-2798a109.js} +3 -3
- flowfile/web/static/assets/{fullEditor-f7971590.js → fullEditor-cf7d7d93.js} +11 -10
- flowfile/web/static/assets/{fullEditor-178376bb.css → fullEditor-fe9f7e18.css} +77 -65
- flowfile/web/static/assets/{genericNodeSettings-4fe5f36b.js → genericNodeSettings-14eac1c3.js} +5 -5
- flowfile/web/static/assets/{genericNodeSettings-924759c7.css → genericNodeSettings-3b2507ea.css} +10 -10
- flowfile/web/static/assets/{index-5429bbf8.js → index-387a6f18.js} +41806 -40958
- flowfile/web/static/assets/index-6b367bb5.js +38 -0
- flowfile/web/static/assets/{index-50508d4d.css → index-e96ab018.css} +2184 -569
- flowfile/web/static/assets/index-f0a6e5a5.js +2696 -0
- flowfile/web/static/assets/node.types-2c15bb7e.js +82 -0
- flowfile/web/static/assets/nodeInput-ed2ae8d7.js +2 -0
- flowfile/web/static/assets/{outputCsv-076b85ab.js → outputCsv-3c1757e8.js} +3 -3
- flowfile/web/static/assets/outputCsv-b9a072af.css +2499 -0
- flowfile/web/static/assets/{outputExcel-0fd17dbe.js → outputExcel-686e1f48.js} +3 -3
- flowfile/web/static/assets/{outputExcel-b41305c0.css → outputExcel-f5d272b2.css} +26 -26
- flowfile/web/static/assets/outputParquet-54597c3c.css +4 -0
- flowfile/web/static/assets/{outputParquet-b61e0847.js → outputParquet-df28faa7.js} +4 -4
- flowfile/web/static/assets/{readCsv-c767cb37.css → readCsv-3bfac4c3.css} +15 -15
- flowfile/web/static/assets/{readCsv-a8bb8b61.js → readCsv-e37eee21.js} +3 -3
- flowfile/web/static/assets/{readExcel-806d2826.css → readExcel-3db6b763.css} +13 -13
- flowfile/web/static/assets/{readExcel-67b4aee0.js → readExcel-a13f14bb.js} +5 -5
- flowfile/web/static/assets/{readParquet-92ce1dbc.js → readParquet-344cf746.js} +3 -3
- flowfile/web/static/assets/{readParquet-48c81530.css → readParquet-c5244ad5.css} +4 -4
- flowfile/web/static/assets/secrets.api-ae198c5c.js +65 -0
- flowfile/web/static/assets/{selectDynamic-92e25ee3.js → selectDynamic-6b4b0767.js} +5 -5
- flowfile/web/static/assets/{selectDynamic-aa913ff4.css → selectDynamic-f2fb394f.css} +21 -20
- flowfile/web/static/assets/{vue-codemirror.esm-41b0e0d7.js → vue-codemirror.esm-31ba0e0b.js} +31 -640
- flowfile/web/static/assets/{vue-content-loader.es-2c8e608f.js → vue-content-loader.es-4469c8ff.js} +1 -1
- flowfile/web/static/index.html +2 -2
- {flowfile-0.5.1.dist-info → flowfile-0.5.4.dist-info}/METADATA +3 -4
- flowfile-0.5.4.dist-info/RECORD +407 -0
- flowfile_core/__init__.py +13 -6
- flowfile_core/auth/jwt.py +51 -16
- flowfile_core/auth/models.py +32 -7
- flowfile_core/auth/password.py +89 -0
- flowfile_core/auth/secrets.py +64 -19
- flowfile_core/configs/__init__.py +9 -7
- flowfile_core/configs/flow_logger.py +15 -14
- flowfile_core/configs/node_store/__init__.py +72 -4
- flowfile_core/configs/node_store/nodes.py +155 -172
- flowfile_core/configs/node_store/user_defined_node_registry.py +108 -27
- flowfile_core/configs/settings.py +28 -15
- flowfile_core/database/connection.py +7 -6
- flowfile_core/database/init_db.py +96 -2
- flowfile_core/database/models.py +3 -1
- flowfile_core/fileExplorer/__init__.py +17 -0
- flowfile_core/fileExplorer/funcs.py +145 -57
- flowfile_core/fileExplorer/utils.py +10 -11
- flowfile_core/flowfile/_extensions/real_time_interface.py +10 -8
- flowfile_core/flowfile/analytics/analytics_processor.py +26 -24
- flowfile_core/flowfile/analytics/graphic_walker.py +11 -12
- flowfile_core/flowfile/analytics/utils.py +1 -1
- flowfile_core/flowfile/code_generator/__init__.py +11 -0
- flowfile_core/flowfile/code_generator/code_generator.py +706 -247
- flowfile_core/flowfile/connection_manager/_connection_manager.py +6 -5
- flowfile_core/flowfile/connection_manager/models.py +1 -1
- flowfile_core/flowfile/database_connection_manager/db_connections.py +60 -44
- flowfile_core/flowfile/database_connection_manager/models.py +1 -1
- flowfile_core/flowfile/extensions.py +17 -12
- flowfile_core/flowfile/flow_data_engine/cloud_storage_reader.py +34 -32
- flowfile_core/flowfile/flow_data_engine/create/funcs.py +115 -83
- flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +493 -423
- flowfile_core/flowfile/flow_data_engine/flow_file_column/interface.py +2 -2
- flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +92 -52
- flowfile_core/flowfile/flow_data_engine/flow_file_column/polars_type.py +12 -11
- flowfile_core/flowfile/flow_data_engine/flow_file_column/type_registry.py +6 -6
- flowfile_core/flowfile/flow_data_engine/flow_file_column/utils.py +26 -30
- flowfile_core/flowfile/flow_data_engine/fuzzy_matching/prepare_for_fuzzy_match.py +31 -20
- flowfile_core/flowfile/flow_data_engine/join/__init__.py +1 -1
- flowfile_core/flowfile/flow_data_engine/join/utils.py +11 -9
- flowfile_core/flowfile/flow_data_engine/join/verify_integrity.py +14 -15
- flowfile_core/flowfile/flow_data_engine/pivot_table.py +5 -7
- flowfile_core/flowfile/flow_data_engine/polars_code_parser.py +95 -82
- flowfile_core/flowfile/flow_data_engine/read_excel_tables.py +66 -65
- flowfile_core/flowfile/flow_data_engine/sample_data.py +27 -21
- flowfile_core/flowfile/flow_data_engine/subprocess_operations/__init__.py +1 -1
- flowfile_core/flowfile/flow_data_engine/subprocess_operations/models.py +13 -11
- flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +190 -127
- flowfile_core/flowfile/flow_data_engine/threaded_processes.py +8 -8
- flowfile_core/flowfile/flow_data_engine/utils.py +99 -67
- flowfile_core/flowfile/flow_graph.py +920 -571
- flowfile_core/flowfile/flow_graph_utils.py +31 -49
- flowfile_core/flowfile/flow_node/flow_node.py +379 -258
- flowfile_core/flowfile/flow_node/models.py +53 -41
- flowfile_core/flowfile/flow_node/schema_callback.py +14 -19
- flowfile_core/flowfile/graph_tree/graph_tree.py +41 -41
- flowfile_core/flowfile/handler.py +80 -30
- flowfile_core/flowfile/manage/compatibility_enhancements.py +209 -126
- flowfile_core/flowfile/manage/io_flowfile.py +54 -57
- flowfile_core/flowfile/node_designer/__init__.py +19 -13
- flowfile_core/flowfile/node_designer/_type_registry.py +34 -37
- flowfile_core/flowfile/node_designer/custom_node.py +162 -36
- flowfile_core/flowfile/node_designer/ui_components.py +278 -34
- flowfile_core/flowfile/schema_callbacks.py +71 -51
- flowfile_core/flowfile/setting_generator/__init__.py +0 -1
- flowfile_core/flowfile/setting_generator/setting_generator.py +6 -5
- flowfile_core/flowfile/setting_generator/settings.py +64 -53
- flowfile_core/flowfile/sources/external_sources/base_class.py +12 -10
- flowfile_core/flowfile/sources/external_sources/custom_external_sources/external_source.py +27 -17
- flowfile_core/flowfile/sources/external_sources/custom_external_sources/sample_users.py +9 -9
- flowfile_core/flowfile/sources/external_sources/factory.py +0 -1
- flowfile_core/flowfile/sources/external_sources/sql_source/models.py +45 -31
- flowfile_core/flowfile/sources/external_sources/sql_source/sql_source.py +198 -73
- flowfile_core/flowfile/sources/external_sources/sql_source/utils.py +250 -196
- flowfile_core/flowfile/util/calculate_layout.py +9 -13
- flowfile_core/flowfile/util/execution_orderer.py +25 -17
- flowfile_core/flowfile/util/node_skipper.py +4 -4
- flowfile_core/flowfile/utils.py +19 -21
- flowfile_core/main.py +26 -19
- flowfile_core/routes/auth.py +284 -11
- flowfile_core/routes/cloud_connections.py +25 -25
- flowfile_core/routes/logs.py +21 -29
- flowfile_core/routes/public.py +46 -4
- flowfile_core/routes/routes.py +70 -34
- flowfile_core/routes/secrets.py +25 -27
- flowfile_core/routes/user_defined_components.py +483 -4
- flowfile_core/run_lock.py +0 -1
- flowfile_core/schemas/__init__.py +4 -6
- flowfile_core/schemas/analysis_schemas/graphic_walker_schemas.py +55 -55
- flowfile_core/schemas/cloud_storage_schemas.py +96 -66
- flowfile_core/schemas/input_schema.py +231 -144
- flowfile_core/schemas/output_model.py +49 -34
- flowfile_core/schemas/schemas.py +116 -89
- flowfile_core/schemas/transform_schema.py +518 -263
- flowfile_core/schemas/yaml_types.py +21 -7
- flowfile_core/secret_manager/secret_manager.py +123 -18
- flowfile_core/types.py +29 -9
- flowfile_core/utils/arrow_reader.py +7 -6
- flowfile_core/utils/excel_file_manager.py +3 -3
- flowfile_core/utils/fileManager.py +7 -7
- flowfile_core/utils/fl_executor.py +8 -10
- flowfile_core/utils/utils.py +4 -4
- flowfile_core/utils/validate_setup.py +5 -4
- flowfile_frame/__init__.py +117 -51
- flowfile_frame/adapters.py +2 -9
- flowfile_frame/adding_expr.py +73 -32
- flowfile_frame/cloud_storage/frame_helpers.py +27 -23
- flowfile_frame/cloud_storage/secret_manager.py +12 -26
- flowfile_frame/config.py +2 -5
- flowfile_frame/database/__init__.py +36 -0
- flowfile_frame/database/connection_manager.py +205 -0
- flowfile_frame/database/frame_helpers.py +249 -0
- flowfile_frame/expr.py +311 -218
- flowfile_frame/expr.pyi +160 -159
- flowfile_frame/expr_name.py +23 -23
- flowfile_frame/flow_frame.py +571 -476
- flowfile_frame/flow_frame.pyi +123 -104
- flowfile_frame/flow_frame_methods.py +227 -246
- flowfile_frame/group_frame.py +50 -20
- flowfile_frame/join.py +2 -2
- flowfile_frame/lazy.py +129 -87
- flowfile_frame/lazy_methods.py +83 -30
- flowfile_frame/list_name_space.py +55 -50
- flowfile_frame/selectors.py +148 -68
- flowfile_frame/series.py +9 -7
- flowfile_frame/utils.py +19 -21
- flowfile_worker/__init__.py +12 -7
- flowfile_worker/configs.py +41 -33
- flowfile_worker/create/__init__.py +14 -9
- flowfile_worker/create/funcs.py +114 -77
- flowfile_worker/create/models.py +46 -43
- flowfile_worker/create/pl_types.py +14 -15
- flowfile_worker/create/read_excel_tables.py +34 -41
- flowfile_worker/create/utils.py +22 -19
- flowfile_worker/external_sources/s3_source/main.py +18 -51
- flowfile_worker/external_sources/s3_source/models.py +34 -27
- flowfile_worker/external_sources/sql_source/main.py +8 -5
- flowfile_worker/external_sources/sql_source/models.py +13 -9
- flowfile_worker/flow_logger.py +10 -8
- flowfile_worker/funcs.py +214 -155
- flowfile_worker/main.py +11 -17
- flowfile_worker/models.py +35 -28
- flowfile_worker/process_manager.py +2 -3
- flowfile_worker/routes.py +121 -90
- flowfile_worker/secrets.py +114 -21
- flowfile_worker/spawner.py +89 -54
- flowfile_worker/utils.py +3 -2
- shared/__init__.py +2 -7
- shared/storage_config.py +25 -13
- test_utils/postgres/commands.py +3 -2
- test_utils/postgres/fixtures.py +9 -9
- test_utils/s3/commands.py +1 -1
- test_utils/s3/data_generator.py +3 -4
- test_utils/s3/demo_data_generator.py +4 -7
- test_utils/s3/fixtures.py +7 -5
- tools/migrate/__init__.py +1 -1
- tools/migrate/__main__.py +16 -29
- tools/migrate/legacy_schemas.py +251 -190
- tools/migrate/migrate.py +193 -181
- tools/migrate/tests/conftest.py +1 -3
- tools/migrate/tests/test_migrate.py +36 -41
- tools/migrate/tests/test_migration_e2e.py +28 -29
- tools/migrate/tests/test_node_migrations.py +50 -20
- flowfile/web/static/assets/CloudConnectionManager-2dfdce2f.css +0 -86
- flowfile/web/static/assets/ContextMenu-23e909da.js +0 -41
- flowfile/web/static/assets/ContextMenu-4c74eef1.css +0 -26
- flowfile/web/static/assets/ContextMenu-63cfa99b.css +0 -26
- flowfile/web/static/assets/ContextMenu-70ae0c79.js +0 -41
- flowfile/web/static/assets/ContextMenu-c13f91d0.css +0 -26
- flowfile/web/static/assets/ContextMenu-f149cf7c.js +0 -41
- flowfile/web/static/assets/CustomNode-74a37f74.css +0 -32
- flowfile/web/static/assets/DatabaseManager-30fa27e5.css +0 -64
- flowfile/web/static/assets/Filter-9b6d08db.js +0 -164
- flowfile/web/static/assets/Filter-f62091b3.css +0 -20
- flowfile/web/static/assets/GroupBy-b9505323.css +0 -51
- flowfile/web/static/assets/ManualInput-3246a08d.css +0 -96
- flowfile/web/static/assets/Output-283fe388.css +0 -37
- flowfile/web/static/assets/PivotValidation-891ddfb0.css +0 -13
- flowfile/web/static/assets/PivotValidation-c46cd420.css +0 -13
- flowfile/web/static/assets/SQLQueryComponent-36cef432.css +0 -27
- flowfile/web/static/assets/SliderInput-b8fb6a8c.css +0 -4
- flowfile/web/static/assets/Sort-3643d625.css +0 -51
- flowfile/web/static/assets/Unique-f9fb0809.css +0 -51
- flowfile/web/static/assets/UnpivotValidation-0d240eeb.css +0 -13
- flowfile/web/static/assets/nodeInput-5d0d6b79.js +0 -41
- flowfile/web/static/assets/outputCsv-9cc59e0b.css +0 -2499
- flowfile/web/static/assets/outputParquet-cf8cf3f2.css +0 -4
- flowfile/web/static/assets/secretApi-68435402.js +0 -46
- flowfile/web/static/assets/vue-codemirror-bccfde04.css +0 -32
- flowfile-0.5.1.dist-info/RECORD +0 -388
- {flowfile-0.5.1.dist-info → flowfile-0.5.4.dist-info}/WHEEL +0 -0
- {flowfile-0.5.1.dist-info → flowfile-0.5.4.dist-info}/entry_points.txt +0 -0
- {flowfile-0.5.1.dist-info → flowfile-0.5.4.dist-info}/licenses/LICENSE +0 -0
flowfile_frame/group_frame.py
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
from flowfile_frame.expr import col, Expr, Column, lit
|
|
2
|
-
from flowfile_frame.selectors import Selector
|
|
3
|
-
from flowfile_frame.utils import _parse_inputs_as_iterable
|
|
4
|
-
from flowfile_core.schemas import transform_schema, input_schema
|
|
5
1
|
from typing import TYPE_CHECKING, Any
|
|
6
|
-
|
|
2
|
+
|
|
3
|
+
from flowfile_core.schemas import input_schema, transform_schema
|
|
4
|
+
from flowfile_frame.expr import Column, Expr, col, lit
|
|
5
|
+
from flowfile_frame.selectors import Selector
|
|
6
|
+
from flowfile_frame.utils import (
|
|
7
|
+
_check_if_convertible_to_code,
|
|
8
|
+
_parse_inputs_as_iterable,
|
|
9
|
+
ensure_inputs_as_iterable,
|
|
10
|
+
get_pl_expr_from_expr,
|
|
11
|
+
)
|
|
7
12
|
|
|
8
13
|
if TYPE_CHECKING:
|
|
9
14
|
from flowfile_frame.flow_frame import FlowFrame
|
|
@@ -53,11 +58,11 @@ class GroupByFrame:
|
|
|
53
58
|
parts.append(f'''"{str(c)}"''')
|
|
54
59
|
return ", ".join(parts)
|
|
55
60
|
|
|
56
|
-
def len(self) ->
|
|
61
|
+
def len(self) -> "FlowFrame":
|
|
57
62
|
"""Count number of rows per group. Output column is named 'len'."""
|
|
58
63
|
return self._generate_direct_polars_code("len")
|
|
59
64
|
|
|
60
|
-
def count(self) ->
|
|
65
|
+
def count(self) -> "FlowFrame":
|
|
61
66
|
"""Count number of rows per group. Output column is named 'count'."""
|
|
62
67
|
return self._generate_direct_polars_code("count")
|
|
63
68
|
|
|
@@ -82,8 +87,15 @@ class GroupByFrame:
|
|
|
82
87
|
if can_be_converted:
|
|
83
88
|
can_be_converted = self._process_named_agg_expressions(agg_cols, named_agg_exprs)
|
|
84
89
|
node_desc = self.description or f"Aggregate after grouping by {self.readable_group()}"
|
|
85
|
-
return self._create_agg_node(
|
|
86
|
-
|
|
90
|
+
return self._create_agg_node(
|
|
91
|
+
self.node_id,
|
|
92
|
+
can_be_converted,
|
|
93
|
+
agg_cols,
|
|
94
|
+
agg_expressions,
|
|
95
|
+
named_agg_exprs,
|
|
96
|
+
convertable_to_code=convertable_to_code,
|
|
97
|
+
description=node_desc,
|
|
98
|
+
)
|
|
87
99
|
|
|
88
100
|
def _process_group_columns(self, agg_cols: list[transform_schema.AggColl]) -> bool:
|
|
89
101
|
"""Process grouping columns for aggregation schema."""
|
|
@@ -150,8 +162,16 @@ class GroupByFrame:
|
|
|
150
162
|
return False
|
|
151
163
|
return True
|
|
152
164
|
|
|
153
|
-
def _create_agg_node(
|
|
154
|
-
|
|
165
|
+
def _create_agg_node(
|
|
166
|
+
self,
|
|
167
|
+
node_id_to_use: int,
|
|
168
|
+
can_be_converted: bool,
|
|
169
|
+
agg_cols: list,
|
|
170
|
+
agg_expressions,
|
|
171
|
+
named_agg_exprs,
|
|
172
|
+
convertable_to_code: bool,
|
|
173
|
+
description: str,
|
|
174
|
+
):
|
|
155
175
|
"""Create node for explicit aggregations via self.agg()."""
|
|
156
176
|
|
|
157
177
|
if can_be_converted:
|
|
@@ -159,9 +179,11 @@ class GroupByFrame:
|
|
|
159
179
|
flow_id=self.parent.flow_graph.flow_id,
|
|
160
180
|
node_id=node_id_to_use,
|
|
161
181
|
groupby_input=transform_schema.GroupByInput(agg_cols=agg_cols),
|
|
162
|
-
pos_x=200,
|
|
182
|
+
pos_x=200,
|
|
183
|
+
pos_y=200,
|
|
184
|
+
is_setup=True,
|
|
163
185
|
depending_on_id=self.parent.node_id,
|
|
164
|
-
description=description
|
|
186
|
+
description=description,
|
|
165
187
|
)
|
|
166
188
|
self.parent.flow_graph.add_group_by(group_by_settings)
|
|
167
189
|
else:
|
|
@@ -169,11 +191,17 @@ class GroupByFrame:
|
|
|
169
191
|
pl_agg_expressions = list(map(get_pl_expr_from_expr, ensure_inputs_as_iterable(agg_expressions)))
|
|
170
192
|
pl_group_expr = list(map(get_pl_expr_from_expr, ensure_inputs_as_iterable(self.expr_by_cols)))
|
|
171
193
|
pl_kwargs_expr = {k: self._create_expr_col(c).expr for k, c in named_agg_exprs.items()}
|
|
172
|
-
self.parent._add_polars_code(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
194
|
+
self.parent._add_polars_code(
|
|
195
|
+
new_node_id=node_id_to_use,
|
|
196
|
+
code=code,
|
|
197
|
+
description=description,
|
|
198
|
+
method_name="group_by",
|
|
199
|
+
convertable_to_code=convertable_to_code,
|
|
200
|
+
polars_expr=pl_agg_expressions,
|
|
201
|
+
group_expr=pl_group_expr,
|
|
202
|
+
kwargs_expr=pl_kwargs_expr,
|
|
203
|
+
group_kwargs={"maintain_order": self.maintain_order},
|
|
204
|
+
)
|
|
177
205
|
return self.parent._create_child_frame(node_id_to_use)
|
|
178
206
|
|
|
179
207
|
def _generate_direct_polars_code(self, method_name: str, *args, **kwargs) -> "FlowFrame":
|
|
@@ -190,7 +218,9 @@ class GroupByFrame:
|
|
|
190
218
|
readable_group_str = self.readable_group()
|
|
191
219
|
execution = "(" + ",".join(args) + ",".join([f"{k}={v}" for k, v in kwargs.items()]) + ")"
|
|
192
220
|
|
|
193
|
-
code =
|
|
221
|
+
code = (
|
|
222
|
+
f"input_df.group_by([{readable_group_str}], maintain_order={self.maintain_order}).{method_name}{execution}"
|
|
223
|
+
)
|
|
194
224
|
node_description = self.description or f"{method_name.capitalize()} after grouping by {readable_group_str}"
|
|
195
225
|
self.parent._add_polars_code(new_node_id=self.node_id, code=code, description=node_description)
|
|
196
226
|
return self.parent._create_child_frame(self.node_id)
|
|
@@ -246,4 +276,4 @@ class GroupByFrame:
|
|
|
246
276
|
|
|
247
277
|
def last(self):
|
|
248
278
|
"""Get last value for all non-grouping columns."""
|
|
249
|
-
return self._generate_direct_polars_code("last")
|
|
279
|
+
return self._generate_direct_polars_code("last")
|
flowfile_frame/join.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Assume these imports are correct from your original context
|
|
2
|
-
from flowfile_frame.expr import Column
|
|
3
2
|
from flowfile_core.schemas import transform_schema
|
|
3
|
+
from flowfile_frame.expr import Column
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def _normalize_columns_to_list(columns):
|
|
@@ -61,7 +61,7 @@ def _create_join_mappings(left_columns, right_columns):
|
|
|
61
61
|
join_mappings = []
|
|
62
62
|
needs_polars_code = False
|
|
63
63
|
|
|
64
|
-
for left_col, right_col in zip(left_columns, right_columns):
|
|
64
|
+
for left_col, right_col in zip(left_columns, right_columns, strict=False):
|
|
65
65
|
left_name, left_needs_code = _extract_column_name(left_col)
|
|
66
66
|
right_name, right_needs_code = _extract_column_name(right_col)
|
|
67
67
|
|
flowfile_frame/lazy.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import inspect
|
|
2
|
-
from
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
from functools import wraps
|
|
4
|
+
from typing import Any, Literal, Optional, cast
|
|
5
|
+
|
|
3
6
|
import polars as pl
|
|
4
|
-
|
|
7
|
+
|
|
5
8
|
from flowfile_core.flowfile.flow_graph import FlowGraph
|
|
6
9
|
from flowfile_frame.expr import Expr
|
|
10
|
+
from flowfile_frame.flow_frame import FlowFrame, can_be_expr, generate_node_id
|
|
7
11
|
from flowfile_frame.utils import _get_function_source
|
|
8
|
-
from typing import cast
|
|
9
|
-
from functools import wraps
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
def _determine_return_type(func_signature: inspect.Signature) -> Literal["FlowFrame", "Expr"]:
|
|
@@ -32,16 +34,18 @@ def _determine_return_type(func_signature: inspect.Signature) -> Literal["FlowFr
|
|
|
32
34
|
# Allow for type aliases or Union types that might include DataFrame/LazyFrame/Expr
|
|
33
35
|
if "DataFrame" in return_annotation or "LazyFrame" in return_annotation:
|
|
34
36
|
return "FlowFrame"
|
|
35
|
-
if
|
|
37
|
+
if (
|
|
38
|
+
"Expr" in return_annotation
|
|
39
|
+
and "DataFrame" not in return_annotation
|
|
40
|
+
and "LazyFrame" not in return_annotation
|
|
41
|
+
):
|
|
36
42
|
return "Expr"
|
|
37
|
-
raise ValueError(
|
|
38
|
-
f"Function does not return a Frame or Expr. "
|
|
39
|
-
f"Got return annotation: {return_annotation}"
|
|
40
|
-
)
|
|
43
|
+
raise ValueError(f"Function does not return a Frame or Expr. " f"Got return annotation: {return_annotation}")
|
|
41
44
|
|
|
42
45
|
|
|
43
|
-
def _analyze_parameters(
|
|
44
|
-
|
|
46
|
+
def _analyze_parameters(
|
|
47
|
+
func_signature: inspect.Signature,
|
|
48
|
+
) -> tuple[dict[str, bool], list[tuple[str, inspect.Parameter]]]:
|
|
45
49
|
"""
|
|
46
50
|
Analyze function parameters to determine which can accept Expr types.
|
|
47
51
|
|
|
@@ -99,6 +103,7 @@ def _deep_get_repr(obj: Any, can_be_expr: bool = False) -> str:
|
|
|
99
103
|
String representation suitable for code generation
|
|
100
104
|
"""
|
|
101
105
|
from flowfile_frame.expr import _get_expr_and_repr
|
|
106
|
+
|
|
102
107
|
if isinstance(obj, Expr):
|
|
103
108
|
# FlowFile Expr - get its representation
|
|
104
109
|
_, repr_str = _get_expr_and_repr(obj)
|
|
@@ -131,7 +136,7 @@ def _deep_get_repr(obj: Any, can_be_expr: bool = False) -> str:
|
|
|
131
136
|
return repr(obj)
|
|
132
137
|
|
|
133
138
|
|
|
134
|
-
def _process_callable_arg(arg: Any) ->
|
|
139
|
+
def _process_callable_arg(arg: Any) -> tuple[str, Any, bool, str | None]:
|
|
135
140
|
"""
|
|
136
141
|
Process a callable argument for representation and conversion.
|
|
137
142
|
|
|
@@ -154,7 +159,7 @@ def _process_callable_arg(arg: Any) -> Tuple[str, Any, bool, Optional[str]]:
|
|
|
154
159
|
return repr(arg), arg, False, None
|
|
155
160
|
|
|
156
161
|
|
|
157
|
-
def _process_argument(arg: Any, can_be_expr: bool) ->
|
|
162
|
+
def _process_argument(arg: Any, can_be_expr: bool) -> tuple[str, Any, bool, str | None]:
|
|
158
163
|
"""
|
|
159
164
|
Process a single argument, handling all types including nested structures.
|
|
160
165
|
|
|
@@ -166,7 +171,7 @@ def _process_argument(arg: Any, can_be_expr: bool) -> Tuple[str, Any, bool, Opti
|
|
|
166
171
|
Tuple of (repr_string, processed_arg_for_polars, convertible_to_code, function_source)
|
|
167
172
|
"""
|
|
168
173
|
# Special handling for callables (but not Expr objects which might be callable)
|
|
169
|
-
if callable(arg) and not isinstance(arg, (Expr, pl.Expr)) and not hasattr(arg,
|
|
174
|
+
if callable(arg) and not isinstance(arg, (Expr, pl.Expr)) and not hasattr(arg, "expr"):
|
|
170
175
|
return _process_callable_arg(arg)
|
|
171
176
|
repr_str = _deep_get_repr(arg, can_be_expr)
|
|
172
177
|
|
|
@@ -177,8 +182,9 @@ def _process_argument(arg: Any, can_be_expr: bool) -> Tuple[str, Any, bool, Opti
|
|
|
177
182
|
return repr_str, processed_arg, convertible, None
|
|
178
183
|
|
|
179
184
|
|
|
180
|
-
def _process_arguments(
|
|
181
|
-
|
|
185
|
+
def _process_arguments(
|
|
186
|
+
args: tuple[Any, ...], param_can_be_expr: dict[str, bool], param_list: list[tuple[str, inspect.Parameter]]
|
|
187
|
+
) -> tuple[list[str], list[Any], bool, list[str]]:
|
|
182
188
|
"""
|
|
183
189
|
Process positional arguments for the wrapper function.
|
|
184
190
|
|
|
@@ -213,8 +219,9 @@ def _process_arguments(args: Tuple[Any, ...], param_can_be_expr: Dict[str, bool]
|
|
|
213
219
|
return args_repr, pl_args, convertible_to_code, function_sources
|
|
214
220
|
|
|
215
221
|
|
|
216
|
-
def _process_keyword_arguments(
|
|
217
|
-
|
|
222
|
+
def _process_keyword_arguments(
|
|
223
|
+
kwargs: dict[str, Any], param_can_be_expr: dict[str, bool]
|
|
224
|
+
) -> tuple[list[str], dict[str, Any], bool, list[str]]:
|
|
218
225
|
"""
|
|
219
226
|
Process keyword arguments for the wrapper function.
|
|
220
227
|
|
|
@@ -244,8 +251,9 @@ def _process_keyword_arguments(kwargs: Dict[str, Any],
|
|
|
244
251
|
return kwargs_repr, pl_kwargs, convertible_to_code, function_sources
|
|
245
252
|
|
|
246
253
|
|
|
247
|
-
def _build_repr_string(
|
|
248
|
-
|
|
254
|
+
def _build_repr_string(
|
|
255
|
+
polars_func_name: str, args_repr: list[str], kwargs_repr: list[str], function_sources: list[str] = None
|
|
256
|
+
) -> str:
|
|
249
257
|
"""
|
|
250
258
|
Build the string representation of the function call.
|
|
251
259
|
|
|
@@ -290,7 +298,7 @@ def _build_repr_string(polars_func_name: str, args_repr: List[str], kwargs_repr:
|
|
|
290
298
|
return call_repr
|
|
291
299
|
|
|
292
300
|
|
|
293
|
-
def _create_flowframe_result(polars_func_name: str, full_repr: str, flow_graph:
|
|
301
|
+
def _create_flowframe_result(polars_func_name: str, full_repr: str, flow_graph: Any | None) -> "FlowFrame":
|
|
294
302
|
"""
|
|
295
303
|
Create a FlowFrame result for functions that return DataFrames/LazyFrames.
|
|
296
304
|
|
|
@@ -320,11 +328,12 @@ def _create_flowframe_result(polars_func_name: str, full_repr: str, flow_graph:
|
|
|
320
328
|
node_id=node_id,
|
|
321
329
|
depending_on_ids=[],
|
|
322
330
|
description=f"Execute: {polars_func_name}",
|
|
323
|
-
polars_code_input=transform_schema.PolarsCodeInput(polars_code)
|
|
331
|
+
polars_code_input=transform_schema.PolarsCodeInput(polars_code),
|
|
324
332
|
)
|
|
325
333
|
flow_graph.add_polars_code(node_polars_code)
|
|
326
334
|
|
|
327
335
|
try:
|
|
336
|
+
|
|
328
337
|
class MockNode:
|
|
329
338
|
def get_resulting_data(self):
|
|
330
339
|
class MockData:
|
|
@@ -332,7 +341,7 @@ def _create_flowframe_result(polars_func_name: str, full_repr: str, flow_graph:
|
|
|
332
341
|
|
|
333
342
|
return MockData()
|
|
334
343
|
|
|
335
|
-
if not hasattr(flow_graph,
|
|
344
|
+
if not hasattr(flow_graph, "get_node"):
|
|
336
345
|
flow_graph.get_node = lambda nid: MockNode()
|
|
337
346
|
|
|
338
347
|
actual_data = flow_graph.get_node(node_id).get_resulting_data().data_frame
|
|
@@ -348,7 +357,7 @@ def _create_flowframe_result(polars_func_name: str, full_repr: str, flow_graph:
|
|
|
348
357
|
)
|
|
349
358
|
|
|
350
359
|
|
|
351
|
-
def _check_for_non_serializable_functions(args:
|
|
360
|
+
def _check_for_non_serializable_functions(args: list[Any], kwargs: dict[str, Any]) -> list[str]:
|
|
352
361
|
"""
|
|
353
362
|
Check for non-serializable functions in arguments and return warnings.
|
|
354
363
|
|
|
@@ -365,16 +374,16 @@ def _check_for_non_serializable_functions(args: List[Any], kwargs: Dict[str, Any
|
|
|
365
374
|
"""Recursively check for non-serializable functions."""
|
|
366
375
|
if callable(value) and not isinstance(value, (type, pl.Expr)):
|
|
367
376
|
# Check if it's a lambda or local function
|
|
368
|
-
if hasattr(value,
|
|
369
|
-
if value.__name__ ==
|
|
377
|
+
if hasattr(value, "__name__"):
|
|
378
|
+
if value.__name__ == "<lambda>":
|
|
370
379
|
warnings.append(
|
|
371
380
|
f"Lambda function found at {path}. "
|
|
372
381
|
"This will cause 'serialization not supported for this opaque function' error. "
|
|
373
382
|
"Consider using a named function at module level instead."
|
|
374
383
|
)
|
|
375
|
-
elif hasattr(value,
|
|
384
|
+
elif hasattr(value, "__code__") and value.__code__.co_flags & 0x10: # CO_NESTED flag
|
|
376
385
|
# Check if it's a local/nested function (excluding top-level module functions)
|
|
377
|
-
if value.__code__.co_name !=
|
|
386
|
+
if value.__code__.co_name != "<module>": # Ensure it's not a module itself
|
|
378
387
|
warnings.append(
|
|
379
388
|
f"Local function '{value.__name__}' found at {path}. "
|
|
380
389
|
"This may cause serialization issues. "
|
|
@@ -401,9 +410,16 @@ def _check_for_non_serializable_functions(args: List[Any], kwargs: Dict[str, Any
|
|
|
401
410
|
return warnings
|
|
402
411
|
|
|
403
412
|
|
|
404
|
-
def _create_expr_result(
|
|
405
|
-
|
|
406
|
-
|
|
413
|
+
def _create_expr_result(
|
|
414
|
+
polars_func: Callable,
|
|
415
|
+
pl_args: list[Any],
|
|
416
|
+
pl_kwargs: dict[str, Any],
|
|
417
|
+
polars_func_name: str,
|
|
418
|
+
full_repr: str,
|
|
419
|
+
is_agg: bool,
|
|
420
|
+
convertible_to_code: bool,
|
|
421
|
+
function_sources: list[str] = None,
|
|
422
|
+
) -> "Expr":
|
|
407
423
|
"""
|
|
408
424
|
Create an Expr result for functions that return expressions.
|
|
409
425
|
|
|
@@ -422,9 +438,10 @@ def _create_expr_result(polars_func: Callable, pl_args: List[Any], pl_kwargs: Di
|
|
|
422
438
|
Returns:
|
|
423
439
|
Expr instance wrapping the polars expression
|
|
424
440
|
"""
|
|
425
|
-
from flowfile_frame.expr import Expr
|
|
426
441
|
import warnings
|
|
427
442
|
|
|
443
|
+
from flowfile_frame.expr import Expr
|
|
444
|
+
|
|
428
445
|
# Check for non-serializable functions
|
|
429
446
|
serialization_warnings = _check_for_non_serializable_functions(pl_args, pl_kwargs)
|
|
430
447
|
|
|
@@ -440,28 +457,30 @@ def _create_expr_result(polars_func: Callable, pl_args: List[Any], pl_kwargs: Di
|
|
|
440
457
|
try:
|
|
441
458
|
# Test serialization
|
|
442
459
|
import io
|
|
460
|
+
|
|
443
461
|
buffer = io.BytesIO()
|
|
444
|
-
pl_expr.serialize(file=buffer, format=
|
|
462
|
+
pl_expr.serialize(file=buffer, format="json")
|
|
445
463
|
except Exception as e:
|
|
446
464
|
serialization_error = str(e)
|
|
447
465
|
|
|
448
466
|
except Exception as e:
|
|
449
467
|
print(
|
|
450
|
-
f"Warning: Polars function '{polars_func_name}' failed to create an expression with provided arguments. Error: {e}"
|
|
468
|
+
f"Warning: Polars function '{polars_func_name}' failed to create an expression with provided arguments. Error: {e}"
|
|
469
|
+
)
|
|
451
470
|
if "serialization not supported" in str(e).lower():
|
|
452
471
|
serialization_error = str(e)
|
|
453
472
|
|
|
454
473
|
# Issue warnings if we found non-serializable functions
|
|
455
474
|
if serialization_warnings:
|
|
456
475
|
warnings.warn(
|
|
457
|
-
f"\n⚠️ SERIALIZATION WARNING for {polars_func_name}:\n"
|
|
458
|
-
"\n".join(f" • {w}" for w in serialization_warnings)
|
|
459
|
-
"\n\nThis expression cannot be saved to a FlowFile format and will need to be "
|
|
460
|
-
"recreated from scratch when loading the flow. The expression will work in the "
|
|
461
|
-
"current session but won't persist.\n"
|
|
462
|
-
(f"\nActual error from Polars: {serialization_error}" if serialization_error else ""),
|
|
476
|
+
f"\n⚠️ SERIALIZATION WARNING for {polars_func_name}:\n"
|
|
477
|
+
+ "\n".join(f" • {w}" for w in serialization_warnings)
|
|
478
|
+
+ "\n\nThis expression cannot be saved to a FlowFile format and will need to be "
|
|
479
|
+
+ "recreated from scratch when loading the flow. The expression will work in the "
|
|
480
|
+
+ "current session but won't persist.\n"
|
|
481
|
+
+ (f"\nActual error from Polars: {serialization_error}" if serialization_error else ""),
|
|
463
482
|
category=UserWarning,
|
|
464
|
-
stacklevel=3
|
|
483
|
+
stacklevel=3,
|
|
465
484
|
)
|
|
466
485
|
|
|
467
486
|
# Extract just the expression part without function definitions for repr_str
|
|
@@ -469,7 +488,7 @@ def _create_expr_result(polars_func: Callable, pl_args: List[Any], pl_kwargs: Di
|
|
|
469
488
|
# Get the part after the split
|
|
470
489
|
repr_str = full_repr.split("─────SPLIT─────")[-1].strip()
|
|
471
490
|
if repr_str.startswith("output_df = "):
|
|
472
|
-
repr_str = repr_str[len("output_df = "):]
|
|
491
|
+
repr_str = repr_str[len("output_df = ") :]
|
|
473
492
|
else:
|
|
474
493
|
repr_str = full_repr
|
|
475
494
|
|
|
@@ -479,11 +498,11 @@ def _create_expr_result(polars_func: Callable, pl_args: List[Any], pl_kwargs: Di
|
|
|
479
498
|
agg_func=polars_func_name if is_agg else None,
|
|
480
499
|
is_complex=True,
|
|
481
500
|
convertable_to_code=convertible_to_code and (pl_expr is not None),
|
|
482
|
-
_function_sources=function_sources # Pass function sources to Expr
|
|
501
|
+
_function_sources=function_sources, # Pass function sources to Expr
|
|
483
502
|
)
|
|
484
503
|
|
|
485
504
|
|
|
486
|
-
def _copy_function_metadata(original_func: Callable, polars_func_name: str) ->
|
|
505
|
+
def _copy_function_metadata(original_func: Callable, polars_func_name: str) -> tuple[str, str]:
|
|
487
506
|
"""
|
|
488
507
|
Copy metadata from the original polars function.
|
|
489
508
|
|
|
@@ -494,7 +513,7 @@ def _copy_function_metadata(original_func: Callable, polars_func_name: str) -> T
|
|
|
494
513
|
Returns:
|
|
495
514
|
Tuple of (function_name, docstring)
|
|
496
515
|
"""
|
|
497
|
-
original_doc = getattr(original_func,
|
|
516
|
+
original_doc = getattr(original_func, "__doc__", None) or ""
|
|
498
517
|
enhanced_doc = f"""FlowFile wrapper for pl.{polars_func_name}.
|
|
499
518
|
|
|
500
519
|
Original Polars documentation:
|
|
@@ -509,9 +528,9 @@ Wrapped functions returning Exprs will produce FlowFile Expr objects.
|
|
|
509
528
|
|
|
510
529
|
|
|
511
530
|
def polars_function_wrapper(
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
531
|
+
polars_func_name_or_callable: str | Callable,
|
|
532
|
+
is_agg: bool = False,
|
|
533
|
+
return_type: Literal["FlowFrame", "Expr"] | None = None,
|
|
515
534
|
):
|
|
516
535
|
"""
|
|
517
536
|
Create a wrapper for a polars function that returns either a FlowFrame or Expr.
|
|
@@ -547,31 +566,35 @@ def polars_function_wrapper(
|
|
|
547
566
|
wrapper_return_annotation_str: str
|
|
548
567
|
|
|
549
568
|
if determined_rt == "FlowFrame":
|
|
550
|
-
wrapper_return_annotation_str =
|
|
551
|
-
if not any(p.name ==
|
|
569
|
+
wrapper_return_annotation_str = "FlowFrame"
|
|
570
|
+
if not any(p.name == "flow_graph" for p in final_params_for_sig):
|
|
552
571
|
fg_param = inspect.Parameter(
|
|
553
|
-
name=
|
|
554
|
-
|
|
572
|
+
name="flow_graph",
|
|
573
|
+
kind=inspect.Parameter.KEYWORD_ONLY,
|
|
574
|
+
default=None,
|
|
575
|
+
annotation=Optional[FlowGraph], # Corrected annotation
|
|
555
576
|
)
|
|
556
577
|
var_kw_idx = next(
|
|
557
|
-
(i for i, p in enumerate(final_params_for_sig) if p.kind == inspect.Parameter.VAR_KEYWORD), -1
|
|
578
|
+
(i for i, p in enumerate(final_params_for_sig) if p.kind == inspect.Parameter.VAR_KEYWORD), -1
|
|
579
|
+
)
|
|
558
580
|
if var_kw_idx != -1:
|
|
559
581
|
final_params_for_sig.insert(var_kw_idx, fg_param)
|
|
560
582
|
else:
|
|
561
583
|
final_params_for_sig.append(fg_param)
|
|
562
584
|
elif determined_rt == "Expr":
|
|
563
|
-
wrapper_return_annotation_str =
|
|
585
|
+
wrapper_return_annotation_str = "Expr"
|
|
564
586
|
else:
|
|
565
587
|
wrapper_return_annotation_str = str(original_polars_sig.return_annotation)
|
|
566
588
|
|
|
567
|
-
wrapper_sig = inspect.Signature(
|
|
568
|
-
|
|
589
|
+
wrapper_sig = inspect.Signature(
|
|
590
|
+
parameters=final_params_for_sig, return_annotation=wrapper_return_annotation_str
|
|
591
|
+
)
|
|
569
592
|
|
|
570
593
|
@wraps(polars_f)
|
|
571
594
|
def wrapper(*args, **kwargs):
|
|
572
595
|
flow_graph_val = None
|
|
573
596
|
if determined_rt == "FlowFrame":
|
|
574
|
-
flow_graph_val = kwargs.pop(
|
|
597
|
+
flow_graph_val = kwargs.pop("flow_graph", None)
|
|
575
598
|
|
|
576
599
|
args_repr_val, pl_args_val, args_conv, args_func_sources = _process_arguments(
|
|
577
600
|
args, param_can_be_expr_map, param_list_for_processing
|
|
@@ -586,12 +609,18 @@ def polars_function_wrapper(
|
|
|
586
609
|
actual_polars_func_name, args_repr_val, kwargs_repr_val, all_func_sources
|
|
587
610
|
)
|
|
588
611
|
|
|
589
|
-
if determined_rt ==
|
|
612
|
+
if determined_rt == "FlowFrame":
|
|
590
613
|
return _create_flowframe_result(actual_polars_func_name, full_repr_val, flow_graph_val)
|
|
591
614
|
else: # Expr
|
|
592
615
|
return _create_expr_result(
|
|
593
|
-
polars_f,
|
|
594
|
-
|
|
616
|
+
polars_f,
|
|
617
|
+
pl_args_val,
|
|
618
|
+
pl_kwargs_val,
|
|
619
|
+
actual_polars_func_name,
|
|
620
|
+
full_repr_val,
|
|
621
|
+
is_agg,
|
|
622
|
+
conv_to_code,
|
|
623
|
+
all_func_sources, # Pass function sources
|
|
595
624
|
)
|
|
596
625
|
|
|
597
626
|
wrapper.__name__ = wrapper_name
|
|
@@ -604,7 +633,7 @@ def polars_function_wrapper(
|
|
|
604
633
|
else: # Used as @polars_function_wrapper("name", ...) or assigned
|
|
605
634
|
actual_polars_func_name = cast(str, polars_func_name_or_callable)
|
|
606
635
|
|
|
607
|
-
def decorator(func:
|
|
636
|
+
def decorator(func: Callable | None = None): # func is the decorated placeholder
|
|
608
637
|
polars_f = getattr(pl, actual_polars_func_name, None)
|
|
609
638
|
if polars_f is None:
|
|
610
639
|
raise ValueError(f"Polars function '{actual_polars_func_name}' not found.")
|
|
@@ -620,56 +649,68 @@ def polars_function_wrapper(
|
|
|
620
649
|
wrapper_return_annotation_str: str
|
|
621
650
|
|
|
622
651
|
if determined_rt == "FlowFrame":
|
|
623
|
-
wrapper_return_annotation_str =
|
|
624
|
-
if not any(p.name ==
|
|
652
|
+
wrapper_return_annotation_str = "FlowFrame"
|
|
653
|
+
if not any(p.name == "flow_graph" for p in final_params_for_sig):
|
|
625
654
|
flow_graph_param = inspect.Parameter(
|
|
626
|
-
name=
|
|
655
|
+
name="flow_graph",
|
|
627
656
|
kind=inspect.Parameter.KEYWORD_ONLY,
|
|
628
657
|
default=None,
|
|
629
|
-
annotation=Optional[FlowGraph] # Corrected annotation
|
|
658
|
+
annotation=Optional[FlowGraph], # Corrected annotation
|
|
630
659
|
)
|
|
631
660
|
var_kw_idx = next(
|
|
632
|
-
(i for i, p in enumerate(final_params_for_sig) if p.kind == inspect.Parameter.VAR_KEYWORD), -1
|
|
661
|
+
(i for i, p in enumerate(final_params_for_sig) if p.kind == inspect.Parameter.VAR_KEYWORD), -1
|
|
662
|
+
)
|
|
633
663
|
if var_kw_idx != -1:
|
|
634
664
|
final_params_for_sig.insert(var_kw_idx, flow_graph_param)
|
|
635
665
|
else:
|
|
636
666
|
final_params_for_sig.append(flow_graph_param)
|
|
637
667
|
elif determined_rt == "Expr":
|
|
638
|
-
wrapper_return_annotation_str =
|
|
668
|
+
wrapper_return_annotation_str = "Expr"
|
|
639
669
|
else:
|
|
640
670
|
wrapper_return_annotation_str = str(original_polars_sig.return_annotation)
|
|
641
671
|
|
|
642
672
|
wrapper_signature = inspect.Signature(
|
|
643
|
-
parameters=final_params_for_sig,
|
|
644
|
-
return_annotation=wrapper_return_annotation_str
|
|
673
|
+
parameters=final_params_for_sig, return_annotation=wrapper_return_annotation_str
|
|
645
674
|
)
|
|
646
675
|
|
|
647
676
|
@wraps(polars_f)
|
|
648
677
|
def wrapper(*args, **kwargs):
|
|
649
678
|
flow_graph_val = None
|
|
650
679
|
if determined_rt == "FlowFrame":
|
|
651
|
-
flow_graph_val = kwargs.pop(
|
|
680
|
+
flow_graph_val = kwargs.pop("flow_graph", None)
|
|
652
681
|
|
|
653
682
|
args_repr_val, pl_args_val, args_convertible_val, args_func_sources = _process_arguments(
|
|
654
683
|
args, param_can_be_expr_map, param_list_for_processing
|
|
655
684
|
)
|
|
656
|
-
kwargs_repr_val, pl_kwargs_val, kwargs_convertible_val, kwargs_func_sources =
|
|
657
|
-
kwargs, param_can_be_expr_map
|
|
685
|
+
kwargs_repr_val, pl_kwargs_val, kwargs_convertible_val, kwargs_func_sources = (
|
|
686
|
+
_process_keyword_arguments(kwargs, param_can_be_expr_map)
|
|
658
687
|
)
|
|
659
688
|
|
|
660
|
-
convertible_to_code_val =
|
|
689
|
+
convertible_to_code_val = (
|
|
690
|
+
args_convertible_val and kwargs_convertible_val
|
|
691
|
+
) # Correct variable for this scope
|
|
661
692
|
all_func_sources = args_func_sources + kwargs_func_sources
|
|
662
693
|
|
|
663
694
|
full_repr_val = _build_repr_string(
|
|
664
|
-
actual_polars_func_name,
|
|
695
|
+
actual_polars_func_name,
|
|
696
|
+
args_repr_val,
|
|
697
|
+
kwargs_repr_val,
|
|
698
|
+
all_func_sources, # Corrected variable
|
|
665
699
|
)
|
|
666
700
|
|
|
667
|
-
if determined_rt ==
|
|
701
|
+
if determined_rt == "FlowFrame":
|
|
668
702
|
return _create_flowframe_result(actual_polars_func_name, full_repr_val, flow_graph_val)
|
|
669
703
|
else: # Expr
|
|
670
|
-
return _create_expr_result(
|
|
671
|
-
|
|
672
|
-
|
|
704
|
+
return _create_expr_result(
|
|
705
|
+
polars_f,
|
|
706
|
+
pl_args_val,
|
|
707
|
+
pl_kwargs_val,
|
|
708
|
+
actual_polars_func_name,
|
|
709
|
+
full_repr_val,
|
|
710
|
+
is_agg,
|
|
711
|
+
convertible_to_code_val,
|
|
712
|
+
all_func_sources,
|
|
713
|
+
) # Pass function sources
|
|
673
714
|
|
|
674
715
|
wrapper.__name__ = wrapper_name
|
|
675
716
|
wrapper.__doc__ = wrapper_doc
|
|
@@ -683,22 +724,23 @@ def polars_function_wrapper(
|
|
|
683
724
|
|
|
684
725
|
# Example usage with the new decorator (from original snippet):
|
|
685
726
|
|
|
727
|
+
|
|
686
728
|
# For functions that return FlowFrames
|
|
687
|
-
@polars_function_wrapper(
|
|
688
|
-
def read_json(*args, flow_graph:
|
|
729
|
+
@polars_function_wrapper("read_json", return_type="FlowFrame")
|
|
730
|
+
def read_json(*args, flow_graph: FlowGraph | None = None, **kwargs) -> FlowFrame:
|
|
689
731
|
pass
|
|
690
732
|
|
|
691
733
|
|
|
692
|
-
@polars_function_wrapper(
|
|
693
|
-
def read_avro(*args, flow_graph:
|
|
734
|
+
@polars_function_wrapper("read_avro", return_type="FlowFrame")
|
|
735
|
+
def read_avro(*args, flow_graph: FlowGraph | None = None, **kwargs) -> FlowFrame:
|
|
694
736
|
pass
|
|
695
737
|
|
|
696
738
|
|
|
697
|
-
@polars_function_wrapper(
|
|
698
|
-
def read_ndjson(*args, flow_graph:
|
|
739
|
+
@polars_function_wrapper("read_ndjson", return_type="FlowFrame")
|
|
740
|
+
def read_ndjson(*args, flow_graph: FlowGraph | None = None, **kwargs) -> FlowFrame:
|
|
699
741
|
pass
|
|
700
742
|
|
|
701
743
|
|
|
702
|
-
@polars_function_wrapper(
|
|
703
|
-
def fold(*args, **kwargs) ->
|
|
704
|
-
pass
|
|
744
|
+
@polars_function_wrapper("fold", return_type="Expr")
|
|
745
|
+
def fold(*args, **kwargs) -> "Expr": # Type hint 'Expr' refers to flowfile_frame.expr.Expr
|
|
746
|
+
pass
|