Skip to content

Commit 88f3380

Browse files
committed
Use ruff to lint
1 parent 5b67928 commit 88f3380

File tree

6 files changed

+241
-194
lines changed

6 files changed

+241
-194
lines changed

.github/workflows/ci.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on:
55
- master
66
pull_request:
77
jobs:
8-
test_python:
8+
build:
99
runs-on: ubuntu-latest
1010
steps:
1111
- uses: actions/checkout@v4
@@ -14,3 +14,13 @@ jobs:
1414
python-version: "3.13"
1515
- run: pip install -e . wheel build
1616
- run: python -m build
17+
lint:
18+
runs-on: ubuntu-latest
19+
steps:
20+
- uses: actions/checkout@v4
21+
- uses: actions/setup-python@v5
22+
with:
23+
python-version: "3.13"
24+
- run: pip install ruff
25+
- run: ruff format --check .
26+
- run: ruff check .

buckup/bucket_creator.py

Lines changed: 98 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@
22
import time
33

44
import boto3
5-
from botocore.exceptions import (
6-
ClientError, NoCredentialsError, ParamValidationError
7-
)
5+
from botocore.exceptions import ClientError, NoCredentialsError, ParamValidationError
86

97
from .exceptions import (
10-
BucketNameAlreadyInUse, CannotGetCurrentUser, CannotListAccountAliases,
11-
CredentialsNotFound, InvalidBucketName, InvalidUserName, UserNameTaken
8+
BucketNameAlreadyInUse,
9+
CannotGetCurrentUser,
10+
CannotListAccountAliases,
11+
CredentialsNotFound,
12+
InvalidBucketName,
13+
InvalidUserName,
14+
UserNameTaken,
1215
)
1316

14-
15-
POLICY_NAME_FORMAT = '{bucket_name}-owner-policy'
17+
POLICY_NAME_FORMAT = "{bucket_name}-owner-policy"
1618

1719
REQUIRE_HTTPS_CONDITION = {
1820
"Bool": {
@@ -21,48 +23,51 @@
2123
},
2224
"NumericGreaterThanEquals": {
2325
# Require TLS >= 1.2
24-
"s3:TlsVersion": [
25-
"1.2"
26-
]
27-
}
26+
"s3:TlsVersion": ["1.2"]
27+
},
2828
}
2929

3030

3131
class BucketCreator:
3232
def __init__(self, profile_name=None, region_name=None):
33-
self.session = boto3.session.Session(profile_name=profile_name,
34-
region_name=region_name)
35-
self.s3 = self.session.resource('s3')
36-
self.s3_client = self.session.client('s3')
37-
self.iam = self.session.resource('iam')
33+
self.session = boto3.session.Session(
34+
profile_name=profile_name, region_name=region_name
35+
)
36+
self.s3 = self.session.resource("s3")
37+
self.s3_client = self.session.client("s3")
38+
self.iam = self.session.resource("iam")
3839

3940
def commit(self, data):
40-
bucket = self.create_bucket(data['bucket_name'], data['region'])
41-
user = self.create_user(bucket, data['user_name'])
41+
bucket = self.create_bucket(data["bucket_name"], data["region"])
42+
user = self.create_user(bucket, data["user_name"])
4243
self.set_bucket_policy(
4344
bucket,
4445
user,
4546
allow_public_acls=data["allow_public_acls"],
46-
public_get_object_paths=data.get('public_get_object_paths')
47+
public_get_object_paths=data.get("public_get_object_paths"),
4748
)
48-
if data.get('cors_origins'):
49-
self.set_cors(bucket, data['cors_origins'])
50-
if data.get('enable_versioning'):
49+
if data.get("cors_origins"):
50+
self.set_cors(bucket, data["cors_origins"])
51+
if data.get("enable_versioning"):
5152
self.enable_versioning(bucket)
5253

