Safemotion Lib
Loading...
Searching...
No Matches
file_io.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3
4import errno
5import logging
6import os
7import shutil
8from collections import OrderedDict
9from typing import (
10 IO,
11 Any,
12 Callable,
13 Dict,
14 List,
15 MutableMapping,
16 Optional,
17 Union,
18)
19
20__all__ = ["PathManager", "get_cache_dir"]
21
22
23def get_cache_dir(cache_dir: Optional[str] = None) -> str:
24 """
25 Returns a default directory to cache static files
26 (usually downloaded from Internet), if None is provided.
27 Args:
28 cache_dir (None or str): if not None, will be returned as is.
29 If None, returns the default cache directory as:
30 1) $FVCORE_CACHE, if set
31 2) otherwise ~/.torch/fvcore_cache
32 """
33 if cache_dir is None:
34 cache_dir = os.path.expanduser(
35 os.getenv("FVCORE_CACHE", "~/.torch/fvcore_cache")
36 )
37 return cache_dir
38
39
41 """
42 PathHandler is a base class that defines common I/O functionality for a URI
43 protocol. It routes I/O for a generic URI which may look like "protocol://*"
44 or a canonical filepath "/foo/bar/baz".
45 """
46
47 _strict_kwargs_check = True
48
49 def _check_kwargs(self, kwargs: Dict[str, Any]) -> None:
50 """
51 Checks if the given arguments are empty. Throws a ValueError if strict
52 kwargs checking is enabled and args are non-empty. If strict kwargs
53 checking is disabled, only a warning is logged.
54 Args:
55 kwargs (Dict[str, Any])
56 """
58 if len(kwargs) > 0:
59 raise ValueError("Unused arguments: {}".format(kwargs))
60 else:
61 logger = logging.getLogger(__name__)
62 for k, v in kwargs.items():
63 logger.warning(
64 "[PathManager] {}={} argument ignored".format(k, v)
65 )
66
67 def _get_supported_prefixes(self) -> List[str]:
68 """
69 Returns:
70 List[str]: the list of URI prefixes this PathHandler can support
71 """
72 raise NotImplementedError()
73
74 def _get_local_path(self, path: str, **kwargs: Any) -> str:
75 """
76 Get a filepath which is compatible with native Python I/O such as `open`
77 and `os.path`.
78 If URI points to a remote resource, this function may download and cache
79 the resource to local disk. In this case, this function is meant to be
80 used with read-only resources.
81 Args:
82 path (str): A URI supported by this PathHandler
83 Returns:
84 local_path (str): a file path which exists on the local file system
85 """
86 raise NotImplementedError()
87
88 def _open(
89 self, path: str, mode: str = "r", buffering: int = -1, **kwargs: Any
90 ) -> Union[IO[str], IO[bytes]]:
91 """
92 Open a stream to a URI, similar to the built-in `open`.
93 Args:
94 path (str): A URI supported by this PathHandler
95 mode (str): Specifies the mode in which the file is opened. It defaults
96 to 'r'.
97 buffering (int): An optional integer used to set the buffering policy.
98 Pass 0 to switch buffering off and an integer >= 1 to indicate the
99 size in bytes of a fixed-size chunk buffer. When no buffering
100 argument is given, the default buffering policy depends on the
101 underlying I/O implementation.
102 Returns:
103 file: a file-like object.
104 """
105 raise NotImplementedError()
106
107 def _copy(
108 self,
109 src_path: str,
110 dst_path: str,
111 overwrite: bool = False,
112 **kwargs: Any,
113 ) -> bool:
114 """
115 Copies a source path to a destination path.
116 Args:
117 src_path (str): A URI supported by this PathHandler
118 dst_path (str): A URI supported by this PathHandler
119 overwrite (bool): Bool flag for forcing overwrite of existing file
120 Returns:
121 status (bool): True on success
122 """
123 raise NotImplementedError()
124
125 def _exists(self, path: str, **kwargs: Any) -> bool:
126 """
127 Checks if there is a resource at the given URI.
128 Args:
129 path (str): A URI supported by this PathHandler
130 Returns:
131 bool: true if the path exists
132 """
133 raise NotImplementedError()
134
135 def _isfile(self, path: str, **kwargs: Any) -> bool:
136 """
137 Checks if the resource at the given URI is a file.
138 Args:
139 path (str): A URI supported by this PathHandler
140 Returns:
141 bool: true if the path is a file
142 """
143 raise NotImplementedError()
144
145 def _isdir(self, path: str, **kwargs: Any) -> bool:
146 """
147 Checks if the resource at the given URI is a directory.
148 Args:
149 path (str): A URI supported by this PathHandler
150 Returns:
151 bool: true if the path is a directory
152 """
153 raise NotImplementedError()
154
155 def _ls(self, path: str, **kwargs: Any) -> List[str]:
156 """
157 List the contents of the directory at the provided URI.
158 Args:
159 path (str): A URI supported by this PathHandler
160 Returns:
161 List[str]: list of contents in given path
162 """
163 raise NotImplementedError()
164
165 def _mkdirs(self, path: str, **kwargs: Any) -> None:
166 """
167 Recursive directory creation function. Like mkdir(), but makes all
168 intermediate-level directories needed to contain the leaf directory.
169 Similar to the native `os.makedirs`.
170 Args:
171 path (str): A URI supported by this PathHandler
172 """
173 raise NotImplementedError()
174
175 def _rm(self, path: str, **kwargs: Any) -> None:
176 """
177 Remove the file (not directory) at the provided URI.
178 Args:
179 path (str): A URI supported by this PathHandler
180 """
181 raise NotImplementedError()
182
183
185 """
186 Handles paths that can be accessed using Python native system calls. This
187 handler uses `open()` and `os.*` calls on the given path.
188 """
189
190 def _get_local_path(self, path: str, **kwargs: Any) -> str:
191 self._check_kwargs(kwargs)
192 return path
193
194 def _open(
195 self,
196 path: str,
197 mode: str = "r",
198 buffering: int = -1,
199 encoding: Optional[str] = None,
200 errors: Optional[str] = None,
201 newline: Optional[str] = None,
202 closefd: bool = True,
203 opener: Optional[Callable] = None,
204 **kwargs: Any,
205 ) -> Union[IO[str], IO[bytes]]:
206 """
207 Open a path.
208 Args:
209 path (str): A URI supported by this PathHandler
210 mode (str): Specifies the mode in which the file is opened. It defaults
211 to 'r'.
212 buffering (int): An optional integer used to set the buffering policy.
213 Pass 0 to switch buffering off and an integer >= 1 to indicate the
214 size in bytes of a fixed-size chunk buffer. When no buffering
215 argument is given, the default buffering policy works as follows:
216 * Binary files are buffered in fixed-size chunks; the size of
217 the buffer is chosen using a heuristic trying to determine the
218 underlying device’s “block size” and falling back on
219 io.DEFAULT_BUFFER_SIZE. On many systems, the buffer will
220 typically be 4096 or 8192 bytes long.
221 encoding (Optional[str]): the name of the encoding used to decode or
222 encode the file. This should only be used in text mode.
223 errors (Optional[str]): an optional string that specifies how encoding
224 and decoding errors are to be handled. This cannot be used in binary
225 mode.
226 newline (Optional[str]): controls how universal newlines mode works
227 (it only applies to text mode). It can be None, '', '\n', '\r',
228 and '\r\n'.
229 closefd (bool): If closefd is False and a file descriptor rather than
230 a filename was given, the underlying file descriptor will be kept
231 open when the file is closed. If a filename is given closefd must
232 be True (the default) otherwise an error will be raised.
233 opener (Optional[Callable]): A custom opener can be used by passing
234 a callable as opener. The underlying file descriptor for the file
235 object is then obtained by calling opener with (file, flags).
236 opener must return an open file descriptor (passing os.open as opener
237 results in functionality similar to passing None).
238 See https://docs.python.org/3/library/functions.html#open for details.
239 Returns:
240 file: a file-like object.
241 """
242 self._check_kwargs(kwargs)
243 return open( # type: ignore
244 path,
245 mode,
246 buffering=buffering,
247 encoding=encoding,
248 errors=errors,
249 newline=newline,
250 closefd=closefd,
251 opener=opener,
252 )
253
254 def _copy(
255 self,
256 src_path: str,
257 dst_path: str,
258 overwrite: bool = False,
259 **kwargs: Any,
260 ) -> bool:
261 """
262 Copies a source path to a destination path.
263 Args:
264 src_path (str): A URI supported by this PathHandler
265 dst_path (str): A URI supported by this PathHandler
266 overwrite (bool): Bool flag for forcing overwrite of existing file
267 Returns:
268 status (bool): True on success
269 """
270 self._check_kwargs(kwargs)
271
272 if os.path.exists(dst_path) and not overwrite:
273 logger = logging.getLogger(__name__)
274 logger.error("Destination file {} already exists.".format(dst_path))
275 return False
276
277 try:
278 shutil.copyfile(src_path, dst_path)
279 return True
280 except Exception as e:
281 logger = logging.getLogger(__name__)
282 logger.error("Error in file copy - {}".format(str(e)))
283 return False
284
285 def _exists(self, path: str, **kwargs: Any) -> bool:
286 self._check_kwargs(kwargs)
287 return os.path.exists(path)
288
289 def _isfile(self, path: str, **kwargs: Any) -> bool:
290 self._check_kwargs(kwargs)
291 return os.path.isfile(path)
292
293 def _isdir(self, path: str, **kwargs: Any) -> bool:
294 self._check_kwargs(kwargs)
295 return os.path.isdir(path)
296
297 def _ls(self, path: str, **kwargs: Any) -> List[str]:
298 self._check_kwargs(kwargs)
299 return os.listdir(path)
300
301 def _mkdirs(self, path: str, **kwargs: Any) -> None:
302 self._check_kwargs(kwargs)
303 try:
304 os.makedirs(path, exist_ok=True)
305 except OSError as e:
306 # EEXIST it can still happen if multiple processes are creating the dir
307 if e.errno != errno.EEXIST:
308 raise
309
310 def _rm(self, path: str, **kwargs: Any) -> None:
311 self._check_kwargs(kwargs)
312 os.remove(path)
313
314
316 """
317 A class for users to open generic paths or translate generic paths to file names.
318 """
319
320 _PATH_HANDLERS: MutableMapping[str, PathHandler] = OrderedDict()
321 _NATIVE_PATH_HANDLER = NativePathHandler()
322
323 @staticmethod
324 def __get_path_handler(path: str) -> PathHandler:
325 """
326 Finds a PathHandler that supports the given path. Falls back to the native
327 PathHandler if no other handler is found.
328 Args:
329 path (str): URI path to resource
330 Returns:
331 handler (PathHandler)
332 """
333 for p in PathManager._PATH_HANDLERS.keys():
334 if path.startswith(p):
335 return PathManager._PATH_HANDLERS[p]
336 return PathManager._NATIVE_PATH_HANDLER
337
338 @staticmethod
339 def open(
340 path: str, mode: str = "r", buffering: int = -1, **kwargs: Any
341 ) -> Union[IO[str], IO[bytes]]:
342 """
343 Open a stream to a URI, similar to the built-in `open`.
344 Args:
345 path (str): A URI supported by this PathHandler
346 mode (str): Specifies the mode in which the file is opened. It defaults
347 to 'r'.
348 buffering (int): An optional integer used to set the buffering policy.
349 Pass 0 to switch buffering off and an integer >= 1 to indicate the
350 size in bytes of a fixed-size chunk buffer. When no buffering
351 argument is given, the default buffering policy depends on the
352 underlying I/O implementation.
353 Returns:
354 file: a file-like object.
355 """
356 return PathManager.__get_path_handler(path)._open( # type: ignore
357 path, mode, buffering=buffering, **kwargs
358 )
359
360 @staticmethod
361 def copy(
362 src_path: str, dst_path: str, overwrite: bool = False, **kwargs: Any
363 ) -> bool:
364 """
365 Copies a source path to a destination path.
366 Args:
367 src_path (str): A URI supported by this PathHandler
368 dst_path (str): A URI supported by this PathHandler
369 overwrite (bool): Bool flag for forcing overwrite of existing file
370 Returns:
371 status (bool): True on success
372 """
373
374 # Copying across handlers is not supported.
375 assert PathManager.__get_path_handler( # type: ignore
376 src_path
377 ) == PathManager.__get_path_handler(dst_path)
378 return PathManager.__get_path_handler(src_path)._copy(
379 src_path, dst_path, overwrite, **kwargs
380 )
381
382 @staticmethod
383 def get_local_path(path: str, **kwargs: Any) -> str:
384 """
385 Get a filepath which is compatible with native Python I/O such as `open`
386 and `os.path`.
387 If URI points to a remote resource, this function may download and cache
388 the resource to local disk.
389 Args:
390 path (str): A URI supported by this PathHandler
391 Returns:
392 local_path (str): a file path which exists on the local file system
393 """
394 return PathManager.__get_path_handler( # type: ignore
395 path
396 )._get_local_path(path, **kwargs)
397
398 @staticmethod
399 def exists(path: str, **kwargs: Any) -> bool:
400 """
401 Checks if there is a resource at the given URI.
402 Args:
403 path (str): A URI supported by this PathHandler
404 Returns:
405 bool: true if the path exists
406 """
407 return PathManager.__get_path_handler(path)._exists( # type: ignore
408 path, **kwargs
409 )
410
411 @staticmethod
412 def isfile(path: str, **kwargs: Any) -> bool:
413 """
414 Checks if there the resource at the given URI is a file.
415 Args:
416 path (str): A URI supported by this PathHandler
417 Returns:
418 bool: true if the path is a file
419 """
420 return PathManager.__get_path_handler(path)._isfile( # type: ignore
421 path, **kwargs
422 )
423
424 @staticmethod
425 def isdir(path: str, **kwargs: Any) -> bool:
426 """
427 Checks if the resource at the given URI is a directory.
428 Args:
429 path (str): A URI supported by this PathHandler
430 Returns:
431 bool: true if the path is a directory
432 """
433 return PathManager.__get_path_handler(path)._isdir( # type: ignore
434 path, **kwargs
435 )
436
437 @staticmethod
438 def ls(path: str, **kwargs: Any) -> List[str]:
439 """
440 List the contents of the directory at the provided URI.
441 Args:
442 path (str): A URI supported by this PathHandler
443 Returns:
444 List[str]: list of contents in given path
445 """
446 return PathManager.__get_path_handler(path)._ls( # type: ignore
447 path, **kwargs
448 )
449
450 @staticmethod
451 def mkdirs(path: str, **kwargs: Any) -> None:
452 """
453 Recursive directory creation function. Like mkdir(), but makes all
454 intermediate-level directories needed to contain the leaf directory.
455 Similar to the native `os.makedirs`.
456 Args:
457 path (str): A URI supported by this PathHandler
458 """
459 return PathManager.__get_path_handler(path)._mkdirs( # type: ignore
460 path, **kwargs
461 )
462
463 @staticmethod
464 def rm(path: str, **kwargs: Any) -> None:
465 """
466 Remove the file (not directory) at the provided URI.
467 Args:
468 path (str): A URI supported by this PathHandler
469 """
470 return PathManager.__get_path_handler(path)._rm( # type: ignore
471 path, **kwargs
472 )
473
474 @staticmethod
475 def register_handler(handler: PathHandler) -> None:
476 """
477 Register a path handler associated with `handler._get_supported_prefixes`
478 URI prefixes.
479 Args:
480 handler (PathHandler)
481 """
482 assert isinstance(handler, PathHandler), handler
483 for prefix in handler._get_supported_prefixes():
484 assert prefix not in PathManager._PATH_HANDLERS
485 PathManager._PATH_HANDLERS[prefix] = handler
486
487 # Sort path handlers in reverse order so longer prefixes take priority,
488 # eg: http://foo/bar before http://foo
489 PathManager._PATH_HANDLERS = OrderedDict(
490 sorted(
491 PathManager._PATH_HANDLERS.items(),
492 key=lambda t: t[0],
493 reverse=True,
494 )
495 )
496
497 @staticmethod
498 def set_strict_kwargs_checking(enable: bool) -> None:
499 """
500 Toggles strict kwargs checking. If enabled, a ValueError is thrown if any
501 unused parameters are passed to a PathHandler function. If disabled, only
502 a warning is given.
503 With a centralized file API, there's a tradeoff of convenience and
504 correctness delegating arguments to the proper I/O layers. An underlying
505 `PathHandler` may support custom arguments which should not be statically
506 exposed on the `PathManager` function. For example, a custom `HTTPURLHandler`
507 may want to expose a `cache_timeout` argument for `open()` which specifies
508 how old a locally cached resource can be before it's refetched from the
509 remote server. This argument would not make sense for a `NativePathHandler`.
510 If strict kwargs checking is disabled, `cache_timeout` can be passed to
511 `PathManager.open` which will forward the arguments to the underlying
512 handler. By default, checking is enabled since it is innately unsafe:
513 multiple `PathHandler`s could reuse arguments with different semantic
514 meanings or types.
515 Args:
516 enable (bool)
517 """
518 PathManager._NATIVE_PATH_HANDLER._strict_kwargs_check = enable
519 for handler in PathManager._PATH_HANDLERS.values():
520 handler._strict_kwargs_check = enable
bool _isdir(self, str path, **Any kwargs)
Definition file_io.py:293
None _rm(self, str path, **Any kwargs)
Definition file_io.py:310
List[str] _ls(self, str path, **Any kwargs)
Definition file_io.py:297
bool _exists(self, str path, **Any kwargs)
Definition file_io.py:285
str _get_local_path(self, str path, **Any kwargs)
Definition file_io.py:190
Union[IO[str], IO[bytes]] _open(self, str path, str mode="r", int buffering=-1, Optional[str] encoding=None, Optional[str] errors=None, Optional[str] newline=None, bool closefd=True, Optional[Callable] opener=None, **Any kwargs)
Definition file_io.py:205
bool _copy(self, str src_path, str dst_path, bool overwrite=False, **Any kwargs)
Definition file_io.py:260
bool _isfile(self, str path, **Any kwargs)
Definition file_io.py:289
None _mkdirs(self, str path, **Any kwargs)
Definition file_io.py:301
None _mkdirs(self, str path, **Any kwargs)
Definition file_io.py:165
bool _exists(self, str path, **Any kwargs)
Definition file_io.py:125
Union[IO[str], IO[bytes]] _open(self, str path, str mode="r", int buffering=-1, **Any kwargs)
Definition file_io.py:90
None _check_kwargs(self, Dict[str, Any] kwargs)
Definition file_io.py:49
str _get_local_path(self, str path, **Any kwargs)
Definition file_io.py:74
bool _isdir(self, str path, **Any kwargs)
Definition file_io.py:145
bool _isfile(self, str path, **Any kwargs)
Definition file_io.py:135
None _rm(self, str path, **Any kwargs)
Definition file_io.py:175
List[str] _get_supported_prefixes(self)
Definition file_io.py:67
List[str] _ls(self, str path, **Any kwargs)
Definition file_io.py:155
bool _copy(self, str src_path, str dst_path, bool overwrite=False, **Any kwargs)
Definition file_io.py:113
bool isfile(str path, **Any kwargs)
Definition file_io.py:412
None mkdirs(str path, **Any kwargs)
Definition file_io.py:451
List[str] ls(str path, **Any kwargs)
Definition file_io.py:438
bool isdir(str path, **Any kwargs)
Definition file_io.py:425
None rm(str path, **Any kwargs)
Definition file_io.py:464
bool exists(str path, **Any kwargs)
Definition file_io.py:399
None register_handler(PathHandler handler)
Definition file_io.py:475
Union[IO[str], IO[bytes]] open(str path, str mode="r", int buffering=-1, **Any kwargs)
Definition file_io.py:341
str get_local_path(str path, **Any kwargs)
Definition file_io.py:383
bool copy(str src_path, str dst_path, bool overwrite=False, **Any kwargs)
Definition file_io.py:363
None set_strict_kwargs_checking(bool enable)
Definition file_io.py:498
str get_cache_dir(Optional[str] cache_dir=None)
Definition file_io.py:23