You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

s3path

Package Overview
Dependencies
Maintainers
1
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

s3path - pypi Package Compare versions

Comparing version
0.6.2
to
0.6.3
+1
-1
PKG-INFO
Metadata-Version: 2.4
Name: s3path
Version: 0.6.2
Version: 0.6.3
Home-page: https://github.com/liormizr/s3path

@@ -5,0 +5,0 @@ Author: Lior Mizrahi

Metadata-Version: 2.4
Name: s3path
Version: 0.6.2
Version: 0.6.3
Home-page: https://github.com/liormizr/s3path

@@ -5,0 +5,0 @@ Author: Lior Mizrahi

@@ -8,3 +8,3 @@ """

__version__ = '0.6.2'
__version__ = '0.6.3'
__all__ = (

@@ -11,0 +11,0 @@ 'Path',

@@ -158,4 +158,2 @@ import sys

return True
with suppress(KeyError):
return path._cache['is_dir']

@@ -168,5 +166,3 @@ resource, config = configuration_map.get_configuration(path)

config=config)
is_dir = any(query)
path._cache['is_dir'] = is_dir
return is_dir
return any(query)

@@ -173,0 +169,0 @@

@@ -5,3 +5,2 @@ from __future__ import annotations

import sys
import typing
import fnmatch

@@ -13,3 +12,3 @@ import posixpath

from pathlib import PurePath, Path
from typing import Union, Literal, Optional
from typing import TYPE_CHECKING, Literal, Self, Generator
from io import DEFAULT_BUFFER_SIZE, TextIOWrapper

@@ -19,6 +18,7 @@

if typing.TYPE_CHECKING:
if TYPE_CHECKING:
from os import PathLike
import smart_open
from boto3.resources.factory import ServiceResource
KeyFileObjectType = Union[TextIOWrapper, smart_open.s3.Reader, smart_open.s3.MultipartWriter]
from boto3.resources.base import ServiceResource
KeyFileObjectType = TextIOWrapper | smart_open.s3.Reader | smart_open.s3.MultipartWriter

@@ -31,5 +31,5 @@ from . import accessor

*,
parameters: Optional[dict] = None,
resource: Optional[ServiceResource] = None,
glob_new_algorithm: Optional[bool] = None):
parameters: dict | None = None,
resource: ServiceResource | None = None,
glob_new_algorithm: bool | None = None):
if not isinstance(path, PureS3Path):

@@ -81,3 +81,3 @@ raise TypeError(f'path argument have to be a {PurePath} type. got {type(path)}')

@classmethod
def from_uri(cls, uri: str):
def from_uri(cls, uri: str) -> PureS3Path:
"""

@@ -96,3 +96,3 @@ from_uri class method create a class instance from url

@classmethod
def from_bucket_key(cls, bucket: str, key: str):
def from_bucket_key(cls, bucket: str | PathLike, key: str | PathLike) -> PureS3Path:
"""

@@ -286,14 +286,5 @@ from_bucket_key class method create a class instance from bucket, key pair's

class _PathCacheMixin:
"""
This is a mixin class to cache the results and path state.
Note: this is experimental and will be more robust in the future.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._cache = {}
class S3Path(_PathNotSupportedMixin, _PathCacheMixin, PureS3Path, Path):
def stat(self, *, follow_symlinks: bool = True) -> accessor.StatResult:
class S3Path(_PathNotSupportedMixin, PureS3Path, Path):
def stat(self, *, follow_symlinks: bool = True) -> accessor.StatResult | None:
"""

@@ -313,3 +304,3 @@ Returns information about this path (similarly to boto3's ObjectSummary).

def absolute(self) -> S3Path:
def absolute(self) -> Self:
"""

@@ -324,3 +315,3 @@ Handle absolute method only if the path is already an absolute one

def owner(self) -> str:
def owner(self, *, follow_symlinks: bool = False) -> str:
"""

@@ -331,2 +322,4 @@ Returns the name of the user owning the Bucket or key.

self._absolute_path_validation()
if follow_symlinks:
raise NotImplementedError(f'Setting follow_symlinks to {follow_symlinks} is unsupported on S3 service.')
if not self.is_file():

@@ -336,3 +329,3 @@ raise KeyError('file not found')

def rename(self, target):
def rename(self, target) -> S3Path:
"""

@@ -351,3 +344,3 @@ Renames this file or Bucket / key prefix / key to the given target.

def replace(self, target):
def replace(self, target) -> S3Path:
"""

@@ -370,3 +363,3 @@ Renames this Bucket / key prefix / key to the given target.

def samefile(self, other_path: Union[str, S3Path]) -> bool:
def samefile(self, other_path: str | PathLike) -> bool:
"""

@@ -377,3 +370,3 @@ Returns whether this path points to the same Bucket key as other_path,

self._absolute_path_validation()
if not isinstance(other_path, Path):
if not isinstance(other_path, S3Path):
other_path = type(self)(other_path)

