Skip to content

Commit 7049f1a

Browse files
committed
linting: Rewriting code for better linting compliance
Linting rewrite and validation assisted by Claude Code + Codex. Signed-off-by: Denys Fedoryshchenko <denys.f@collabora.com>
1 parent da39c4e commit 7049f1a

37 files changed

Lines changed: 1589 additions & 1674 deletions

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,4 @@ jobs:
111111

112112
- name: Run ruff lint check (E/W/F/I + complexity policy)
113113
run: |
114-
/opt/venv/bin/ruff check --line-length 110 --select E,W,F,I,C90 --ignore E203,W503 api tests
114+
/opt/venv/bin/ruff check --line-length 110 --select E,W,F,I,C901 --ignore E203 api tests

api/admin.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99

1010
"""Command line utility for creating an admin user"""
1111

12-
import asyncio
1312
import argparse
14-
import sys
13+
import asyncio
1514
import getpass
1615
import os
16+
import sys
1717
import pymongo
1818

1919
from .auth import Authentication
@@ -42,13 +42,15 @@ async def setup_admin_user(db, username, email, password=None):
4242
hashed_password = Authentication.get_password_hash(password)
4343
print(f"Creating {username} user...")
4444
try:
45-
return await db.create(User(
46-
username=username,
47-
hashed_password=hashed_password,
48-
email=email,
49-
is_superuser=1,
50-
is_verified=1,
51-
))
45+
return await db.create(
46+
User(
47+
username=username,
48+
hashed_password=hashed_password,
49+
email=email,
50+
is_superuser=1,
51+
is_verified=1,
52+
)
53+
)
5254
except pymongo.errors.DuplicateKeyError as exc:
5355
err = str(exc)
5456
if "username" in err:
@@ -73,19 +75,19 @@ async def main(args):
7375
return created is not None
7476

7577

76-
if __name__ == '__main__':
78+
if __name__ == "__main__":
7779
parser = argparse.ArgumentParser("Create KernelCI API admin user")
78-
parser.add_argument('--mongo', default='mongodb://db:27017',
79-
help="Mongo server connection string")
80-
parser.add_argument('--username', default='admin',
81-
help="Admin username")
82-
parser.add_argument('--database', default='kernelci',
83-
help="KernelCI database name")
84-
parser.add_argument('--email', required=True,
85-
help="Admin user email address")
8680
parser.add_argument(
87-
'--password',
88-
default='',
81+
"--mongo",
82+
default="mongodb://db:27017",
83+
help="Mongo server connection string",
84+
)
85+
parser.add_argument("--username", default="admin", help="Admin username")
86+
parser.add_argument("--database", default="kernelci", help="KernelCI database name")
87+
parser.add_argument("--email", required=True, help="Admin user email address")
88+
parser.add_argument(
89+
"--password",
90+
default="",
8991
help="Admin password (if empty, falls back to KCI_INITIAL_PASSWORD)",
9092
)
9193
arguments = parser.parse_args()

api/auth.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66

77
"""User authentication utilities"""
88

9-
from passlib.context import CryptContext
109
from fastapi_users.authentication import (
1110
AuthenticationBackend,
1211
BearerTransport,
1312
JWTStrategy,
1413
)
14+
from passlib.context import CryptContext
15+
1516
from .config import AuthSettings
1617

1718

@@ -34,7 +35,7 @@ def get_jwt_strategy(self) -> JWTStrategy:
3435
return JWTStrategy(
3536
secret=self._settings.secret_key,
3637
algorithm=self._settings.algorithm,
37-
lifetime_seconds=self._settings.access_token_expire_seconds
38+
lifetime_seconds=self._settings.access_token_expire_seconds,
3839
)
3940

4041
def get_user_authentication_backend(self):

api/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# pylint: disable=too-few-public-methods
1313
class AuthSettings(BaseSettings):
1414
"""Authentication settings"""
15+
1516
secret_key: str
1617
algorithm: str = "HS256"
1718
# Set to None so tokens don't expire
@@ -23,6 +24,7 @@ class AuthSettings(BaseSettings):
2324
# pylint: disable=too-few-public-methods
2425
class PubSubSettings(BaseSettings):
2526
"""Pub/Sub settings loaded from the environment"""
27+
2628
cloud_events_source: str = "https://api.kernelci.org/"
2729
redis_host: str = "redis"
2830
redis_db_number: int = 1
@@ -36,6 +38,7 @@ class PubSubSettings(BaseSettings):
3638
# pylint: disable=too-few-public-methods
3739
class EmailSettings(BaseSettings):
3840
"""Email settings"""
41+
3942
smtp_host: str
4043
smtp_port: int
4144
email_sender: EmailStr

api/db.py

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@
66

77
"""Database abstraction"""
88

