File size: 2,286 Bytes
72268ee |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
"""
Adapt s3 to package_streaming
"""
from __future__ import annotations
import typing
from contextlib import closing
from typing import Any
from . import package_streaming
if typing.TYPE_CHECKING: # pragma: no cover
from mypy_boto3_s3 import Client
from mypy_boto3_s3.type_defs import GetObjectOutputTypeDef
else:
Client = GetObjectOutputTypeDef = None
from .url import conda_reader_for_url
__all__ = ["stream_conda_info", "conda_reader_for_s3"]
class ResponseFacade:
def __init__(self, response: GetObjectOutputTypeDef):
self.response = response
self.raw: Any = response["Body"]
def raise_for_status(self):
# s3 get_object raises automatically?
pass
@property
def status_code(self):
return self.response["ResponseMetadata"]["HTTPStatusCode"]
@property
def headers(self):
# a case-sensitive dict; keys may be lowercased always?
return self.response["ResponseMetadata"]["HTTPHeaders"]
def iter_content(self, n: int):
return iter(lambda: self.raw.read(n), b"")
class SessionFacade:
"""
Make s3 client look just enough like a requests.session for LazyZipOverHTTP
"""
def __init__(self, client: Client, bucket: str, key: str):
self.client = client
self.bucket = bucket
self.key = key
def get(self, url, *, headers: dict | None = None, stream=True):
if headers and "Range" in headers:
response = self.client.get_object(
Bucket=self.bucket, Key=self.key, Range=headers["Range"]
)
else:
response = self.client.get_object(Bucket=self.bucket, Key=self.key)
return ResponseFacade(response)
def stream_conda_info(client, bucket, key):
"""
Yield (tar, member) for conda package.
Just "info/" for .conda, all members for tar.
"""
filename, conda = conda_reader_for_s3(client, bucket, key)
with closing(conda):
yield from package_streaming.stream_conda_info(filename, conda)
def conda_reader_for_s3(client: Client, bucket: str, key: str):
"""
Return (name, file_like) suitable for package_streaming APIs
"""
session: Any = SessionFacade(client, bucket, key)
return conda_reader_for_url(key, session)
|