Spaces:
Sleeping
Sleeping
| import gspread | |
| from google.oauth2.service_account import Credentials | |
| from google.auth.exceptions import GoogleAuthError | |
| import pandas as pd | |
| from datetime import datetime | |
| import os | |
| import sys | |
| class GoogleSheetsExporter: | |
| """ | |
| Класс для экспорта задач в Google Sheets (исправленная версия) | |
| """ | |
| def __init__(self, credentials_path='credentials/google-credentials.json'): | |
| """ | |
| Инициализация подключения к Google Sheets | |
| """ | |
| self.credentials_path = credentials_path | |
| self.client = None | |
| self.spreadsheet = None | |
| # Проверяем наличие файла с ключами | |
| if not os.path.exists(credentials_path): | |
| print(f"❌ Файл с ключами не найден: {credentials_path}") | |
| print("💡 Убедитесь, что файл лежит в папке credentials/") | |
| sys.exit(1) | |
| self._authenticate() | |
| def _authenticate(self): | |
| """Аутентификация в Google Sheets API""" | |
| try: | |
| # Определяем права доступа | |
| scope = [ | |
| 'https://www.googleapis.com/auth/spreadsheets', | |
| 'https://www.googleapis.com/auth/drive' | |
| ] | |
| # Загружаем ключи | |
| credentials = Credentials.from_service_account_file( | |
| self.credentials_path, | |
| scopes=scope | |
| ) | |
| # Авторизуемся | |
| self.client = gspread.authorize(credentials) | |
| print("✅ Успешная аутентификация в Google Sheets") | |
| except Exception as e: | |
| print(f"❌ Ошибка аутентификации: {e}") | |
| sys.exit(1) | |
| def use_existing_spreadsheet(self, spreadsheet_identifier): | |
| """ | |
| ИСПРАВЛЕНО: Открывает существующую таблицу (по URL, ID или названию) | |
| Args: | |
| spreadsheet_identifier: URL, ID или название таблицы | |
| """ | |
| try: | |
| # Пробуем открыть по URL | |
| if spreadsheet_identifier.startswith('https://'): | |
| self.spreadsheet = self.client.open_by_url(spreadsheet_identifier) | |
| print(f"✅ Открыта таблица по URL") | |
| else: | |
| # Пробуем открыть по ID или названию | |
| try: | |
| self.spreadsheet = self.client.open_by_key(spreadsheet_identifier) | |
| except: | |
| self.spreadsheet = self.client.open(spreadsheet_identifier) | |
| print(f"✅ Таблица: {self.spreadsheet.title}") | |
| return self.spreadsheet | |
| except gspread.SpreadsheetNotFound: | |
| print(f"❌ Таблица не найдена. Проверьте:") | |
| print(f" 1. Правильно ли вы скопировали ссылку/ID") | |
| print(f" 2. Расшарили ли таблицу на email сервисного аккаунта") | |
| return None | |
| except Exception as e: | |
| print(f"❌ Ошибка при открытии таблицы: {e}") | |
| return None | |
| def export_dataframe(self, df, sheet_name='Tasks', clear_sheet=True): | |
| """ | |
| Экспортирует DataFrame в открытую Google таблицу | |
| """ | |
| if self.spreadsheet is None: | |
| print("❌ Сначала откройте таблицу через use_existing_spreadsheet()") | |
| return False | |
| try: | |
| # Проверяем, существует ли лист с таким названием | |
| try: | |
| worksheet = self.spreadsheet.worksheet(sheet_name) | |
| if clear_sheet: | |
| worksheet.clear() | |
| print(f"🧹 Лист '{sheet_name}' очищен") | |
| except gspread.WorksheetNotFound: | |
| # Создаем новый лист | |
| worksheet = self.spreadsheet.add_worksheet( | |
| title=sheet_name, | |
| rows=max(100, len(df) + 10), | |
| cols=len(df.columns) + 5 | |
| ) | |
| print(f"📄 Создан новый лист: '{sheet_name}'") | |
| # Подготавливаем данные | |
| headers = df.columns.tolist() | |
| data = df.values.tolist() | |
| all_data = [headers] + data | |
| # Записываем | |
| worksheet.update('A1', all_data) | |
| print(f"✅ Записано {len(df)} строк в лист '{sheet_name}'") | |
| return worksheet | |
| except Exception as e: | |
| print(f"❌ Ошибка при экспорте: {e}") | |
| return False | |
| def get_shareable_link(self): | |
| """Возвращает ссылку на таблицу""" | |
| if self.spreadsheet: | |
| return self.spreadsheet.url | |
| return None |