2

As per the attrs documentation, optional attributes should be declared as follow:

>>> @attr.s
... class C(object):
...     x = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(int)))
>>> C(42)
C(x=42)
>>> C("42")
Traceback (most recent call last):
   ...
TypeError: ("'x' must be <type 'int'> (got '42' that is a <type 'str'>).", Attribute(name='x', default=NOTHING, validator=<instance_of validator for type <type 'int'>>, type=None, kw_only=False), <type 'int'>, '42')
>>> C(None)
C(x=None)

However, when I try to use optional attributes, I get the following results:


python
Python 2.7.15 (default, Jul 23 2018, 21:27:06)
[GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.2)] on darwin

class with mandatory attribute

class definition

>>> import attr
>>> @attr.s
... class Result(object):
...   log = attr.ib(validator=attr.validators.instance_of(str))
...

Instantiation of the class

with missing attribute
>>> test = Result()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes exactly 2 arguments (1 given)

OK

with invalid type
>>> test = Result(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<attrs generated init 086c7a4a2a56d2e9002255c4e881a832c6bc5360>", line 4, in __init__
  File "/.../.venv/lib/python2.7/site-packages/attr/validators.py", line 32, in __call__
    value,
TypeError: ("'log' must be <type 'str'> (got 1 that is a <type 'int'>).", Attribute(name='log', default=NOTHING, validator=<instance_of validator for type <type 'str'>>, repr=True, cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False), <type 'str'>, 1)

OK

with correct type
>>> test = Result('aaa')
>>> test.log
'aaa'

OK

class with optional attribute

class definition

>>> import attr
>>> @attr.s
... class Result(object):
...   log = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(str)))
...

Instantiation of the class

with missing attribute
>>> test = Result()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes exactly 2 arguments (1 given)

KO

with invalid type
>>> test = Result(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<attrs generated init 7e2ff957cec78e81193f38c89e2f4eb2ff2dad4e>", line 4, in __init__
  File "/.../.venv/lib/python2.7/site-packages/attr/validators.py", line 106, in __call__
    self.validator(inst, attr, value)
  File "/.../.venv/lib/python2.7/site-packages/attr/validators.py", line 32, in __call__
    value,
TypeError: ("'log' must be <type 'str'> (got 1 that is a <type 'int'>).", Attribute(name='log', default=NOTHING, validator=<optional validator for <instance_of validator for type <type 'str'>> or None>, repr=True, cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False), <type 'str'>, 1)

OK

with correct type
>>> test = Result('aaa')
>>> test.log
'aaa'

OK


What am I doing wrong to use optional attributes? Where is my misconception?

1 Answer 1

1

The correct class definition is:

>>> @attr.s
... class Result(object):
...   log = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(str)))
Sign up to request clarification or add additional context in comments.

4 Comments

Yes, optional means "can be None" – not "can be missing".
@hynek Thanks for the pointer. I'm apparently still struggling with the difference between missing and null (coming from the .net world where such a distinction does not exist)
@E.Jaep Python doesn't have a notion of "missing" as such. You have to consider the underlying data model here. If you never write foo.x = at any point, foo never gets an x attribute. That's what "missing" could mean here -- the constructor/init function would never assign x to the object being constructed/initialized. Another possible meaning could be that the parameter has a default value, meaning you can omit it from the call. This is what default= does in attrs.
I get No mandatory attributes allowed after an attribute with a default value or factory when using this exact code?!?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.