pyglove 0.5.0.dev202511240812__py3-none-any.whl → 0.5.0.dev202512080812__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyglove might be problematic. Click here for more details.
- pyglove/core/io/file_system.py +157 -0
- pyglove/core/io/file_system_test.py +151 -0
- {pyglove-0.5.0.dev202511240812.dist-info → pyglove-0.5.0.dev202512080812.dist-info}/METADATA +1 -1
- {pyglove-0.5.0.dev202511240812.dist-info → pyglove-0.5.0.dev202512080812.dist-info}/RECORD +7 -7
- {pyglove-0.5.0.dev202511240812.dist-info → pyglove-0.5.0.dev202512080812.dist-info}/WHEEL +0 -0
- {pyglove-0.5.0.dev202511240812.dist-info → pyglove-0.5.0.dev202512080812.dist-info}/licenses/LICENSE +0 -0
- {pyglove-0.5.0.dev202511240812.dist-info → pyglove-0.5.0.dev202512080812.dist-info}/top_level.txt +0 -0
pyglove/core/io/file_system.py
CHANGED
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
"""Pluggable file system."""
|
|
15
15
|
|
|
16
16
|
import abc
|
|
17
|
+
import datetime
|
|
17
18
|
import fnmatch
|
|
18
19
|
import glob as std_glob
|
|
19
20
|
import io
|
|
20
21
|
import os
|
|
21
22
|
import re
|
|
23
|
+
import shutil
|
|
22
24
|
from typing import Any, Literal, Optional, Union
|
|
23
25
|
|
|
24
26
|
|
|
@@ -99,6 +101,14 @@ class FileSystem(metaclass=abc.ABCMeta):
|
|
|
99
101
|
def isdir(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
100
102
|
"""Returns True if a path is a directory."""
|
|
101
103
|
|
|
104
|
+
@abc.abstractmethod
|
|
105
|
+
def getctime(self, path: Union[str, os.PathLike[str]]) -> float:
|
|
106
|
+
"""Returns the creation time of a file."""
|
|
107
|
+
|
|
108
|
+
@abc.abstractmethod
|
|
109
|
+
def getmtime(self, path: Union[str, os.PathLike[str]]) -> float:
|
|
110
|
+
"""Returns the last modification time of a file."""
|
|
111
|
+
|
|
102
112
|
@abc.abstractmethod
|
|
103
113
|
def mkdir(
|
|
104
114
|
self, path: Union[str, os.PathLike[str]], mode: int = 0o777
|
|
@@ -134,6 +144,14 @@ class FileSystem(metaclass=abc.ABCMeta):
|
|
|
134
144
|
def rmdirs(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
135
145
|
"""Removes a directory chain based on a path."""
|
|
136
146
|
|
|
147
|
+
@abc.abstractmethod
|
|
148
|
+
def copy(
|
|
149
|
+
self,
|
|
150
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
151
|
+
newpath: Union[str, os.PathLike[str]],
|
|
152
|
+
) -> None:
|
|
153
|
+
"""Copies a file to a new path."""
|
|
154
|
+
|
|
137
155
|
|
|
138
156
|
def resolve_path(path: Union[str, os.PathLike[str]]) -> str:
|
|
139
157
|
if isinstance(path, str):
|
|
@@ -202,6 +220,12 @@ class StdFileSystem(FileSystem):
|
|
|
202
220
|
def isdir(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
203
221
|
return os.path.isdir(path)
|
|
204
222
|
|
|
223
|
+
def getctime(self, path: Union[str, os.PathLike[str]]) -> float:
|
|
224
|
+
return os.path.getctime(path)
|
|
225
|
+
|
|
226
|
+
def getmtime(self, path: Union[str, os.PathLike[str]]) -> float:
|
|
227
|
+
return os.path.getmtime(path)
|
|
228
|
+
|
|
205
229
|
def mkdir(
|
|
206
230
|
self, path: Union[str, os.PathLike[str]], mode: int = 0o777
|
|
207
231
|
) -> None:
|
|
@@ -231,6 +255,13 @@ class StdFileSystem(FileSystem):
|
|
|
231
255
|
def rmdirs(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
232
256
|
os.removedirs(path)
|
|
233
257
|
|
|
258
|
+
def copy(
|
|
259
|
+
self,
|
|
260
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
261
|
+
newpath: Union[str, os.PathLike[str]],
|
|
262
|
+
) -> None:
|
|
263
|
+
shutil.copy(oldpath, newpath)
|
|
264
|
+
|
|
234
265
|
|
|
235
266
|
#
|
|
236
267
|
# Memory file system.
|
|
@@ -244,6 +275,9 @@ class MemoryFile(File):
|
|
|
244
275
|
super().__init__()
|
|
245
276
|
self._buffer = buffer
|
|
246
277
|
self._pos = 0
|
|
278
|
+
now = datetime.datetime.now().timestamp()
|
|
279
|
+
self.ctime = now
|
|
280
|
+
self.mtime = now
|
|
247
281
|
|
|
248
282
|
def read(self, size: Optional[int] = None) -> Union[str, bytes]:
|
|
249
283
|
return self._buffer.read(size)
|
|
@@ -253,6 +287,7 @@ class MemoryFile(File):
|
|
|
253
287
|
|
|
254
288
|
def write(self, content: Union[str, bytes]) -> None:
|
|
255
289
|
self._buffer.write(content)
|
|
290
|
+
self.mtime = datetime.datetime.now().timestamp()
|
|
256
291
|
|
|
257
292
|
def seek(self, offset: int, whence: Literal[0, 1, 2] = 0) -> int:
|
|
258
293
|
return self._buffer.seek(offset, whence)
|
|
@@ -336,6 +371,24 @@ class MemoryFileSystem(FileSystem):
|
|
|
336
371
|
def isdir(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
337
372
|
return isinstance(self._locate(path), dict)
|
|
338
373
|
|
|
374
|
+
def getctime(self, path: Union[str, os.PathLike[str]]) -> float:
|
|
375
|
+
"""Returns the creation time of a file."""
|
|
376
|
+
f = self._locate(path)
|
|
377
|
+
if isinstance(f, dict):
|
|
378
|
+
raise IsADirectoryError(path)
|
|
379
|
+
if f is None:
|
|
380
|
+
raise FileNotFoundError(path)
|
|
381
|
+
return f.ctime
|
|
382
|
+
|
|
383
|
+
def getmtime(self, path: Union[str, os.PathLike[str]]) -> float:
|
|
384
|
+
"""Returns the last modification time of a file."""
|
|
385
|
+
f = self._locate(path)
|
|
386
|
+
if isinstance(f, dict):
|
|
387
|
+
raise IsADirectoryError(path)
|
|
388
|
+
if f is None:
|
|
389
|
+
raise FileNotFoundError(path)
|
|
390
|
+
return f.mtime
|
|
391
|
+
|
|
339
392
|
def _parent_and_name(
|
|
340
393
|
self, path: Union[str, os.PathLike[str]]
|
|
341
394
|
) -> tuple[dict[str, Any], str]:
|
|
@@ -460,6 +513,37 @@ class MemoryFileSystem(FileSystem):
|
|
|
460
513
|
return not dir_dict
|
|
461
514
|
_rmdir(self._root, self._internal_path(path))
|
|
462
515
|
|
|
516
|
+
def copy(
|
|
517
|
+
self,
|
|
518
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
519
|
+
newpath: Union[str, os.PathLike[str]],
|
|
520
|
+
) -> None:
|
|
521
|
+
old_file = self._locate(oldpath)
|
|
522
|
+
if old_file is None:
|
|
523
|
+
raise FileNotFoundError(oldpath)
|
|
524
|
+
if not isinstance(old_file, MemoryFile):
|
|
525
|
+
raise IsADirectoryError(oldpath)
|
|
526
|
+
|
|
527
|
+
if self.isdir(newpath):
|
|
528
|
+
_, old_file_name = self._parent_and_name(oldpath)
|
|
529
|
+
newpath = resolve_path(newpath)
|
|
530
|
+
newpath = newpath.rstrip('/') + '/' + old_file_name
|
|
531
|
+
|
|
532
|
+
# If newpath exists as file, remove it for overwrite.
|
|
533
|
+
if self.exists(newpath) and not self.isdir(newpath):
|
|
534
|
+
self.rm(newpath)
|
|
535
|
+
elif self.isdir(newpath):
|
|
536
|
+
raise IsADirectoryError(newpath)
|
|
537
|
+
|
|
538
|
+
old_pos = old_file.tell()
|
|
539
|
+
old_file.seek(0)
|
|
540
|
+
content = old_file.read()
|
|
541
|
+
old_file.seek(old_pos)
|
|
542
|
+
|
|
543
|
+
is_binary = isinstance(old_file._buffer, io.BytesIO) # pylint: disable=protected-access
|
|
544
|
+
with self.open(newpath, 'wb' if is_binary else 'w') as f_new:
|
|
545
|
+
f_new.write(content)
|
|
546
|
+
|
|
463
547
|
|
|
464
548
|
class _FileSystemRegistry:
|
|
465
549
|
"""File system registry."""
|
|
@@ -567,6 +651,22 @@ class FsspecFileSystem(FileSystem):
|
|
|
567
651
|
fs, path = fsspec.core.url_to_fs(path)
|
|
568
652
|
return fs.isdir(path)
|
|
569
653
|
|
|
654
|
+
def getctime(self, path: Union[str, os.PathLike[str]]) -> float:
|
|
655
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
656
|
+
fs, path_in_fs = fsspec.core.url_to_fs(path)
|
|
657
|
+
created = fs.created(path_in_fs)
|
|
658
|
+
if created is None:
|
|
659
|
+
raise OSError(f'c-time is not available for path {path!r}')
|
|
660
|
+
return created.timestamp()
|
|
661
|
+
|
|
662
|
+
def getmtime(self, path: Union[str, os.PathLike[str]]) -> float:
|
|
663
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
664
|
+
fs, path_in_fs = fsspec.core.url_to_fs(path)
|
|
665
|
+
modified = fs.modified(path_in_fs)
|
|
666
|
+
if modified is None:
|
|
667
|
+
raise OSError(f'm-time is not available for path {path!r}')
|
|
668
|
+
return modified.timestamp()
|
|
669
|
+
|
|
570
670
|
def mkdir(
|
|
571
671
|
self,
|
|
572
672
|
path: Union[str, os.PathLike[str]], mode: int = 0o777
|
|
@@ -615,6 +715,32 @@ class FsspecFileSystem(FileSystem):
|
|
|
615
715
|
fs, path = fsspec.core.url_to_fs(path)
|
|
616
716
|
fs.rm(path, recursive=True)
|
|
617
717
|
|
|
718
|
+
def copy(
|
|
719
|
+
self,
|
|
720
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
721
|
+
newpath: Union[str, os.PathLike[str]],
|
|
722
|
+
) -> None:
|
|
723
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
724
|
+
fs1, old_path_in_fs = fsspec.core.url_to_fs(oldpath)
|
|
725
|
+
fs2, new_path_in_fs = fsspec.core.url_to_fs(newpath)
|
|
726
|
+
|
|
727
|
+
if fs2.isdir(new_path_in_fs):
|
|
728
|
+
new_path_in_fs = os.path.join(
|
|
729
|
+
new_path_in_fs, os.path.basename(old_path_in_fs)
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
if fs1.__class__ == fs2.__class__:
|
|
733
|
+
fs1.copy(old_path_in_fs, new_path_in_fs)
|
|
734
|
+
else:
|
|
735
|
+
with fs1.open(old_path_in_fs, 'rb') as f1:
|
|
736
|
+
with fs2.open(new_path_in_fs, 'wb') as f2:
|
|
737
|
+
while True:
|
|
738
|
+
# Reads the file in 16MB chunks.
|
|
739
|
+
chunk = f1.read(16 * 1024 * 1024)
|
|
740
|
+
if not chunk:
|
|
741
|
+
break
|
|
742
|
+
f2.write(chunk)
|
|
743
|
+
|
|
618
744
|
|
|
619
745
|
class _FsspecUriCatcher(FileSystem):
|
|
620
746
|
"""File system to catch URI paths and redirect to FsspecFileSystem."""
|
|
@@ -653,6 +779,12 @@ class _FsspecUriCatcher(FileSystem):
|
|
|
653
779
|
def isdir(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
654
780
|
return self.get_fs(path).isdir(path)
|
|
655
781
|
|
|
782
|
+
def getctime(self, path: Union[str, os.PathLike[str]]) -> float:
|
|
783
|
+
return self.get_fs(path).getctime(path)
|
|
784
|
+
|
|
785
|
+
def getmtime(self, path: Union[str, os.PathLike[str]]) -> float:
|
|
786
|
+
return self.get_fs(path).getmtime(path)
|
|
787
|
+
|
|
656
788
|
def mkdir(
|
|
657
789
|
self,
|
|
658
790
|
path: Union[str, os.PathLike[str]],
|
|
@@ -684,6 +816,13 @@ class _FsspecUriCatcher(FileSystem):
|
|
|
684
816
|
def rmdirs(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
685
817
|
self.get_fs(path).rmdirs(path)
|
|
686
818
|
|
|
819
|
+
def copy(
|
|
820
|
+
self,
|
|
821
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
822
|
+
newpath: Union[str, os.PathLike[str]],
|
|
823
|
+
) -> None:
|
|
824
|
+
self.get_fs(oldpath).copy(oldpath, newpath)
|
|
825
|
+
|
|
687
826
|
|
|
688
827
|
if fsspec is not None:
|
|
689
828
|
fsspec_fs = FsspecFileSystem()
|
|
@@ -751,6 +890,14 @@ def rm(path: Union[str, os.PathLike[str]]) -> None:
|
|
|
751
890
|
_fs.get(path).rm(path)
|
|
752
891
|
|
|
753
892
|
|
|
893
|
+
def copy(
|
|
894
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
895
|
+
newpath: Union[str, os.PathLike[str]],
|
|
896
|
+
) -> None:
|
|
897
|
+
"""Copies a file."""
|
|
898
|
+
_fs.get(oldpath).copy(oldpath, newpath)
|
|
899
|
+
|
|
900
|
+
|
|
754
901
|
def path_exists(path: Union[str, os.PathLike[str]]) -> bool:
|
|
755
902
|
"""Returns True if path exists."""
|
|
756
903
|
return _fs.get(path).exists(path)
|
|
@@ -776,6 +923,16 @@ def isdir(path: Union[str, os.PathLike[str]]) -> bool:
|
|
|
776
923
|
return _fs.get(path).isdir(path)
|
|
777
924
|
|
|
778
925
|
|
|
926
|
+
def getctime(path: Union[str, os.PathLike[str]]) -> float:
|
|
927
|
+
"""Returns the creation time of a file."""
|
|
928
|
+
return _fs.get(path).getctime(path)
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
def getmtime(path: Union[str, os.PathLike[str]]) -> float:
|
|
932
|
+
"""Returns the last modification time of a file."""
|
|
933
|
+
return _fs.get(path).getmtime(path)
|
|
934
|
+
|
|
935
|
+
|
|
779
936
|
def mkdir(path: Union[str, os.PathLike[str]], mode: int = 0o777) -> None:
|
|
780
937
|
"""Makes a directory."""
|
|
781
938
|
_fs.get(path).mkdir(path, mode=mode)
|
|
@@ -12,9 +12,12 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
import datetime
|
|
15
16
|
import os
|
|
16
17
|
import pathlib
|
|
18
|
+
import shutil
|
|
17
19
|
import tempfile
|
|
20
|
+
import time
|
|
18
21
|
import unittest
|
|
19
22
|
from unittest import mock
|
|
20
23
|
import fsspec
|
|
@@ -153,6 +156,42 @@ class StdFileSystemTest(unittest.TestCase):
|
|
|
153
156
|
os.path.join(tmp_dir, 'y')
|
|
154
157
|
)
|
|
155
158
|
|
|
159
|
+
def test_copy(self):
|
|
160
|
+
tmp_dir = tempfile.mkdtemp()
|
|
161
|
+
fs = file_system.StdFileSystem()
|
|
162
|
+
foo_txt = os.path.join(tmp_dir, 'foo.txt')
|
|
163
|
+
bar_txt = os.path.join(tmp_dir, 'bar.txt')
|
|
164
|
+
sub_dir = os.path.join(tmp_dir, 'sub')
|
|
165
|
+
sub_foo_txt = os.path.join(sub_dir, 'foo.txt')
|
|
166
|
+
|
|
167
|
+
with fs.open(foo_txt, 'w') as f:
|
|
168
|
+
f.write('hello')
|
|
169
|
+
fs.copy(foo_txt, bar_txt)
|
|
170
|
+
with fs.open(bar_txt) as f:
|
|
171
|
+
self.assertEqual(f.read(), 'hello')
|
|
172
|
+
fs.mkdir(sub_dir)
|
|
173
|
+
fs.copy(foo_txt, sub_dir)
|
|
174
|
+
with fs.open(sub_foo_txt) as f:
|
|
175
|
+
self.assertEqual(f.read(), 'hello')
|
|
176
|
+
with fs.open(foo_txt, 'w') as f:
|
|
177
|
+
f.write('overwrite')
|
|
178
|
+
fs.copy(foo_txt, bar_txt)
|
|
179
|
+
with fs.open(bar_txt) as f:
|
|
180
|
+
self.assertEqual(f.read(), 'overwrite')
|
|
181
|
+
shutil.rmtree(tmp_dir)
|
|
182
|
+
|
|
183
|
+
def test_getctime_getmtime(self):
|
|
184
|
+
tmp_dir = tempfile.mkdtemp()
|
|
185
|
+
fs = file_system.StdFileSystem()
|
|
186
|
+
file1 = os.path.join(tmp_dir, 'file1')
|
|
187
|
+
with fs.open(file1, 'w') as f:
|
|
188
|
+
f.write('hello')
|
|
189
|
+
ctime = fs.getctime(file1)
|
|
190
|
+
mtime = fs.getmtime(file1)
|
|
191
|
+
self.assertLess(0, ctime)
|
|
192
|
+
self.assertLessEqual(ctime, mtime)
|
|
193
|
+
shutil.rmtree(tmp_dir)
|
|
194
|
+
|
|
156
195
|
|
|
157
196
|
class MemoryFileSystemTest(unittest.TestCase):
|
|
158
197
|
|
|
@@ -339,6 +378,57 @@ class MemoryFileSystemTest(unittest.TestCase):
|
|
|
339
378
|
with self.assertRaises(FileNotFoundError):
|
|
340
379
|
fs.rename('/mem/non-existent', '/mem/y')
|
|
341
380
|
|
|
381
|
+
def test_copy(self):
|
|
382
|
+
fs = file_system.MemoryFileSystem()
|
|
383
|
+
fs.mkdirs('/mem/a')
|
|
384
|
+
with fs.open('/mem/a/foo.txt', 'w') as f:
|
|
385
|
+
f.write('hello')
|
|
386
|
+
fs.copy('/mem/a/foo.txt', '/mem/a/bar.txt')
|
|
387
|
+
self.assertEqual(fs.open('/mem/a/bar.txt').read(), 'hello')
|
|
388
|
+
fs.mkdir('/mem/b')
|
|
389
|
+
fs.copy('/mem/a/foo.txt', '/mem/b')
|
|
390
|
+
self.assertEqual(fs.open('/mem/b/foo.txt').read(), 'hello')
|
|
391
|
+
with fs.open('/mem/a/foo.txt', 'w') as f:
|
|
392
|
+
f.write('overwrite')
|
|
393
|
+
fs.copy('/mem/a/foo.txt', '/mem/a/bar.txt')
|
|
394
|
+
self.assertEqual(fs.open('/mem/a/bar.txt').read(), 'overwrite')
|
|
395
|
+
|
|
396
|
+
# Test exceptions
|
|
397
|
+
with self.assertRaises(FileNotFoundError):
|
|
398
|
+
fs.copy('/mem/non-existent', '/mem/y')
|
|
399
|
+
with self.assertRaisesRegex(IsADirectoryError, '/mem/a'):
|
|
400
|
+
fs.copy('/mem/a', '/mem/y')
|
|
401
|
+
|
|
402
|
+
fs.mkdirs('/mem/c/foo.txt')
|
|
403
|
+
with self.assertRaisesRegex(IsADirectoryError, '/mem/c/foo.txt'):
|
|
404
|
+
fs.copy('/mem/a/foo.txt', '/mem/c')
|
|
405
|
+
|
|
406
|
+
def test_getctime_getmtime(self):
|
|
407
|
+
fs = file_system.MemoryFileSystem()
|
|
408
|
+
fs.mkdirs('/mem/a')
|
|
409
|
+
file1 = '/mem/file1_times'
|
|
410
|
+
with fs.open(file1, 'w') as f:
|
|
411
|
+
f.write('hello')
|
|
412
|
+
ctime = fs.getctime(file1)
|
|
413
|
+
mtime = fs.getmtime(file1)
|
|
414
|
+
self.assertLess(0, ctime)
|
|
415
|
+
self.assertLess(ctime, mtime)
|
|
416
|
+
time.sleep(0.01)
|
|
417
|
+
with fs.open(file1, 'w') as f:
|
|
418
|
+
f.write('world')
|
|
419
|
+
self.assertEqual(fs.getctime(file1), ctime)
|
|
420
|
+
self.assertLess(mtime, fs.getmtime(file1))
|
|
421
|
+
|
|
422
|
+
with self.assertRaises(IsADirectoryError):
|
|
423
|
+
fs.getctime('/mem/a')
|
|
424
|
+
with self.assertRaises(FileNotFoundError):
|
|
425
|
+
fs.getctime('/mem/non_existent')
|
|
426
|
+
|
|
427
|
+
with self.assertRaises(IsADirectoryError):
|
|
428
|
+
fs.getmtime('/mem/a')
|
|
429
|
+
with self.assertRaises(FileNotFoundError):
|
|
430
|
+
fs.getmtime('/mem/non_existent')
|
|
431
|
+
|
|
342
432
|
|
|
343
433
|
class FileIoApiTest(unittest.TestCase):
|
|
344
434
|
|
|
@@ -424,6 +514,19 @@ class FileIoApiTest(unittest.TestCase):
|
|
|
424
514
|
sorted(file_system.glob('/mem/g/a/*')),
|
|
425
515
|
['/mem/g/a/b', '/mem/g/a/b/bar.txt', '/mem/g/a/foo2.txt'])
|
|
426
516
|
|
|
517
|
+
def test_getctime_getmtime(self):
|
|
518
|
+
# Test with standard file system.
|
|
519
|
+
std_file = os.path.join(tempfile.mkdtemp(), 'file_ctime_mtime')
|
|
520
|
+
file_system.writefile(std_file, 'foo')
|
|
521
|
+
self.assertLess(0, file_system.getctime(std_file))
|
|
522
|
+
self.assertLess(0, file_system.getmtime(std_file))
|
|
523
|
+
|
|
524
|
+
# Test with memory file system.
|
|
525
|
+
mem_file = '/mem/file_ctime_mtime'
|
|
526
|
+
file_system.writefile(mem_file, 'foo')
|
|
527
|
+
self.assertLess(0, file_system.getctime(mem_file))
|
|
528
|
+
self.assertLess(0, file_system.getmtime(mem_file))
|
|
529
|
+
|
|
427
530
|
|
|
428
531
|
class FsspecFileSystemTest(unittest.TestCase):
|
|
429
532
|
|
|
@@ -433,10 +536,12 @@ class FsspecFileSystemTest(unittest.TestCase):
|
|
|
433
536
|
self.fs.pipe('memory:///a/b/c', b'abc')
|
|
434
537
|
self.fs.pipe('memory:///a/b/d', b'abd')
|
|
435
538
|
self.fs.mkdir('memory:///a/e')
|
|
539
|
+
self.tmp_dir = tempfile.mkdtemp()
|
|
436
540
|
|
|
437
541
|
def tearDown(self):
|
|
438
542
|
super().tearDown()
|
|
439
543
|
fsspec.filesystem('memory').rm('/', recursive=True)
|
|
544
|
+
shutil.rmtree(self.tmp_dir)
|
|
440
545
|
|
|
441
546
|
def test_read_file(self):
|
|
442
547
|
self.assertEqual(file_system.readfile('memory:///a/b/c', mode='rb'), b'abc')
|
|
@@ -513,6 +618,44 @@ class FsspecFileSystemTest(unittest.TestCase):
|
|
|
513
618
|
file_system.rmdirs('memory:///x')
|
|
514
619
|
self.assertFalse(file_system.path_exists('memory:///x'))
|
|
515
620
|
|
|
621
|
+
def test_copy(self):
|
|
622
|
+
# same FS copy
|
|
623
|
+
file_system.copy('memory:///a/b/c', 'memory:///a/f')
|
|
624
|
+
self.assertEqual(file_system.readfile('memory:///a/f', mode='rb'), b'abc')
|
|
625
|
+
|
|
626
|
+
# same FS copy to dir
|
|
627
|
+
file_system.copy('memory:///a/b/d', 'memory:///a/e')
|
|
628
|
+
self.assertEqual(file_system.readfile('memory:///a/e/d', mode='rb'), b'abd')
|
|
629
|
+
|
|
630
|
+
# cross FS copy: memory to local
|
|
631
|
+
local_path = os.path.join(self.tmp_dir, 'test.txt')
|
|
632
|
+
file_system.copy('memory:///a/b/c', f'file://{local_path}')
|
|
633
|
+
self.assertEqual(file_system.readfile(local_path, mode='rb'), b'abc')
|
|
634
|
+
|
|
635
|
+
# cross FS copy: local to memory
|
|
636
|
+
file_system.copy(f'file://{local_path}', 'memory:///a/g')
|
|
637
|
+
self.assertEqual(file_system.readfile('memory:///a/g', mode='rb'), b'abc')
|
|
638
|
+
|
|
639
|
+
def test_getctime_getmtime(self):
|
|
640
|
+
self.fs.touch('memory:///a/b/c_time')
|
|
641
|
+
now = datetime.datetime.now()
|
|
642
|
+
with mock.patch.object(self.fs, 'created', return_value=now):
|
|
643
|
+
self.assertEqual(
|
|
644
|
+
file_system.getctime('memory:///a/b/c_time'), now.timestamp()
|
|
645
|
+
)
|
|
646
|
+
with mock.patch.object(self.fs, 'modified', return_value=now):
|
|
647
|
+
self.assertEqual(
|
|
648
|
+
file_system.getmtime('memory:///a/b/c_time'), now.timestamp()
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
with mock.patch.object(self.fs, 'created', return_value=None):
|
|
652
|
+
with self.assertRaisesRegex(OSError, 'c-time is not available'):
|
|
653
|
+
file_system.getctime('memory:///a/b/c_time')
|
|
654
|
+
|
|
655
|
+
with mock.patch.object(self.fs, 'modified', return_value=None):
|
|
656
|
+
with self.assertRaisesRegex(OSError, 'm-time is not available'):
|
|
657
|
+
file_system.getmtime('memory:///a/b/c_time')
|
|
658
|
+
|
|
516
659
|
def test_fsspec_uri_catcher(self):
|
|
517
660
|
with mock.patch.object(
|
|
518
661
|
file_system.FsspecFileSystem, 'exists', return_value=True
|
|
@@ -539,6 +682,14 @@ class FsspecFileSystemTest(unittest.TestCase):
|
|
|
539
682
|
'some-proto://foo', 'some-proto://bar'
|
|
540
683
|
)
|
|
541
684
|
|
|
685
|
+
with mock.patch.object(
|
|
686
|
+
file_system.FsspecFileSystem, 'copy', return_value=None
|
|
687
|
+
) as mock_fsspec_copy:
|
|
688
|
+
file_system.copy('some-proto://foo', 'some-proto://bar')
|
|
689
|
+
mock_fsspec_copy.assert_called_once_with(
|
|
690
|
+
'some-proto://foo', 'some-proto://bar'
|
|
691
|
+
)
|
|
692
|
+
|
|
542
693
|
|
|
543
694
|
if __name__ == '__main__':
|
|
544
695
|
unittest.main()
|
|
@@ -56,8 +56,8 @@ pyglove/core/hyper/numerical_test.py,sha256=UWdH55Bok7bghYDLJOGsgOwV_2LNkhj1AmFw
|
|
|
56
56
|
pyglove/core/hyper/object_template.py,sha256=YPALTV0mMULa7iuqnryTpA2wMsdyFZ_6g-R525asAr8,22222
|
|
57
57
|
pyglove/core/hyper/object_template_test.py,sha256=TEFX7LIqUvdCdJILnK_gP5xIgNJKzRnioUF0CGVBzcY,9105
|
|
58
58
|
pyglove/core/io/__init__.py,sha256=4ZT1a595DqQuLTNYc2JP_eCp_KesXvHmKRkr777bzpg,785
|
|
59
|
-
pyglove/core/io/file_system.py,sha256=
|
|
60
|
-
pyglove/core/io/file_system_test.py,sha256=
|
|
59
|
+
pyglove/core/io/file_system.py,sha256=cggBMIzQxQpTjPsYQPQj8IsO-UpunsEGxaclYQcUHjw,28093
|
|
60
|
+
pyglove/core/io/file_system_test.py,sha256=2c2l3HCNS8Q4mv8k1dqopnGpeVLiWSzmc8eDIx4b5oo,24561
|
|
61
61
|
pyglove/core/io/sequence.py,sha256=XdVpPBuvhUnrTIWMUrak_qdcNdUJBpjgH5c1b5I3E2A,8873
|
|
62
62
|
pyglove/core/io/sequence_test.py,sha256=mnONyNG1M1sCae2tyI-tF8qns96htfZPKycthETPthU,4062
|
|
63
63
|
pyglove/core/patching/__init__.py,sha256=C1Q1cWPV74YL3eXbzGvc-8aPw1DR8EK6lRhQYDCwHek,2059
|
|
@@ -220,8 +220,8 @@ pyglove/ext/scalars/randoms.py,sha256=LkMIIx7lOq_lvJvVS3BrgWGuWl7Pi91-lA-O8x_gZs
|
|
|
220
220
|
pyglove/ext/scalars/randoms_test.py,sha256=nEhiqarg8l_5EOucp59CYrpO2uKxS1pe0hmBdZUzRNM,2000
|
|
221
221
|
pyglove/ext/scalars/step_wise.py,sha256=IDw3tuTpv0KVh7AN44W43zqm1-E0HWPUlytWOQC9w3Y,3789
|
|
222
222
|
pyglove/ext/scalars/step_wise_test.py,sha256=TL1vJ19xVx2t5HKuyIzGoogF7N3Rm8YhLE6JF7i0iy8,2540
|
|
223
|
-
pyglove-0.5.0.
|
|
224
|
-
pyglove-0.5.0.
|
|
225
|
-
pyglove-0.5.0.
|
|
226
|
-
pyglove-0.5.0.
|
|
227
|
-
pyglove-0.5.0.
|
|
223
|
+
pyglove-0.5.0.dev202512080812.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
|
224
|
+
pyglove-0.5.0.dev202512080812.dist-info/METADATA,sha256=E7UuKxo0wIhPc7Z3L0cRpVKXxj9eY_qfcbr0fjPfym8,7349
|
|
225
|
+
pyglove-0.5.0.dev202512080812.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
226
|
+
pyglove-0.5.0.dev202512080812.dist-info/top_level.txt,sha256=wITzJSKcj8GZUkbq-MvUQnFadkiuAv_qv5qQMw0fIow,8
|
|
227
|
+
pyglove-0.5.0.dev202512080812.dist-info/RECORD,,
|
|
File without changes
|
{pyglove-0.5.0.dev202511240812.dist-info → pyglove-0.5.0.dev202512080812.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{pyglove-0.5.0.dev202511240812.dist-info → pyglove-0.5.0.dev202512080812.dist-info}/top_level.txt
RENAMED
|
File without changes
|