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
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
from typing import List, Tuple
|
|
3
|
-
from flowfile_core.flowfile.manage.compatibility_enhancements import ensure_compatibility, load_flowfile_pickle
|
|
4
|
-
from flowfile_core.flowfile.flow_graph import FlowGraph
|
|
1
|
+
import json
|
|
5
2
|
from pathlib import Path
|
|
3
|
+
|
|
6
4
|
from flowfile_core.configs.node_store import CUSTOM_NODE_STORE
|
|
7
|
-
from flowfile_core.configs.settings import
|
|
8
|
-
import
|
|
5
|
+
from flowfile_core.configs.settings import is_docker_mode
|
|
6
|
+
from flowfile_core.flowfile.flow_graph import FlowGraph
|
|
7
|
+
from flowfile_core.flowfile.manage.compatibility_enhancements import ensure_compatibility, load_flowfile_pickle
|
|
8
|
+
from flowfile_core.schemas import input_schema, schemas
|
|
9
9
|
from shared.storage_config import storage
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
try:
|
|
13
12
|
import yaml
|
|
14
13
|
except ImportError:
|
|
@@ -20,7 +19,7 @@ def _validate_flow_path(flow_path: Path) -> Path:
|
|
|
20
19
|
resolved = flow_path.resolve()
|
|
21
20
|
|
|
22
21
|
# Check extension
|
|
23
|
-
allowed_extensions = {
|
|
22
|
+
allowed_extensions = {".yaml", ".yml", ".json", ".flowfile"}
|
|
24
23
|
if resolved.suffix.lower() not in allowed_extensions:
|
|
25
24
|
raise ValueError(f"Unsupported file extension: {resolved.suffix}")
|
|
26
25
|
|
|
@@ -30,16 +29,13 @@ def _validate_flow_path(flow_path: Path) -> Path:
|
|
|
30
29
|
|
|
31
30
|
# Allow paths within known safe directories
|
|
32
31
|
|
|
33
|
-
if
|
|
32
|
+
if is_docker_mode():
|
|
34
33
|
safe_directories = [
|
|
35
34
|
storage.flows_directory,
|
|
36
35
|
storage.uploads_directory,
|
|
37
36
|
storage.temp_directory_for_flows,
|
|
38
37
|
]
|
|
39
|
-
is_safe = any(
|
|
40
|
-
resolved.is_relative_to(safe_dir)
|
|
41
|
-
for safe_dir in safe_directories
|
|
42
|
-
)
|
|
38
|
+
is_safe = any(resolved.is_relative_to(safe_dir) for safe_dir in safe_directories)
|
|
43
39
|
else:
|
|
44
40
|
is_safe = True
|
|
45
41
|
|
|
@@ -52,7 +48,7 @@ def _validate_flow_path(flow_path: Path) -> Path:
|
|
|
52
48
|
return resolved
|
|
53
49
|
|
|
54
50
|
|
|
55
|
-
def _derive_connections_from_nodes(nodes:
|
|
51
|
+
def _derive_connections_from_nodes(nodes: list[schemas.FlowfileNode]) -> list[tuple[int, int]]:
|
|
56
52
|
"""Derive node connections from the outputs stored in each node."""
|
|
57
53
|
connections = []
|
|
58
54
|
for node in nodes:
|
|
@@ -63,7 +59,7 @@ def _derive_connections_from_nodes(nodes: List[schemas.FlowfileNode]) -> List[Tu
|
|
|
63
59
|
|
|
64
60
|
|
|
65
61
|
def determine_insertion_order(node_storage: schemas.FlowInformation):
|
|
66
|
-
ingest_order:
|
|
62
|
+
ingest_order: list[int] = []
|
|
67
63
|
ingest_order_set: set[int] = set()
|
|
68
64
|
all_nodes = set(node_storage.data.keys())
|
|
69
65
|
|
|
@@ -78,10 +74,11 @@ def determine_insertion_order(node_storage: schemas.FlowInformation):
|
|
|
78
74
|
return
|
|
79
75
|
output_ids = current_node.outputs
|
|
80
76
|
main_input_ids = current_node.input_ids if current_node.input_ids else []
|
|
81
|
-
input_ids = [
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
input_ids = [
|
|
78
|
+
n
|
|
79
|
+
for n in [current_node.left_input_id, current_node.right_input_id] + main_input_ids
|
|
80
|
+
if (n is not None and n not in ingest_order_set)
|
|
81
|
+
]
|
|
85
82
|
if len(input_ids) > 0:
|
|
86
83
|
for input_id in input_ids:
|
|
87
84
|
new_node = node_storage.data.get(input_id)
|
|
@@ -123,7 +120,7 @@ def _load_flowfile_yaml(flow_path: Path) -> schemas.FlowInformation:
|
|
|
123
120
|
if yaml is None:
|
|
124
121
|
raise ImportError("PyYAML is required for YAML files. Install with: pip install pyyaml")
|
|
125
122
|
flow_path = _validate_flow_path(flow_path)
|
|
126
|
-
with open(flow_path,
|
|
123
|
+
with open(flow_path, encoding="utf-8") as f:
|
|
127
124
|
data = yaml.safe_load(f)
|
|
128
125
|
# Load as FlowfileData first (handles setting_input validation via node type)
|
|
129
126
|
flowfile_data = schemas.FlowfileData.model_validate(data)
|
|
@@ -142,7 +139,7 @@ def _load_flowfile_json(flow_path: Path) -> schemas.FlowInformation:
|
|
|
142
139
|
FlowInformation object
|
|
143
140
|
"""
|
|
144
141
|
flow_path = _validate_flow_path(flow_path)
|
|
145
|
-
with open(flow_path,
|
|
142
|
+
with open(flow_path, encoding="utf-8") as f:
|
|
146
143
|
data = json.load(f)
|
|
147
144
|
|
|
148
145
|
# Load as FlowfileData first (handles setting_input validation via node type)
|
|
@@ -168,40 +165,42 @@ def _flowfile_data_to_flow_information(flowfile_data: schemas.FlowfileData) -> s
|
|
|
168
165
|
is_user_defined = model_class == input_schema.UserDefinedNode
|
|
169
166
|
|
|
170
167
|
# Inject fields that were excluded during serialization
|
|
171
|
-
setting_data =
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
setting_data[
|
|
175
|
-
setting_data[
|
|
176
|
-
setting_data[
|
|
177
|
-
setting_data[
|
|
168
|
+
setting_data = (
|
|
169
|
+
node.setting_input if isinstance(node.setting_input, dict) else node.setting_input.model_dump()
|
|
170
|
+
)
|
|
171
|
+
setting_data["flow_id"] = flowfile_data.flowfile_id
|
|
172
|
+
setting_data["node_id"] = node.id
|
|
173
|
+
setting_data["pos_x"] = float(node.x_position or 0)
|
|
174
|
+
setting_data["pos_y"] = float(node.y_position or 0)
|
|
175
|
+
setting_data["description"] = node.description or ""
|
|
176
|
+
setting_data["is_setup"] = True
|
|
178
177
|
|
|
179
178
|
if is_user_defined:
|
|
180
|
-
setting_data[
|
|
179
|
+
setting_data["is_user_defined"] = True
|
|
181
180
|
depending_ids = list(node.input_ids or [])
|
|
182
181
|
if node.left_input_id:
|
|
183
182
|
depending_ids.append(node.left_input_id)
|
|
184
183
|
if node.right_input_id:
|
|
185
184
|
depending_ids.append(node.right_input_id)
|
|
186
|
-
setting_data[
|
|
185
|
+
setting_data["depending_on_ids"] = depending_ids
|
|
187
186
|
else:
|
|
188
|
-
if
|
|
189
|
-
setting_data[
|
|
190
|
-
if
|
|
187
|
+
if "depending_on_id" in model_class.model_fields:
|
|
188
|
+
setting_data["depending_on_id"] = node.input_ids[0] if node.input_ids else -1
|
|
189
|
+
if "depending_on_ids" in model_class.model_fields:
|
|
191
190
|
depending_ids = list(node.input_ids or [])
|
|
192
191
|
if node.left_input_id:
|
|
193
192
|
depending_ids.append(node.left_input_id)
|
|
194
193
|
if node.right_input_id:
|
|
195
194
|
depending_ids.append(node.right_input_id)
|
|
196
|
-
setting_data[
|
|
195
|
+
setting_data["depending_on_ids"] = depending_ids
|
|
197
196
|
|
|
198
|
-
if node.type ==
|
|
199
|
-
output_settings = setting_data[
|
|
200
|
-
file_type = output_settings.get(
|
|
197
|
+
if node.type == "output" and "output_settings" in setting_data:
|
|
198
|
+
output_settings = setting_data["output_settings"]
|
|
199
|
+
file_type = output_settings.get("file_type", None)
|
|
201
200
|
if file_type is None:
|
|
202
201
|
raise ValueError("Output node's output_settings must include 'file_type'")
|
|
203
|
-
if
|
|
204
|
-
output_settings[
|
|
202
|
+
if "table_settings" not in output_settings:
|
|
203
|
+
output_settings["table_settings"] = {"file_type": file_type}
|
|
205
204
|
|
|
206
205
|
setting_input = model_class.model_validate(setting_data)
|
|
207
206
|
|
|
@@ -243,6 +242,7 @@ def _flowfile_data_to_flow_information(flowfile_data: schemas.FlowfileData) -> s
|
|
|
243
242
|
node_connections=connections,
|
|
244
243
|
)
|
|
245
244
|
|
|
245
|
+
|
|
246
246
|
def _load_flow_storage(flow_path: Path) -> schemas.FlowInformation:
|
|
247
247
|
"""
|
|
248
248
|
Load flow storage from any supported format.
|
|
@@ -260,21 +260,20 @@ def _load_flow_storage(flow_path: Path) -> schemas.FlowInformation:
|
|
|
260
260
|
"""
|
|
261
261
|
flow_path = _validate_flow_path(flow_path)
|
|
262
262
|
suffix = flow_path.suffix.lower()
|
|
263
|
-
if suffix ==
|
|
263
|
+
if suffix == ".flowfile":
|
|
264
264
|
try:
|
|
265
265
|
flow_storage_obj = load_flowfile_pickle(str(flow_path))
|
|
266
266
|
ensure_compatibility(flow_storage_obj, str(flow_path))
|
|
267
267
|
return flow_storage_obj
|
|
268
268
|
except Exception as e:
|
|
269
269
|
raise ValueError(
|
|
270
|
-
f"Failed to open legacy .flowfile: {e}\n\n"
|
|
271
|
-
f"Try migrating: migrate_flowfile('{flow_path}')"
|
|
270
|
+
f"Failed to open legacy .flowfile: {e}\n\n" f"Try migrating: migrate_flowfile('{flow_path}')"
|
|
272
271
|
) from e
|
|
273
272
|
|
|
274
|
-
elif suffix in (
|
|
273
|
+
elif suffix in (".yaml", ".yml"):
|
|
275
274
|
return _load_flowfile_yaml(flow_path)
|
|
276
275
|
|
|
277
|
-
elif suffix ==
|
|
276
|
+
elif suffix == ".json":
|
|
278
277
|
return _load_flowfile_json(flow_path)
|
|
279
278
|
else:
|
|
280
279
|
raise ValueError(f"Unsupported file format: {suffix}")
|
|
@@ -304,9 +303,8 @@ def open_flow(flow_path: Path) -> FlowGraph:
|
|
|
304
303
|
|
|
305
304
|
# Determine node insertion order
|
|
306
305
|
ingestion_order = determine_insertion_order(flow_storage_obj)
|
|
307
|
-
|
|
308
|
-
# Create new FlowGraph
|
|
309
306
|
new_flow = FlowGraph(name=flow_storage_obj.flow_name, flow_settings=flow_storage_obj.flow_settings)
|
|
307
|
+
# Create new FlowGraph
|
|
310
308
|
|
|
311
309
|
# First pass: add node promises
|
|
312
310
|
for node_id in ingestion_order:
|
|
@@ -316,9 +314,9 @@ def open_flow(flow_path: Path) -> FlowGraph:
|
|
|
316
314
|
node_id=node_info.id,
|
|
317
315
|
pos_x=node_info.x_position,
|
|
318
316
|
pos_y=node_info.y_position,
|
|
319
|
-
node_type=node_info.type
|
|
317
|
+
node_type=node_info.type,
|
|
320
318
|
)
|
|
321
|
-
if hasattr(node_info.setting_input,
|
|
319
|
+
if hasattr(node_info.setting_input, "cache_results"):
|
|
322
320
|
node_promise.cache_results = node_info.setting_input.cache_results
|
|
323
321
|
new_flow.add_node_promise(node_promise)
|
|
324
322
|
|
|
@@ -331,15 +329,14 @@ def open_flow(flow_path: Path) -> FlowGraph:
|
|
|
331
329
|
user_defined_node_class = CUSTOM_NODE_STORE[node_info.type]
|
|
332
330
|
new_flow.add_user_defined_node(
|
|
333
331
|
custom_node=user_defined_node_class.from_settings(node_info.setting_input.settings),
|
|
334
|
-
user_defined_node_settings=node_info.setting_input
|
|
332
|
+
user_defined_node_settings=node_info.setting_input,
|
|
335
333
|
)
|
|
336
334
|
else:
|
|
337
|
-
getattr(new_flow,
|
|
335
|
+
getattr(new_flow, "add_" + node_info.type)(node_info.setting_input)
|
|
338
336
|
|
|
339
337
|
# Setup connections
|
|
340
338
|
from_node = new_flow.get_node(node_id)
|
|
341
|
-
for output_node_id in
|
|
342
|
-
|
|
339
|
+
for output_node_id in node_info.outputs or []:
|
|
343
340
|
to_node = new_flow.get_node(output_node_id)
|
|
344
341
|
if to_node is not None:
|
|
345
342
|
output_node_obj = flow_storage_obj.data[output_node_id]
|
|
@@ -352,17 +349,17 @@ def open_flow(flow_path: Path) -> FlowGraph:
|
|
|
352
349
|
is_main_input = node_id in (output_node_obj.input_ids or [])
|
|
353
350
|
|
|
354
351
|
if is_left_input:
|
|
355
|
-
insert_type =
|
|
352
|
+
insert_type = "left"
|
|
356
353
|
elif is_right_input:
|
|
357
|
-
insert_type =
|
|
354
|
+
insert_type = "right"
|
|
358
355
|
elif is_main_input:
|
|
359
|
-
insert_type =
|
|
356
|
+
insert_type = "main"
|
|
360
357
|
else:
|
|
361
358
|
continue
|
|
362
359
|
to_node.add_node_connection(from_node, insert_type)
|
|
363
360
|
else:
|
|
364
361
|
from_node.delete_lead_to_node(output_node_id)
|
|
365
|
-
if
|
|
362
|
+
if (from_node.node_id, output_node_id) not in flow_storage_obj.node_connections:
|
|
366
363
|
continue
|
|
367
364
|
flow_storage_obj.node_connections.pop(
|
|
368
365
|
flow_storage_obj.node_connections.index((from_node.node_id, output_node_id))
|
|
@@ -380,7 +377,7 @@ def open_flow(flow_path: Path) -> FlowGraph:
|
|
|
380
377
|
return new_flow
|
|
381
378
|
|
|
382
379
|
|
|
383
|
-
def test_if_circular_connection(connection:
|
|
380
|
+
def test_if_circular_connection(connection: tuple[int, int], flow: FlowGraph):
|
|
384
381
|
to_node = flow.get_node(connection[1])
|
|
385
382
|
leads_to_nodes_queue = [n for n in to_node.leads_to_nodes]
|
|
386
383
|
circular_connection: bool = False
|
|
@@ -8,40 +8,42 @@ custom nodes, define their UI, and implement their data processing logic.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Import the core base class for creating a new node
|
|
11
|
+
# Import the main `Types` object for filtering in ColumnSelector
|
|
12
|
+
from flowfile_core.types import Types
|
|
13
|
+
|
|
11
14
|
from .custom_node import CustomNodeBase, NodeSettings
|
|
12
15
|
|
|
13
16
|
# Import all UI components so they can be used directly
|
|
14
17
|
from .ui_components import (
|
|
18
|
+
AvailableSecrets,
|
|
19
|
+
ColumnSelector,
|
|
20
|
+
IncomingColumns,
|
|
21
|
+
MultiSelect,
|
|
22
|
+
NumericInput,
|
|
23
|
+
SecretSelector,
|
|
15
24
|
Section,
|
|
25
|
+
SingleSelect,
|
|
26
|
+
SliderInput,
|
|
16
27
|
TextInput,
|
|
17
|
-
NumericInput,
|
|
18
28
|
ToggleSwitch,
|
|
19
|
-
SingleSelect,
|
|
20
|
-
MultiSelect,
|
|
21
|
-
ColumnSelector,
|
|
22
|
-
IncomingColumns, # Important marker class for dynamic dropdowns
|
|
23
29
|
)
|
|
24
30
|
|
|
25
|
-
# Import the main `Types` object for filtering in ColumnSelector
|
|
26
|
-
from flowfile_core.types import Types
|
|
27
|
-
|
|
28
|
-
|
|
29
31
|
# Define the public API of this package
|
|
30
32
|
__all__ = [
|
|
31
33
|
# Core Node Class
|
|
32
34
|
"CustomNodeBase",
|
|
33
|
-
|
|
34
35
|
# UI Components & Layout
|
|
35
36
|
"Section",
|
|
36
37
|
"TextInput",
|
|
37
38
|
"NumericInput",
|
|
39
|
+
"SliderInput",
|
|
38
40
|
"ToggleSwitch",
|
|
39
41
|
"SingleSelect",
|
|
40
42
|
"MultiSelect",
|
|
41
43
|
"NodeSettings",
|
|
42
44
|
"ColumnSelector",
|
|
43
45
|
"IncomingColumns",
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
"AvailableSecrets",
|
|
47
|
+
"SecretSelector",
|
|
46
48
|
"Types",
|
|
47
|
-
]
|
|
49
|
+
]
|
|
@@ -5,18 +5,20 @@ This module should not be imported directly by users.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from dataclasses import dataclass
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
9
10
|
import polars as pl
|
|
10
11
|
|
|
11
12
|
# Import public types
|
|
12
|
-
from flowfile_core.types import
|
|
13
|
+
from flowfile_core.types import DataType, TypeGroup
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
@dataclass(frozen=True)
|
|
16
17
|
class TypeMapping:
|
|
17
18
|
"""Internal mapping between type representations."""
|
|
19
|
+
|
|
18
20
|
data_type: DataType
|
|
19
|
-
polars_type:
|
|
21
|
+
polars_type: type[pl.DataType]
|
|
20
22
|
type_group: TypeGroup
|
|
21
23
|
aliases: tuple[str, ...] = ()
|
|
22
24
|
|
|
@@ -28,42 +30,32 @@ class TypeRegistry:
|
|
|
28
30
|
"""
|
|
29
31
|
|
|
30
32
|
def __init__(self):
|
|
31
|
-
self._mappings:
|
|
33
|
+
self._mappings: list[TypeMapping] = [
|
|
32
34
|
# Numeric types
|
|
33
35
|
TypeMapping(DataType.Int8, pl.Int8, TypeGroup.Numeric, ("i8",)),
|
|
34
36
|
TypeMapping(DataType.Int16, pl.Int16, TypeGroup.Numeric, ("i16",)),
|
|
35
37
|
TypeMapping(DataType.Int32, pl.Int32, TypeGroup.Numeric, ("i32", "int32")),
|
|
36
|
-
TypeMapping(DataType.Int64, pl.Int64, TypeGroup.Numeric,
|
|
37
|
-
("i64", "int64", "int", "integer", "bigint")),
|
|
38
|
+
TypeMapping(DataType.Int64, pl.Int64, TypeGroup.Numeric, ("i64", "int64", "int", "integer", "bigint")),
|
|
38
39
|
TypeMapping(DataType.UInt8, pl.UInt8, TypeGroup.Numeric, ("u8",)),
|
|
39
40
|
TypeMapping(DataType.UInt16, pl.UInt16, TypeGroup.Numeric, ("u16",)),
|
|
40
41
|
TypeMapping(DataType.UInt32, pl.UInt32, TypeGroup.Numeric, ("u32", "uint32")),
|
|
41
42
|
TypeMapping(DataType.UInt64, pl.UInt64, TypeGroup.Numeric, ("u64", "uint64")),
|
|
42
43
|
TypeMapping(DataType.Float32, pl.Float32, TypeGroup.Numeric, ("f32", "float32")),
|
|
43
|
-
TypeMapping(DataType.Float64, pl.Float64, TypeGroup.Numeric,
|
|
44
|
-
|
|
45
|
-
TypeMapping(DataType.Decimal, pl.Decimal, TypeGroup.Numeric,
|
|
46
|
-
("decimal", "numeric", "dec")),
|
|
47
|
-
|
|
44
|
+
TypeMapping(DataType.Float64, pl.Float64, TypeGroup.Numeric, ("f64", "float64", "float", "double")),
|
|
45
|
+
TypeMapping(DataType.Decimal, pl.Decimal, TypeGroup.Numeric, ("decimal", "dec")),
|
|
48
46
|
# String types
|
|
49
|
-
TypeMapping(DataType.String, pl.String, TypeGroup.String,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
TypeMapping(DataType.String, pl.String, TypeGroup.String, ("str", "string", "utf8", "varchar", "text")),
|
|
48
|
+
TypeMapping(
|
|
49
|
+
DataType.Categorical, pl.Categorical, TypeGroup.String, ("cat", "categorical", "enum", "factor")
|
|
50
|
+
),
|
|
54
51
|
# Date types
|
|
55
52
|
TypeMapping(DataType.Date, pl.Date, TypeGroup.Date, ("date",)),
|
|
56
|
-
TypeMapping(DataType.Datetime, pl.Datetime, TypeGroup.Date,
|
|
57
|
-
("datetime", "timestamp")),
|
|
53
|
+
TypeMapping(DataType.Datetime, pl.Datetime, TypeGroup.Date, ("datetime", "timestamp")),
|
|
58
54
|
TypeMapping(DataType.Time, pl.Time, TypeGroup.Date, ("time",)),
|
|
59
|
-
TypeMapping(DataType.Duration, pl.Duration, TypeGroup.Date,
|
|
60
|
-
("duration", "timedelta")),
|
|
61
|
-
|
|
55
|
+
TypeMapping(DataType.Duration, pl.Duration, TypeGroup.Date, ("duration", "timedelta")),
|
|
62
56
|
# Other types
|
|
63
|
-
TypeMapping(DataType.Boolean, pl.Boolean, TypeGroup.Boolean,
|
|
64
|
-
|
|
65
|
-
TypeMapping(DataType.Binary, pl.Binary, TypeGroup.Binary,
|
|
66
|
-
("binary", "bytes", "bytea")),
|
|
57
|
+
TypeMapping(DataType.Boolean, pl.Boolean, TypeGroup.Boolean, ("bool", "boolean")),
|
|
58
|
+
TypeMapping(DataType.Binary, pl.Binary, TypeGroup.Binary, ("binary", "bytes", "bytea")),
|
|
67
59
|
TypeMapping(DataType.List, pl.List, TypeGroup.Complex, ("list", "array")),
|
|
68
60
|
TypeMapping(DataType.Struct, pl.Struct, TypeGroup.Complex, ("struct", "object")),
|
|
69
61
|
TypeMapping(DataType.Array, pl.Array, TypeGroup.Complex, ("fixed_array",)),
|
|
@@ -73,10 +65,10 @@ class TypeRegistry:
|
|
|
73
65
|
|
|
74
66
|
def _build_indices(self):
|
|
75
67
|
"""Build lookup indices for fast access."""
|
|
76
|
-
self._by_data_type:
|
|
77
|
-
self._by_polars_type:
|
|
78
|
-
self._by_alias:
|
|
79
|
-
self._by_group:
|
|
68
|
+
self._by_data_type: dict[DataType, TypeMapping] = {}
|
|
69
|
+
self._by_polars_type: dict[type[pl.DataType], TypeMapping] = {}
|
|
70
|
+
self._by_alias: dict[str, TypeMapping] = {}
|
|
71
|
+
self._by_group: dict[TypeGroup, list[TypeMapping]] = {g: [] for g in TypeGroup}
|
|
80
72
|
|
|
81
73
|
for mapping in self._mappings:
|
|
82
74
|
self._by_data_type[mapping.data_type] = mapping
|
|
@@ -96,12 +88,13 @@ class TypeRegistry:
|
|
|
96
88
|
# Register "pl.TypeName" format
|
|
97
89
|
self._by_alias[f"pl.{mapping.polars_type.__name__}".lower()] = mapping
|
|
98
90
|
|
|
99
|
-
def normalize(self, type_spec: Any) ->
|
|
91
|
+
def normalize(self, type_spec: Any) -> set[DataType]:
|
|
100
92
|
"""
|
|
101
93
|
Normalize any type specification to a set of DataType enums.
|
|
102
94
|
This is the main internal API for type resolution.
|
|
103
95
|
"""
|
|
104
96
|
# Handle special case: All types
|
|
97
|
+
|
|
105
98
|
if type_spec == TypeGroup.All or type_spec == "ALL":
|
|
106
99
|
return set(self._by_data_type.keys())
|
|
107
100
|
|
|
@@ -121,7 +114,7 @@ class TypeRegistry:
|
|
|
121
114
|
|
|
122
115
|
# Handle Polars type instance
|
|
123
116
|
if isinstance(type_spec, pl.DataType):
|
|
124
|
-
base_type = type_spec.base_type() if hasattr(type_spec,
|
|
117
|
+
base_type = type_spec.base_type() if hasattr(type_spec, "base_type") else type(type_spec)
|
|
125
118
|
mapping = self._by_polars_type.get(base_type)
|
|
126
119
|
if mapping:
|
|
127
120
|
return {mapping.data_type}
|
|
@@ -129,6 +122,10 @@ class TypeRegistry:
|
|
|
129
122
|
# Handle string aliases
|
|
130
123
|
if isinstance(type_spec, str):
|
|
131
124
|
type_spec_lower = type_spec.lower()
|
|
125
|
+
group: TypeGroup
|
|
126
|
+
for group in TypeGroup:
|
|
127
|
+
if group.lower() == type_spec_lower:
|
|
128
|
+
return {m.data_type for m in (self._by_group.get(group) or [])}
|
|
132
129
|
|
|
133
130
|
# Try TypeGroup name
|
|
134
131
|
try:
|
|
@@ -152,14 +149,14 @@ class TypeRegistry:
|
|
|
152
149
|
# Default to empty set if unrecognized
|
|
153
150
|
return set()
|
|
154
151
|
|
|
155
|
-
def normalize_list(self, type_specs:
|
|
152
|
+
def normalize_list(self, type_specs: list[Any]) -> set[DataType]:
|
|
156
153
|
"""Normalize a list of type specifications."""
|
|
157
154
|
result = set()
|
|
158
155
|
for spec in type_specs:
|
|
159
156
|
result.update(self.normalize(spec))
|
|
160
157
|
return result
|
|
161
158
|
|
|
162
|
-
def get_polars_types(self, data_types:
|
|
159
|
+
def get_polars_types(self, data_types: set[DataType]) -> set[type[pl.DataType]]:
|
|
163
160
|
"""Convert a set of DataType enums to Polars types."""
|
|
164
161
|
result = set()
|
|
165
162
|
for dt in data_types:
|
|
@@ -168,7 +165,7 @@ class TypeRegistry:
|
|
|
168
165
|
result.add(mapping.polars_type)
|
|
169
166
|
return result
|
|
170
167
|
|
|
171
|
-
def get_polars_type(self, data_type: DataType) ->
|
|
168
|
+
def get_polars_type(self, data_type: DataType) -> type[pl.DataType]:
|
|
172
169
|
"""Get the Polars type for a single DataType."""
|
|
173
170
|
mapping = self._by_data_type.get(data_type)
|
|
174
171
|
return mapping.polars_type if mapping else pl.String # Default fallback
|
|
@@ -179,19 +176,19 @@ _registry = TypeRegistry()
|
|
|
179
176
|
|
|
180
177
|
|
|
181
178
|
# Internal API functions (not for public use)
|
|
182
|
-
def normalize_type_spec(type_spec: Any) ->
|
|
179
|
+
def normalize_type_spec(type_spec: Any) -> set[DataType]:
|
|
183
180
|
"""Internal function to normalize type specifications."""
|
|
184
181
|
if isinstance(type_spec, list):
|
|
185
182
|
return _registry.normalize_list(type_spec)
|
|
186
183
|
return _registry.normalize(type_spec)
|
|
187
184
|
|
|
188
185
|
|
|
189
|
-
def get_polars_types(data_types:
|
|
186
|
+
def get_polars_types(data_types: set[DataType]) -> set[type[pl.DataType]]:
|
|
190
187
|
"""Internal function to get Polars types."""
|
|
191
188
|
return _registry.get_polars_types(data_types)
|
|
192
189
|
|
|
193
190
|
|
|
194
|
-
def check_column_type(column_dtype: pl.DataType, accepted_types:
|
|
191
|
+
def check_column_type(column_dtype: pl.DataType, accepted_types: set[DataType]) -> bool:
|
|
195
192
|
"""Check if a column's dtype matches the accepted types."""
|
|
196
193
|
normalized = _registry.normalize(column_dtype)
|
|
197
194
|
return bool(normalized & accepted_types)
|