53-
def get_bucket_policy_statement_for_get_object(self, bucket, public_get_object_paths):
54+
def get_bucket_policy_statement_for_get_object(
55+
self, bucket, public_get_object_paths
56+
):
5457
"""
5558
Create policy statement to enable the public to perform s3:getObject
5659
on specified paths.
5760
"""
5861
if public_get_object_paths:
62+
5963
def format_path(path):
60-
if path.startswith('/'):
64+
if path.startswith("/"):
6165
path = path[1:]
6266
return "arn:aws:s3:::{bucket_name}/{path}".format(
6367
bucket_name=bucket.name,
6468
path=path,
6569
)
70+
6671
paths_resources = []
6772
for path in public_get_object_paths:
6873
paths_resources.append(format_path(path))
@@ -73,7 +78,7 @@ def format_path(path):
7378
"Action": ["s3:GetObject"],
7479
"Resource": paths_resources,
7580
# Require HTTPS for public requests
76-
"Condition": REQUIRE_HTTPS_CONDITION
81+
"Condition": REQUIRE_HTTPS_CONDITION,
7782
}
7883

7984
def get_bucket_policy_statements_for_user_access(self, bucket, user):
@@ -82,38 +87,32 @@ def get_bucket_policy_statements_for_user_access(self, bucket, user):
8287
yield {
8388
"Sid": "AllowUserManageBucket",
8489
"Effect": "Allow",
85-
"Principal": {
86-
"AWS": user.arn
87-
},
90+
"Principal": {"AWS": user.arn},
8891
"Action": [
8992
"s3:ListBucket",
9093
"s3:GetBucketLocation",
9194
"s3:ListBucketMultipartUploads",
92-
"s3:ListBucketVersions"
95+
"s3:ListBucketVersions",
9396
],
94-
"Resource": "arn:aws:s3:::{bucket_name}".format(
95-
bucket_name=bucket.name
96-
),
97+
"Resource": "arn:aws:s3:::{bucket_name}".format(bucket_name=bucket.name),
9798
# Require HTTPS for API
98-
"Condition": REQUIRE_HTTPS_CONDITION
99+
"Condition": REQUIRE_HTTPS_CONDITION,
99100
}
100101
# Create policy statement giving the created user full access over the
101102
# objects.
102103
yield {
103104
"Sid": "AllowUserManageBucketObjects",
104105
"Effect": "Allow",
105-
"Principal": {
106-
"AWS": user.arn
107-
},
106+
"Principal": {"AWS": user.arn},
108107
"Action": "s3:*",
109-
"Resource": "arn:aws:s3:::{bucket_name}/*".format(
110-
bucket_name=bucket.name
111-
),
108+
"Resource": "arn:aws:s3:::{bucket_name}/*".format(bucket_name=bucket.name),
112109
# Require HTTPS for API
113-
"Condition": REQUIRE_HTTPS_CONDITION
110+
"Condition": REQUIRE_HTTPS_CONDITION,
114111
}
115112

116-
def set_bucket_policy(self, bucket, user, allow_public_acls, public_get_object_paths=None):
113+
def set_bucket_policy(
114+
self, bucket, user, allow_public_acls, public_get_object_paths=None
115+
):
117116
policy_statement = []
118117
public_access = bool(public_get_object_paths)
119118

@@ -124,38 +123,42 @@ def set_bucket_policy(self, bucket, user, allow_public_acls, public_get_object_p
124123
"BlockPublicAcls": not allow_public_acls,
125124
"IgnorePublicAcls": not allow_public_acls,
126125
"BlockPublicPolicy": not public_access,
127-
"RestrictPublicBuckets": not public_access
128-
}
126+
"RestrictPublicBuckets": not public_access,
127+
},
129128
)
130129
if public_access or allow_public_acls:
131-
print('Configured public access to bucket.')
130+
print("Configured public access to bucket.")
132131

