Edit part name and property values in one go.

        In order to prevent the backend from updating the frontend you may add `suppress_kevents=True` as
        additional keyword=value argument to this method. This will improve performance of the backend
        against a trade-off that someone looking at the frontend won't notice any changes unless the page
        is refreshed.

        :param name: new part name (defined as a string)
        :type name: basestring or None
        :param update_dict: dictionary with keys being property names (str) or property ids (uuid)
                            and values being property values
        :type update_dict: dict
        :param bulk: True to use the bulk_update_properties API endpoint for KE-chain versions later then 2.1.0b
        :type bulk: boolean or None
        :param kwargs: (optional) additional keyword arguments that will be passed inside the update request
        :type kwargs: dict or None
        :return: the updated :class:`Part`
        :raises NotFoundError: when the property name is not a valid property of this part
        :raises IllegalArgumentError: when the type or value of an argument provided is incorrect
        :raises APIError: in case an Error occurs

        Example
        -------

        >>> bike = client.scope('Bike Project').part('Bike')
        >>> bike.update(name='Good name', update_dict={'Gears': 11, 'Total Height': 56.3}, bulk=True)

def update(self, name=None, update_dict=None, bulk=True, **kwargs):
        """
        Edit part name and property values in one go.

        In order to prevent the backend from updating the frontend you may add `suppress_kevents=True` as
        additional keyword=value argument to this method. This will improve performance of the backend
        against a trade-off that someone looking at the frontend won't notice any changes unless the page
        is refreshed.

        :param name: new part name (defined as a string)
        :type name: basestring or None
        :param update_dict: dictionary with keys being property names (str) or property ids (uuid)
                            and values being property values
        :type update_dict: dict
        :param bulk: True to use the bulk_update_properties API endpoint for KE-chain versions later then 2.1.0b
        :type bulk: boolean or None
        :param kwargs: (optional) additional keyword arguments that will be passed inside the update request
        :type kwargs: dict or None
        :return: the updated :class:`Part`
        :raises NotFoundError: when the property name is not a valid property of this part
        :raises IllegalArgumentError: when the type or value of an argument provided is incorrect
        :raises APIError: in case an Error occurs

        Example
        -------

        >>> bike = client.scope('Bike Project').part('Bike')
        >>> bike.update(name='Good name', update_dict={'Gears': 11, 'Total Height': 56.3}, bulk=True)

        """
        # dict(name=name, properties=json.dumps(update_dict))) with property ids:value
        action = 'bulk_update_properties'

        request_body = dict()
        for prop_name_or_id, property_value in update_dict.items():
            if is_uuid(prop_name_or_id):
                request_body[prop_name_or_id] = property_value
            else:
                request_body[self.property(prop_name_or_id).id] = property_value

        if bulk and len(update_dict.keys()) > 1:
            if name:
                if not isinstance(name, str):
                    raise IllegalArgumentError("Name of the part should be provided as a string")
            r = self._client._request('PUT', self._client._build_url('part', part_id=self.id),
                                      data=dict(name=name, properties=json.dumps(request_body), **kwargs),
                                      params=dict(select_action=action))
            if r.status_code != requests.codes.ok:  # pragma: no cover
                raise APIError('{}: {}'.format(str(r), r.content))
        else:
            for property_name, property_value in update_dict.items():
                self.property(property_name).value = property_value