consolidate the retry mechanism into the handle_http_errors decorator, mitigates idempotency risks by limiting retries to read-only operations
This commit is contained in:
@@ -10,28 +10,14 @@ import functools
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from googleapiclient.errors import HttpError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def retry_on_ssl_error(max_retries=3, base_delay=1):
|
||||
"""
|
||||
A decorator to retry a function call on ssl.SSLError with exponential backoff.
|
||||
"""
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
async def wrapper(*args, **kwargs):
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return await func(*args, **kwargs)
|
||||
except ssl.SSLError as e:
|
||||
if attempt < max_retries - 1:
|
||||
delay = base_delay * (2 ** attempt)
|
||||
logger.warning(f"SSL error in {func.__name__} on attempt {attempt + 1}: {e}. Retrying in {delay} seconds...")
|
||||
await asyncio.sleep(delay)
|
||||
else:
|
||||
logger.error(f"SSL error in {func.__name__} on final attempt: {e}. Raising exception.")
|
||||
raise
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
class TransientNetworkError(Exception):
|
||||
"""Custom exception for transient network errors after retries."""
|
||||
pass
|
||||
|
||||
|
||||
def check_credentials_directory_permissions(credentials_dir: str = None) -> None:
|
||||
@@ -186,38 +172,57 @@ def extract_office_xml_text(file_bytes: bytes, mime_type: str) -> Optional[str]:
|
||||
logger.error(f"Failed to extract office XML text for {mime_type}: {e}", exc_info=True)
|
||||
return None
|
||||
|
||||
import functools
|
||||
from googleapiclient.errors import HttpError
|
||||
|
||||
def handle_http_errors(tool_name: str):
|
||||
def handle_http_errors(tool_name: str, is_read_only: bool = False):
|
||||
"""
|
||||
A decorator to handle Google API HttpErrors in a standardized way.
|
||||
A decorator to handle Google API HttpErrors and transient SSL errors in a standardized way.
|
||||
|
||||
It wraps a tool function, catches HttpError, logs a detailed error message,
|
||||
and raises a generic Exception with a user-friendly message.
|
||||
|
||||
If is_read_only is True, it will also catch ssl.SSLError and retry with
|
||||
exponential backoff. After exhausting retries, it raises a TransientNetworkError.
|
||||
|
||||
Args:
|
||||
tool_name (str): The name of the tool being decorated (e.g., 'list_calendars').
|
||||
This is used for logging purposes.
|
||||
is_read_only (bool): If True, the operation is considered safe to retry on
|
||||
transient network errors. Defaults to False.
|
||||
"""
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
async def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return await func(*args, **kwargs)
|
||||
except HttpError as error:
|
||||
user_google_email = kwargs.get('user_google_email', 'N/A')
|
||||
message = (
|
||||
f"API error in {tool_name}: {error}. "
|
||||
f"You might need to re-authenticate for user '{user_google_email}'. "
|
||||
f"LLM: Try 'start_google_auth' with the user's email and the appropriate service_name."
|
||||
)
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message)
|
||||
except Exception as e:
|
||||
# Catch any other unexpected errors
|
||||
message = f"An unexpected error occurred in {tool_name}: {e}"
|
||||
logger.exception(message)
|
||||
raise Exception(message)
|
||||
max_retries = 3
|
||||
base_delay = 1
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return await func(*args, **kwargs)
|
||||
except ssl.SSLError as e:
|
||||
if is_read_only and attempt < max_retries - 1:
|
||||
delay = base_delay * (2 ** attempt)
|
||||
logger.warning(f"SSL error in {tool_name} on attempt {attempt + 1}: {e}. Retrying in {delay} seconds...")
|
||||
await asyncio.sleep(delay)
|
||||
else:
|
||||
logger.error(f"SSL error in {tool_name} on final attempt: {e}. Raising exception.")
|
||||
raise TransientNetworkError(
|
||||
f"A transient SSL error occurred in '{tool_name}' after {max_retries} attempts. "
|
||||
"This is likely a temporary network or certificate issue. Please try again shortly."
|
||||
) from e
|
||||
except HttpError as error:
|
||||
user_google_email = kwargs.get('user_google_email', 'N/A')
|
||||
message = (
|
||||
f"API error in {tool_name}: {error}. "
|
||||
f"You might need to re-authenticate for user '{user_google_email}'. "
|
||||
f"LLM: Try 'start_google_auth' with the user's email and the appropriate service_name."
|
||||
)
|
||||
logger.error(message, exc_info=True)
|
||||
raise Exception(message) from error
|
||||
except TransientNetworkError:
|
||||
# Re-raise without wrapping to preserve the specific error type
|
||||
raise
|
||||
except Exception as e:
|
||||
# Catch any other unexpected errors
|
||||
message = f"An unexpected error occurred in {tool_name}: {e}"
|
||||
logger.exception(message)
|
||||
raise Exception(message) from e
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@@ -15,7 +15,7 @@ from googleapiclient.errors import HttpError
|
||||
from googleapiclient.discovery import build
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.utils import handle_http_errors, retry_on_ssl_error
|
||||
from core.utils import handle_http_errors
|
||||
|
||||
from core.server import server
|
||||
|
||||
@@ -80,9 +80,8 @@ def _correct_time_format_for_api(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("list_calendars", is_read_only=True)
|
||||
@require_google_service("calendar", "calendar_read")
|
||||
@handle_http_errors("list_calendars")
|
||||
@retry_on_ssl_error()
|
||||
async def list_calendars(service, user_google_email: str) -> str:
|
||||
"""
|
||||
Retrieves a list of calendars accessible to the authenticated user.
|
||||
@@ -115,9 +114,8 @@ async def list_calendars(service, user_google_email: str) -> str:
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_events", is_read_only=True)
|
||||
@require_google_service("calendar", "calendar_read")
|
||||
@handle_http_errors("get_events")
|
||||
@retry_on_ssl_error()
|
||||
async def get_events(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -204,9 +202,8 @@ async def get_events(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("calendar", "calendar_events")
|
||||
@handle_http_errors("create_event")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("calendar", "calendar_events")
|
||||
async def create_event(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -329,9 +326,8 @@ async def create_event(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("calendar", "calendar_events")
|
||||
@handle_http_errors("modify_event")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("calendar", "calendar_events")
|
||||
async def modify_event(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -450,9 +446,8 @@ async def modify_event(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("calendar", "calendar_events")
|
||||
@handle_http_errors("delete_event")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("calendar", "calendar_events")
|
||||
async def delete_event(service, user_google_email: str, event_id: str, calendar_id: str = "primary") -> str:
|
||||
"""
|
||||
Deletes an existing event.
|
||||
@@ -505,9 +500,8 @@ async def delete_event(service, user_google_email: str, event_id: str, calendar_
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_event", is_read_only=True)
|
||||
@require_google_service("calendar", "calendar_read")
|
||||
@handle_http_errors("get_event")
|
||||
@retry_on_ssl_error()
|
||||
async def get_event(
|
||||
service,
|
||||
user_google_email: str,
|
||||
|
||||
@@ -13,16 +13,15 @@ from googleapiclient.http import MediaIoBaseDownload
|
||||
|
||||
# Auth & server utilities
|
||||
from auth.service_decorator import require_google_service, require_multiple_services
|
||||
from core.utils import extract_office_xml_text, handle_http_errors, retry_on_ssl_error
|
||||
from core.utils import extract_office_xml_text, handle_http_errors
|
||||
from core.server import server
|
||||
from core.comments import create_comment_tools
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("search_docs", is_read_only=True)
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("search_docs")
|
||||
@retry_on_ssl_error()
|
||||
async def search_docs(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -58,12 +57,11 @@ async def search_docs(
|
||||
return "\n".join(output)
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_doc_content", is_read_only=True)
|
||||
@require_multiple_services([
|
||||
{"service_type": "drive", "scopes": "drive_read", "param_name": "drive_service"},
|
||||
{"service_type": "docs", "scopes": "docs_read", "param_name": "docs_service"}
|
||||
])
|
||||
@handle_http_errors("get_doc_content")
|
||||
@retry_on_ssl_error()
|
||||
async def get_doc_content(
|
||||
drive_service,
|
||||
docs_service,
|
||||
@@ -159,9 +157,8 @@ async def get_doc_content(
|
||||
return header + body_text
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("list_docs_in_folder", is_read_only=True)
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("list_docs_in_folder")
|
||||
@retry_on_ssl_error()
|
||||
async def list_docs_in_folder(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -192,9 +189,8 @@ async def list_docs_in_folder(
|
||||
return "\n".join(out)
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("docs", "docs_write")
|
||||
@handle_http_errors("create_doc")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("docs", "docs_write")
|
||||
async def create_doc(
|
||||
service,
|
||||
user_google_email: str,
|
||||
|
||||
@@ -15,7 +15,7 @@ import io
|
||||
import httpx
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.utils import extract_office_xml_text, handle_http_errors, retry_on_ssl_error
|
||||
from core.utils import extract_office_xml_text, handle_http_errors
|
||||
from core.server import server
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -76,9 +76,8 @@ def _build_drive_list_params(
|
||||
return list_params
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("search_drive_files", is_read_only=True)
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("search_drive_files")
|
||||
@retry_on_ssl_error()
|
||||
async def search_drive_files(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -144,9 +143,8 @@ async def search_drive_files(
|
||||
return text_output
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_drive_file_content", is_read_only=True)
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("get_drive_file_content")
|
||||
@retry_on_ssl_error()
|
||||
async def get_drive_file_content(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -235,9 +233,8 @@ async def get_drive_file_content(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("list_drive_items", is_read_only=True)
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("list_drive_items")
|
||||
@retry_on_ssl_error()
|
||||
async def list_drive_items(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -292,9 +289,8 @@ async def list_drive_items(
|
||||
return text_output
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("drive", "drive_file")
|
||||
@handle_http_errors("create_drive_file")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("drive", "drive_file")
|
||||
async def create_drive_file(
|
||||
service,
|
||||
user_google_email: str,
|
||||
|
||||
@@ -12,15 +12,14 @@ from mcp import types
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.server import server
|
||||
from core.utils import handle_http_errors, retry_on_ssl_error
|
||||
from core.utils import handle_http_errors
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("forms", "forms")
|
||||
@handle_http_errors("create_form")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("forms", "forms")
|
||||
async def create_form(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -68,9 +67,8 @@ async def create_form(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_form", is_read_only=True)
|
||||
@require_google_service("forms", "forms")
|
||||
@handle_http_errors("get_form")
|
||||
@retry_on_ssl_error()
|
||||
async def get_form(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -125,9 +123,8 @@ async def get_form(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("forms", "forms")
|
||||
@handle_http_errors("set_publish_settings")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("forms", "forms")
|
||||
async def set_publish_settings(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -164,9 +161,8 @@ async def set_publish_settings(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_form_response", is_read_only=True)
|
||||
@require_google_service("forms", "forms")
|
||||
@handle_http_errors("get_form_response")
|
||||
@retry_on_ssl_error()
|
||||
async def get_form_response(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -219,9 +215,8 @@ async def get_form_response(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("list_form_responses", is_read_only=True)
|
||||
@require_google_service("forms", "forms")
|
||||
@handle_http_errors("list_form_responses")
|
||||
@retry_on_ssl_error()
|
||||
async def list_form_responses(
|
||||
service,
|
||||
user_google_email: str,
|
||||
|
||||
@@ -7,9 +7,6 @@ This module provides MCP tools for interacting with the Gmail API.
|
||||
import logging
|
||||
import asyncio
|
||||
import base64
|
||||
import ssl
|
||||
import time
|
||||
import functools
|
||||
from typing import Optional, List, Dict, Literal
|
||||
|
||||
from email.mime.text import MIMEText
|
||||
@@ -18,7 +15,7 @@ from mcp import types
|
||||
from fastapi import Body
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.utils import handle_http_errors, retry_on_ssl_error
|
||||
from core.utils import handle_http_errors
|
||||
from core.server import (
|
||||
GMAIL_READONLY_SCOPE,
|
||||
GMAIL_SEND_SCOPE,
|
||||
@@ -134,9 +131,8 @@ def _format_gmail_results_plain(messages: list, query: str) -> str:
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("search_gmail_messages", is_read_only=True)
|
||||
@require_google_service("gmail", "gmail_read")
|
||||
@handle_http_errors("search_gmail_messages")
|
||||
@retry_on_ssl_error()
|
||||
async def search_gmail_messages(
|
||||
service, query: str, user_google_email: str, page_size: int = 10
|
||||
) -> str:
|
||||
@@ -168,9 +164,8 @@ async def search_gmail_messages(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_gmail_message_content", is_read_only=True)
|
||||
@require_google_service("gmail", "gmail_read")
|
||||
@handle_http_errors("get_gmail_message_content")
|
||||
@retry_on_ssl_error()
|
||||
async def get_gmail_message_content(
|
||||
service, message_id: str, user_google_email: str
|
||||
) -> str:
|
||||
@@ -237,9 +232,8 @@ async def get_gmail_message_content(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_gmail_messages_content_batch", is_read_only=True)
|
||||
@require_google_service("gmail", "gmail_read")
|
||||
@handle_http_errors("get_gmail_messages_content_batch")
|
||||
@retry_on_ssl_error()
|
||||
async def get_gmail_messages_content_batch(
|
||||
service,
|
||||
message_ids: List[str],
|
||||
@@ -391,9 +385,8 @@ async def get_gmail_messages_content_batch(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("gmail", GMAIL_SEND_SCOPE)
|
||||
@handle_http_errors("send_gmail_message")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("gmail", GMAIL_SEND_SCOPE)
|
||||
async def send_gmail_message(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -429,9 +422,8 @@ async def send_gmail_message(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("gmail", GMAIL_COMPOSE_SCOPE)
|
||||
@handle_http_errors("draft_gmail_message")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("gmail", GMAIL_COMPOSE_SCOPE)
|
||||
async def draft_gmail_message(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -477,9 +469,8 @@ async def draft_gmail_message(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_gmail_thread_content", is_read_only=True)
|
||||
@require_google_service("gmail", "gmail_read")
|
||||
@handle_http_errors("get_gmail_thread_content")
|
||||
@retry_on_ssl_error()
|
||||
async def get_gmail_thread_content(
|
||||
service, thread_id: str, user_google_email: str
|
||||
) -> str:
|
||||
@@ -566,9 +557,8 @@ async def get_gmail_thread_content(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("list_gmail_labels", is_read_only=True)
|
||||
@require_google_service("gmail", "gmail_read")
|
||||
@handle_http_errors("list_gmail_labels")
|
||||
@retry_on_ssl_error()
|
||||
async def list_gmail_labels(service, user_google_email: str) -> str:
|
||||
"""
|
||||
Lists all labels in the user's Gmail account.
|
||||
@@ -615,9 +605,8 @@ async def list_gmail_labels(service, user_google_email: str) -> str:
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("gmail", GMAIL_LABELS_SCOPE)
|
||||
@handle_http_errors("manage_gmail_label")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("gmail", GMAIL_LABELS_SCOPE)
|
||||
async def manage_gmail_label(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -690,9 +679,8 @@ async def manage_gmail_label(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("gmail", GMAIL_MODIFY_SCOPE)
|
||||
@handle_http_errors("modify_gmail_message_labels")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("gmail", GMAIL_MODIFY_SCOPE)
|
||||
async def modify_gmail_message_labels(
|
||||
service,
|
||||
user_google_email: str,
|
||||
|
||||
@@ -13,7 +13,7 @@ from googleapiclient.errors import HttpError
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.server import server
|
||||
from core.utils import handle_http_errors, retry_on_ssl_error
|
||||
from core.utils import handle_http_errors
|
||||
from core.comments import create_comment_tools
|
||||
|
||||
# Configure module logger
|
||||
@@ -21,9 +21,8 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("list_spreadsheets", is_read_only=True)
|
||||
@require_google_service("drive", "drive_read")
|
||||
@handle_http_errors("list_spreadsheets")
|
||||
@retry_on_ssl_error()
|
||||
async def list_spreadsheets(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -71,9 +70,8 @@ async def list_spreadsheets(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_spreadsheet_info", is_read_only=True)
|
||||
@require_google_service("sheets", "sheets_read")
|
||||
@handle_http_errors("get_spreadsheet_info")
|
||||
@retry_on_ssl_error()
|
||||
async def get_spreadsheet_info(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -122,9 +120,8 @@ async def get_spreadsheet_info(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("read_sheet_values", is_read_only=True)
|
||||
@require_google_service("sheets", "sheets_read")
|
||||
@handle_http_errors("read_sheet_values")
|
||||
@retry_on_ssl_error()
|
||||
async def read_sheet_values(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -173,9 +170,8 @@ async def read_sheet_values(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("sheets", "sheets_write")
|
||||
@handle_http_errors("modify_sheet_values")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("sheets", "sheets_write")
|
||||
async def modify_sheet_values(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -245,9 +241,8 @@ async def modify_sheet_values(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("sheets", "sheets_write")
|
||||
@handle_http_errors("create_spreadsheet")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("sheets", "sheets_write")
|
||||
async def create_spreadsheet(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -295,9 +290,8 @@ async def create_spreadsheet(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("sheets", "sheets_write")
|
||||
@handle_http_errors("create_sheet")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("sheets", "sheets_write")
|
||||
async def create_sheet(
|
||||
service,
|
||||
user_google_email: str,
|
||||
|
||||
@@ -13,16 +13,15 @@ from googleapiclient.errors import HttpError
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.server import server
|
||||
from core.utils import handle_http_errors, retry_on_ssl_error
|
||||
from core.utils import handle_http_errors
|
||||
from core.comments import create_comment_tools
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("slides", "slides")
|
||||
@handle_http_errors("create_presentation")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("slides", "slides")
|
||||
async def create_presentation(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -62,9 +61,8 @@ async def create_presentation(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_presentation", is_read_only=True)
|
||||
@require_google_service("slides", "slides_read")
|
||||
@handle_http_errors("get_presentation")
|
||||
@retry_on_ssl_error()
|
||||
async def get_presentation(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -111,9 +109,8 @@ Slides Breakdown:
|
||||
|
||||
|
||||
@server.tool()
|
||||
@require_google_service("slides", "slides")
|
||||
@handle_http_errors("batch_update_presentation")
|
||||
@retry_on_ssl_error()
|
||||
@require_google_service("slides", "slides")
|
||||
async def batch_update_presentation(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -169,9 +166,8 @@ async def batch_update_presentation(
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_page", is_read_only=True)
|
||||
@require_google_service("slides", "slides_read")
|
||||
@handle_http_errors("get_page")
|
||||
@retry_on_ssl_error()
|
||||
async def get_page(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -232,9 +228,8 @@ Page Elements:
|
||||
|
||||
|
||||
@server.tool()
|
||||
@handle_http_errors("get_page_thumbnail", is_read_only=True)
|
||||
@require_google_service("slides", "slides_read")
|
||||
@handle_http_errors("get_page_thumbnail")
|
||||
@retry_on_ssl_error()
|
||||
async def get_page_thumbnail(
|
||||
service,
|
||||
user_google_email: str,
|
||||
|
||||
@@ -13,7 +13,7 @@ from googleapiclient.errors import HttpError
|
||||
|
||||
from auth.service_decorator import require_google_service
|
||||
from core.server import server
|
||||
from core.utils import handle_http_errors, retry_on_ssl_error
|
||||
from core.utils import handle_http_errors
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -21,7 +21,6 @@ logger = logging.getLogger(__name__)
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks_read")
|
||||
@handle_http_errors("list_task_lists")
|
||||
@retry_on_ssl_error()
|
||||
async def list_task_lists(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -82,7 +81,6 @@ async def list_task_lists(
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks_read")
|
||||
@handle_http_errors("get_task_list")
|
||||
@retry_on_ssl_error()
|
||||
async def get_task_list(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -127,7 +125,6 @@ async def get_task_list(
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks")
|
||||
@handle_http_errors("create_task_list")
|
||||
@retry_on_ssl_error()
|
||||
async def create_task_list(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -176,7 +173,6 @@ async def create_task_list(
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks")
|
||||
@handle_http_errors("update_task_list")
|
||||
@retry_on_ssl_error()
|
||||
async def update_task_list(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -227,7 +223,6 @@ async def update_task_list(
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks")
|
||||
@handle_http_errors("delete_task_list")
|
||||
@retry_on_ssl_error()
|
||||
async def delete_task_list(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -268,7 +263,6 @@ async def delete_task_list(
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks_read")
|
||||
@handle_http_errors("list_tasks")
|
||||
@retry_on_ssl_error()
|
||||
async def list_tasks(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -375,7 +369,6 @@ async def list_tasks(
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks_read")
|
||||
@handle_http_errors("get_task")
|
||||
@retry_on_ssl_error()
|
||||
async def get_task(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -437,7 +430,6 @@ async def get_task(
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks")
|
||||
@handle_http_errors("create_task")
|
||||
@retry_on_ssl_error()
|
||||
async def create_task(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -513,7 +505,6 @@ async def create_task(
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks")
|
||||
@handle_http_errors("update_task")
|
||||
@retry_on_ssl_error()
|
||||
async def update_task(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -596,7 +587,6 @@ async def update_task(
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks")
|
||||
@handle_http_errors("delete_task")
|
||||
@retry_on_ssl_error()
|
||||
async def delete_task(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -639,7 +629,6 @@ async def delete_task(
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks")
|
||||
@handle_http_errors("move_task")
|
||||
@retry_on_ssl_error()
|
||||
async def move_task(
|
||||
service,
|
||||
user_google_email: str,
|
||||
@@ -719,7 +708,6 @@ async def move_task(
|
||||
@server.tool()
|
||||
@require_google_service("tasks", "tasks")
|
||||
@handle_http_errors("clear_completed_tasks")
|
||||
@retry_on_ssl_error()
|
||||
async def clear_completed_tasks(
|
||||
service,
|
||||
user_google_email: str,
|
||||
|
||||
Reference in New Issue
Block a user