Skip to content

Commit adeda66

Browse files
committed
test: review skipped tests (networking timeouts) (#1027)
* return a http.client.HTTPException instead of OSError * rerun tests on http.client.HTTPException * remove test skip for xrootd * rename test * rename test * do not capitalize variables * correctly load default options * timeout error * update test (TODO: review) * add TimeoutError to retry exceptions * correctly initialized num_bytes * correctly access resource * rerun on timeout * update retry regex * remove outdated test
1 parent 63315f3 commit adeda66

File tree

11 files changed

+52
-85
lines changed

11 files changed

+52
-85
lines changed

.github/workflows/build-test.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,7 @@ jobs:
6767

6868
- name: Run pytest
6969
run: |
70-
python -m pytest -vv tests \
71-
--reruns 3 --reruns-delay 30 \
72-
--only-rerun requests.exceptions.HTTPError
70+
python -m pytest -vv tests --reruns 3 --reruns-delay 30 --only-rerun "(?i)http|timeout"
7371
7472
vanilla-build:
7573
strategy:
@@ -93,4 +91,4 @@ jobs:
9391

9492
- name: Run pytest
9593
run: |
96-
python -m pytest -vv tests --reruns 3 --reruns-delay 30 --only-rerun requests.exceptions.HTTPError
94+
python -m pytest -vv tests --reruns 3 --reruns-delay 30 --only-rerun "(?i)http|timeout"

src/uproot/source/chunk.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ class Resource:
3030
:doc:`uproot.source.futures.ResourceFuture`.
3131
"""
3232

33+
def __init__(self):
34+
self._file_path = None
35+
3336
@property
3437
def file_path(self) -> str:
3538
"""
@@ -49,6 +52,14 @@ class Source:
4952
the file.
5053
"""
5154

55+
def __init__(self):
56+
self._num_requested_bytes = 0
57+
self._num_requests = 0
58+
self._num_requested_chunks = 0
59+
self._file_path = None
60+
self._num_bytes = None
61+
self._executor = None
62+
5263
def chunk(self, start: int, stop: int) -> Chunk:
5364
"""
5465
Args:
@@ -139,6 +150,9 @@ def closed(self) -> bool:
139150
True if the associated file/connection/thread pool is closed; False
140151
otherwise.
141152
"""
153+
if self._executor is None:
154+
return True
155+
142156
return self._executor.closed
143157

144158

src/uproot/source/fsspec.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ class FSSpecSource(uproot.source.chunk.Source):
2727
"""
2828

2929
def __init__(self, file_path: str, **options):
30-
default_options = uproot.reading.open.defaults
31-
32-
exclude_keys = set(default_options.keys())
33-
storage_options = {k: v for k, v in options.items() if k not in exclude_keys}
30+
options = dict(uproot.reading.open.defaults, **options)
31+
storage_options = {
32+
k: v
33+
for k, v in options.items()
34+
if k not in uproot.reading.open.defaults.keys()
35+
}
3436

3537
self._open()
3638

src/uproot/source/futures.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -453,9 +453,7 @@ def submit(self, future: ResourceFuture) -> ResourceFuture:
453453
"""
454454
assert isinstance(future, ResourceFuture)
455455
if self.closed:
456-
raise OSError(
457-
f"resource is closed for file {self._workers[0].resource.file_path}"
458-
)
456+
raise OSError(f"resource is closed for file {self._resource.file_path}")
459457
future._run(self._resource)
460458
return future
461459

src/uproot/source/http.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def get_num_bytes(file_path: str, parsed_url: urllib.parse.ParseResult, timeout)
106106
response = connection.getresponse()
107107
break
108108
else:
109-
raise OSError(
109+
raise http.client.HTTPException(
110110
"""remote server responded with status {} (redirect) without a 'location'
111111
for URL {}""".format(
112112
response.status, file_path
@@ -119,7 +119,7 @@ def get_num_bytes(file_path: str, parsed_url: urllib.parse.ParseResult, timeout)
119119

120120
if response.status != 200:
121121
connection.close()
122-
raise OSError(
122+
raise http.client.HTTPException(
123123
"""HTTP response was {}, rather than 200, in attempt to get file size
124124
in file {}""".format(
125125
response.status, file_path
@@ -132,7 +132,7 @@ def get_num_bytes(file_path: str, parsed_url: urllib.parse.ParseResult, timeout)
132132
return int(x)
133133
else:
134134
connection.close()
135-
raise OSError(
135+
raise http.client.HTTPException(
136136
"""response headers did not include content-length: {}
137137
in file {}""".format(
138138
dict(response.getheaders()), file_path
@@ -216,7 +216,7 @@ def get(self, connection, start: int, stop: int) -> bytes:
216216
)
217217
return self.get(redirect, start, stop)
218218

219-
raise OSError(
219+
raise http.client.HTTPException(
220220
"""remote server responded with status {} (redirect) without a 'location'
221221
for URL {}""".format(
222222
response.status, self._file_path
@@ -225,7 +225,7 @@ def get(self, connection, start: int, stop: int) -> bytes:
225225

226226
if response.status != 206:
227227
connection.close()
228-
raise OSError(
228+
raise http.client.HTTPException(
229229
"""remote server responded with status {}, rather than 206 (range requests)
230230
for URL {}""".format(
231231
response.status, self._file_path
@@ -322,7 +322,7 @@ def task(resource):
322322
task(resource)
323323
return
324324

325-
raise OSError(
325+
raise http.client.HTTPException(
326326
"""remote server responded with status {} (redirect) without a 'location'
327327
for URL {}""".format(
328328
response.status, source.file_path
@@ -428,7 +428,7 @@ def handle_multipart(
428428
data = response_buffer.read(length)
429429

430430
if len(data) != length:
431-
raise OSError(
431+
raise http.client.HTTPException(
432432
"""wrong chunk length {} (expected {}) for byte range {} "
433433
"in HTTP multipart
434434
for URL {}""".format(
@@ -454,7 +454,7 @@ def handle_multipart(
454454
else:
455455
range_string = range_string.decode("utf-8", "surrogateescape")
456456
expecting = ", ".join(f"{a}-{b - 1}" for a, b in futures)
457-
raise OSError(
457+
raise http.client.HTTPException(
458458
"""unrecognized byte range in headers of HTTP multipart: {}
459459
460460
expecting: {}

src/uproot/source/xrootd.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ def get_server_config(file):
6363
XRootD_client.flags.QueryCode.CONFIG, "readv_iov_max readv_ior_max"
6464
)
6565
if status.error:
66-
raise OSError(status.message)
66+
if status.code in (206,):
67+
raise TimeoutError(status.message)
68+
else:
69+
raise OSError(status.message)
6770

