Другое

Исправление TypeError 'str' object is not callable Google Sheets API

Решение TypeError при использовании Google Sheets API с олицетворением сервисного аккаунта. Узнайте пошаговые решения, включая обновление учетных данных, очистку кэша и альтернативные методы аутентификации.

Как исправить “TypeError: объект ‘str’ не вызывается” при использовании Google SDK для получения таблицы с олицетворением сервисного аккаунта?

Я столкнулся с TypeError при попытке получить данные из Google Таблицы с использованием Google Sheets API с олицетворением сервисного аккаунта. Вот мой код:

python
def build_gcp_sheets_service():
    target_scopes = ['https://www.googleapis.com/auth/spreadsheets.readonly']
    
    source_credentials, _ = google.auth.default()
    
    target_credentials = impersonated_credentials.Credentials(
        source_credentials=source_credentials,
        target_principal=config.gcp.local_service_account,
        target_scopes=target_scopes,
        lifetime=60
    )
    
    service = build('sheets', 'v4', credentials=target_credentials)
    return service

service = build_gcp_sheets_service()
sheet = service.spreadsheets()
request = sheet.values().get(spreadsheetId=file_id, range=sheet_range)
result = request.execute() # Ошибка возникает здесь

При вызове request.execute() я получаю эту ошибку:

