11from contextlib import contextmanager
22from tarfile import open as tarfile_open
33from tempfile import NamedTemporaryFile
4+ from os import remove as os_remove
45
56try :
67 import zstandard
@@ -14,29 +15,47 @@ def __init__(self, **kwargs):
1415
1516 @contextmanager
1617 def read (self , path : str , mode : str ):
17- with NamedTemporaryFile () as decompressed :
18- with open (path , 'rb' ) as compressed :
19- zstd = zstandard .ZstdDecompressor (** self .zstd_kwargs )
20- zstd .copy_stream (compressed , decompressed )
21- decompressed .seek (0 )
22- archive = tarfile_open (mode = mode , fileobj = decompressed )
23- try :
24- yield archive
25- finally :
26- archive .close ()
18+ try :
19+ with NamedTemporaryFile (delete = False ) as decompressed :
20+ with open (path , 'rb' ) as compressed :
21+ zstd = zstandard .ZstdDecompressor (** self .zstd_kwargs )
22+ zstd .copy_stream (compressed , decompressed )
23+ decompressed .seek (0 )
24+ archive = tarfile_open (mode = mode , fileobj = decompressed )
25+ try :
26+ yield archive
27+ finally :
28+ archive .close ()
29+ finally :
30+ # We delete it manually because otherwise on Windows
31+ # it gets deleted before we move it to the output file location.
32+ # This is because on Windows, file handles with the O_TEMPORARY
33+ # flag (which is set if we pass `delete=True`) are deleted as
34+ # soon as they're closed.
35+ decompressed .close ()
36+ os_remove (decompressed .name )
2737
2838 @contextmanager
2939 def write (self , path : str , mode : str ):
30- with NamedTemporaryFile () as decompressed :
31- archive = tarfile_open (decompressed .name , mode = mode )
32- try :
33- yield archive
34- finally :
35- archive .close ()
36- decompressed .seek (0 )
37- with open (path , 'wb' ) as compressed :
38- zstd = zstandard .ZstdCompressor (** self .zstd_kwargs )
39- zstd .copy_stream (decompressed , compressed )
40+ try :
41+ with NamedTemporaryFile (delete = False ) as decompressed :
42+ archive = tarfile_open (decompressed .name , mode = mode )
43+ try :
44+ yield archive
45+ finally :
46+ archive .close ()
47+ decompressed .seek (0 )
48+ with open (path , 'wb' ) as compressed :
49+ zstd = zstandard .ZstdCompressor (** self .zstd_kwargs )
50+ zstd .copy_stream (decompressed , compressed )
51+ finally :
52+ # We delete it manually because otherwise on Windows
53+ # it gets deleted before we move it to the output file location.
54+ # This is because on Windows, file handles with the O_TEMPORARY
55+ # flag (which is set if we pass `delete=True`) are deleted as
56+ # soon as they're closed.
57+ decompressed .close ()
58+ os_remove (decompressed .name )
4059
4160
4261if zstandard is None :
0 commit comments