Skip to content

Commit 08aaa02

Browse files
committed
Fix failing py3.13 tests, impl details.
1 parent 15c418a commit 08aaa02

1 file changed

Lines changed: 69 additions & 62 deletions

File tree

tests/test_df.py

Lines changed: 69 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -330,45 +330,48 @@ def test_from_map_batched_integration_with_datafusion_via_read_xarray():
330330

331331

332332
def test_read_xarray_loads_one_chunk_at_a_time(large_ds):
333+
tracemalloc.stop() # reset any state left by a previously-failed test
333334
tracemalloc.start()
334-
iterable = read_xarray(large_ds)
335-
first_size, first_peak = tracemalloc.get_traced_memory()
336-
tracemalloc.reset_peak()
335+
try:
336+
iterable = read_xarray(large_ds)
337+
first_size, first_peak = tracemalloc.get_traced_memory()
338+
tracemalloc.reset_peak()
337339

338-
sizes, peaks = [], []
340+
sizes, peaks = [], []
339341

340-
first_chunk = large_ds.isel(next(block_slices(large_ds)))
341-
chunk_size = first_chunk.nbytes
342+
first_chunk = large_ds.isel(next(block_slices(large_ds)))
343+
chunk_size = first_chunk.nbytes
342344

343-
# Creating the iterator should be inexpensive -- less than one chunk.
344-
# We multiply by constant factors because chunks have additional overhead
345-
assert first_size < chunk_size * 3
346-
assert first_peak < chunk_size * 6
347-
348-
for it in iterable:
349-
_ = it
350-
cur_size, cur_peak = tracemalloc.get_traced_memory()
351-
tracemalloc.reset_peak()
352-
sizes.append(cur_size)
353-
peaks.append(cur_peak)
345+
# Creating the iterator should be inexpensive -- less than one chunk.
346+
# We multiply by constant factors because chunks have additional overhead
347+
assert first_size < chunk_size * 3
348+
assert first_peak < chunk_size * 6
354349

355-
for size in sizes:
356-
# Observed range: 1.59–1.83× chunk_size.
357-
# iter_record_batches holds data-variable arrays (≈1× chunk) while
358-
# yielding sub-batches, plus the current Arrow batch (≈0.65× chunk).
359-
assert chunk_size * 1.3 < size, f"size {size} unexpectedly low"
360-
assert chunk_size * 2.2 > size, f"size {size} unexpectedly high"
350+
for it in iterable:
351+
_ = it
352+
cur_size, cur_peak = tracemalloc.get_traced_memory()
353+
tracemalloc.reset_peak()
354+
sizes.append(cur_size)
355+
peaks.append(cur_peak)
361356

362-
for peak in peaks:
363-
# Observed range: 1.84–3.28× chunk_size.
364-
# Peak includes data arrays + Arrow batch + temporary coordinate index
365-
# arrays; the first batch of each chunk is highest (Dask compute overhead).
366-
assert chunk_size * 1.5 < peak, f"peak {peak} unexpectedly low"
367-
assert chunk_size * 4.0 > peak, f"peak {peak} unexpectedly high"
357+
for size in sizes:
358+
# Observed range: 1.59–1.83× on macOS, up to ~2.7× on Linux
359+
# (glibc + Arrow allocate more intermediate buffers).
360+
# iter_record_batches holds data-variable arrays (≈1× chunk) while
361+
# yielding sub-batches, plus the current Arrow batch (≈0.65× chunk).
362+
assert chunk_size * 1.3 < size, f"size {size} unexpectedly low"
363+
assert chunk_size * 3.5 > size, f"size {size} unexpectedly high"
368364

369-
assert max(peaks) < large_ds.nbytes
365+
for peak in peaks:
366+
# Observed range: 1.84–3.28× chunk_size.
367+
# Peak includes data arrays + Arrow batch + temporary coordinate index
368+
# arrays; the first batch of each chunk is highest (Dask compute overhead).
369+
assert chunk_size * 1.5 < peak, f"peak {peak} unexpectedly low"
370+
assert chunk_size * 4.0 > peak, f"peak {peak} unexpectedly high"
370371

