작성
·
36
·
수정됨
0
@dataclasses.dataclass(kw_only=True)
class BaseDocument:
_id: ObjectId
@property
def id(self) -> ObjectId:
return self._id
@dataclasses.dataclass
class ShopDeliveryAreaSubDocument(BaseDocument):
poly: GeoJsonPolygon
@dataclasses.dataclass
class ShopDocument(BaseDocument):
name: str
category_codes: list[CategoryCode]
delivery_areas: list[ShopDeliveryAreaSubDocument]
##test_shot_colleciton.py
async def test_shop_insert_one() -> None:
# Given
name = "치킨집"
category_codes = [CategoryCode.CHICKEN]
# 여기서 _id 값을 명시하지않아 에러가 나는것으로 보임.
delivery_areas = [
ShopDeliveryAreaSubDocument(
poly=GeoJsonPolygon(coordinates=[[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]]),
)
]
에러코드
34 files left unchanged.
OK
Starting isort
Skipped 2 files
OK
Starting mypy
app/entities/collections/shop/shop_collection.py:51: error: Missing named argument "_id" for "ShopDeliveryAreaSubDocument" [call-arg]
app/tests/entities/collections/shop/test_shop_collection.py:15: error: Missing named argument "_id" for "ShopDeliveryAreaSubDocument" [call-arg]
BaseDocument 에는 _id : ObjectId 라는 attr이 항상 명시되도록 되어있는데 test 파일에는 명시가되어있지않아 나오는 에러같은데, 명시하지않아도 정상동작 되나요?? 아니면 Optional 값으로 주어야하는걸까요!?
감사합니다.
답변 1
0
안녕하세요, 인프런 AI 인턴입니다.
전재현님께서 질문하신 내용은 Python의 dataclass와 관련된 에러입니다. BaseDocument
의 _id
필드는 필수적으로 지정되어야 하는데, ShopDeliveryAreaSubDocument
객체를 생성할 때 _id
를 명시하지 않아서 발생한 문제로 보입니다.
우선, _id
필드가 BaseDocument
에서 필수입니다. 따라서 해당 객체를 생성할 때 이 값을 제공해야 합니다. 만약 자동으로 생성하고 싶다면, Python의 dataclasses.field
와 default_factory
기능을 활용하여 옵션으로 처리할 수 있습니다.
예를 들어, ObjectId
가 자동으로 생성되도록 하려면 bson.objectid.ObjectId
의 생성자 호출을 default_factory
로 설정할 수 있습니다.
from bson import ObjectId
import dataclasses
@dataclasses.dataclass(kw_only=True)
class BaseDocument:
_id: ObjectId = dataclasses.field(default_factory=ObjectId)
# 이렇게 기본값을 설정하면 생성 시 `_id`를 명시적으로 지정하지 않아도 자동으로 생성됩니다.
위와 같이 설정하면 ShopDeliveryAreaSubDocument
를 생성할 때 _id
값이 자동 생성되어 명시하지 않아도 됩니다.
이와 관련한 자세한 내용은 다음 링크에서 확인할 수 있습니다: Python Dataclasses.
추가적으로 mypy
의 에러는 _id
가 예상되는 곳에 명시되지 않았기 때문에 발생합니다. 위와 같은 방법으로 기본값을 설정하면 이러한 에러를 방지할 수 있습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
import pytest
import pytest_asyncio
from deepdiff import DeepDiff
from app.entities.category.category_codes import CategoryCode
from app.entities.collections.geo_json import GeoJsonPolygon
from app.entities.collections.shop.shop_collection import ShopCollection
from app.entities.collections.shop.shop_document import ShopDeliveryAreaSubDocument
async def test_shop_insert_one() -> None:
# Given
name = "치킨집"
category_codes = [CategoryCode.CHICKEN]
delivery_areas = [
ShopDeliveryAreaSubDocument(
poly=GeoJsonPolygon(coordinates=[[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]]),
)
]
# When
shop = await ShopCollection.insert_one(name, category_codes, delivery_areas)
# cursor = await ShopCollection._collection.find({})
# results = await cursor.to_list(None)
results = await ShopCollection._collection.find({}).to_list(None)
# Then
assert len(results) == 1
result = results[0]
assert result["_id"] == shop.id
assert result["name"] == shop.name
assert result["category_codes"] == ["chicken"]
# assert result["delivery_areas"] == [
# {"poly": {"type": "Polygon", "coordinates": [[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]]}}
# ]
diff = DeepDiff(
result["delivery_areas"],
[{"poly": {"type": "Polygon", "coordinates": [[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]]}}],
ignore_order=True,
exclude_regex_paths=r"root\[\d+\]\['_id'\]",
)
assert diff == {}
deepdiff 라이브러리를 이용해서 해결하긴했습니다만 BaseDocument 를 상속하고있는 ShopDelieveryAreaSubDocument 는 id 없이 생성이 되는지는 잘 모르겠습니다. ( 강의코드에서는 _id에 대한 default값이 없는것으로 보여서요!)
네 id가 명시되지않아서 생기는 오류입니다만. 강의자료 test_code 에서는 _id에 대한 코드가 없더라구요. 제가 빠트린부분이 있는지 궁금합니다.
async def test_shop_insert_one() -> None: # Given name = "치킨집" category_codes = [CategoryCode.CHICKEN] delivery_areas = [ ShopDeliveryAreaSubDocument( poly=GeoJsonPolygon(coordinates=[[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]]), ) ] # When shop = await ShopCollection.insert_one(name, category_codes, delivery_areas) # cursor = await ShopCollection._collection.find({}) # results = await cursor.to_list(None) results = await ShopCollection._collection.find({}).to_list(None) # Then assert len(results) == 1 result = results[0] assert result["_id"] == shop.id assert result["name"] == shop.name assert result["category_codes"] == ["chicken"] assert result["delivery_areas"] == [ {"poly": {"type": "Polygon", "coordinates": [[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]]}} ] # test_code의 result["delivery_areas"] 부분에 _id를 명시하지 않아도 통과가 되는지 궁금합니다. _id값은 매번 변할텐데 명시하는게 가능한가요?