9-
from bson import ObjectId
109
from beanie import init_beanie
10+
from bson import ObjectId
1111
from fastapi_pagination.ext.motor import paginate
12-
from motor import motor_asyncio
13-
from redis import asyncio as aioredis
1412
from kernelci.api.models import (
15-
EventHistory, Hierarchy, Node, TelemetryEvent, parse_node_obj
13+
EventHistory,
14+
Hierarchy,
15+
Node,
16+
TelemetryEvent,
17+
parse_node_obj,
1618
)
19+
from motor import motor_asyncio
20+
from redis import asyncio as aioredis
21+
1722
from .models import User, UserGroup
1823

1924

@@ -26,33 +31,30 @@ class Database:
2631
"""
2732

2833
COLLECTIONS = {
29-
User: 'user',
30-
Node: 'node',
31-
UserGroup: 'usergroup',
32-
EventHistory: 'eventhistory',
33-
TelemetryEvent: 'telemetry',
34+
User: "user",
35+
Node: "node",
36+
UserGroup: "usergroup",
37+
EventHistory: "eventhistory",
38+
TelemetryEvent: "telemetry",
3439
}
3540

3641
OPERATOR_MAP = {
37-
'lt': '$lt',
38-
'lte': '$lte',
39-
'gt': '$gt',
40-
'gte': '$gte',
41-
'ne': '$ne',
42-
're': '$regex',
43-
'in': '$in',
44-
'nin': '$nin',
42+
"lt": "$lt",
43+
"lte": "$lte",
44+
"gt": "$gt",
45+
"gte": "$gte",
46+
"ne": "$ne",
47+
"re": "$regex",
48+
"in": "$in",
49+
"nin": "$nin",
4550
}
4651

47-
BOOL_VALUE_MAP = {
48-
'true': True,
49-
'false': False
50-
}
52+
BOOL_VALUE_MAP = {"true": True, "false": False}
5153

52-
def __init__(self, service='mongodb://db:27017', db_name='kernelci'):
54+
def __init__(self, service="mongodb://db:27017", db_name="kernelci"):
5355
self._motor = motor_asyncio.AsyncIOMotorClient(service)
5456
# TBD: Make redis host configurable
55-
self._redis = aioredis.from_url('redis://redis:6379')
57+
self._redis = aioredis.from_url("redis://redis:6379")
5658
self._db = self._motor[db_name]
5759

5860
async def initialize_beanie(self):
@@ -143,14 +145,13 @@ def _translate_operators(self, attributes):
143145
for op_name, op_value in value.items():
144146
op_key = self.OPERATOR_MAP.get(op_name)
145147
if op_key:
146-
if op_key in ('$in', '$nin'):
148+
if op_key in ("$in", "$nin"):
147149
# Create a list of values from ',' separated string
148150
op_value = op_value.split(",")
149151
if isinstance(op_value, str) and op_value.isdecimal():
150152
op_value = int(op_value)
151153
if translated_attributes.get(key):
152-
translated_attributes[key].update({
153-
op_key: op_value})
154+
translated_attributes[key].update({op_key: op_value})
154155
else:
155156
translated_attributes[key] = {op_key: op_value}
156157
return translated_attributes
@@ -160,7 +161,7 @@ def _convert_int_values(cls, attributes):
160161
for key, val in attributes.items():
161162
if isinstance(val, dict):
162163
for sub_key, sub_val in val.items():
163-
if sub_key == 'int':
164+
if sub_key == "int":
164165
attributes[key] = int(sub_val)
165166
return attributes
166167

@@ -205,14 +206,13 @@ async def find_by_attributes_nonpaginated(self, model, attributes):
205206
query = self._prepare_query(attributes)
206207
# find "limit" and "offset" keys in the query, retrieve them and
207208
# remove them from the query
208-
limit = query.pop('limit', None)
209-
offset = query.pop('offset', None)
209+
limit = query.pop("limit", None)
210+
offset = query.pop("offset", None)
210211
# convert to int if limit and offset are strings
211212
limit = int(limit) if limit is not None else None
212213
offset = int(offset) if offset is not None else None
213214
if limit is not None and offset is not None:
214-
return await (col.find(query)
215-
.skip(offset).limit(limit).to_list(None))
215+
return await col.find(query).skip(offset).limit(limit).to_list(None)
216216
if limit is not None:
217217
return await col.find(query).limit(limit).to_list(None)
218218
if offset is not None:
@@ -239,7 +239,7 @@ async def create(self, obj):
239239
"""
240240
if obj.id is not None:
241241
raise ValueError(f"Object cannot be created with id: {obj.id}")
242-
delattr(obj, 'id')
242+
delattr(obj, "id")
243243
col = self._get_collection(obj.__class__)
244244
res = await col.insert_one(obj.model_dump(by_alias=True))
245245
obj.id = res.inserted_id
@@ -251,22 +251,19 @@ async def insert_many(self, model, documents):
251251
result = await col.insert_many(documents)
252252
return result.inserted_ids
253253

