コード例 #1
0
 async def create_value(self, value, type_spec=None):
     type_spec = computation_types.to_type(type_spec)
     if isinstance(value, intrinsic_defs.IntrinsicDef):
         if not type_utils.is_concrete_instance_of(type_spec,
                                                   value.type_signature):
             raise TypeError(
                 'Incompatible type {} used with intrinsic {}.'.format(
                     type_spec, value.uri))
         else:
             return FederatedExecutorValue(value, type_spec)
     if isinstance(value, placement_literals.PlacementLiteral):
         if type_spec is not None:
             py_typecheck.check_type(type_spec,
                                     computation_types.PlacementType)
         return FederatedExecutorValue(value,
                                       computation_types.PlacementType())
     elif isinstance(value, computation_impl.ComputationImpl):
         return await self.create_value(
             computation_impl.ComputationImpl.get_proto(value),
             type_utils.reconcile_value_with_type_spec(value, type_spec))
     elif isinstance(value, pb.Computation):
         if type_spec is None:
             type_spec = type_serialization.deserialize_type(value.type)
         which_computation = value.WhichOneof('computation')
         if which_computation in ['tensorflow', 'lambda']:
             return FederatedExecutorValue(value, type_spec)
         elif which_computation == 'reference':
             raise ValueError(
                 'Encountered an unexpected unbound references "{}".'.
                 format(value.reference.name))
         elif which_computation == 'intrinsic':
             intr = intrinsic_defs.uri_to_intrinsic_def(value.intrinsic.uri)
             if intr is None:
                 raise ValueError(
                     'Encountered an unrecognized intrinsic "{}".'.format(
                         value.intrinsic.uri))
             py_typecheck.check_type(intr, intrinsic_defs.IntrinsicDef)
             return await self.create_value(intr, type_spec)
         elif which_computation == 'placement':
             return await self.create_value(
                 placement_literals.uri_to_placement_literal(
                     value.placement.uri), type_spec)
         elif which_computation == 'call':
             parts = [value.call.function]
             if value.call.argument.WhichOneof('computation'):
                 parts.append(value.call.argument)
             parts = await asyncio.gather(
                 *[self.create_value(x) for x in parts])
             return await self.create_call(
                 parts[0], parts[1] if len(parts) > 1 else None)
         elif which_computation == 'tuple':
             element_values = await asyncio.gather(
                 *[self.create_value(x.value) for x in value.tuple.element])
             return await self.create_tuple(
                 anonymous_tuple.AnonymousTuple([
                     (e.name if e.name else None, v)
                     for e, v in zip(value.tuple.element, element_values)
                 ]))
         elif which_computation == 'selection':
             which_selection = value.selection.WhichOneof('selection')
             if which_selection == 'name':
                 name = value.selection.name
                 index = None
             elif which_selection != 'index':
                 raise ValueError(
                     'Unrecognized selection type: "{}".'.format(
                         which_selection))
             else:
                 index = value.selection.index
                 name = None
             return await self.create_selection(await self.create_value(
                 value.selection.source),
                                                index=index,
                                                name=name)
         else:
             raise ValueError(
                 'Unsupported computation building block of type "{}".'.
                 format(which_computation))
     else:
         py_typecheck.check_type(type_spec, computation_types.Type)
         if isinstance(type_spec, computation_types.FunctionType):
             raise ValueError(
                 'Encountered a value of a functional TFF type {} and Python type '
                 '{} that is not of one of the recognized representations.'.
                 format(type_spec, py_typecheck.type_string(type(value))))
         elif isinstance(type_spec, computation_types.FederatedType):
             children = self._target_executors.get(type_spec.placement)
             if not children:
                 raise ValueError(
                     'Placement "{}" is not configured in this executor.'.
                     format(type_spec.placement))
             py_typecheck.check_type(children, list)
             if not type_spec.all_equal:
                 py_typecheck.check_type(value,
                                         (list, tuple, set, frozenset))
                 if not isinstance(value, list):
                     value = list(value)
             elif isinstance(value, list):
                 raise ValueError(
                     'An all_equal value should be passed directly, not as a list.'
                 )
             else:
                 value = [value for _ in children]
             if len(value) != len(children):
                 raise ValueError(
                     'Federated value contains {} items, but the placement {} in this '
                     'executor is configured with {} participants.'.format(
                         len(value), type_spec.placement, len(children)))
             child_vals = await asyncio.gather(*[
                 c.create_value(v, type_spec.member)
                 for v, c in zip(value, children)
             ])
             return FederatedExecutorValue(child_vals, type_spec)
         else:
             child = self._target_executors.get(None)
             if not child or len(child) > 1:
                 raise RuntimeError(
                     'Executor is not configured for unplaced values.')
             else:
                 return FederatedExecutorValue(
                     await child[0].create_value(value, type_spec),
                     type_spec)
