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,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
+
@@ -0,0 +1,10 @@
1
+ from fastapi import APIRouter
2
+ from fastapi.responses import RedirectResponse
3
+
4
+ # Router setup
5
+ router = APIRouter()
6
+
7
+
8
+ @router.get("/", tags=['admin'])
9
+ async def docs_redirect():
10
+ return RedirectResponse(url='/docs')