Рефакторинг запросов HTTPAdapter на httpx HTTPTransport

Раньше мы использовали requests.adapters.HTTPAdapter для этого ответа с requests==2.32.3 и google-cloud-storage==2.16.0:

from google.cloud import storage
from requests.adapters import HTTPAdapter

gcs_client = storage.Client()

adapter = HTTPAdapter(pool_connections=30, pool_maxsize=30)
gcs_client._http.mount("https://", adapter)
gcs_client._http._auth_request.session.mount("https://", adapter)

Мы переносим нашу кодовую базу на httpx. Этот комментарий к выпуску на GitHub инструктирует использовать специальные транспорты. Я пытался выполнить что-то вроде приведенного ниже с помощью httpx==0.27.0, но это не сработало:

import google.auth
import httpx
from google.cloud import storage

transport = httpx.HTTPTransport(
    limits=httpx.Limits(
        max_connections=30, max_keepalive_connections=30
    )
)
http = httpx.Client(transport=transport)
http.is_mtls = False  # Emulating https://github.com/googleapis/google-auth-library-python/blob/v2.29.0/google/auth/transport/requests.py#L400
return Client(
    _http=http,
    # Emulating https://github.com/googleapis/python-cloud-core/blob/v2.4.1/google/cloud/client/__init__.py#L178
    credentials=google.auth.default(scopes=Client.SCOPE)[0],
)

Эта реализация выдает ошибку Unauthorized:

google.api_core.Exceptions.Unauthorized: 401 GET https://storage.googleapis.com/storage/v1/b/foo?projection=noAcl&prettyPrint=false: анонимный вызывающий абонент не имеет доступа к Storage.buckets.get Корзина облачного хранилища Google. Разрешение «storage.buckets.get» для ресурса отклонено (или оно может не существовать).

Как можно перейти из requests.adapters.HTTPAdapter в httpx.HTTPTransport?


Этот вопрос похож на Как реорганизовать HTTP-адаптер запроса для использования с aiohttp?, но для httpx, а не для aiohttp.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
125
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

К сожалению, на данный момент у меня нет возможности протестировать это решение. Но вы можете попробовать создать «пользовательский» транспорт, который будет обновлять заголовки аутентификации при отправке любого запроса с использованием этого транспорта.

import google.auth
import google.auth.transport.requests
import httpx
from google.cloud import storage

credentials, project = google.auth.default(scopes=storage.Client.SCOPE)


def get_httpx_client(credentials):
    class AuthenticatedTransport(httpx.BaseTransport):
        def __init__(self, transport):
            self.transport = transport
            self.auth_request = google.auth.transport.requests.Request()

        def handle_request(self, request):
            headers = dict(request.headers)

            credentials.before_request(
                self.auth_request, request.method, request.url, headers
            )
            request.headers.update(headers)
            return self.transport.handle_request(request)

    transport = httpx.HTTPTransport(
        limits=httpx.Limits(max_connections=30, max_keepalive_connections=30)
    )
    authenticated_transport = AuthenticatedTransport(transport)

    return httpx.Client(transport=authenticated_transport)


custom_client = get_httpx_client(credentials)

gcs_client = storage.Client(_http=custom_client, project=project)

ОБНОВЛЯТЬ

Для потоковой передачи ответов перейдите по ссылке https://www.python-httpx.org/quickstart/#streaming-responses

Что-то вроде:

def fetch_stream_file(url):
    with custom_client.stream("GET", url) as response:
        response.raise_for_status()
        for chunk in response.iter_bytes():
            yield chunk

Спасибо @Alex, это делает меня намного ближе. К сожалению, это пока не совсем работает, потому что здесь передается stream=True, а httpx не поддерживает поток kwarg. Итак, я получаю TypeError: httpx.Client.request() got an unexpected keyword argument 'stream'

Intrastellar Explorer 10.06.2024 22:33

поэтому, если вам нужно обрабатывать потоковые ответы, следуйте python-httpx.org/quickstart/#streaming-responses

Alex 11.06.2024 00:36

Другие вопросы по теме