Flowfile 0.3.10__py3-none-any.whl → 0.4.0__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 (108) hide show
  1. flowfile/__init__.py +6 -1
  2. flowfile/web/static/assets/{CloudConnectionManager-d7c2c028.js → CloudConnectionManager-109ecc3c.js} +2 -2
  3. flowfile/web/static/assets/{CloudStorageReader-d467329f.js → CloudStorageReader-19cdd67a.js} +6 -6
  4. flowfile/web/static/assets/{CloudStorageWriter-071b8b00.js → CloudStorageWriter-48e0ae20.js} +6 -6
  5. flowfile/web/static/assets/ColumnSelector-47996a16.css +10 -0
  6. flowfile/web/static/assets/ColumnSelector-ecaf7c44.js +83 -0
  7. flowfile/web/static/assets/{ContextMenu-2dea5e27.js → ContextMenu-2b348c4c.js} +1 -1
  8. flowfile/web/static/assets/{ContextMenu-785554c4.js → ContextMenu-a779eed7.js} +1 -1
  9. flowfile/web/static/assets/{ContextMenu-a51e19ea.js → ContextMenu-eca26a03.js} +1 -1
  10. flowfile/web/static/assets/{CrossJoin-cf68ec7a.js → CrossJoin-a88f8142.js} +7 -7
  11. flowfile/web/static/assets/CustomNode-74a37f74.css +32 -0
  12. flowfile/web/static/assets/CustomNode-cb863dff.js +211 -0
  13. flowfile/web/static/assets/{DatabaseConnectionSettings-435c5dd8.js → DatabaseConnectionSettings-819d3267.js} +2 -2
  14. flowfile/web/static/assets/{DatabaseManager-349e33a8.js → DatabaseManager-84ee2834.js} +2 -2
  15. flowfile/web/static/assets/{DatabaseReader-8075bd28.js → DatabaseReader-060dd412.js} +9 -9
  16. flowfile/web/static/assets/{DatabaseWriter-3e2dda89.js → DatabaseWriter-7fc7750f.js} +8 -8
  17. flowfile/web/static/assets/{ExploreData-76ec698c.js → ExploreData-82c95991.js} +5 -5
  18. flowfile/web/static/assets/{ExternalSource-609a265c.js → ExternalSource-e1a6ddc7.js} +5 -5
  19. flowfile/web/static/assets/{Filter-97cff793.js → Filter-8aca894a.js} +7 -7
  20. flowfile/web/static/assets/{Formula-09de0ec9.js → Formula-e33686d9.js} +7 -7
  21. flowfile/web/static/assets/{FuzzyMatch-bdf70248.js → FuzzyMatch-abda150d.js} +8 -8
  22. flowfile/web/static/assets/{GraphSolver-0b5a0e05.js → GraphSolver-4ecad1d7.js} +6 -6
  23. flowfile/web/static/assets/{GroupBy-eaddadde.js → GroupBy-656d07f3.js} +5 -5
  24. flowfile/web/static/assets/{Join-3313371b.js → Join-b84ec849.js} +8 -8
  25. flowfile/web/static/assets/{ManualInput-e8bfc0be.js → ManualInput-346f4135.js} +4 -4
  26. flowfile/web/static/assets/MultiSelect-61b98268.js +5 -0
  27. flowfile/web/static/assets/MultiSelect.vue_vue_type_script_setup_true_lang-2a7c8312.js +63 -0
  28. flowfile/web/static/assets/NumericInput-e36602c2.js +5 -0
  29. flowfile/web/static/assets/NumericInput.vue_vue_type_script_setup_true_lang-211a1990.js +35 -0
  30. flowfile/web/static/assets/{Output-7303bb09.js → Output-eb041599.js} +6 -6
  31. flowfile/web/static/assets/{Pivot-3b1c54ef.js → Pivot-f5c774f4.js} +7 -7
  32. flowfile/web/static/assets/{PivotValidation-3bb36c8f.js → PivotValidation-26546cbc.js} +1 -1
  33. flowfile/web/static/assets/{PivotValidation-eaa819c0.js → PivotValidation-e150a24b.js} +1 -1
  34. flowfile/web/static/assets/{PolarsCode-aa12e25d.js → PolarsCode-da3a7abf.js} +5 -5
  35. flowfile/web/static/assets/{Read-a2bfc618.js → Read-0c768769.js} +8 -8
  36. flowfile/web/static/assets/{RecordCount-aa0dc082.js → RecordCount-84736276.js} +4 -4
  37. flowfile/web/static/assets/{RecordId-48ee1a3b.js → RecordId-60055e6d.js} +6 -6
  38. flowfile/web/static/assets/{SQLQueryComponent-e149dbf2.js → SQLQueryComponent-8a486004.js} +1 -1
  39. flowfile/web/static/assets/{Sample-f06cb97a.js → Sample-2d662611.js} +4 -4
  40. flowfile/web/static/assets/{SecretManager-37f34886.js → SecretManager-ef586cab.js} +2 -2
  41. flowfile/web/static/assets/{Select-b60e6c47.js → Select-2e4a6965.js} +7 -7
  42. flowfile/web/static/assets/{SettingsSection-75b6cf4f.js → SettingsSection-310b61c0.js} +1 -1
  43. flowfile/web/static/assets/{SettingsSection-e57a672e.js → SettingsSection-5634f439.js} +1 -1
  44. flowfile/web/static/assets/{SettingsSection-70e5a7b1.js → SettingsSection-7c68b19f.js} +1 -1
  45. flowfile/web/static/assets/SingleSelect-7298811a.js +5 -0
  46. flowfile/web/static/assets/SingleSelect.vue_vue_type_script_setup_true_lang-43807bad.js +62 -0
  47. flowfile/web/static/assets/SliderInput-53105476.js +40 -0
  48. flowfile/web/static/assets/SliderInput-b8fb6a8c.css +4 -0
  49. flowfile/web/static/assets/{Sort-51b1ee4d.js → Sort-4fdebe74.js} +5 -5
  50. flowfile/web/static/assets/TextInput-28366b7e.js +5 -0
  51. flowfile/web/static/assets/TextInput.vue_vue_type_script_setup_true_lang-9cad14ba.js +32 -0
  52. flowfile/web/static/assets/{TextToRows-26835f8f.js → TextToRows-73ffa692.js} +7 -7
  53. flowfile/web/static/assets/ToggleSwitch-598add30.js +5 -0
  54. flowfile/web/static/assets/ToggleSwitch.vue_vue_type_script_setup_true_lang-f620cd32.js +31 -0
  55. flowfile/web/static/assets/{UnavailableFields-88a4cd0c.js → UnavailableFields-66239e83.js} +2 -2
  56. flowfile/web/static/assets/{Union-4d0088eb.js → Union-26b10614.js} +4 -4
  57. flowfile/web/static/assets/{Unique-7d554a62.js → Unique-33b9edbb.js} +7 -7
  58. flowfile/web/static/assets/{Unpivot-4668595c.js → Unpivot-ef69d0e2.js} +6 -6
  59. flowfile/web/static/assets/{UnpivotValidation-d4f0e0e8.js → UnpivotValidation-8658388e.js} +1 -1
  60. flowfile/web/static/assets/{VueGraphicWalker-5324d566.js → VueGraphicWalker-4d7861f4.js} +1 -1
  61. flowfile/web/static/assets/{api-31e4fea6.js → api-2d1394bd.js} +1 -1
  62. flowfile/web/static/assets/{api-271ed117.js → api-c908fffe.js} +1 -1
  63. flowfile/web/static/assets/{designer-bf3d9487.js → designer-1667687d.js} +24 -16
  64. flowfile/web/static/assets/{designer-091bdc3f.css → designer-665e9408.css} +18 -18
  65. flowfile/web/static/assets/{documentation-4d0a1cea.js → documentation-5eed779e.js} +1 -1
  66. flowfile/web/static/assets/{dropDown-025888df.js → dropDown-41ebe3c2.js} +1 -1
  67. flowfile/web/static/assets/{fullEditor-1df991ec.js → fullEditor-0670d32d.js} +2 -2
  68. flowfile/web/static/assets/{genericNodeSettings-d3b2b2ac.js → genericNodeSettings-38410ebf.js} +3 -3
  69. flowfile/web/static/assets/{index-681a3ed0.css → index-50508d4d.css} +8 -0
  70. flowfile/web/static/assets/{index-d0518598.js → index-5ec791df.js} +6 -6
  71. flowfile/web/static/assets/{outputCsv-d8457527.js → outputCsv-059583b6.js} +1 -1
  72. flowfile/web/static/assets/{outputExcel-be89153e.js → outputExcel-76b1e02c.js} +1 -1
  73. flowfile/web/static/assets/{outputParquet-fabb445a.js → outputParquet-440fd4c7.js} +1 -1
  74. flowfile/web/static/assets/{readCsv-e8359522.js → readCsv-9813903a.js} +1 -1
  75. flowfile/web/static/assets/{readExcel-dabaf51b.js → readExcel-7f40d237.js} +3 -3
  76. flowfile/web/static/assets/{readParquet-e0771ef2.js → readParquet-22d56002.js} +1 -1
  77. flowfile/web/static/assets/{secretApi-ce823eee.js → secretApi-b3cb072e.js} +1 -1
  78. flowfile/web/static/assets/{selectDynamic-5476546e.js → selectDynamic-7ad95bca.js} +3 -3
  79. flowfile/web/static/assets/user-defined-icon-0ae16c90.png +0 -0
  80. flowfile/web/static/assets/{vue-codemirror.esm-9ed00d50.js → vue-codemirror.esm-b1dfaa46.js} +33 -3
  81. flowfile/web/static/assets/{vue-content-loader.es-7bca2d9b.js → vue-content-loader.es-22bac17c.js} +1 -1
  82. flowfile/web/static/index.html +2 -2
  83. {flowfile-0.3.10.dist-info → flowfile-0.4.0.dist-info}/METADATA +1 -1
  84. {flowfile-0.3.10.dist-info → flowfile-0.4.0.dist-info}/RECORD +108 -82
  85. flowfile_core/configs/node_store/__init__.py +30 -0
  86. flowfile_core/configs/node_store/nodes.py +383 -358
  87. flowfile_core/configs/node_store/user_defined_node_registry.py +193 -0
  88. flowfile_core/flowfile/flow_data_engine/flow_file_column/interface.py +4 -0
  89. flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +19 -34
  90. flowfile_core/flowfile/flow_data_engine/flow_file_column/type_registry.py +36 -0
  91. flowfile_core/flowfile/flow_graph.py +20 -1
  92. flowfile_core/flowfile/flow_node/flow_node.py +4 -4
  93. flowfile_core/flowfile/manage/open_flowfile.py +9 -1
  94. flowfile_core/flowfile/node_designer/__init__.py +47 -0
  95. flowfile_core/flowfile/node_designer/_type_registry.py +197 -0
  96. flowfile_core/flowfile/node_designer/custom_node.py +371 -0
  97. flowfile_core/flowfile/node_designer/data_types.py +146 -0
  98. flowfile_core/flowfile/node_designer/ui_components.py +277 -0
  99. flowfile_core/main.py +2 -1
  100. flowfile_core/routes/routes.py +16 -20
  101. flowfile_core/routes/user_defined_components.py +55 -0
  102. flowfile_core/schemas/input_schema.py +8 -1
  103. flowfile_core/schemas/schemas.py +6 -3
  104. flowfile_core/utils/validate_setup.py +3 -1
  105. shared/storage_config.py +17 -2
  106. {flowfile-0.3.10.dist-info → flowfile-0.4.0.dist-info}/LICENSE +0 -0
  107. {flowfile-0.3.10.dist-info → flowfile-0.4.0.dist-info}/WHEEL +0 -0
  108. {flowfile-0.3.10.dist-info → flowfile-0.4.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,371 @@
1
+ # Fixed custom_node.py with proper type hints
2
+
3
+ import polars as pl
4
+ from pydantic import BaseModel
5
+ from typing import Any, Dict, Optional, TypeVar, Callable
6
+ from flowfile_core.flowfile.node_designer.ui_components import FlowfileInComponent, IncomingColumns, Section
7
+ from flowfile_core.schemas.schemas import NodeTemplate, NodeTypeLiteral, TransformTypeLiteral
8
+
9
+
10
+ def to_frontend_schema(model_instance: BaseModel) -> dict:
11
+ """
12
+ Recursively converts a Pydantic model instance into a JSON-serializable
13
+ dictionary suitable for the frontend.
14
+
15
+ This function handles special marker classes like `IncomingColumns` and
16
+ nested `Section` and `FlowfileInComponent` instances.
17
+
18
+ Args:
19
+ model_instance: The Pydantic model instance to convert.
20
+
21
+ Returns:
22
+ A dictionary representation of the model.
23
+ """
24
+ result = {}
25
+ extra_fields = getattr(model_instance, '__pydantic_extra__', {})
26
+ model_fields = {k: getattr(model_instance, k) for k in model_instance.model_fields.keys()}
27
+ for key, value in (extra_fields|model_fields).items():
28
+ result[key] = _convert_value(value)
29
+ return result
30
+
31
+
32
+ def _convert_value(value: Any) -> Any:
33
+ """
34
+ Helper function to convert any value to a frontend-ready format.
35
+ """
36
+ if isinstance(value, Section):
37
+ section_data = value.model_dump(
38
+ include={'title', 'description', 'hidden'},
39
+ exclude_none=True
40
+ )
41
+ section_data["component_type"] = "Section"
42
+ section_data["components"] = {
43
+ key: _convert_value(comp)
44
+ for key, comp in value.get_components().items()
45
+ }
46
+ return section_data
47
+
48
+ elif isinstance(value, FlowfileInComponent):
49
+ component_dict = value.model_dump(exclude_none=True)
50
+ if 'options' in component_dict:
51
+ if component_dict['options'] is IncomingColumns or (
52
+ isinstance(component_dict['options'], type) and
53
+ issubclass(component_dict['options'], IncomingColumns)
54
+ ):
55
+ component_dict['options'] = {"__type__": "IncomingColumns"}
56
+ return component_dict
57
+ elif isinstance(value, BaseModel):
58
+ return to_frontend_schema(value)
59
+ elif isinstance(value, list):
60
+ return [_convert_value(item) for item in value]
61
+ elif isinstance(value, dict):
62
+ return {k: _convert_value(v) for k, v in value.items()}
63
+ elif isinstance(value, tuple):
64
+ return tuple(_convert_value(item) for item in value)
65
+ else:
66
+ return value
67
+
68
+
69
+ # Type variable for the Section factory
70
+ T = TypeVar('T', bound=Section)
71
+
72
+
73
+ def create_section(**components: FlowfileInComponent) -> Section:
74
+ """
75
+ Factory function to create a Section with proper type hints.
76
+
77
+ This is a convenience function that makes it easier to create `Section`
78
+ objects with autocomplete and type checking in modern editors.
79
+
80
+ Usage:
81
+ advanced_config_section = create_section(
82
+ case_sensitive=case_sensitive_toggle
83
+ )
84
+
85
+ Args:
86
+ **components: Keyword arguments where each key is the component name
87
+ and the value is a `FlowfileInComponent` instance.
88
+
89
+ Returns:
90
+ A new `Section` instance containing the provided components.
91
+ """
92
+ return Section(**components)
93
+
94
+
95
+ class NodeSettings(BaseModel):
96
+ """
97
+ The top-level container for all sections in a node's UI.
98
+
99
+ This class holds all the `Section` objects that make up the settings panel
100
+ for a custom node.
101
+
102
+ Example:
103
+ class MyNodeSettings(NodeSettings):
104
+ main_config = main_config_section
105
+ advanced_options = advanced_config_section
106
+ """
107
+ class Config:
108
+ extra = 'allow'
109
+ arbitrary_types_allowed = True
110
+
111
+ def __init__(self, **sections):
112
+ """
113
+ Initialize NodeSettings with sections as keyword arguments.
114
+ """
115
+ super().__init__(**sections)
116
+
117
+ def populate_values(self, values: Dict[str, Any]) -> 'NodeSettings':
118
+ """
119
+ Populates the settings with values received from the frontend.
120
+
121
+ This method is used internally to update the node's state based on
122
+ user input in the UI.
123
+
124
+ Args:
125
+ values: A dictionary of values from the frontend, where keys are
126
+ section names and values are dictionaries of component
127
+ values.
128
+
129
+ Returns:
130
+ The `NodeSettings` instance with updated component values.
131
+ """
132
+ # Handle both extra fields and defined fields
133
+ all_sections = {}
134
+
135
+ # Get extra fields
136
+ extra_fields = getattr(self, '__pydantic_extra__', {})
137
+ all_sections.update(extra_fields)
138
+
139
+ # Get defined fields that are Sections
140
+ for field_name in self.model_fields:
141
+ field_value = getattr(self, field_name, None)
142
+ if isinstance(field_value, Section):
143
+ all_sections[field_name] = field_value
144
+
145
+ for section_name, section in all_sections.items():
146
+ if section_name in values:
147
+ section_values = values[section_name]
148
+ for component_name, component in section.get_components().items():
149
+ if component_name in section_values:
150
+ component.set_value(section_values[component_name])
151
+ return self
152
+
153
+
154
+ def create_node_settings(**sections: Section) -> NodeSettings:
155
+ """
156
+ Factory function to create NodeSettings with proper type hints.
157
+
158
+ This is a convenience function for creating `NodeSettings` instances.
159
+
160
+ Usage:
161
+ FilterNodeSchema = create_node_settings(
162
+ main_config=main_config_section,
163
+ advanced_options=advanced_config_section
164
+ )
165
+
166
+ Args:
167
+ **sections: Keyword arguments where each key is the section name
168
+ and the value is a `Section` instance.
169
+
170
+ Returns:
171
+ A new `NodeSettings` instance containing the provided sections.
172
+ """
173
+ return NodeSettings(**sections)
174
+
175
+
176
+ class SectionBuilder:
177
+ """
178
+ A builder pattern for creating `Section` objects with proper type hints.
179
+
180
+ This provides a more fluent and readable way to construct complex sections,
181
+ especially when the number of components is large.
182
+
183
+ Usage:
184
+ builder = SectionBuilder(title="Advanced Settings")
185
+ builder.add_component("timeout", NumericInput(label="Timeout (s)"))
186
+ builder.add_component("retries", NumericInput(label="Number of Retries"))
187
+ advanced_section = builder.build()
188
+ """
189
+
190
+ def __init__(self, title: Optional[str] = None, description: Optional[str] = None, hidden: bool = False):
191
+ self._section = Section(title=title, description=description, hidden=hidden)
192
+
193
+ def add_component(self, name: str, component: FlowfileInComponent) -> 'SectionBuilder':
194
+ """Add a component to the section."""
195
+ setattr(self._section, name, component)
196
+ extra = getattr(self._section, '__pydantic_extra__', {})
197
+ extra[name] = component
198
+ return self
199
+
200
+ def build(self) -> Section:
201
+ """Build and return the Section."""
202
+ return self._section
203
+
204
+
205
+ class NodeSettingsBuilder:
206
+ """
207
+ A builder pattern for creating `NodeSettings` objects.
208
+
209
+ Provides a fluent interface for constructing the entire settings schema
210
+ for a custom node.
211
+
212
+ Usage:
213
+ settings_builder = NodeSettingsBuilder()
214
+ settings_builder.add_section("main", main_section)
215
+ settings_builder.add_section("advanced", advanced_section)
216
+ my_node_settings = settings_builder.build()
217
+ """
218
+
219
+ def __init__(self):
220
+ self._settings = NodeSettings()
221
+
222
+ def add_section(self, name: str, section: Section) -> 'NodeSettingsBuilder':
223
+ """Add a section to the node settings."""
224
+ setattr(self._settings, name, section)
225
+ extra = getattr(self._settings, '__pydantic_extra__', {})
226
+ extra[name] = section
227
+ return self
228
+
229
+ def build(self) -> NodeSettings:
230
+ """Build and return the NodeSettings."""
231
+ return self._settings
232
+
233
+
234
+ class CustomNodeBase(BaseModel):
235
+ """
236
+ The base class for creating a custom node in Flowfile.
237
+
238
+ To create a new node, you should inherit from this class and define its
239
+ attributes and the `process` method.
240
+ """
241
+ # Core node properties
242
+ node_name: str
243
+ node_category: str = "Custom"
244
+ node_icon: str = "user-defined-icon.png"
245
+ settings_schema: Optional[NodeSettings] = None
246
+
247
+ # I/O configuration
248
+ number_of_inputs: int = 1
249
+ number_of_outputs: int = 1
250
+
251
+ # Display properties in the UI
252
+ node_group: Optional[str] = "custom"
253
+ title: Optional[str] = "Custom Node"
254
+ intro: Optional[str] = "A custom node for data processing"
255
+
256
+ # Behavior properties
257
+ node_type: NodeTypeLiteral = "process"
258
+ transform_type: TransformTypeLiteral = "wide"
259
+
260
+ @property
261
+ def item(self):
262
+ """A unique identifier for the node, derived from its name."""
263
+ return self.node_name.replace(" ", "_").lower()
264
+
265
+ class Config:
266
+ arbitrary_types_allowed = True
267
+
268
+ def __init__(self, **data):
269
+ """
270
+ Initialize the node, optionally populating settings from initial values.
271
+ """
272
+ initial_values = data.pop('initial_values', None)
273
+ super().__init__(**data)
274
+ if self.settings_schema and initial_values:
275
+ self.settings_schema.populate_values(initial_values)
276
+
277
+ def get_frontend_schema(self) -> dict:
278
+ """
279
+ Get the frontend-ready schema with current values.
280
+
281
+ This method is called by the backend to send the node's UI definition
282
+ and current state to the frontend.
283
+
284
+ Returns:
285
+ A dictionary representing the node's schema and values.
286
+ """
287
+ schema = {
288
+ "node_name": self.node_name,
289
+ "node_category": self.node_category,
290
+ "node_icon": self.node_icon,
291
+ "number_of_inputs": self.number_of_inputs,
292
+ "number_of_outputs": self.number_of_outputs,
293
+ "node_group": self.node_group,
294
+ "title": self.title,
295
+ "intro": self.intro,
296
+ }
297
+
298
+ if self.settings_schema:
299
+ schema["settings_schema"] = to_frontend_schema(self.settings_schema)
300
+ else:
301
+ schema["settings_schema"] = {}
302
+
303
+ return schema
304
+
305
+ @classmethod
306
+ def from_frontend_schema(cls, schema: dict) -> 'CustomNodeBase':
307
+ """
308
+ Create a node instance from a frontend schema.
309
+
310
+ This is used when loading a node from a saved flow.
311
+ """
312
+ settings_values = schema.pop('settings_schema', {})
313
+ node = cls(**schema)
314
+ if settings_values and node.settings_schema:
315
+ node.settings_schema.populate_values(settings_values)
316
+ return node
317
+
318
+ @classmethod
319
+ def from_settings(cls, settings_values: dict) -> 'CustomNodeBase':
320
+ """
321
+ Create a node instance with just its settings values.
322
+
323
+ Useful for creating a configured node instance programmatically.
324
+ """
325
+ node = cls()
326
+ if settings_values and node.settings_schema:
327
+ node.settings_schema.populate_values(settings_values)
328
+ return node
329
+
330
+ def update_settings(self, values: Dict[str, Any]) -> 'CustomNodeBase':
331
+ """
332
+ Update the settings with new values from the frontend.
333
+ """
334
+ if self.settings_schema:
335
+ self.settings_schema.populate_values(values)
336
+ return self
337
+
338
+ def process(self, *inputs: pl.DataFrame) -> pl.DataFrame:
339
+ """
340
+ The main data processing logic for the node.
341
+
342
+ This method must be implemented by all subclasses. It receives one or
343
+ more Polars DataFrames as input and should return a single DataFrame
344
+ as output.
345
+
346
+ Args:
347
+ *inputs: A variable number of Polars DataFrames, corresponding to
348
+ the inputs connected to the node.
349
+
350
+ Returns:
351
+ A Polars DataFrame containing the processed data.
352
+ """
353
+ raise NotImplementedError
354
+
355
+ def to_node_template(self) -> NodeTemplate:
356
+ """
357
+ Convert the node to a `NodeTemplate` for storage or transmission.
358
+ """
359
+ return NodeTemplate(
360
+ name=self.node_name,
361
+ item=self.item,
362
+ input=self.number_of_inputs,
363
+ output=self.number_of_outputs,
364
+ image=self.node_icon,
365
+ node_group=self.node_group,
366
+ drawer_title=self.title,
367
+ drawer_intro=self.intro,
368
+ node_type=self.node_type,
369
+ transform_type=self.transform_type,
370
+ custom_node=True
371
+ )
@@ -0,0 +1,146 @@
1
+ # types.py - Public API for type specifications
2
+ """
3
+ Public type system for column selection and data type specification.
4
+
5
+ Usage:
6
+ from flowfile_core.types import Types
7
+
8
+ # Use type groups
9
+ ColumnSelector(data_types=Types.Numeric)
10
+ ColumnSelector(data_types=Types.String)
11
+
12
+ # Use specific types
13
+ ColumnSelector(data_types=Types.Int64)
14
+ ColumnSelector(data_types=Types.Float)
15
+
16
+ # Mix and match
17
+ ColumnSelector(data_types=[Types.Numeric, Types.String])
18
+ """
19
+
20
+ from enum import Enum
21
+ from typing import List, Union
22
+ import polars as pl
23
+
24
+
25
+ class TypeGroup(str, Enum):
26
+ """High-level type groups for column selection."""
27
+ Numeric = "Numeric"
28
+ String = "String"
29
+ Date = "Date"
30
+ Boolean = "Boolean"
31
+ Binary = "Binary"
32
+ Complex = "Complex"
33
+ All = "ALL"
34
+
35
+ def __str__(self) -> str:
36
+ return self.value
37
+
38
+ def __repr__(self) -> str:
39
+ return f"Types.{self.name}"
40
+
41
+
42
+ class DataType(str, Enum):
43
+ """Specific data types for fine-grained control."""
44
+ # Numeric types
45
+ Int8 = "Int8"
46
+ Int16 = "Int16"
47
+ Int32 = "Int32"
48
+ Int64 = "Int64"
49
+ UInt8 = "UInt8"
50
+ UInt16 = "UInt16"
51
+ UInt32 = "UInt32"
52
+ UInt64 = "UInt64"
53
+ Float32 = "Float32"
54
+ Float64 = "Float64"
55
+ Decimal = "Decimal"
56
+
57
+ # String types
58
+ String = "String"
59
+ Categorical = "Categorical"
60
+
61
+ # Date types
62
+ Date = "Date"
63
+ Datetime = "Datetime"
64
+ Time = "Time"
65
+ Duration = "Duration"
66
+
67
+ # Other types
68
+ Boolean = "Boolean"
69
+ Binary = "Binary"
70
+ List = "List"
71
+ Struct = "Struct"
72
+ Array = "Array"
73
+
74
+ def __str__(self) -> str:
75
+ return self.value
76
+
77
+ def __repr__(self) -> str:
78
+ return f"Types.{self.name}"
79
+
80
+
81
+ class Types:
82
+ """
83
+ Main entry point for type specifications.
84
+
85
+ Examples:
86
+ Types.Numeric # All numeric columns
87
+ Types.String # All string columns
88
+ Types.Int64 # 64-bit integers only
89
+ Types.Float # Alias for Float64
90
+ Types.All # All column types
91
+ """
92
+
93
+ # Type groups (most common use case)
94
+ Numeric = TypeGroup.Numeric
95
+ String = TypeGroup.String
96
+ Date = TypeGroup.Date
97
+ Boolean = TypeGroup.Boolean
98
+ Binary = TypeGroup.Binary
99
+ Complex = TypeGroup.Complex
100
+ All = TypeGroup.All
101
+
102
+ # Specific numeric types
103
+ Int = DataType.Int64 # Default integer
104
+ Int8 = DataType.Int8
105
+ Int16 = DataType.Int16
106
+ Int32 = DataType.Int32
107
+ Int64 = DataType.Int64
108
+ UInt8 = DataType.UInt8
109
+ UInt16 = DataType.UInt16
110
+ UInt32 = DataType.UInt32
111
+ UInt64 = DataType.UInt64
112
+
113
+ Float = DataType.Float64 # Default float
114
+ Float32 = DataType.Float32
115
+ Float64 = DataType.Float64
116
+ Decimal = DataType.Decimal
117
+
118
+ # String types
119
+ Str = DataType.String
120
+ Text = DataType.String # Alias
121
+ Categorical = DataType.Categorical
122
+ Cat = DataType.Categorical # Short alias
123
+
124
+ # Date/time types
125
+ Date = DataType.Date
126
+ Datetime = DataType.Datetime
127
+ Time = DataType.Time
128
+ Duration = DataType.Duration
129
+
130
+ # Other types
131
+ Bool = DataType.Boolean
132
+ Bytes = DataType.Binary
133
+ List = DataType.List
134
+ Struct = DataType.Struct
135
+ Array = DataType.Array
136
+
137
+
138
+ # Type alias for better type hints
139
+ TypeSpec = Union[
140
+ TypeGroup,
141
+ DataType,
142
+ str,
143
+ List[Union[TypeGroup, DataType, str, type[pl.DataType], pl.DataType]],
144
+ type[pl.DataType],
145
+ pl.DataType
146
+ ]