Flowfile 0.3.2__py3-none-any.whl → 0.3.3.1__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.
- flowfile/__init__.py +3 -2
- flowfile/web/__init__.py +3 -0
- {flowfile-0.3.2.dist-info → flowfile-0.3.3.1.dist-info}/METADATA +4 -3
- {flowfile-0.3.2.dist-info → flowfile-0.3.3.1.dist-info}/RECORD +46 -35
- flowfile_core/configs/__init__.py +15 -4
- flowfile_core/configs/settings.py +5 -3
- flowfile_core/configs/utils.py +18 -0
- flowfile_core/flowfile/FlowfileFlow.py +13 -18
- flowfile_core/flowfile/database_connection_manager/db_connections.py +1 -1
- flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +54 -17
- flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +42 -9
- flowfile_core/flowfile/flow_data_engine/flow_file_column/utils.py +42 -3
- flowfile_core/flowfile/flow_data_engine/polars_code_parser.py +2 -1
- flowfile_core/flowfile/flow_data_engine/sample_data.py +25 -7
- flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +4 -3
- flowfile_core/flowfile/flow_data_engine/utils.py +1 -0
- flowfile_core/flowfile/flow_node/flow_node.py +2 -1
- flowfile_core/flowfile/sources/external_sources/airbyte_sources/models.py +2 -2
- flowfile_core/flowfile/sources/external_sources/sql_source/sql_source.py +1 -1
- flowfile_core/flowfile/utils.py +34 -3
- flowfile_core/main.py +2 -3
- flowfile_core/routes/secrets.py +1 -1
- flowfile_core/schemas/input_schema.py +10 -4
- flowfile_core/schemas/transform_schema.py +25 -47
- flowfile_frame/__init__.py +11 -4
- flowfile_frame/adding_expr.py +280 -0
- flowfile_frame/config.py +9 -0
- flowfile_frame/expr.py +301 -83
- flowfile_frame/expr.pyi +2174 -0
- flowfile_frame/expr_name.py +258 -0
- flowfile_frame/flow_frame.py +584 -1002
- flowfile_frame/flow_frame.pyi +368 -0
- flowfile_frame/flow_frame_methods.py +617 -0
- flowfile_frame/group_frame.py +89 -42
- flowfile_frame/join.py +1 -2
- flowfile_frame/lazy.py +704 -0
- flowfile_frame/lazy_methods.py +201 -0
- flowfile_frame/list_name_space.py +324 -0
- flowfile_frame/selectors.py +3 -0
- flowfile_frame/series.py +70 -0
- flowfile_frame/utils.py +80 -4
- {flowfile-0.3.2.dist-info → flowfile-0.3.3.1.dist-info}/LICENSE +0 -0
- {flowfile-0.3.2.dist-info → flowfile-0.3.3.1.dist-info}/WHEEL +0 -0
- {flowfile-0.3.2.dist-info → flowfile-0.3.3.1.dist-info}/entry_points.txt +0 -0
- /flowfile_core/{secrets → secret_manager}/__init__.py +0 -0
- /flowfile_core/{secrets/secrets.py → secret_manager/secret_manager.py} +0 -0
flowfile_frame/utils.py
CHANGED
|
@@ -4,20 +4,30 @@ import os
|
|
|
4
4
|
import requests
|
|
5
5
|
import subprocess
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
import polars as pl
|
|
7
8
|
from typing import Iterable, Any, List, Optional
|
|
9
|
+
|
|
8
10
|
from flowfile_core.flowfile.FlowfileFlow import FlowGraph
|
|
9
11
|
from flowfile_core.schemas import schemas
|
|
10
12
|
from tempfile import TemporaryDirectory
|
|
11
|
-
|
|
13
|
+
import inspect
|
|
14
|
+
import textwrap
|
|
12
15
|
|
|
13
16
|
def _is_iterable(obj: Any) -> bool:
|
|
14
17
|
# Avoid treating strings as iterables in this context
|
|
15
18
|
return isinstance(obj, Iterable) and not isinstance(obj, (str, bytes))
|
|
16
19
|
|
|
17
20
|
|
|
18
|
-
def
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
def _check_if_convertible_to_code(expressions: List[Any]) -> bool:
|
|
22
|
+
from flowfile_frame.expr import Expr
|
|
23
|
+
for expr in expressions:
|
|
24
|
+
if isinstance(expr, Expr):
|
|
25
|
+
if not expr.convertable_to_code:
|
|
26
|
+
return False
|
|
27
|
+
return True
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _parse_inputs_as_iterable(inputs: tuple[Any, ...] | tuple[Iterable[Any]],) -> List[Any]:
|
|
21
31
|
if not inputs:
|
|
22
32
|
return []
|
|
23
33
|
|
|
@@ -28,6 +38,51 @@ def _parse_inputs_as_iterable(
|
|
|
28
38
|
return list(inputs)
|
|
29
39
|
|
|
30
40
|
|
|
41
|
+
def get_pl_expr_from_expr(expr: Any) -> pl.Expr:
|
|
42
|
+
"""Get the polars expression from the given expression."""
|
|
43
|
+
return expr.expr
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _get_function_source(func):
|
|
47
|
+
"""
|
|
48
|
+
Get the source code of a function if possible.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
tuple: (source_code, is_module_level)
|
|
52
|
+
"""
|
|
53
|
+
try:
|
|
54
|
+
# Try to get the source code
|
|
55
|
+
source = inspect.getsource(func)
|
|
56
|
+
|
|
57
|
+
# Check if it's a lambda
|
|
58
|
+
if func.__name__ == '<lambda>':
|
|
59
|
+
# Extract just the lambda expression
|
|
60
|
+
# This is tricky as getsource returns the entire line
|
|
61
|
+
return None, False
|
|
62
|
+
|
|
63
|
+
# Check if it's a module-level function
|
|
64
|
+
is_module_level = func.__code__.co_flags & 0x10 == 0
|
|
65
|
+
|
|
66
|
+
# Dedent the source to remove any indentation
|
|
67
|
+
source = textwrap.dedent(source)
|
|
68
|
+
|
|
69
|
+
return source, is_module_level
|
|
70
|
+
except (OSError, TypeError):
|
|
71
|
+
# Can't get source (e.g., built-in function, C extension)
|
|
72
|
+
return None, False
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def ensure_inputs_as_iterable(inputs: Any | Iterable[Any]) -> List[Any]:
|
|
76
|
+
"""Convert inputs to list, treating strings as single items."""
|
|
77
|
+
if inputs is None or (hasattr(inputs, '__len__') and len(inputs) == 0):
|
|
78
|
+
return []
|
|
79
|
+
# Treat strings/bytes as atomic items, everything else check if iterable
|
|
80
|
+
if isinstance(inputs, (str, bytes)) or not _is_iterable(inputs):
|
|
81
|
+
return [inputs]
|
|
82
|
+
|
|
83
|
+
return list(inputs)
|
|
84
|
+
|
|
85
|
+
|
|
31
86
|
def _generate_id() -> int:
|
|
32
87
|
"""Generate a simple unique ID for nodes."""
|
|
33
88
|
return int(uuid.uuid4().int % 100000)
|
|
@@ -43,3 +98,24 @@ def create_flow_graph() -> FlowGraph:
|
|
|
43
98
|
flow_graph = FlowGraph(flow_id=flow_id, flow_settings=flow_settings)
|
|
44
99
|
flow_graph.flow_settings.execution_location = 'local' # always create a local frame so that the run time does not attempt to use the flowfile_worker process
|
|
45
100
|
return flow_graph
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def stringify_values(v: Any) -> str:
|
|
104
|
+
"""Convert various types of values to a string representation.
|
|
105
|
+
|
|
106
|
+
Strings are wrapped in double quotes with proper escaping.
|
|
107
|
+
All other types are converted to their string representation.
|
|
108
|
+
"""
|
|
109
|
+
if isinstance(v, str):
|
|
110
|
+
# Escape any existing double quotes in the string
|
|
111
|
+
escaped_str = v.replace('"', '\\"')
|
|
112
|
+
return '"' + escaped_str + '"'
|
|
113
|
+
elif isinstance(v, bool):
|
|
114
|
+
# Handle booleans explicitly (returns "True" or "False")
|
|
115
|
+
return str(v)
|
|
116
|
+
elif isinstance(v, (int, float, complex, type(None))):
|
|
117
|
+
# Handle numbers and None explicitly
|
|
118
|
+
return str(v)
|
|
119
|
+
else:
|
|
120
|
+
# Handle any other types
|
|
121
|
+
return str(v)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|