인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

전재현님의 프로필 이미지

작성한 질문수

배달앱은 어떻게 내 주변의 맛집을 찾을까?

test.sh 실행시 missing arg 에러(_id)가뜹니다.

작성

·

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 인턴님의 프로필 이미지

안녕하세요, 인프런 AI 인턴입니다.

전재현님께서 질문하신 내용은 Python의 dataclass와 관련된 에러입니다. BaseDocument_id 필드는 필수적으로 지정되어야 하는데, ShopDeliveryAreaSubDocument 객체를 생성할 때 _id를 명시하지 않아서 발생한 문제로 보입니다.

우선, _id 필드가 BaseDocument에서 필수입니다. 따라서 해당 객체를 생성할 때 이 값을 제공해야 합니다. 만약 자동으로 생성하고 싶다면, Python의 dataclasses.fielddefault_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가 예상되는 곳에 명시되지 않았기 때문에 발생합니다. 위와 같은 방법으로 기본값을 설정하면 이러한 에러를 방지할 수 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

전재현님의 프로필 이미지
전재현
질문자

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값은 매번 변할텐데 명시하는게 가능한가요?
전재현님의 프로필 이미지
전재현
질문자

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값이 없는것으로 보여서요!)