コード例 #2
0
 async def create_value(self, value, type_spec=None):
   type_spec = computation_types.to_type(type_spec)
   py_typecheck.check_type(type_spec, computation_types.Type)
   if isinstance(value, intrinsic_defs.IntrinsicDef):
     if not type_utils.is_concrete_instance_of(type_spec,
                                               value.type_signature):  # pytype: disable=attribute-error
       raise TypeError('Incompatible type {} used with intrinsic {}.'.format(
           type_spec, value.uri))  # pytype: disable=attribute-error
     else:
       return CompositeValue(value, type_spec)
   elif isinstance(value, pb.Computation):
     which_computation = value.WhichOneof('computation')
     if which_computation in ['tensorflow', 'lambda']:
       return CompositeValue(value, type_spec)
     elif which_computation == 'intrinsic':
       intr = intrinsic_defs.uri_to_intrinsic_def(value.intrinsic.uri)
       if intr is None:
         raise ValueError('Encountered an unrecognized intrinsic "{}".'.format(
             value.intrinsic.uri))
       py_typecheck.check_type(intr, intrinsic_defs.IntrinsicDef)
       return await self.create_value(intr, type_spec)
     else:
       raise NotImplementedError(
           'Unimplemented computation type {}.'.format(which_computation))
   elif isinstance(type_spec, computation_types.NamedTupleType):
     v_el = anonymous_tuple.to_elements(anonymous_tuple.from_container(value))
     t_el = anonymous_tuple.to_elements(type_spec)
     items = await asyncio.gather(
         *[self.create_value(v, t) for (_, v), (_, t) in zip(v_el, t_el)])
     return self.create_tuple(
         anonymous_tuple.AnonymousTuple([
             (k, i) for (k, _), i in zip(t_el, items)
         ]))
   elif isinstance(type_spec, computation_types.FederatedType):
     if type_spec.placement == placement_literals.SERVER:
       if type_spec.all_equal:
         return CompositeValue(
             await self._parent_executor.create_value(value, type_spec.member),
             type_spec)
       else:
         raise ValueError('A non-all_equal value on the server is unexpected.')
     elif type_spec.placement == placement_literals.CLIENTS:
       if type_spec.all_equal:
         return CompositeValue(
             await asyncio.gather(*[
                 c.create_value(value, type_spec)
                 for c in self._child_executors
             ]), type_spec)
       else:
         py_typecheck.check_type(value, list)
         if self._cardinalities is None:
           self._cardinalities = asyncio.ensure_future(
               self._get_cardinalities())
         cardinalities = await self._cardinalities
         py_typecheck.check_len(cardinalities, len(self._child_executors))
         count = sum(cardinalities)
         py_typecheck.check_len(value, count)
         result = []
         offset = 0
         for c, n in zip(self._child_executors, cardinalities):
           new_offset = offset + n
           # The slice opporator is not supported on all the types `value`
           # supports.
           # pytype: disable=unsupported-operands
           result.append(c.create_value(value[offset:new_offset], type_spec))
           # pytype: enable=unsupported-operands
           offset = new_offset
         return CompositeValue(await asyncio.gather(*result), type_spec)
     else:
       raise ValueError('Unexpected placement {}.'.format(type_spec.placement))
   else:
     return CompositeValue(
         await self._parent_executor.create_value(value, type_spec), type_spec)
