docs: def add_parametric_object_params(prepend=False, hide_private=True):
      """
      Add :class:`ParametricObject <cqparts.params.ParametricObject>` parameters
      in a list to the *docstring*.
  
      This is only intended to be used with *sphinx autodoc*.
  
      In your *sphinx* ``config.py`` file::
  
          from cqparts.utils.sphinx import add_parametric_object_params
          def setup(app):
              app.connect("autodoc-process-docstring", add_parametric_object_params())
  
      Then, when documenting your :class:`Part <cqparts.Part>` or
      :class:`Assembly <cqparts.Assembly>` the
      :class:`ParametricObject <cqparts.params.ParametricObject>` parameters
      will also be documented in the output.
  
      :param prepend: if True, parameters are added to the beginning of the *docstring*.
                      otherwise, they're appended at the end.
      :type prepend: :class:`bool`
      :param hide_private: if True, parameters with a ``_`` prefix are not documented.
      :type hide_private: :class:`bool`
      """
  
      from ..params import ParametricObject
  
      def param_lines(app, obj):
          params = obj.class_params(hidden=(not hide_private))
  
          # Header
          doc_lines = []
          if params:  # only add a header if it's relevant
              doc_lines += [
                  ":class:`ParametricObject <cqparts.params.ParametricObject>` constructor parameters:",
                  "",
              ]
  
          for (name, param) in sorted(params.items(), key=lambda x: x[0]):  # sort by name
              doc_lines.append(':param {name}: {doc}'.format(
                  name=name, doc=param._param(),
              ))
              doc_lines.append(':type {name}: {doc}'.format(
                  name=name, doc=param._type(),
              ))
  
          return doc_lines
  
      # Conditions for running above `param_lines` function (in order)
      conditions = [  # (all conditions must be met)
          lambda o: type(o) == type,
          lambda o: o is not ParametricObject,
          lambda o: issubclass(o, ParametricObject),
      ]
  
      def callback(app, what, name, obj, options, lines):
          # sphinx callback
          # (this method is what actually gets sent to the sphinx runtime)
          if all(c(obj) for c in conditions):
              new_lines = param_lines(app, obj)
              _add_lines(lines, new_lines, prepend=prepend)
  
      return callback