Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions src/adaptix/_internal/type_tools/fundamentals.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
import types
from typing import TypeVar, get_args, get_origin, get_type_hints

Expand Down Expand Up @@ -41,5 +42,22 @@ def get_generic_args(tp: TypeHint) -> VarTuple[TypeHint]:
return get_args(tp)


def get_all_type_hints(obj, globalns=None, localns=None):
return get_type_hints(obj, globalns, localns, include_extras=True)
if sys.version_info >= (3, 14):
import annotationlib

def get_all_type_hints(obj, globalns=None, localns=None):
return get_type_hints(
obj,
globalns,
localns,
include_extras=True,
format=annotationlib.Format.FORWARDREF,
)
else:
def get_all_type_hints(obj, globalns=None, localns=None):
return get_type_hints(
obj,
globalns,
localns,
include_extras=True,
)
Empty file.
5 changes: 5 additions & 0 deletions tests/unit/integrations/sqlalchemy/forward_ref/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from sqlalchemy.orm import DeclarativeBase


class Base(DeclarativeBase):
pass
13 changes: 13 additions & 0 deletions tests/unit/integrations/sqlalchemy/forward_ref/product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from sqlalchemy.orm import Mapped, mapped_column, relationship

from .base import Base
from .tag import Tag


class Product(Base):
__tablename__ = "products"

id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]

tags: Mapped[list[Tag]] = relationship(back_populates="product")
19 changes: 19 additions & 0 deletions tests/unit/integrations/sqlalchemy/forward_ref/tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from typing import TYPE_CHECKING

from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship

from .base import Base

if TYPE_CHECKING:
from .product import Product


class Tag(Base):
__tablename__ = "tags"

id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
product_id: Mapped[int] = mapped_column(ForeignKey("products.id"))

product: Mapped["Product"] = relationship(back_populates="tags")
37 changes: 37 additions & 0 deletions tests/unit/integrations/sqlalchemy/test_cyclic_forward_ref.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from dataclasses import asdict, dataclass

from adaptix.conversion import get_converter

from .forward_ref.product import Product
from .forward_ref.tag import Tag


@dataclass
class TagView:
id: int
name: str


@dataclass
class ProductView:
id: int
name: str
tags: list[TagView]


def test_cyclic_forward_ref():
product = Product(
id=1,
name="prod_name",
tags=[Tag(id=1, name="tag1"), Tag(id=2, name="tag2")],
)
converter = get_converter(
Product,
ProductView,
)
result = converter(product)
assert asdict(result) == {
"id": 1,
"name": "prod_name",
"tags": [{"id": 1, "name": "tag1"}, {"id": 2, "name": "tag2"}],
}
Loading