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.
- build_backends/__init__.py +0 -0
- build_backends/main.py +313 -0
- build_backends/main_prd.py +202 -0
- flowfile/__init__.py +71 -0
- flowfile/__main__.py +24 -0
- flowfile-0.2.2.dist-info/LICENSE +21 -0
- flowfile-0.2.2.dist-info/METADATA +225 -0
- flowfile-0.2.2.dist-info/RECORD +171 -0
- flowfile-0.2.2.dist-info/WHEEL +4 -0
- flowfile-0.2.2.dist-info/entry_points.txt +9 -0
- flowfile_core/__init__.py +13 -0
- flowfile_core/auth/__init__.py +0 -0
- flowfile_core/auth/jwt.py +140 -0
- flowfile_core/auth/models.py +40 -0
- flowfile_core/auth/secrets.py +178 -0
- flowfile_core/configs/__init__.py +35 -0
- flowfile_core/configs/flow_logger.py +433 -0
- flowfile_core/configs/node_store/__init__.py +0 -0
- flowfile_core/configs/node_store/nodes.py +98 -0
- flowfile_core/configs/settings.py +120 -0
- flowfile_core/database/__init__.py +0 -0
- flowfile_core/database/connection.py +51 -0
- flowfile_core/database/init_db.py +45 -0
- flowfile_core/database/models.py +41 -0
- flowfile_core/fileExplorer/__init__.py +0 -0
- flowfile_core/fileExplorer/funcs.py +259 -0
- flowfile_core/fileExplorer/utils.py +53 -0
- flowfile_core/flowfile/FlowfileFlow.py +1403 -0
- flowfile_core/flowfile/__init__.py +0 -0
- flowfile_core/flowfile/_extensions/__init__.py +0 -0
- flowfile_core/flowfile/_extensions/real_time_interface.py +51 -0
- flowfile_core/flowfile/analytics/__init__.py +0 -0
- flowfile_core/flowfile/analytics/analytics_processor.py +123 -0
- flowfile_core/flowfile/analytics/graphic_walker.py +60 -0
- flowfile_core/flowfile/analytics/schemas/__init__.py +0 -0
- flowfile_core/flowfile/analytics/utils.py +9 -0
- flowfile_core/flowfile/connection_manager/__init__.py +3 -0
- flowfile_core/flowfile/connection_manager/_connection_manager.py +48 -0
- flowfile_core/flowfile/connection_manager/models.py +10 -0
- flowfile_core/flowfile/database_connection_manager/__init__.py +0 -0
- flowfile_core/flowfile/database_connection_manager/db_connections.py +139 -0
- flowfile_core/flowfile/database_connection_manager/models.py +15 -0
- flowfile_core/flowfile/extensions.py +36 -0
- flowfile_core/flowfile/flow_data_engine/__init__.py +0 -0
- flowfile_core/flowfile/flow_data_engine/create/__init__.py +0 -0
- flowfile_core/flowfile/flow_data_engine/create/funcs.py +146 -0
- flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +1521 -0
- flowfile_core/flowfile/flow_data_engine/flow_file_column/__init__.py +0 -0
- flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +144 -0
- flowfile_core/flowfile/flow_data_engine/flow_file_column/polars_type.py +24 -0
- flowfile_core/flowfile/flow_data_engine/flow_file_column/utils.py +36 -0
- flowfile_core/flowfile/flow_data_engine/fuzzy_matching/__init__.py +0 -0
- flowfile_core/flowfile/flow_data_engine/fuzzy_matching/prepare_for_fuzzy_match.py +38 -0
- flowfile_core/flowfile/flow_data_engine/fuzzy_matching/settings_validator.py +90 -0
- flowfile_core/flowfile/flow_data_engine/join/__init__.py +1 -0
- flowfile_core/flowfile/flow_data_engine/join/verify_integrity.py +54 -0
- flowfile_core/flowfile/flow_data_engine/pivot_table.py +20 -0
- flowfile_core/flowfile/flow_data_engine/polars_code_parser.py +249 -0
- flowfile_core/flowfile/flow_data_engine/read_excel_tables.py +143 -0
- flowfile_core/flowfile/flow_data_engine/sample_data.py +120 -0
- flowfile_core/flowfile/flow_data_engine/subprocess_operations/__init__.py +1 -0
- flowfile_core/flowfile/flow_data_engine/subprocess_operations/models.py +36 -0
- flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +503 -0
- flowfile_core/flowfile/flow_data_engine/threaded_processes.py +27 -0
- flowfile_core/flowfile/flow_data_engine/types.py +0 -0
- flowfile_core/flowfile/flow_data_engine/utils.py +212 -0
- flowfile_core/flowfile/flow_node/__init__.py +0 -0
- flowfile_core/flowfile/flow_node/flow_node.py +771 -0
- flowfile_core/flowfile/flow_node/models.py +111 -0
- flowfile_core/flowfile/flow_node/schema_callback.py +70 -0
- flowfile_core/flowfile/handler.py +123 -0
- flowfile_core/flowfile/manage/__init__.py +0 -0
- flowfile_core/flowfile/manage/compatibility_enhancements.py +70 -0
- flowfile_core/flowfile/manage/manage_flowfile.py +0 -0
- flowfile_core/flowfile/manage/open_flowfile.py +136 -0
- flowfile_core/flowfile/setting_generator/__init__.py +2 -0
- flowfile_core/flowfile/setting_generator/setting_generator.py +41 -0
- flowfile_core/flowfile/setting_generator/settings.py +176 -0
- flowfile_core/flowfile/sources/__init__.py +0 -0
- flowfile_core/flowfile/sources/external_sources/__init__.py +3 -0
- flowfile_core/flowfile/sources/external_sources/airbyte_sources/__init__.py +0 -0
- flowfile_core/flowfile/sources/external_sources/airbyte_sources/airbyte.py +159 -0
- flowfile_core/flowfile/sources/external_sources/airbyte_sources/models.py +172 -0
- flowfile_core/flowfile/sources/external_sources/airbyte_sources/settings.py +173 -0
- flowfile_core/flowfile/sources/external_sources/base_class.py +39 -0
- flowfile_core/flowfile/sources/external_sources/custom_external_sources/__init__.py +2 -0
- flowfile_core/flowfile/sources/external_sources/custom_external_sources/exchange_rate.py +0 -0
- flowfile_core/flowfile/sources/external_sources/custom_external_sources/external_source.py +100 -0
- flowfile_core/flowfile/sources/external_sources/custom_external_sources/google_sheet.py +74 -0
- flowfile_core/flowfile/sources/external_sources/custom_external_sources/sample_users.py +29 -0
- flowfile_core/flowfile/sources/external_sources/factory.py +22 -0
- flowfile_core/flowfile/sources/external_sources/sql_source/__init__.py +0 -0
- flowfile_core/flowfile/sources/external_sources/sql_source/models.py +90 -0
- flowfile_core/flowfile/sources/external_sources/sql_source/sql_source.py +328 -0
- flowfile_core/flowfile/sources/external_sources/sql_source/utils.py +379 -0
- flowfile_core/flowfile/util/__init__.py +0 -0
- flowfile_core/flowfile/util/calculate_layout.py +137 -0
- flowfile_core/flowfile/util/execution_orderer.py +141 -0
- flowfile_core/flowfile/utils.py +106 -0
- flowfile_core/main.py +138 -0
- flowfile_core/routes/__init__.py +0 -0
- flowfile_core/routes/auth.py +34 -0
- flowfile_core/routes/logs.py +163 -0
- flowfile_core/routes/public.py +10 -0
- flowfile_core/routes/routes.py +601 -0
- flowfile_core/routes/secrets.py +85 -0
- flowfile_core/run_lock.py +11 -0
- flowfile_core/schemas/__init__.py +0 -0
- flowfile_core/schemas/analysis_schemas/__init__.py +0 -0
- flowfile_core/schemas/analysis_schemas/graphic_walker_schemas.py +118 -0
- flowfile_core/schemas/defaults.py +9 -0
- flowfile_core/schemas/external_sources/__init__.py +0 -0
- flowfile_core/schemas/external_sources/airbyte_schemas.py +20 -0
- flowfile_core/schemas/input_schema.py +477 -0
- flowfile_core/schemas/models.py +193 -0
- flowfile_core/schemas/output_model.py +115 -0
- flowfile_core/schemas/schemas.py +106 -0
- flowfile_core/schemas/transform_schema.py +569 -0
- flowfile_core/secrets/__init__.py +0 -0
- flowfile_core/secrets/secrets.py +64 -0
- flowfile_core/utils/__init__.py +0 -0
- flowfile_core/utils/arrow_reader.py +247 -0
- flowfile_core/utils/excel_file_manager.py +18 -0
- flowfile_core/utils/fileManager.py +45 -0
- flowfile_core/utils/fl_executor.py +38 -0
- flowfile_core/utils/utils.py +8 -0
- flowfile_frame/__init__.py +56 -0
- flowfile_frame/__main__.py +12 -0
- flowfile_frame/adapters.py +17 -0
- flowfile_frame/expr.py +1163 -0
- flowfile_frame/flow_frame.py +2093 -0
- flowfile_frame/group_frame.py +199 -0
- flowfile_frame/join.py +75 -0
- flowfile_frame/selectors.py +242 -0
- flowfile_frame/utils.py +184 -0
- flowfile_worker/__init__.py +55 -0
- flowfile_worker/configs.py +95 -0
- flowfile_worker/create/__init__.py +37 -0
- flowfile_worker/create/funcs.py +146 -0
- flowfile_worker/create/models.py +86 -0
- flowfile_worker/create/pl_types.py +35 -0
- flowfile_worker/create/read_excel_tables.py +110 -0
- flowfile_worker/create/utils.py +84 -0
- flowfile_worker/external_sources/__init__.py +0 -0
- flowfile_worker/external_sources/airbyte_sources/__init__.py +0 -0
- flowfile_worker/external_sources/airbyte_sources/cache_manager.py +161 -0
- flowfile_worker/external_sources/airbyte_sources/main.py +89 -0
- flowfile_worker/external_sources/airbyte_sources/models.py +133 -0
- flowfile_worker/external_sources/airbyte_sources/settings.py +0 -0
- flowfile_worker/external_sources/sql_source/__init__.py +0 -0
- flowfile_worker/external_sources/sql_source/main.py +56 -0
- flowfile_worker/external_sources/sql_source/models.py +72 -0
- flowfile_worker/flow_logger.py +58 -0
- flowfile_worker/funcs.py +327 -0
- flowfile_worker/main.py +108 -0
- flowfile_worker/models.py +95 -0
- flowfile_worker/polars_fuzzy_match/__init__.py +0 -0
- flowfile_worker/polars_fuzzy_match/matcher.py +435 -0
- flowfile_worker/polars_fuzzy_match/models.py +36 -0
- flowfile_worker/polars_fuzzy_match/pre_process.py +213 -0
- flowfile_worker/polars_fuzzy_match/process.py +86 -0
- flowfile_worker/polars_fuzzy_match/utils.py +50 -0
- flowfile_worker/process_manager.py +36 -0
- flowfile_worker/routes.py +440 -0
- flowfile_worker/secrets.py +148 -0
- flowfile_worker/spawner.py +187 -0
- flowfile_worker/utils.py +25 -0
- test_utils/__init__.py +3 -0
- test_utils/postgres/__init__.py +1 -0
- test_utils/postgres/commands.py +109 -0
- test_utils/postgres/fixtures.py +417 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
import time
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import AsyncGenerator
|
|
6
|
+
import aiofiles
|
|
7
|
+
from fastapi import APIRouter, HTTPException, Depends
|
|
8
|
+
from fastapi.responses import StreamingResponse
|
|
9
|
+
|
|
10
|
+
from flowfile_core import ServerRun
|
|
11
|
+
from flowfile_core import flow_file_handler
|
|
12
|
+
# Core modules
|
|
13
|
+
from flowfile_core.configs import logger
|
|
14
|
+
from flowfile_core.configs.flow_logger import clear_all_flow_logs
|
|
15
|
+
from flowfile_core.auth.jwt import get_current_active_user, get_current_user_from_query
|
|
16
|
+
|
|
17
|
+
# Schema and models
|
|
18
|
+
from flowfile_core.schemas import schemas
|
|
19
|
+
|
|
20
|
+
router = APIRouter()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@router.post("/clear-logs", tags=['flow_logging'])
|
|
24
|
+
async def clear_logs(current_user=Depends(get_current_active_user)):
|
|
25
|
+
clear_all_flow_logs()
|
|
26
|
+
return {"message": "All flow logs have been cleared."}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
async def format_sse_message(data: str) -> str:
|
|
30
|
+
"""Format the data as a proper SSE message"""
|
|
31
|
+
return f"data: {json.dumps(data)}\n\n"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@router.post("/logs/{flow_id}", tags=['flow_logging'])
|
|
35
|
+
async def add_log(flow_id: int, log_message: str):
|
|
36
|
+
"""
|
|
37
|
+
Adds a log message to the log file for a given flow_id.
|
|
38
|
+
"""
|
|
39
|
+
flow = flow_file_handler.get_flow(flow_id)
|
|
40
|
+
if not flow:
|
|
41
|
+
raise HTTPException(status_code=404, detail="Flow not found")
|
|
42
|
+
flow.flow_logger.info(log_message)
|
|
43
|
+
return {"message": "Log added successfully"}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@router.post("/raw_logs", tags=['flow_logging'])
|
|
47
|
+
async def add_raw_log(raw_log_input: schemas.RawLogInput):
|
|
48
|
+
"""
|
|
49
|
+
Adds a log message to the log file for a given flow_id.
|
|
50
|
+
"""
|
|
51
|
+
logger.info('Adding raw logs')
|
|
52
|
+
flow = flow_file_handler.get_flow(raw_log_input.flowfile_flow_id)
|
|
53
|
+
if not flow:
|
|
54
|
+
raise HTTPException(status_code=404, detail="Flow not found")
|
|
55
|
+
flow.flow_logger.get_log_filepath()
|
|
56
|
+
flow_logger = flow.flow_logger
|
|
57
|
+
flow_logger.get_log_filepath()
|
|
58
|
+
if raw_log_input.log_type == 'INFO':
|
|
59
|
+
flow_logger.info(raw_log_input.log_message,
|
|
60
|
+
extra=raw_log_input.extra)
|
|
61
|
+
elif raw_log_input.log_type == 'ERROR':
|
|
62
|
+
flow_logger.error(raw_log_input.log_message,
|
|
63
|
+
extra=raw_log_input.extra)
|
|
64
|
+
return {"message": "Log added successfully"}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
async def stream_log_file(
|
|
68
|
+
log_file_path: Path,
|
|
69
|
+
is_running_callable: callable,
|
|
70
|
+
idle_timeout: int = 60 # timeout in seconds
|
|
71
|
+
) -> AsyncGenerator[str, None]:
|
|
72
|
+
logger.info(f"Streaming log file: {log_file_path}")
|
|
73
|
+
last_active = time.monotonic()
|
|
74
|
+
try:
|
|
75
|
+
async with aiofiles.open(log_file_path, "r") as file:
|
|
76
|
+
|
|
77
|
+
# Ensure we start at the beginning
|
|
78
|
+
await file.seek(0)
|
|
79
|
+
while is_running_callable():
|
|
80
|
+
# Immediately check if shutdown has been triggered
|
|
81
|
+
if ServerRun.exit:
|
|
82
|
+
yield await format_sse_message("Server is shutting down. Closing connection.")
|
|
83
|
+
break
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
line = await file.readline()
|
|
87
|
+
if line:
|
|
88
|
+
formatted_message = await format_sse_message(line.strip())
|
|
89
|
+
logger.info(f'Yielding line: {line.strip()}')
|
|
90
|
+
yield formatted_message
|
|
91
|
+
last_active = time.monotonic() # Reset idle timer on activity
|
|
92
|
+
else:
|
|
93
|
+
# Check for idle timeout
|
|
94
|
+
if time.monotonic() - last_active > idle_timeout:
|
|
95
|
+
yield await format_sse_message("Connection timed out due to inactivity.")
|
|
96
|
+
break
|
|
97
|
+
# Allow the event loop to process other tasks (like signals)
|
|
98
|
+
await asyncio.sleep(0.1)
|
|
99
|
+
|
|
100
|
+
# Optionally, read any final lines
|
|
101
|
+
while True:
|
|
102
|
+
if ServerRun.exit:
|
|
103
|
+
break
|
|
104
|
+
line = await file.readline()
|
|
105
|
+
if not line:
|
|
106
|
+
break
|
|
107
|
+
yield await format_sse_message(line.strip())
|
|
108
|
+
|
|
109
|
+
logger.info("Streaming completed")
|
|
110
|
+
|
|
111
|
+
except FileNotFoundError:
|
|
112
|
+
error_msg = await format_sse_message(f"Log file not found: {log_file_path}")
|
|
113
|
+
yield error_msg
|
|
114
|
+
raise HTTPException(status_code=404, detail=f"Log file not found: {log_file_path}")
|
|
115
|
+
except Exception as e:
|
|
116
|
+
error_msg = await format_sse_message(f"Error reading log file: {str(e)}")
|
|
117
|
+
yield error_msg
|
|
118
|
+
raise HTTPException(status_code=500, detail=f"Error reading log file: {e}")
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@router.get("/logs/{flow_id}", tags=['flow_logging'])
|
|
122
|
+
async def stream_logs(
|
|
123
|
+
flow_id: int,
|
|
124
|
+
idle_timeout: int = 300,
|
|
125
|
+
current_user=Depends(get_current_user_from_query)
|
|
126
|
+
):
|
|
127
|
+
"""
|
|
128
|
+
Streams logs for a given flow_id using Server-Sent Events.
|
|
129
|
+
Requires authentication via token in query parameter.
|
|
130
|
+
The connection will close gracefully if the server shuts down.
|
|
131
|
+
"""
|
|
132
|
+
logger.info(f"Starting log stream for flow_id: {flow_id} by user: {current_user.username}")
|
|
133
|
+
await asyncio.sleep(.3)
|
|
134
|
+
flow = flow_file_handler.get_flow(flow_id)
|
|
135
|
+
logger.info('Streaming logs')
|
|
136
|
+
if not flow:
|
|
137
|
+
raise HTTPException(status_code=404, detail="Flow not found")
|
|
138
|
+
|
|
139
|
+
log_file_path = flow.flow_logger.get_log_filepath()
|
|
140
|
+
if not Path(log_file_path).exists():
|
|
141
|
+
raise HTTPException(status_code=404, detail="Log file not found")
|
|
142
|
+
|
|
143
|
+
class RunningState:
|
|
144
|
+
def __init__(self):
|
|
145
|
+
self.has_started = False
|
|
146
|
+
|
|
147
|
+
def is_running(self):
|
|
148
|
+
if flow.flow_settings.is_running:
|
|
149
|
+
self.has_started = True
|
|
150
|
+
return flow.flow_settings.is_running or not self.has_started
|
|
151
|
+
|
|
152
|
+
running_state = RunningState()
|
|
153
|
+
|
|
154
|
+
return StreamingResponse(
|
|
155
|
+
stream_log_file(log_file_path, running_state.is_running, idle_timeout),
|
|
156
|
+
media_type="text/event-stream",
|
|
157
|
+
headers={
|
|
158
|
+
"Cache-Control": "no-cache",
|
|
159
|
+
"Connection": "keep-alive",
|
|
160
|
+
"Content-Type": "text/event-stream",
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
|