Skip to content

Commit 0ca5ecc

Browse files
fix: parenthesize Py2 multi-exception except clauses so the package imports
except A, B: is Py2 syntax (catch A, bind to name B) and fails to parse under Py3 — it broke 'import s3proxy', so the whole pytest suite couldn't collect (conftest imports s3proxy.concurrency). Parenthesize the 8 sites across utils, concurrency, request_handler and dashboard/* to catch both types as intended. Lets the list-objects self-check import the real module directly (drops the sibling-stubbing workaround).
1 parent ceefc47 commit 0ca5ecc

6 files changed

Lines changed: 13 additions & 54 deletions

File tree

s3proxy/concurrency.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def _create_malloc_release() -> Callable[[], int] | None:
3636
libc.malloc_trim.argtypes = [ctypes.c_size_t]
3737
libc.malloc_trim.restype = ctypes.c_int
3838
return lambda: libc.malloc_trim(0)
39-
except OSError, AttributeError:
39+
except (OSError, AttributeError):
4040
return None
4141

4242

s3proxy/dashboard/collectors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def _latency_percentiles(cumulative: dict[str, float] | None = None) -> dict[str
134134
continue
135135
try:
136136
buckets.append((float(le), float(count)))
137-
except ValueError, TypeError:
137+
except (ValueError, TypeError):
138138
continue
139139
if total < 1 and buckets:
140140
total = max(c for _, c in buckets)

s3proxy/dashboard/stats_store.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ async def series(self, metric: str, range_key: str) -> tuple[list[float], list[f
561561
for k, v in raw.items():
562562
try:
563563
points.append((int(k), float(v)))
564-
except ValueError, TypeError:
564+
except (ValueError, TypeError):
565565
continue
566566
return bucket_series(points, window, bucket)
567567

@@ -642,7 +642,7 @@ def _hfloat(h: dict, field: bytes) -> float:
642642
return 0.0
643643
try:
644644
return float(v)
645-
except ValueError, TypeError:
645+
except (ValueError, TypeError):
646646
return 0.0
647647

648648

@@ -652,7 +652,7 @@ def _decode_float_map(h: dict) -> dict[str, float]:
652652
key = k.decode() if isinstance(k, bytes) else str(k)
653653
try:
654654
out[key] = float(v)
655-
except ValueError, TypeError:
655+
except (ValueError, TypeError):
656656
continue
657657
return out
658658

@@ -665,7 +665,7 @@ def _loads_sample(raw: bytes) -> RequestSample | None:
665665
try:
666666
d = orjson.loads(raw)
667667
return RequestSample(**d)
668-
except ValueError, TypeError:
668+
except (ValueError, TypeError):
669669
return None
670670

671671

s3proxy/request_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ async def _handle_proxy_request_impl(
214214
dispatcher = RequestDispatcher(handler)
215215
try:
216216
return await dispatcher.dispatch(request, verified_creds)
217-
except HTTPException, S3Error:
217+
except (HTTPException, S3Error):
218218
raise
219219
except UnknownKidError as e:
220220
logger.warning("Cannot decrypt object: key not configured", kid=e.kid)

s3proxy/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def parse_http_date(date_str: str | None) -> datetime | None:
1717
return None
1818
try:
1919
return parsedate_to_datetime(date_str)
20-
except ValueError, TypeError:
20+
except (ValueError, TypeError):
2121
return None
2222

2323

tests/unit/test_list_objects_parallel.py

Lines changed: 5 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,59 +3,18 @@
33
Sequential HEADs on a recursive list stack into a client-timeout-tripping stall.
44
This proves: HEADs run concurrently, output order matches input order, internal
55
keys are skipped, and a failing HEAD falls back to the listed size/etag.
6-
7-
The repo's package __init__ chain currently pulls in modules with pre-existing
8-
Py2 `except A, B:` syntax (utils.py, dashboard/*) that won't import under Py3,
9-
so we load buckets.py directly with stubbed siblings to exercise the real code.
106
"""
117

128
import asyncio
139
import datetime as dt
14-
import importlib.util
15-
import sys
16-
import types
17-
from pathlib import Path
18-
19-
REPO = Path(__file__).resolve().parents[2]
20-
21-
22-
def _load_buckets():
23-
def stub(name, **attrs):
24-
m = types.ModuleType(name)
25-
for k, v in attrs.items():
26-
setattr(m, k, v)
27-
sys.modules[name] = m
28-
return m
29-
30-
stub("s3proxy")
31-
stub("s3proxy.handlers")
32-
stub("s3proxy.xml_responses")
33-
stub("s3proxy.client", S3Credentials=object)
34-
stub("s3proxy.errors", S3Error=type("S3Error", (Exception,), {}))
35-
stub(
36-
"s3proxy.state",
37-
INTERNAL_PREFIX="s3proxy-internal/",
38-
META_SUFFIX_LEGACY=".s3proxy-meta",
39-
delete_multipart_metadata=lambda *a, **k: None,
40-
)
41-
stub("s3proxy.xml_utils", find_element=lambda *a, **k: None, find_elements=lambda *a, **k: [])
42-
stub("s3proxy.handlers.base", BaseHandler=object)
43-
44-
spec = importlib.util.spec_from_file_location(
45-
"s3proxy.handlers.buckets", REPO / "s3proxy" / "handlers" / "buckets.py"
46-
)
47-
mod = importlib.util.module_from_spec(spec)
48-
sys.modules["s3proxy.handlers.buckets"] = mod
49-
spec.loader.exec_module(mod)
50-
return mod
51-
52-
53-
buckets = _load_buckets()
10+
11+
from s3proxy.handlers.buckets import LIST_HEAD_CONCURRENCY, BucketHandlerMixin
12+
5413
INTERNAL_PREFIX = "s3proxy-internal/"
5514

5615

5716
class FakeHandler:
58-
_process_list_objects = buckets.BucketHandlerMixin._process_list_objects
17+
_process_list_objects = BucketHandlerMixin._process_list_objects
5918

6019
def __init__(self):
6120
self.inflight = 0
@@ -120,7 +79,7 @@ def test_parallel_order_and_fallback():
12079
assert result[1]["etag"] == "raw-etag"
12180
# HEADs actually ran concurrently (would be 1 if sequential), and stayed bounded.
12281
assert handler.max_inflight > 1
123-
assert handler.max_inflight <= buckets.LIST_HEAD_CONCURRENCY
82+
assert handler.max_inflight <= LIST_HEAD_CONCURRENCY
12483

12584

12685
if __name__ == "__main__":

0 commit comments

Comments
 (0)