Source code for descarteslabs.workflows.types.containers.list_

import operator

from collections import abc

from ....common.graft import client
from ...cereal import serializable
from ..core import (
    ProxyTypeError,
    GenericProxytype,
    typecheck_promote,
    assert_is_proxytype,
    merge_params,
)
from ..primitives import Int, Bool
from .collection import CollectionMixin
from .slice import Slice

from ._check_valid_binop import check_valid_binop_for


[docs]@serializable() class List(GenericProxytype, CollectionMixin): """ ``List[ValueType]``: Proxy sequence of any number of elements, all of the same type. Can be instantiated from any Python iterable, or another List of the same type. Examples -------- >>> from descarteslabs.workflows import List, Str, Int >>> List[Str](["foo", "bar", "baz"]) # list of Strs <descarteslabs.workflows.types.containers.list_.List[Str] object at 0x...> >>> List[List[Int]]([[1, 2], [-1], [10, 11, 12]]) # list of lists of Ints <descarteslabs.workflows.types.containers.list_.List[List[Int]] object at 0x...> >>> from descarteslabs.workflows import List, Float >>> my_list = List[Float]([1.1, 2.2, 3.3, 4.4]) >>> my_list <descarteslabs.workflows.types.containers.list_.List[Float] object at 0x...> >>> my_list.compute() # doctest: +SKIP [1.1, 2.2, 3.3, 4.4] >>> my_list[2].compute() # doctest: +SKIP 3.3 >>> (my_list * 2).compute() # doctest: +SKIP [1.1, 2.2, 3.3, 4.4, 1.1, 2.2, 3.3, 4.4] >>> (my_list == my_list).compute() # doctest: +SKIP True """ def __init__(self, iterable): if self._type_params is None: raise TypeError( "Cannot instantiate a generic List; the item type must be specified (like `List[Int]`)" ) if isinstance(iterable, type(self)): self.graft = client.apply_graft("wf.list.copy", iterable) self.params = iterable.params elif isinstance(iterable, List): raise ProxyTypeError( "Cannot convert {} to {}, since they have different value types".format( type(iterable).__name__, type(self).__name__ ) ) else: if not isinstance(iterable, abc.Iterable): raise ProxyTypeError("Expected an iterable, got {}".format(iterable)) value_type = self._type_params[0] def checker_promoter(i, x): try: return value_type._promote(x) except ProxyTypeError: raise ProxyTypeError( "{}: Expected iterable values of type {}, but for item {}, got {!r}".format( type(self).__name__, value_type, i, x ) ) iterable = tuple(checker_promoter(i, x) for i, x in enumerate(iterable)) self.graft = client.apply_graft("wf.list", *iterable) self.params = merge_params(*iterable) @classmethod def _validate_params(cls, type_params): assert len(type_params) == 1, "List can only have one element type specified" type_param = type_params[0] error_message = "List type must be a Proxytype, got {}".format(type_param) assert_is_proxytype(type_param, error_message=error_message) @typecheck_promote((Int, Slice)) def __getitem__(self, item): # TODO(gabe): cache return_type = self._type_params[0] if isinstance(item, Int) else type(self) return return_type._from_apply("wf.get", self, item) def __iter__(self): raise TypeError( "Proxy List object is not iterable, since it contains an unknown number of elements" ) @property def _element_type(self): return self._type_params[0] @typecheck_promote(lambda self: type(self)) def __lt__(self, other): check_valid_binop_for( operator.lt, self._type_params[0], "Operator `<` invalid for {}".format(type(self).__name__), ) return Bool._from_apply("wf.lt", self, other) @typecheck_promote(lambda self: type(self)) def __le__(self, other): check_valid_binop_for( operator.le, self._type_params[0], "Operator `<=` invalid for {}".format(type(self).__name__), ) return Bool._from_apply("wf.le", self, other) @typecheck_promote(lambda self: type(self)) def __gt__(self, other): check_valid_binop_for( operator.gt, self._type_params[0], "Operator `>` invalid for {}".format(type(self).__name__), ) return Bool._from_apply("wf.gt", self, other) @typecheck_promote(lambda self: type(self)) def __ge__(self, other): check_valid_binop_for( operator.ge, self._type_params[0], "Operator `>=` invalid for {}".format(type(self).__name__), ) return Bool._from_apply("wf.ge", self, other) @typecheck_promote(lambda self: type(self)) def __eq__(self, other): check_valid_binop_for( operator.eq, self._type_params[0], "Operator `==` invalid for {}".format(type(self).__name__), ) return Bool._from_apply("wf.eq", self, other) @typecheck_promote(lambda self: type(self)) def __ne__(self, other): check_valid_binop_for( operator.ne, self._type_params[0], "Operator `!=` invalid for {}".format(type(self).__name__), ) return Bool._from_apply("wf.ne", self, other) @typecheck_promote(lambda self: type(self)) def __add__(self, other): return self._from_apply("wf.add", self, other) @typecheck_promote(lambda self: type(self)) def __radd__(self, other): return self._from_apply("wf.add", other, self) @typecheck_promote(Int) def __mul__(self, times): return self._from_apply("wf.mul", self, times) @typecheck_promote(Int) def __rmul__(self, times): return self._from_apply("wf.mul", times, self)