Skip to content

Commit

Permalink
feat: replace ConflictError with IntegrityError (#129)
Browse files Browse the repository at this point in the history
  • Loading branch information
cofin committed Feb 3, 2024
1 parent 3e74b9e commit 0c4e8de
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 21 deletions.
4 changes: 2 additions & 2 deletions advanced_alchemy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
from advanced_alchemy.service._async import SQLAlchemyAsyncRepositoryReadService, SQLAlchemyAsyncRepositoryService
from advanced_alchemy.service._sync import SQLAlchemySyncRepositoryReadService, SQLAlchemySyncRepositoryService

from .exceptions import ConflictError, NotFoundError, RepositoryError
from .exceptions import IntegrityError, NotFoundError, RepositoryError
from .filters import FilterTypes

__all__ = (
"ConflictError",
"IntegrityError",
"FilterTypes",
"NotFoundError",
"RepositoryError",
Expand Down
16 changes: 16 additions & 0 deletions advanced_alchemy/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from typing import Any

from advanced_alchemy.utils.deprecation import deprecated


class AdvancedAlchemyError(Exception):
"""Base exception class from which all Advanced Alchemy exceptions inherit."""
Expand Down Expand Up @@ -65,6 +67,20 @@ class RepositoryError(AdvancedAlchemyError):
class ConflictError(RepositoryError):
"""Data integrity error."""

@deprecated(
version="0.7.1",
alternative="advanced_alchemy.exceptions.IntegrityError",
kind="method",
removal_in="1.0.0",
info="`ConflictError` has been renamed to `IntegrityError`",
)
def __init__(self, *args: Any, detail: str = "") -> None:
super().__init__(*args, detail=detail)


class IntegrityError(RepositoryError):
"""Data integrity error."""


class NotFoundError(RepositoryError):
"""An identity does not exist."""
9 changes: 5 additions & 4 deletions advanced_alchemy/repository/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from contextlib import contextmanager
from typing import TYPE_CHECKING, Any, cast

from sqlalchemy.exc import IntegrityError, SQLAlchemyError
from sqlalchemy.exc import IntegrityError as SQLAlchemyIntegrityError
from sqlalchemy.exc import SQLAlchemyError

from advanced_alchemy.exceptions import ConflictError, RepositoryError
from advanced_alchemy.exceptions import IntegrityError, RepositoryError

if TYPE_CHECKING:
from sqlalchemy.orm import InstrumentedAttribute
Expand All @@ -29,8 +30,8 @@ def wrap_sqlalchemy_exception() -> Any:
"""
try:
yield
except IntegrityError as exc:
raise ConflictError from exc
except SQLAlchemyIntegrityError as exc:
raise IntegrityError from exc
except SQLAlchemyError as exc:
msg = f"An exception occurred: {exc}"
raise RepositoryError(msg) from exc
Expand Down
12 changes: 6 additions & 6 deletions advanced_alchemy/repository/memory/_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession
from sqlalchemy.orm import InstrumentedAttribute

from advanced_alchemy.exceptions import ConflictError, NotFoundError, RepositoryError
from advanced_alchemy.exceptions import IntegrityError, NotFoundError, RepositoryError
from advanced_alchemy.filters import (
BeforeAfter,
CollectionFilter,
Expand Down Expand Up @@ -294,13 +294,13 @@ async def _list_and_count_window(
def _find_or_raise_not_found(self, id_: Any) -> ModelT:
return self.check_not_found(self.__collection__().get_or_none(id_))

def _find_one_or_raise_conflict(self, result: list[ModelT]) -> ModelT:
def _find_one_or_raise_error(self, result: list[ModelT]) -> ModelT:
if not result:
msg = "No item found when one was expected"
raise ConflictError(msg)
raise IntegrityError(msg)
if len(result) > 1:
msg = "Multiple objects when one was expected"
raise ConflictError(msg)
raise IntegrityError(msg)
return result[0]

@classmethod
Expand All @@ -317,7 +317,7 @@ async def get_one_or_none(self, **kwargs: Any) -> ModelT | None:
result = self._filter_result_by_kwargs(self.__collection__().list(), kwargs)
if len(result) > 1:
msg = "Multiple objects when one was expected"
raise ConflictError(msg)
raise IntegrityError(msg)
return result[0] if result else None

@deprecated(version="0.3.5", alternative="SQLAlchemyAsyncRepository.get_or_upsert", kind="method")
Expand Down Expand Up @@ -390,7 +390,7 @@ async def add(self, data: ModelT, **_: Any) -> ModelT:
self.__database__.add(self.model_type, data)
except KeyError as exc:
msg = "Item already exist in collection"
raise ConflictError(msg) from exc
raise IntegrityError(msg) from exc
return data

async def add_many(self, data: list[ModelT], **_: Any) -> list[ModelT]:
Expand Down
12 changes: 6 additions & 6 deletions advanced_alchemy/repository/memory/_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from sqlalchemy.ext.asyncio import AsyncEngine
from sqlalchemy.orm import InstrumentedAttribute, Session

from advanced_alchemy.exceptions import ConflictError, NotFoundError, RepositoryError
from advanced_alchemy.exceptions import IntegrityError, NotFoundError, RepositoryError
from advanced_alchemy.filters import (
BeforeAfter,
CollectionFilter,
Expand Down Expand Up @@ -296,13 +296,13 @@ def _list_and_count_window(
def _find_or_raise_not_found(self, id_: Any) -> ModelT:
return self.check_not_found(self.__collection__().get_or_none(id_))

def _find_one_or_raise_conflict(self, result: list[ModelT]) -> ModelT:
def _find_one_or_raise_error(self, result: list[ModelT]) -> ModelT:
if not result:
msg = "No item found when one was expected"
raise ConflictError(msg)
raise IntegrityError(msg)
if len(result) > 1:
msg = "Multiple objects when one was expected"
raise ConflictError(msg)
raise IntegrityError(msg)
return result[0]

@classmethod
Expand All @@ -319,7 +319,7 @@ def get_one_or_none(self, **kwargs: Any) -> ModelT | None:
result = self._filter_result_by_kwargs(self.__collection__().list(), kwargs)
if len(result) > 1:
msg = "Multiple objects when one was expected"
raise ConflictError(msg)
raise IntegrityError(msg)
return result[0] if result else None

@deprecated(version="0.3.5", alternative="SQLAlchemyAsyncRepository.get_or_upsert", kind="method")
Expand Down Expand Up @@ -392,7 +392,7 @@ def add(self, data: ModelT, **_: Any) -> ModelT:
self.__database__.add(self.model_type, data)
except KeyError as exc:
msg = "Item already exist in collection"
raise ConflictError(msg) from exc
raise IntegrityError(msg) from exc
return data

def add_many(self, data: list[ModelT], **_: Any) -> list[ModelT]:
Expand Down
11 changes: 11 additions & 0 deletions tests/unit/test_exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import contextlib

import pytest


async def test_repo_get_or_create_deprecation() -> None:
with pytest.warns(DeprecationWarning):
from advanced_alchemy.exceptions import ConflictError

with contextlib.suppress(Exception):
raise ConflictError
6 changes: 3 additions & 3 deletions tests/unit/test_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import pytest
from pytest_lazyfixture import lazy_fixture
from sqlalchemy import String
from sqlalchemy.exc import IntegrityError, InvalidRequestError, SQLAlchemyError
from sqlalchemy.exc import InvalidRequestError, SQLAlchemyError
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import InstrumentedAttribute, Mapped, Session, mapped_column

Expand All @@ -20,7 +20,7 @@
base,
wrap_sqlalchemy_exception,
)
from advanced_alchemy.exceptions import ConflictError, RepositoryError
from advanced_alchemy.exceptions import IntegrityError, RepositoryError
from advanced_alchemy.filters import (
BeforeAfter,
CollectionFilter,
Expand Down Expand Up @@ -178,7 +178,7 @@ class TheBigIntModel(base.BigIntBase):

def test_wrap_sqlalchemy_integrity_error() -> None:
"""Test to ensure we wrap IntegrityError."""
with pytest.raises(ConflictError), wrap_sqlalchemy_exception():
with pytest.raises(IntegrityError), wrap_sqlalchemy_exception():
raise IntegrityError(None, None, Exception())


Expand Down

0 comments on commit 0c4e8de

Please sign in to comment.