docs: def parts(self,
                name=None,  # type: Optional[str]
                pk=None,  # type: Optional[str]
                model=None,  # type: Optional[Part]
                category=Category.INSTANCE,  # type: Optional[str]
                bucket=None,  # type: Optional[str]
                parent=None,  # type: Optional[str]
                activity=None,  # type: Optional[str]
                limit=None,  # type: Optional[int]
                batch=100,  # type: int
                **kwargs):
          # type: (...) -> PartSet
          """Retrieve multiple KE-chain parts.
  
          If no parameters are provided, all parts are retrieved.
  
          If additional `keyword=value` arguments are provided, these are added to the request parameters. Please
          refer to the documentation of the KE-chain API for additional query parameters.
  
          :param name: filter on name
          :type name: basestring or None
          :param pk: filter on primary key
          :type pk: basestring or None
          :param model: filter on model_id
          :type model: basestring or None
          :param category: filter on category (INSTANCE, MODEL, None)
          :type category: basestring or None
          :param bucket: filter on bucket_id
          :type bucket: basestring or None
          :param parent: filter on the parent_id, returns all childrent of the parent_id
          :type parent: basestring or None
          :param activity: filter on activity_id
          :type activity: basestring or None
          :param limit: limit the return to # items (default unlimited, so return all results)
          :type limit: int or None
          :param batch: limit the batch size to # items (defaults to 100 items per batch)
          :type batch: int or None
          :param kwargs: additional `keyword=value` arguments for the api
          :type kwargs: dict or None
          :return: :class:`models.PartSet` which is an iterator of :class:`models.Part`
          :raises NotFoundError: If no `Part` is found
  
          Examples
          --------
          Return all parts (defaults to instances) with exact name 'Gears'.
  
          >>> client = Client(url='https://default.localhost:9443', verify=False)
          >>> client.login('admin','pass')
          >>> client.parts(name='Gears')  # doctest:Ellipsis
          ...
  
          Return all parts with category is MODEL or category is INSTANCE.
  
          >>> client.parts(name='Gears', category=None)  # doctest:Ellipsis
          ...
  
          Return a maximum of 5 parts
  
          >>> client.parts(limit=5)  # doctest:Ellipsis
          ...
  
          """
          # if limit is provided and the batchsize is bigger than the limit, ensure that the batch size is maximised
          if limit and limit < batch:
              batch = limit
  
          request_params = {
              'id': pk,
              'name': name,
              'model': model.id if model else None,
              'category': category,
              'bucket': bucket,
              'parent': parent,
              'activity_id': activity,
              'limit': batch
          }
  
          if kwargs:
              request_params.update(**kwargs)
  
          response = self._request('GET', self._build_url('parts'), params=request_params)
  
          if response.status_code != requests.codes.ok:  # pragma: no cover
              raise NotFoundError("Could not retrieve parts")
  
          data = response.json()
  
          part_results = data['results']
  
          if batch and data.get('next'):
              while data['next']:
                  # respect the limit if set to > 0
                  if limit and len(part_results) >= limit:
                      break
                  response = self._request('GET', data['next'])
                  data = response.json()
                  part_results.extend(data['results'])
  
          return PartSet((Part(p, client=self) for p in part_results))