Search code examples
pythondocstring

Copying the docstring of function onto another function by name


I'm looking to copy the docstring of a function in the same file by name (with a decorator).

I can easily do it with a function that is out of the current module, but I'm a bit confused when it comes to the same module (or the same class more specifically)

Here's what I have so far:

import inspect

def copy_doc(func_name: str):
    def wrapper(func):
        doc = ... # get doc from function that has the name as func_name
        func.__doc__ = doc
        return func
    retun wrapper

I'm looking for something that can do two of these examples:

Ex 1:

def this() -> None:
    """Fun doc string"""
    return

@copy_doc('this')
def that() -> None:
    return

print(that.__doc__)

Ex 2:

class This:
    def foo(self) -> None:
        """Fun doc string"""
        return None

    @copy_doc('foo')
    def bar(self) -> None:
        return None

print(This().bar.__doc__)

Any fun ideas?


Solution

  • After some testing and experimentation, I learned you could directly reference the function in a given class.

    * Note ParamSpec and TypeVar are to keep the correct signature of the wrapped function, you can remove all the annotations if you do not need them.

    from typing import Callable, TypeVar, Any, TypeAlias
    from typing_extensions import ParamSpec
    
    T = TypeVar('T')
    P = ParamSpec('P')
    WrappedFuncDeco: TypeAlias = Callable[[Callable[P, T]], Callable[P, T]]
    
    
    def copy_doc(copy_func: Callable[..., Any]) -> WrappedFuncDeco[P, T]:
        """Copies the doc string of the given function to another. 
        This function is intended to be used as a decorator.
    
        .. code-block:: python3
    
            def foo():
                '''This is a foo doc string'''
                ...
    
            @copy_doc(foo)
            def bar():
                ...
        """
    
        def wrapped(func: Callable[P, T]) -> Callable[P, T]:
            func.__doc__ = copy_func.__doc__
            return func
    
        return wrapped
    
    
    class Cas:
        def foo(self) -> None:
            """This is the foo doc string."""
            return
    
        @copy_doc(foo)
        def bar(self) -> None:
            return
    
    
    print(Cas.bar.__doc__)
    # >>> This is the foo doc string.