Commit ff6da8f
fix(FsspecStore): close owned async filesystem on store.close() (#4003)
* fix(FsspecStore): close owned async filesystem on store.close()
FsspecStore.from_url() and from_mapper() create their own async
filesystem instance that zarr is responsible for — but Store.close()
never cleaned it up, leaving the underlying aiohttp ClientSession open
until garbage collection. This produced "Unclosed client session"
ResourceWarnings from aiohttp, and in environments where the finalizer
ran on the wrong event loop (e.g. Python 3.12+ with eager_start=True)
it could raise RuntimeError.
Changes:
- Add _close_fs() async helper: calls fs.set_session() then
client.close() for filesystems that expose set_session() (e.g.
s3fs); no-op for all others.
- Add _owns_fs: bool to FsspecStore.__init__ (default False).
Set True in from_url() unconditionally; set True in from_mapper()
only when _make_async() produced a new instance (sync→async wrap).
Direct construction and from_upath() leave _owns_fs=False — the
caller supplied the fs and remains responsible for it.
- Override close() to invoke zarr_sync(_close_fs(self.fs)) before
calling super().close(), guarded by _owns_fs and a bare except so
it can never raise from a destructor path.
Tests:
- Update pytestmark comment (the filter stays for GC-path warnings).
- test_from_url_owns_filesystem / test_from_url_close_releases_store
- test_direct_construction_does_not_own_filesystem
- test_from_upath_does_not_own_filesystem
- test_from_mapper_does_not_own_already_async_filesystem
- test_from_mapper_owns_wrapped_sync_filesystem
- test_close_fs_closes_s3_client / test_close_fs_no_op_for_fs_without_set_session
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix lint: use contextlib.suppress instead of try/except/pass (SIM105)
* add towncrier release note for #4003
* changes: expand 4003 release note to document fix scope and s3fs limitation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(FsspecStore): propagate fs ownership through with_read_only
Addresses roborev review findings on the filesystem-ownership change:
- with_read_only() transferred fs ownership: it built the derived store
with _owns_fs=False while sharing the same fs. In the common
from_url(...).with_read_only() chain the only owner (the unreferenced
source) was GC'd without close(), reintroducing the unclosed-session
leak. Ownership now transfers to the surviving store and is cleared on
the source to avoid a double-close. Covered by a new test.
- close() now logs at debug before suppressing, so a regression in the
close path stays observable instead of silently reverting to leaking.
- Documented that set_session() lazily creates a session, so closing a
store that never did I/O may instantiate one purely to close it
(accepted best-effort behavior).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>1 parent 1cda981 commit ff6da8f
3 files changed
Lines changed: 224 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| 22 | + | |
| 23 | + | |
21 | 24 | | |
22 | 25 | | |
23 | 26 | | |
| |||
35 | 38 | | |
36 | 39 | | |
37 | 40 | | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
38 | 61 | | |
39 | 62 | | |
40 | 63 | | |
| |||
129 | 152 | | |
130 | 153 | | |
131 | 154 | | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
132 | 158 | | |
133 | 159 | | |
134 | 160 | | |
| |||
194 | 220 | | |
195 | 221 | | |
196 | 222 | | |
197 | | - | |
198 | | - | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
199 | 226 | | |
200 | 227 | | |
201 | 228 | | |
202 | 229 | | |
203 | 230 | | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
204 | 234 | | |
205 | 235 | | |
206 | 236 | | |
| |||
242 | 272 | | |
243 | 273 | | |
244 | 274 | | |
245 | | - | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
246 | 278 | | |
247 | 279 | | |
248 | 280 | | |
249 | | - | |
| 281 | + | |
250 | 282 | | |
251 | 283 | | |
252 | 284 | | |
253 | 285 | | |
254 | 286 | | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
255 | 308 | | |
256 | 309 | | |
257 | 310 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
39 | | - | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
40 | 42 | | |
41 | 43 | | |
42 | 44 | | |
| |||
283 | 285 | | |
284 | 286 | | |
285 | 287 | | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
286 | 357 | | |
287 | 358 | | |
288 | 359 | | |
| |||
512 | 583 | | |
513 | 584 | | |
514 | 585 | | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
515 | 662 | | |
516 | 663 | | |
517 | 664 | | |
| |||
0 commit comments