6871
# Result is something like b'178956968\n2097136\n'
6972
readv_iov_max, readv_ior_max = map(int, result.split(b"\n", 1))
@@ -121,12 +124,12 @@ def _xrd_error(self, status):
121124
# https://github.com/xrootd/xrootd/blob/250eced4d3787c2ac5be2c8c922134153bbf7f08/src/XrdCl/XrdClStatus.cc#L34-L74
122125
if status.code in (101, 304, 400):
123126
raise uproot._util._file_not_found(self._file_path, status.message)
124-
125-
else:
126-
raise OSError(
127-
f"""XRootD error: {status.message}
128-
in file {self._file_path}"""
127+
elif status.code in (206,):
128+
raise TimeoutError(
129+
f"XRootD error: {status.message} in file {self._file_path}"
129130
)
131+
else:
132+
raise OSError(f"XRootD error: {status.message} in file {self._file_path}")
130133

131134
@property
132135
def timeout(self) -> float | None:
@@ -266,6 +269,8 @@ class XRootDSource(uproot.source.chunk.Source):
266269
ResourceClass = XRootDResource
267270

268271
def __init__(self, file_path: str, **options):
272+
options = dict(uproot.reading.open.defaults, **options)
273+
269274
self._timeout = options["timeout"]
270275
self._desired_max_num_elements = options["max_num_elements"]
271276
self._use_threads = options["use_threads"]
@@ -285,7 +290,7 @@ def _open(self):
285290
# futures that wait for chunks that have been split to merge them.
286291
if self._use_threads:
287292
self._executor = uproot.source.futures.ResourceThreadPoolExecutor(
288-
[trivial_resource() for x in range(self._num_workers)]
293+
[trivial_resource() for _ in range(self._num_workers)]
289294
)
290295
else:
291296
self._executor = uproot.source.futures.ResourceTrivialExecutor(
@@ -458,6 +463,8 @@ class MultithreadedXRootDSource(uproot.source.chunk.MultithreadedSource):
458463
ResourceClass = XRootDResource
459464

460465
def __init__(self, file_path: str, **options):
466+
options = dict(uproot.reading.open.defaults, **options)
467+
461468
self._num_workers = options["num_workers"]
462469
self._timeout = options["timeout"]
463470
self._use_threads = options["use_threads"]
@@ -501,5 +508,9 @@ def timeout(self) -> float | None:
501508
@property
502509
def num_bytes(self) -> int:
503510
if self._num_bytes is None:
504-
self._num_bytes = self._executor.workers[0].resource.num_bytes
511+
if hasattr(self._executor, "workers"):
512+
self._num_bytes = self._executor.workers[0].resource.num_bytes
513+
else:
514+
self._num_bytes = self._executor._resource.num_bytes
515+
505516
return self._num_bytes

tests/test_0001_source_class.py

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -299,9 +299,6 @@ def test_fallback(server, use_threads, num_workers):
299299
assert one[:4] == b"root"
300300

301301

302-
@pytest.mark.skip(
303-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
304-
)
305302
@pytest.mark.network
306303
@pytest.mark.xrootd
307304
@pytest.mark.parametrize("use_threads", [True, False], indirect=True)
@@ -322,22 +319,6 @@ def test_xrootd(use_threads):
322319
assert one[:4] == b"root"
323320

324321

325-
@pytest.mark.skip(
326-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
327-
)
328-
@pytest.mark.network
329-
@pytest.mark.xrootd
330-
@pytest.mark.parametrize("use_threads", [True, False], indirect=True)
331-
def test_xrootd_deadlock(use_threads):
332-
pytest.importorskip("XRootD")
333-
# Attach this file to the "test_xrootd_deadlock" function, so it leaks
334-
pytest.uproot_test_xrootd_deadlock_f = uproot.source.xrootd.XRootDResource(
335-
"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/Run2012B_DoubleMuParked.root",
336-
timeout=20,
337-
use_threads=use_threads,
338-
)
339-
340-
341322
@pytest.mark.network
342323
@pytest.mark.xrootd
343324
@pytest.mark.parametrize("use_threads", [True, False], indirect=True)
@@ -352,9 +333,6 @@ def test_xrootd_fail(use_threads):
352333
)
353334

354335

355-
@pytest.mark.skip(
356-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
357-
)
358336
@pytest.mark.network
359337
@pytest.mark.xrootd
360338
@pytest.mark.parametrize("use_threads", [True, False], indirect=True)
@@ -376,9 +354,6 @@ def test_xrootd_vectorread(use_threads):
376354
assert one[:4] == b"root"
377355

378356

379-
@pytest.mark.skip(
380-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
381-
)
382357
@pytest.mark.network
383358
@pytest.mark.xrootd
384359
@pytest.mark.parametrize("use_threads", [True, False], indirect=True)
@@ -398,18 +373,15 @@ def test_xrootd_vectorread_max_element_split(use_threads):
398373
assert len(one) == max_element_size + 1
399374

400375

401-
@pytest.mark.skip(
402-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
403-
)
404376
@pytest.mark.network
405377
@pytest.mark.xrootd
406378
@pytest.mark.parametrize("use_threads", [True, False], indirect=True)
407379
def test_xrootd_vectorread_max_element_split_consistency(use_threads):
408380
pytest.importorskip("XRootD")
409381
filename = "root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/Run2012B_DoubleMuParked.root"
410382

411-
def get_chunk(Source, **kwargs):
412-
with Source(filename, **kwargs) as source:
383+
def get_chunk(source_cls, **kwargs):
384+
with source_cls(filename, **kwargs) as source:
413385
notifications = queue.Queue()
414386
max_element_size = 2097136
415387
chunks = source.chunks([(0, max_element_size + 1)], notifications)
@@ -444,9 +416,6 @@ def test_xrootd_vectorread_fail(use_threads):
444416
)
445417

