Skip to content

Commit ee2bbbb

Browse files
authored
Test AiohttpStore (#21)
* Test AiohttpStore * Use asyncio.run() * More tests
1 parent 38fe54e commit ee2bbbb

File tree

3 files changed

+604
-20
lines changed

3 files changed

+604
-20
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ test = [
5151
"mypy",
5252
"pytest-xdist",
5353
"minio",
54+
"docker",
5455
]
5556
xarray = [
5657
"xarray",

src/obspec_utils/aiohttp.py

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,26 @@ def _build_url(self, path: str) -> str:
216216
path = path.removeprefix("/")
217217
return f"{self.base_url}/{path}" if path else self.base_url
218218

219+
def _get_header_case_insensitive(
220+
self, headers: dict, name: str, default: str | None = None
221+
) -> str | None:
222+
"""Get a header value with case-insensitive name lookup."""
223+
# Try exact match first
224+
if name in headers:
225+
return headers[name]
226+
# Try case-insensitive lookup
227+
name_lower = name.lower()
228+
for key, value in headers.items():
229+
if key.lower() == name_lower:
230+
return value
231+
return default
232+
219233
def _parse_meta_from_headers(
220234
self, path: str, headers: dict, content_length: int | None = None
221235
) -> ObjectMeta:
222236
"""Extract ObjectMeta from HTTP response headers."""
223237
# Parse last-modified header
224-
last_modified_str = headers.get("Last-Modified")
238+
last_modified_str = self._get_header_case_insensitive(headers, "Last-Modified")
225239
if last_modified_str:
226240
# Parse HTTP date format
227241
try:
@@ -235,36 +249,41 @@ def _parse_meta_from_headers(
235249

236250
# Get size from Content-Length or Content-Range
237251
size = content_length or 0
238-
content_range = headers.get("Content-Range")
252+
content_range = self._get_header_case_insensitive(headers, "Content-Range")
239253
if content_range and "/" in content_range:
240254
# Format: bytes 0-999/1234
241255
total_str = content_range.split("/")[-1]
242256
if total_str != "*":
243257
size = int(total_str)
244-
elif "Content-Length" in headers:
245-
size = int(headers["Content-Length"])
258+
else:
259+
content_length_str = self._get_header_case_insensitive(
260+
headers, "Content-Length"
261+
)
262+
if content_length_str:
263+
size = int(content_length_str)
246264

247265
return {
248266
"path": path,
249267
"last_modified": last_modified,
250268
"size": size,
251-
"e_tag": headers.get("ETag"),
269+
"e_tag": self._get_header_case_insensitive(headers, "ETag"),
252270
"version": None,
253271
}
254272

255273
def _parse_attributes_from_headers(self, headers: dict) -> Attributes:
256274
"""Extract Attributes from HTTP response headers."""
257275
attrs: Attributes = {}
258-
header_map = {
259-
"Content-Disposition": "Content-Disposition",
260-
"Content-Encoding": "Content-Encoding",
261-
"Content-Language": "Content-Language",
262-
"Content-Type": "Content-Type",
263-
"Cache-Control": "Cache-Control",
264-
}
265-
for attr_name, header_name in header_map.items():
266-
if header_name in headers:
267-
attrs[attr_name] = headers[header_name]
276+
header_names = [
277+
"Content-Disposition",
278+
"Content-Encoding",
279+
"Content-Language",
280+
"Content-Type",
281+
"Cache-Control",
282+
]
283+
for header_name in header_names:
284+
value = self._get_header_case_insensitive(headers, header_name)
285+
if value is not None:
286+
attrs[header_name] = value
268287
return attrs
269288

270289
# --- Async methods (primary implementation) ---
@@ -478,9 +497,7 @@ def get(
478497
AiohttpGetResult
479498
Result object with buffer() method and metadata.
480499
"""
481-
result = asyncio.get_event_loop().run_until_complete(
482-
self.get_async(path, options=options)
483-
)
500+
result = asyncio.run(self.get_async(path, options=options))
484501
return AiohttpGetResult(
485502
_data=result._data,
486503
_meta=result._meta,
@@ -517,7 +534,7 @@ def get_range(
517534
bytes
518535
The requested byte range.
519536
"""
520-
return asyncio.get_event_loop().run_until_complete(
537+
return asyncio.run(
521538
self.get_range_async(path, start=start, end=end, length=length)
522539
)
523540

@@ -550,7 +567,7 @@ def get_ranges(
550567
Sequence[bytes]
551568
The requested byte ranges.
552569
"""
553-
return asyncio.get_event_loop().run_until_complete(
570+
return asyncio.run(
554571
self.get_ranges_async(path, starts=starts, ends=ends, lengths=lengths)
555572
)
556573

0 commit comments

Comments
 (0)