Skip to content

Commit 8a1b3b5

Browse files
committed
lint: added ruff linter rules and formatted files
1 parent 309472a commit 8a1b3b5

File tree

12 files changed

+114
-101
lines changed

12 files changed

+114
-101
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ repos:
1919
rev: v0.5.4
2020
hooks:
2121
- id: ruff
22-
args: [--fix]
22+
args: [--fix, --exclude, alembic/]
2323
- id: ruff-format

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ migrate: ## Apply the database migration
4646
$(ALEMBIC) upgrade head
4747

4848
check: ## Run all checks using tox and pre-commit
49-
$(PIP) install tox==4.16.0 pre-commit==3.7.1
49+
$(PIP) install tox==4.16.0 pre-commit==3.8.0
5050
$(TOX)
5151
$(PRE_COMMIT) install
5252
$(PRE_COMMIT) run --all-files
@@ -65,6 +65,7 @@ clean: ## Clean up the project
6565
@rm -rf *.log
6666
@rm -rf .mypy_cache
6767
@rm -rf .ruff_cache
68+
@rm -rf .pytest_cache
6869
@rm -rf *.egg-info
6970
@rm -rf dist
7071
@find . -name "*.pyc" -delete

alembic/env.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1+
import os
12
from logging.config import fileConfig
23

3-
from sqlalchemy import engine_from_config
4-
from sqlalchemy import pool
4+
from dotenv import load_dotenv
5+
from sqlalchemy import engine_from_config, pool
56

67
from alembic import context
7-
8-
from decouple import config as decouple_config
9-
108
from api.v1.models.base import Base
119

10+
load_dotenv()
11+
1212
# this is the Alembic Config object, which provides
1313
# access to the values within the .ini file in use.
1414
config = context.config
@@ -19,7 +19,7 @@
1919
fileConfig(config.config_file_name)
2020

2121
# Set the SQLAlchemy URL dynamically
22-
database_url = decouple_config("DB_URL")
22+
database_url = os.getenv("DB_URL")
2323
config.set_main_option("sqlalchemy.url", database_url)
2424

2525
# add your model's MetaData object here

api/v1/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Import models here.
2+
23
Example:
34
from api.v1.models.user import User
45
"""

api/v1/routes/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
"""
2-
Router configuration.
1+
"""Router configuration.
32
43
This module sets up the routing for the API version, including the necessary
54
routers for various modules. To add a new router to this configuration, follow
@@ -16,7 +15,7 @@
1615
This configuration is included in the `main.py` application router to
1716
make the API version endpoints available.
1817
19-
Example:
18+
Example:
2019
from fastapi import FastAPI
2120
from api.v1.routes import api_version_one
2221

api/v1/routes/blog.py

Lines changed: 42 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""API routes and handlers for blog-related operations."""
2+
13
import logging
24

35
from fastapi import APIRouter, Depends, HTTPException, Query, status
@@ -28,8 +30,7 @@ async def create_blog(
2830
blog: BlogCreate,
2931
db: Session = Depends(get_db),
3032
) -> BlogResponse:
31-
"""
32-
Create a new blog post.
33+
"""Create a new blog post.
3334
3435
Args:
3536
blog (BlogCreate): The blog post data to create.
@@ -45,23 +46,23 @@ async def create_blog(
4546
try:
4647
return BlogService.create_blog(db, blog)
4748
except ValueError as e:
48-
logger.warning(str(e))
49+
logger.warning("Value error occurred: %s", str(e))
4950
raise HTTPException(
5051
status_code=status.HTTP_409_CONFLICT,
5152
detail=str(e),
52-
)
53+
) from e
5354
except SQLAlchemyError as e:
54-
logger.error(f"Database error occurred: {e}")
55+
logger.exception("Database error occurred", exc_info=e)
5556
raise HTTPException(
5657
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
5758
detail="Database error occurred.",
58-
)
59+
) from e
5960
except Exception as e:
60-
logger.error(f"Internal server error: {e}")
61+
logger.exception("Internal server error", exc_info=e)
6162
raise HTTPException(
6263
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
6364
detail="Internal server error.",
64-
)
65+
) from e
6566

6667

