@@ -195,19 +195,20 @@ def getS3Client(profile: str | None = None) -> boto3.client:
195
195
196
196
Notes
197
197
-----
198
- If an explicit profile name is specified, its configuration is read from an
199
- environment variable named ``LSST_RESOURCES_S3_PROFILE_<profile>``. Note
200
- that the name of the profile is case sensitive. This configuration is
201
- specified in the format:
202
- ``https://<access key ID>:<secret key>@<s3 endpoint hostname>``
198
+ If an explicit profile name is specified, its configuration will be read
199
+ from an environment variable named ``LSST_RESOURCES_S3_PROFILE_<profile>``
200
+ if it exists. Note that the name of the profile is case sensitive. This
201
+ configuration is specified in the format: ``https://<access key ID>:<secret
202
+ key>@<s3 endpoint hostname>``. If the access key ID or secret key values
203
+ contain slashes, the slashes must be URI-encoded (replace "/" with "%2F").
203
204
204
- If the access key ID or secret key values contain slashes, the slashes must
205
- be URI-encoded (replace "/" with "%2F".) The access key ID and secret key
206
- are optional -- if not specified, they will be looked up via the AWS
207
- credentials file.
205
+ If profile is `None` or the profile environment variable was not set, the
206
+ configuration is read from the environment variable ``S3_ENDPOINT_URL``.
207
+ If it is not specified, the default AWS endpoint is used.
208
208
209
- If profile is `None`, this configuration is from the environment variable
210
- S3_ENDPOINT_URL. If none is specified, the default AWS one is used.
209
+ The access key ID and secret key are optional -- if not specified, they
210
+ will be looked up via the `AWS credentials file
211
+ <https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html>`_.
211
212
212
213
If the environment variable LSST_DISABLE_BUCKET_VALIDATION exists
213
214
and has a value that is not empty, "0", "f", "n", or "false"
@@ -220,33 +221,37 @@ def getS3Client(profile: str | None = None) -> boto3.client:
220
221
if botocore is None :
221
222
raise ModuleNotFoundError ("Could not find botocore. Are you sure it is installed?" )
222
223
223
- if profile is None :
224
- endpoint = os .environ .get ("S3_ENDPOINT_URL" , None )
225
- if not endpoint :
226
- endpoint = None # Handle ""
227
- else :
224
+ endpoint = None
225
+ if profile is not None :
228
226
var_name = f"LSST_RESOURCES_S3_PROFILE_{ profile } "
229
227
endpoint = os .environ .get (var_name , None )
230
- if not endpoint :
231
- raise RuntimeError (
232
- f"No configuration found for requested S3 profile '{ profile } '."
233
- f" Set the environment variable '{ var_name } ' to configure it."
234
- )
228
+ if not endpoint :
229
+ endpoint = os .environ .get ("S3_ENDPOINT_URL" , None )
230
+ if not endpoint :
231
+ endpoint = None # Handle ""
235
232
236
233
disable_value = os .environ .get ("LSST_DISABLE_BUCKET_VALIDATION" , "0" )
237
234
skip_validation = not re .search (r"^(0|f|n|false)?$" , disable_value , re .I )
238
235
239
- return _get_s3_client (endpoint , skip_validation )
236
+ return _get_s3_client (endpoint , profile , skip_validation )
240
237
241
238
242
239
@functools .lru_cache
243
- def _get_s3_client (endpoint : str | None , skip_validation : bool ) -> boto3 .client :
240
+ def _get_s3_client (endpoint : str | None , profile : str | None , skip_validation : bool ) -> boto3 .client :
244
241
# Helper function to cache the client for this endpoint
245
242
config = botocore .config .Config (read_timeout = 180 , retries = {"mode" : "adaptive" , "max_attempts" : 10 })
246
243
247
244
endpoint_config = _parse_endpoint_config (endpoint )
248
245
249
- client = boto3 .client (
246
+ if endpoint_config .access_key_id is not None and endpoint_config .secret_access_key is not None :
247
+ # We already have the necessary configuration for the profile, so do
248
+ # not pass the profile to boto3. boto3 will raise an exception if the
249
+ # profile is not defined in its configuration file, whether or not it
250
+ # needs to read the configuration from it.
251
+ profile = None
252
+ session = boto3 .Session (profile_name = profile )
253
+
254
+ client = session .client (
250
255
"s3" ,
251
256
endpoint_url = endpoint_config .endpoint_url ,
252
257
aws_access_key_id = endpoint_config .access_key_id ,
0 commit comments