@@ -419,3 +412,3 @@ return self.bucket == other_path.bucket and self.key == other_path.key and self.is_file()

def is_dir(self) -> bool:
def is_dir(self, *, follow_symlinks: bool = False) -> bool:
"""

@@ -427,2 +420,4 @@ Returns True if the path points to a Bucket or a key prefix, False if it points to a full key path.

self._absolute_path_validation()
if follow_symlinks:
raise NotImplementedError(f'Setting follow_symlinks to {follow_symlinks} is unsupported on S3 service.')
if self.bucket and not self.key:

@@ -432,3 +427,3 @@ return True

def is_file(self) -> bool:
def is_file(self, *, follow_symlinks: bool = False) -> bool:
"""

@@ -440,2 +435,4 @@ Returns True if the path points to a Bucket key, False if it points to Bucket or a key prefix.

self._absolute_path_validation()
if follow_symlinks:
raise NotImplementedError(f'Setting follow_symlinks to {follow_symlinks} is unsupported on S3 service.')
if not self.bucket or not self.key:

@@ -448,3 +445,3 @@ return False

def exists(self) -> bool:
def exists(self, *, follow_symlinks: bool = False) -> bool:
"""

@@ -454,2 +451,4 @@ Whether the path points to an existing Bucket, key or key prefix.

self._absolute_path_validation()
if follow_symlinks:
raise NotImplementedError(f'Setting follow_symlinks to {follow_symlinks} is unsupported on S3 service.')
if not self.bucket:

@@ -459,3 +458,3 @@ return True

def iterdir(self):
def iterdir(self) -> Generator['S3Path']:
"""

@@ -468,3 +467,2 @@ When the path points to a Bucket or a key prefix, yield path objects of the directory contents

path = self / entry.name
path._cache['is_dir'] = entry.is_dir()
yield path

@@ -476,5 +474,5 @@

buffering: int = DEFAULT_BUFFER_SIZE,
encoding: Optional[str] = None,
errors: Optional[str] = None,
newline: Optional[str] = None) -> KeyFileObjectType:
encoding: str | None = None,
errors: str | None = None,
newline: str | None = None) -> KeyFileObjectType:
"""

@@ -494,3 +492,7 @@ Opens the Bucket key pointed to by the path, returns a Key file object that you can read/write with

def glob(self, pattern: str, *, case_sensitive=None, recurse_symlinks=False):
def glob(
self,
pattern: str, *,
case_sensitive: bool | None = None,
recurse_symlinks: bool = False) -> Generator['S3Path']:
"""

@@ -518,3 +520,7 @@ Glob the given relative pattern in the Bucket / key prefix represented by this path,

def rglob(self, pattern: str, *, case_sensitive=None, recurse_symlinks=False):
def rglob(
self,
pattern: str, *,
case_sensitive: bool | None = None,
recurse_symlinks: bool = False) -> Generator['S3Path']:
"""

@@ -540,3 +546,3 @@ This is like calling S3Path.glob with "**/" added in front of the given relative pattern

def get_presigned_url(self, expire_in: Union[timedelta, int] = 3600) -> str:
def get_presigned_url(self, expire_in: timedelta | int = 3600) -> str:
"""

@@ -612,3 +618,7 @@ Returns a pre-signed url. Anyone with the url can make a GET request to get the file.

def walk(self, top_down: bool = True, on_error:bool = None, follow_symlinks: bool = False):
def walk(
self,
top_down: bool = True,
on_error:bool = None,
follow_symlinks: bool = False) -> Generator[tuple['S3Path', list[str], list[str]]]:
if follow_symlinks:

@@ -652,3 +662,3 @@ raise NotImplementedError(f'Setting follow_symlinks to {follow_symlinks} is unsupported on S3 service.')

@classmethod
def from_uri(cls, uri: str, *, version_id: str):
def from_uri(cls, uri: str, *, version_id: str) -> PureVersionedS3Path:
"""

@@ -666,3 +676,3 @@ from_uri class method creates a class instance from uri and version id

@classmethod
def from_bucket_key(cls, bucket: str, key: str, *, version_id: str):
def from_bucket_key(cls, bucket: str, key: str, *, version_id: str) -> PureVersionedS3Path:
"""

@@ -679,3 +689,3 @@ from_bucket_key class method creates a class instance from bucket, key and version id

def with_segments(self, *pathsegments):
def with_segments(self, *pathsegments) -> PureVersionedS3Path:
"""Construct a new path object from any number of path-like objects.

@@ -682,0 +692,0 @@ Subclasses may override this method to customize how new path objects

@@ -258,16 +258,9 @@ """

dummy_object = resource.Object('bucket', 'key')
if smart_open.__version__ >= '5.1.0':
self._smart_open_new_version_kwargs(
dummy_object,
resource,
config,
transport_params,
smart_open_kwargs)
else:
self._smart_open_old_version_kwargs(
dummy_object,
resource,
config,
transport_params,
smart_open_kwargs)
self._update_smart_open_kwargs(
dummy_object,
resource,
config,
transport_params,
smart_open_kwargs,
)

