Search code examples
pythontypingpydantic

Optional field requires a necessary value


I have a function with optional field url

def create_ads_task(
    template_id: int,
    ad_account_id: str,
    adset_ids: List[str],
    placements: Dict[str, str],
    locales: List[Locale],
    url: Optional[HttpUrl],
) -> List[Dict[str, Union[str, int]]]:
    ...body...

When I run the tests, I get an error

E       TypeError: create_ads_task() missing 1 required positional argument: 'url'

test.py

assert create_ads_task(
    TEMPLATE_ID, AD_ACCOUNT_ID, ADSET_IDS, PLACEMENTS, LOCALES
) == [ ..... ]

How to fix test I now, but I cant understand why optional field is required. The function does not always need the url parameter, sometimes it is not passed from the frontend. How do I define the optional parameter correctly?


Solution

  • Optional[..] says that the parameter passed SHOULD BE of the mentioned type OR None, like in your case url should be of type HttpUrl OR None, but it does not mean that if it's not passed it will carry a default value. See the below example:

    from typing import Optional
    
    # In this b will should be passed as str or None
    def test_with_optional(a: str, b: Optional[str]):
        print (a,b)
        
    # In this if b is not passed, it will carry a default value of None
    def test_with_none(a: str, b: str=None):
        print (a,b)
        
    test_with_optional('1', None)
    test_with_none('2')
    

    test_with_optional('1') will throw error TypeError: test_with_optional() missing 1 required positional argument: 'b' because what it expects b either as a string or as None.

    For your case your definition will be as below. Read more about optional parameters here

    def create_ads_task(
            template_id: int,
            ad_account_id: str,
            adset_ids: List[str],
            placements: Dict[str, str],
            locales: List[Locale],
            url: Optional[HttpUrl]=None,
        ) -> List[Dict[str, Union[str, int]]]:
            ...body...