pyglove 0.5.0.dev202508250811__py3-none-any.whl → 0.5.0.dev202511300809__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.
- pyglove/core/__init__.py +8 -1
- pyglove/core/geno/base.py +7 -3
- pyglove/core/io/file_system.py +295 -2
- pyglove/core/io/file_system_test.py +291 -0
- pyglove/core/logging.py +45 -1
- pyglove/core/logging_test.py +12 -21
- pyglove/core/monitoring.py +657 -0
- pyglove/core/monitoring_test.py +289 -0
- pyglove/core/symbolic/__init__.py +7 -0
- pyglove/core/symbolic/base.py +89 -35
- pyglove/core/symbolic/base_test.py +3 -3
- pyglove/core/symbolic/dict.py +31 -12
- pyglove/core/symbolic/dict_test.py +49 -0
- pyglove/core/symbolic/list.py +17 -3
- pyglove/core/symbolic/list_test.py +24 -2
- pyglove/core/symbolic/object.py +3 -1
- pyglove/core/symbolic/object_test.py +13 -10
- pyglove/core/symbolic/ref.py +19 -7
- pyglove/core/symbolic/ref_test.py +94 -7
- pyglove/core/symbolic/unknown_symbols.py +147 -0
- pyglove/core/symbolic/unknown_symbols_test.py +100 -0
- pyglove/core/typing/annotation_conversion.py +8 -1
- pyglove/core/typing/annotation_conversion_test.py +14 -19
- pyglove/core/typing/class_schema.py +24 -1
- pyglove/core/typing/json_schema.py +221 -8
- pyglove/core/typing/json_schema_test.py +508 -12
- pyglove/core/typing/type_conversion.py +17 -3
- pyglove/core/typing/type_conversion_test.py +7 -2
- pyglove/core/typing/value_specs.py +5 -1
- pyglove/core/typing/value_specs_test.py +5 -0
- pyglove/core/utils/__init__.py +2 -0
- pyglove/core/utils/contextual.py +9 -4
- pyglove/core/utils/contextual_test.py +10 -0
- pyglove/core/utils/error_utils.py +59 -25
- pyglove/core/utils/json_conversion.py +360 -63
- pyglove/core/utils/json_conversion_test.py +146 -13
- pyglove/core/views/html/controls/tab.py +33 -0
- pyglove/core/views/html/controls/tab_test.py +37 -0
- pyglove/ext/evolution/base_test.py +1 -1
- {pyglove-0.5.0.dev202508250811.dist-info → pyglove-0.5.0.dev202511300809.dist-info}/METADATA +8 -1
- {pyglove-0.5.0.dev202508250811.dist-info → pyglove-0.5.0.dev202511300809.dist-info}/RECORD +44 -40
- {pyglove-0.5.0.dev202508250811.dist-info → pyglove-0.5.0.dev202511300809.dist-info}/WHEEL +0 -0
- {pyglove-0.5.0.dev202508250811.dist-info → pyglove-0.5.0.dev202511300809.dist-info}/licenses/LICENSE +0 -0
- {pyglove-0.5.0.dev202508250811.dist-info → pyglove-0.5.0.dev202511300809.dist-info}/top_level.txt +0 -0
pyglove/core/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2025 The PyGlove Authors
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -306,6 +306,7 @@ format = utils.format # pylint: disable=redefined-builtin
|
|
|
306
306
|
print = utils.print # pylint: disable=redefined-builtin
|
|
307
307
|
docstr = utils.docstr
|
|
308
308
|
catch_errors = utils.catch_errors
|
|
309
|
+
match_error = utils.match_error
|
|
309
310
|
timeit = utils.timeit
|
|
310
311
|
|
|
311
312
|
contextual_override = utils.contextual_override
|
|
@@ -352,6 +353,12 @@ from pyglove.core import coding
|
|
|
352
353
|
|
|
353
354
|
from pyglove.core import logging
|
|
354
355
|
|
|
356
|
+
#
|
|
357
|
+
# Symbols from `monitoring.py`.
|
|
358
|
+
#
|
|
359
|
+
|
|
360
|
+
from pyglove.core import monitoring
|
|
361
|
+
|
|
355
362
|
# pylint: enable=g-import-not-at-top
|
|
356
363
|
# pylint: enable=reimported
|
|
357
364
|
# pylint: enable=unused-import
|
pyglove/core/geno/base.py
CHANGED
|
@@ -1447,6 +1447,7 @@ class DNA(symbolic.Object):
|
|
|
1447
1447
|
*,
|
|
1448
1448
|
allow_partial: bool = False,
|
|
1449
1449
|
root_path: Optional[utils.KeyPath] = None,
|
|
1450
|
+
**kwargs,
|
|
1450
1451
|
) -> 'DNA':
|
|
1451
1452
|
"""Class method that load a DNA from a JSON value.
|
|
1452
1453
|
|
|
@@ -1454,6 +1455,7 @@ class DNA(symbolic.Object):
|
|
|
1454
1455
|
json_value: Input JSON value, only JSON dict is acceptable.
|
|
1455
1456
|
allow_partial: Whether to allow elements of the list to be partial.
|
|
1456
1457
|
root_path: KeyPath of loaded object in its object tree.
|
|
1458
|
+
**kwargs: Keyword arguments that will be passed to symbolic.from_json.
|
|
1457
1459
|
|
|
1458
1460
|
Returns:
|
|
1459
1461
|
A DNA object.
|
|
@@ -1463,16 +1465,18 @@ class DNA(symbolic.Object):
|
|
|
1463
1465
|
# NOTE(daiyip): DNA.parse will validate the input. Therefore, we can
|
|
1464
1466
|
# disable runtime type check during constructing the DNA objects.
|
|
1465
1467
|
with symbolic.enable_type_check(False):
|
|
1466
|
-
dna = DNA.parse(symbolic.from_json(json_value.get('value')))
|
|
1468
|
+
dna = DNA.parse(symbolic.from_json(json_value.get('value'), **kwargs))
|
|
1467
1469
|
if 'metadata' in json_value:
|
|
1468
1470
|
dna.rebind(
|
|
1469
|
-
metadata=symbolic.from_json(json_value.get('metadata')),
|
|
1471
|
+
metadata=symbolic.from_json(json_value.get('metadata'), **kwargs),
|
|
1470
1472
|
raise_on_no_change=False, skip_notification=True)
|
|
1471
1473
|
else:
|
|
1472
1474
|
dna = super(DNA, cls).from_json(
|
|
1473
1475
|
json_value,
|
|
1474
1476
|
allow_partial=allow_partial,
|
|
1475
|
-
root_path=root_path
|
|
1477
|
+
root_path=root_path,
|
|
1478
|
+
**kwargs,
|
|
1479
|
+
) # pytype: disable=bad-return-type
|
|
1476
1480
|
assert isinstance(dna, DNA)
|
|
1477
1481
|
if cloneable_metadata_keys:
|
|
1478
1482
|
dna._cloneable_metadata_keys = set(cloneable_metadata_keys) # pylint: disable=protected-access
|
pyglove/core/io/file_system.py
CHANGED
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
"""Pluggable file system."""
|
|
15
15
|
|
|
16
16
|
import abc
|
|
17
|
+
import fnmatch
|
|
18
|
+
import glob as std_glob
|
|
17
19
|
import io
|
|
18
20
|
import os
|
|
21
|
+
import re
|
|
19
22
|
from typing import Any, Literal, Optional, Union
|
|
20
23
|
|
|
21
24
|
|
|
@@ -84,6 +87,10 @@ class FileSystem(metaclass=abc.ABCMeta):
|
|
|
84
87
|
def exists(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
85
88
|
"""Returns True if a path exists."""
|
|
86
89
|
|
|
90
|
+
@abc.abstractmethod
|
|
91
|
+
def glob(self, pattern: Union[str, os.PathLike[str]]) -> list[str]:
|
|
92
|
+
"""Lists all files or sub-directories."""
|
|
93
|
+
|
|
87
94
|
@abc.abstractmethod
|
|
88
95
|
def listdir(self, path: Union[str, os.PathLike[str]]) -> list[str]:
|
|
89
96
|
"""Lists all files or sub-directories."""
|
|
@@ -111,6 +118,14 @@ class FileSystem(metaclass=abc.ABCMeta):
|
|
|
111
118
|
def rm(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
112
119
|
"""Removes a file based on a path."""
|
|
113
120
|
|
|
121
|
+
@abc.abstractmethod
|
|
122
|
+
def rename(
|
|
123
|
+
self,
|
|
124
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
125
|
+
newpath: Union[str, os.PathLike[str]],
|
|
126
|
+
) -> None:
|
|
127
|
+
"""Renames a file based on a path."""
|
|
128
|
+
|
|
114
129
|
@abc.abstractmethod
|
|
115
130
|
def rmdir(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
116
131
|
"""Removes a directory based on a path."""
|
|
@@ -137,9 +152,10 @@ def resolve_path(path: Union[str, os.PathLike[str]]) -> str:
|
|
|
137
152
|
class StdFile(File):
|
|
138
153
|
"""The standard file."""
|
|
139
154
|
|
|
140
|
-
def __init__(self, file_object) -> None:
|
|
155
|
+
def __init__(self, file_object, path: Union[str, os.PathLike[str]]) -> None:
|
|
141
156
|
super().__init__()
|
|
142
157
|
self._file_object = file_object
|
|
158
|
+
self._path = path
|
|
143
159
|
|
|
144
160
|
def read(self, size: Optional[int] = None) -> Union[str, bytes]:
|
|
145
161
|
return self._file_object.read(size)
|
|
@@ -169,7 +185,7 @@ class StdFileSystem(FileSystem):
|
|
|
169
185
|
def open(
|
|
170
186
|
self, path: Union[str, os.PathLike[str]], mode: str = 'r', **kwargs
|
|
171
187
|
) -> File:
|
|
172
|
-
return StdFile(io.open(path, mode, **kwargs))
|
|
188
|
+
return StdFile(io.open(path, mode, **kwargs), path)
|
|
173
189
|
|
|
174
190
|
def chmod(self, path: Union[str, os.PathLike[str]], mode: int) -> None:
|
|
175
191
|
os.chmod(path, mode)
|
|
@@ -177,6 +193,9 @@ class StdFileSystem(FileSystem):
|
|
|
177
193
|
def exists(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
178
194
|
return os.path.exists(path)
|
|
179
195
|
|
|
196
|
+
def glob(self, pattern: Union[str, os.PathLike[str]]) -> list[str]:
|
|
197
|
+
return std_glob.glob(pattern)
|
|
198
|
+
|
|
180
199
|
def listdir(self, path: Union[str, os.PathLike[str]]) -> list[str]:
|
|
181
200
|
return os.listdir(path)
|
|
182
201
|
|
|
@@ -196,6 +215,13 @@ class StdFileSystem(FileSystem):
|
|
|
196
215
|
) -> None:
|
|
197
216
|
os.makedirs(path, mode, exist_ok)
|
|
198
217
|
|
|
218
|
+
def rename(
|
|
219
|
+
self,
|
|
220
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
221
|
+
newpath: Union[str, os.PathLike[str]],
|
|
222
|
+
) -> None:
|
|
223
|
+
os.rename(oldpath, newpath)
|
|
224
|
+
|
|
199
225
|
def rm(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
200
226
|
os.remove(path)
|
|
201
227
|
|
|
@@ -286,6 +312,21 @@ class MemoryFileSystem(FileSystem):
|
|
|
286
312
|
def exists(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
287
313
|
return self._locate(path) is not None
|
|
288
314
|
|
|
315
|
+
def glob(self, pattern: Union[str, os.PathLike[str]]) -> list[str]:
|
|
316
|
+
pattern = resolve_path(pattern)
|
|
317
|
+
regex = re.compile(fnmatch.translate(pattern))
|
|
318
|
+
|
|
319
|
+
results = []
|
|
320
|
+
def _traverse(node, prefix_parts):
|
|
321
|
+
for k, v in node.items():
|
|
322
|
+
path = self._prefix + '/'.join(prefix_parts + [k])
|
|
323
|
+
if regex.match(path):
|
|
324
|
+
results.append(path)
|
|
325
|
+
if isinstance(v, dict):
|
|
326
|
+
_traverse(v, prefix_parts + [k])
|
|
327
|
+
_traverse(self._root, [])
|
|
328
|
+
return results
|
|
329
|
+
|
|
289
330
|
def listdir(self, path: Union[str, os.PathLike[str]]) -> list[str]:
|
|
290
331
|
d = self._locate(path)
|
|
291
332
|
if not isinstance(d, dict):
|
|
@@ -338,6 +379,46 @@ class MemoryFileSystem(FileSystem):
|
|
|
338
379
|
raise NotADirectoryError(path)
|
|
339
380
|
current = entry
|
|
340
381
|
|
|
382
|
+
def rename(
|
|
383
|
+
self,
|
|
384
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
385
|
+
newpath: Union[str, os.PathLike[str]],
|
|
386
|
+
) -> None:
|
|
387
|
+
oldpath_str = resolve_path(oldpath)
|
|
388
|
+
newpath_str = resolve_path(newpath)
|
|
389
|
+
|
|
390
|
+
old_parent_dir, old_name = self._parent_and_name(oldpath_str)
|
|
391
|
+
entry = old_parent_dir.get(old_name)
|
|
392
|
+
|
|
393
|
+
if entry is None:
|
|
394
|
+
raise FileNotFoundError(oldpath_str)
|
|
395
|
+
|
|
396
|
+
new_entry = self._locate(newpath_str)
|
|
397
|
+
if new_entry is not None:
|
|
398
|
+
if isinstance(entry, dict): # oldpath is dir
|
|
399
|
+
if not isinstance(new_entry, dict):
|
|
400
|
+
raise NotADirectoryError(
|
|
401
|
+
f'Cannot rename directory {oldpath_str!r} '
|
|
402
|
+
f'to non-directory {newpath_str!r}')
|
|
403
|
+
elif new_entry:
|
|
404
|
+
raise OSError(f'Directory not empty: {newpath_str!r}')
|
|
405
|
+
else:
|
|
406
|
+
self.rmdir(newpath_str)
|
|
407
|
+
else: # oldpath is file
|
|
408
|
+
if isinstance(new_entry, dict):
|
|
409
|
+
raise IsADirectoryError(
|
|
410
|
+
f'Cannot rename non-directory {oldpath_str!r} '
|
|
411
|
+
f'to directory {newpath_str!r}')
|
|
412
|
+
else:
|
|
413
|
+
self.rm(newpath_str)
|
|
414
|
+
elif isinstance(entry, dict) and newpath_str.startswith(oldpath_str + '/'):
|
|
415
|
+
raise OSError(f'Cannot move directory {oldpath_str!r} '
|
|
416
|
+
f'to a subdirectory of itself {newpath_str!r}')
|
|
417
|
+
|
|
418
|
+
new_parent_dir, new_name = self._parent_and_name(newpath_str)
|
|
419
|
+
new_parent_dir[new_name] = entry
|
|
420
|
+
del old_parent_dir[old_name]
|
|
421
|
+
|
|
341
422
|
def rm(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
342
423
|
parent_dir, name = self._parent_and_name(path)
|
|
343
424
|
entry = parent_dir.get(name)
|
|
@@ -412,6 +493,205 @@ def add_file_system(prefix: str, fs: FileSystem) -> None:
|
|
|
412
493
|
add_file_system('/mem/', MemoryFileSystem('/mem/'))
|
|
413
494
|
|
|
414
495
|
|
|
496
|
+
try:
|
|
497
|
+
# pylint: disable=g-import-not-at-top
|
|
498
|
+
# pytype: disable=import-error
|
|
499
|
+
import fsspec
|
|
500
|
+
# pytype: enable=import-error
|
|
501
|
+
# pylint: enable=g-import-not-at-top
|
|
502
|
+
except ImportError:
|
|
503
|
+
fsspec = None
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
class FsspecFile(File):
|
|
507
|
+
"""File object based on fsspec."""
|
|
508
|
+
|
|
509
|
+
def __init__(self, f):
|
|
510
|
+
self._f = f
|
|
511
|
+
|
|
512
|
+
def read(self, size: Optional[int] = None) -> Union[str, bytes]:
|
|
513
|
+
return self._f.read(size)
|
|
514
|
+
|
|
515
|
+
def readline(self) -> Union[str, bytes]:
|
|
516
|
+
return self._f.readline()
|
|
517
|
+
|
|
518
|
+
def write(self, content: Union[str, bytes]) -> None:
|
|
519
|
+
self._f.write(content)
|
|
520
|
+
|
|
521
|
+
def seek(self, offset: int, whence: Literal[0, 1, 2] = 0) -> int:
|
|
522
|
+
return self._f.seek(offset, whence)
|
|
523
|
+
|
|
524
|
+
def tell(self) -> int:
|
|
525
|
+
return self._f.tell()
|
|
526
|
+
|
|
527
|
+
def flush(self) -> None:
|
|
528
|
+
self._f.flush()
|
|
529
|
+
|
|
530
|
+
def close(self) -> None:
|
|
531
|
+
self._f.close()
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
class FsspecFileSystem(FileSystem):
|
|
535
|
+
"""File system based on fsspec."""
|
|
536
|
+
|
|
537
|
+
def open(
|
|
538
|
+
self, path: Union[str, os.PathLike[str]], mode: str = 'r', **kwargs
|
|
539
|
+
) -> File:
|
|
540
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
541
|
+
return FsspecFile(fsspec.open(path, mode, **kwargs).open())
|
|
542
|
+
|
|
543
|
+
def chmod(self, path: Union[str, os.PathLike[str]], mode: int) -> None:
|
|
544
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
545
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
546
|
+
if hasattr(fs, 'chmod'):
|
|
547
|
+
fs.chmod(path, mode)
|
|
548
|
+
|
|
549
|
+
def exists(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
550
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
551
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
552
|
+
return fs.exists(path)
|
|
553
|
+
|
|
554
|
+
def glob(self, pattern: Union[str, os.PathLike[str]]) -> list[str]:
|
|
555
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
556
|
+
fs, path = fsspec.core.url_to_fs(pattern)
|
|
557
|
+
protocol = fsspec.utils.get_protocol(pattern)
|
|
558
|
+
return [f'{protocol}:///{r.lstrip("/")}' for r in fs.glob(path)]
|
|
559
|
+
|
|
560
|
+
def listdir(self, path: Union[str, os.PathLike[str]]) -> list[str]:
|
|
561
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
562
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
563
|
+
return [os.path.basename(f) for f in fs.ls(path, detail=False)]
|
|
564
|
+
|
|
565
|
+
def isdir(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
566
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
567
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
568
|
+
return fs.isdir(path)
|
|
569
|
+
|
|
570
|
+
def mkdir(
|
|
571
|
+
self,
|
|
572
|
+
path: Union[str, os.PathLike[str]], mode: int = 0o777
|
|
573
|
+
) -> None:
|
|
574
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
575
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
576
|
+
fs.mkdir(path)
|
|
577
|
+
|
|
578
|
+
def mkdirs(
|
|
579
|
+
self,
|
|
580
|
+
path: Union[str, os.PathLike[str]],
|
|
581
|
+
mode: int = 0o777,
|
|
582
|
+
exist_ok: bool = True,
|
|
583
|
+
) -> None:
|
|
584
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
585
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
586
|
+
fs.makedirs(path, exist_ok=exist_ok)
|
|
587
|
+
|
|
588
|
+
def rm(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
589
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
590
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
591
|
+
fs.rm(path)
|
|
592
|
+
|
|
593
|
+
def rename(
|
|
594
|
+
self,
|
|
595
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
596
|
+
newpath: Union[str, os.PathLike[str]],
|
|
597
|
+
) -> None:
|
|
598
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
599
|
+
fs, old_path = fsspec.core.url_to_fs(oldpath)
|
|
600
|
+
fs2, new_path = fsspec.core.url_to_fs(newpath)
|
|
601
|
+
if fs.__class__ != fs2.__class__:
|
|
602
|
+
raise ValueError(
|
|
603
|
+
f'Rename across different filesystems is not supported: '
|
|
604
|
+
f'{type(fs)} vs {type(fs2)}'
|
|
605
|
+
)
|
|
606
|
+
fs.rename(old_path, new_path)
|
|
607
|
+
|
|
608
|
+
def rmdir(self, path: Union[str, os.PathLike[str]]) -> None: # pytype: disable=signature-mismatch
|
|
609
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
610
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
611
|
+
fs.rmdir(path)
|
|
612
|
+
|
|
613
|
+
def rmdirs(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
614
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
615
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
616
|
+
fs.rm(path, recursive=True)
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
class _FsspecUriCatcher(FileSystem):
|
|
620
|
+
"""File system to catch URI paths and redirect to FsspecFileSystem."""
|
|
621
|
+
|
|
622
|
+
# Catch all paths that contains '://' but not registered by
|
|
623
|
+
# available_protocols.
|
|
624
|
+
_URI_PATTERN = re.compile(r'^[a-zA-Z][a-zA-Z0-9+-.]*://.*')
|
|
625
|
+
|
|
626
|
+
def __init__(self):
|
|
627
|
+
super().__init__()
|
|
628
|
+
self._std_fs = StdFileSystem()
|
|
629
|
+
self._fsspec_fs = FsspecFileSystem()
|
|
630
|
+
|
|
631
|
+
def get_fs(self, path: Union[str, os.PathLike[str]]) -> FileSystem:
|
|
632
|
+
if self._URI_PATTERN.match(resolve_path(path)):
|
|
633
|
+
return self._fsspec_fs
|
|
634
|
+
return self._std_fs
|
|
635
|
+
|
|
636
|
+
def open(
|
|
637
|
+
self, path: Union[str, os.PathLike[str]], mode: str = 'r', **kwargs
|
|
638
|
+
) -> File:
|
|
639
|
+
return self.get_fs(path).open(path, mode, **kwargs)
|
|
640
|
+
|
|
641
|
+
def chmod(self, path: Union[str, os.PathLike[str]], mode: int) -> None:
|
|
642
|
+
self.get_fs(path).chmod(path, mode)
|
|
643
|
+
|
|
644
|
+
def exists(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
645
|
+
return self.get_fs(path).exists(path)
|
|
646
|
+
|
|
647
|
+
def glob(self, pattern: Union[str, os.PathLike[str]]) -> list[str]:
|
|
648
|
+
return self.get_fs(pattern).glob(pattern)
|
|
649
|
+
|
|
650
|
+
def listdir(self, path: Union[str, os.PathLike[str]]) -> list[str]:
|
|
651
|
+
return self.get_fs(path).listdir(path)
|
|
652
|
+
|
|
653
|
+
def isdir(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
654
|
+
return self.get_fs(path).isdir(path)
|
|
655
|
+
|
|
656
|
+
def mkdir(
|
|
657
|
+
self,
|
|
658
|
+
path: Union[str, os.PathLike[str]],
|
|
659
|
+
mode: int = 0o777
|
|
660
|
+
) -> None:
|
|
661
|
+
self.get_fs(path).mkdir(path, mode)
|
|
662
|
+
|
|
663
|
+
def mkdirs(
|
|
664
|
+
self,
|
|
665
|
+
path: Union[str, os.PathLike[str]],
|
|
666
|
+
mode: int = 0o777,
|
|
667
|
+
exist_ok: bool = True,
|
|
668
|
+
) -> None:
|
|
669
|
+
self.get_fs(path).mkdirs(path, mode, exist_ok)
|
|
670
|
+
|
|
671
|
+
def rm(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
672
|
+
self.get_fs(path).rm(path)
|
|
673
|
+
|
|
674
|
+
def rename(
|
|
675
|
+
self,
|
|
676
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
677
|
+
newpath: Union[str, os.PathLike[str]],
|
|
678
|
+
) -> None:
|
|
679
|
+
self.get_fs(oldpath).rename(oldpath, newpath)
|
|
680
|
+
|
|
681
|
+
def rmdir(self, path: Union[str, os.PathLike[str]]) -> None: # pytype: disable=signature-mismatch
|
|
682
|
+
self.get_fs(path).rmdir(path)
|
|
683
|
+
|
|
684
|
+
def rmdirs(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
685
|
+
self.get_fs(path).rmdirs(path)
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
if fsspec is not None:
|
|
689
|
+
fsspec_fs = FsspecFileSystem()
|
|
690
|
+
for p in fsspec.available_protocols():
|
|
691
|
+
add_file_system(p + '://', fsspec_fs)
|
|
692
|
+
add_file_system('', _FsspecUriCatcher())
|
|
693
|
+
|
|
694
|
+
|
|
415
695
|
#
|
|
416
696
|
# APIs for file IO.
|
|
417
697
|
#
|
|
@@ -458,6 +738,14 @@ def writefile(
|
|
|
458
738
|
chmod(path, perms)
|
|
459
739
|
|
|
460
740
|
|
|
741
|
+
def rename(
|
|
742
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
743
|
+
newpath: Union[str, os.PathLike[str]],
|
|
744
|
+
) -> None:
|
|
745
|
+
"""Renames a file."""
|
|
746
|
+
_fs.get(oldpath).rename(oldpath, newpath)
|
|
747
|
+
|
|
748
|
+
|
|
461
749
|
def rm(path: Union[str, os.PathLike[str]]) -> None:
|
|
462
750
|
"""Removes a file."""
|
|
463
751
|
_fs.get(path).rm(path)
|
|
@@ -468,6 +756,11 @@ def path_exists(path: Union[str, os.PathLike[str]]) -> bool:
|
|
|
468
756
|
return _fs.get(path).exists(path)
|
|
469
757
|
|
|
470
758
|
|
|
759
|
+
def glob(pattern: Union[str, os.PathLike[str]]) -> list[str]:
|
|
760
|
+
"""Lists all files or sub-directories."""
|
|
761
|
+
return _fs.get(pattern).glob(pattern)
|
|
762
|
+
|
|
763
|
+
|
|
471
764
|
def listdir(
|
|
472
765
|
path: Union[str, os.PathLike[str]], fullpath: bool = False
|
|
473
766
|
) -> list[str]: # pylint: disable=redefined-builtin
|