133132
if public_access:
134133
policy_statement.append(
135134
self.get_bucket_policy_statement_for_get_object(
136135
bucket, public_get_object_paths
137136
)
138137
)
139-
policy_statement.extend(list(
140-
self.get_bucket_policy_statements_for_user_access(bucket, user)
141-
))
142-
policy = json.dumps({
143-
"Version": "2012-10-17",
144-
"Statement": policy_statement,
145-
})
138+
policy_statement.extend(
139+
list(self.get_bucket_policy_statements_for_user_access(bucket, user))
140+
)
141+
policy = json.dumps(
142+
{
143+
"Version": "2012-10-17",
144+
"Statement": policy_statement,
145+
}
146+
)
146147
while True:
147148
try:
148149
bucket.Policy().put(Policy=policy)
149150
except ClientError as e:
150-
if e.response['Error']['Code'] == 'MalformedPolicy':
151-
print('Waiting for the user to be available to be '
152-
'attached to the policy (wait 5s).')
151+
if e.response["Error"]["Code"] == "MalformedPolicy":
152+
print(
153+
"Waiting for the user to be available to be "
154+
"attached to the policy (wait 5s)."
155+
)
153156
time.sleep(5)
154157
continue
155158
raise e
156159
else:
157160
break
158-
print('Bucket policy set.')
161+
print("Bucket policy set.")
159162

