docs: def move_part_instance(part_instance, target_parent, part_model, name=None, include_children=True):
      """
      Move the `Part` instance to target parent and updates the properties based on the original part instance.
  
      .. versionadded:: 2.3
  
      :param part_instance: `Part` object to be moved
      :type part_instance: :class:`Part`
      :param part_model: `Part` object representing the model of part_instance
      :type part_model: :class: `Part`
      :param target_parent: `Part` object under which the desired `Part` is moved
      :type target_parent: :class:`Part`
      :param name: how the moved top-level `Part` should be called
      :type name: basestring
      :param include_children: True to move also the descendants of `Part`. If False, the children will be lost.
      :type include_children: bool
      :return: moved :class: `Part` instance
      """
      # If no specific name has been required, then call in as Clone of the part_instance.
      if not name:
          name = part_instance.name
  
      # Retrieve the model of the future part to be created
      moved_model = get_mapping_dictionary()[part_model.id]
  
      # Now act based on multiplicity
      if moved_model.multiplicity == Multiplicity.ONE:
          # If multiplicity is 'Exactly 1', that means the instance was automatically created with the model, so just
          # retrieve it, map the original instance with the moved one and update the name and property values.
          moved_instance = moved_model.instances(parent_id=target_parent.id)[0]
          map_property_instances(part_instance, moved_instance)
          moved_instance = update_part_with_properties(part_instance, moved_instance, name=str(name))
      elif moved_model.multiplicity == Multiplicity.ONE_MANY:
          # If multiplicity is '1 or more', that means one instance has automatically been created with the model, so
          # retrieve it, map the original instance with the moved one and update the name and property values. Store
          # the model in a list, in case there are multiple instance those need to be recreated.
          if target_parent.id not in get_edited_one_many():
              moved_instance = moved_model.instances(parent_id=target_parent.id)[0]
              map_property_instances(part_instance, moved_instance)
              moved_instance = update_part_with_properties(part_instance, moved_instance, name=str(name))
              get_edited_one_many().append(target_parent.id)
          else:
              moved_instance = target_parent.add(name=part_instance.name, model=moved_model, suppress_kevents=True)
              map_property_instances(part_instance, moved_instance)
              moved_instance = update_part_with_properties(part_instance, moved_instance, name=str(name))
      else:
          # If multiplicity is '0 or more' or '0 or 1', it means no instance has been created automatically with the
          # model, so then everything must be created and then updated.
          moved_instance = target_parent.add(name=name, model=moved_model, suppress_kevents=True)
          map_property_instances(part_instance, moved_instance)
          moved_instance = update_part_with_properties(part_instance, moved_instance, name=str(name))
  
      # If include_children is True, then recursively call this function for every descendant. Keep the name of the
      # original sub-instance.
      if include_children:
          for sub_instance in part_instance._cached_children:
              move_part_instance(part_instance=sub_instance, target_parent=moved_instance,
                                 part_model=sub_instance.model(),
                                 name=sub_instance.name, include_children=True)
  
      return moved_instance