Flowfile 0.2.2__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.

Potentially problematic release.


This version of Flowfile might be problematic. Click here for more details.

Files changed (171) hide show
  1. build_backends/__init__.py +0 -0
  2. build_backends/main.py +313 -0
  3. build_backends/main_prd.py +202 -0
  4. flowfile/__init__.py +71 -0
  5. flowfile/__main__.py +24 -0
  6. flowfile-0.2.2.dist-info/LICENSE +21 -0
  7. flowfile-0.2.2.dist-info/METADATA +225 -0
  8. flowfile-0.2.2.dist-info/RECORD +171 -0
  9. flowfile-0.2.2.dist-info/WHEEL +4 -0
  10. flowfile-0.2.2.dist-info/entry_points.txt +9 -0
  11. flowfile_core/__init__.py +13 -0
  12. flowfile_core/auth/__init__.py +0 -0
  13. flowfile_core/auth/jwt.py +140 -0
  14. flowfile_core/auth/models.py +40 -0
  15. flowfile_core/auth/secrets.py +178 -0
  16. flowfile_core/configs/__init__.py +35 -0
  17. flowfile_core/configs/flow_logger.py +433 -0
  18. flowfile_core/configs/node_store/__init__.py +0 -0
  19. flowfile_core/configs/node_store/nodes.py +98 -0
  20. flowfile_core/configs/settings.py +120 -0
  21. flowfile_core/database/__init__.py +0 -0
  22. flowfile_core/database/connection.py +51 -0
  23. flowfile_core/database/init_db.py +45 -0
  24. flowfile_core/database/models.py +41 -0
  25. flowfile_core/fileExplorer/__init__.py +0 -0
  26. flowfile_core/fileExplorer/funcs.py +259 -0
  27. flowfile_core/fileExplorer/utils.py +53 -0
  28. flowfile_core/flowfile/FlowfileFlow.py +1403 -0
  29. flowfile_core/flowfile/__init__.py +0 -0
  30. flowfile_core/flowfile/_extensions/__init__.py +0 -0
  31. flowfile_core/flowfile/_extensions/real_time_interface.py +51 -0
  32. flowfile_core/flowfile/analytics/__init__.py +0 -0
  33. flowfile_core/flowfile/analytics/analytics_processor.py +123 -0
  34. flowfile_core/flowfile/analytics/graphic_walker.py +60 -0
  35. flowfile_core/flowfile/analytics/schemas/__init__.py +0 -0
  36. flowfile_core/flowfile/analytics/utils.py +9 -0
  37. flowfile_core/flowfile/connection_manager/__init__.py +3 -0
  38. flowfile_core/flowfile/connection_manager/_connection_manager.py +48 -0
  39. flowfile_core/flowfile/connection_manager/models.py +10 -0
  40. flowfile_core/flowfile/database_connection_manager/__init__.py +0 -0
  41. flowfile_core/flowfile/database_connection_manager/db_connections.py +139 -0
  42. flowfile_core/flowfile/database_connection_manager/models.py +15 -0
  43. flowfile_core/flowfile/extensions.py +36 -0
  44. flowfile_core/flowfile/flow_data_engine/__init__.py +0 -0
  45. flowfile_core/flowfile/flow_data_engine/create/__init__.py +0 -0
  46. flowfile_core/flowfile/flow_data_engine/create/funcs.py +146 -0
  47. flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +1521 -0
  48. flowfile_core/flowfile/flow_data_engine/flow_file_column/__init__.py +0 -0
  49. flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +144 -0
  50. flowfile_core/flowfile/flow_data_engine/flow_file_column/polars_type.py +24 -0
  51. flowfile_core/flowfile/flow_data_engine/flow_file_column/utils.py +36 -0
  52. flowfile_core/flowfile/flow_data_engine/fuzzy_matching/__init__.py +0 -0
  53. flowfile_core/flowfile/flow_data_engine/fuzzy_matching/prepare_for_fuzzy_match.py +38 -0
  54. flowfile_core/flowfile/flow_data_engine/fuzzy_matching/settings_validator.py +90 -0
  55. flowfile_core/flowfile/flow_data_engine/join/__init__.py +1 -0
  56. flowfile_core/flowfile/flow_data_engine/join/verify_integrity.py +54 -0
  57. flowfile_core/flowfile/flow_data_engine/pivot_table.py +20 -0
  58. flowfile_core/flowfile/flow_data_engine/polars_code_parser.py +249 -0
  59. flowfile_core/flowfile/flow_data_engine/read_excel_tables.py +143 -0
  60. flowfile_core/flowfile/flow_data_engine/sample_data.py +120 -0
  61. flowfile_core/flowfile/flow_data_engine/subprocess_operations/__init__.py +1 -0
  62. flowfile_core/flowfile/flow_data_engine/subprocess_operations/models.py +36 -0
  63. flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +503 -0
  64. flowfile_core/flowfile/flow_data_engine/threaded_processes.py +27 -0
  65. flowfile_core/flowfile/flow_data_engine/types.py +0 -0
  66. flowfile_core/flowfile/flow_data_engine/utils.py +212 -0
  67. flowfile_core/flowfile/flow_node/__init__.py +0 -0
  68. flowfile_core/flowfile/flow_node/flow_node.py +771 -0
  69. flowfile_core/flowfile/flow_node/models.py +111 -0
  70. flowfile_core/flowfile/flow_node/schema_callback.py +70 -0
  71. flowfile_core/flowfile/handler.py +123 -0
  72. flowfile_core/flowfile/manage/__init__.py +0 -0
  73. flowfile_core/flowfile/manage/compatibility_enhancements.py +70 -0
  74. flowfile_core/flowfile/manage/manage_flowfile.py +0 -0
  75. flowfile_core/flowfile/manage/open_flowfile.py +136 -0
  76. flowfile_core/flowfile/setting_generator/__init__.py +2 -0
  77. flowfile_core/flowfile/setting_generator/setting_generator.py +41 -0
  78. flowfile_core/flowfile/setting_generator/settings.py +176 -0
  79. flowfile_core/flowfile/sources/__init__.py +0 -0
  80. flowfile_core/flowfile/sources/external_sources/__init__.py +3 -0
  81. flowfile_core/flowfile/sources/external_sources/airbyte_sources/__init__.py +0 -0
  82. flowfile_core/flowfile/sources/external_sources/airbyte_sources/airbyte.py +159 -0
  83. flowfile_core/flowfile/sources/external_sources/airbyte_sources/models.py +172 -0
  84. flowfile_core/flowfile/sources/external_sources/airbyte_sources/settings.py +173 -0
  85. flowfile_core/flowfile/sources/external_sources/base_class.py +39 -0
  86. flowfile_core/flowfile/sources/external_sources/custom_external_sources/__init__.py +2 -0
  87. flowfile_core/flowfile/sources/external_sources/custom_external_sources/exchange_rate.py +0 -0
  88. flowfile_core/flowfile/sources/external_sources/custom_external_sources/external_source.py +100 -0
  89. flowfile_core/flowfile/sources/external_sources/custom_external_sources/google_sheet.py +74 -0
  90. flowfile_core/flowfile/sources/external_sources/custom_external_sources/sample_users.py +29 -0
  91. flowfile_core/flowfile/sources/external_sources/factory.py +22 -0
  92. flowfile_core/flowfile/sources/external_sources/sql_source/__init__.py +0 -0
  93. flowfile_core/flowfile/sources/external_sources/sql_source/models.py +90 -0
  94. flowfile_core/flowfile/sources/external_sources/sql_source/sql_source.py +328 -0
  95. flowfile_core/flowfile/sources/external_sources/sql_source/utils.py +379 -0
  96. flowfile_core/flowfile/util/__init__.py +0 -0
  97. flowfile_core/flowfile/util/calculate_layout.py +137 -0
  98. flowfile_core/flowfile/util/execution_orderer.py +141 -0
  99. flowfile_core/flowfile/utils.py +106 -0
  100. flowfile_core/main.py +138 -0
  101. flowfile_core/routes/__init__.py +0 -0
  102. flowfile_core/routes/auth.py +34 -0
  103. flowfile_core/routes/logs.py +163 -0
  104. flowfile_core/routes/public.py +10 -0
  105. flowfile_core/routes/routes.py +601 -0
  106. flowfile_core/routes/secrets.py +85 -0
  107. flowfile_core/run_lock.py +11 -0
  108. flowfile_core/schemas/__init__.py +0 -0
  109. flowfile_core/schemas/analysis_schemas/__init__.py +0 -0
  110. flowfile_core/schemas/analysis_schemas/graphic_walker_schemas.py +118 -0
  111. flowfile_core/schemas/defaults.py +9 -0
  112. flowfile_core/schemas/external_sources/__init__.py +0 -0
  113. flowfile_core/schemas/external_sources/airbyte_schemas.py +20 -0
  114. flowfile_core/schemas/input_schema.py +477 -0
  115. flowfile_core/schemas/models.py +193 -0
  116. flowfile_core/schemas/output_model.py +115 -0
  117. flowfile_core/schemas/schemas.py +106 -0
  118. flowfile_core/schemas/transform_schema.py +569 -0
  119. flowfile_core/secrets/__init__.py +0 -0
  120. flowfile_core/secrets/secrets.py +64 -0
  121. flowfile_core/utils/__init__.py +0 -0
  122. flowfile_core/utils/arrow_reader.py +247 -0
  123. flowfile_core/utils/excel_file_manager.py +18 -0
  124. flowfile_core/utils/fileManager.py +45 -0
  125. flowfile_core/utils/fl_executor.py +38 -0
  126. flowfile_core/utils/utils.py +8 -0
  127. flowfile_frame/__init__.py +56 -0
  128. flowfile_frame/__main__.py +12 -0
  129. flowfile_frame/adapters.py +17 -0
  130. flowfile_frame/expr.py +1163 -0
  131. flowfile_frame/flow_frame.py +2093 -0
  132. flowfile_frame/group_frame.py +199 -0
  133. flowfile_frame/join.py +75 -0
  134. flowfile_frame/selectors.py +242 -0
  135. flowfile_frame/utils.py +184 -0
  136. flowfile_worker/__init__.py +55 -0
  137. flowfile_worker/configs.py +95 -0
  138. flowfile_worker/create/__init__.py +37 -0
  139. flowfile_worker/create/funcs.py +146 -0
  140. flowfile_worker/create/models.py +86 -0
  141. flowfile_worker/create/pl_types.py +35 -0
  142. flowfile_worker/create/read_excel_tables.py +110 -0
  143. flowfile_worker/create/utils.py +84 -0
  144. flowfile_worker/external_sources/__init__.py +0 -0
  145. flowfile_worker/external_sources/airbyte_sources/__init__.py +0 -0
  146. flowfile_worker/external_sources/airbyte_sources/cache_manager.py +161 -0
  147. flowfile_worker/external_sources/airbyte_sources/main.py +89 -0
  148. flowfile_worker/external_sources/airbyte_sources/models.py +133 -0
  149. flowfile_worker/external_sources/airbyte_sources/settings.py +0 -0
  150. flowfile_worker/external_sources/sql_source/__init__.py +0 -0
  151. flowfile_worker/external_sources/sql_source/main.py +56 -0
  152. flowfile_worker/external_sources/sql_source/models.py +72 -0
  153. flowfile_worker/flow_logger.py +58 -0
  154. flowfile_worker/funcs.py +327 -0
  155. flowfile_worker/main.py +108 -0
  156. flowfile_worker/models.py +95 -0
  157. flowfile_worker/polars_fuzzy_match/__init__.py +0 -0
  158. flowfile_worker/polars_fuzzy_match/matcher.py +435 -0
  159. flowfile_worker/polars_fuzzy_match/models.py +36 -0
  160. flowfile_worker/polars_fuzzy_match/pre_process.py +213 -0
  161. flowfile_worker/polars_fuzzy_match/process.py +86 -0
  162. flowfile_worker/polars_fuzzy_match/utils.py +50 -0
  163. flowfile_worker/process_manager.py +36 -0
  164. flowfile_worker/routes.py +440 -0
  165. flowfile_worker/secrets.py +148 -0
  166. flowfile_worker/spawner.py +187 -0
  167. flowfile_worker/utils.py +25 -0
  168. test_utils/__init__.py +3 -0
  169. test_utils/postgres/__init__.py +1 -0
  170. test_utils/postgres/commands.py +109 -0
  171. test_utils/postgres/fixtures.py +417 -0