6768
@blog.get(
@@ -71,11 +72,10 @@ async def create_blog(
7172
)
7273
async def list_blog(
7374
page: int = Query(1, ge=1),
74-
page_size: int = Query(10, ge=1, le=100),
75+
page_size: int = Query(10, ge=1, le=25),
7576
db: Session = Depends(get_db),
7677
) -> BlogListResponse:
77-
"""
78-
Retrieve a list of blog posts with pagination.
78+
"""Retrieve a list of blog posts with pagination.
7979
8080
Args:
8181
page (int): The page number for pagination.
@@ -91,17 +91,17 @@ async def list_blog(
9191
try:
9292
return BlogService.list_blog(db, page, page_size)
9393
except SQLAlchemyError as e:
94-
logger.error(f"Database error occurred: {e}")
94+
logger.exception("Database error occurred", exc_info=e)
9595
raise HTTPException(
9696
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
9797
detail="Database error occurred.",
98-
)
98+
) from e
9999
except Exception as e:
100-
logger.error(f"Internal server error: {e}")
100+
logger.exception("Internal server error", exc_info=e)
101101
raise HTTPException(
102102
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
103103
detail="Internal server error.",
104-
)
104+
) from e
105105

106106

107107
@blog.get(
@@ -113,8 +113,7 @@ async def read_blog(
113113
id: int,
114114
db: Session = Depends(get_db),
115115
) -> BlogResponse:
116-
"""
117-
Retrieve a blog post by ID.
116+
"""Retrieve a blog post by ID.
118117
119118
Args:
120119
id (int): The ID of the blog post to retrieve.
@@ -124,28 +123,29 @@ async def read_blog(
124123
BlogResponse: The blog post response.
125124
126125
Raises:
127-
HTTPException: If the blog post is not found or a database error occurs.
126+
HTTPException: If the blog post is not found
127+
or a database error occurs.
128128
"""
129129
try:
130130
return BlogService.read_blog(db, id)
131131
except ValueError as e:
132-
logger.warning(str(e))
132+
logger.warning("Value error occurred: %s", str(e))
133133
raise HTTPException(
134134
status_code=status.HTTP_404_NOT_FOUND,
135135
detail=str(e),
136-
)
136+
) from e
137137
except SQLAlchemyError as e:
138-
logger.error(f"Database error occurred: {e}")
138+
logger.exception("Database error occurred", exc_info=e)
139139
raise HTTPException(
140140
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
141141
detail="Database error occurred.",
142-
)
142+
) from e
143143
except Exception as e:
144-
logger.error(f"Internal server error: {e}")
144+
logger.exception("Internal server error", exc_info=e)
145145
raise HTTPException(
146146
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
147147
detail="Internal server error.",
148-
)
148+
) from e
149149

150150

151151
@blog.patch(
@@ -158,8 +158,7 @@ async def update_blog(
158158
blog_update: BlogUpdate,
159159
db: Session = Depends(get_db),
160160
) -> BlogResponse:
161-
"""
162-
Update an existing blog post by ID.
161+
"""Update an existing blog post by ID.
163162
164163
Args:
165164
id (int): The ID of the blog post to update.
@@ -176,31 +175,31 @@ async def update_blog(
176175
try:
177176
return BlogService.update_blog(db, id, blog_update)
178177
except RequestValidationError as e:
179-
logger.warning(f"Validation error: {e}")
178+
logger.warning("Validation error: %s", str(e))
180179
raise HTTPException(
181180
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
182181
detail=e.errors(),
183-
)
182+
) from e
184183
except ValueError as e:
185-
logger.warning(str(e))
184+
logger.warning("Value error occurred: %s", str(e))
186185
raise HTTPException(
187186
status_code=status.HTTP_404_NOT_FOUND
188187
if "not found" in str(e).lower()
189188
else status.HTTP_409_CONFLICT,
190189
detail=str(e),
191-
)
190+
) from e
192191
except SQLAlchemyError as e:
193-
logger.error(f"Database error occurred: {e}")
192+
logger.exception("Database error occurred", exc_info=e)
194193
raise HTTPException(
195194
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
196195
detail="Database error occurred.",
197-
)
196+
) from e
198197
except Exception as e:
199-
logger.error(f"Internal server error: {e}")
198+
logger.exception("Internal server error", exc_info=e)
200199
raise HTTPException(
201200
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
202201
detail="Internal server error.",
203-
)
202+
) from e
204203

205204

206205
@blog.delete(
@@ -211,33 +210,33 @@ async def delete_blog(
211210
id: int,
212211
db: Session = Depends(get_db),
213212
) -> None:
214-
"""
215-
Delete a blog post by ID (soft delete).
213+
"""Delete a blog post by ID (soft delete).
216214
217215
Args:
218216
id (int): The ID of the blog post to delete.
219217
db (Session): The database session dependency.
220218
221219
Raises:
222-
HTTPException: If the blog post is not found or a database error occurs.
220+
HTTPException: If the blog post is not found
221+
or a database error occurs.
223222
"""
224223
try:
225224
BlogService.delete_blog(db, id)
226225
except ValueError as e:
227-
logger.warning(str(e))
226+
logger.warning("Value error occurred: %s", str(e))
228227
raise HTTPException(
229228
status_code=status.HTTP_404_NOT_FOUND,
230229
detail=str(e),
231-
)
230+
) from e
232231
except SQLAlchemyError as e:
233-
logger.error(f"Database error occurred: {e}")
232+
logger.exception("Database error occurred", exc_info=e)
234233
raise HTTPException(
235234
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
236235
detail="Database error occurred.",
237-
)
236+
) from e
238237
except Exception as e:
239-
logger.error(f"Internal server error: {e}")
238+
logger.exception("Internal server error", exc_info=e)
240239
raise HTTPException(
241240
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
242241
detail="Internal server error.",
243-
)
242+
) from e

