Search code examples
pythonattr

Python @attr.s causes error when creating object with optional attribute


I have a class with an optional attribute. When I try instantiating the class without specifying the optional attribute, I get an error TypeError: __init__() missing 1 required positional argument: 'time_range'.

import attr
from typeguard import typechecked
from typing import Optional

@attr.s(auto_attribs=True)
class TimeRange:
    start_time: Optional[str] = attr.ib()
    end_time: Optional[str] = attr.ib()

    @typechecked
    def __init__(
        self,
        start_time: Optional[str] = None,
        end_time: Optional[str] = None,
    ):
        self.start_time = start_time
        self.end_time = end_time

@attr.s(auto_attribs=True)
class Date:
    date: int
    time_range: Optional[TimeRange] = attr.ib()

    @typechecked
    def __init__(
        self,
        date: int,
        time_range: Optional[TimeRange] = None,
    ):
        self.date = date
        self.time_range = time_range


# This throws an error
new_date = Date(date=731)
# This also throws an error
new_date = Date(731)

How can I instantiate an object without specifying the optional arg?


Solution

  • attr.s creates an __init__ function that overwrites yours. To fix this, just provide __init__=False:

    import attr
    from typeguard import typechecked
    from typing import Optional
    
    # note the init=False
    @attr.s(auto_attribs=True, init=False)
    class TimeRange:
        start_time: Optional[str] = attr.ib()
        end_time: Optional[str] = attr.ib()
    
        @typechecked
        def __init__(
            self,
            start_time: Optional[str] = None,
            end_time: Optional[str] = None,
        ):
            self.start_time = start_time
            self.end_time = end_time
    
    @attr.s(auto_attribs=True, init=False)
    class Date:
        date: int
        time_range: Optional[TimeRange] = attr.ib()
    
        @typechecked
        def __init__(
            self,
            date: int,
            time_range: Optional[TimeRange] = None,
        ):
            self.date = date
            self.time_range = time_range
    
    
    new_date = Date(date=731)
    new_date = Date(731)