4444 S3Object ,
4545 S3ObjectType ,
4646 S3ObjectVersion ,
47- S3PutObject ,
4847 S3StorageClass ,
4948)
5049from pyathena .filesystem .s3_path import S3Path
@@ -1403,7 +1402,9 @@ def touch(self, path: str, truncate: bool = True, **kwargs) -> dict[str, Any]:
14031402 if not s3_path .key :
14041403 raise ValueError ("Cannot touch the bucket." )
14051404
1406- object_ = self ._put_object (bucket = s3_path .bucket , key = s3_path .key , body = None , ** kwargs )
1405+ # The empty body is passed, so that a body keyword argument raises
1406+ # TypeError.
1407+ object_ = self .core .put_object (s3_path , None , ** kwargs )
14071408 self .invalidate_cache (path )
14081409 return object_ .to_dict ()
14091410
@@ -1873,7 +1874,7 @@ def pipe_file(
18731874 # buffered path does.
18741875 value = bytes (value )
18751876
1876- self ._put_object ( bucket = s3_path . bucket , key = s3_path . key , body = value , ** request_kwargs )
1877+ self .core . put_object ( s3_path , value , ** request_kwargs )
18771878 self .invalidate_cache (path )
18781879
18791880 def _finish_multipart_upload (
@@ -2012,13 +2013,7 @@ def cat_file(
20122013 return b""
20132014 ranges = (start , end )
20142015 try :
2015- return self ._get_object (
2016- bucket = s3_path .bucket ,
2017- key = s3_path .key ,
2018- ranges = ranges ,
2019- version_id = version_id ,
2020- ** kwargs ,
2021- )[1 ]
2016+ return self .core .get_object (s3_path .with_version_id (version_id ), ranges , ** kwargs )
20222017 except OSError as e :
20232018 if (
20242019 ranges
@@ -2869,69 +2864,6 @@ def _open(
28692864 ** kwargs ,
28702865 )
28712866
2872- def _get_object (
2873- self ,
2874- bucket : str ,
2875- key : str ,
2876- ranges : tuple [int , int | None ] | None = None ,
2877- version_id : str | None = None ,
2878- ** kwargs ,
2879- ) -> tuple [int , bytes ]:
2880- """Read an object or a byte range of it with GetObject.
2881-
2882- Args:
2883- bucket: The bucket name.
2884- key: The object key.
2885- ranges: The ``(start, end)`` byte range to read, with an exclusive
2886- end or ``None`` to read to the end of the object (the last
2887- ``-start`` bytes for a negative start), or ``None`` to read
2888- the whole object.
2889- version_id: The version ID to read, or ``None`` for the latest.
2890- **kwargs: Additional parameters passed to the GetObject API.
2891-
2892- Returns:
2893- Tuple of the start of the range as given (0 for the whole
2894- object) and the bytes read.
2895-
2896- Raises:
2897- ValueError: If the range is empty. S3 ignores a range whose last
2898- byte precedes its first byte and returns the whole object.
2899- """
2900- request = {"Bucket" : bucket , "Key" : key }
2901- if ranges :
2902- if ranges [1 ] is not None and ranges [0 ] >= ranges [1 ]:
2903- raise ValueError (f"Invalid empty range: { ranges } ." )
2904- range_ = S3File ._format_ranges (ranges )
2905- request .update ({"Range" : range_ })
2906- else :
2907- ranges = (0 , 0 )
2908- range_ = "bytes=0-"
2909- if version_id :
2910- request .update ({"VersionId" : version_id })
2911-
2912- _logger .debug (f"Get object: { S3Path (bucket , key , version_id ).uri } range={ range_ } " )
2913- response = self ._call (
2914- self ._client .get_object ,
2915- # The fields of the request take precedence over inherited
2916- # parameters of the same name.
2917- ** {** kwargs , ** request },
2918- )
2919- return ranges [0 ], cast (bytes , response ["Body" ].read ())
2920-
2921- def _put_object (self , bucket : str , key : str , body : bytes | None , ** kwargs ) -> S3PutObject :
2922- request : dict [str , Any ] = {"Bucket" : bucket , "Key" : key }
2923- if body :
2924- request .update ({"Body" : body })
2925-
2926- _logger .debug (f"Put object: s3://{ bucket } /{ key } " )
2927- response = self ._call (
2928- self ._client .put_object ,
2929- # The fields of the request take precedence over inherited
2930- # parameters of the same name.
2931- ** {** kwargs , ** request },
2932- )
2933- return S3PutObject (response )
2934-
29352867 def _call (self , method : str | Callable [..., Any ], ** kwargs ) -> dict [str , Any ]:
29362868 """Send a request with the core (see :meth:`S3Core.call`).
29372869
@@ -3364,11 +3296,8 @@ def commit(self) -> None:
33643296 # Upload files smaller than block size.
33653297 self .buffer .seek (0 )
33663298 data = self .buffer .read ()
3367- self .fs ._put_object (
3368- bucket = self .bucket ,
3369- key = self .key ,
3370- body = data ,
3371- ** self ._get_request_kwargs ("put_object" ),
3299+ self .fs .core .put_object (
3300+ S3Path (self .bucket , self .key ), data , ** self ._get_request_kwargs ("put_object" )
33723301 )
33733302 else :
33743303 if not self .multipart_upload :
@@ -3488,45 +3417,18 @@ def _fetch_range(self, start: int, end: int) -> bytes:
34883417 ranges = self ._get_ranges (
34893418 start , end , max_workers = self .max_workers , worker_block_size = self .blocksize
34903419 )
3420+ path = S3Path (self .bucket , self .key , self .version_id )
3421+ request_kwargs = self ._get_request_kwargs ("get_object" )
34913422 if len (ranges ) > 1 :
34923423 futures = [
3493- self ._executor .submit (
3494- self .fs ._get_object ,
3495- bucket = self .bucket ,
3496- key = self .key ,
3497- ranges = r ,
3498- version_id = self .version_id ,
3499- ** self ._get_request_kwargs ("get_object" ),
3500- )
3424+ self ._executor .submit (self .fs .core .get_object , path , r , ** request_kwargs )
35013425 for r in ranges
35023426 ]
3503- object_ = self ._merge_objects ([f .result () for f in as_completed (futures )])
3504- else :
3505- object_ = self .fs ._get_object (
3506- self .bucket ,
3507- self .key ,
3508- ranges [0 ],
3509- self .version_id ,
3510- ** self ._get_request_kwargs ("get_object" ),
3511- )[1 ]
3512- return object_
3513-
3514- @staticmethod
3515- def _format_ranges (ranges : tuple [int , int | None ]) -> str :
3516- """Format a byte range as the value of an HTTP ``Range`` header.
3517-
3518- Args:
3519- ranges: The ``(start, end)`` byte range, with an exclusive end or
3520- ``None`` for the end of the object. A negative start with no
3521- end selects the last ``-start`` bytes.
3522-
3523- Returns:
3524- The range, such as ``bytes=0-99``, ``bytes=100-`` or ``bytes=-8``.
3525- """
3526- start , end = ranges
3527- if end is None :
3528- return f"bytes={ start } " if start < 0 else f"bytes={ start } -"
3529- return f"bytes={ start } -{ end - 1 } "
3427+ for future in as_completed (futures ):
3428+ # The failure of the first read to finish is raised.
3429+ future .result ()
3430+ return b"" .join (f .result () for f in futures )
3431+ return self .fs .core .get_object (path , ranges [0 ], ** request_kwargs )
35303432
35313433 @staticmethod
35323434 def _get_ranges (
@@ -3548,8 +3450,3 @@ def _get_ranges(
35483450 else :
35493451 ranges .append ((start , end ))
35503452 return ranges
3551-
3552- @staticmethod
3553- def _merge_objects (objects : list [tuple [int , bytes ]]) -> bytes :
3554- objects .sort (key = lambda x : x [0 ])
3555- return b"" .join ([obj for start , obj in objects ])
0 commit comments