11
11
_PathParents ,
12
12
)
13
13
14
- import shutil
15
14
import sys
16
15
from typing import (
17
16
overload ,
33
32
)
34
33
from urllib .parse import urlparse
35
34
from warnings import warn
35
+ import weakref
36
36
37
37
if sys .version_info >= (3 , 10 ):
38
38
from typing import TypeGuard
@@ -58,6 +58,7 @@ def _make_selector(pattern_parts, _flavour, case_sensitive=True):
58
58
59
59
from . import anypath
60
60
61
+ from .cache_utils import _clear_cache
61
62
from .exceptions import (
62
63
ClientMismatchError ,
63
64
CloudPathFileExistsError ,
@@ -188,6 +189,20 @@ def __init__(cls, name: str, bases: Tuple[type, ...], dic: Dict[str, Any]) -> No
188
189
getattr (cls , attr ).fget .__doc__ = docstring
189
190
190
191
192
+ def _cloudpath_finalizer (handle : Optional [IO ], client : Optional ["Client" ], _no_prefix : str ):
193
+ """Use weakref.finalizer instead of __del__ since it is more reliable (does
194
+ not wait for garbage collection to actually run).
195
+ """
196
+ # make sure that file handle to local path is closed
197
+ if handle is not None :
198
+ handle .close ()
199
+
200
+ # ensure file removed from cache when cloudpath object deleted
201
+ if client is not None :
202
+ if getattr (client , "file_cache_mode" , None ) == FileCacheMode .cloudpath_object :
203
+ _clear_cache (client ._local_cache_dir / _no_prefix )
204
+
205
+
191
206
# Abstract base class
192
207
class CloudPath (metaclass = CloudPathMeta ):
193
208
"""Base class for cloud storage file URIs, in the style of the Python standard library's
@@ -242,23 +257,16 @@ def __init__(
242
257
# track if local has been written to, if so it may need to be uploaded
243
258
self ._dirty = False
244
259
260
+ # register cache cleanup method when this object is marked for garbage collection
261
+ weakref .finalize (self , _cloudpath_finalizer , self ._handle , self ._client , self ._no_prefix )
262
+
245
263
@property
246
264
def client (self ):
247
265
if getattr (self , "_client" , None ) is None :
248
266
self ._client = self ._cloud_meta .client_class .get_default_client ()
249
267
250
268
return self ._client
251
269
252
- def __del__ (self ) -> None :
253
- # make sure that file handle to local path is closed
254
- if self ._handle is not None :
255
- self ._handle .close ()
256
-
257
- # ensure file removed from cache when cloudpath object deleted
258
- client = getattr (self , "_client" , None )
259
- if getattr (client , "file_cache_mode" , None ) == FileCacheMode .cloudpath_object :
260
- self .clear_cache ()
261
-
262
270
def __getstate__ (self ) -> Dict [str , Any ]:
263
271
state = self .__dict__ .copy ()
264
272
@@ -1088,11 +1096,7 @@ def copytree(self, destination, force_overwrite_to_cloud=None, ignore=None):
1088
1096
1089
1097
def clear_cache (self ):
1090
1098
"""Removes cache if it exists"""
1091
- if self ._local .exists ():
1092
- if self ._local .is_file ():
1093
- self ._local .unlink ()
1094
- else :
1095
- shutil .rmtree (self ._local )
1099
+ _clear_cache (self ._local )
1096
1100
1097
1101
# =========== private cloud methods ===============
1098
1102
@property
0 commit comments