Traceback (most recent call last):
  File "/aircraft-detection/ml/gcp.py", line 69, in _fetch_spreadsheet
    result = request.execute()
             ^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/googleapiclient/_helpers.py", line 130, in positional_wrapper
    return wrapped(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/googleapiclient/http.py", line 923, in execute
    resp, content = _retry_request(
                    ^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/googleapiclient/http.py", line 191, in _retry_request
    resp, content = http.request(uri, method, *args, **kwargs)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/google_auth_httplib2.py", line 207, in request
    self.credentials.before_request(self._request, method, uri, request_headers)
  File "/usr/local/lib/python3.11/site-packages/google/auth/credentials.py", line 228, in before_request
    self._blocking_refresh(request)
  File "/usr/local/lib/python3.11/site-packages/google/auth/credentials.py", line 191, in _blocking_refresh
    self.refresh(request)
  File "/usr/local/lib/python3.11/site-packages/google/auth/credentials.py", line 365, in refresh
    self._refresh_token(request)
  File "/usr/local/lib/python3.11/site-packages/google/auth/impersonated_credentials.py", line 289, in _refresh_token
    self._source_credentials._refresh_token(request)
TypeError: 'str' object is not callable

Я подозреваю, что это проблема конфигурации gcloud, а не кода, потому что:

  1. Этот код раньше работал, и ошибка начала возникать, несмотря на отсутствие изменений в коде.
  2. Код работает на других компьютерах разработчиков.
  3. Я переустановил gcloud SDK и перенастроил его, но проблема сохраняется.

Как можно решить эту проблему “TypeError: объект ‘str’ не вызывается” при использовании Google SDK с олицетворением сервисного аккаунта?

Ошибка “TypeError: ‘str’ object is not callable” при использовании Google SDK с олицетворением сервисного аккаунта обычно указывает на более глубокую проблему с обработкой учетных данных в процессе обновления токена. Исходя из исследований и трассировки ошибки, эта проблема часто возникает из-за проблем с конфигурацией учетных данных или конфликтов версий библиотек, а не из-за ошибок в логике кода.


Содержание


Понимание ошибки

Ошибка возникает, потому что библиотека аутентификации Google пытается вызвать строку как функцию в процессе обновления токена. Как объясняется в документации библиотеки аутентификации Google, это обычно происходит при несоответствии в обработке учетных данных.

Трассировка ошибки показывает, что проблема возникает в файле google.auth.impersonated_credentials.py в методе _refresh_token, конкретно при вызове self._source_credentials._refresh_token(request). Это указывает на проблему в обработке исходных учетных данных при олицетворении.

Распространенные причины

  1. Конфликт имен переменных: Переменная с именем str может переопределять встроенную функцию str()
  2. Ошибки в библиотеке аутентификации Google: Проблемы, специфичные для версий, связанные с обработкой учетных данных при олицетворении
  3. Проблемы конфигурации сервисного аккаунта: Неправильная настройка сервисного аккаунта, который олицетворяется
  4. Конфликт переменных окружения: Переменные окружения, мешающие обработке учетных данных
  5. Повреждение кэша токенов: Проблемы с аутентификационным потоком, вызванные кэшированными токенами

Пошаговые решения

1. Проверьте конфликты имен переменных

Убедитесь, что у вас нет переменных с именем str в вашем коде или импортированных модулях:

python
# Проверка распространенных конфликтов имен
import builtins
if hasattr(builtins, 'str') and not callable(builtins.str):
    print("Предупреждение: str переопределена!")

2. Обновите библиотеку аутентификации Google

Установите последнюю версию библиотеки аутентификации Google для решения известных ошибок:

bash
pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2

3. Проверьте конфигурацию сервисного аккаунта

Убедитесь, что у вашего сервисного аккаунта есть правильные разрешения:

python
def build_gcp_sheets_service():
    target_scopes = ['https://www.googleapis.com/auth/spreadsheets.readonly']
    
    # Используйте явные учетные данные вместо default()
    from google.oauth2 import service_account
    source_credentials = service_account.Credentials.from_service_account_file(
        'путь/к/вашему/service-account.json',
        scopes=['https://www.googleapis.com/auth/cloud-platform']
    )
    
    target_credentials = impersonated_credentials.Credentials(
        source_credentials=source_credentials,
        target_principal=config.gcp.local_service_account,
        target_scopes=target_scopes,
        lifetime=3600  # Попробуйте с временем жизни 1 час
    )
    
    service = build('sheets', 'v4', credentials=target_credentials)
    return service

4. Очистите кэш токенов

Удалите кэшированные учетные данные, которые могут вызывать проблемы:

python
import os
import shutil

# Очистка кэша учетных данных gcloud
cache_dirs = [
    os.path.expanduser('~/.config/gcloud/credentials.db'),
    os.path.expanduser('~/.config/gcloud/application_default_credentials.json')
]

for cache_dir in cache_dirs:
    if os.path.exists(cache_dir):
        os.remove(cache_dir)

5. Используйте альтернативный метод аутентификации

Попробуйте использовать прямую аутентификацию сервисного аккаунта вместо олицетворения:

python
def build_gcp_sheets_service():
    from google.oauth2 import service_account
    
    credentials = service_account.Credentials.from_service_account_file(
        'путь/к/вашему/service-account.json',
        scopes=['https://www.googleapis.com/auth/spreadsheets.readonly']
    )
    
    service = build('sheets', 'v4', credentials=credentials)
    return service

Расширенное устранение неполадок

1. Отладьте поток аутентификации

Добавьте отладочную информацию для понимания, где строка вызывается как функция:

python
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger('google.auth').setLevel(logging.DEBUG)

2. Проверьте версию Google Cloud SDK

Убедитесь, что ваш Google Cloud SDK обновлен:

bash
gcloud components update

3. Проверьте переменные окружения

Проверьте наличие конфликтующих переменных окружения:

python
import os
print("GOOGLE_APPLICATION_CREDENTIALS:", os.environ.get('GOOGLE_APPLICATION_CREDENTIALS'))
print("GCLOUD_PROJECT:", os.environ.get('GCLOUD_PROJECT'))

4. Протестируйте с другим сервисным аккаунтом

Создайте новый сервисный аккаунт с минимальными разрешениями для изоляции проблемы:

python
# Создайте новый сервисный аккаунт с доступом только к таблицам
gcloud iam service-accounts create test-sa \
    --display-name="Тестовый сервисный аккаунт"
gcloud projects add-iam-policy-binding ВАШ_ID_ПРОЕКТА \
    --member="serviceAccount:test-sa@ВАШ_ID_ПРОЕКТА.iam.gserviceaccount.com" \
    --role="roles/spreadsheets.viewer"

Стратегии предотвращения

  1. Используйте явные учетные данные: Избегайте google.auth.default() и используйте явные учетные данные сервисного аккаунта
  2. Регулярные обновления: Держите библиотеки аутентификации и SDK Google в актуальном состоянии
  3. Изоляция окружения: Используйте виртуальные окружения для предотвращения конфликтов зависимостей
  4. Вращение учетных данных: Регулярно меняйте учетные данные сервисного аккаунта
  5. Мониторинг: Реализуйте логирование для раннего обнаружения проблем аутентификации

Связанные ресурсы

  1. Документация библиотеки аутентификации Google - Олицетворенные учетные данные
  2. GitHub Issue: Ошибка в методе with_target_audience
  3. Python TypeError: ‘str’ object is not callable - Как исправить

Ошибка, с которой вы столкнулись, обычно решается путем обновления зависимостей, очистки кэша учетных данных или использования явной обработки учетных данных. Если проблема сохраняется после попыток этих решений, рассмотрите возможность отправки отчета об ошибке команде библиотеки аутентификации Google, так как это может указывать на специфическую для библиотеки проблему, требующую исправления.

Авторы
Проверено модерацией
Модерация