from traits.api import HasTraits, Str, Tuple
class Data(HasTraits):
values = Tuple(Str, ...)
data = Data(values=("a", "b", "c"))
Output:
TraitError: The 'values' trait of a Data instance must be a tuple of the form: (a string, an ellipsis or None), but a value of ('a', 'b', 'c') <class 'tuple'> was specified.
I am learning traits api and read the docs, I didn't a find way to pass any specific type to the variable-length tuple in traits. I am getting error! How do i solve this?
Changed values = Tuple(Str, ...)
to values = Tuple(Str)
, Still got:
TraitError: The 'values' trait of a Data instance must be a tuple of the form: (a string), but a value of ('a', 'b', 'c') <class 'tuple'> was specified.
According to the Tuple docs, variable length tuples are not an option:
The default value is determined as follows:
- If no arguments are specified, the default value is ().
- If a tuple is specified as the first argument, it is the default value.
- If a tuple is not specified as the first argument, the default value is a tuple whose length is the length of the argument list, and whose values are the default values for the corresponding trait types.
The use case you're describing, a variable-length sequence of a single type is what you get with a List(Str)
, although you do not get immutability. You could fake it, by creating a Property that gets and sets tuples but stores a List under the cover:
from traits.api import HasTraits, List, Str, Tuple, Property
class Foo(HasTraits):
t_prop = Property(Tuple)
_data = List(Str)
def _get_t_prop(self):
return tuple(self._data)
def _set_t_prop(self, value):
self._data = list(value)
foo = Foo()
foo.t_prop = ('a',)
print(foo.t_prop)
foo.t_prop = ('a', 'b')
print(foo.t_prop)
foo.t_prop = ('a', 'b', 1)
print(foo.t_prop)
This produces the output below. It's not quite right because the error message is triggered by the List validator, not the Tuple's.
('a',)
('a', 'b')
Traceback (most recent call last):
...
traits.trait_errors.TraitError: Each element of the '_data' trait of a Foo instance must be a string, but a value of 1 <class 'int'> was specified.
You could validate the Tuple type with something like the following, but this starts feeling a little icky:
def _set_t_prop(self, value):
validator = Tuple((Str, ) * len(value))
validator.validate(self, "t_prop", value)
self._data = list(value)
The generated output is:
('a',)
('a', 'b')
traits.trait_errors.TraitError: The 't_prop' trait of a Foo instance must be a tuple of the form: (a string, a string, a string), but a value of ('a', 'b', 1) <class 'tuple'> was specified.