コード例 #3
0
 async def create_value(self, value, type_spec=None):
   type_spec = computation_types.to_type(type_spec)
   py_typecheck.check_type(type_spec, computation_types.Type)
   if isinstance(value, intrinsic_defs.IntrinsicDef):
     if not type_utils.is_concrete_instance_of(type_spec,
                                               value.type_signature):  # pytype: disable=attribute-error
       raise TypeError('Incompatible type {} used with intrinsic {}.'.format(
           type_spec, value.uri))  # pytype: disable=attribute-error
     else:
       return CompositeValue(value, type_spec)
   elif isinstance(value, pb.Computation):
     which_computation = value.WhichOneof('computation')
     if which_computation in ['tensorflow', 'lambda']:
       return CompositeValue(value, type_spec)
     elif which_computation == 'intrinsic':
       intr = intrinsic_defs.uri_to_intrinsic_def(value.intrinsic.uri)
       if intr is None:
         raise ValueError('Encountered an unrecognized intrinsic "{}".'.format(
             value.intrinsic.uri))
       py_typecheck.check_type(intr, intrinsic_defs.IntrinsicDef)
       return await self.create_value(intr, type_spec)
     else:
       raise NotImplementedError(
           'Unimplemented computation type {}.'.format(which_computation))
   elif isinstance(type_spec, computation_types.NamedTupleType):
     value_tuple = anonymous_tuple.from_container(value)
     items = await asyncio.gather(
         *[self.create_value(v, t) for v, t in zip(value_tuple, type_spec)])
     type_elemnents_iter = anonymous_tuple.iter_elements(type_spec)
     return self.create_tuple(
         anonymous_tuple.AnonymousTuple(
             (k, i) for (k, _), i in zip(type_elemnents_iter, items)))
   elif isinstance(type_spec, computation_types.FederatedType):
     if type_spec.placement == placement_literals.SERVER:
       if not type_spec.all_equal:
         raise ValueError(
             'Expected an all equal value at the `SERVER` placement, '
             'found {}.'.format(type_spec))
       results = await self._parent_executor.create_value(
           value, type_spec.member)
       return CompositeValue(results, type_spec)
     elif type_spec.placement == placement_literals.CLIENTS:
       if type_spec.all_equal:
         results = await asyncio.gather(*[
             c.create_value(value, type_spec) for c in self._child_executors
         ])
         return CompositeValue(results, type_spec)
       else:
         py_typecheck.check_type(value, list)
         cardinalities = await self._get_cardinalities()
         total_clients = sum(cardinalities)
         py_typecheck.check_len(value, total_clients)
         results = []
         offset = 0
         for child, num_clients in zip(self._child_executors, cardinalities):
           new_offset = offset + num_clients
           result = child.create_value(value[offset:new_offset], type_spec)
           results.append(result)
           offset = new_offset
         return CompositeValue(await asyncio.gather(*results), type_spec)
     else:
       raise ValueError('Unexpected placement {}.'.format(type_spec.placement))
   else:
     return CompositeValue(
         await self._parent_executor.create_value(value, type_spec), type_spec)
コード例 #4
0
    async def create_value(self, value, type_spec=None):
        """Creates a value in this executor.

    The following kinds of `value` are supported as the input:

    * An instance of TFF computation proto containing one of the supported
      sequence intrinsics as its sole body.

    * An instance of eager TF dataset.

    * Anything that is supported by the target executor (as a pass-through).

    * A nested structure of any of the above.

    Args:
      value: The input for which to create a value.
      type_spec: An optional TFF type (required if `value` is not an instance of
        `typed_object.TypedObject`, otherwise it can be `None`).

    Returns:
      An instance of `SequenceExecutorValue` that represents the embedded value.
    """
        if type_spec is None:
            py_typecheck.check_type(value, typed_object.TypedObject)
            type_spec = value.type_signature
        else:
            type_spec = computation_types.to_type(type_spec)
        if isinstance(type_spec, computation_types.SequenceType):
            return SequenceExecutorValue(
                _SequenceFromPayload(value, type_spec), type_spec)
        if isinstance(value, pb.Computation):
            value_type = type_serialization.deserialize_type(value.type)
            value_type.check_equivalent_to(type_spec)
            which_computation = value.WhichOneof('computation')
            # NOTE: If not a supported type of intrinsic, we let it fall through and
            # be handled by embedding in the target executor (below).
            if which_computation == 'intrinsic':
                intrinsic_def = intrinsic_defs.uri_to_intrinsic_def(
                    value.intrinsic.uri)
                if intrinsic_def is None:
                    raise ValueError(
                        'Encountered an unrecognized intrinsic "{}".'.format(
                            value.intrinsic.uri))
                op_type = SequenceExecutor._SUPPORTED_INTRINSIC_TO_SEQUENCE_OP.get(
                    intrinsic_def.uri)
                if op_type is not None:
                    type_analysis.check_concrete_instance_of(
                        type_spec, intrinsic_def.type_signature)
                    op = op_type(type_spec)
                    return SequenceExecutorValue(op, type_spec)
        if isinstance(type_spec, computation_types.StructType):
            if not isinstance(value, structure.Struct):
                value = structure.from_container(value)
            elements = structure.flatten(value)
            element_types = structure.flatten(type_spec)
            flat_embedded_vals = await asyncio.gather(*[
                self.create_value(el, el_type)
                for el, el_type in zip(elements, element_types)
            ])
            embedded_struct = structure.pack_sequence_as(
                value, flat_embedded_vals)
            return await self.create_struct(embedded_struct)
        target_value = await self._target_executor.create_value(
            value, type_spec)
        return SequenceExecutorValue(target_value, type_spec)
コード例 #5
0
  async def create_value(
      self,
      value: Any,
      type_spec: Any = None) -> executor_value_base.ExecutorValue:
    """Creates an embedded value from the given `value` and `type_spec`.

    The kinds of supported `value`s are:

    * An instance of `intrinsic_defs.IntrinsicDef`.

    * An instance of `placements.PlacementLiteral`.

    * An instance of `pb.Computation` if of one of the following kinds:
      intrinsic, lambda, tensorflow, xla, or data.

    * A Python `list` if `type_spec` is a federated type.

      Note: The `value` must be a list even if it is of an `all_equal` type or
      if there is only a single participant associated with the given placement.

    * A Python value if `type_spec` is a non-functional, non-federated type.

    Args:
      value: An object to embed in the executor, one of the supported types
        defined by above.
      type_spec: An optional type convertible to instance of `tff.Type` via
        `tff.to_type`, the type of `value`.

    Returns:
      An instance of `executor_value_base.ExecutorValue` representing a value
      embedded in the `FederatingExecutor` using a particular
      `FederatingStrategy`.

    Raises:
      TypeError: If the `value` and `type_spec` do not match.
      ValueError: If `value` is not a kind supported by the
        `FederatingExecutor`.
    """
    type_spec = computation_types.to_type(type_spec)
    if isinstance(value, intrinsic_defs.IntrinsicDef):
      type_analysis.check_concrete_instance_of(type_spec, value.type_signature)
      return self._strategy.ingest_value(value, type_spec)
    elif isinstance(value, placements.PlacementLiteral):
      if type_spec is None:
        type_spec = computation_types.PlacementType()
      type_spec.check_placement()
      return self._strategy.ingest_value(value, type_spec)
    elif isinstance(value, computation_impl.ConcreteComputation):
      return await self.create_value(
          computation_impl.ConcreteComputation.get_proto(value),
          executor_utils.reconcile_value_with_type_spec(value, type_spec))
    elif isinstance(value, pb.Computation):
      deserialized_type = type_serialization.deserialize_type(value.type)
      if type_spec is None:
        type_spec = deserialized_type
      else:
        type_spec.check_assignable_from(deserialized_type)
      which_computation = value.WhichOneof('computation')
      if which_computation in ['lambda', 'tensorflow', 'xla', 'data']:
        return self._strategy.ingest_value(value, type_spec)
      elif which_computation == 'intrinsic':
        if value.intrinsic.uri in FederatingExecutor._FORWARDED_INTRINSICS:
          return self._strategy.ingest_value(value, type_spec)
        intrinsic_def = intrinsic_defs.uri_to_intrinsic_def(value.intrinsic.uri)
        if intrinsic_def is None:
          raise ValueError('Encountered an unrecognized intrinsic "{}".'.format(
              value.intrinsic.uri))
        return await self.create_value(intrinsic_def, type_spec)
      else:
        raise ValueError(
            'Unsupported computation building block of type "{}".'.format(
                which_computation))
    elif type_spec is not None and type_spec.is_federated():
      return await self._strategy.compute_federated_value(value, type_spec)
    else:
      result = await self._unplaced_executor.create_value(value, type_spec)
      return self._strategy.ingest_value(result, type_spec)
コード例 #6
0
    async def create_value(self, value, type_spec=None):
        """A coroutine that creates embedded value from `value` of type `type_spec`.

    See the `FederatingExecutorValue` for detailed information about the
    `value`s and `type_spec`s that can be embedded using `create_value`.

    Args:
      value: An object that represents the value to embed within the executor.
      type_spec: An optional `tff.Type` of the value represented by this object,
        or something convertible to it.

    Returns:
      An instance of `FederatingExecutorValue` that represents the embedded
      value.

    Raises:
      TypeError: If the `value` and `type_spec` do not match.
      ValueError: If `value` is not a kind recognized by the
        `FederatingExecutor`.
    """
        type_spec = computation_types.to_type(type_spec)
        if isinstance(type_spec, computation_types.FederatedType):
            self._check_executor_compatible_with_placement(type_spec.placement)
        elif (isinstance(type_spec, computation_types.FunctionType) and
              isinstance(type_spec.result, computation_types.FederatedType)):
            self._check_executor_compatible_with_placement(
                type_spec.result.placement)
        if isinstance(value, intrinsic_defs.IntrinsicDef):
            if not type_analysis.is_concrete_instance_of(
                    type_spec, value.type_signature):
                raise TypeError(
                    'Incompatible type {} used with intrinsic {}.'.format(
                        type_spec, value.uri))
            return FederatingExecutorValue(value, type_spec)
        elif isinstance(value, placement_literals.PlacementLiteral):
            if type_spec is None:
                type_spec = computation_types.PlacementType()
            else:
                py_typecheck.check_type(type_spec,
                                        computation_types.PlacementType)
            return FederatingExecutorValue(value, type_spec)
        elif isinstance(value, computation_impl.ComputationImpl):
            return await self.create_value(
                computation_impl.ComputationImpl.get_proto(value),
                type_utils.reconcile_value_with_type_spec(value, type_spec))
        elif isinstance(value, pb.Computation):
            deserialized_type = type_serialization.deserialize_type(value.type)
            if type_spec is None:
                type_spec = deserialized_type
            else:
                type_analysis.check_assignable_from(type_spec,
                                                    deserialized_type)
            which_computation = value.WhichOneof('computation')
            if which_computation in ['lambda', 'tensorflow']:
                return FederatingExecutorValue(value, type_spec)
            elif which_computation == 'intrinsic':
                intrinsic_def = intrinsic_defs.uri_to_intrinsic_def(
                    value.intrinsic.uri)
                if intrinsic_def is None:
                    raise ValueError(
                        'Encountered an unrecognized intrinsic "{}".'.format(
                            value.intrinsic.uri))
                return await self.create_value(intrinsic_def, type_spec)
            else:
                raise ValueError(
                    'Unsupported computation building block of type "{}".'.
                    format(which_computation))
        elif isinstance(type_spec, computation_types.FederatedType):
            self._check_value_compatible_with_placement(
                value, type_spec.placement, type_spec.all_equal)
            children = self._target_executors[type_spec.placement]
            if type_spec.all_equal:
                value = [value for _ in children]
            results = await asyncio.gather(*[
                c.create_value(v, type_spec.member)
                for v, c in zip(value, children)
            ])
            return FederatingExecutorValue(results, type_spec)
        else:
            child = self._target_executors[None][0]
            return FederatingExecutorValue(
                await child.create_value(value, type_spec), type_spec)
