Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Documentation of functions defined with functools partialmethod

Tags:

python

I have tried to somehow get a documentation for a partialmethod to work. My current code is

from functools import partialmethod

class Fun(object):

  def test(self, num):
    """
    I have a documentation
    """
    return num

  test2 = partialmethod(test, num=10)
  test2.__doc__ = """Blub"""

  test3 = partialmethod(test, num=20)

But if I run

a = Fun()
a.test2.__doc__ # only returns the partials documentation not "Blub"
Fun.test2.__doc__ # gives nothing

and Sphinx lists them using autoclass as undocumented members.

I have read https://docs.python.org/3/library/functools.html#partial-objects and https://docs.python.org/3/library/functools.html#functools.partialmethod but does that mean that there is no way of getting documentations into partialmethods or am I just too stupid about it?

like image 255
MSeifert Avatar asked Oct 19 '22 00:10

MSeifert


1 Answers

It's not possible to set a docstring on a partialmethod object. That's because partialmethod is a class written in Python, and instances of classes get their docstring from the class's __doc__, not from a __doc__ attribute on the instances. Functions behave differently, with the __doc__ attribute of the function object being looked at.

Depending on how complicated your use of partialmethod is, you may be able to write your own version that returns a function, rather than an instance, thus allowing you to customize the documentation by assigning to the __doc__ attribute.

Here's a quick version I've thrown together with only basic testing. I think it works for common cases (e.g. where func is an actual function), but it probably won't be as flexible as the regular partialmethod type, so you should double check that it does everything you need it to do:

import functools

def my_partialmethod(func, *args1, **kwargs1):
    @functools.wraps(func)  # copy attributes to start, they can be overwritten later
    def method(self, *args2, **kwargs2):
        return func(self, *args1, *args2, **kwargs1, **kwargs2)
    return method

The multiple unpacking in the call to func is only legal in Python 3.5. In older Python versions, you'll have to merge the arguments yourself with something like this:

    def method(self, *args2, **kwargs2):
        kwargs = kwargs1.copy()
        kwargs.update(kwargs2)
        return func(self, *(args1+args2), **kwargs)

Here's an example use:

class Test(object):
    def method1(self, arg):
        "docstring1"
        print(arg)

    method2 = my_partial_method(method1, "foo")
    method2.__name__ = "method2"
    method2.__doc__ = "docstring2"

    method3 = my_partial_method(method1, arg="bar")
    method3.__name__ = "method3"
    method3.__doc__ = "docstring3"

You can of course pick which attributes to overwrite. I'm not sure if using functools.wraps is a good idea or not, as it may copy over a bunch of invalid attributes, beyond the ones I'm modifying in my example.

like image 64
Blckknght Avatar answered Oct 21 '22 17:10

Blckknght