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
tools/migrate/migrate.py
CHANGED
|
@@ -3,10 +3,9 @@ Migration logic for converting old flowfile pickles to new YAML format.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import pickle
|
|
6
|
-
from dataclasses import fields, is_dataclass
|
|
6
|
+
from dataclasses import asdict, fields, is_dataclass
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Any
|
|
9
|
-
import sys
|
|
8
|
+
from typing import Any
|
|
10
9
|
|
|
11
10
|
try:
|
|
12
11
|
import yaml
|
|
@@ -27,28 +26,28 @@ class LegacyUnpickler(pickle.Unpickler):
|
|
|
27
26
|
# ONLY these classes changed from @dataclass to BaseModel
|
|
28
27
|
# These are all from flowfile_core/schemas/transform_schema.py
|
|
29
28
|
DATACLASS_TO_PYDANTIC = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
29
|
+
"SelectInput",
|
|
30
|
+
"FieldInput",
|
|
31
|
+
"FunctionInput",
|
|
32
|
+
"BasicFilter",
|
|
33
|
+
"FilterInput",
|
|
34
|
+
"SelectInputs",
|
|
35
|
+
"JoinInputs",
|
|
36
|
+
"JoinMap",
|
|
37
|
+
"CrossJoinInput",
|
|
38
|
+
"JoinInput",
|
|
39
|
+
"FuzzyMatchInput",
|
|
40
|
+
"AggColl",
|
|
41
|
+
"GroupByInput",
|
|
42
|
+
"PivotInput",
|
|
43
|
+
"SortByInput",
|
|
44
|
+
"RecordIdInput",
|
|
45
|
+
"TextToRowsInput",
|
|
46
|
+
"UnpivotInput",
|
|
47
|
+
"UnionInput",
|
|
48
|
+
"UniqueInput",
|
|
49
|
+
"GraphSolverInput",
|
|
50
|
+
"PolarsCodeInput",
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
def find_class(self, module: str, name: str):
|
|
@@ -71,7 +70,7 @@ def load_legacy_flowfile(path: Path) -> Any:
|
|
|
71
70
|
Returns:
|
|
72
71
|
The deserialized FlowInformation object (as legacy dataclass)
|
|
73
72
|
"""
|
|
74
|
-
with open(path,
|
|
73
|
+
with open(path, "rb") as f:
|
|
75
74
|
return LegacyUnpickler(f).load()
|
|
76
75
|
|
|
77
76
|
|
|
@@ -111,7 +110,7 @@ def convert_to_dict(obj: Any, _seen: set = None) -> Any:
|
|
|
111
110
|
|
|
112
111
|
try:
|
|
113
112
|
# Handle Pydantic models FIRST (check for model_dump method)
|
|
114
|
-
if hasattr(obj,
|
|
113
|
+
if hasattr(obj, "model_dump") and callable(obj.model_dump):
|
|
115
114
|
try:
|
|
116
115
|
data = obj.model_dump()
|
|
117
116
|
# Recursively convert any nested structures
|
|
@@ -150,9 +149,8 @@ def convert_to_dict(obj: Any, _seen: set = None) -> Any:
|
|
|
150
149
|
return str(obj)
|
|
151
150
|
|
|
152
151
|
# Handle objects with __dict__ (generic fallback)
|
|
153
|
-
if hasattr(obj,
|
|
154
|
-
return {k: convert_to_dict(v, _seen) for k, v in obj.__dict__.items()
|
|
155
|
-
if not k.startswith('_')}
|
|
152
|
+
if hasattr(obj, "__dict__"):
|
|
153
|
+
return {k: convert_to_dict(v, _seen) for k, v in obj.__dict__.items() if not k.startswith("_")}
|
|
156
154
|
|
|
157
155
|
# Fallback: try to convert to string
|
|
158
156
|
return str(obj)
|
|
@@ -161,7 +159,7 @@ def convert_to_dict(obj: Any, _seen: set = None) -> Any:
|
|
|
161
159
|
_seen.discard(obj_id)
|
|
162
160
|
|
|
163
161
|
|
|
164
|
-
def transform_to_new_schema(data:
|
|
162
|
+
def transform_to_new_schema(data: dict) -> dict:
|
|
165
163
|
"""
|
|
166
164
|
Transform the legacy schema structure to the new FlowfileData format.
|
|
167
165
|
|
|
@@ -176,39 +174,39 @@ def transform_to_new_schema(data: Dict) -> Dict:
|
|
|
176
174
|
Returns:
|
|
177
175
|
Transformed dict ready for YAML serialization (FlowfileData format)
|
|
178
176
|
"""
|
|
179
|
-
node_starts = set(data.get(
|
|
177
|
+
node_starts = set(data.get("node_starts", []))
|
|
180
178
|
|
|
181
179
|
result = {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
"flowfile_version": "2.0",
|
|
181
|
+
"flowfile_id": data.get("flow_id", 1),
|
|
182
|
+
"flowfile_name": data.get("flow_name", ""),
|
|
183
|
+
"flowfile_settings": _transform_flow_settings(data.get("flow_settings", {})),
|
|
184
|
+
"nodes": _transform_nodes(data.get("data", {}), node_starts),
|
|
187
185
|
}
|
|
188
186
|
|
|
189
187
|
return result
|
|
190
188
|
|
|
191
189
|
|
|
192
|
-
def _transform_flow_settings(settings:
|
|
190
|
+
def _transform_flow_settings(settings: dict) -> dict:
|
|
193
191
|
"""Transform flow settings to FlowfileSettings format."""
|
|
194
192
|
if not settings:
|
|
195
193
|
return {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
194
|
+
"execution_mode": "Development",
|
|
195
|
+
"execution_location": "local",
|
|
196
|
+
"auto_save": False,
|
|
197
|
+
"show_detailed_progress": True,
|
|
200
198
|
}
|
|
201
199
|
|
|
202
200
|
return {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
201
|
+
"description": settings.get("description"),
|
|
202
|
+
"execution_mode": settings.get("execution_mode", "Development"),
|
|
203
|
+
"execution_location": settings.get("execution_location", "local"),
|
|
204
|
+
"auto_save": settings.get("auto_save", False),
|
|
205
|
+
"show_detailed_progress": settings.get("show_detailed_progress", True),
|
|
208
206
|
}
|
|
209
207
|
|
|
210
208
|
|
|
211
|
-
def _transform_nodes(nodes_data:
|
|
209
|
+
def _transform_nodes(nodes_data: dict, node_starts: set) -> list[dict]:
|
|
212
210
|
"""Transform nodes dict to FlowfileNode list format."""
|
|
213
211
|
nodes = []
|
|
214
212
|
|
|
@@ -216,34 +214,34 @@ def _transform_nodes(nodes_data: Dict, node_starts: set) -> List[Dict]:
|
|
|
216
214
|
if not isinstance(node_info, dict):
|
|
217
215
|
node_info = convert_to_dict(node_info)
|
|
218
216
|
|
|
219
|
-
actual_node_id = node_info.get(
|
|
217
|
+
actual_node_id = node_info.get("id", node_id)
|
|
220
218
|
|
|
221
219
|
node = {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
220
|
+
"id": actual_node_id,
|
|
221
|
+
"type": node_info.get("type", ""),
|
|
222
|
+
"is_start_node": actual_node_id in node_starts,
|
|
223
|
+
"description": node_info.get("description", ""),
|
|
224
|
+
"x_position": int(node_info.get("x_position", 0) or 0),
|
|
225
|
+
"y_position": int(node_info.get("y_position", 0) or 0),
|
|
226
|
+
"left_input_id": node_info.get("left_input_id"),
|
|
227
|
+
"right_input_id": node_info.get("right_input_id"),
|
|
228
|
+
"input_ids": node_info.get("input_ids", []),
|
|
229
|
+
"outputs": node_info.get("outputs", []),
|
|
232
230
|
}
|
|
233
231
|
|
|
234
232
|
# Transform settings based on node type
|
|
235
|
-
setting_input = node_info.get(
|
|
233
|
+
setting_input = node_info.get("setting_input", {})
|
|
236
234
|
if setting_input:
|
|
237
235
|
if not isinstance(setting_input, dict):
|
|
238
236
|
setting_input = convert_to_dict(setting_input)
|
|
239
|
-
node[
|
|
237
|
+
node["setting_input"] = _transform_node_settings(node["type"], setting_input)
|
|
240
238
|
|
|
241
239
|
nodes.append(node)
|
|
242
240
|
|
|
243
241
|
return nodes
|
|
244
242
|
|
|
245
243
|
|
|
246
|
-
def _transform_node_settings(node_type: str, settings:
|
|
244
|
+
def _transform_node_settings(node_type: str, settings: dict) -> dict:
|
|
247
245
|
"""Transform node-specific settings to new format.
|
|
248
246
|
|
|
249
247
|
Handles structural changes for various node types:
|
|
@@ -254,72 +252,85 @@ def _transform_node_settings(node_type: str, settings: Dict) -> Dict:
|
|
|
254
252
|
- join/fuzzy_match: Handle JoinInput/FuzzyMatchInput changes
|
|
255
253
|
"""
|
|
256
254
|
# Remove common fields that are stored elsewhere
|
|
257
|
-
settings = {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
255
|
+
settings = {
|
|
256
|
+
k: v
|
|
257
|
+
for k, v in settings.items()
|
|
258
|
+
if k
|
|
259
|
+
not in (
|
|
260
|
+
"flow_id",
|
|
261
|
+
"node_id",
|
|
262
|
+
"pos_x",
|
|
263
|
+
"pos_y",
|
|
264
|
+
"is_setup",
|
|
265
|
+
"description",
|
|
266
|
+
"cache_results",
|
|
267
|
+
"user_id",
|
|
268
|
+
"is_flow_output",
|
|
269
|
+
"is_user_defined",
|
|
270
|
+
)
|
|
271
|
+
}
|
|
261
272
|
|
|
262
273
|
# Handle specific node types
|
|
263
|
-
if node_type ==
|
|
274
|
+
if node_type == "read":
|
|
264
275
|
return _transform_read_settings(settings)
|
|
265
|
-
elif node_type ==
|
|
276
|
+
elif node_type == "output":
|
|
266
277
|
return _transform_output_settings(settings)
|
|
267
|
-
elif node_type ==
|
|
278
|
+
elif node_type == "polars_code":
|
|
268
279
|
return _transform_polars_code_settings(settings)
|
|
269
|
-
elif node_type ==
|
|
280
|
+
elif node_type == "select":
|
|
270
281
|
return _transform_select_settings(settings)
|
|
271
|
-
elif node_type in (
|
|
282
|
+
elif node_type in ("join", "fuzzy_match", "cross_join"):
|
|
272
283
|
return _transform_join_settings(settings)
|
|
273
284
|
|
|
274
285
|
return settings
|
|
275
286
|
|
|
276
287
|
|
|
277
|
-
def _transform_select_settings(settings:
|
|
288
|
+
def _transform_select_settings(settings: dict) -> dict:
|
|
278
289
|
"""Transform NodeSelect settings - ensure all fields exist."""
|
|
279
290
|
# Ensure sorted_by field exists (added in new version)
|
|
280
|
-
if
|
|
281
|
-
settings[
|
|
291
|
+
if "sorted_by" not in settings:
|
|
292
|
+
settings["sorted_by"] = "none"
|
|
282
293
|
|
|
283
294
|
# Ensure select_input items have position field
|
|
284
|
-
select_input = settings.get(
|
|
295
|
+
select_input = settings.get("select_input", [])
|
|
285
296
|
if isinstance(select_input, list):
|
|
286
297
|
for i, item in enumerate(select_input):
|
|
287
|
-
if isinstance(item, dict) and item.get(
|
|
288
|
-
item[
|
|
298
|
+
if isinstance(item, dict) and item.get("position") is None:
|
|
299
|
+
item["position"] = i
|
|
289
300
|
|
|
290
301
|
return settings
|
|
291
302
|
|
|
292
303
|
|
|
293
|
-
def _transform_join_settings(settings:
|
|
304
|
+
def _transform_join_settings(settings: dict) -> dict:
|
|
294
305
|
"""Transform join-related node settings.
|
|
295
306
|
|
|
296
307
|
Handles migration of old JoinInput where left_select/right_select could be None.
|
|
297
308
|
New schema requires these to be JoinInputs with renames list.
|
|
298
309
|
"""
|
|
299
310
|
# Handle join_input transformation
|
|
300
|
-
join_input = settings.get(
|
|
311
|
+
join_input = settings.get("join_input") or settings.get("cross_join_input")
|
|
301
312
|
if join_input and isinstance(join_input, dict):
|
|
302
313
|
# ADD DEFAULT EMPTY JoinInputs IF MISSING (required in new schema)
|
|
303
|
-
for side in [
|
|
314
|
+
for side in ["left_select", "right_select"]:
|
|
304
315
|
if join_input.get(side) is None:
|
|
305
|
-
join_input[side] = {
|
|
316
|
+
join_input[side] = {"renames": []}
|
|
306
317
|
|
|
307
318
|
select = join_input.get(side)
|
|
308
319
|
if select and isinstance(select, dict):
|
|
309
320
|
# Ensure renames key exists
|
|
310
|
-
if
|
|
311
|
-
select[
|
|
321
|
+
if "renames" not in select:
|
|
322
|
+
select["renames"] = []
|
|
312
323
|
|
|
313
|
-
renames = select.get(
|
|
324
|
+
renames = select.get("renames", [])
|
|
314
325
|
if isinstance(renames, list):
|
|
315
326
|
for i, item in enumerate(renames):
|
|
316
|
-
if isinstance(item, dict) and item.get(
|
|
317
|
-
item[
|
|
327
|
+
if isinstance(item, dict) and item.get("position") is None:
|
|
328
|
+
item["position"] = i
|
|
318
329
|
|
|
319
330
|
return settings
|
|
320
331
|
|
|
321
332
|
|
|
322
|
-
def _transform_read_settings(settings:
|
|
333
|
+
def _transform_read_settings(settings: dict) -> dict:
|
|
323
334
|
"""Transform NodeRead settings - extract table_settings from old flat structure.
|
|
324
335
|
|
|
325
336
|
OLD structure (flat):
|
|
@@ -338,85 +349,85 @@ def _transform_read_settings(settings: Dict) -> Dict:
|
|
|
338
349
|
delimiter: ","
|
|
339
350
|
encoding: "utf-8"
|
|
340
351
|
"""
|
|
341
|
-
received_file = settings.get(
|
|
352
|
+
received_file = settings.get("received_file", {})
|
|
342
353
|
if not received_file:
|
|
343
354
|
return settings
|
|
344
355
|
|
|
345
356
|
# Check if already transformed (has table_settings)
|
|
346
|
-
if
|
|
357
|
+
if "table_settings" in received_file and isinstance(received_file["table_settings"], dict):
|
|
347
358
|
return settings
|
|
348
359
|
|
|
349
|
-
file_type = received_file.get(
|
|
360
|
+
file_type = received_file.get("file_type", "csv")
|
|
350
361
|
|
|
351
362
|
# Build table_settings based on file_type, extracting from flat structure
|
|
352
|
-
if file_type ==
|
|
363
|
+
if file_type == "csv":
|
|
353
364
|
table_settings = {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
365
|
+
"file_type": "csv",
|
|
366
|
+
"reference": received_file.get("reference", ""),
|
|
367
|
+
"starting_from_line": received_file.get("starting_from_line", 0),
|
|
368
|
+
"delimiter": received_file.get("delimiter", ","),
|
|
369
|
+
"has_headers": received_file.get("has_headers", True),
|
|
370
|
+
"encoding": received_file.get("encoding", "utf-8") or "utf-8",
|
|
371
|
+
"parquet_ref": received_file.get("parquet_ref"),
|
|
372
|
+
"row_delimiter": received_file.get("row_delimiter", "\n"),
|
|
373
|
+
"quote_char": received_file.get("quote_char", '"'),
|
|
374
|
+
"infer_schema_length": received_file.get("infer_schema_length", 10000),
|
|
375
|
+
"truncate_ragged_lines": received_file.get("truncate_ragged_lines", False),
|
|
376
|
+
"ignore_errors": received_file.get("ignore_errors", False),
|
|
366
377
|
}
|
|
367
|
-
elif file_type ==
|
|
378
|
+
elif file_type == "json":
|
|
368
379
|
table_settings = {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
380
|
+
"file_type": "json",
|
|
381
|
+
"reference": received_file.get("reference", ""),
|
|
382
|
+
"starting_from_line": received_file.get("starting_from_line", 0),
|
|
383
|
+
"delimiter": received_file.get("delimiter", ","),
|
|
384
|
+
"has_headers": received_file.get("has_headers", True),
|
|
385
|
+
"encoding": received_file.get("encoding", "utf-8") or "utf-8",
|
|
386
|
+
"parquet_ref": received_file.get("parquet_ref"),
|
|
387
|
+
"row_delimiter": received_file.get("row_delimiter", "\n"),
|
|
388
|
+
"quote_char": received_file.get("quote_char", '"'),
|
|
389
|
+
"infer_schema_length": received_file.get("infer_schema_length", 10000),
|
|
390
|
+
"truncate_ragged_lines": received_file.get("truncate_ragged_lines", False),
|
|
391
|
+
"ignore_errors": received_file.get("ignore_errors", False),
|
|
381
392
|
}
|
|
382
|
-
elif file_type ==
|
|
393
|
+
elif file_type == "excel":
|
|
383
394
|
table_settings = {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
395
|
+
"file_type": "excel",
|
|
396
|
+
"sheet_name": received_file.get("sheet_name"),
|
|
397
|
+
"start_row": received_file.get("start_row", 0),
|
|
398
|
+
"start_column": received_file.get("start_column", 0),
|
|
399
|
+
"end_row": received_file.get("end_row", 0),
|
|
400
|
+
"end_column": received_file.get("end_column", 0),
|
|
401
|
+
"has_headers": received_file.get("has_headers", True),
|
|
402
|
+
"type_inference": received_file.get("type_inference", False),
|
|
392
403
|
}
|
|
393
|
-
elif file_type ==
|
|
394
|
-
table_settings = {
|
|
404
|
+
elif file_type == "parquet":
|
|
405
|
+
table_settings = {"file_type": "parquet"}
|
|
395
406
|
else:
|
|
396
407
|
# Unknown file type - try to preserve what we can
|
|
397
|
-
table_settings = {
|
|
408
|
+
table_settings = {"file_type": file_type or "csv"}
|
|
398
409
|
|
|
399
410
|
# Build new structure with metadata + nested table_settings
|
|
400
411
|
return {
|
|
401
|
-
|
|
412
|
+
"received_file": {
|
|
402
413
|
# Metadata fields (preserved from old structure)
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
414
|
+
"id": received_file.get("id"),
|
|
415
|
+
"name": received_file.get("name"),
|
|
416
|
+
"path": received_file.get("path", ""),
|
|
417
|
+
"directory": received_file.get("directory"),
|
|
418
|
+
"analysis_file_available": received_file.get("analysis_file_available", False),
|
|
419
|
+
"status": received_file.get("status"),
|
|
420
|
+
"fields": received_file.get("fields", []),
|
|
421
|
+
"abs_file_path": received_file.get("abs_file_path"),
|
|
411
422
|
# New discriminator field
|
|
412
|
-
|
|
423
|
+
"file_type": file_type,
|
|
413
424
|
# Nested table settings
|
|
414
|
-
|
|
425
|
+
"table_settings": table_settings,
|
|
415
426
|
}
|
|
416
427
|
}
|
|
417
428
|
|
|
418
429
|
|
|
419
|
-
def _transform_output_settings(settings:
|
|
430
|
+
def _transform_output_settings(settings: dict) -> dict:
|
|
420
431
|
"""Transform NodeOutput settings - consolidate separate table settings into single field.
|
|
421
432
|
|
|
422
433
|
OLD structure:
|
|
@@ -434,80 +445,80 @@ def _transform_output_settings(settings: Dict) -> Dict:
|
|
|
434
445
|
delimiter: ","
|
|
435
446
|
encoding: "utf-8"
|
|
436
447
|
"""
|
|
437
|
-
output_settings = settings.get(
|
|
448
|
+
output_settings = settings.get("output_settings", {})
|
|
438
449
|
if not output_settings:
|
|
439
450
|
return settings
|
|
440
451
|
|
|
441
452
|
# Check if already transformed
|
|
442
|
-
if
|
|
453
|
+
if "table_settings" in output_settings and isinstance(output_settings["table_settings"], dict):
|
|
443
454
|
return settings
|
|
444
455
|
|
|
445
|
-
file_type = output_settings.get(
|
|
456
|
+
file_type = output_settings.get("file_type", "csv")
|
|
446
457
|
|
|
447
458
|
# Build table_settings from old separate fields
|
|
448
|
-
if file_type ==
|
|
449
|
-
old_csv = output_settings.get(
|
|
459
|
+
if file_type == "csv":
|
|
460
|
+
old_csv = output_settings.get("output_csv_table", {}) or {}
|
|
450
461
|
table_settings = {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
462
|
+
"file_type": "csv",
|
|
463
|
+
"delimiter": old_csv.get("delimiter", ","),
|
|
464
|
+
"encoding": old_csv.get("encoding", "utf-8"),
|
|
454
465
|
}
|
|
455
|
-
elif file_type ==
|
|
456
|
-
old_excel = output_settings.get(
|
|
466
|
+
elif file_type == "excel":
|
|
467
|
+
old_excel = output_settings.get("output_excel_table", {}) or {}
|
|
457
468
|
table_settings = {
|
|
458
|
-
|
|
459
|
-
|
|
469
|
+
"file_type": "excel",
|
|
470
|
+
"sheet_name": old_excel.get("sheet_name", "Sheet1"),
|
|
460
471
|
}
|
|
461
|
-
elif file_type ==
|
|
462
|
-
table_settings = {
|
|
472
|
+
elif file_type == "parquet":
|
|
473
|
+
table_settings = {"file_type": "parquet"}
|
|
463
474
|
else:
|
|
464
|
-
table_settings = {
|
|
475
|
+
table_settings = {"file_type": file_type or "csv"}
|
|
465
476
|
|
|
466
477
|
return {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
478
|
+
"output_settings": {
|
|
479
|
+
"name": output_settings.get("name", ""),
|
|
480
|
+
"directory": output_settings.get("directory", ""),
|
|
481
|
+
"file_type": file_type,
|
|
482
|
+
"fields": output_settings.get("fields", []),
|
|
483
|
+
"write_mode": output_settings.get("write_mode", "overwrite"),
|
|
484
|
+
"abs_file_path": output_settings.get("abs_file_path"),
|
|
485
|
+
"table_settings": table_settings,
|
|
475
486
|
}
|
|
476
487
|
}
|
|
477
488
|
|
|
478
489
|
|
|
479
|
-
def _transform_polars_code_settings(settings:
|
|
490
|
+
def _transform_polars_code_settings(settings: dict) -> dict:
|
|
480
491
|
"""Transform NodePolarsCode settings.
|
|
481
492
|
|
|
482
493
|
Extracts polars_code from PolarsCodeInput and handles depending_on_id → depending_on_ids.
|
|
483
494
|
"""
|
|
484
|
-
polars_code_input = settings.get(
|
|
495
|
+
polars_code_input = settings.get("polars_code_input", {})
|
|
485
496
|
|
|
486
497
|
# Extract the actual code
|
|
487
|
-
polars_code =
|
|
498
|
+
polars_code = ""
|
|
488
499
|
if isinstance(polars_code_input, dict):
|
|
489
|
-
polars_code = polars_code_input.get(
|
|
490
|
-
elif hasattr(polars_code_input,
|
|
500
|
+
polars_code = polars_code_input.get("polars_code", "")
|
|
501
|
+
elif hasattr(polars_code_input, "polars_code"):
|
|
491
502
|
polars_code = polars_code_input.polars_code
|
|
492
503
|
|
|
493
504
|
# Handle depending_on_id → depending_on_ids migration
|
|
494
|
-
depending_on_ids = settings.get(
|
|
505
|
+
depending_on_ids = settings.get("depending_on_ids", [])
|
|
495
506
|
if not depending_on_ids or depending_on_ids == [-1]:
|
|
496
|
-
old_id = settings.get(
|
|
507
|
+
old_id = settings.get("depending_on_id")
|
|
497
508
|
if old_id is not None and old_id != -1:
|
|
498
509
|
depending_on_ids = [old_id]
|
|
499
510
|
else:
|
|
500
511
|
depending_on_ids = []
|
|
501
512
|
|
|
502
513
|
return {
|
|
503
|
-
|
|
504
|
-
|
|
514
|
+
"polars_code_input": {
|
|
515
|
+
"polars_code": polars_code,
|
|
505
516
|
},
|
|
506
|
-
|
|
517
|
+
"depending_on_ids": depending_on_ids,
|
|
507
518
|
}
|
|
508
519
|
|
|
509
520
|
|
|
510
|
-
def migrate_flowfile(input_path: Path, output_path: Path = None, format: str =
|
|
521
|
+
def migrate_flowfile(input_path: Path, output_path: Path = None, format: str = "yaml") -> Path:
|
|
511
522
|
"""
|
|
512
523
|
Migrate a single flowfile from pickle to YAML format.
|
|
513
524
|
|
|
@@ -519,12 +530,12 @@ def migrate_flowfile(input_path: Path, output_path: Path = None, format: str = '
|
|
|
519
530
|
Returns:
|
|
520
531
|
Path to the created output file
|
|
521
532
|
"""
|
|
522
|
-
if format ==
|
|
533
|
+
if format == "yaml" and yaml is None:
|
|
523
534
|
raise ImportError("PyYAML is required for YAML output. Install with: pip install pyyaml")
|
|
524
535
|
|
|
525
536
|
# Determine output path
|
|
526
537
|
if output_path is None:
|
|
527
|
-
suffix =
|
|
538
|
+
suffix = ".yaml" if format == "yaml" else ".json"
|
|
528
539
|
output_path = input_path.with_suffix(suffix)
|
|
529
540
|
|
|
530
541
|
print(f"Loading: {input_path}")
|
|
@@ -541,18 +552,19 @@ def migrate_flowfile(input_path: Path, output_path: Path = None, format: str = '
|
|
|
541
552
|
# Write output
|
|
542
553
|
print(f"Writing: {output_path}")
|
|
543
554
|
|
|
544
|
-
with open(output_path,
|
|
545
|
-
if format ==
|
|
555
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
556
|
+
if format == "yaml":
|
|
546
557
|
yaml.dump(transformed, f, default_flow_style=False, sort_keys=False, allow_unicode=True)
|
|
547
558
|
else:
|
|
548
559
|
import json
|
|
560
|
+
|
|
549
561
|
json.dump(transformed, f, indent=2, ensure_ascii=False)
|
|
550
562
|
|
|
551
563
|
print(f"✓ Migrated: {input_path.name} → {output_path.name}")
|
|
552
564
|
return output_path
|
|
553
565
|
|
|
554
566
|
|
|
555
|
-
def migrate_directory(dir_path: Path, output_dir: Path = None, format: str =
|
|
567
|
+
def migrate_directory(dir_path: Path, output_dir: Path = None, format: str = "yaml") -> list[Path]:
|
|
556
568
|
"""
|
|
557
569
|
Migrate all flowfiles in a directory.
|
|
558
570
|
|
|
@@ -567,7 +579,7 @@ def migrate_directory(dir_path: Path, output_dir: Path = None, format: str = 'ya
|
|
|
567
579
|
output_dir = output_dir or dir_path
|
|
568
580
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
569
581
|
|
|
570
|
-
flowfiles = list(dir_path.glob(
|
|
582
|
+
flowfiles = list(dir_path.glob("**/*.flowfile"))
|
|
571
583
|
|
|
572
584
|
if not flowfiles:
|
|
573
585
|
print(f"No .flowfile files found in {dir_path}")
|
|
@@ -581,7 +593,7 @@ def migrate_directory(dir_path: Path, output_dir: Path = None, format: str = 'ya
|
|
|
581
593
|
for flowfile in flowfiles:
|
|
582
594
|
# Preserve directory structure
|
|
583
595
|
relative = flowfile.relative_to(dir_path)
|
|
584
|
-
suffix =
|
|
596
|
+
suffix = ".yaml" if format == "yaml" else ".json"
|
|
585
597
|
output_path = output_dir / relative.with_suffix(suffix)
|
|
586
598
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
587
599
|
|