4 Commits

7 changed files with 18 additions and 7 deletions

View File

@@ -1,6 +1,6 @@
[project]
name = "fastapi-toolsets"
version = "0.7.0"
version = "0.7.1"
description = "Reusable tools for FastAPI: async CRUD, fixtures, CLI, and standardized responses for SQLAlchemy + PostgreSQL"
readme = "README.md"
license = "MIT"

View File

@@ -21,4 +21,4 @@ Example usage:
return Response(data={"user": user.username}, message="Success")
"""
__version__ = "0.7.0"
__version__ = "0.7.1"

View File

@@ -1,5 +1,7 @@
"""Generic async CRUD operations for SQLAlchemy models."""
from __future__ import annotations
from collections.abc import Sequence
from typing import Any, ClassVar, Generic, Literal, Self, TypeVar, cast, overload

View File

@@ -29,9 +29,14 @@ def get_obj_by_attr(
The first model instance where the attribute matches the given value.
Raises:
StopIteration: If no matching object is found.
StopIteration: If no matching object is found in the fixture group.
"""
return next(obj for obj in fixtures() if getattr(obj, attr_name) == value)
try:
return next(obj for obj in fixtures() if getattr(obj, attr_name) == value)
except StopIteration:
raise StopIteration(
f"No object with {attr_name}={value} found in fixture '{getattr(fixtures, '__name__', repr(fixtures))}'"
) from None
async def load_fixtures(

View File

@@ -10,6 +10,7 @@ __all__ = [
"ErrorResponse",
"Pagination",
"PaginatedResponse",
"PydanticBase",
"Response",
"ResponseStatus",
]

View File

@@ -744,8 +744,11 @@ class TestGetObjByAttr:
assert user.username == "alice"
def test_no_match_raises_stop_iteration(self):
"""Raises StopIteration when no object matches."""
with pytest.raises(StopIteration):
"""Raises StopIteration with contextual message when no object matches."""
with pytest.raises(
StopIteration,
match="No object with name=nonexistent found in fixture 'roles'",
):
get_obj_by_attr(self.roles, "name", "nonexistent")
def test_no_match_on_wrong_value_type(self):

2
uv.lock generated
View File

@@ -220,7 +220,7 @@ wheels = [
[[package]]
name = "fastapi-toolsets"
version = "0.7.0"
version = "0.7.1"
source = { editable = "." }
dependencies = [
{ name = "asyncpg" },