Copying the docstring of function onto another function by name
Question:
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?
Answers:
After some testing, I learned you could do something like this:
from typing import Callable
def copy_doc(copy_func: Callable) -> Callable:
"""Use Example: copy_doc(self.copy_func)(self.func) or used as deco"""
def wrapper(func: Callable) -> Callable:
func.__doc__ = copy_func.__doc__
return func
return wrapper
class Test:
def foo(self) -> None:
"""Woa"""
...
@copy_doc(foo)
def this(self) -> None:
...
print(Test().this.__doc__)
# Outputs:
> Woa
Here is an expansion of Iced Chai’s answer that will also copy over the function signature as well:
from typing import Callable, TypeVar, ParamSpec
P = ParamSpec("P")
T = TypeVar("T")
def wraps(wrapper: Callable[P, T]):
"""An implementation of functools.wraps."""
def decorator(func: Callable) -> Callable[P, T]:
func.__doc__ = wrapper.__doc__
return func
return decorator
Please note that on Python version <= 3.9 ParamSpec
is imported from typing_extensions
instead from typing
. If you need cross version compatibility you can import like this:
import sys
from typing import Callable, TypeVar
if sys.version_info <= (3, 9):
from typing_extensions import ParamSpec
else:
from typing import ParamSpec
Example usage
def func(x: int, y: int) -> str:
"""I have a docstring and arguments"""
@wraps(func)
def anotherfunc(*args, **kwargs):
return func(*args, **kwargs)
Your IDE intellisense/autocomplete should suggest/preview the signature and docstring of func
when typing anotherfunc()
. I tested this on VSCode and it worked for me. I often use this approach instead of importing functools.wraps
because functools.wraps
doesn’t seem to copying the function signature for VSCode’s intellisense.
On VSCode when I type anotherfunc()
the intellisense suggestion popup shows:
(x: int, y: int) -> str
-------------------------
I have a docstring
Here is why it works for anyone curious:
Callable[P, T]
essentially means "A function that takes in P parameters and returns a type T". ParamSpec
reserves not just the argument types, but also their names, order, defaults, and whether they are positional arguments or keyword arguments. Typing two variables with `Callable[P, T] within some common scope is the same as saying "Both of these functions take the same arguments and return the same type"
Here we type hint both the wrapper
parameter of wraps
and the return type of decorator
with Callable[P, T]
. This tells editor’s static type checker that the resulting function from decoration has the same signature as the input parameter of the wraps
function.
More concretely, using the example above, we’re saying that the signature of the resulting function from decorating anotherfunc
has the same signature as func
.
Resources:
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?
After some testing, I learned you could do something like this:
from typing import Callable
def copy_doc(copy_func: Callable) -> Callable:
"""Use Example: copy_doc(self.copy_func)(self.func) or used as deco"""
def wrapper(func: Callable) -> Callable:
func.__doc__ = copy_func.__doc__
return func
return wrapper
class Test:
def foo(self) -> None:
"""Woa"""
...
@copy_doc(foo)
def this(self) -> None:
...
print(Test().this.__doc__)
# Outputs:
> Woa
Here is an expansion of Iced Chai’s answer that will also copy over the function signature as well:
from typing import Callable, TypeVar, ParamSpec
P = ParamSpec("P")
T = TypeVar("T")
def wraps(wrapper: Callable[P, T]):
"""An implementation of functools.wraps."""
def decorator(func: Callable) -> Callable[P, T]:
func.__doc__ = wrapper.__doc__
return func
return decorator
Please note that on Python version <= 3.9 ParamSpec
is imported from typing_extensions
instead from typing
. If you need cross version compatibility you can import like this:
import sys
from typing import Callable, TypeVar
if sys.version_info <= (3, 9):
from typing_extensions import ParamSpec
else:
from typing import ParamSpec
Example usage
def func(x: int, y: int) -> str:
"""I have a docstring and arguments"""
@wraps(func)
def anotherfunc(*args, **kwargs):
return func(*args, **kwargs)
Your IDE intellisense/autocomplete should suggest/preview the signature and docstring of func
when typing anotherfunc()
. I tested this on VSCode and it worked for me. I often use this approach instead of importing functools.wraps
because functools.wraps
doesn’t seem to copying the function signature for VSCode’s intellisense.
On VSCode when I type anotherfunc()
the intellisense suggestion popup shows:
(x: int, y: int) -> str
-------------------------
I have a docstring
Here is why it works for anyone curious:
Callable[P, T]
essentially means "A function that takes in P parameters and returns a type T". ParamSpec
reserves not just the argument types, but also their names, order, defaults, and whether they are positional arguments or keyword arguments. Typing two variables with `Callable[P, T] within some common scope is the same as saying "Both of these functions take the same arguments and return the same type"
Here we type hint both the wrapper
parameter of wraps
and the return type of decorator
with Callable[P, T]
. This tells editor’s static type checker that the resulting function from decoration has the same signature as the input parameter of the wraps
function.
More concretely, using the example above, we’re saying that the signature of the resulting function from decorating anotherfunc
has the same signature as func
.
Resources: