code: def create_value(cls, prop_name, val, model=None):  # @NoSelf
          
  
          if isinstance(val, tuple):
              # this might be a class instance to be wrapped
              # (thanks to Tobias Weber for
              # providing a bug fix to avoid TypeError (in 1.99.1)
              if len(val) == 3:
                  try:
                      wrap_instance = isinstance(val[1], val[0]) and \
                          (isinstance(val[2], tuple) or
                           isinstance(val[2], list))
                  except TypeError:
                      pass  # not recognized, it must be another type of tuple
                  else:
                      if wrap_instance:
                          res = wrappers.ObsUserClassWrapper(val[1], val[2])
                          if model:
                              res.__add_model__(model, prop_name)
                          return res
  
          elif isinstance(val, list):
              res = wrappers.ObsListWrapper(val)
              if model:
                  res.__add_model__(model, prop_name)
              return res
  
          elif isinstance(val, set):
              res = wrappers.ObsSetWrapper(val)
              if model:
                  res.__add_model__(model, prop_name)
              return res
  
          elif isinstance(val, dict):
              res = wrappers.ObsMapWrapper(val)
              if model:
                  res.__add_model__(model, prop_name)
              return res
  
          return val
docs: This is used to create a value to be assigned to a
          property. Depending on the type of the value, different values
          are created and returned. For example, for a list, a
          ListWrapper is created to wrap it, and returned for the
          assignment. model is different from None when the value is
          changed (a model exists). Otherwise, during property creation
          model is None