From 21ab3016df38e9012bb8454f9178114101ae454c Mon Sep 17 00:00:00 2001 From: Cody Fincher Date: Mon, 10 Mar 2025 01:34:23 +0000 Subject: [PATCH 1/3] feat!: 1.0 release --- advanced_alchemy/base.py | 97 +++++---------------------- advanced_alchemy/exceptions.py | 25 ------- advanced_alchemy/utils/deprecation.py | 4 +- tests/unit/test_base.py | 53 +++------------ 4 files changed, 26 insertions(+), 153 deletions(-) diff --git a/advanced_alchemy/base.py b/advanced_alchemy/base.py index a1fa45a8..0807cdd4 100644 --- a/advanced_alchemy/base.py +++ b/advanced_alchemy/base.py @@ -23,74 +23,45 @@ from typing_extensions import Self, TypeVar from advanced_alchemy.mixins import ( - AuditColumns as _AuditColumns, -) -from advanced_alchemy.mixins import ( - BigIntPrimaryKey as _BigIntPrimaryKey, -) -from advanced_alchemy.mixins import ( - NanoIDPrimaryKey as _NanoIDPrimaryKey, -) -from advanced_alchemy.mixins import ( - UUIDPrimaryKey as _UUIDPrimaryKey, -) -from advanced_alchemy.mixins import ( - UUIDv6PrimaryKey as _UUIDv6PrimaryKey, -) -from advanced_alchemy.mixins import ( - UUIDv7PrimaryKey as _UUIDv7PrimaryKey, + AuditColumns, + BigIntPrimaryKey, + NanoIDPrimaryKey, + UUIDPrimaryKey, + UUIDv6PrimaryKey, + UUIDv7PrimaryKey, ) from advanced_alchemy.types import GUID, DateTimeUTC, JsonB from advanced_alchemy.utils.dataclass import DataclassProtocol -from advanced_alchemy.utils.deprecation import warn_deprecation if TYPE_CHECKING: - # these should stay here since they are deprecated. They are imported in the __getattr__ function from sqlalchemy.sql import FromClause from sqlalchemy.sql.schema import ( _NamingSchemaParameter as NamingSchemaParameter, # pyright: ignore[reportPrivateUsage] ) - from advanced_alchemy.mixins import ( - AuditColumns, - BigIntPrimaryKey, - NanoIDPrimaryKey, - SlugKey, - UUIDPrimaryKey, - UUIDv6PrimaryKey, - UUIDv7PrimaryKey, - ) - __all__ = ( "AdvancedDeclarativeBase", - "AuditColumns", "BasicAttributes", "BigIntAuditBase", "BigIntBase", "BigIntBaseT", - "BigIntPrimaryKey", "CommonTableAttributes", "ModelProtocol", "NanoIDAuditBase", "NanoIDBase", "NanoIDBaseT", - "NanoIDPrimaryKey", "SQLQuery", - "SlugKey", "TableArgsType", "UUIDAuditBase", "UUIDBase", "UUIDBaseT", - "UUIDPrimaryKey", "UUIDv6AuditBase", "UUIDv6Base", "UUIDv6BaseT", - "UUIDv6PrimaryKey", "UUIDv7AuditBase", "UUIDv7Base", "UUIDv7BaseT", - "UUIDv7PrimaryKey", "convention", "create_registry", "merge_table_arguments", @@ -100,42 +71,6 @@ ) -def __getattr__(attr_name: str) -> object: - if attr_name == "__path__": - return __file__ - - _deprecated_attrs = { - "SlugKey", - "AuditColumns", - "NanoIDPrimaryKey", - "BigIntPrimaryKey", - "UUIDPrimaryKey", - "UUIDv6PrimaryKey", - "UUIDv7PrimaryKey", - } - if attr_name in _deprecated_attrs: - from advanced_alchemy import mixins - - module = "advanced_alchemy.mixins" - value = globals()[attr_name] = getattr(mixins, attr_name) - - warn_deprecation( - deprecated_name=f"advanced_alchemy.base.{attr_name}", - version="0.26.0", - kind="import", - removal_in="1.0.0", - info=f"importing {attr_name} from 'advanced_alchemy.base' is deprecated, please import it from '{module}' instead", - ) - - return value - if attr_name in set(__all__).difference(_deprecated_attrs): - value = globals()[attr_name] = locals()[attr_name] - return value - - msg = f"module {__name__!r} has no attribute {attr_name!r}" - raise AttributeError(msg) - - UUIDBaseT = TypeVar("UUIDBaseT", bound="UUIDBase") """Type variable for :class:`UUIDBase`.""" BigIntBaseT = TypeVar("BigIntBaseT", bound="BigIntBase") @@ -385,7 +320,7 @@ def __init_subclass__(cls, **kwargs: Any) -> None: super().__init_subclass__(**kwargs) -class UUIDBase(_UUIDPrimaryKey, CommonTableAttributes, AdvancedDeclarativeBase, AsyncAttrs): +class UUIDBase(UUIDPrimaryKey, CommonTableAttributes, AdvancedDeclarativeBase, AsyncAttrs): """Base for all SQLAlchemy declarative models with UUID v4 primary keys. .. seealso:: @@ -398,7 +333,7 @@ class UUIDBase(_UUIDPrimaryKey, CommonTableAttributes, AdvancedDeclarativeBase, __abstract__ = True -class UUIDAuditBase(CommonTableAttributes, _UUIDPrimaryKey, _AuditColumns, AdvancedDeclarativeBase, AsyncAttrs): +class UUIDAuditBase(CommonTableAttributes, UUIDPrimaryKey, AuditColumns, AdvancedDeclarativeBase, AsyncAttrs): """Base for declarative models with UUID v4 primary keys and audit columns. .. seealso:: @@ -412,7 +347,7 @@ class UUIDAuditBase(CommonTableAttributes, _UUIDPrimaryKey, _AuditColumns, Advan __abstract__ = True -class UUIDv6Base(_UUIDv6PrimaryKey, CommonTableAttributes, AdvancedDeclarativeBase, AsyncAttrs): +class UUIDv6Base(UUIDv6PrimaryKey, CommonTableAttributes, AdvancedDeclarativeBase, AsyncAttrs): """Base for all SQLAlchemy declarative models with UUID v6 primary keys. .. seealso:: @@ -425,7 +360,7 @@ class UUIDv6Base(_UUIDv6PrimaryKey, CommonTableAttributes, AdvancedDeclarativeBa __abstract__ = True -class UUIDv6AuditBase(CommonTableAttributes, _UUIDv6PrimaryKey, _AuditColumns, AdvancedDeclarativeBase, AsyncAttrs): +class UUIDv6AuditBase(CommonTableAttributes, UUIDv6PrimaryKey, AuditColumns, AdvancedDeclarativeBase, AsyncAttrs): """Base for declarative models with UUID v6 primary keys and audit columns. .. seealso:: @@ -439,7 +374,7 @@ class UUIDv6AuditBase(CommonTableAttributes, _UUIDv6PrimaryKey, _AuditColumns, A __abstract__ = True -class UUIDv7Base(_UUIDv7PrimaryKey, CommonTableAttributes, AdvancedDeclarativeBase, AsyncAttrs): +class UUIDv7Base(UUIDv7PrimaryKey, CommonTableAttributes, AdvancedDeclarativeBase, AsyncAttrs): """Base for all SQLAlchemy declarative models with UUID v7 primary keys. .. seealso:: @@ -452,7 +387,7 @@ class UUIDv7Base(_UUIDv7PrimaryKey, CommonTableAttributes, AdvancedDeclarativeBa __abstract__ = True -class UUIDv7AuditBase(CommonTableAttributes, _UUIDv7PrimaryKey, _AuditColumns, AdvancedDeclarativeBase, AsyncAttrs): +class UUIDv7AuditBase(CommonTableAttributes, UUIDv7PrimaryKey, AuditColumns, AdvancedDeclarativeBase, AsyncAttrs): """Base for declarative models with UUID v7 primary keys and audit columns. .. seealso:: @@ -466,7 +401,7 @@ class UUIDv7AuditBase(CommonTableAttributes, _UUIDv7PrimaryKey, _AuditColumns, A __abstract__ = True -class NanoIDBase(_NanoIDPrimaryKey, CommonTableAttributes, AdvancedDeclarativeBase, AsyncAttrs): +class NanoIDBase(NanoIDPrimaryKey, CommonTableAttributes, AdvancedDeclarativeBase, AsyncAttrs): """Base for all SQLAlchemy declarative models with Nano ID primary keys. .. seealso:: @@ -479,7 +414,7 @@ class NanoIDBase(_NanoIDPrimaryKey, CommonTableAttributes, AdvancedDeclarativeBa __abstract__ = True -class NanoIDAuditBase(CommonTableAttributes, _NanoIDPrimaryKey, _AuditColumns, AdvancedDeclarativeBase, AsyncAttrs): +class NanoIDAuditBase(CommonTableAttributes, NanoIDPrimaryKey, AuditColumns, AdvancedDeclarativeBase, AsyncAttrs): """Base for declarative models with Nano ID primary keys and audit columns. .. seealso:: @@ -493,7 +428,7 @@ class NanoIDAuditBase(CommonTableAttributes, _NanoIDPrimaryKey, _AuditColumns, A __abstract__ = True -class BigIntBase(_BigIntPrimaryKey, CommonTableAttributes, AdvancedDeclarativeBase, AsyncAttrs): +class BigIntBase(BigIntPrimaryKey, CommonTableAttributes, AdvancedDeclarativeBase, AsyncAttrs): """Base for all SQLAlchemy declarative models with BigInt primary keys. .. seealso:: @@ -506,7 +441,7 @@ class BigIntBase(_BigIntPrimaryKey, CommonTableAttributes, AdvancedDeclarativeBa __abstract__ = True -class BigIntAuditBase(CommonTableAttributes, _BigIntPrimaryKey, _AuditColumns, AdvancedDeclarativeBase, AsyncAttrs): +class BigIntAuditBase(CommonTableAttributes, BigIntPrimaryKey, AuditColumns, AdvancedDeclarativeBase, AsyncAttrs): """Base for declarative models with BigInt primary keys and audit columns. .. seealso:: diff --git a/advanced_alchemy/exceptions.py b/advanced_alchemy/exceptions.py index 6d78fc2e..1d803dbc 100644 --- a/advanced_alchemy/exceptions.py +++ b/advanced_alchemy/exceptions.py @@ -7,11 +7,8 @@ from sqlalchemy.exc import InvalidRequestError as SQLAlchemyInvalidRequestError from sqlalchemy.exc import MultipleResultsFound, SQLAlchemyError, StatementError -from advanced_alchemy.utils.deprecation import deprecated - __all__ = ( "AdvancedAlchemyError", - "ConflictError", "DuplicateKeyError", "ErrorMessages", "ForeignKeyError", @@ -173,28 +170,6 @@ class RepositoryError(AdvancedAlchemyError): """ -class ConflictError(RepositoryError): - """Data integrity error. - - Args: - *args: Variable length argument list passed to parent class. - detail: Detailed error message. - - Note: - This class is deprecated in favor of :class:`advanced_alchemy.exceptions.IntegrityError`. - """ - - @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. diff --git a/advanced_alchemy/utils/deprecation.py b/advanced_alchemy/utils/deprecation.py index 86a83014..4c0305ad 100644 --- a/advanced_alchemy/utils/deprecation.py +++ b/advanced_alchemy/utils/deprecation.py @@ -78,8 +78,8 @@ def deprecated( """Create a decorator wrapping a function, method or property with a warning call about a (pending) deprecation. Args: - version: Litestar version where the deprecation will occur - removal_in: Litestar version where the deprecated function will be removed + version: Advanced Alchemy version where the deprecation will occur + removal_in: Advanced Alchemy version where the deprecated function will be removed alternative: Name of a function that should be used instead info: Additional information pending: Use :class:`warnings.PendingDeprecationWarning` instead of :class:`warnings.DeprecationWarning` diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py index c78336ad..d2e75cef 100644 --- a/tests/unit/test_base.py +++ b/tests/unit/test_base.py @@ -4,54 +4,11 @@ import warnings -import pytest - from tests.helpers import purge_module -def test_deprecated_uuid_primary_keys() -> None: - """Test that using UUIDv7PrimaryKey from base raises a deprecation warning.""" - purge_module(["advanced_alchemy.base"], __file__) - with pytest.warns(DeprecationWarning, match="please import it from 'advanced_alchemy.mixins' instead"): - from advanced_alchemy.base import UUIDv7PrimaryKey - - with pytest.warns(DeprecationWarning, match="please import it from 'advanced_alchemy.mixins' instead"): - from advanced_alchemy.base import UUIDv6PrimaryKey - - with pytest.warns(DeprecationWarning, match="please import it from 'advanced_alchemy.mixins' instead"): - from advanced_alchemy.base import UUIDPrimaryKey - - -def test_deprecated_slug_mixin() -> None: - """Test that using SlugMixin from base raises a deprecation warning.""" - purge_module(["advanced_alchemy.base", "advanced_alchemy.mixins.slug", "advanced_alchemy.mixins"], __file__) - with pytest.warns(DeprecationWarning, match="please import it from 'advanced_alchemy.mixins' instead"): - from advanced_alchemy.base import SlugKey - - -def test_deprecated_bigint_primary_key() -> None: - """Test that using BigIntPrimaryKey from base raises a deprecation warning.""" - purge_module(["advanced_alchemy.base", "advanced_alchemy.mixins.bigint", "advanced_alchemy.mixins"], __file__) - with pytest.warns(DeprecationWarning, match="please import it from 'advanced_alchemy.mixins' instead"): - from advanced_alchemy.base import BigIntPrimaryKey - - -def test_deprecated_nanoid_primary_key() -> None: - """Test that using NanoIDPrimaryKey from base raises a deprecation warning.""" - purge_module(["advanced_alchemy.base", "advanced_alchemy.mixins.nanoid", "advanced_alchemy.mixins"], __file__) - with pytest.warns(DeprecationWarning, match="please import it from 'advanced_alchemy.mixins' instead"): - from advanced_alchemy.base import NanoIDPrimaryKey - - -def test_deprecated_audit_columns() -> None: - """Test that using AuditColumns from base raises a deprecation warning.""" - purge_module(["advanced_alchemy.base", "advanced_alchemy.mixins.audit", "advanced_alchemy.mixins"], __file__) - with pytest.warns(DeprecationWarning, match="please import it from 'advanced_alchemy.mixins' instead"): - from advanced_alchemy.base import AuditColumns - - def test_deprecated_classes_functionality() -> None: - """Test that deprecated classes maintain functionality while warning.""" + """Test that mixins classes maintain have base functionality.""" purge_module(["advanced_alchemy.base", "advanced_alchemy.mixins"], __file__) warnings.filterwarnings("ignore", category=DeprecationWarning) @@ -60,7 +17,13 @@ def test_deprecated_classes_functionality() -> None: warnings.filterwarnings("ignore", category=sa_exc.SAWarning) # Test instantiation and basic attributes - from advanced_alchemy.base import AuditColumns, NanoIDPrimaryKey, UUIDPrimaryKey, UUIDv6PrimaryKey, UUIDv7PrimaryKey + from advanced_alchemy.mixins import ( + AuditColumns, + NanoIDPrimaryKey, + UUIDPrimaryKey, + UUIDv6PrimaryKey, + UUIDv7PrimaryKey, + ) uuidv7_pk = UUIDv7PrimaryKey() uuidv6_pk = UUIDv6PrimaryKey() From 93f4ed960897fb43228e5ff89e4582a70bd87f62 Mon Sep 17 00:00:00 2001 From: Cody Fincher Date: Mon, 10 Mar 2025 03:05:10 +0000 Subject: [PATCH 2/3] fix: remove deprecated test --- tests/unit/test_exceptions.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py index 0a2e0619..e440238d 100644 --- a/tests/unit/test_exceptions.py +++ b/tests/unit/test_exceptions.py @@ -1,4 +1,3 @@ -import contextlib import pytest from sqlalchemy.exc import ( @@ -24,14 +23,6 @@ ) -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 - - def test_wrap_sqlalchemy_exception_multiple_results_found() -> None: with pytest.raises(MultipleResultsFoundError), wrap_sqlalchemy_exception(): raise MultipleResultsFound() From 7ee8bc89119730b888b427a03b8b6babb8f69617 Mon Sep 17 00:00:00 2001 From: Cody Fincher Date: Mon, 10 Mar 2025 03:05:42 +0000 Subject: [PATCH 3/3] fix: linting --- tests/unit/test_exceptions.py | 1 - uv.lock | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py index e440238d..7850afcb 100644 --- a/tests/unit/test_exceptions.py +++ b/tests/unit/test_exceptions.py @@ -1,4 +1,3 @@ - import pytest from sqlalchemy.exc import ( IntegrityError as SQLAlchemyIntegrityError, diff --git a/uv.lock b/uv.lock index b3611b11..16127057 100644 --- a/uv.lock +++ b/uv.lock @@ -3267,16 +3267,16 @@ wheels = [ [[package]] name = "rich-click" -version = "1.8.7" +version = "1.8.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/20/be68db605c37ad2f96fa4e43590cf3f35e53c1740906a992103c62c657be/rich_click-1.8.7.tar.gz", hash = "sha256:075aa0140a3f796768e1e650174d4e12828de87f3a0aed49fe48fb897fcaa627", size = 38344 } +sdist = { url = "https://files.pythonhosted.org/packages/a6/7a/4b78c5997f2a799a8c5c07f3b2145bbcda40115c4d35c76fbadd418a3c89/rich_click-1.8.8.tar.gz", hash = "sha256:547c618dea916620af05d4a6456da797fbde904c97901f44d2f32f89d85d6c84", size = 39066 } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/fb/dc3a3c7c7355a20c4c5cb97b20728f8bfd9bf2933bd90bd589b7528d72e3/rich_click-1.8.7-py3-none-any.whl", hash = "sha256:b089453e8e6079815b2689c903bd782c0408a062ad763e708023becd85b8f5d9", size = 35156 }, + { url = "https://files.pythonhosted.org/packages/fa/69/963f0bf44a654f6465bdb66fb5a91051b0d7af9f742b5bd7202607165036/rich_click-1.8.8-py3-none-any.whl", hash = "sha256:205aabd5a98e64ab2c105dee9e368be27480ba004c7dfa2accd0ed44f9f1550e", size = 35747 }, ] [[package]]