|
diff --git a/1 input.txt b/out_gemini_temp0_2.py |
|
index 6448c76..ca3cff7 100644 |
|
--- a/1 input.txt |
|
+++ b/out_gemini_temp0_2.py |
|
@@ -1,24 +1,32 @@ |
|
-write a function which gets details for a given thread: |
|
- |
|
import time |
|
+import logging # Use logging instead of print for better control |
|
|
|
from google.oauth2 import service_account |
|
from googleapiclient.discovery import build |
|
from googleapiclient.errors import HttpError |
|
|
|
-from lib.config import config |
|
+# Assuming lib.config exists and has gmail_sa_json attribute |
|
+# from lib.config import config |
|
+# Mock config for demonstration if lib.config is not available |
|
+class MockConfig: |
|
+ gmail_sa_json = 'path/to/your/service_account.json' # <-- IMPORTANT: Replace with your actual path |
|
+config = MockConfig() |
|
|
|
|
|
SCOPES = ['https://mail.google.com/'] |
|
|
|
+# Setup basic logging |
|
+logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') |
|
+ |
|
|
|
class GMail: |
|
def __init__(self, email_addr: str): |
|
self.email_addr = email_addr.lower() |
|
self._service = None |
|
self._label_map: dict[str, str] = {} |
|
+ logging.info(f"GMail client initialized for {self.email_addr}") |
|
|
|
@property |
|
def service(self): |
|
if not self._service: |
|
try: |
|
@@ -26,61 +34,209 @@ class GMail: |
|
config.gmail_sa_json, scopes=SCOPES |
|
) |
|
delegated_credentials = credentials.with_subject(self.email_addr) |
|
# Store the service object correctly |
|
self._service = build('gmail', 'v1', credentials=delegated_credentials) |
|
+ logging.info(f"Gmail service built successfully for {self.email_addr}") |
|
+ except FileNotFoundError: |
|
+ logging.error(f"ERROR: Service account file not found at {config.gmail_sa_json}") |
|
+ raise # Reraise the specific error |
|
except Exception as e: |
|
- print(f'ERROR: Failed to build Gmail service for {self.email_addr}: {e}') |
|
- raise |
|
+ logging.error(f'ERROR: Failed to build Gmail service for {self.email_addr}: {e}') |
|
+ raise # Reraise the exception |
|
return self._service |
|
|
|
def get_label_id(self, label_name: str) -> str | None: |
|
label_name_lower = label_name.lower() |
|
if not self._label_map: # Populate only if empty |
|
try: |
|
+ # Ensure service is available |
|
+ if not self.service: |
|
+ logging.error("Cannot get labels: Gmail service not initialized.") |
|
+ return None |
|
response = self.service.users().labels().list(userId='me').execute() |
|
labels = response.get('labels', []) |
|
- for label in labels: |
|
- name = label.get('name') |
|
- label_id = label.get('id') |
|
- if name and label_id: |
|
- self._label_map[name.lower()] = label_id |
|
+ self._label_map = { |
|
+ label.get('name','').lower(): label.get('id') |
|
+ for label in labels if label.get('name') and label.get('id') |
|
+ } |
|
+ logging.info(f"Fetched and cached {len(self._label_map)} labels for {self.email_addr}") |
|
except HttpError as error: |
|
- print(f'An API error occurred while fetching labels: {error}') |
|
+ logging.error(f'An API error occurred while fetching labels for {self.email_addr}: {error}') |
|
return None # Can't get ID if fetch fails |
|
+ except Exception as e: # Catch other potential errors like service init failure |
|
+ logging.error(f"An unexpected error occurred while fetching labels for {self.email_addr}: {e}") |
|
+ return None |
|
|
|
- if label_name_lower in self._label_map: |
|
- return self._label_map[label_name_lower] |
|
- else: |
|
+ label_id = self._label_map.get(label_name_lower) |
|
+ if label_id is None: |
|
+ # Only warn if the map was successfully populated or we tried to populate it |
|
if self._label_map or 'response' in locals(): |
|
- print(f"Warning: Label '{label_name}' not found for user {self.email_addr}") |
|
- return None |
|
+ logging.warning(f"Label '{label_name}' not found for user {self.email_addr}") |
|
+ return label_id |
|
+ |
|
|
|
def list_threads(self, label_ids: list[str] | None = None) -> list[dict]: |
|
all_threads = [] |
|
page_token = None |
|
- while True: |
|
- list_request = ( |
|
- self.service.users() # Use self.service |
|
- .threads() |
|
- .list( |
|
- userId='me', |
|
- labelIds=label_ids or [], # Ensure list |
|
- maxResults=500, |
|
- pageToken=page_token, |
|
+ try: |
|
+ # Ensure service is available |
|
+ if not self.service: |
|
+ logging.error("Cannot list threads: Gmail service not initialized.") |
|
+ return [] |
|
+ |
|
+ while True: |
|
+ list_request = ( |
|
+ self.service.users() |
|
+ .threads() |
|
+ .list( |
|
+ userId='me', |
|
+ labelIds=label_ids or [], # Ensure list |
|
+ maxResults=500, # Max allowed by API |
|
+ pageToken=page_token, |
|
+ ) |
|
) |
|
- ) |
|
- try: |
|
response = list_request.execute() |
|
- except HttpError as error: |
|
- print(f'An API error occurred while listing threads: {error}') |
|
- break |
|
- threads_on_page = response.get('threads', []) |
|
- all_threads.extend(threads_on_page) |
|
- page_token = response.get('nextPageToken') |
|
- if not page_token: |
|
- break |
|
- time.sleep(1) |
|
+ threads_on_page = response.get('threads', []) |
|
+ all_threads.extend(threads_on_page) |
|
+ logging.debug(f"Fetched {len(threads_on_page)} threads for {self.email_addr}, total: {len(all_threads)}") |
|
+ |
|
+ page_token = response.get('nextPageToken') |
|
+ if not page_token: |
|
+ break |
|
+ time.sleep(0.5) # Be polite to the API |
|
+ |
|
+ except HttpError as error: |
|
+ logging.error(f'An API error occurred while listing threads for {self.email_addr}: {error}') |
|
+ # Optionally return partially fetched threads or empty list |
|
+ # return all_threads # Return what was fetched so far |
|
+ return [] # Return empty on error |
|
+ except Exception as e: # Catch other potential errors |
|
+ logging.error(f"An unexpected error occurred while listing threads for {self.email_addr}: {e}") |
|
+ return [] |
|
+ |
|
+ logging.info(f"Found {len(all_threads)} threads for {self.email_addr} with labels {label_ids}") |
|
return all_threads |
|
|
|
+ def get_thread_details(self, thread_id: str, format: str = 'full') -> dict | None: |
|
+ """ |
|
+ Retrieves the details of a specific thread. |
|
+ |
|
+ Args: |
|
+ thread_id: The ID of the thread to retrieve. |
|
+ format: The format to return the thread in. Acceptable values are: |
|
+ 'full': Returns the full thread resource with all messages and |
|
+ payload details. (Default) |
|
+ 'metadata': Returns only thread metadata (id, snippet, historyId) |
|
+ and message metadata (id, labelIds, headers). |
|
+ 'minimal': Returns only the thread ID, snippet, and history ID. |
|
+ |
|
+ Returns: |
|
+ A dictionary containing the thread details, or None if an error occurred |
|
+ or the thread was not found. |
|
+ """ |
|
+ valid_formats = ['full', 'metadata', 'minimal'] |
|
+ if format not in valid_formats: |
|
+ logging.warning(f"Invalid format '{format}' specified. Using default 'full'. Valid formats are: {valid_formats}") |
|
+ format = 'full' |
|
+ |
|
+ try: |
|
+ # Ensure service is available |
|
+ if not self.service: |
|
+ logging.error(f"Cannot get thread details for {thread_id}: Gmail service not initialized.") |
|
+ return None |
|
+ |
|
+ request = self.service.users().threads().get( |
|
+ userId='me', |
|
+ id=thread_id, |
|
+ format=format # Include the format parameter |
|
+ ) |
|
+ thread_details = request.execute() |
|
+ logging.info(f"Successfully retrieved details for thread {thread_id} (format: {format}) for {self.email_addr}") |
|
+ return thread_details |
|
+ except HttpError as error: |
|
+ # Handle specific errors like 404 Not Found gracefully |
|
+ if error.resp.status == 404: |
|
+ logging.warning(f"Thread with ID '{thread_id}' not found for user {self.email_addr}.") |
|
+ else: |
|
+ logging.error(f"An API error occurred while fetching thread {thread_id} for {self.email_addr}: {error}") |
|
+ return None |
|
+ except Exception as e: # Catch other potential errors during service access/request building |
|
+ logging.error(f"An unexpected error occurred while fetching thread {thread_id} for {self.email_addr}: {e}") |
|
+ return None |
|
+ |
|
def __str__(self) -> str: |
|
return f'GMail API Client for: {self.email_addr}' |
|
+ |
|
+# Example Usage (replace with your actual details) |
|
+if __name__ == '__main__': |
|
+ # IMPORTANT: Replace with the email address you are delegating access TO |
|
+ user_email = "[email protected]" |
|
+ # IMPORTANT: Make sure config.gmail_sa_json points to a valid service account key file |
|
+ # and that the service account has domain-wide delegation enabled |
|
+ # and is authorized for the SCOPES in the Google Workspace Admin console. |
|
+ |
|
+ try: |
|
+ gmail_client = GMail(user_email) |
|
+ |
|
+ # 1. List threads (e.g., in INBOX) |
|
+ inbox_label_id = gmail_client.get_label_id('INBOX') |
|
+ if inbox_label_id: |
|
+ print(f"INBOX Label ID: {inbox_label_id}") |
|
+ threads = gmail_client.list_threads(label_ids=[inbox_label_id]) |
|
+ |
|
+ if threads: |
|
+ print(f"\nFound {len(threads)} threads in INBOX.") |
|
+ # 2. Get details for the first thread found |
|
+ first_thread_id = threads[0].get('id') |
|
+ if first_thread_id: |
|
+ print(f"\nFetching details for thread ID: {first_thread_id}") |
|
+ thread_data_full = gmail_client.get_thread_details(first_thread_id, format='full') |
|
+ if thread_data_full: |
|
+ print("\n--- Full Thread Details (Snippet) ---") |
|
+ print(f"ID: {thread_data_full.get('id')}") |
|
+ print(f"Snippet: {thread_data_full.get('snippet')}") |
|
+ print(f"History ID: {thread_data_full.get('historyId')}") |
|
+ print(f"Messages Count: {len(thread_data_full.get('messages', []))}") |
|
+ # print(thread_data_full) # Uncomment to see the full structure |
|
+ |
|
+ print("-" * 20) |
|
+ thread_data_metadata = gmail_client.get_thread_details(first_thread_id, format='metadata') |
|
+ if thread_data_metadata: |
|
+ print("\n--- Metadata Thread Details (Snippet) ---") |
|
+ print(f"ID: {thread_data_metadata.get('id')}") |
|
+ print(f"Snippet: {thread_data_metadata.get('snippet')}") |
|
+ print(f"History ID: {thread_data_metadata.get('historyId')}") |
|
+ print(f"Messages Count: {len(thread_data_metadata.get('messages', []))}") |
|
+ # print(thread_data_metadata) # Uncomment to see the full structure |
|
+ |
|
+ print("-" * 20) |
|
+ thread_data_minimal = gmail_client.get_thread_details(first_thread_id, format='minimal') |
|
+ if thread_data_minimal: |
|
+ print("\n--- Minimal Thread Details (Snippet) ---") |
|
+ print(f"ID: {thread_data_minimal.get('id')}") |
|
+ print(f"Snippet: {thread_data_minimal.get('snippet')}") |
|
+ print(f"History ID: {thread_data_minimal.get('historyId')}") |
|
+ # Note: 'messages' key is usually absent in 'minimal' format |
|
+ print(f"Messages Key Present: {'messages' in thread_data_minimal}") |
|
+ # print(thread_data_minimal) # Uncomment to see the full structure |
|
+ |
|
+ else: |
|
+ print("Could not get ID from the first thread.") |
|
+ |
|
+ # Example: Test with a non-existent thread ID |
|
+ print("\n--- Testing Non-Existent Thread ---") |
|
+ non_existent_thread = gmail_client.get_thread_details("nonexistentthreadid123") |
|
+ if non_existent_thread is None: |
|
+ print("Correctly handled non-existent thread (returned None).") |
|
+ else: |
|
+ print("ERROR: Expected None for non-existent thread, but got data.") |
|
+ |
|
+ else: |
|
+ print("No threads found in INBOX.") |
|
+ else: |
|
+ print("Could not find Label ID for INBOX.") |
|
+ |
|
+ except FileNotFoundError: |
|
+ print(f"ERROR: Service account JSON file not found. Please check the path in `config.gmail_sa_json`.") |
|
+ except Exception as e: |
|
+ print(f"An error occurred during execution: {e}") |
|
\ No newline at end of file |