371-
tracemalloc.stop()
372+
assert max(peaks) < large_ds.nbytes
373+
finally:
374+
tracemalloc.stop()
372375

373376

374377
def test_read_xarray_table_memory_bounds(large_ds):
@@ -384,37 +387,41 @@ def test_read_xarray_table_memory_bounds(large_ds):
384387
first_chunk = large_ds.isel(next(block_slices(large_ds)))
385388
chunk_size = first_chunk.nbytes
386389

390+
tracemalloc.stop() # reset any state left by a previously-failed test
387391
# --- Registration phase ---
388392
tracemalloc.start()
389-
table = read_xarray_table(large_ds)
390-
reg_size, reg_peak = tracemalloc.get_traced_memory()
391-
tracemalloc.reset_peak()
392-
393-
# The lazy generator only materialises coord arrays (~O(dim sizes)) and
394-
# factory closure objects — no data arrays. Both metrics should be well
395-
# below one chunk of data.
396-
assert reg_size < chunk_size, (
397-
f"Registration held {reg_size} bytes >= chunk_size {chunk_size}: "
398-
"data may have been loaded eagerly"
399-
)
400-
assert (
401-
reg_peak < chunk_size * 2
402-
), f"Registration peak {reg_peak} too high (expected < 2× chunk_size {chunk_size})"
403-
404-
# --- Query phase ---
405-
ctx = SessionContext()
406-
ctx.register_table("weather", table)
407-
ctx.sql("SELECT AVG(temperature), AVG(precipitation) FROM weather").collect()
408-
_, query_peak = tracemalloc.get_traced_memory()
409-
410-
# tracemalloc measures Python-heap allocations, which include Arrow
411-
# buffer copies and object overhead on top of the raw data. The
412-
# observed peak is typically 1.1–1.5× the raw dataset size; we use
413-
# 2× as a generous bound that would still catch catastrophic regressions
414-
# (e.g. loading all partitions twice simultaneously).
415-
assert query_peak < large_ds.nbytes * 2, (
416-
f"Query peak {query_peak} >= 2× dataset {large_ds.nbytes}: "
417-
"may be holding excessive data in memory"
418-
)
393+
try:
394+
table = read_xarray_table(large_ds)
395+
reg_size, reg_peak = tracemalloc.get_traced_memory()
396+
tracemalloc.reset_peak()
419397

420-
tracemalloc.stop()
398+
# The lazy generator only materialises coord arrays (~O(dim sizes)) and
399+
# factory closure objects — no data arrays. Both metrics should be well
400+
# below one chunk of data.
401+
assert reg_size < chunk_size, (
402+
f"Registration held {reg_size} bytes >= chunk_size {chunk_size}: "
403+
"data may have been loaded eagerly"
404+
)
405+
assert (
406+
reg_peak < chunk_size * 2
407+
), f"Registration peak {reg_peak} too high (expected < 2× chunk_size {chunk_size})"
408+
409+
# --- Query phase ---
410+
ctx = SessionContext()
411+
ctx.register_table("weather", table)
412+
ctx.sql(
413+
"SELECT AVG(temperature), AVG(precipitation) FROM weather"
414+
).collect()
415+
_, query_peak = tracemalloc.get_traced_memory()
416+
417+
# tracemalloc measures Python-heap allocations, which include Arrow
418+
# buffer copies and object overhead on top of the raw data. The
419+
# observed peak is typically 1.1–1.5× the raw dataset size; we use
420+
# 2× as a generous bound that would still catch catastrophic regressions
421+
# (e.g. loading all partitions twice simultaneously).
422+
assert query_peak < large_ds.nbytes * 2, (
423+
f"Query peak {query_peak} >= 2× dataset {large_ds.nbytes}: "
424+
"may be holding excessive data in memory"
425+
)
426+
finally:
427+
tracemalloc.stop()

0 commit comments

Comments
 (0)