446418

447-
@pytest.mark.skip(
448-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
449-
)
450419
@pytest.mark.network
451420
@pytest.mark.xrootd
452421
@pytest.mark.parametrize("use_threads", [True, False], indirect=True)
@@ -461,7 +430,6 @@ def test_xrootd_size(use_threads):
461430
) as source:
462431
size1 = source.num_bytes
463432

464-
pytest.importorskip("XRootD")
465433
with uproot.source.xrootd.MultithreadedXRootDSource(
466434
"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/Run2012B_DoubleMuParked.root",
467435
timeout=10,
@@ -474,9 +442,6 @@ def test_xrootd_size(use_threads):
474442
assert size1 == 3469136394
475443

476444

477-
@pytest.mark.skip(
478-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
479-
)
480445
@pytest.mark.network
481446
@pytest.mark.xrootd
482447
@pytest.mark.parametrize("use_threads", [True, False], indirect=True)

tests/test_0006_notify_when_downloaded.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,6 @@ def test_http_fallback_workers(server):
145145
expected.pop((chunk.start, chunk.stop))
146146

147147

148-
@pytest.mark.skip(
149-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
150-
)
151148
@pytest.mark.network
152149
@pytest.mark.xrootd
153150
def test_xrootd():
@@ -168,9 +165,6 @@ def test_xrootd():
168165
expected.pop((chunk.start, chunk.stop))
169166

170167

171-
@pytest.mark.skip(
172-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
173-
)
174168
@pytest.mark.network
175169
@pytest.mark.xrootd
176170
def test_xrootd_workers():
@@ -191,9 +185,6 @@ def test_xrootd_workers():
191185
expected.pop((chunk.start, chunk.stop))
192186

193187

194-
@pytest.mark.skip(
195-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
196-
)
197188
@pytest.mark.network
198189
@pytest.mark.xrootd
199190
def test_xrootd_vectorread():

tests/test_0007_single_chunk_interface.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,6 @@ def test_http_multipart_fail():
125125
tobytes(source.chunk(0, 100).raw_data)
126126

127127

128-
@pytest.mark.skip(
129-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
130-
)
131128
@pytest.mark.network
132129
@pytest.mark.xrootd
133130
def test_xrootd():
@@ -147,9 +144,6 @@ def test_xrootd():
147144
assert one[:4] == b"root"
148145

149146

150-
@pytest.mark.skip(
151-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
152-
)
153147
@pytest.mark.network
154148
@pytest.mark.xrootd
155149
def test_xrootd_worker():
@@ -169,9 +163,6 @@ def test_xrootd_worker():
169163
assert one[:4] == b"root"
170164

171165

172-
@pytest.mark.skip(
173-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
174-
)
175166
@pytest.mark.network
176167
@pytest.mark.xrootd
177168
def test_xrootd_vectorread():

tests/test_0302_pickle.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,6 @@ def test_pickle_roundtrip_http():
5353
]
5454

5555

56-
@pytest.mark.skip(
57-
reason="RECHECK: Run2012B_DoubleMuParked.root is super-flaky right now"
58-
)
5956
@pytest.mark.network
6057
@pytest.mark.xrootd
6158
def test_pickle_roundtrip_xrootd():

0 commit comments

Comments
 (0)