254-
async def _create_recursively(self, hierarchy: Hierarchy, parent: Node,
255-
cls, col):
254+
async def _create_recursively(self, hierarchy: Hierarchy, parent: Node, cls, col):
256255
obj = parse_node_obj(hierarchy.node)
257256
if parent:
258257
obj.parent = parent.id
259258
if obj.id:
260259
obj.update()
261260
if obj.parent == obj.id:
262261
raise ValueError("Parent cannot be the same as the object")
263-
res = await col.replace_one(
264-
{'_id': ObjectId(obj.id)}, obj.dict(by_alias=True)
265-
)
262+
res = await col.replace_one({"_id": ObjectId(obj.id)}, obj.dict(by_alias=True))
266263
if res.matched_count == 0:
267264
raise ValueError(f"No object found with id: {obj.id}")
268265
else:
269-
delattr(obj, 'id')
266+
delattr(obj, "id")
270267
res = await col.insert_one(obj.dict(by_alias=True))
271268
obj.id = res.inserted_id
272269
obj = cls(**await col.find_one(ObjectId(obj.id)))
@@ -296,9 +293,7 @@ async def update(self, obj):
296293
obj.update()
297294
if obj.parent == obj.id:
298295
raise ValueError("Parent cannot be the same as the object")
299-
res = await col.replace_one(
300-
{'_id': ObjectId(obj.id)}, obj.dict(by_alias=True)
301-
)
296+
res = await col.replace_one({"_id": ObjectId(obj.id)}, obj.dict(by_alias=True))
302297
if res.matched_count == 0:
303298
raise ValueError(f"No object found with id: {obj.id}")
304299
return obj.__class__(**await col.find_one(ObjectId(obj.id)))

api/email_sender.py

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,43 @@
77

88
"""SMTP Email Sender module"""
99

10-
from email.mime.multipart import MIMEMultipart
1110
import email
1211
import email.mime.text
1312
import smtplib
13+
from email.mime.multipart import MIMEMultipart
14+
1415
from fastapi import HTTPException, status
16+
1517
from .config import EmailSettings
1618

1719

1820
class EmailSender: # pylint: disable=too-few-public-methods
1921
"""Class to send email report using SMTP"""
22+
2023
def __init__(self):
2124
self._settings = EmailSettings()
2225

2326
def _smtp_connect(self):
2427
"""Method to create a connection with SMTP server"""
2528
if self._settings.smtp_port == 465:
26-
smtp = smtplib.SMTP_SSL(self._settings.smtp_host,
27-
self._settings.smtp_port)
29+
smtp = smtplib.SMTP_SSL(self._settings.smtp_host, self._settings.smtp_port)
2830
else:
29-
smtp = smtplib.SMTP(self._settings.smtp_host,
30-
self._settings.smtp_port)
31+
smtp = smtplib.SMTP(self._settings.smtp_host, self._settings.smtp_port)
3132
smtp.starttls()
32-
smtp.login(self._settings.email_sender,
33-
self._settings.email_password)
33+
smtp.login(self._settings.email_sender, self._settings.email_password)
3434
return smtp
3535

3636
def _create_email(self, email_subject, email_content, email_recipient):
3737
"""Method to create an email message from email subject, contect,
3838
sender, and receiver"""
3939
email_msg = MIMEMultipart()
4040
email_text = email.mime.text.MIMEText(email_content, "plain", "utf-8")
41-
email_text.replace_header('Content-Transfer-Encoding', 'quopri')
42-
email_text.set_payload(email_content, 'utf-8')
41+
email_text.replace_header("Content-Transfer-Encoding", "quopri")
42+
email_text.set_payload(email_content, "utf-8")
4343
email_msg.attach(email_text)
44-
email_msg['To'] = email_recipient
45-
email_msg['From'] = self._settings.email_sender
46-
email_msg['Subject'] = email_subject
44+
email_msg["To"] = email_recipient
45+
email_msg["From"] = self._settings.email_sender
46+
email_msg["Subject"] = email_subject
4747
return email_msg
4848

4949
def _send_email(self, email_msg):
@@ -57,13 +57,10 @@ def _send_email(self, email_msg):
5757
print(f"Error in sending email: {str(exc)}")
5858
raise HTTPException(
5959
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
60-
detail="Failed to send email"
61-
)from exc
60+
detail="Failed to send email",
61+
) from exc
6262

63-
def create_and_send_email(self, email_subject, email_content,
64-
email_recipient):
63+
def create_and_send_email(self, email_subject, email_content, email_recipient):
6564
"""Method to create and send email"""
66-
email_msg = self._create_email(
67-
email_subject, email_content, email_recipient
68-
)
65+
email_msg = self._create_email(email_subject, email_content, email_recipient)
6966
self._send_email(email_msg)

0 commit comments

Comments
 (0)