@@ -0,0 +1,193 @@
1
+ from pydantic import BaseModel
2
+ from typing import List, Any, Callable
3
+ from datetime import datetime
4
+ from dataclasses import dataclass, field
5
+ import os
6
+ import mimetypes
7
+ from copy import deepcopy
8
+ from flowfile_core.configs.settings import FILE_LOCATION
9
+
10
+
11
+ class DirItem:
12
+ name: str
13
+ full_path: str
14
+ path: str
15
+ type: str
16
+ stats: os.stat = None
17
+ creation_date: datetime = None
18
+ access_date: datetime = None
19
+ modification_date: datetime = None
20
+ source_path: str = None
21
+
22
+ def __init__(self, name: str, path: str,
23
+ stats: os.stat = None,
24
+ creation_date: datetime = None,
25
+ modification_date: datetime = None,
26
+ access_date: datetime = None, *args, **kwargs):
27
+ self.full_path = os.path.relpath(path)
28
+ if name == FILE_LOCATION:
29
+ self.name = self.full_path
30
+ self.source_path = self.full_path
31
+ else:
32
+ self.name = name
33
+ self.source_path = os.sep.join(os.path.split(self.full_path)[:-1])
34
+ self.path = self.full_path
35
+ self.stats = os.stat(self.full_path) if stats is None else stats
36
+ self.creation_date = datetime.fromtimestamp(self.stats.st_ctime) if creation_date is None else creation_date
37
+ self.modification_date = datetime.fromtimestamp(self.stats.st_mtime) if modification_date is None else modification_date
38
+ self.access_date = datetime.fromtimestamp(self.stats.st_atime) if access_date is None else access_date
39
+
40
+
41
+ @dataclass
42
+ class DirFile(DirItem):
43
+ ext: str
44
+ file_size: int
45
+ size: int
46
+ mimetype: str = None
47
+
48
+ def __init__(self, name: str, path: str):
49
+ ext = os.path.splitext(name)[-1]
50
+ if ext == '':
51
+ ext = 'unk'
52
+ self.ext = ext
53
+ self.type = 'file'
54
+ self.mimetype = mimetypes.guess_type(path)[0]
55
+ super().__init__(name, path)
56
+ self.file_size = self.stats.st_size
57
+ self.size = self.file_size_in_kb
58
+
59
+
60
+ @property
61
+ def file_size_in_kb(self) -> int:
62
+ return int(self.file_size/1024)
63
+
64
+ def json_repr(self):
65
+ self_dict = deepcopy(self.__dict__)
66
+ self_dict.pop('stats')
67
+ return self_dict
68
+
69
+ @dataclass
70
+ class DirLocation(DirItem):
71
+ all_items: List[str] = field(default_factory=list)
72
+ number_of_items: int = -1
73
+ files: List[DirFile] = field(default_factory=list)
74
+ directories: List["DirLocation"] = field(default_factory=list)
75
+ __size: int = -1
76
+
77
+ def __init__(self, name: str, path: str = None):
78
+ path = '.' + os.path.sep + name if path is None else path
79
+ self.all_items = os.listdir(path)
80
+ self.files = []
81
+ self.directories = []
82
+ self.type = 'dir'
83
+ super().__init__(name, path)
84
+ self.create_structure()
85
+ self.number_of_items = len(self.all_items)
86
+
87
+ def as_dict(self):
88
+ return {**self.__dict__,**{'size':self.size}}
89
+
90
+ def get_dirs(self):
91
+ return self.directories
92
+
93
+ @property
94
+ def size(self) -> int:
95
+ if self.__size<0:
96
+ size = 0
97
+ for file in self.files:
98
+ size += file.size
99
+ for d in self.directories:
100
+ size += d.size
101
+ self.__size = size
102
+ return self.__size
103
+
104
+ def create_structure(self):
105
+ for item_name in self.all_items:
106
+
107
+ ref = os.path.join(self.full_path, item_name)
108
+ if os.path.isdir(ref):
109
+ self.directories.append(self.__class__(item_name,ref))
110
+ elif os.path.isfile(ref):
111
+ self.files.append(DirFile(item_name,ref))
112
+
113
+ def json_repr(self):
114
+ self_dict = deepcopy(self.__dict__)
115
+ self_dict.pop('stats')
116
+ files: List[DirFile] = self_dict.pop('files')
117
+ directories: List[DirLocation] = self_dict.pop('directories')
118
+ self_dict.pop('all_items')
119
+ self_dict['files'] = [f.json_repr() for f in files]
120
+ self_dict['directories'] = [d.json_repr() for d in directories]
121
+ return self_dict
122
+
123
+ class Country(BaseModel):
124
+ id: int
125
+ name: str
126
+ abbreviation: str
127
+
128
+
129
+ class Address(BaseModel):
130
+ street: str = None
131
+ house_number: int = None
132
+ house_number_addition: str = None
133
+ city: str = None
134
+ zipcode: str = None
135
+ country: Country = None
136
+
137
+
138
+ class Team(Address):
139
+ id: int
140
+ name: str
141
+
142
+
143
+ class User(Address):
144
+ user_name: str
145
+ hashed_password: str
146
+ user_id: int
147
+ team: Team
148
+
149
+
150
+ class ExampleValues(BaseModel):
151
+ pass
152
+
153
+
154
+ class SourceStats(BaseModel):
155
+ id: int
156
+ created_by: User
157
+ created_date: datetime = datetime.now()
158
+ updated_by: User
159
+ updated_date: datetime = datetime.now()
160
+
161
+
162
+ class Source(SourceStats):
163
+ name: str
164
+ team: Team
165
+
166
+
167
+ class Table(SourceStats):
168
+ name: str
169
+ table_type: str = None
170
+ table_fields: List['TableField'] = None
171
+
172
+
173
+ class TableField(BaseModel):
174
+ id: int
175
+ source: Source
176
+ name: str
177
+ python_type: type
178
+
179
+
180
+ class FieldMapper(SourceStats):
181
+ mapping_type: str = None # direct, formula, default value
182
+ input_fields: List[TableField] = None
183
+ output_fields: List[TableField]
184
+ source_table: Table
185
+ target_table: Table
186
+ formula: Callable = None
187
+ default_value: Any = None
188
+
189
+
190
+ class TableMapper(SourceStats):
191
+ source_table: Table
192
+ target_table: Table
193
+
@@ -0,0 +1,115 @@
1
+ from typing import List, Dict, Optional, Any
2
+ from pydantic import BaseModel, Field
3
+ from datetime import datetime
4
+ import time
5
+
6
+
7
+ class NodeResult(BaseModel):
8
+ node_id: int
9
+ node_name: str = None
10
+ start_timestamp: float = Field(default_factory=time.time)
11
+ end_timestamp: float = 0
12
+ success: Optional[bool] = None
13
+ error: str = ''
14
+ run_time: int = -1
15
+ is_running: bool = True
16
+
17
+
18
+ class RunInformation(BaseModel):
19
+ flow_id: int
20
+ start_time: Optional[datetime] = Field(default_factory=datetime.now)
21
+ end_time: Optional[datetime] = None
22
+ success: bool
23
+ nodes_completed: int = 0
24
+ number_of_nodes: int = 0
25
+ node_step_result: List[NodeResult]
26
+
27
+
28
+ class BaseItem(BaseModel):
29
+ name: str
30
+ path: str
31
+ size: Optional[int] = None
32
+ creation_date: Optional[datetime] = None
33
+ access_date: Optional[datetime] = None
34
+ modification_date: Optional[datetime] = None
35
+ source_path: Optional[str] = None
36
+ number_of_items: int = -1
37
+
38
+
39
+ class FileColumn(BaseModel):
40
+ name: str
41
+ data_type: str
42
+ is_unique: bool
43
+ max_value: str
44
+ min_value: str
45
+ number_of_empty_values: int
46
+ number_of_filled_values: int
47
+ number_of_unique_values: int
48
+ size: int
49
+
50
+
51
+ class TableExample(BaseModel):
52
+ node_id: int
53
+ number_of_records: int
54
+ number_of_columns: int
55
+ name: str
56
+ table_schema: List[FileColumn]
57
+ columns: List[str]
58
+ data: Optional[List[Dict]] = {}
59
+
60
+
61
+ class NodeData(BaseModel):
62
+ flow_id: int
63
+ node_id: int
64
+ flow_type: str
65
+ left_input: Optional[TableExample] = None
66
+ right_input: Optional[TableExample] = None
67
+ main_input: Optional[TableExample] = None
68
+ main_output: Optional[TableExample] = None
69
+ left_output: Optional[TableExample] = None
70
+ right_output: Optional[TableExample] = None
71
+ has_run: bool = False
72
+ is_cached: bool = False
73
+ setting_input: Any = None
74
+
75
+
76
+ class OutputFile(BaseItem):
77
+ ext: Optional[str] = None
78
+ mimetype: Optional[str] = None
79
+
80
+
81
+ class OutputFiles(BaseItem):
82
+ files: List[OutputFile] = Field(default_factory=list)
83
+
84
+
85
+ class OutputTree(OutputFiles):
86
+ directories: List[OutputFiles] = Field(default_factory=list)
87
+
88
+
89
+ class ItemInfo(OutputFile):
90
+ id: int = -1
91
+ type: str
92
+ analysis_file_available: bool = False
93
+ analysis_file_location: str = None
94
+ analysis_file_error: str = None
95
+
96
+
97
+ class OutputDir(BaseItem):
98
+ all_items: List[str]
99
+ items: List[ItemInfo]
100
+
101
+
102
+ class ExpressionRef(BaseModel):
103
+ name: str
104
+ doc: Optional[str]
105
+
106
+
107
+ class ExpressionsOverview(BaseModel):
108
+ expression_type: str
109
+ expressions: List[ExpressionRef]
110
+
111
+
112
+ class InstantFuncResult(BaseModel):
113
+ success: Optional[bool] = None
114
+ result: str
115
+
@@ -0,0 +1,106 @@
1
+ from pydantic import BaseModel, field_validator, ConfigDict
2
+ from typing import List, Dict, Tuple, Iterable, Optional, Any, Literal
3
+
4
+
5
+ ExecutionModeLiteral = Literal['Development', 'Performance']
6
+ ExecutionLocationsLiteral = Literal['auto', 'local', 'remote']
7
+
8
+
9
+ class FlowSettings(BaseModel):
10
+ flow_id: int
11
+ description: Optional[str] = None
12
+ save_location: Optional[str] = None
13
+ auto_save: bool = False
14
+ name: str = ''
15
+ modified_on: Optional[float] = None
16
+ path: str
17
+ execution_mode: ExecutionModeLiteral = 'Performance'
18
+ show_detailed_progress: bool = True
19
+ is_running: bool = False
20
+ is_canceled: bool = False
21
+ execution_location: ExecutionLocationsLiteral = "auto"
22
+
23
+
24
+ class RawLogInput(BaseModel):
25
+ flowfile_flow_id: int
26
+ log_message: str
27
+ log_type: Literal["INFO", "ERROR"]
28
+ extra: Optional[dict] = None
29
+
30
+
31
+ class NodeTemplate(BaseModel):
32
+ name: str
33
+ item: str
34
+ input: int
35
+ output: int
36
+ image: str
37
+ multi: bool = False
38
+ node_group: str
39
+ prod_ready: bool = True
40
+ can_be_start: bool = False
41
+
42
+
43
+ class NodeInformation(BaseModel):
44
+ id: Optional[int] = None
45
+ type: Optional[str] = None
46
+ is_setup: Optional[bool] = None
47
+ description: Optional[str] = ''
48
+ x_position: Optional[int] = 0
49
+ y_position: Optional[int] = 0
50
+ left_input_id: Optional[int] = None
51
+ right_input_id: Optional[int] = None
52
+ input_ids: Optional[List[int]] = [-1]
53
+ outputs: Optional[List[int]] = [-1]
54
+ setting_input: Optional[Any] = None
55
+
56
+ @property
57
+ def data(self):
58
+ return self.setting_input
59
+
60
+ @property
61
+ def main_input_ids(self):
62
+ return self.input_ids
63
+
64
+
65
+ class FlowInformation(BaseModel):
66
+ flow_id: int
67
+ flow_name: Optional[str] = ''
68
+ flow_settings: FlowSettings
69
+ data: Dict[int, NodeInformation] = {}
70
+ node_starts: List[int]
71
+ node_connections: List[Tuple[int, int]] = []
72
+
73
+ @field_validator('flow_name', mode="before")
74
+ def ensure_string(cls, v):
75
+ return str(v) if v is not None else ''
76
+
77
+
78
+ class NodeInput(NodeTemplate):
79
+ id: int
80
+ pos_x: float
81
+ pos_y: float
82
+
83
+
84
+ class NodeEdge(BaseModel):
85
+ model_config = ConfigDict(coerce_numbers_to_str=True)
86
+ id: str
87
+ source: str
88
+ target: str
89
+ targetHandle: str
90
+ sourceHandle: str
91
+
92
+
93
+ class VueFlowInput(BaseModel):
94
+ node_edges: List[NodeEdge]
95
+ node_inputs: List[NodeInput]
96
+
97
+
98
+ NodeTypeLiteral = Literal['input', 'output', 'process']
99
+ TransformTypeLiteral = Literal['narrow', 'wide', 'other']
100
+
101
+
102
+ class NodeDefault(BaseModel):
103
+ node_name: str
104
+ node_type: NodeTypeLiteral
105
+ transform_type: TransformTypeLiteral
106
+ has_default_settings: Optional[Any] = None