@@ -445,9 +438,9 @@ file_object = smart_open.open(**smart_open_kwargs)

def _boto3_method_with_extraargs(
self,
boto3_method,
config=None,
args=(),
kwargs=None,
extra_args=None,
allowed_extra_args=()):
self,
boto3_method,
config=None,
args=(),
kwargs=None,
extra_args=None,
allowed_extra_args=()):
kwargs = kwargs or {}

@@ -464,3 +457,3 @@ extra_args = extra_args or {}

def _smart_open_new_version_kwargs(
def _update_smart_open_kwargs(
self,

@@ -473,3 +466,3 @@ dummy_object,

"""
New Smart-Open api
New Smart-Open (>=5.1.0) api
Doc: https://github.com/RaRe-Technologies/smart_open/blob/develop/MIGRATING_FROM_OLDER_VERSIONS.rst

@@ -493,50 +486,3 @@ """

def _smart_open_old_version_kwargs(
self,
dummy_object,
resource,
config,
transport_params,
smart_open_kwargs):
"""
Old Smart-Open api
<5.0.0
"""
def get_resource_kwargs():
# This is a good example of the complicity of boto3 and botocore
# resource arguments from the resource object :-/
# very annoying...
try:
access_key = resource.meta.client._request_signer._credentials.access_key
secret_key = resource.meta.client._request_signer._credentials.secret_key
token = resource.meta.client._request_signer._credentials.token
except AttributeError:
access_key = secret_key = token = None
return {
'endpoint_url': resource.meta.client.meta._endpoint_url,
'config': resource.meta.client._client_config,
'region_name': resource.meta.client._client_config.region_name,
'use_ssl': resource.meta.client._endpoint.host.startswith('https'),
'verify': resource.meta.client._endpoint.http_session._verify,
'aws_access_key_id': access_key,
'aws_secret_access_key': secret_key,
'aws_session_token': token,
}
initiate_multipart_upload_kwargs = self._update_kwargs_with_config(
dummy_object.initiate_multipart_upload, config=config)
object_kwargs = self._update_kwargs_with_config(dummy_object.get, config=config)
transport_params.update(
multipart_upload_kwargs=initiate_multipart_upload_kwargs,
object_kwargs=object_kwargs,
resource_kwargs=get_resource_kwargs(),
session=boto3.DEFAULT_SESSION,
)
smart_open_kwargs.update(
ignore_ext=True,
transport_params=transport_params,
)
class _VersionedS3Accessor(_S3Accessor):

@@ -583,16 +529,9 @@

dummy_object = resource.Object('bucket', 'key')
if smart_open.__version__ >= '5.1.0':
self._smart_open_new_version_kwargs(
dummy_object,
resource,
config,
transport_params,
smart_open_kwargs)
else:
self._smart_open_old_version_kwargs(
dummy_object,
resource,
config,
transport_params,
smart_open_kwargs)
self._update_smart_open_kwargs(
dummy_object,
resource,
config,
transport_params,
smart_open_kwargs,
)

@@ -1031,4 +970,2 @@ file_object = smart_open.open(**smart_open_kwargs)

self._absolute_path_validation()
if smart_open.__version__ < '4.0.0' and mode.startswith('b'):
mode = ''.join(reversed(mode))
return self._accessor.open(

@@ -1035,0 +972,0 @@ self,

@@ -8,3 +8,3 @@ #!/usr/bin/env python

name='s3path',
version='0.6.2',
version='0.6.3',
url='https://github.com/liormizr/s3path',

@@ -11,0 +11,0 @@ author='Lior Mizrahi',

@@ -405,3 +405,3 @@ import shutil

with S3Path('/test-bucket/directory/Test.test').open() as fp:
assert len(fp.readlines(1)) == (1 if sys.version_info >= (3, 6) else 2)
assert len(fp.readlines(1)) == 1

@@ -497,18 +497,2 @@ with S3Path('/test-bucket/directory/Test.test').open('br') as fp:

@pytest.mark.skipif(sys.version_info < (3, 12), reason="requires python 3.12 or higher")
def test_issue_193(s3_mock):
s3 = boto3.resource('s3')
s3.create_bucket(Bucket='test-bucket')
object_summary = s3.ObjectSummary('test-bucket', 'docs/conf.py')
object_summary.put(Body=b'test data')
s3_path = S3Path('/test-bucket/docs')
assert sorted(s3_path.iterdir()) == sorted([
S3Path('/test-bucket/docs/conf.py'),
])
path = list(s3_path.iterdir())[0]
assert 'is_dir' in path._cache
assert not path._cache['is_dir']
def test_open_for_reading(s3_mock):

@@ -515,0 +499,0 @@ s3 = boto3.resource('s3')