Flowfile 0.5.1__py3-none-any.whl → 0.5.3__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 +178 -74
- flowfile/__main__.py +10 -7
- flowfile/api.py +51 -57
- flowfile/web/__init__.py +14 -9
- flowfile/web/static/assets/AdminView-49392a9a.js +713 -0
- flowfile/web/static/assets/AdminView-f53bad23.css +129 -0
- flowfile/web/static/assets/CloudConnectionView-36bcd6df.css +72 -0
- flowfile/web/static/assets/{CloudConnectionManager-0dfba9f2.js → CloudConnectionView-f13f202b.js} +11 -11
- flowfile/web/static/assets/{CloudStorageReader-d5b1b6c9.js → CloudStorageReader-0023d4a5.js} +10 -8
- flowfile/web/static/assets/{CloudStorageReader-29d14fcc.css → CloudStorageReader-24c54524.css} +27 -27
- flowfile/web/static/assets/{CloudStorageWriter-b0ee067f.css → CloudStorageWriter-60547855.css} +26 -26
- flowfile/web/static/assets/{CloudStorageWriter-00d87aad.js → CloudStorageWriter-8e781e11.js} +10 -8
- flowfile/web/static/assets/{ColumnSelector-47996a16.css → ColumnSelector-371637fb.css} +2 -2
- flowfile/web/static/assets/{ColumnSelector-4685e75d.js → ColumnSelector-8ad68ea9.js} +3 -5
- flowfile/web/static/assets/{ContextMenu-c13f91d0.css → ContextMenu-26d4dd27.css} +6 -6
- flowfile/web/static/assets/{ContextMenu-23e909da.js → ContextMenu-31ee57f0.js} +3 -3
- flowfile/web/static/assets/{ContextMenu-70ae0c79.js → ContextMenu-69a74055.js} +3 -3
- flowfile/web/static/assets/{ContextMenu-f149cf7c.js → ContextMenu-8e2051c6.js} +3 -3
- flowfile/web/static/assets/{ContextMenu-4c74eef1.css → ContextMenu-8ec1729e.css} +6 -6
- flowfile/web/static/assets/{ContextMenu-63cfa99b.css → ContextMenu-9b310c60.css} +6 -6
- flowfile/web/static/assets/{CrossJoin-702a3edd.js → CrossJoin-03df6938.js} +12 -10
- flowfile/web/static/assets/{CrossJoin-1119d18e.css → CrossJoin-71b4cc10.css} +20 -20
- flowfile/web/static/assets/CustomNode-59e99a86.css +32 -0
- flowfile/web/static/assets/{CustomNode-b1519993.js → CustomNode-8479239b.js} +36 -24
- flowfile/web/static/assets/{DatabaseConnectionSettings-6f3e4ea5.js → DatabaseConnectionSettings-869e3efd.js} +5 -4
- flowfile/web/static/assets/{DatabaseConnectionSettings-0c04b2e5.css → DatabaseConnectionSettings-e91df89a.css} +13 -13
- flowfile/web/static/assets/{DatabaseReader-ae61773c.css → DatabaseReader-36898a00.css} +24 -24
- flowfile/web/static/assets/{DatabaseReader-d38c7295.js → DatabaseReader-c58b9552.js} +25 -15
- flowfile/web/static/assets/DatabaseView-6655afd6.css +57 -0
- flowfile/web/static/assets/{DatabaseManager-cf5ef661.js → DatabaseView-d26a9140.js} +11 -11
- flowfile/web/static/assets/{DatabaseWriter-2f570e53.css → DatabaseWriter-217a99f1.css} +19 -19
- flowfile/web/static/assets/{DatabaseWriter-b04ef46a.js → DatabaseWriter-4d05ddc7.js} +17 -10
- flowfile/web/static/assets/{designer-8da3ba3a.css → DesignerView-a6d0ee84.css} +614 -546
- flowfile/web/static/assets/{designer-9633482a.js → DesignerView-e6f5c0e8.js} +1107 -3170
- flowfile/web/static/assets/{documentation-ca400224.js → DocumentationView-2e78ef1b.js} +5 -5
- flowfile/web/static/assets/{documentation-12216a74.css → DocumentationView-fd46c656.css} +7 -7
- flowfile/web/static/assets/{ExploreData-2d0cf4db.css → ExploreData-10c5acc8.css} +13 -12
- flowfile/web/static/assets/{ExploreData-5fa10ed8.js → ExploreData-7b54caca.js} +18 -9
- flowfile/web/static/assets/{ExternalSource-d39af878.js → ExternalSource-3fa399b2.js} +9 -7
- flowfile/web/static/assets/{ExternalSource-e37b6275.css → ExternalSource-47ab05a3.css} +17 -17
- flowfile/web/static/assets/Filter-7494ea97.css +48 -0
- flowfile/web/static/assets/Filter-8cbbdbf3.js +287 -0
- flowfile/web/static/assets/{Formula-bb96803d.css → Formula-53d58c43.css} +7 -7
- flowfile/web/static/assets/{Formula-6b04fb1d.js → Formula-aac42b1e.js} +13 -11
- flowfile/web/static/assets/{FuzzyMatch-1010f966.css → FuzzyMatch-ad6361d6.css} +68 -69
- flowfile/web/static/assets/{FuzzyMatch-999521f4.js → FuzzyMatch-cd9bbfca.js} +12 -10
- flowfile/web/static/assets/{Pivot-cf333e3d.css → GraphSolver-c24dec17.css} +5 -5
- flowfile/web/static/assets/{GraphSolver-17dd2198.js → GraphSolver-c7e6780e.js} +13 -11
- flowfile/web/static/assets/{GroupBy-6b039e18.js → GroupBy-93c5d22b.js} +9 -7
- flowfile/web/static/assets/{GroupBy-b9505323.css → GroupBy-be7ac0bf.css} +10 -10
- flowfile/web/static/assets/{Join-fd79b451.css → Join-28b5e18f.css} +22 -22
- flowfile/web/static/assets/{Join-24d0f113.js → Join-a19b2de2.js} +13 -11
- flowfile/web/static/assets/LoginView-0df4ed0a.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-8d3374b2.js} +170 -116
- flowfile/web/static/assets/{MultiSelect-0e8724a3.js → MultiSelect-ad1b6243.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-e278950d.js} +1 -1
- flowfile/web/static/assets/NodeDesigner-40b647c9.js +2610 -0
- flowfile/web/static/assets/NodeDesigner-5f53be3f.css +1429 -0
- flowfile/web/static/assets/{NumericInput-3d63a470.js → NumericInput-7100234c.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-5130219f.js} +5 -2
- flowfile/web/static/assets/{Output-283fe388.css → Output-35e97000.css} +6 -6
- flowfile/web/static/assets/{Output-edea9802.js → Output-f5efd2aa.js} +12 -9
- flowfile/web/static/assets/{GraphSolver-f0cb7bfb.css → Pivot-0eda81b4.css} +5 -5
- flowfile/web/static/assets/{Pivot-61d19301.js → Pivot-d981d23c.js} +11 -9
- flowfile/web/static/assets/PivotValidation-0e905b1a.css +13 -0
- flowfile/web/static/assets/{PivotValidation-f97fec5b.js → PivotValidation-39386e95.js} +3 -3
- flowfile/web/static/assets/PivotValidation-41b57ad6.css +13 -0
- flowfile/web/static/assets/{PivotValidation-de9f43fe.js → PivotValidation-63de1f73.js} +3 -3
- flowfile/web/static/assets/{PolarsCode-650322d1.css → PolarsCode-2b1f1f23.css} +4 -4
- flowfile/web/static/assets/{PolarsCode-bc3c9984.js → PolarsCode-f9d69217.js} +18 -9
- flowfile/web/static/assets/PopOver-b22f049e.js +939 -0
- flowfile/web/static/assets/PopOver-d96599db.css +33 -0
- flowfile/web/static/assets/{Read-e808b239.css → Read-36e7bd51.css} +12 -12
- flowfile/web/static/assets/{Read-64a3f259.js → Read-aec2e377.js} +14 -11
- flowfile/web/static/assets/{RecordCount-3d5039be.js → RecordCount-78ed6845.js} +6 -4
- flowfile/web/static/assets/{RecordId-597510e0.js → RecordId-2156e890.js} +8 -6
- flowfile/web/static/assets/{SQLQueryComponent-36cef432.css → SQLQueryComponent-1c2f26b4.css} +5 -5
- flowfile/web/static/assets/{SQLQueryComponent-df51adbe.js → SQLQueryComponent-48c72f5b.js} +3 -3
- flowfile/web/static/assets/{Sample-4be0a507.js → Sample-1352ca74.js} +6 -4
- flowfile/web/static/assets/SecretSelector-22b5ff89.js +113 -0
- flowfile/web/static/assets/SecretSelector-6329f743.css +43 -0
- flowfile/web/static/assets/{SecretManager-4839be57.js → SecretsView-17df66ee.js} +35 -36
- flowfile/web/static/assets/SecretsView-aa291340.css +38 -0
- flowfile/web/static/assets/{Select-9b72f201.js → Select-0aee4c54.js} +9 -7
- flowfile/web/static/assets/{SettingsSection-f0f75a42.js → SettingsSection-0784e157.js} +3 -3
- 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-2e4d03c4.css → SettingsSection-8f980839.css} +4 -4
- flowfile/web/static/assets/{SettingsSection-e1e9c953.js → SettingsSection-cd341bb6.js} +3 -3
- flowfile/web/static/assets/{SettingsSection-7ded385d.js → SettingsSection-f2002a6d.js} +3 -3
- flowfile/web/static/assets/{SingleSelect-6c777aac.js → SingleSelect-460cc0ea.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-30741bb2.js} +1 -1
- flowfile/web/static/assets/{SliderInput-7cb93e62.js → SliderInput-5d926864.js} +7 -4
- flowfile/web/static/assets/SliderInput-f2e4f23c.css +4 -0
- flowfile/web/static/assets/{Sort-6cbde21a.js → Sort-3cdc971b.js} +9 -7
- flowfile/web/static/assets/{Unique-f9fb0809.css → Sort-8a871341.css} +10 -10
- flowfile/web/static/assets/{TextInput-d9a40c11.js → TextInput-a2d0bfbd.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-abad1ca2.js} +5 -2
- flowfile/web/static/assets/{TextToRows-5d2c1190.css → TextToRows-12afb4f4.css} +10 -10
- flowfile/web/static/assets/{TextToRows-c4fcbf4d.js → TextToRows-918945f7.js} +11 -10
- flowfile/web/static/assets/{ToggleSwitch-4ef91d19.js → ToggleSwitch-f0ef5196.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-5605c793.js} +1 -1
- flowfile/web/static/assets/{UnavailableFields-5edd5322.css → UnavailableFields-54d2f518.css} +6 -6
- flowfile/web/static/assets/{UnavailableFields-a03f512c.js → UnavailableFields-bdad6144.js} +4 -4
- flowfile/web/static/assets/{Union-af6c3d9b.css → Union-d6a8d7d5.css} +7 -7
- flowfile/web/static/assets/{Union-bfe9b996.js → Union-e8ab8c86.js} +8 -6
- flowfile/web/static/assets/{Unique-5d023a27.js → Unique-8cd4f976.js} +13 -10
- flowfile/web/static/assets/{Sort-3643d625.css → Unique-9fb2f567.css} +10 -10
- flowfile/web/static/assets/{Unpivot-1e422df3.css → Unpivot-710a2948.css} +7 -7
- flowfile/web/static/assets/{Unpivot-91cc5354.js → Unpivot-8da14095.js} +10 -8
- flowfile/web/static/assets/{UnpivotValidation-7ee2de44.js → UnpivotValidation-6f7d89ff.js} +3 -3
- flowfile/web/static/assets/UnpivotValidation-d5ca3b7b.css +13 -0
- flowfile/web/static/assets/{VueGraphicWalker-e51b9924.js → VueGraphicWalker-3fb312e1.js} +4 -4
- flowfile/web/static/assets/{VueGraphicWalker-ed5ab88b.css → VueGraphicWalker-430f0b86.css} +1 -1
- flowfile/web/static/assets/{api-cf1221f0.js → api-24483f0d.js} +1 -1
- flowfile/web/static/assets/{api-c1bad5ca.js → api-8b81fa73.js} +1 -1
- flowfile/web/static/assets/{dropDown-35135ba8.css → dropDown-3d8dc5fa.css} +40 -40
- flowfile/web/static/assets/{dropDown-614b998d.js → dropDown-ac0fda9d.js} +3 -3
- flowfile/web/static/assets/{fullEditor-f7971590.js → fullEditor-5497a84a.js} +11 -10
- flowfile/web/static/assets/{fullEditor-178376bb.css → fullEditor-a0be62b3.css} +74 -62
- flowfile/web/static/assets/{genericNodeSettings-924759c7.css → genericNodeSettings-3b2507ea.css} +10 -10
- flowfile/web/static/assets/{genericNodeSettings-4fe5f36b.js → genericNodeSettings-99014e1d.js} +5 -5
- flowfile/web/static/assets/index-07dda503.js +38 -0
- flowfile/web/static/assets/index-3ba44389.js +2696 -0
- flowfile/web/static/assets/{index-50508d4d.css → index-e6289dd0.css} +1945 -569
- flowfile/web/static/assets/{index-5429bbf8.js → index-fb6493ae.js} +41626 -40867
- flowfile/web/static/assets/node.types-2c15bb7e.js +82 -0
- flowfile/web/static/assets/nodeInput-0eb13f1a.js +2 -0
- flowfile/web/static/assets/{outputCsv-076b85ab.js → outputCsv-8f8ba42d.js} +3 -3
- flowfile/web/static/assets/outputCsv-b9a072af.css +2499 -0
- flowfile/web/static/assets/{outputExcel-0fd17dbe.js → outputExcel-393f4fef.js} +3 -3
- flowfile/web/static/assets/{outputExcel-b41305c0.css → outputExcel-f5d272b2.css} +26 -26
- flowfile/web/static/assets/{outputParquet-b61e0847.js → outputParquet-07c81f65.js} +4 -4
- flowfile/web/static/assets/outputParquet-54597c3c.css +4 -0
- flowfile/web/static/assets/{readCsv-a8bb8b61.js → readCsv-07f6d9ad.js} +3 -3
- flowfile/web/static/assets/{readCsv-c767cb37.css → readCsv-3bfac4c3.css} +15 -15
- flowfile/web/static/assets/{readExcel-806d2826.css → readExcel-3db6b763.css} +13 -13
- flowfile/web/static/assets/{readExcel-67b4aee0.js → readExcel-ed69bc8f.js} +5 -5
- flowfile/web/static/assets/{readParquet-48c81530.css → readParquet-c5244ad5.css} +4 -4
- flowfile/web/static/assets/{readParquet-92ce1dbc.js → readParquet-e3ed4528.js} +3 -3
- flowfile/web/static/assets/secrets.api-002e7d7e.js +65 -0
- flowfile/web/static/assets/{selectDynamic-92e25ee3.js → selectDynamic-80b92899.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-0965f39f.js} +31 -640
- flowfile/web/static/assets/{vue-content-loader.es-2c8e608f.js → vue-content-loader.es-c506ad97.js} +1 -1
- flowfile/web/static/index.html +2 -2
- {flowfile-0.5.1.dist-info → flowfile-0.5.3.dist-info}/METADATA +2 -3
- flowfile-0.5.3.dist-info/RECORD +402 -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 +8 -6
- 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 +123 -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/code_generator.py +358 -244
- 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 +481 -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 +918 -571
- flowfile_core/flowfile/flow_graph_utils.py +31 -49
- flowfile_core/flowfile/flow_node/flow_node.py +330 -233
- 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 +15 -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 +135 -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 +3 -3
- 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 +59 -53
- 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 +17 -13
- 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 +106 -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/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 +11 -19
- 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 +9 -6
- flowfile_worker/spawner.py +80 -49
- 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/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/ManualInput-3246a08d.css +0 -96
- flowfile/web/static/assets/PivotValidation-891ddfb0.css +0 -13
- flowfile/web/static/assets/PivotValidation-c46cd420.css +0 -13
- flowfile/web/static/assets/SliderInput-b8fb6a8c.css +0 -4
- 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.3.dist-info}/WHEEL +0 -0
- {flowfile-0.5.1.dist-info → flowfile-0.5.3.dist-info}/entry_points.txt +0 -0
- {flowfile-0.5.1.dist-info → flowfile-0.5.3.dist-info}/licenses/LICENSE +0 -0
flowfile_core/auth/models.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
1
|
from pydantic import BaseModel, SecretStr
|
|
3
|
-
from typing import Optional, List
|
|
4
2
|
|
|
5
3
|
|
|
6
4
|
class Token(BaseModel):
|
|
@@ -9,21 +7,48 @@ class Token(BaseModel):
|
|
|
9
7
|
|
|
10
8
|
|
|
11
9
|
class TokenData(BaseModel):
|
|
12
|
-
username:
|
|
10
|
+
username: str | None = None
|
|
13
11
|
|
|
14
12
|
|
|
15
13
|
class User(BaseModel):
|
|
16
14
|
username: str
|
|
17
|
-
id:
|
|
18
|
-
email:
|
|
19
|
-
full_name:
|
|
20
|
-
disabled:
|
|
15
|
+
id: int | None = None
|
|
16
|
+
email: str | None = None
|
|
17
|
+
full_name: str | None = None
|
|
18
|
+
disabled: bool | None = False
|
|
19
|
+
is_admin: bool | None = False
|
|
20
|
+
must_change_password: bool | None = False
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class UserInDB(User):
|
|
24
24
|
hashed_password: str
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
class UserCreate(BaseModel):
|
|
28
|
+
"""Model for creating a new user (admin only)"""
|
|
29
|
+
username: str
|
|
30
|
+
password: str
|
|
31
|
+
email: str | None = None
|
|
32
|
+
full_name: str | None = None
|
|
33
|
+
is_admin: bool = False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class UserUpdate(BaseModel):
|
|
37
|
+
"""Model for updating a user (admin only)"""
|
|
38
|
+
email: str | None = None
|
|
39
|
+
full_name: str | None = None
|
|
40
|
+
disabled: bool | None = None
|
|
41
|
+
is_admin: bool | None = None
|
|
42
|
+
password: str | None = None # Optional password change
|
|
43
|
+
must_change_password: bool | None = None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ChangePassword(BaseModel):
|
|
47
|
+
"""Model for user changing their own password"""
|
|
48
|
+
current_password: str
|
|
49
|
+
new_password: str
|
|
50
|
+
|
|
51
|
+
|
|
27
52
|
class SecretInput(BaseModel):
|
|
28
53
|
name: str
|
|
29
54
|
value: SecretStr
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Password hashing and verification utilities."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from passlib.context import CryptContext
|
|
5
|
+
|
|
6
|
+
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
|
7
|
+
|
|
8
|
+
# Password requirements
|
|
9
|
+
PASSWORD_MIN_LENGTH = 8
|
|
10
|
+
PASSWORD_REQUIREMENTS = {
|
|
11
|
+
"min_length": PASSWORD_MIN_LENGTH,
|
|
12
|
+
"require_number": True,
|
|
13
|
+
"require_special": True,
|
|
14
|
+
"special_chars": "!@#$%^&*()_+-=[]{}|;:,.<>?"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PasswordValidationError(Exception):
|
|
19
|
+
"""Raised when password doesn't meet requirements."""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def validate_password(password: str) -> tuple[bool, str]:
|
|
24
|
+
"""
|
|
25
|
+
Validate password against security requirements.
|
|
26
|
+
|
|
27
|
+
Requirements:
|
|
28
|
+
- Minimum 8 characters
|
|
29
|
+
- At least one number
|
|
30
|
+
- At least one special character
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
password: The plain text password to validate
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Tuple of (is_valid, error_message)
|
|
37
|
+
"""
|
|
38
|
+
if len(password) < PASSWORD_MIN_LENGTH:
|
|
39
|
+
return False, f"Password must be at least {PASSWORD_MIN_LENGTH} characters long"
|
|
40
|
+
|
|
41
|
+
if not re.search(r'\d', password):
|
|
42
|
+
return False, "Password must contain at least one number"
|
|
43
|
+
|
|
44
|
+
if not re.search(r'[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]', password):
|
|
45
|
+
return False, "Password must contain at least one special character (!@#$%^&*()_+-=[]{}|;:,.<>?)"
|
|
46
|
+
|
|
47
|
+
return True, ""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def validate_password_or_raise(password: str) -> None:
|
|
51
|
+
"""
|
|
52
|
+
Validate password and raise exception if invalid.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
password: The plain text password to validate
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
PasswordValidationError: If password doesn't meet requirements
|
|
59
|
+
"""
|
|
60
|
+
is_valid, error_message = validate_password(password)
|
|
61
|
+
if not is_valid:
|
|
62
|
+
raise PasswordValidationError(error_message)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def verify_password(plain: str, hashed: str) -> bool:
|
|
66
|
+
"""
|
|
67
|
+
Verify a plain password against a hashed password.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
plain: The plain text password
|
|
71
|
+
hashed: The hashed password to verify against
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
True if the password matches, False otherwise
|
|
75
|
+
"""
|
|
76
|
+
return pwd_context.verify(plain, hashed)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_password_hash(password: str) -> str:
|
|
80
|
+
"""
|
|
81
|
+
Hash a plain text password.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
password: The plain text password to hash
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
The hashed password
|
|
88
|
+
"""
|
|
89
|
+
return pwd_context.hash(password)
|
flowfile_core/auth/secrets.py
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Secure storage module for FlowFile credentials and secrets.
|
|
3
3
|
"""
|
|
4
|
-
|
|
5
|
-
import os
|
|
6
|
-
from pathlib import Path
|
|
4
|
+
|
|
7
5
|
import json
|
|
8
6
|
import logging
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from cryptography.fernet import Fernet
|
|
9
11
|
|
|
10
12
|
logger = logging.getLogger(__name__)
|
|
11
13
|
|
|
@@ -15,7 +17,7 @@ class SecureStorage:
|
|
|
15
17
|
|
|
16
18
|
def __init__(self):
|
|
17
19
|
env = os.environ.get("FLOWFILE_MODE")
|
|
18
|
-
logger.debug(f
|
|
20
|
+
logger.debug(f"Using secure storage in {env} mode")
|
|
19
21
|
if os.environ.get("FLOWFILE_MODE") == "electron":
|
|
20
22
|
app_data = os.environ.get("APPDATA") or os.path.expanduser("~/.config")
|
|
21
23
|
self.storage_path = Path(app_data) / "flowfile"
|
|
@@ -148,7 +150,7 @@ def get_docker_secret_key():
|
|
|
148
150
|
secret_path = "/run/secrets/flowfile_master_key"
|
|
149
151
|
if os.path.exists(secret_path):
|
|
150
152
|
try:
|
|
151
|
-
with open(secret_path
|
|
153
|
+
with open(secret_path) as f:
|
|
152
154
|
return f.read().strip()
|
|
153
155
|
except Exception as e:
|
|
154
156
|
logger.error(f"Failed to read master key from Docker secret: {e}")
|
|
@@ -168,7 +170,7 @@ def get_master_key():
|
|
|
168
170
|
Returns:
|
|
169
171
|
str: The master encryption key
|
|
170
172
|
"""
|
|
171
|
-
if os.environ.get("
|
|
173
|
+
if os.environ.get("FLOWFILE_MODE") == "docker":
|
|
172
174
|
return get_docker_secret_key()
|
|
173
175
|
|
|
174
176
|
key = get_password("flowfile", "master_key")
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# flowfile_core/flowfile_core/configs/__init__.py
|
|
2
2
|
import logging
|
|
3
|
+
import os
|
|
3
4
|
import sys
|
|
4
5
|
from pathlib import Path
|
|
5
|
-
import os
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
if "FLOWFILE_MODE" not in os.environ:
|
|
8
|
+
os.environ["FLOWFILE_MODE"] = "electron"
|
|
8
9
|
|
|
9
10
|
# Create and configure the logger
|
|
10
|
-
logger = logging.getLogger(
|
|
11
|
+
logger = logging.getLogger("PipelineHandler")
|
|
11
12
|
logger.setLevel(logging.INFO)
|
|
12
13
|
logger.propagate = False
|
|
13
14
|
|
|
@@ -17,9 +18,9 @@ if logger.hasHandlers():
|
|
|
17
18
|
|
|
18
19
|
# Try to determine the best output stream
|
|
19
20
|
output_stream = None
|
|
20
|
-
if hasattr(sys.stdout,
|
|
21
|
+
if hasattr(sys.stdout, "isatty") and sys.stdout.isatty():
|
|
21
22
|
output_stream = sys.stdout
|
|
22
|
-
elif hasattr(sys.stderr,
|
|
23
|
+
elif hasattr(sys.stderr, "isatty") and sys.stderr.isatty():
|
|
23
24
|
output_stream = sys.stderr
|
|
24
25
|
else:
|
|
25
26
|
# Use __stdout__ for debugger environments (PyDev, PyCharm, etc.)
|
|
@@ -29,7 +30,7 @@ console_handler = logging.StreamHandler(output_stream)
|
|
|
29
30
|
console_handler.setLevel(logging.INFO)
|
|
30
31
|
|
|
31
32
|
# Create formatter
|
|
32
|
-
formatter = logging.Formatter(
|
|
33
|
+
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
|
33
34
|
console_handler.setFormatter(formatter)
|
|
34
35
|
|
|
35
36
|
logger.addHandler(console_handler)
|
|
@@ -37,10 +38,11 @@ logger.addHandler(console_handler)
|
|
|
37
38
|
# Create logs directory in temp at startup
|
|
38
39
|
try:
|
|
39
40
|
from tempfile import gettempdir
|
|
41
|
+
|
|
40
42
|
log_dir = Path(gettempdir()) / "flowfile_logs"
|
|
41
43
|
log_dir.mkdir(exist_ok=True)
|
|
42
44
|
except Exception as e:
|
|
43
45
|
logger.warning(f"Failed to create logs directory: {e}")
|
|
44
46
|
|
|
45
47
|
# Initialize vault
|
|
46
|
-
logger.info("Logging system initialized")
|
|
48
|
+
logger.info("Logging system initialized")
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
import os
|
|
5
2
|
import logging.handlers
|
|
3
|
+
import os
|
|
6
4
|
import queue
|
|
7
5
|
import threading
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
8
9
|
from shared.storage_config import storage
|
|
9
10
|
|
|
10
11
|
_process_safe_queue = queue.Queue(-1)
|
|
11
|
-
main_logger = logging.getLogger(
|
|
12
|
+
main_logger = logging.getLogger("PipelineHandler")
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class NodeLogger:
|
|
@@ -38,6 +39,7 @@ class NodeLogger:
|
|
|
38
39
|
|
|
39
40
|
class FlowLogger:
|
|
40
41
|
"""Thread-safe logger for flow execution"""
|
|
42
|
+
|
|
41
43
|
_instances = {}
|
|
42
44
|
_instances_lock = threading.RLock()
|
|
43
45
|
_queue_listener = None
|
|
@@ -47,7 +49,7 @@ class FlowLogger:
|
|
|
47
49
|
def handle_extra_log_info(flow_id: int, extra: dict = None) -> dict:
|
|
48
50
|
if extra is None:
|
|
49
51
|
extra = {}
|
|
50
|
-
extra[
|
|
52
|
+
extra["flow_id"] = flow_id
|
|
51
53
|
return extra
|
|
52
54
|
|
|
53
55
|
def __new__(cls, flow_id: int, clear_existing_logs: bool = False):
|
|
@@ -75,7 +77,7 @@ class FlowLogger:
|
|
|
75
77
|
|
|
76
78
|
def _setup_new_logger(self):
|
|
77
79
|
"""Creates a new logger instance with appropriate handlers"""
|
|
78
|
-
logger_name = f
|
|
80
|
+
logger_name = f"FlowExecution.{self.flow_id}"
|
|
79
81
|
self._logger = logging.getLogger(logger_name)
|
|
80
82
|
self._logger.setLevel(logging.INFO)
|
|
81
83
|
self.setup_logging()
|
|
@@ -131,7 +133,7 @@ class FlowLogger:
|
|
|
131
133
|
|
|
132
134
|
try:
|
|
133
135
|
# Create an empty file
|
|
134
|
-
with open(self.log_file_path,
|
|
136
|
+
with open(self.log_file_path, "w") as f:
|
|
135
137
|
pass
|
|
136
138
|
|
|
137
139
|
# Re-setup the logger
|
|
@@ -154,9 +156,7 @@ class FlowLogger:
|
|
|
154
156
|
"""Start the queue listener for asynchronous logging"""
|
|
155
157
|
queue_handler = logging.handlers.QueueHandler(_process_safe_queue)
|
|
156
158
|
cls._queue_listener = logging.handlers.QueueListener(
|
|
157
|
-
_process_safe_queue,
|
|
158
|
-
queue_handler,
|
|
159
|
-
respect_handler_level=True
|
|
159
|
+
_process_safe_queue, queue_handler, respect_handler_level=True
|
|
160
160
|
)
|
|
161
161
|
cls._queue_listener.start()
|
|
162
162
|
|
|
@@ -193,7 +193,7 @@ class FlowLogger:
|
|
|
193
193
|
|
|
194
194
|
# Add file handler
|
|
195
195
|
file_handler = logging.FileHandler(self.log_file_path)
|
|
196
|
-
formatter = logging.Formatter(
|
|
196
|
+
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
|
|
197
197
|
file_handler.setFormatter(formatter)
|
|
198
198
|
self._logger.addHandler(file_handler)
|
|
199
199
|
|
|
@@ -214,7 +214,8 @@ class FlowLogger:
|
|
|
214
214
|
else:
|
|
215
215
|
# If still can't get lock, proceed anyway
|
|
216
216
|
main_logger.warning(
|
|
217
|
-
f"Could not acquire lock for flow {self.flow_id}, proceeding with file clearing anyway"
|
|
217
|
+
f"Could not acquire lock for flow {self.flow_id}, proceeding with file clearing anyway"
|
|
218
|
+
)
|
|
218
219
|
self._clear_log_impl()
|
|
219
220
|
|
|
220
221
|
def _clear_log_impl(self):
|
|
@@ -223,7 +224,7 @@ class FlowLogger:
|
|
|
223
224
|
# Ensure parent directory exists
|
|
224
225
|
self.refresh_logger_if_needed()
|
|
225
226
|
# Truncate file
|
|
226
|
-
with open(self.log_file_path,
|
|
227
|
+
with open(self.log_file_path, "w") as f:
|
|
227
228
|
pass
|
|
228
229
|
main_logger.info(f"Log file cleared for flow {self.flow_id}")
|
|
229
230
|
except Exception as e:
|
|
@@ -409,7 +410,7 @@ def read_log_from_line(log_file_path: Path, start_line: int = 0):
|
|
|
409
410
|
"""Read log file content starting from a specific line"""
|
|
410
411
|
lines = []
|
|
411
412
|
try:
|
|
412
|
-
with open(log_file_path
|
|
413
|
+
with open(log_file_path) as file:
|
|
413
414
|
# Skip lines efficiently if needed
|
|
414
415
|
if start_line > 0:
|
|
415
416
|
for _ in range(start_line):
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import logging
|
|
2
|
+
|
|
2
3
|
from flowfile_core.configs.node_store.nodes import get_all_standard_nodes
|
|
3
|
-
from flowfile_core.
|
|
4
|
+
from flowfile_core.configs.node_store.user_defined_node_registry import (
|
|
5
|
+
get_all_nodes_from_standard_location,
|
|
6
|
+
load_single_node_from_file,
|
|
7
|
+
unload_node_by_name,
|
|
8
|
+
)
|
|
4
9
|
from flowfile_core.flowfile.node_designer.custom_node import CustomNodeBase
|
|
10
|
+
from flowfile_core.schemas.schemas import NodeTemplate
|
|
5
11
|
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
6
13
|
|
|
7
|
-
nodes_with_defaults = {
|
|
14
|
+
nodes_with_defaults = {"sample", "sort", "union", "select", "record_count"}
|
|
8
15
|
|
|
9
16
|
|
|
10
17
|
def register_custom_node(node: NodeTemplate):
|
|
@@ -18,6 +25,68 @@ def add_to_custom_node_store(custom_node: type[CustomNodeBase]):
|
|
|
18
25
|
register_custom_node(custom_node().to_node_template())
|
|
19
26
|
|
|
20
27
|
|
|
28
|
+
def remove_from_custom_node_store(node_key: str, file_stem: str = None) -> bool:
|
|
29
|
+
"""
|
|
30
|
+
Remove a custom node from both CUSTOM_NODE_STORE and node registries.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
node_key: The key/item name of the node to remove
|
|
34
|
+
file_stem: Optional file name stem (without .py) to use as fallback for matching
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
True if the node was found and removed, False otherwise
|
|
38
|
+
"""
|
|
39
|
+
removed = False
|
|
40
|
+
|
|
41
|
+
logger.info(f"Attempting to remove node with key: '{node_key}' (file_stem: '{file_stem}')")
|
|
42
|
+
logger.info(f"Current CUSTOM_NODE_STORE keys: {list(CUSTOM_NODE_STORE.keys())}")
|
|
43
|
+
logger.info(f"Current nodes_list items: {[n.item for n in nodes_list if hasattr(n, 'item')]}")
|
|
44
|
+
|
|
45
|
+
# Try to find the key - use exact match first, then fallback to file_stem
|
|
46
|
+
actual_key = None
|
|
47
|
+
if node_key in CUSTOM_NODE_STORE:
|
|
48
|
+
actual_key = node_key
|
|
49
|
+
elif file_stem and file_stem in CUSTOM_NODE_STORE:
|
|
50
|
+
actual_key = file_stem
|
|
51
|
+
logger.info(f"Using file_stem '{file_stem}' as key instead of '{node_key}'")
|
|
52
|
+
|
|
53
|
+
# Remove from CUSTOM_NODE_STORE
|
|
54
|
+
if actual_key and actual_key in CUSTOM_NODE_STORE:
|
|
55
|
+
del CUSTOM_NODE_STORE[actual_key]
|
|
56
|
+
logger.info(f"Removed '{actual_key}' from CUSTOM_NODE_STORE")
|
|
57
|
+
removed = True
|
|
58
|
+
else:
|
|
59
|
+
logger.warning(f"Key '{node_key}' (or file_stem '{file_stem}') not found in CUSTOM_NODE_STORE")
|
|
60
|
+
|
|
61
|
+
# Remove from node_dict - try both keys
|
|
62
|
+
key_to_use = actual_key or node_key
|
|
63
|
+
if key_to_use in node_dict:
|
|
64
|
+
del node_dict[key_to_use]
|
|
65
|
+
logger.info(f"Removed '{key_to_use}' from node_dict")
|
|
66
|
+
elif file_stem and file_stem in node_dict:
|
|
67
|
+
del node_dict[file_stem]
|
|
68
|
+
logger.info(f"Removed '{file_stem}' from node_dict")
|
|
69
|
+
|
|
70
|
+
# Remove from nodes_list - try both keys
|
|
71
|
+
removed_from_list = False
|
|
72
|
+
for i, node in enumerate(nodes_list):
|
|
73
|
+
if node.item == key_to_use or (file_stem and node.item == file_stem):
|
|
74
|
+
nodes_list.pop(i)
|
|
75
|
+
logger.info(f"Removed '{node.item}' from nodes_list at index {i}")
|
|
76
|
+
removed_from_list = True
|
|
77
|
+
break
|
|
78
|
+
|
|
79
|
+
if not removed_from_list:
|
|
80
|
+
logger.warning(f"Key '{node_key}' not found in nodes_list")
|
|
81
|
+
|
|
82
|
+
# Clean up module cache
|
|
83
|
+
unload_node_by_name(node_key)
|
|
84
|
+
if file_stem and file_stem != node_key:
|
|
85
|
+
unload_node_by_name(file_stem)
|
|
86
|
+
|
|
87
|
+
return removed
|
|
88
|
+
|
|
89
|
+
|
|
21
90
|
CUSTOM_NODE_STORE = get_all_nodes_from_standard_location()
|
|
22
91
|
nodes_list, node_dict, node_defaults = get_all_standard_nodes()
|
|
23
92
|
|
|
@@ -26,5 +95,4 @@ for custom_node in CUSTOM_NODE_STORE.values():
|
|
|
26
95
|
|
|
27
96
|
|
|
28
97
|
def check_if_has_default_setting(node_item: str):
|
|
29
|
-
|
|
30
98
|
return node_item in nodes_with_defaults
|