160163
def create_bucket(self, name, region):
161164
"""
@@ -164,23 +167,25 @@ def create_bucket(self, name, region):
164167
create_bucket_kwargs = {}
165168
create_bucket_config = {}
166169
# us-east-1 does not work with location specified.
167-
if region != 'us-east-1':
168-
create_bucket_config['LocationConstraint'] = region
170+
if region != "us-east-1":
171+
create_bucket_config["LocationConstraint"] = region
169172
if create_bucket_config:
170-
create_bucket_kwargs['CreateBucketConfiguration'] = (
171-
create_bucket_config
172-
)
173+
create_bucket_kwargs["CreateBucketConfiguration"] = create_bucket_config
173174
bucket = self.s3.Bucket(name)
174175
response = bucket.create(**create_bucket_kwargs)
175-
msg = 'Created bucket "{bucket_name}" at "{bucket_location}" in ' \
176-
'region "{region}".'
177-
print(msg.format(
178-
bucket_name=name,
179-
bucket_location=response['Location'],
180-
region=region,
181-
))
176+
msg = (
177+
'Created bucket "{bucket_name}" at "{bucket_location}" in '
178+
'region "{region}".'
179+
)
180+
print(
181+
msg.format(
182+
bucket_name=name,
183+
bucket_location=response["Location"],
184+
region=region,
185+
)
186+
)
182187
print()
183-
print('\tAWS_STORAGE_BUCKET_NAME', name)
188+
print("\tAWS_STORAGE_BUCKET_NAME", name)
184189
print()
185190
bucket.wait_until_exists()
186191
return bucket
@@ -191,22 +196,22 @@ def enable_versioning(self, bucket):
191196

192197
def create_user(self, bucket, user_name):
193198
user = self.iam.User(user_name).create()
194-
self.iam.meta.client.get_waiter('user_exists').wait(UserName=user_name)
199+
self.iam.meta.client.get_waiter("user_exists").wait(UserName=user_name)
195200
user.load()
196-
print('Created IAM user "{user_name}".'.format(
197-
user_name=user.arn
198-
))
201+
print('Created IAM user "{user_name}".'.format(user_name=user.arn))
199202
self.create_user_access_key_pair(user)
200203
return user
201204

202205
def create_user_access_key_pair(self, user):
203206
access_key_pair = user.create_access_key_pair()
204-
print('Created access key pair for user "{user}".'.format(
205-
user=user.arn,
206-
))
207+
print(
208+
'Created access key pair for user "{user}".'.format(
209+
user=user.arn,
210+
)
211+
)
207212
print()
208-
print('\tAWS_ACCESS_KEY_ID', access_key_pair.access_key_id)
209-
print('\tAWS_SECRET_ACCESS_KEY', access_key_pair.secret_access_key)
213+
print("\tAWS_ACCESS_KEY_ID", access_key_pair.access_key_id)
214+
print("\tAWS_SECRET_ACCESS_KEY", access_key_pair.secret_access_key)
210215
print()
211216
return access_key_pair
212217

@@ -216,32 +221,32 @@ def set_cors(self, bucket, origins):
216221
# not empty.
217222
next(iter(origins))
218223
except StopIteration:
219-
raise ValueError("'origins' cannot be empty.")
224+
raise ValueError("'origins' cannot be empty.") from None
220225
config = {
221-
'CORSRules': [
226+
"CORSRules": [
222227
{
223-
'AllowedMethods': ['GET'],
224-
'AllowedOrigins': origins,
225-
'MaxAgeSeconds': 3000,
226-
'AllowedHeaders': ['Authorization'],
228+
"AllowedMethods": ["GET"],
229+
"AllowedOrigins": origins,
230+
"MaxAgeSeconds": 3000,
231+
"AllowedHeaders": ["Authorization"],
227232
}
228233
]
229234
}
230-
msg = "Set CORS for domains {domains} to bucket \"{bucket_name}\"."
231-
print(msg.format(domains=', '.join(origins), bucket_name=bucket.name))
235+
msg = 'Set CORS for domains {domains} to bucket "{bucket_name}".'
236+
print(msg.format(domains=", ".join(origins), bucket_name=bucket.name))
232237
bucket.Cors().put(CORSConfiguration=config)
233238

234239
def validate_bucket_name(self, bucket_name):
235240
try:
236241
self.s3.meta.client.head_bucket(Bucket=bucket_name)
237242
except ClientError as e:
238243
# Bucket does not exist, proceed with creation.
239-
if e.response['Error']['Code'] == '404':
244+
if e.response["Error"]["Code"] == "404":
240245
return
241246
# No access to the bucket means that it already exists but we
242247
# cannot run head request on it.
243-
elif e.response['Error']['Code'] == '403':
244-
raise BucketNameAlreadyInUse
248+
elif e.response["Error"]["Code"] == "403":
249+
raise BucketNameAlreadyInUse() from None
245250
else:
246251
raise e
247252
except ParamValidationError as e:
@@ -253,9 +258,9 @@ def validate_user_name(self, user_name):
253258
try:
254259
self.iam.User(user_name).load()
255260
except ClientError as e:
256-
if e.response['Error']['Code'] == 'ValidationError':
261+
if e.response["Error"]["Code"] == "ValidationError":
257262
raise InvalidUserName(str(e)) from e
258-
if not e.response['Error']['Code'] == 'EntityAlreadyExists':
263+
if not e.response["Error"]["Code"] == "EntityAlreadyExists":
259264
return
260265
raise e
261266
else:
@@ -269,7 +274,7 @@ def get_current_user(self):
269274
except NoCredentialsError as e:
270275
raise CredentialsNotFound from e
271276
except ClientError as e:
272-
if e.response['Error']['Code'] == 'AccessDenied':
277+
if e.response["Error"]["Code"] == "AccessDenied":
273278
raise CannotGetCurrentUser from e
274279
raise e
275280

@@ -279,10 +284,10 @@ def get_current_account_alias(self):
279284
except NoCredentialsError as e:
280285
raise CredentialsNotFound from e
281286
except ClientError as e:
282-
if e.response['Error']['Code'] == 'AccessDenied':
287+
if e.response["Error"]["Code"] == "AccessDenied":
283288
raise CannotListAccountAliases from e
284289
raise e
285290
try:
286-
return response['AccountAliases'][0]
291+
return response["AccountAliases"][0]
287292
except IndexError:
288293
return

0 commit comments

Comments
 (0)