cloud.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. from __future__ import annotations
  2. import os
  3. from typing import Any
  4. from upath._compat import FSSpecAccessorShim as _FSSpecAccessorShim
  5. from upath._flavour import upath_strip_protocol
  6. from upath.core import UPath
  7. __all__ = [
  8. "CloudPath",
  9. "GCSPath",
  10. "S3Path",
  11. "AzurePath",
  12. ]
  13. # accessors are deprecated
  14. _CloudAccessor = _FSSpecAccessorShim
  15. class CloudPath(UPath):
  16. __slots__ = ()
  17. @classmethod
  18. def _transform_init_args(
  19. cls,
  20. args: tuple[str | os.PathLike, ...],
  21. protocol: str,
  22. storage_options: dict[str, Any],
  23. ) -> tuple[tuple[str | os.PathLike, ...], str, dict[str, Any]]:
  24. for key in ["bucket", "netloc"]:
  25. bucket = storage_options.pop(key, None)
  26. if bucket:
  27. if str(args[0]).startswith("/"):
  28. args = (f"{protocol}://{bucket}{args[0]}", *args[1:])
  29. else:
  30. args0 = upath_strip_protocol(args[0])
  31. args = (f"{protocol}://{bucket}/", args0, *args[1:])
  32. break
  33. return super()._transform_init_args(args, protocol, storage_options)
  34. def mkdir(
  35. self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False
  36. ) -> None:
  37. if not parents and not exist_ok and self.exists():
  38. raise FileExistsError(self.path)
  39. super().mkdir(mode=mode, parents=parents, exist_ok=exist_ok)
  40. def iterdir(self):
  41. if self.is_file():
  42. raise NotADirectoryError(str(self))
  43. if self.parts[-1:] == ("",):
  44. yield from self.parent.iterdir()
  45. else:
  46. yield from super().iterdir()
  47. def relative_to(self, other, /, *_deprecated, walk_up=False):
  48. # use the parent implementation for the ValueError logic
  49. super().relative_to(other, *_deprecated, walk_up=False)
  50. return self
  51. class GCSPath(CloudPath):
  52. __slots__ = ()
  53. def __init__(
  54. self, *args, protocol: str | None = None, **storage_options: Any
  55. ) -> None:
  56. super().__init__(*args, protocol=protocol, **storage_options)
  57. if not self.drive and len(self.parts) > 1:
  58. raise ValueError("non key-like path provided (bucket/container missing)")
  59. def mkdir(
  60. self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False
  61. ) -> None:
  62. try:
  63. super().mkdir(mode=mode, parents=parents, exist_ok=exist_ok)
  64. except TypeError as err:
  65. if "unexpected keyword argument 'create_parents'" in str(err):
  66. self.fs.mkdir(self.path)
  67. class S3Path(CloudPath):
  68. __slots__ = ()
  69. def __init__(
  70. self, *args, protocol: str | None = None, **storage_options: Any
  71. ) -> None:
  72. super().__init__(*args, protocol=protocol, **storage_options)
  73. if not self.drive and len(self.parts) > 1:
  74. raise ValueError("non key-like path provided (bucket/container missing)")
  75. class AzurePath(CloudPath):
  76. __slots__ = ()
  77. def __init__(
  78. self, *args, protocol: str | None = None, **storage_options: Any
  79. ) -> None:
  80. super().__init__(*args, protocol=protocol, **storage_options)
  81. if not self.drive and len(self.parts) > 1:
  82. raise ValueError("non key-like path provided (bucket/container missing)")