6

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?

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I actually had such a decorator (ok, it was a bit different) before using functools.partialmethod. But that approach has some downsides - i.e. it copies the original function signature (which normally is a good thing but not with partials). But it seems very sad that the partialmethod is not capable of providing such functionality. Especially because partial allows such an usage - but only for functions not methods. But nevertheless many thanks for your answer and if no other possibility presents itself I will accept your answer tomorrow. :-)
Yeah, my function is essentially partial with a special case for self. It should work find when wrapping ordinary methods, but won't work if you're wrapping something like a staticmethod or another descriptor that doesn't expect to get self. If the wraps call causes more trouble than good, you can remove it (the signature of the wrapper function will then be (*args2, **kwargs2), which may or may not be an improvement).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.