1step1leap
1step1leap

Reputation: 615

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?

Upvotes: 0

Views: 1483

Answers (2)

Eric M.
Eric M.

Reputation: 2977

Even simpler, you do neither have to write a custom init function nor to block attr to generate one.

You just need to add a default value in the attr.ib call of each optional property (like you did in your custom init function).

import attr
from typing import Optional

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

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

# No more errors
new_date = Date(date=731)
new_date = Date(731)

Upvotes: 1

Aplet123
Aplet123

Reputation: 35560

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)

Upvotes: 0

Related Questions