Advertisement
sansun_nam

Adaptix

May 3rd, 2025
216
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.75 KB | Software | 0 0
  1. from dataclasses import asdict, dataclass
  2. from adaptix import Retort, name_mapping
  3. import pytest
  4. from sqlalchemy import Column, Integer, String, ForeignKey, create_engine, inspect, select
  5. from sqlalchemy.orm import (
  6.     declarative_base,
  7.     Session,
  8.     column_property,
  9.     declared_attr,
  10.     Mapped,
  11. )
  12.  
  13. Base = declarative_base()
  14.  
  15.  
  16. class ProductPackagingTypeORM(Base):
  17.     __tablename__ = "product_packaging_types"
  18.  
  19.     id: Mapped[int] = Column(Integer, primary_key=True)
  20.     name: Mapped[str] = Column(String)
  21.  
  22.  
  23. class ProductORM(Base):
  24.     __tablename__ = "products"
  25.     __allow_unmapped__ = True  # позволяет использовать column_property с аннотацией
  26.  
  27.     id: Mapped[int] = Column(Integer, primary_key=True)
  28.     packaging_type_id: Mapped[int] = Column(
  29.         Integer, ForeignKey("product_packaging_types.id")
  30.     )
  31.  
  32.     product_packaging_type: Mapped[str]
  33.  
  34.     @declared_attr
  35.     def product_packaging_type(cls):
  36.         return column_property(
  37.             select(ProductPackagingTypeORM.name)
  38.             .where(ProductPackagingTypeORM.id == cls.packaging_type_id)
  39.             .scalar_subquery()
  40.             .label("product_packaging_type")
  41.         )
  42.  
  43.  
  44. @dataclass
  45. class Product:
  46.     id: int
  47.     packaging_type_id: int
  48.     product_packaging_type: str | None = None
  49.  
  50.  
  51. @pytest.fixture
  52. def sqlite_session():
  53.     engine = create_engine("sqlite:///:memory:")
  54.     Base.metadata.create_all(engine)
  55.     with Session(engine) as session:
  56.         session.add_all(
  57.             [
  58.                 ProductPackagingTypeORM(id=1, name="Картон"),
  59.                 ProductORM(id=1, packaging_type_id=1),
  60.             ]
  61.         )
  62.         session.commit()
  63.         yield session
  64.  
  65.  
  66. def test_product_alias_field_without_retort(sqlite_session):
  67.     orm_product = sqlite_session.query(ProductORM).first()
  68.     assert orm_product.product_packaging_type == "Картон"
  69.  
  70.     # 🔄 Ручной маппинг ORM → Domain
  71.     product = Product(
  72.         id=orm_product.id,
  73.         packaging_type_id=orm_product.packaging_type_id,
  74.         product_packaging_type=orm_product.product_packaging_type,
  75.     )
  76.     print(product)
  77.  
  78.     # ✅ Проверка значения
  79.     assert product == Product(
  80.         id=1, packaging_type_id=1, product_packaging_type="Картон"
  81.     )
  82.  
  83.     # 🔄 Domain → Dict (как dump)
  84.     result_dict = asdict(product)
  85.  
  86.     # ✅ Проверка словаря вручную
  87.     assert result_dict == {
  88.         "id": 1,
  89.         "packaging_type_id": 1,
  90.         "product_packaging_type": "Картон",
  91.     }
  92.  
  93.  
  94. def test_product_alias_field_with_retort(sqlite_session):
  95.     orm_product = sqlite_session.query(ProductORM).first()
  96.     assert orm_product.product_packaging_type == "Картон"
  97.     # аттрибуты orm_product:
  98.     for attr in inspect(orm_product).attrs:
  99.         print(f"orm_product_attributes: {attr.key} = {attr.value}")
  100.    
  101.     retort = Retort(hide_traceback=False)
  102.     # Проблема: Retort по умолчанию сериализует только реальные столбцы SQLAlchemy,
  103.     # а `product_packaging_type` — это column_property (alias), и не попадает в dump.
  104.     product = retort.dump(orm_product)
  105.     print(f"product_from_orm: {product}")
  106.  
  107.     # При десериализации поле product_packaging_type не восстанавливается → None
  108.     product_dataclass = retort.load(product, Product)
  109.     print(f"product_dataclass: {product_dataclass}")
  110.  
  111.     # ❌ Тест упадёт, потому что product_packaging_type == None вместо "Картон"
  112.     assert product_dataclass == Product(
  113.         id=1, packaging_type_id=1, product_packaging_type="Картон"
  114.     )
  115.  
Tags: adaptix
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement