code: def __setattr__(self, name, value):
      if not self.overwrite:
          raise NotImplementedError
  
      if name == "type":
          if value is None:
              # Type: None
              pass
          elif util.is_iterable(x=value):
              # Type: tuple(*types)
              if any(_normalize_type(dtype=x) is None for x in value):
                  raise TensorforceError.value(
                      name="TensorSpec", argument=name, value=value
                  )
              value = tuple(_normalize_type(dtype=x) for x in value)
          else:
              # Type: 'bool' | 'int' | 'float'
              if _normalize_type(dtype=value) is None:
                  raise TensorforceError.value(
                      name="TensorSpec", argument=name, value=value
                  )
              value = _normalize_type(dtype=value)
  
          # Delete attributes not required anymore
          if (
              self.type is not None
              and self.type != "bool"
              and value == "bool"
          ):
              super().__delattr__("min_value")
              super().__delattr__("max_value")
          if (
              self.type is not None
              and (
                  self.type == "int"
                  or (
                      isinstance(self.type, tuple)
                      and "int" in self.type
                  )
              )
              and value != "int"
              and (not isinstance(value, tuple) or "int" not in value)
          ):
              super().__delattr__("num_values")
  
          # Set type attribute
          super().__setattr__(name, value)
  
          # Reset attributes
          if self.type == "int" or (
              isinstance(self.type, tuple) and "int" in self.type
          ):
              self.min_value = None
              self.max_value = None
              self.num_values = None
          elif self.type != "bool":
              self.min_value = None
              self.max_value = None
  
      elif name == "shape":
          if value is None:
              # Shape: None
              pass
          elif util.is_iterable(x=value):
              if len(value) > 0 and value[0] is None:
                  # Shape: tuple(None, *ints >= -1)
                  try:
                      value = (None,) + tuple(int(x) for x in value[1:])
                      if any(x < -1 for x in value[1:]):
                          raise TensorforceError.value(
                              name="TensorSpec",
                              argument=name,
                              value=value,
                          )
                  except BaseException:
                      raise TensorforceError.type(
                          name="TensorSpec",
                          argument=name,
                          value=type(value),
                      )
              else:
                  # Shape: tuple(*ints >= -1)
                  try:
                      value = tuple(int(x) for x in value)
                      if any(x < -1 for x in value):
                          raise TensorforceError.value(
                              name="TensorSpec",
                              argument=name,
                              value=value,
                          )
                  except BaseException:
                      raise TensorforceError.value(
                          name="TensorSpec", argument=name, value=value
                      )
          else:
              # Shape: (int >= -1,)
              try:
                  value = (int(value),)
                  if value[0] < -1:
                      raise TensorforceError.value(
                          name="TensorSpec", argument=name, value=value
                      )
              except BaseException:
                  raise TensorforceError.type(
                      name="TensorSpec",
                      argument=name,
                      value=type(value),
                  )
  
          # TODO: check min/max_value shape if np.ndarray
  
          # Set shape attribute
          super().__setattr__(name, value)
  
      elif name == "min_value" or name == "max_value":
          # Invalid for type == 'bool', or type == 'int' and num_values != None
          if self.type == "bool":
              raise TensorforceError.invalid(
                  name="TensorSpec",
                  argument=name,
                  condition="type is bool",
              )
  
          if value is None:
              # Min/max value: None
              pass
          else:
              # Min/max value: int/float
              try:
                  value = self.py_type()(value)
                  if self.type == "int" and self.num_values is not None:
                      if name == "min_value":
                          assert value == 0
                      elif name == "max_value":
                          assert value == self.num_values - 1
              except BaseException:
                  try:
                      value = np.asarray(value, dtype=self.np_type())
                      if self.type == "int":
                          assert self.num_values is None
                  except BaseException:
                      raise TensorforceError.type(
                          name="TensorSpec",
                          argument=name,
                          value=type(value),
                      )
  
              if isinstance(value, np.ndarray):
                  if self.shape is not None and (
                      value.ndim > len(self.shape)
                      or value.shape != self.shape[: value.ndim]
                  ):
                      raise TensorforceError.value(
                          name="TensorSpec",
                          argument=(name + " shape"),
                          value=value.shape,
                          hint="incompatible with {}".format(
                              self.shape
                          ),
                      )
                  if (
                      name == "min_value"
                      and self.max_value is not None
                      and (value > self.max_value - util.epsilon).any()
                  ):
                      raise TensorforceError.value(
                          name="TensorSpec",
                          argument=name,
                          value=value,
                          condition="max_value = {}".format(
                              self.max_value
                          ),
                      )
                  elif (
                      name == "max_value"
                      and self.min_value is not None
                      and (value < self.min_value + util.epsilon).any()
                  ):
                      raise TensorforceError.value(
                          name="TensorSpec",
                          argument=name,
                          value=value,
                          condition="min_value = {}".format(
                              self.min_value
                          ),
                      )
              else:
                  if name == "min_value" and self.max_value is not None:
                      if isinstance(self.max_value, np.ndarray):
                          if (
                              value > self.max_value - util.epsilon
                          ).any():
                              raise TensorforceError.value(
                                  name="TensorSpec",
                                  argument=name,
                                  value=value,
                                  condition="max_value = {}".format(
                                      self.max_value
                                  ),
                              )
                      elif value > self.max_value - util.epsilon:
                          raise TensorforceError.value(
                              name="TensorSpec",
                              argument=name,
                              value=value,
                              condition="max_value = {}".format(
                                  self.max_value
                              ),
                          )
                  elif (
                      name == "max_value" and self.min_value is not None
                  ):
                      if isinstance(self.min_value, np.ndarray):
                          if (
                              value < self.min_value + util.epsilon
                          ).any():
                              raise TensorforceError.value(
                                  name="TensorSpec",
                                  argument=name,
                                  value=value,
                                  condition="min_value = {}".format(
                                      self.min_value
                                  ),
                              )
                      elif value < self.min_value + util.epsilon:
                          raise TensorforceError.value(
                              name="TensorSpec",
                              argument=name,
                              value=value,
                              condition="min_value = {}".format(
                                  self.min_value
                              ),
                          )
  
          # Set min/max_value attribute
          super().__setattr__(name, value)
  
      elif name == "num_values":
          # Invalid for type != 'int'
          if self.type != "int" and (
              not isinstance(self.type, tuple) or "int" not in self.type
          ):
              raise TensorforceError.invalid(
                  name="TensorSpec",
                  argument=name,
                  condition="type is {}".format(self.type),
              )
  
          if value is None:
              # Num values: None
              pass
          else:
              # Num values: int >= 0
              try:
                  value = int(value)
              except BaseException:
                  raise TensorforceError.type(
                      name="TensorSpec",
                      argument=name,
                      value=type(value),
                  )
              if value < 0:
                  raise TensorforceError.value(
                      name="TensorSpec", argument=name, value=value
                  )
  
          # Set num_values attribute and min/max_value accordingly
          super().__setattr__(name, value)
          if value is not None and value > 0:
              super().__setattr__("min_value", 0)
              super().__setattr__("max_value", value - 1)
          else:
              super().__setattr__("min_value", None)
              super().__setattr__("max_value", None)
  
      else:
          raise TensorforceError.invalid(
              name="TensorSpec", argument=name
          )
  
imports: from functools import total_ordering
  import numpy
  import tensorflow
  from tensorforce import TensorforceError, util
  from tensorforce.core.utils import tf_util
label_desc: Use image node_id 17 for calling the TensorSpec obj's underlying member method code with example usage: obj.__setattr__(name, value) without return types