コード例 #7
0
    async def create_value(self, value, type_spec=None):
        """A coroutine that creates embedded value from `value` of type `type_spec`.

    See the `FederatingExecutorValue` for detailed information about the
    `value`s and `type_spec`s that can be embedded using `create_value`.

    Args:
      value: An object that represents the value to embed within the executor.
      type_spec: An optional `tff.Type` of the value represented by this object,
        or something convertible to it.

    Returns:
      An instance of `FederatingExecutorValue` that represents the embedded
      value.

    Raises:
      TypeError: If the `value` and `type_spec` do not match.
      ValueError: If `value` is not a kind recognized by the
        `FederatingExecutor`.
    """
        type_spec = computation_types.to_type(type_spec)
        if isinstance(type_spec, computation_types.FederatedType):
            self._check_executor_compatible_with_placement(type_spec.placement)
        elif (isinstance(type_spec, computation_types.FunctionType) and
              isinstance(type_spec.result, computation_types.FederatedType)):
            self._check_executor_compatible_with_placement(
                type_spec.result.placement)
        if isinstance(value, intrinsic_defs.IntrinsicDef):
            if not type_analysis.is_concrete_instance_of(
                    type_spec, value.type_signature):
                raise TypeError(
                    'Incompatible type {} used with intrinsic {}.'.format(
                        type_spec, value.uri))
            return FederatingExecutorValue(value, type_spec)
        elif isinstance(value, placement_literals.PlacementLiteral):
            if type_spec is None:
                type_spec = computation_types.PlacementType()
            else:
                py_typecheck.check_type(type_spec,
                                        computation_types.PlacementType)
            return FederatingExecutorValue(value, type_spec)
        elif isinstance(value, computation_impl.ComputationImpl):
            return await self.create_value(
                computation_impl.ComputationImpl.get_proto(value),
                type_utils.reconcile_value_with_type_spec(value, type_spec))
        elif isinstance(value, pb.Computation):
            deserialized_type = type_serialization.deserialize_type(value.type)
            if type_spec is None:
                type_spec = deserialized_type
            else:
                type_analysis.check_assignable_from(type_spec,
                                                    deserialized_type)
            which_computation = value.WhichOneof('computation')
            if which_computation in ['lambda', 'tensorflow']:
                return FederatingExecutorValue(value, type_spec)
            elif which_computation == 'reference':
                raise ValueError(
                    'Encountered an unexpected unbound references "{}".'.
                    format(value.reference.name))
            elif which_computation == 'intrinsic':
                intr = intrinsic_defs.uri_to_intrinsic_def(value.intrinsic.uri)
                if intr is None:
                    raise ValueError(
                        'Encountered an unrecognized intrinsic "{}".'.format(
                            value.intrinsic.uri))
                py_typecheck.check_type(intr, intrinsic_defs.IntrinsicDef)
                return await self.create_value(intr, type_spec)
            elif which_computation == 'placement':
                return await self.create_value(
                    placement_literals.uri_to_placement_literal(
                        value.placement.uri), type_spec)
            elif which_computation == 'call':
                parts = [value.call.function]
                if value.call.argument.WhichOneof('computation'):
                    parts.append(value.call.argument)
                parts = await asyncio.gather(
                    *[self.create_value(x) for x in parts])
                return await self.create_call(
                    parts[0], parts[1] if len(parts) > 1 else None)
            elif which_computation == 'tuple':
                element_values = await asyncio.gather(
                    *[self.create_value(x.value) for x in value.tuple.element])
                return await self.create_tuple(
                    anonymous_tuple.AnonymousTuple(
                        (e.name if e.name else None, v)
                        for e, v in zip(value.tuple.element, element_values)))
            elif which_computation == 'selection':
                which_selection = value.selection.WhichOneof('selection')
                if which_selection == 'name':
                    name = value.selection.name
                    index = None
                elif which_selection != 'index':
                    raise ValueError(
                        'Unrecognized selection type: "{}".'.format(
                            which_selection))
                else:
                    index = value.selection.index
                    name = None
                return await self.create_selection(await self.create_value(
                    value.selection.source),
                                                   index=index,
                                                   name=name)
            else:
                raise ValueError(
                    'Unsupported computation building block of type "{}".'.
                    format(which_computation))
        else:
            py_typecheck.check_type(type_spec, computation_types.Type)
            if isinstance(type_spec, computation_types.FunctionType):
                raise ValueError(
                    'Encountered a value of a functional TFF type {} and Python type '
                    '{} that is not of one of the recognized representations.'.
                    format(type_spec, py_typecheck.type_string(type(value))))
            elif isinstance(type_spec, computation_types.FederatedType):
                children = self._target_executors.get(type_spec.placement)
                self._check_value_compatible_with_placement(
                    value, type_spec.placement, type_spec.all_equal)
                if type_spec.all_equal:
                    value = [value for _ in children]
                child_vals = await asyncio.gather(*[
                    c.create_value(v, type_spec.member)
                    for v, c in zip(value, children)
                ])
                return FederatingExecutorValue(child_vals, type_spec)
            else:
                child = self._target_executors.get(None)
                if not child or len(child) > 1:
                    raise ValueError(
                        'Executor is not configured for unplaced values.')
                else:
                    return FederatingExecutorValue(
                        await child[0].create_value(value, type_spec),
                        type_spec)