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
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
Compatibility enhancements for opening old flowfile versions.
|
|
3
3
|
Migrates old schema structures to new ones during file load.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
import pickle
|
|
6
|
-
from typing import Any
|
|
7
7
|
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
8
9
|
|
|
9
|
-
from flowfile_core.schemas import
|
|
10
|
+
from flowfile_core.schemas import input_schema, schemas
|
|
10
11
|
from tools.migrate.legacy_schemas import LEGACY_CLASS_MAP
|
|
11
12
|
|
|
12
|
-
|
|
13
13
|
# =============================================================================
|
|
14
14
|
# LEGACY PICKLE LOADING
|
|
15
15
|
# =============================================================================
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
class LegacyUnpickler(pickle.Unpickler):
|
|
18
19
|
"""
|
|
19
20
|
Custom unpickler that redirects class lookups to legacy dataclass definitions.
|
|
@@ -45,7 +46,7 @@ def load_flowfile_pickle(path: str) -> Any:
|
|
|
45
46
|
The deserialized FlowInformation object
|
|
46
47
|
"""
|
|
47
48
|
resolved_path = Path(path).resolve()
|
|
48
|
-
with open(resolved_path,
|
|
49
|
+
with open(resolved_path, "rb") as f:
|
|
49
50
|
return LegacyUnpickler(f).load()
|
|
50
51
|
|
|
51
52
|
|
|
@@ -53,9 +54,10 @@ def load_flowfile_pickle(path: str) -> Any:
|
|
|
53
54
|
# DATACLASS DETECTION AND MIGRATION
|
|
54
55
|
# =============================================================================
|
|
55
56
|
|
|
57
|
+
|
|
56
58
|
def _is_dataclass_instance(obj: Any) -> bool:
|
|
57
59
|
"""Check if an object is a dataclass instance (not a Pydantic model)."""
|
|
58
|
-
return hasattr(obj,
|
|
60
|
+
return hasattr(obj, "__dataclass_fields__") and not hasattr(obj, "model_dump")
|
|
59
61
|
|
|
60
62
|
|
|
61
63
|
def _migrate_dataclass_to_basemodel(obj: Any, model_class: type) -> Any:
|
|
@@ -66,7 +68,8 @@ def _migrate_dataclass_to_basemodel(obj: Any, model_class: type) -> Any:
|
|
|
66
68
|
if not _is_dataclass_instance(obj):
|
|
67
69
|
return obj # Already a BaseModel or dict
|
|
68
70
|
|
|
69
|
-
from dataclasses import
|
|
71
|
+
from dataclasses import asdict, fields
|
|
72
|
+
|
|
70
73
|
try:
|
|
71
74
|
data = asdict(obj)
|
|
72
75
|
except Exception:
|
|
@@ -80,42 +83,43 @@ def _migrate_dataclass_to_basemodel(obj: Any, model_class: type) -> Any:
|
|
|
80
83
|
# NODE-SPECIFIC COMPATIBILITY FUNCTIONS
|
|
81
84
|
# =============================================================================
|
|
82
85
|
|
|
86
|
+
|
|
83
87
|
def ensure_compatibility_node_read(node_read: input_schema.NodeRead):
|
|
84
88
|
"""Migrate old NodeRead/ReceivedTable structure to new table_settings format."""
|
|
85
|
-
if not hasattr(node_read,
|
|
89
|
+
if not hasattr(node_read, "received_file") or node_read.received_file is None:
|
|
86
90
|
return
|
|
87
91
|
|
|
88
92
|
received_file = node_read.received_file
|
|
89
93
|
|
|
90
94
|
# Ensure fields list exists
|
|
91
|
-
if not hasattr(received_file,
|
|
92
|
-
|
|
95
|
+
if not hasattr(received_file, "fields"):
|
|
96
|
+
received_file.fields = []
|
|
93
97
|
|
|
94
98
|
# Check if already migrated (has table_settings as proper object, not dict)
|
|
95
|
-
if hasattr(received_file,
|
|
99
|
+
if hasattr(received_file, "table_settings") and received_file.table_settings is not None:
|
|
96
100
|
if not isinstance(received_file.table_settings, dict):
|
|
97
101
|
return
|
|
98
102
|
|
|
99
103
|
# Determine file_type - use existing or infer from attributes
|
|
100
|
-
file_type = getattr(received_file,
|
|
104
|
+
file_type = getattr(received_file, "file_type", None)
|
|
101
105
|
if file_type is None:
|
|
102
|
-
path = getattr(received_file,
|
|
103
|
-
if path.endswith(
|
|
104
|
-
file_type =
|
|
105
|
-
elif path.endswith((
|
|
106
|
-
file_type =
|
|
107
|
-
elif path.endswith(
|
|
108
|
-
file_type =
|
|
106
|
+
path = getattr(received_file, "path", "") or ""
|
|
107
|
+
if path.endswith(".parquet"):
|
|
108
|
+
file_type = "parquet"
|
|
109
|
+
elif path.endswith((".xlsx", ".xls")):
|
|
110
|
+
file_type = "excel"
|
|
111
|
+
elif path.endswith(".json"):
|
|
112
|
+
file_type = "json"
|
|
109
113
|
else:
|
|
110
|
-
file_type =
|
|
114
|
+
file_type = "csv"
|
|
111
115
|
|
|
112
116
|
# Build table_settings based on file_type, extracting old flat attributes
|
|
113
117
|
table_settings_dict = _build_input_table_settings(received_file, file_type)
|
|
114
118
|
|
|
115
119
|
# Re-validate the entire ReceivedTable to get proper Pydantic model
|
|
116
120
|
received_file_dict = received_file.model_dump()
|
|
117
|
-
received_file_dict[
|
|
118
|
-
received_file_dict[
|
|
121
|
+
received_file_dict["file_type"] = file_type
|
|
122
|
+
received_file_dict["table_settings"] = table_settings_dict
|
|
119
123
|
|
|
120
124
|
# Create new validated ReceivedTable and replace
|
|
121
125
|
new_received_file = input_schema.ReceivedTable.model_validate(received_file_dict)
|
|
@@ -125,79 +129,79 @@ def ensure_compatibility_node_read(node_read: input_schema.NodeRead):
|
|
|
125
129
|
def _build_input_table_settings(received_file: Any, file_type: str) -> dict:
|
|
126
130
|
"""Build appropriate table_settings dict from old flat attributes."""
|
|
127
131
|
|
|
128
|
-
if file_type ==
|
|
132
|
+
if file_type == "csv":
|
|
129
133
|
return {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
134
|
+
"file_type": "csv",
|
|
135
|
+
"reference": getattr(received_file, "reference", ""),
|
|
136
|
+
"starting_from_line": getattr(received_file, "starting_from_line", 0),
|
|
137
|
+
"delimiter": getattr(received_file, "delimiter", ","),
|
|
138
|
+
"has_headers": getattr(received_file, "has_headers", True),
|
|
139
|
+
"encoding": getattr(received_file, "encoding", "utf-8"),
|
|
140
|
+
"parquet_ref": getattr(received_file, "parquet_ref", None),
|
|
141
|
+
"row_delimiter": getattr(received_file, "row_delimiter", "\n"),
|
|
142
|
+
"quote_char": getattr(received_file, "quote_char", '"'),
|
|
143
|
+
"infer_schema_length": getattr(received_file, "infer_schema_length", 10_000),
|
|
144
|
+
"truncate_ragged_lines": getattr(received_file, "truncate_ragged_lines", False),
|
|
145
|
+
"ignore_errors": getattr(received_file, "ignore_errors", False),
|
|
142
146
|
}
|
|
143
147
|
|
|
144
|
-
elif file_type ==
|
|
148
|
+
elif file_type == "json":
|
|
145
149
|
return {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
150
|
+
"file_type": "json",
|
|
151
|
+
"reference": getattr(received_file, "reference", ""),
|
|
152
|
+
"starting_from_line": getattr(received_file, "starting_from_line", 0),
|
|
153
|
+
"delimiter": getattr(received_file, "delimiter", ","),
|
|
154
|
+
"has_headers": getattr(received_file, "has_headers", True),
|
|
155
|
+
"encoding": getattr(received_file, "encoding", "utf-8"),
|
|
156
|
+
"parquet_ref": getattr(received_file, "parquet_ref", None),
|
|
157
|
+
"row_delimiter": getattr(received_file, "row_delimiter", "\n"),
|
|
158
|
+
"quote_char": getattr(received_file, "quote_char", '"'),
|
|
159
|
+
"infer_schema_length": getattr(received_file, "infer_schema_length", 10_000),
|
|
160
|
+
"truncate_ragged_lines": getattr(received_file, "truncate_ragged_lines", False),
|
|
161
|
+
"ignore_errors": getattr(received_file, "ignore_errors", False),
|
|
158
162
|
}
|
|
159
163
|
|
|
160
|
-
elif file_type ==
|
|
161
|
-
return {
|
|
164
|
+
elif file_type == "parquet":
|
|
165
|
+
return {"file_type": "parquet"}
|
|
162
166
|
|
|
163
|
-
elif file_type ==
|
|
167
|
+
elif file_type == "excel":
|
|
164
168
|
return {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
"file_type": "excel",
|
|
170
|
+
"sheet_name": getattr(received_file, "sheet_name", None),
|
|
171
|
+
"start_row": getattr(received_file, "start_row", 0),
|
|
172
|
+
"start_column": getattr(received_file, "start_column", 0),
|
|
173
|
+
"end_row": getattr(received_file, "end_row", 0),
|
|
174
|
+
"end_column": getattr(received_file, "end_column", 0),
|
|
175
|
+
"has_headers": getattr(received_file, "has_headers", True),
|
|
176
|
+
"type_inference": getattr(received_file, "type_inference", False),
|
|
173
177
|
}
|
|
174
178
|
|
|
175
179
|
# Default to csv settings
|
|
176
|
-
return {
|
|
180
|
+
return {"file_type": "csv", "delimiter": ",", "encoding": "utf-8", "has_headers": True}
|
|
177
181
|
|
|
178
182
|
|
|
179
183
|
def ensure_compatibility_node_output(node_output: input_schema.NodeOutput):
|
|
180
184
|
"""Migrate old OutputSettings structure to new table_settings format."""
|
|
181
|
-
if not hasattr(node_output,
|
|
185
|
+
if not hasattr(node_output, "output_settings") or node_output.output_settings is None:
|
|
182
186
|
return
|
|
183
187
|
|
|
184
188
|
output_settings = node_output.output_settings
|
|
185
189
|
|
|
186
190
|
# Check if already migrated (has table_settings as proper object, not dict)
|
|
187
|
-
if hasattr(output_settings,
|
|
191
|
+
if hasattr(output_settings, "table_settings") and output_settings.table_settings is not None:
|
|
188
192
|
if not isinstance(output_settings.table_settings, dict):
|
|
189
193
|
return
|
|
190
194
|
|
|
191
195
|
# Migrate from old separate fields to new table_settings
|
|
192
|
-
file_type = getattr(output_settings,
|
|
196
|
+
file_type = getattr(output_settings, "file_type", "csv")
|
|
193
197
|
table_settings_dict = _build_output_table_settings(output_settings, file_type)
|
|
194
198
|
|
|
195
199
|
# Re-validate the entire OutputSettings to get proper Pydantic model
|
|
196
200
|
output_settings_dict = output_settings.model_dump()
|
|
197
|
-
output_settings_dict[
|
|
201
|
+
output_settings_dict["table_settings"] = table_settings_dict
|
|
198
202
|
|
|
199
203
|
# Remove old fields if they exist
|
|
200
|
-
for old_field in [
|
|
204
|
+
for old_field in ["output_csv_table", "output_parquet_table", "output_excel_table"]:
|
|
201
205
|
output_settings_dict.pop(old_field, None)
|
|
202
206
|
|
|
203
207
|
# Create new validated OutputSettings and replace
|
|
@@ -208,39 +212,117 @@ def ensure_compatibility_node_output(node_output: input_schema.NodeOutput):
|
|
|
208
212
|
def _build_output_table_settings(output_settings: Any, file_type: str) -> dict:
|
|
209
213
|
"""Build appropriate output table_settings from old separate table fields."""
|
|
210
214
|
|
|
211
|
-
if file_type ==
|
|
212
|
-
old_csv = getattr(output_settings,
|
|
215
|
+
if file_type == "csv":
|
|
216
|
+
old_csv = getattr(output_settings, "output_csv_table", None)
|
|
213
217
|
if old_csv is not None:
|
|
214
218
|
return {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
219
|
+
"file_type": "csv",
|
|
220
|
+
"delimiter": getattr(old_csv, "delimiter", ","),
|
|
221
|
+
"encoding": getattr(old_csv, "encoding", "utf-8"),
|
|
218
222
|
}
|
|
219
|
-
return {
|
|
223
|
+
return {"file_type": "csv", "delimiter": ",", "encoding": "utf-8"}
|
|
220
224
|
|
|
221
|
-
elif file_type ==
|
|
222
|
-
return {
|
|
225
|
+
elif file_type == "parquet":
|
|
226
|
+
return {"file_type": "parquet"}
|
|
223
227
|
|
|
224
|
-
elif file_type ==
|
|
225
|
-
old_excel = getattr(output_settings,
|
|
228
|
+
elif file_type == "excel":
|
|
229
|
+
old_excel = getattr(output_settings, "output_excel_table", None)
|
|
226
230
|
if old_excel is not None:
|
|
227
231
|
return {
|
|
228
|
-
|
|
229
|
-
|
|
232
|
+
"file_type": "excel",
|
|
233
|
+
"sheet_name": getattr(old_excel, "sheet_name", "Sheet1"),
|
|
230
234
|
}
|
|
231
|
-
return {
|
|
235
|
+
return {"file_type": "excel", "sheet_name": "Sheet1"}
|
|
236
|
+
|
|
237
|
+
return {"file_type": "csv", "delimiter": ",", "encoding": "utf-8"}
|
|
232
238
|
|
|
233
|
-
|
|
239
|
+
|
|
240
|
+
def ensure_compatibility_node_groupby(node_groupby: input_schema.NodeGroupBy):
|
|
241
|
+
"""Migrate old NodeGroupBy structure:
|
|
242
|
+
- GroupByInput dataclass -> BaseModel
|
|
243
|
+
- AggColl dataclass -> BaseModel
|
|
244
|
+
"""
|
|
245
|
+
if not hasattr(node_groupby, "groupby_input") or node_groupby.groupby_input is None:
|
|
246
|
+
return
|
|
247
|
+
|
|
248
|
+
groupby_input = node_groupby.groupby_input
|
|
249
|
+
|
|
250
|
+
# Check if already migrated (is a Pydantic model)
|
|
251
|
+
if not _is_dataclass_instance(groupby_input):
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
from flowfile_core.schemas import transform_schema
|
|
255
|
+
|
|
256
|
+
# Migrate each AggColl in agg_cols
|
|
257
|
+
agg_cols = getattr(groupby_input, "agg_cols", []) or []
|
|
258
|
+
new_agg_cols = []
|
|
259
|
+
for agg_col in agg_cols:
|
|
260
|
+
if _is_dataclass_instance(agg_col):
|
|
261
|
+
new_agg_col = _migrate_dataclass_to_basemodel(agg_col, transform_schema.AggColl)
|
|
262
|
+
new_agg_cols.append(new_agg_col)
|
|
263
|
+
else:
|
|
264
|
+
new_agg_cols.append(agg_col)
|
|
265
|
+
|
|
266
|
+
# Create new validated GroupByInput and replace
|
|
267
|
+
new_groupby_input = transform_schema.GroupByInput(agg_cols=new_agg_cols)
|
|
268
|
+
node_groupby.groupby_input = new_groupby_input
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def ensure_compatibility_node_filter(node_filter: input_schema.NodeFilter):
|
|
272
|
+
"""Migrate old NodeFilter structure:
|
|
273
|
+
- FilterInput dataclass -> BaseModel
|
|
274
|
+
- filter_type -> mode
|
|
275
|
+
- BasicFilter.filter_type -> BasicFilter.operator
|
|
276
|
+
- BasicFilter.filter_value -> BasicFilter.value
|
|
277
|
+
"""
|
|
278
|
+
if not hasattr(node_filter, "filter_input") or node_filter.filter_input is None:
|
|
279
|
+
return
|
|
280
|
+
|
|
281
|
+
filter_input = node_filter.filter_input
|
|
282
|
+
|
|
283
|
+
# Check if already migrated (is a Pydantic model)
|
|
284
|
+
if not _is_dataclass_instance(filter_input):
|
|
285
|
+
return
|
|
286
|
+
|
|
287
|
+
from flowfile_core.schemas import transform_schema
|
|
288
|
+
|
|
289
|
+
# Build the new FilterInput data with field name mappings
|
|
290
|
+
filter_data = {
|
|
291
|
+
# filter_type -> mode
|
|
292
|
+
"mode": getattr(filter_input, "filter_type", "basic"),
|
|
293
|
+
"advanced_filter": getattr(filter_input, "advanced_filter", ""),
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
# Handle BasicFilter migration
|
|
297
|
+
basic_filter = getattr(filter_input, "basic_filter", None)
|
|
298
|
+
if basic_filter is not None:
|
|
299
|
+
if _is_dataclass_instance(basic_filter):
|
|
300
|
+
# Map old field names to new ones
|
|
301
|
+
basic_filter_data = {
|
|
302
|
+
"field": getattr(basic_filter, "field", ""),
|
|
303
|
+
# filter_type -> operator
|
|
304
|
+
"operator": getattr(basic_filter, "filter_type", "equals"),
|
|
305
|
+
# filter_value -> value
|
|
306
|
+
"value": getattr(basic_filter, "filter_value", ""),
|
|
307
|
+
}
|
|
308
|
+
filter_data["basic_filter"] = transform_schema.BasicFilter.model_validate(basic_filter_data)
|
|
309
|
+
else:
|
|
310
|
+
filter_data["basic_filter"] = basic_filter
|
|
311
|
+
|
|
312
|
+
# Create new validated FilterInput and replace
|
|
313
|
+
new_filter_input = transform_schema.FilterInput.model_validate(filter_data)
|
|
314
|
+
node_filter.filter_input = new_filter_input
|
|
234
315
|
|
|
235
316
|
|
|
236
317
|
def ensure_compatibility_node_select(node_select: input_schema.NodeSelect):
|
|
237
318
|
"""Ensure NodeSelect has position attributes, sorted_by field, and handle dataclass migrations."""
|
|
238
|
-
if not hasattr(node_select,
|
|
319
|
+
if not hasattr(node_select, "select_input"):
|
|
239
320
|
return
|
|
240
321
|
|
|
241
322
|
# Handle dataclass -> BaseModel migration for select_input items
|
|
242
323
|
if node_select.select_input:
|
|
243
324
|
from flowfile_core.schemas import transform_schema
|
|
325
|
+
|
|
244
326
|
new_select_input = []
|
|
245
327
|
needs_migration = any(_is_dataclass_instance(si) for si in node_select.select_input)
|
|
246
328
|
|
|
@@ -254,29 +336,29 @@ def ensure_compatibility_node_select(node_select: input_schema.NodeSelect):
|
|
|
254
336
|
node_select.select_input = new_select_input
|
|
255
337
|
|
|
256
338
|
# Ensure position attributes exist
|
|
257
|
-
if any(not hasattr(select_input,
|
|
339
|
+
if any(not hasattr(select_input, "position") for select_input in node_select.select_input):
|
|
258
340
|
for _index, select_input in enumerate(node_select.select_input):
|
|
259
|
-
|
|
341
|
+
select_input.position = _index
|
|
260
342
|
|
|
261
|
-
if not hasattr(node_select,
|
|
262
|
-
|
|
343
|
+
if not hasattr(node_select, "sorted_by"):
|
|
344
|
+
node_select.sorted_by = "none"
|
|
263
345
|
|
|
264
346
|
|
|
265
347
|
def ensure_compatibility_node_joins(node_settings: input_schema.NodeFuzzyMatch | input_schema.NodeJoin):
|
|
266
348
|
"""Ensure join nodes have position attributes on renames and handle dataclass migrations."""
|
|
267
|
-
if not hasattr(node_settings,
|
|
349
|
+
if not hasattr(node_settings, "join_input") or node_settings.join_input is None:
|
|
268
350
|
return
|
|
269
351
|
|
|
270
352
|
join_input = node_settings.join_input
|
|
271
353
|
|
|
272
354
|
# Check if right_select and left_select exist
|
|
273
|
-
if not hasattr(join_input,
|
|
355
|
+
if not hasattr(join_input, "right_select") or not hasattr(join_input, "left_select"):
|
|
274
356
|
return
|
|
275
357
|
|
|
276
358
|
from flowfile_core.schemas import transform_schema
|
|
277
359
|
|
|
278
360
|
# Handle dataclass -> BaseModel migration for join_mapping
|
|
279
|
-
if hasattr(join_input,
|
|
361
|
+
if hasattr(join_input, "join_mapping") and join_input.join_mapping:
|
|
280
362
|
new_mapping = []
|
|
281
363
|
for jm in join_input.join_mapping:
|
|
282
364
|
if _is_dataclass_instance(jm):
|
|
@@ -287,12 +369,12 @@ def ensure_compatibility_node_joins(node_settings: input_schema.NodeFuzzyMatch |
|
|
|
287
369
|
join_input.join_mapping = new_mapping
|
|
288
370
|
|
|
289
371
|
# Handle dataclass -> BaseModel migration for renames in selects
|
|
290
|
-
for select_attr in [
|
|
372
|
+
for select_attr in ["right_select", "left_select"]:
|
|
291
373
|
select = getattr(join_input, select_attr, None)
|
|
292
374
|
if select is None:
|
|
293
375
|
continue
|
|
294
376
|
|
|
295
|
-
renames = getattr(select,
|
|
377
|
+
renames = getattr(select, "renames", []) or []
|
|
296
378
|
if renames and any(_is_dataclass_instance(r) for r in renames):
|
|
297
379
|
new_renames = []
|
|
298
380
|
for r in renames:
|
|
@@ -303,19 +385,19 @@ def ensure_compatibility_node_joins(node_settings: input_schema.NodeFuzzyMatch |
|
|
|
303
385
|
new_renames.append(r)
|
|
304
386
|
select.renames = new_renames
|
|
305
387
|
|
|
306
|
-
right_renames = getattr(join_input.right_select,
|
|
307
|
-
left_renames = getattr(join_input.left_select,
|
|
388
|
+
right_renames = getattr(join_input.right_select, "renames", []) or []
|
|
389
|
+
left_renames = getattr(join_input.left_select, "renames", []) or []
|
|
308
390
|
|
|
309
391
|
# Ensure position attributes exist
|
|
310
|
-
if any(not hasattr(r,
|
|
392
|
+
if any(not hasattr(r, "position") for r in right_renames + left_renames):
|
|
311
393
|
for _index, select_input in enumerate(right_renames + left_renames):
|
|
312
|
-
|
|
394
|
+
select_input.position = _index
|
|
313
395
|
|
|
314
396
|
|
|
315
397
|
def ensure_description(node: input_schema.NodeBase):
|
|
316
398
|
"""Ensure node has description field."""
|
|
317
|
-
if not hasattr(node,
|
|
318
|
-
|
|
399
|
+
if not hasattr(node, "description"):
|
|
400
|
+
node.description = ""
|
|
319
401
|
|
|
320
402
|
|
|
321
403
|
def ensure_compatibility_node_polars(node_polars: input_schema.NodePolarsCode):
|
|
@@ -324,23 +406,22 @@ def ensure_compatibility_node_polars(node_polars: input_schema.NodePolarsCode):
|
|
|
324
406
|
- PolarsCodeInput from dataclass to BaseModel
|
|
325
407
|
"""
|
|
326
408
|
# Handle depending_on_id -> depending_on_ids migration
|
|
327
|
-
if hasattr(node_polars,
|
|
328
|
-
old_id = getattr(node_polars,
|
|
329
|
-
if not hasattr(node_polars,
|
|
409
|
+
if hasattr(node_polars, "depending_on_id"):
|
|
410
|
+
old_id = getattr(node_polars, "depending_on_id", None)
|
|
411
|
+
if not hasattr(node_polars, "depending_on_ids") or node_polars.depending_on_ids is None:
|
|
330
412
|
if old_id is not None:
|
|
331
|
-
|
|
413
|
+
node_polars.depending_on_ids = [old_id]
|
|
332
414
|
else:
|
|
333
|
-
|
|
415
|
+
node_polars.depending_on_ids = []
|
|
334
416
|
|
|
335
417
|
# Handle PolarsCodeInput dataclass -> BaseModel migration
|
|
336
|
-
if hasattr(node_polars,
|
|
418
|
+
if hasattr(node_polars, "polars_code_input") and node_polars.polars_code_input is not None:
|
|
337
419
|
polars_code_input = node_polars.polars_code_input
|
|
338
420
|
|
|
339
421
|
if _is_dataclass_instance(polars_code_input):
|
|
340
422
|
from flowfile_core.schemas import transform_schema
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
)
|
|
423
|
+
|
|
424
|
+
new_polars_code_input = _migrate_dataclass_to_basemodel(polars_code_input, transform_schema.PolarsCodeInput)
|
|
344
425
|
node_polars.polars_code_input = new_polars_code_input
|
|
345
426
|
|
|
346
427
|
|
|
@@ -348,31 +429,30 @@ def ensure_compatibility_node_polars(node_polars: input_schema.NodePolarsCode):
|
|
|
348
429
|
# FLOW-LEVEL COMPATIBILITY
|
|
349
430
|
# =============================================================================
|
|
350
431
|
|
|
432
|
+
|
|
351
433
|
def ensure_flow_settings(flow_storage_obj: schemas.FlowInformation, flow_path: str):
|
|
352
434
|
"""Ensure flow_settings exists and has all required fields."""
|
|
353
|
-
if not hasattr(flow_storage_obj,
|
|
435
|
+
if not hasattr(flow_storage_obj, "flow_settings") or flow_storage_obj.flow_settings is None:
|
|
354
436
|
flow_settings = schemas.FlowSettings(
|
|
355
|
-
flow_id=flow_storage_obj.flow_id,
|
|
356
|
-
path=flow_path,
|
|
357
|
-
name=flow_storage_obj.flow_name
|
|
437
|
+
flow_id=flow_storage_obj.flow_id, path=flow_path, name=flow_storage_obj.flow_name
|
|
358
438
|
)
|
|
359
|
-
|
|
439
|
+
flow_storage_obj.flow_settings = flow_settings
|
|
360
440
|
flow_storage_obj = schemas.FlowInformation.model_validate(flow_storage_obj)
|
|
361
441
|
return flow_storage_obj
|
|
362
442
|
|
|
363
443
|
fs = flow_storage_obj.flow_settings
|
|
444
|
+
if not hasattr(fs, "execution_location"):
|
|
445
|
+
fs.execution_location = "remote"
|
|
446
|
+
elif fs.execution_location == "auto":
|
|
447
|
+
fs.execution_location = "remote"
|
|
448
|
+
if not hasattr(fs, "is_running"):
|
|
449
|
+
fs.is_running = False
|
|
364
450
|
|
|
365
|
-
if not hasattr(fs,
|
|
366
|
-
|
|
451
|
+
if not hasattr(fs, "is_canceled"):
|
|
452
|
+
fs.is_canceled = False
|
|
367
453
|
|
|
368
|
-
if not hasattr(fs,
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
if not hasattr(fs, 'is_canceled'):
|
|
372
|
-
setattr(fs, 'is_canceled', False)
|
|
373
|
-
|
|
374
|
-
if not hasattr(fs, 'show_detailed_progress'):
|
|
375
|
-
setattr(fs, 'show_detailed_progress', True)
|
|
454
|
+
if not hasattr(fs, "show_detailed_progress"):
|
|
455
|
+
fs.show_detailed_progress = True
|
|
376
456
|
|
|
377
457
|
return flow_storage_obj
|
|
378
458
|
|
|
@@ -381,6 +461,7 @@ def ensure_flow_settings(flow_storage_obj: schemas.FlowInformation, flow_path: s
|
|
|
381
461
|
# MAIN ENTRY POINT
|
|
382
462
|
# =============================================================================
|
|
383
463
|
|
|
464
|
+
|
|
384
465
|
def ensure_compatibility(flow_storage_obj: schemas.FlowInformation, flow_path: str):
|
|
385
466
|
"""
|
|
386
467
|
Main compatibility function - migrates old flowfile schemas to current version.
|
|
@@ -395,25 +476,27 @@ def ensure_compatibility(flow_storage_obj: schemas.FlowInformation, flow_path: s
|
|
|
395
476
|
- Node descriptions
|
|
396
477
|
"""
|
|
397
478
|
flow_storage_obj = ensure_flow_settings(flow_storage_obj, flow_path)
|
|
398
|
-
|
|
399
479
|
for _id, node_information in flow_storage_obj.data.items():
|
|
400
|
-
if not hasattr(node_information,
|
|
480
|
+
if not hasattr(node_information, "setting_input") or node_information.setting_input is None:
|
|
401
481
|
continue
|
|
402
482
|
|
|
403
483
|
setting_input = node_information.setting_input
|
|
404
484
|
class_name = setting_input.__class__.__name__
|
|
405
485
|
|
|
406
|
-
if class_name ==
|
|
486
|
+
if class_name == "NodeRead":
|
|
407
487
|
ensure_compatibility_node_read(setting_input)
|
|
408
|
-
elif class_name ==
|
|
488
|
+
elif class_name == "NodeSelect":
|
|
409
489
|
ensure_compatibility_node_select(setting_input)
|
|
410
|
-
elif class_name ==
|
|
490
|
+
elif class_name == "NodeOutput":
|
|
411
491
|
ensure_compatibility_node_output(setting_input)
|
|
412
|
-
elif class_name in (
|
|
492
|
+
elif class_name in ("NodeJoin", "NodeFuzzyMatch"):
|
|
413
493
|
ensure_compatibility_node_joins(setting_input)
|
|
414
|
-
elif class_name ==
|
|
494
|
+
elif class_name == "NodePolarsCode":
|
|
415
495
|
ensure_compatibility_node_polars(setting_input)
|
|
416
|
-
|
|
496
|
+
elif class_name == "NodeFilter":
|
|
497
|
+
ensure_compatibility_node_filter(setting_input)
|
|
498
|
+
elif class_name == "NodeGroupBy":
|
|
499
|
+
ensure_compatibility_node_groupby(setting_input)
|
|
417
500
|
ensure_description(setting_input)
|
|
418
501
|
|
|
419
502
|
return flow_storage_obj
|