api/v1/schemas/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
"""Pydantic schemas for data validation and serialization."""

api/v1/schemas/blog.py

Lines changed: 9 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Blog Schema."""
22

33
from datetime import datetime
4-
from typing import List, Optional
54

65
from pydantic import BaseModel, Field
76

@@ -13,13 +12,13 @@ class BlogBase(BaseModel):
1312
...,
1413
min_length=10,
1514
max_length=255,
16-
description="Title of the blog post. Must be between 10 and 255 characters.",
15+
description="Title of the blog post.",
1716
)
1817
excerpt: str = Field(
1918
...,
2019
min_length=20,
2120
max_length=300,
22-
description="Short excerpt of the blog post. Must be between 20 and 300 characters.",
21+
description="Short excerpt of the blog post.",
2322
)
2423
content: str = Field(
2524
...,
@@ -30,47 +29,19 @@ class BlogBase(BaseModel):
3029
max_length=255,
3130
description="URL of the blog post image.",
3231
)
33-
is_deleted: Optional[bool] = Field(
34-
False,
35-
description="Flag to indicate if the blog post is deleted. Defaults to False.",
32+
is_deleted: bool | None = Field(
33+
default=False,
34+
description="Flag to indicate if the blog post is deleted.",
3635
)
3736

3837

3938
class BlogCreate(BlogBase):
4039
"""Schema for creating a new blog post."""
4140

42-
pass
43-
4441

45-
class BlogUpdate(BaseModel):
42+
class BlogUpdate(BlogBase):
4643
"""Schema for updating an existing blog post."""
4744

48-
title: Optional[str] = Field(
49-
None,
50-
min_length=10,
51-
max_length=255,
52-
description="Title of the blog post. Must be between 10 and 255 characters.",
53-
)
54-
excerpt: Optional[str] = Field(
55-
None,
56-
min_length=20,
57-
max_length=300,
58-
description="Short excerpt of the blog post. Must be between 20 and 300 characters.",
59-
)
60-
content: Optional[str] = Field(
61-
None,
62-
description="Full content of the blog post.",
63-
)
64-
image_url: Optional[str] = Field(
65-
None,
66-
max_length=255,
67-
description="URL of the blog post image.",
68-
)
69-
is_deleted: Optional[bool] = Field(
70-
False,
71-
description="Flag to indicate if the blog post is deleted. Defaults to False.",
72-
)
73-
7445

7546
class BlogResponse(BlogBase):
7647
"""Schema for returning blog post data."""
@@ -121,15 +92,15 @@ class BlogListResponse(BaseModel):
12192
...,
12293
description="Total number of blog posts.",
12394
)
124-
next: Optional[str] = Field(
95+
next: str | None = Field(
12596
None,
12697
description="URL to the next page of results, if available.",
12798
)
128-
previous: Optional[str] = Field(
99+
previous: str | None = Field(
129100
None,
130101
description="URL to the previous page of results, if available.",
131102
)
132-
results: List[BlogListItemResponse] = Field(
103+
results: list[BlogListItemResponse] = Field(
133104
...,
134105
description="List of blog post items.",
135106
)

0 commit comments

Comments
 (0)