|
37 | 37 | import re |
38 | 38 | import uuid |
39 | 39 | import warnings |
| 40 | +import weakref |
40 | 41 | from abc import ABC, abstractmethod |
41 | 42 | from collections.abc import Callable, Iterable, Iterator |
42 | 43 | from copy import copy |
@@ -396,11 +397,30 @@ def to_input_file(self) -> PyArrowFile: |
396 | 397 | return self |
397 | 398 |
|
398 | 399 |
|
| 400 | +def _fs_by_scheme_cache(file_io: PyArrowFileIO) -> Callable[[str, str | None], FileSystem]: |
| 401 | + """Return a cached FileSystem factory that only weakly references ``file_io``. |
| 402 | +
|
| 403 | + Caching the bound method ``file_io._initialize_fs`` directly would make the cache hold |
| 404 | + ``file_io`` while ``file_io`` holds the cache. That reference cycle keeps the FileIO and |
| 405 | + its cached filesystems (and their connection pools) alive until the cycle collector runs. |
| 406 | + """ |
| 407 | + file_io_ref = weakref.ref(file_io) |
| 408 | + |
| 409 | + @lru_cache |
| 410 | + def fs_by_scheme(scheme: str, netloc: str | None = None) -> FileSystem: |
| 411 | + io = file_io_ref() |
| 412 | + if io is None: |
| 413 | + raise ReferenceError("PyArrowFileIO has already been garbage collected") |
| 414 | + return io._initialize_fs(scheme, netloc) |
| 415 | + |
| 416 | + return fs_by_scheme |
| 417 | + |
| 418 | + |
399 | 419 | class PyArrowFileIO(FileIO): |
400 | 420 | fs_by_scheme: Callable[[str, str | None], FileSystem] |
401 | 421 |
|
402 | 422 | def __init__(self, properties: Properties = EMPTY_DICT): |
403 | | - self.fs_by_scheme: Callable[[str, str | None], FileSystem] = lru_cache(self._initialize_fs) |
| 423 | + self.fs_by_scheme: Callable[[str, str | None], FileSystem] = _fs_by_scheme_cache(self) |
404 | 424 | super().__init__(properties=properties) |
405 | 425 |
|
406 | 426 | @staticmethod |
@@ -725,7 +745,7 @@ def __getstate__(self) -> dict[str, Any]: |
725 | 745 | def __setstate__(self, state: dict[str, Any]) -> None: |
726 | 746 | """Deserialize the state into a PyArrowFileIO instance.""" |
727 | 747 | self.__dict__ = state |
728 | | - self.fs_by_scheme = lru_cache(self._initialize_fs) |
| 748 | + self.fs_by_scheme = _fs_by_scheme_cache(self) |
729 | 749 |
|
730 | 750 |
|
731 | 751 | def schema_to_pyarrow( |
|
0 commit comments