1- struct S3Path{A<: AbstractAWSConfig } <: AbstractPath
1+ struct S3Path{A<: Union{Nothing, AbstractAWSConfig} } <: AbstractPath
22 segments:: Tuple{Vararg{String}}
33 root:: String
44 drive:: String
88
99# constructor that converts but does not require type parameter
1010function S3Path (segments, root:: AbstractString , drive:: AbstractString , isdirectory:: Bool ,
11- config:: AbstractAWSConfig )
11+ config:: Union{Nothing, AbstractAWSConfig} )
1212 S3Path {typeof(config)} (segments, root, drive, isdirectory, config)
1313end
1414
1515"""
1616 S3Path()
17- S3Path(str; config::AbstractAWSConfig=aws_config() )
17+ S3Path(str; config::Union{Nothing, AbstractAWSConfig}=nothing )
1818
1919Construct a new AWS S3 path type which should be of the form
2020"s3://<bucket>/prefix/to/my/object".
@@ -31,28 +31,30 @@ NOTES:
3131- On top of the standard path properties (e.g., `segments`, `root`, `drive`,
3232 `separator`), `S3Path`s also support `bucket` and `key` properties for your
3333 convenience.
34+ - if `config` is left at its default value of `nothing`, then the
35+ latest `global_aws_config()` will be used in any operations involving the
36+ path. To "freeze" the config at construction time, explicitly pass an
37+ `AbstractAWSConfig` to the `config` keyword argument.
3438"""
3539function S3Path ()
36- config = global_aws_config ()
37- account_id = aws_account_number (config)
38- region = config. region
40+ config = nothing
3941
4042 return S3Path (
4143 (),
4244 " /" ,
43- " s3:// $account_id - $region " ,
45+ " " ,
4446 true ,
4547 config,
4648 )
4749end
4850# below definition needed by FilePathsBase
49- S3Path {A} () where {A<: AbstractAWSConfig } = S3Path ()
51+ S3Path {A} () where {A<: Union{Nothing, AbstractAWSConfig} } = S3Path ()
5052
5153function S3Path (
5254 bucket:: AbstractString ,
5355 key:: AbstractString ;
5456 isdirectory:: Bool = false ,
55- config:: AbstractAWSConfig = global_aws_config () ,
57+ config:: Union{Nothing, AbstractAWSConfig} = nothing ,
5658)
5759 return S3Path (
5860 Tuple (filter! (! isempty, split (key, " /" ))),
@@ -67,7 +69,7 @@ function S3Path(
6769 bucket:: AbstractString ,
6870 key:: AbstractPath ;
6971 isdirectory:: Bool = false ,
70- config:: AbstractAWSConfig = global_aws_config () ,
72+ config:: Union{Nothing, AbstractAWSConfig} = nothing ,
7173)
7274 return S3Path (
7375 key. segments,
@@ -79,18 +81,15 @@ function S3Path(
7981end
8082
8183# To avoid a breaking change.
82- function S3Path (str:: AbstractString ; config:: AbstractAWSConfig = global_aws_config () )
84+ function S3Path (str:: AbstractString ; config:: Union{Nothing, AbstractAWSConfig} = nothing )
8385 result = tryparse (S3Path, str; config= config)
8486 result != = nothing || throw (ArgumentError (" Invalid s3 path string: $str " ))
8587 return result
8688end
8789
88- # if config=nothing, will not try to talk to AWS until after string is confirmed to be an s3 path
8990function Base. tryparse (:: Type{<:S3Path} , str:: AbstractString ; config:: Union{Nothing,AbstractAWSConfig} = nothing )
9091 str = String (str)
9192 startswith (str, " s3://" ) || return nothing
92- # we do this here so that the `@p_str` macro only tries to call AWS if it actually has an S3 path
93- (config ≡ nothing ) && (config = global_aws_config ())
9493 root = " "
9594 path = ()
9695 isdirectory = true
@@ -173,7 +172,10 @@ function FilePathsBase.parents(fp::S3Path)
173172 end
174173end
175174
176- FilePathsBase. exists (fp:: S3Path ) = s3_exists (fp. config, fp. bucket, fp. key)
175+ # Use `fp.config` unless it is nothing; in that case, get the latest `global_aws_config`
176+ get_config (fp:: S3Path ) = @something (fp. config, global_aws_config ())
177+
178+ FilePathsBase. exists (fp:: S3Path ) = s3_exists (get_config (fp), fp. bucket, fp. key)
177179Base. isfile (fp:: S3Path ) = ! fp. isdirectory && exists (fp)
178180function Base. isdir (fp:: S3Path )
179181 if isempty (fp. segments)
@@ -184,7 +186,7 @@ function Base.isdir(fp::S3Path)
184186 return false
185187 end
186188
187- objects = s3_list_objects (fp . config , fp. bucket, key; max_items= 1 )
189+ objects = s3_list_objects (get_config (fp) , fp. bucket, key; max_items= 1 )
188190
189191 # `objects` is a `Channel`, so we call iterate to see if there are any objects that
190192 # match our directory key.
@@ -205,7 +207,7 @@ function Base.stat(fp::S3Path)
205207 last_modified = DateTime (0 )
206208
207209 if exists (fp)
208- resp = s3_get_meta (fp . config , fp. bucket, fp. key)
210+ resp = s3_get_meta (get_config (fp) , fp. bucket, fp. key)
209211 # Example: "Thu, 03 Jan 2019 21:09:17 GMT"
210212 last_modified = DateTime (
211213 resp[" Last-Modified" ][1 : end - 4 ],
@@ -261,7 +263,7 @@ function Base.rm(fp::S3Path; recursive=false, kwargs...)
261263 end
262264
263265 @debug " delete: $fp "
264- s3_delete (fp . config , fp. bucket, fp. key)
266+ s3_delete (get_config (fp) , fp. bucket, fp. key)
265267end
266268
267269# We need to special case sync with S3Paths because of how directories
@@ -380,7 +382,7 @@ function Base.readdir(fp::S3Path; join=false, sort=true)
380382 if ! isempty (token)
381383 params[" continuation-token" ] = token
382384 end
383- S3. list_objects_v2 (fp. bucket, params; aws_config= fp . config )
385+ S3. list_objects_v2 (fp. bucket, params; aws_config= get_config (fp) )
384386 catch e
385387 @delay_retry if ecode (e) in [" NoSuchBucket" ] end
386388 end
@@ -401,7 +403,7 @@ function Base.readdir(fp::S3Path; join=false, sort=true)
401403end
402404
403405function Base. read (fp:: S3Path ; byte_range= nothing )
404- return Vector {UInt8} (s3_get (fp . config , fp. bucket, fp. key; raw= true , byte_range= byte_range))
406+ return Vector {UInt8} (s3_get (get_config (fp) , fp. bucket, fp. key; raw= true , byte_range= byte_range))
405407end
406408
407409Base. write (fp:: S3Path , content:: String ; kwargs... ) = Base. write (fp, Vector {UInt8} (content); kwargs... )
@@ -410,10 +412,10 @@ function Base.write(fp::S3Path, content::Vector{UInt8}; part_size_mb=50, multipa
410412 # avoid HTTPClientError('An HTTP Client raised an unhandled exception: string longer than 2147483647 bytes')
411413 MAX_HTTP_BYTES = 2147483647
412414 if ! multipart || length (content) < MAX_HTTP_BYTES
413- return s3_put (fp . config , fp. bucket, fp. key, content)
415+ return s3_put (get_config (fp) , fp. bucket, fp. key, content)
414416 else
415417 io = IOBuffer (content)
416- return s3_multipart_upload (fp . config , fp. bucket, fp. key, io, part_size_mb= part_size_mb; other_kwargs... )
418+ return s3_multipart_upload (get_config (fp) , fp. bucket, fp. key, io, part_size_mb= part_size_mb; other_kwargs... )
417419 end
418420end
419421
0 commit comments