Skip to content

Commit

Permalink
fix: fully qualify all datetime module references (#341)
Browse files Browse the repository at this point in the history
To prevent any namespace collisions with signature resolution, all examples and code using the `datetime` module now use their fully qualified path (i.e. `datetime.datetime.now()`)
  • Loading branch information
cofin authored Jan 14, 2025
1 parent 3d95640 commit e0961d4
Show file tree
Hide file tree
Showing 22 changed files with 152 additions and 144 deletions.
4 changes: 2 additions & 2 deletions advanced_alchemy/_listeners.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from datetime import datetime, timezone
import datetime
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
Expand All @@ -22,4 +22,4 @@ def touch_updated_timestamp(session: Session, *_: Any) -> None:
"""
for instance in session.dirty:
if hasattr(instance, "updated_at"):
instance.updated_at = datetime.now(timezone.utc)
instance.updated_at = datetime.datetime.now(datetime.timezone.utc)
6 changes: 3 additions & 3 deletions advanced_alchemy/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from __future__ import annotations

import contextlib
import datetime
import re
from datetime import date, datetime
from typing import TYPE_CHECKING, Any, Iterator, Optional, Protocol, cast, runtime_checkable
from uuid import UUID

Expand Down Expand Up @@ -286,8 +286,8 @@ def create_registry(
type_annotation_map: dict[Any, type[TypeEngine[Any]] | TypeEngine[Any]] = {
UUID: GUID,
core_uuid.UUID: GUID,
datetime: DateTimeUTC,
date: Date,
datetime.datetime: DateTimeUTC,
datetime.date: Date,
dict: JsonB,
DataclassProtocol: JsonB,
}
Expand Down
16 changes: 8 additions & 8 deletions advanced_alchemy/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
Example:
Basic usage with a datetime filter::
from datetime import datetime
import datetime
from advanced_alchemy.filters import BeforeAfter
filter = BeforeAfter(
field_name="created_at",
before=datetime.now(),
after=datetime(2023, 1, 1),
before=datetime.datetime.now(),
after=datetime.datetime(2023, 1, 1),
)
statement = filter.append_to_statement(select(Model), Model)
Expand All @@ -34,10 +34,10 @@

from __future__ import annotations

import datetime # noqa: TC003
from abc import ABC, abstractmethod
from collections import abc # noqa: TC003
from dataclasses import dataclass
from datetime import datetime # noqa: TC003
from operator import attrgetter
from typing import TYPE_CHECKING, Any, Generic, Literal, cast

Expand Down Expand Up @@ -153,9 +153,9 @@ class BeforeAfter(StatementFilter):

field_name: str
"""Name of the model attribute to filter on."""
before: datetime | None
before: datetime.datetime | None
"""Filter results where field is earlier than this value."""
after: datetime | None
after: datetime.datetime | None
"""Filter results where field is later than this value."""

def append_to_statement(self, statement: StatementTypeT, model: type[ModelT]) -> StatementTypeT:
Expand Down Expand Up @@ -199,9 +199,9 @@ class OnBeforeAfter(StatementFilter):

field_name: str
"""Name of the model attribute to filter on."""
on_or_before: datetime | None
on_or_before: datetime.datetime | None
"""Filter results where field is on or earlier than this value."""
on_or_after: datetime | None
on_or_after: datetime.datetime | None
"""Filter results where field is on or later than this value."""

def append_to_statement(self, statement: StatementTypeT, model: type[ModelT]) -> StatementTypeT:
Expand Down
16 changes: 8 additions & 8 deletions advanced_alchemy/mixins/audit.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from datetime import datetime, timezone
import datetime

from sqlalchemy.orm import Mapped, declarative_mixin, mapped_column, validates

Expand All @@ -11,20 +11,20 @@
class AuditColumns:
"""Created/Updated At Fields Mixin."""

created_at: Mapped[datetime] = mapped_column(
created_at: Mapped[datetime.datetime] = mapped_column(
DateTimeUTC(timezone=True),
default=lambda: datetime.now(timezone.utc),
default=lambda: datetime.datetime.now(datetime.timezone.utc),
)
"""Date/time of instance creation."""
updated_at: Mapped[datetime] = mapped_column(
updated_at: Mapped[datetime.datetime] = mapped_column(
DateTimeUTC(timezone=True),
default=lambda: datetime.now(timezone.utc),
onupdate=lambda: datetime.now(timezone.utc),
default=lambda: datetime.datetime.now(datetime.timezone.utc),
onupdate=lambda: datetime.datetime.now(datetime.timezone.utc),
)
"""Date/time of instance last update."""

@validates("created_at", "updated_at")
def validate_tz_info(self, _: str, value: datetime) -> datetime:
def validate_tz_info(self, _: str, value: datetime.datetime) -> datetime.datetime:
if value.tzinfo is None:
value = value.replace(tzinfo=timezone.utc)
value = value.replace(tzinfo=datetime.timezone.utc)
return value
12 changes: 6 additions & 6 deletions advanced_alchemy/repository/memory/_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@
from advanced_alchemy.utils.text import slugify

if TYPE_CHECKING:
import datetime
from collections import abc
from collections.abc import Iterable
from datetime import datetime

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.ext.asyncio.scoping import async_scoped_session
Expand Down Expand Up @@ -231,14 +231,14 @@ def _filter_on_datetime_field(
self,
result: list[ModelT],
field_name: str,
before: datetime | None = None,
after: datetime | None = None,
on_or_before: datetime | None = None,
on_or_after: datetime | None = None,
before: datetime.datetime | None = None,
after: datetime.datetime | None = None,
on_or_before: datetime.datetime | None = None,
on_or_after: datetime.datetime | None = None,
) -> list[ModelT]:
result_: list[ModelT] = []
for item in result:
attr: datetime = getattr(item, field_name)
attr: datetime.datetime = getattr(item, field_name)
if before is not None and attr < before:
result_.append(item)
if after is not None and attr > after:
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 @@ -42,9 +42,9 @@
from advanced_alchemy.utils.text import slugify

if TYPE_CHECKING:
import datetime
from collections import abc
from collections.abc import Iterable
from datetime import datetime

from sqlalchemy.orm.scoping import scoped_session
from sqlalchemy.orm.strategy_options import _AbstractLoad # pyright: ignore[reportPrivateUsage]
Expand Down Expand Up @@ -232,14 +232,14 @@ def _filter_on_datetime_field(
self,
result: list[ModelT],
field_name: str,
before: datetime | None = None,
after: datetime | None = None,
on_or_before: datetime | None = None,
on_or_after: datetime | None = None,
before: datetime.datetime | None = None,
after: datetime.datetime | None = None,
on_or_before: datetime.datetime | None = None,
on_or_after: datetime.datetime | None = None,
) -> list[ModelT]:
result_: list[ModelT] = []
for item in result:
attr: datetime = getattr(item, field_name)
attr: datetime.datetime = getattr(item, field_name)
if before is not None and attr < before:
result_.append(item)
if after is not None and attr > after:
Expand Down
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# ruff: noqa: FIX002 PLR0911 ARG001 ERA001
from __future__ import annotations

import datetime
import os
import warnings
from datetime import datetime
from functools import partial
from typing import TYPE_CHECKING, Any

Expand All @@ -22,7 +22,7 @@
warnings.filterwarnings("ignore", category=SAWarning)

# -- Project information -----------------------------------------------------
current_year = datetime.now().year # noqa: DTZ005
current_year = datetime.datetime.now().year # noqa: DTZ005
project = __project__
copyright = f"{current_year}, Litestar Organization" # noqa: A001
release = os.getenv("_ADVANCED-ALCHEMY_DOCS_BUILD_VERSION", __version__.rsplit(".")[0])
Expand Down
8 changes: 4 additions & 4 deletions docs/usage/frameworks/fastapi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Define your SQLAlchemy models and Pydantic schemas:

.. code-block:: python
from datetime import date
import datetime
from uuid import UUID
from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
Expand All @@ -71,15 +71,15 @@ Define your SQLAlchemy models and Pydantic schemas:
class Author(BaseModel):
id: UUID | None
name: str
dob: date | None = None
dob: datetime.date | None = None
class AuthorCreate(BaseModel):
name: str
dob: date | None = None
dob: datetime.date | None = None
class AuthorUpdate(BaseModel):
name: str | None = None
dob: date | None = None
dob: datetime.date | None = None
Repository and Service
----------------------
Expand Down
12 changes: 6 additions & 6 deletions docs/usage/frameworks/litestar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Define your SQLAlchemy models using Advanced Alchemy's enhanced base classes:

.. code-block:: python
from datetime import date
import datetime
from uuid import UUID
from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
Expand All @@ -54,7 +54,7 @@ Define your SQLAlchemy models using Advanced Alchemy's enhanced base classes:
class AuthorModel(UUIDBase):
__tablename__ = "author"
name: Mapped[str]
dob: Mapped[date | None]
dob: Mapped[datetime.date | None]
books: Mapped[list[BookModel]] = relationship(back_populates="author", lazy="selectin")
class BookModel(UUIDAuditBase):
Expand All @@ -70,7 +70,7 @@ Define Pydantic schemas for input validation and response serialization:

.. code-block:: python
from datetime import date
import datetime
from pydantic import BaseModel, ConfigDict
from uuid import UUID
from typing import Optional
Expand All @@ -83,17 +83,17 @@ Define Pydantic schemas for input validation and response serialization:
"""Author response schema."""
id: UUID
name: str
dob: Optional[date] = None
dob: Optional[datetime.date] = None
class AuthorCreate(BaseSchema):
"""Schema for creating authors."""
name: str
dob: Optional[date] = None
dob: Optional[datetime.date] = None
class AuthorUpdate(BaseSchema):
"""Schema for updating authors."""
name: Optional[str] = None
dob: Optional[date] = None
dob: Optional[datetime.date] = None
class Book(BaseSchema):
"""Book response schema with author details."""
Expand Down
8 changes: 4 additions & 4 deletions docs/usage/modeling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Let's start with a simple blog post model:
from advanced_alchemy.base import BigIntAuditBase
from sqlalchemy.orm import Mapped, mapped_column
from datetime import datetime
import datetime
from typing import Optional
class Post(BigIntAuditBase):
Expand All @@ -83,7 +83,7 @@ Let's start with a simple blog post model:
title: Mapped[str] = mapped_column(index=True)
content: Mapped[str]
published: Mapped[bool] = mapped_column(default=False)
published_at: Mapped[Optional[datetime]] = mapped_column(default=None)
published_at: Mapped[Optional[datetime.datetime]] = mapped_column(default=None)
Many-to-Many Relationships
--------------------------
Expand Down Expand Up @@ -253,7 +253,7 @@ Here's an example showing a class to generate a server-side UUID primary key for

.. code-block:: python
from datetime import datetime
import datetime
from uuid import UUID, uuid4
from advanced_alchemy.base import CommonTableAttributes, orm_registry
Expand Down Expand Up @@ -294,7 +294,7 @@ Here's an example showing a class to generate a server-side UUID primary key for
email: Mapped[str] = mapped_column(unique=True)
full_name: Mapped[str]
is_active: Mapped[bool] = mapped_column(default=True)
last_login: Mapped[datetime | None] = mapped_column(default=None)
last_login: Mapped[datetime.datetime | None] = mapped_column(default=None)
With this foundation in place, let's look at the repository pattern.
4 changes: 2 additions & 2 deletions docs/usage/repositories.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@ Advanced Alchemy provides powerful filtering capabilities:

.. code-block:: python
from datetime import datetime, timedelta
import datetime
async def get_recent_posts(session: AsyncSession) -> list[Post]:
repository = PostRepository(session=session)
# Create filter for posts from last week
return await repository.list(
Post.published == True,
Post.created_at > (datetime.utcnow() - timedelta(days=7))
Post.created_at > (datetime.datetime.utcnow() - timedelta(days=7))
)
Pagination
Expand Down
12 changes: 6 additions & 6 deletions docs/usage/services.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Let's build upon our blog example by creating services for posts and tags:
from advanced_alchemy.service import SQLAlchemyAsyncRepositoryService
from pydantic import BaseModel
from datetime import datetime
import datetime
from typing import Optional, List
from uuid import UUID
Expand All @@ -47,9 +47,9 @@ Let's build upon our blog example by creating services for posts and tags:
title: str
content: str
published: bool
published_at: Optional[datetime]
created_at: datetime
updated_at: datetime
published_at: Optional[datetime.datetime]
created_at: datetime.datetime
updated_at: datetime.datetime
tags: List["TagResponse"]
model_config = {"from_attributes": True}
Expand Down Expand Up @@ -200,7 +200,7 @@ Services can handle complex business logic involving multiple repositories:
"""Publish or unpublish a post with timestamp."""
data = PostUpdate(
published=publish,
published_at=datetime.utcnow() if publish else None,
published_at=datetime.datetime.utcnow() if publish else None,
)
post = await self.post_service.update(
item_id=post_id,
Expand All @@ -217,7 +217,7 @@ Services can handle complex business logic involving multiple repositories:
"""Get trending posts based on view count and recency."""
posts = await self.post_service.list(
Post.published == True,
Post.created_at > (datetime.utcnow() - timedelta(days=days)),
Post.created_at > (datetime.datetime.utcnow() - timedelta(days=days)),
Post.view_count >= min_views,
order_by=[Post.view_count.desc()],
)
Expand Down
Loading

0 comments on commit e0961d4

Please sign in to comment.