Source code for signal_dataset.storage.backends.s3.options
"""Tunable settings for the S3 backend.These live here rather than in :mod:`signal_dataset.config` because the storagedomain may not import it (see ``tests/test_architecture.py``), and becauseendpoints and retry policy are transport concerns rather than dataset ones.Credentials are deliberately absent. Resolution is boto3's own chain —environment, shared config, instance or container role, web identity — matchinghow the GCS backend defers to Application Default Credentials. This packageneither reads nor stores credentials.To use these with ``sds.open`` and friends, either pass a configured store as``object_store=``, or register a configured backend once:: from signal_dataset.storage import default_registry from signal_dataset.storage.backends.s3 import S3Options, s3_backend default_registry().register( s3_backend(S3Options(endpoint_url="https://minio.example", addressing_style="path")), replace=True, )"""from__future__importannotationsfromdataclassesimportdataclass# A single PutObject is capped by S3 at 5 GiB. Anything larger needs multipart,# which cannot express create-only preconditions the same way.MAX_SINGLE_PART_BYTES=5*1024**3DEFAULT_MAX_ATTEMPTS=5DEFAULT_RETRY_MODE="standard"DEFAULT_CONFLICT_ATTEMPT_LIMIT=5DEFAULT_CONFLICT_RETRY_BASE_SECONDS=0.05DEFAULT_CONFLICT_RETRY_MAX_SECONDS=1.0DEFAULT_ETAG_MEMO_SIZE=128RETRY_MODES=("legacy","standard","adaptive")ADDRESSING_STYLES=("virtual","path")
[docs]@dataclass(frozen=True,slots=True)classS3Options:"""Transport settings for :class:`S3ObjectStore`."""region_name:str|None=Noneendpoint_url:str|None=Noneprofile_name:str|None=Noneaddressing_style:str|None=Nonemax_attempts:int=DEFAULT_MAX_ATTEMPTSretry_mode:str=DEFAULT_RETRY_MODEconflict_attempt_limit:int=DEFAULT_CONFLICT_ATTEMPT_LIMIT"""Total conditional-write attempts, not retries: 1 means no retry."""conflict_retry_base_seconds:float=DEFAULT_CONFLICT_RETRY_BASE_SECONDSconflict_retry_max_seconds:float=DEFAULT_CONFLICT_RETRY_MAX_SECONDSetag_memo_size:int=DEFAULT_ETAG_MEMO_SIZEmax_single_part_bytes:int=MAX_SINGLE_PART_BYTESdef__post_init__(self)->None:fornamein("max_attempts","conflict_attempt_limit","etag_memo_size","max_single_part_bytes",):value=getattr(self,name)ifisinstance(value,bool)ornotisinstance(value,int)orvalue<1:raiseValueError(f"{name} must be a positive integer")ifself.max_single_part_bytes>MAX_SINGLE_PART_BYTES:raiseValueError(f"max_single_part_bytes must not exceed the S3 limit of {MAX_SINGLE_PART_BYTES}")fornamein("conflict_retry_base_seconds","conflict_retry_max_seconds"):value=getattr(self,name)ifisinstance(value,bool)ornotisinstance(value,int|float)orvalue<0:raiseValueError(f"{name} must be a nonnegative number")ifself.conflict_retry_max_seconds<self.conflict_retry_base_seconds:raiseValueError("conflict_retry_max_seconds must not be below the base delay")ifself.retry_modenotinRETRY_MODES:raiseValueError(f"retry_mode must be one of {RETRY_MODES}")ifself.addressing_styleisnotNoneandself.addressing_stylenotinADDRESSING_STYLES:raiseValueError(f"addressing_style must be one of {ADDRESSING_STYLES} or None")fornamein("region_name","endpoint_url","profile_name"):value=getattr(self,name)ifvalueisnotNoneandnotvalue:raiseValueError(f"{name} must be non-empty or None")