ref: Add ruff rules TRY3xx (#4098)

Add ruff rules TRY3xx
This commit is contained in:
Christophe Bornet 2024-10-14 16:14:53 +02:00 • committed by GitHub
commit c7d80f3bc7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 680 additions and 562 deletions

View file

@ -54,9 +54,9 @@ def delete_api_key_route(
):
try:
delete_api_key(db, api_key_id)
return {"detail": "API Key deleted"}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e)) from e
return {"detail": "API Key deleted"}
@router.post("/store")
@ -88,10 +88,11 @@ def save_store_api_key(
domain=auth_settings.COOKIE_DOMAIN,
)
return {"detail": "API Key saved"}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e)) from e
return {"detail": "API Key saved"}
@router.delete("/store")
def delete_store_api_key(
@ -101,6 +102,7 @@ def delete_store_api_key(
try:
current_user.store_api_key = None
db.commit()
return {"detail": "API Key deleted"}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e)) from e
return {"detail": "API Key deleted"}

View file

@ -189,7 +189,6 @@ async def build_flow(
playgroundSuccess=True,
),
)
return first_layer, vertices_to_run, graph
except Exception as exc:
background_tasks.add_task(
telemetry_service.log_package_playground,
@ -205,6 +204,8 @@ async def build_flow(
logger.exception("Error checking build status")
raise HTTPException(status_code=500, detail=str(exc)) from exc
return first_layer, vertices_to_run, graph
async def _build_vertex(vertex_id: str, graph: Graph, event_manager: EventManager) -> VertexBuildResponse:
flow_id_str = str(flow_id)
@ -302,7 +303,6 @@ async def build_flow(
componentErrorMessage=error_message,
),
)
return build_response
except Exception as exc:
background_tasks.add_task(
telemetry_service.log_package_component,
@ -317,6 +317,8 @@ async def build_flow(
message = parse_exception(exc)
raise HTTPException(status_code=500, detail=message) from exc
return build_response
async def build_vertices(
vertex_id: str,
graph: Graph,
@ -588,7 +590,6 @@ async def build_vertex(
componentErrorMessage=error_message,
),
)
return build_response
except Exception as exc:
background_tasks.add_task(
telemetry_service.log_package_component,
@ -603,6 +604,90 @@ async def build_vertex(
message = parse_exception(exc)
raise HTTPException(status_code=500, detail=message) from exc
return build_response
async def _stream_vertex(flow_id: str, vertex_id: str, chat_service: ChatService):
graph = None
try:
try:
cache = await chat_service.get_cache(flow_id)
except Exception as exc: # noqa: BLE001
logger.exception("Error building Component")
yield str(StreamData(event="error", data={"error": str(exc)}))
return
if not cache:
# If there's no cache
msg = f"No cache found for {flow_id}."
logger.error(msg)
yield str(StreamData(event="error", data={"error": msg}))
return
else:
graph = cache.get("result")
try:
vertex: InterfaceVertex = graph.get_vertex(vertex_id)
except Exception as exc: # noqa: BLE001
logger.exception("Error building Component")
yield str(StreamData(event="error", data={"error": str(exc)}))
return
if not hasattr(vertex, "stream"):
msg = f"Vertex {vertex_id} does not support streaming"
logger.error(msg)
yield str(StreamData(event="error", data={"error": msg}))
return
if isinstance(vertex._built_result, str) and vertex._built_result:
stream_data = StreamData(
event="message",
data={"message": f"Streaming vertex {vertex_id}"},
)
yield str(stream_data)
stream_data = StreamData(
event="message",
data={"chunk": vertex._built_result},
)
yield str(stream_data)
elif not vertex.frozen or not vertex._built:
logger.debug(f"Streaming vertex {vertex_id}")
stream_data = StreamData(
event="message",
data={"message": f"Streaming vertex {vertex_id}"},
)
yield str(stream_data)
try:
async for chunk in vertex.stream():
stream_data = StreamData(
event="message",
data={"chunk": chunk},
)
yield str(stream_data)
except Exception as exc: # noqa: BLE001
logger.exception("Error building Component")
exc_message = parse_exception(exc)
if exc_message == "The message must be an iterator or an async iterator.":
exc_message = "This stream has already been closed."
yield str(StreamData(event="error", data={"error": exc_message}))
elif vertex.result is not None:
stream_data = StreamData(
event="message",
data={"chunk": vertex._built_result},
)
yield str(stream_data)
else:
msg = f"No result found for vertex {vertex_id}"
logger.error(msg)
yield str(StreamData(event="error", data={"error": msg}))
return
finally:
logger.debug("Closing stream")
if graph:
await chat_service.set_cache(flow_id, graph)
yield str(StreamData(event="close", data={"message": "Stream closed"}))
@router.get("/build/{flow_id}/{vertex_id}/stream", response_class=StreamingResponse)
async def build_vertex_stream(
@ -638,70 +723,6 @@ async def build_vertex_stream(
HTTPException: If an error occurs while building the vertex.
"""
try:
flow_id_str = str(flow_id)
async def stream_vertex():
graph = None
try:
cache = await chat_service.get_cache(flow_id_str)
if not cache:
# If there's no cache
msg = f"No cache found for {flow_id_str}."
raise ValueError(msg)
else:
graph = cache.get("result")
vertex: InterfaceVertex = graph.get_vertex(vertex_id)
if not hasattr(vertex, "stream"):
msg = f"Vertex {vertex_id} does not support streaming"
raise ValueError(msg)
if isinstance(vertex._built_result, str) and vertex._built_result:
stream_data = StreamData(
event="message",
data={"message": f"Streaming vertex {vertex_id}"},
)
yield str(stream_data)
stream_data = StreamData(
event="message",
data={"chunk": vertex._built_result},
)
yield str(stream_data)
elif not vertex.frozen or not vertex._built:
logger.debug(f"Streaming vertex {vertex_id}")
stream_data = StreamData(
event="message",
data={"message": f"Streaming vertex {vertex_id}"},
)
yield str(stream_data)
async for chunk in vertex.stream():
stream_data = StreamData(
event="message",
data={"chunk": chunk},
)
yield str(stream_data)
elif vertex.result is not None:
stream_data = StreamData(
event="message",
data={"chunk": vertex._built_result},
)
yield str(stream_data)
else:
msg = f"No result found for vertex {vertex_id}"
raise ValueError(msg)
except Exception as exc: # noqa: BLE001
logger.exception("Error building Component")
exc_message = parse_exception(exc)
if exc_message == "The message must be an iterator or an async iterator.":
exc_message = "This stream has already been closed."
yield str(StreamData(event="error", data={"error": exc_message}))
finally:
logger.debug("Closing stream")
if graph:
await chat_service.set_cache(flow_id_str, graph)
yield str(StreamData(event="close", data={"message": "Stream closed"}))
return StreamingResponse(stream_vertex(), media_type="text/event-stream")
return StreamingResponse(_stream_vertex(str(flow_id), vertex_id, chat_service), media_type="text/event-stream")
except Exception as exc:
raise HTTPException(status_code=500, detail="Error building Component") from exc

View file

@ -259,7 +259,6 @@ async def simplified_run_flow(
telemetry_service.log_package_run,
RunPayload(runIsWebhook=False, runSeconds=int(end_time - start_time), runSuccess=True, runErrorMessage=""),
)
return result
except ValueError as exc:
background_tasks.add_task(
@ -291,6 +290,8 @@ async def simplified_run_flow(
)
raise APIException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=exc, flow=flow) from exc
return result
@router.post("/webhook/{flow_id_or_name}", response_model=dict, status_code=HTTPStatus.ACCEPTED) # noqa: RUF100, FAST003
async def webhook_run_flow(
@ -316,58 +317,57 @@ async def webhook_run_flow(
Raises:
HTTPException: If the flow is not found or if there is an error processing the request.
"""
start_time = time.perf_counter()
logger.debug("Received webhook request")
error_msg = ""
try:
start_time = time.perf_counter()
logger.debug("Received webhook request")
data = await request.body()
try:
data = await request.body()
except Exception as exc:
error_msg = str(exc)
raise HTTPException(status_code=500, detail=error_msg) from exc
if not data:
logger.error("Request body is empty")
msg = "Request body is empty. You should provide a JSON payload containing the flow ID."
raise ValueError(
msg,
error_msg = "Request body is empty. You should provide a JSON payload containing the flow ID."
raise HTTPException(status_code=400, detail=error_msg)
try:
# get all webhook components in the flow
webhook_components = get_all_webhook_components_in_flow(flow.data)
tweaks = {}
for component in webhook_components:
tweaks[component["id"]] = {"data": data.decode() if isinstance(data, bytes) else data}
input_request = SimplifiedAPIRequest(
input_value="",
input_type="chat",
output_type="chat",
tweaks=tweaks,
session_id=None,
)
# get all webhook components in the flow
webhook_components = get_all_webhook_components_in_flow(flow.data)
tweaks = {}
for component in webhook_components:
tweaks[component["id"]] = {"data": data.decode() if isinstance(data, bytes) else data}
input_request = SimplifiedAPIRequest(
input_value="",
input_type="chat",
output_type="chat",
tweaks=tweaks,
session_id=None,
)
logger.debug("Starting background task")
background_tasks.add_task(
simple_run_flow_task,
flow=flow,
input_request=input_request,
api_key_user=user,
)
background_tasks.add_task(
telemetry_service.log_package_run,
RunPayload(
runIsWebhook=True, runSeconds=int(time.perf_counter() - start_time), runSuccess=True, runErrorMessage=""
),
)
return {"message": "Task started in the background", "status": "in progress"}
except Exception as exc:
logger.debug("Starting background task")
background_tasks.add_task(
simple_run_flow_task,
flow=flow,
input_request=input_request,
api_key_user=user,
)
except Exception as exc:
error_msg = str(exc)
raise HTTPException(status_code=500, detail=error_msg) from exc
finally:
background_tasks.add_task(
telemetry_service.log_package_run,
RunPayload(
runIsWebhook=True,
runSeconds=int(time.perf_counter() - start_time),
runSuccess=False,
runErrorMessage=str(exc),
runSuccess=error_msg == "",
runErrorMessage=error_msg,
),
)
if "Flow ID is required" in str(exc) or "Request body is empty" in str(exc):
raise HTTPException(status_code=400, detail=str(exc)) from exc
raise HTTPException(status_code=500, detail=str(exc)) from exc
return {"message": "Task started in the background", "status": "in progress"}
@router.post("/run/advanced/{flow_id}", response_model=RunResponse, response_model_exclude_none=True)
@ -429,35 +429,53 @@ async def experimental_run_flow(
This endpoint facilitates complex flow executions with customized inputs, outputs, and configurations,
catering to diverse application requirements.
""" # noqa: E501
try:
flow_id_str = str(flow_id)
if outputs is None:
outputs = []
if inputs is None:
inputs = [InputValueRequest(components=[], input_value="")]
flow_id_str = str(flow_id)
if outputs is None:
outputs = []
if inputs is None:
inputs = [InputValueRequest(components=[], input_value="")]
if session_id:
if session_id:
try:
session_data = await session_service.load_session(session_id, flow_id=flow_id_str)
graph, _artifacts = session_data or (None, None)
if graph is None:
msg = f"Session {session_id} not found"
raise ValueError(msg)
else:
except Exception as exc:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
graph, _artifacts = session_data or (None, None)
if graph is None:
msg = f"Session {session_id} not found"
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=msg)
else:
try:
# Get the flow that matches the flow_id and belongs to the user
# flow = session.query(Flow).filter(Flow.id == flow_id).filter(Flow.user_id == api_key_user.id).first()
flow = session.exec(
select(Flow).where(Flow.id == flow_id_str).where(Flow.user_id == api_key_user.id)
).first()
if flow is None:
msg = f"Flow {flow_id_str} not found"
raise ValueError(msg)
except sa.exc.StatementError as exc:
# StatementError('(builtins.ValueError) badly formed hexadecimal UUID string')
if "badly formed hexadecimal UUID string" in str(exc):
logger.error(f"Flow ID {flow_id_str} is not a valid UUID")
# This means the Flow ID is not a valid UUID which means it can't find the flow
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
except Exception as exc:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
if flow.data is None:
msg = f"Flow {flow_id_str} has no data"
raise ValueError(msg)
if flow is None:
msg = f"Flow {flow_id_str} not found"
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=msg)
if flow.data is None:
msg = f"Flow {flow_id_str} has no data"
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=msg)
try:
graph_data = flow.data
graph_data = process_tweaks(graph_data, tweaks or {})
graph = Graph.from_payload(graph_data, flow_id=flow_id_str)
except Exception as exc:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
try:
task_result, session_id = await run_graph_internal(
graph=graph,
flow_id=flow_id_str,
@ -466,25 +484,11 @@ async def experimental_run_flow(
outputs=outputs,
stream=stream,
)
return RunResponse(outputs=task_result, session_id=session_id)
except sa.exc.StatementError as exc:
# StatementError('(builtins.ValueError) badly formed hexadecimal UUID string')
if "badly formed hexadecimal UUID string" in str(exc):
logger.exception(f"Flow ID {flow_id_str} is not a valid UUID")
# This means the Flow ID is not a valid UUID which means it can't find the flow
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
except ValueError as exc:
if f"Flow {flow_id_str} not found" in str(exc):
logger.exception(f"Flow {flow_id_str} not found")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
if f"Session {session_id} not found" in str(exc):
logger.exception(f"Session {session_id} not found")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
except Exception as exc:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
return RunResponse(outputs=task_result, session_id=session_id)
@router.post(
"/predict/{flow_id}",
@ -639,12 +643,12 @@ async def custom_component_update(
field_value=code_request.field_value,
field_name=code_request.field,
)
component_node["template"] = updated_build_config
return component_node
except Exception as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
component_node["template"] = updated_build_config
return component_node
@router.get("/config", response_model=ConfigResponse)
def get_config():

View file

@ -47,16 +47,24 @@ async def upload_file(
):
try:
max_file_size_upload = get_storage_service().settings_service.settings.max_file_size_upload
if file.size > max_file_size_upload * 1024 * 1024:
raise HTTPException(
status_code=413, detail=f"File size is larger than the maximum file size {max_file_size_upload}MB."
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
if file.size > max_file_size_upload * 1024 * 1024:
raise HTTPException(
status_code=413, detail=f"File size is larger than the maximum file size {max_file_size_upload}MB."
)
try:
flow_id_str = str(flow_id)
flow = session.get(Flow, flow_id_str)
if flow.user_id != current_user.id:
raise HTTPException(status_code=403, detail="You don't have access to this flow")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
if flow.user_id != current_user.id:
raise HTTPException(status_code=403, detail="You don't have access to this flow")
try:
file_content = await file.read()
timestamp = datetime.now(tz=timezone.utc).astimezone().strftime("%Y-%m-%d_%H-%M-%S")
file_name = file.filename or hashlib.sha256(file_content).hexdigest()
@ -72,18 +80,20 @@ async def upload_file(
async def download_file(
file_name: str, flow_id: UUID, storage_service: Annotated[StorageService, Depends(get_storage_service)]
):
flow_id_str = str(flow_id)
extension = file_name.split(".")[-1]
if not extension:
raise HTTPException(status_code=500, detail=f"Extension not found for file {file_name}")
try:
flow_id_str = str(flow_id)
extension = file_name.split(".")[-1]
if not extension:
raise HTTPException(status_code=500, detail=f"Extension not found for file {file_name}")
content_type = build_content_type_from_extension(extension)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
if not content_type:
raise HTTPException(status_code=500, detail=f"Content type not found for extension {extension}")
if not content_type:
raise HTTPException(status_code=500, detail=f"Content type not found for extension {extension}")
try:
file_content = await storage_service.get_file(flow_id=flow_id_str, file_name=file_name)
headers = {
"Content-Disposition": f"attachment; filename={file_name} filename*=UTF-8''{file_name}",
@ -99,20 +109,22 @@ async def download_file(
async def download_image(
file_name: str, flow_id: UUID, storage_service: Annotated[StorageService, Depends(get_storage_service)]
):
extension = file_name.split(".")[-1]
flow_id_str = str(flow_id)
if not extension:
raise HTTPException(status_code=500, detail=f"Extension not found for file {file_name}")
try:
extension = file_name.split(".")[-1]
flow_id_str = str(flow_id)
if not extension:
raise HTTPException(status_code=500, detail=f"Extension not found for file {file_name}")
content_type = build_content_type_from_extension(extension)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
if not content_type:
raise HTTPException(status_code=500, detail=f"Content type not found for extension {extension}")
if not content_type.startswith("image"):
raise HTTPException(status_code=500, detail=f"Content type {content_type} is not an image")
if not content_type:
raise HTTPException(status_code=500, detail=f"Content type not found for extension {extension}")
if not content_type.startswith("image"):
raise HTTPException(status_code=500, detail=f"Content type {content_type} is not an image")
try:
file_content = await storage_service.get_file(flow_id=flow_id_str, file_name=file_name)
return StreamingResponse(BytesIO(file_content), media_type=content_type)
except Exception as e:
@ -150,14 +162,14 @@ async def list_profile_pictures(storage_service: Annotated[StorageService, Depen
people = await storage_service.list_files(flow_id=people_path) # type: ignore[arg-type]
space = await storage_service.list_files(flow_id=space_path) # type: ignore[arg-type]
files = [f"People/{i}" for i in people]
files += [f"Space/{i}" for i in space]
return {"files": files}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
files = [f"People/{i}" for i in people]
files += [f"Space/{i}" for i in space]
return {"files": files}
@router.get("/list/{flow_id}")
async def list_files(
@ -167,10 +179,11 @@ async def list_files(
try:
flow_id_str = str(flow_id)
files = await storage_service.list_files(flow_id=flow_id_str)
return {"files": files}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
return {"files": files}
@router.delete("/delete/{flow_id}/{file_name}")
async def delete_file(
@ -181,6 +194,7 @@ async def delete_file(
try:
flow_id_str = str(flow_id)
await storage_service.delete_file(flow_id=flow_id_str, file_name=file_name)
return {"message": f"File {file_name} deleted successfully"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
return {"message": f"File {file_name} deleted successfully"}

View file

@ -102,7 +102,6 @@ def create_flow(
session.add(db_flow)
session.commit()
session.refresh(db_flow)
return db_flow
except Exception as e:
# If it is a validation error, return the error message
if hasattr(e, "errors"):
@ -122,6 +121,8 @@ def create_flow(
raise
raise HTTPException(status_code=500, detail=str(e)) from e
return db_flow
@router.get("/", response_model=list[FlowRead] | Page[FlowRead] | list[FlowHeader], status_code=200)
def read_flows(
@ -199,13 +200,11 @@ def read_flows(
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/{flow_id}", response_model=FlowRead, status_code=200)
def read_flow(
*,
session: Session = Depends(get_session),
def _read_flow(
session: Session,
flow_id: UUID,
current_user: User = Depends(get_current_active_user),
settings_service: SettingsService = Depends(get_settings_service),
current_user: User,
settings_service: SettingsService,
):
"""Read a flow."""
auth_settings = settings_service.auth_settings
@ -216,7 +215,19 @@ def read_flow(
stmt = stmt.where(
(Flow.user_id == current_user.id) | (Flow.user_id == None) # noqa: E711
)
if user_flow := session.exec(stmt).first():
return session.exec(stmt).first()
@router.get("/{flow_id}", response_model=FlowRead, status_code=200)
def read_flow(
*,
session: Session = Depends(get_session),
flow_id: UUID,
current_user: User = Depends(get_current_active_user),
settings_service: SettingsService = Depends(get_settings_service),
):
"""Read a flow."""
if user_flow := _read_flow(session, flow_id, current_user, settings_service):
return user_flow
raise HTTPException(status_code=404, detail="Flow not found")
@ -232,14 +243,19 @@ def update_flow(
):
"""Update a flow."""
try:
db_flow = read_flow(
db_flow = _read_flow(
session=session,
flow_id=flow_id,
current_user=current_user,
settings_service=settings_service,
)
if not db_flow:
raise HTTPException(status_code=404, detail="Flow not found")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
if not db_flow:
raise HTTPException(status_code=404, detail="Flow not found")
try:
flow_data = flow.model_dump(exclude_unset=True)
if settings_service.settings.remove_api_keys:
flow_data = remove_api_keys(flow_data)
@ -256,7 +272,6 @@ def update_flow(
session.add(db_flow)
session.commit()
session.refresh(db_flow)
return db_flow
except Exception as e:
# If it is a validation error, return the error message
if hasattr(e, "errors"):
@ -272,10 +287,10 @@ def update_flow(
raise HTTPException(
status_code=400, detail=f"{column.capitalize().replace('_', ' ')} must be unique"
) from e
if isinstance(e, HTTPException):
raise
raise HTTPException(status_code=500, detail=str(e)) from e
return db_flow
@router.delete("/{flow_id}", status_code=200)
async def delete_flow(
@ -286,7 +301,7 @@ async def delete_flow(
settings_service=Depends(get_settings_service),
):
"""Delete a flow."""
flow = read_flow(
flow = _read_flow(
session=session,
flow_id=flow_id,
current_user=current_user,

View file

@ -75,10 +75,11 @@ def create_folder(
session.exec(update_statement_flows)
session.commit()
return new_folder
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
return new_folder
@router.get("/", response_model=list[FolderRead], status_code=200)
def read_folders(
@ -111,9 +112,15 @@ def read_folder(
):
try:
folder = session.exec(select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)).first()
if not folder:
raise HTTPException(status_code=404, detail="Folder not found")
except Exception as e:
if "No result found" in str(e):
raise HTTPException(status_code=404, detail="Folder not found") from e
raise HTTPException(status_code=500, detail=str(e)) from e
if not folder:
raise HTTPException(status_code=404, detail="Folder not found")
try:
stmt = select(Flow).where(Flow.folder_id == folder_id, Flow.user_id == current_user.id)
if Flow.updated_at is not None:
@ -128,8 +135,6 @@ def read_folder(
return FolderWithPaginatedFlows(folder=FolderRead.model_validate(folder), flows=paginated_flows)
except Exception as e:
if "No result found" in str(e):
raise HTTPException(status_code=404, detail="Folder not found") from e
raise HTTPException(status_code=500, detail=str(e)) from e
@ -145,8 +150,13 @@ def update_folder(
existing_folder = session.exec(
select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)
).first()
if not existing_folder:
raise HTTPException(status_code=404, detail="Folder not found")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
if not existing_folder:
raise HTTPException(status_code=404, detail="Folder not found")
try:
if folder.name and folder.name != existing_folder.name:
existing_folder.name = folder.name
session.add(existing_folder)
@ -183,11 +193,11 @@ def update_folder(
session.exec(update_statement_components)
session.commit()
return existing_folder
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
return existing_folder
@router.delete("/{folder_id}", status_code=204)
async def delete_folder(
@ -203,11 +213,15 @@ async def delete_folder(
await cascade_delete_flow(session, flow)
folder = session.exec(select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)).first()
if not folder:
raise HTTPException(status_code=404, detail="Folder not found")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
if not folder:
raise HTTPException(status_code=404, detail="Folder not found")
try:
session.delete(folder)
session.commit()
return Response(status_code=status.HTTP_204_NO_CONTENT)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
@ -222,12 +236,17 @@ async def download_file(
):
"""Download all flows from folder."""
try:
return session.exec(select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)).first()
folder = session.exec(select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)).first()
except Exception as e:
if "No result found" in str(e):
raise HTTPException(status_code=404, detail="Folder not found") from e
raise HTTPException(status_code=500, detail=str(e)) from e
if not folder:
raise HTTPException(status_code=404, detail="Folder not found")
return folder
@router.post("/upload/", response_model=list[FlowRead], status_code=201)
async def upload_file(

View file

@ -94,19 +94,23 @@ async def update_message(
):
try:
db_message = session.get(MessageTable, message_id)
if not db_message:
raise HTTPException(status_code=404, detail="Message not found")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
if not db_message:
raise HTTPException(status_code=404, detail="Message not found")
try:
message_dict = message.model_dump(exclude_unset=True, exclude_none=True)
db_message.sqlmodel_update(message_dict)
session.add(db_message)
session.commit()
session.refresh(db_message)
return db_message
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
return db_message
@router.patch("/messages/session/{old_session_id}", response_model=list[MessageResponse])
async def update_session_id(
@ -119,10 +123,13 @@ async def update_session_id(
# Get all messages with the old session ID
stmt = select(MessageTable).where(MessageTable.session_id == old_session_id)
messages = session.exec(stmt).all()
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
if not messages:
raise HTTPException(status_code=404, detail="No messages found with the given session ID")
if not messages:
raise HTTPException(status_code=404, detail="No messages found with the given session ID")
try:
# Update all messages with the new session ID
for message in messages:
message.session_id = new_session_id
@ -134,12 +141,11 @@ async def update_session_id(
for message in messages:
session.refresh(message)
message_responses.append(MessageResponse.model_validate(message, from_attributes=True))
return message_responses
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
return message_responses
@router.delete("/messages/session/{session_id}", status_code=204)
async def delete_messages_session(
@ -153,10 +159,11 @@ async def delete_messages_session(
.execution_options(synchronize_session="fetch")
)
session.commit()
return {"message": "Messages deleted successfully"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
return {"message": "Messages deleted successfully"}
@router.get("/transactions", response_model=list[TransactionReadResponse])
async def get_transactions(

View file

@ -25,19 +25,18 @@ def create_variable(
variable_service: DatabaseVariableService = Depends(get_variable_service),
):
"""Create a new variable."""
if not variable.name and not variable.value:
raise HTTPException(status_code=400, detail="Variable name and value cannot be empty")
if not variable.name:
raise HTTPException(status_code=400, detail="Variable name cannot be empty")
if not variable.value:
raise HTTPException(status_code=400, detail="Variable value cannot be empty")
if variable.name in variable_service.list_variables(user_id=current_user.id, session=session):
raise HTTPException(status_code=400, detail="Variable name already exists")
try:
if not variable.name and not variable.value:
raise HTTPException(status_code=400, detail="Variable name and value cannot be empty")
if not variable.name:
raise HTTPException(status_code=400, detail="Variable name cannot be empty")
if not variable.value:
raise HTTPException(status_code=400, detail="Variable value cannot be empty")
if variable.name in variable_service.list_variables(user_id=current_user.id, session=session):
raise HTTPException(status_code=400, detail="Variable name already exists")
return variable_service.create_variable(
user_id=current_user.id,
name=variable.name,

View file

@ -82,12 +82,13 @@ class LCModelComponent(Component):
message = runnable.invoke(input_value)
result = message.content if hasattr(message, "content") else message
self.status = result
return result
except Exception as e:
if message := self._get_exception_message(e):
raise ValueError(message) from e
raise
return result
def build_status_message(self, message: AIMessage):
"""
Builds a status message from an AIMessage object.
@ -194,12 +195,13 @@ class LCModelComponent(Component):
self.status = result
else:
self.status = result
return result
except Exception as e:
if message := self._get_exception_message(e):
raise ValueError(message) from e
raise
return result
@abstractmethod
def build_model(self) -> LanguageModel: # type: ignore[type-var]
"""

View file

@ -96,7 +96,7 @@ class AddContentToPage(LCToolComponent):
heading_level = text.count("#", 0, 6)
heading_text = text[heading_level:].strip()
if heading_level in range(3):
blocks.append(self.create_block(f"heading_{heading_level+1}", heading_text))
blocks.append(self.create_block(f"heading_{heading_level + 1}", heading_text))
else:
blocks.append(self.create_block("paragraph", text))
elif node.name == "h1":

View file

@ -92,7 +92,6 @@ class NotionPageUpdate(LCToolComponent):
updated_page = response.json()
logger.info(f"Successfully updated Notion page. Response: {json.dumps(updated_page)}")
return updated_page
except requests.exceptions.HTTPError as e:
error_message = f"HTTP Error occurred: {e}"
if e.response is not None:
@ -109,5 +108,7 @@ class NotionPageUpdate(LCToolComponent):
logger.exception(error_message)
return error_message
return updated_page
def __call__(self, *args, **kwargs):
return self._update_notion_page(*args, **kwargs)

View file

@ -132,15 +132,16 @@ class AssemblyAILeMUR(Component):
# Perform LeMUR action
try:
response = self.perform_lemur_action(transcript_group, self.endpoint)
result = Data(data=response)
self.status = result
return result
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error running LeMUR")
error = f"An Error happened: {e}"
self.status = error
return Data(data={"error": error})
result = Data(data=response)
self.status = result
return result
def perform_lemur_action(self, transcript_group: aai.TranscriptGroup, endpoint: str) -> dict:
logger.info("Endpoint:", endpoint, type(endpoint))
if endpoint == "task":

View file

@ -84,10 +84,11 @@ class AssemblyAIListTranscripts(Component):
page = transcriber.list_transcripts(params)
transcripts = convert_page_to_data_list(page)
self.status = transcripts
return transcripts
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error listing transcripts")
error_data = Data(data={"error": f"An error occurred: {e}"})
self.status = [error_data]
return [error_data]
self.status = transcripts
return transcripts

View file

@ -173,14 +173,14 @@ class AssemblyAITranscriptionJobCreator(Component):
try:
transcript = aai.Transcriber().submit(audio, config=config)
if transcript.error:
self.status = transcript.error
return Data(data={"error": transcript.error})
result = Data(data={"transcript_id": transcript.id})
self.status = result
return result
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error submitting transcription job")
self.status = f"An error occurred: {e}"
return Data(data={"error": f"An error occurred: {e}"})
if transcript.error:
self.status = transcript.error
return Data(data={"error": transcript.error})
result = Data(data={"transcript_id": transcript.id})
self.status = result
return result

View file

@ -46,27 +46,27 @@ class MergeDataComponent(Component):
"""
logger.info("Initiating the data merging process.")
data_inputs: list[Data] = self.data_inputs
logger.debug(f"Received {len(data_inputs)} data input(s) for merging.")
if not data_inputs:
logger.warning("No data inputs provided. Returning an empty list.")
return []
# Collect all unique keys from all Data objects
all_keys: set[str] = set()
for idx, data_input in enumerate(data_inputs):
if not isinstance(data_input, Data):
error_message = f"Data input at index {idx} is not of type Data."
logger.error(error_message)
type_error_message = (
f"All items in data_inputs must be of type Data. Item at index {idx} is {type(data_input)}"
)
raise TypeError(type_error_message)
all_keys.update(data_input.data.keys())
logger.debug(f"Collected {len(all_keys)} unique key(s) from input data.")
try:
data_inputs: list[Data] = self.data_inputs
logger.debug(f"Received {len(data_inputs)} data input(s) for merging.")
if not data_inputs:
logger.warning("No data inputs provided. Returning an empty list.")
return []
# Collect all unique keys from all Data objects
all_keys: set[str] = set()
for idx, data_input in enumerate(data_inputs):
if not isinstance(data_input, Data):
error_message = f"Data input at index {idx} is not of type Data."
logger.error(error_message)
type_error_message = (
"All items in data_inputs must be of type Data. " f"Item at index {idx} is {type(data_input)}"
)
raise TypeError(type_error_message)
all_keys.update(data_input.data.keys())
logger.debug(f"Collected {len(all_keys)} unique key(s) from input data.")
# Create new list of Data objects with missing keys filled with empty strings
merged_data_list = []
for idx, data_input in enumerate(data_inputs):
@ -86,9 +86,9 @@ class MergeDataComponent(Component):
merged_data_list.append(merged_data)
logger.debug(f"Merged Data object created for input at index {idx}.")
logger.info("Data merging process completed successfully.")
return merged_data_list
except Exception:
logger.exception("An error occurred during the data merging process.")
raise
logger.info("Data merging process completed successfully.")
return merged_data_list

View file

@ -46,16 +46,21 @@ class SubFlowComponent(CustomComponent):
if field_value is not None and field_name == "flow_name":
try:
flow_data = self.get_flow(field_value)
if not flow_data:
msg = f"Flow {field_value} not found."
raise ValueError(msg)
graph = Graph.from_payload(flow_data.data["data"])
# Get all inputs from the graph
inputs = get_flow_inputs(graph)
# Add inputs to the build config
build_config = self.add_inputs_to_build_config(inputs, build_config)
except Exception: # noqa: BLE001
logger.exception(f"Error getting flow {field_value}")
else:
if not flow_data:
msg = f"Flow {field_value} not found."
logger.error(msg)
else:
try:
graph = Graph.from_payload(flow_data.data["data"])
# Get all inputs from the graph
inputs = get_flow_inputs(graph)
# Add inputs to the build config
build_config = self.add_inputs_to_build_config(inputs, build_config)
except Exception: # noqa: BLE001
logger.exception(f"Error building graph for flow {field_value}")
return build_config

View file

@ -38,46 +38,42 @@ class CSVToDataComponent(Component):
]
def load_csv_to_data(self) -> list[Data]:
if sum(bool(field) for field in [self.csv_file, self.csv_path, self.csv_string]) != 1:
msg = "Please provide exactly one of: CSV file, file path, or CSV string."
raise ValueError(msg)
csv_data = None
try:
if sum(bool(field) for field in [self.csv_file, self.csv_path, self.csv_string]) != 1:
msg = "Please provide exactly one of: CSV file, file path, or CSV string."
raise ValueError(msg)
csv_data = None
if self.csv_file:
resolved_path = self.resolve_path(self.csv_file)
file_path = Path(resolved_path)
if file_path.suffix.lower() != ".csv":
msg = "The provided file must be a CSV file."
raise ValueError(msg)
with file_path.open(newline="", encoding="utf-8") as csvfile:
csv_data = csvfile.read()
self.status = "The provided file must be a CSV file."
else:
with file_path.open(newline="", encoding="utf-8") as csvfile:
csv_data = csvfile.read()
elif self.csv_path:
file_path = Path(self.csv_path)
if file_path.suffix.lower() != ".csv":
msg = "The provided file must be a CSV file."
raise ValueError(msg)
with file_path.open(newline="", encoding="utf-8") as csvfile:
csv_data = csvfile.read()
self.status = "The provided file must be a CSV file."
else:
with file_path.open(newline="", encoding="utf-8") as csvfile:
csv_data = csvfile.read()
elif self.csv_string:
else:
csv_data = self.csv_string
if not csv_data:
msg = "No CSV data provided."
raise ValueError(msg)
if csv_data:
csv_reader = csv.DictReader(io.StringIO(csv_data))
result = [Data(data=row) for row in csv_reader]
csv_reader = csv.DictReader(io.StringIO(csv_data))
result = [Data(data=row) for row in csv_reader]
if not result:
self.status = "The CSV data is empty."
return []
if not result:
self.status = "The CSV data is empty."
return []
self.status = result
return result
self.status = result
return result
except csv.Error as e:
error_message = f"CSV parsing error: {e}"
@ -88,3 +84,6 @@ class CSVToDataComponent(Component):
error_message = f"An error occurred: {e}"
self.status = error_message
raise ValueError(error_message) from e
# An error occurred
raise ValueError(self.status)

View file

@ -41,53 +41,50 @@ class JSONToDataComponent(Component):
]
def convert_json_to_data(self) -> Data | list[Data]:
if sum(bool(field) for field in [self.json_file, self.json_path, self.json_string]) != 1:
msg = "Please provide exactly one of: JSON file, file path, or JSON string."
self.status = msg
raise ValueError(msg)
json_data = None
try:
if sum(bool(field) for field in [self.json_file, self.json_path, self.json_string]) != 1:
msg = "Please provide exactly one of: JSON file, file path, or JSON string."
raise ValueError(msg)
json_data = None
if self.json_file:
resolved_path = self.resolve_path(self.json_file)
file_path = Path(resolved_path)
if file_path.suffix.lower() != ".json":
msg = "The provided file must be a JSON file."
raise ValueError(msg)
with file_path.open(encoding="utf-8") as jsonfile:
json_data = jsonfile.read()
self.status = "The provided file must be a JSON file."
else:
with file_path.open(encoding="utf-8") as jsonfile:
json_data = jsonfile.read()
elif self.json_path:
file_path = Path(self.json_path)
if file_path.suffix.lower() != ".json":
msg = "The provided file must be a JSON file."
raise ValueError(msg)
with file_path.open(encoding="utf-8") as jsonfile:
json_data = jsonfile.read()
self.status = "The provided file must be a JSON file."
else:
with file_path.open(encoding="utf-8") as jsonfile:
json_data = jsonfile.read()
elif self.json_string:
else:
json_data = self.json_string
if not json_data:
msg = "No JSON data provided."
raise ValueError(msg)
if json_data:
# Try to parse the JSON string
try:
parsed_data = json.loads(json_data)
except json.JSONDecodeError:
# If JSON parsing fails, try to repair the JSON string
repaired_json_string = repair_json(json_data)
parsed_data = json.loads(repaired_json_string)
# Try to parse the JSON string
try:
parsed_data = json.loads(json_data)
except json.JSONDecodeError:
# If JSON parsing fails, try to repair the JSON string
repaired_json_string = repair_json(json_data)
parsed_data = json.loads(repaired_json_string)
# Check if the parsed data is a list
if isinstance(parsed_data, list):
result = [Data(data=item) for item in parsed_data]
else:
result = Data(data=parsed_data)
self.status = result
return result
# Check if the parsed data is a list
if isinstance(parsed_data, list):
result = [Data(data=item) for item in parsed_data]
else:
result = Data(data=parsed_data)
self.status = result
return result
except (json.JSONDecodeError, SyntaxError, ValueError) as e:
error_message = f"Invalid JSON or Python literal: {e}"
@ -98,3 +95,6 @@ class JSONToDataComponent(Component):
error_message = f"An error occurred: {e}"
self.status = error_message
raise ValueError(error_message) from e
# An error occurred
raise ValueError(self.status)

View file

@ -46,27 +46,27 @@ class MergeDataComponent(Component):
"""
logger.info("Initiating the data merging process.")
data_inputs: list[Data] = self.data_inputs
logger.debug(f"Received {len(data_inputs)} data input(s) for merging.")
if not data_inputs:
logger.warning("No data inputs provided. Returning an empty list.")
return []
# Collect all unique keys from all Data objects
all_keys: set[str] = set()
for idx, data_input in enumerate(data_inputs):
if not isinstance(data_input, Data):
error_message = f"Data input at index {idx} is not of type Data."
logger.error(error_message)
type_error_message = (
f"All items in data_inputs must be of type Data. Item at index {idx} is {type(data_input)}"
)
raise TypeError(type_error_message)
all_keys.update(data_input.data.keys())
logger.debug(f"Collected {len(all_keys)} unique key(s) from input data.")
try:
data_inputs: list[Data] = self.data_inputs
logger.debug(f"Received {len(data_inputs)} data input(s) for merging.")
if not data_inputs:
logger.warning("No data inputs provided. Returning an empty list.")
return []
# Collect all unique keys from all Data objects
all_keys: set[str] = set()
for idx, data_input in enumerate(data_inputs):
if not isinstance(data_input, Data):
error_message = f"Data input at index {idx} is not of type Data."
logger.error(error_message)
type_error_message = (
"All items in data_inputs must be of type Data. " f"Item at index {idx} is {type(data_input)}"
)
raise TypeError(type_error_message)
all_keys.update(data_input.data.keys())
logger.debug(f"Collected {len(all_keys)} unique key(s) from input data.")
# Create new list of Data objects with missing keys filled with empty strings
merged_data_list = []
for idx, data_input in enumerate(data_inputs):
@ -86,9 +86,9 @@ class MergeDataComponent(Component):
merged_data_list.append(merged_data)
logger.debug("Merged Data object created for input at index: " + str(idx))
logger.info("Data merging process completed successfully.")
return merged_data_list
except Exception:
logger.exception("An error occurred during the data merging process.")
raise
logger.info("Data merging process completed successfully.")
return merged_data_list

View file

@ -26,18 +26,14 @@ class MessageToDataComponent(Component):
]
def convert_message_to_data(self) -> Data:
try:
if not isinstance(self.message, Message):
msg = "Input must be a Message object"
raise TypeError(msg)
if isinstance(self.message, Message):
# Convert Message to Data
data = Data(data=self.message.data)
self.status = "Successfully converted Message to Data"
return data
except Exception as e: # noqa: BLE001
error_message = f"Error converting Message to Data: {e}"
logger.opt(exception=True).debug(error_message)
self.status = error_message
return Data(data={"error": error_message})
msg = "Error converting Message to Data: Input must be a Message object"
logger.opt(exception=True).debug(msg)
self.status = msg
return Data(data={"error": msg})

Some files were not shown because too many files have changed in this diff Show more