Coverage for python/lsst/utils/inheritDoc.py: 92%
18 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-03-20 10:50 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-03-20 10:50 +0000
1# This file is part of utils.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# Use of this source code is governed by a 3-clause BSD-style
10# license that can be found in the LICENSE file.
12from __future__ import annotations
14__all__ = ("inheritDoc",)
16import inspect
17from collections.abc import Callable
20def inheritDoc(klass: type) -> Callable:
21 """Extend existing documentation for a method that exists in another
22 class and extend it with any additional documentation defined.
24 This decorator takes a class from which to draw documentation from as an
25 argument. This is so that any class may be used as a source of
26 documentation and not just the immediate parent of a class. This is useful
27 when there may be a long inheritance chain, or in the case of mixins.
29 Parameters
30 ----------
31 klass : object
32 The class to inherit documentation from.
34 Returns
35 -------
36 decorator : callable
37 Intermediate decorator used in the documentation process.
39 Notes
40 -----
41 This method naively appends the doc string from the decorated method to the
42 doc string of the equivalent method from the given class. No attempt
43 is made to ensure that duplicated sections are merged together or
44 overwritten.
46 This decorator is not necessary to ensure that a parent doc string appears
47 in a subclass. Tools like ``pydoc`` and Sphinx handle that automatically.
48 This can, though, be used to ensure that a specific docstring from a
49 parent class appears if there is ambiguity from multiple inheritance.
50 """
52 def _tmpDecorator(method: type) -> Callable:
53 """Update the documentation from a class with the same method."""
54 methodName = method.__name__
55 if not hasattr(klass, methodName): 55 ↛ 56line 55 didn't jump to line 56, because the condition on line 55 was never true
56 raise AttributeError(f"{klass} has no method named {methodName} to inherit from")
58 # To append reliably, the doc strings need to be cleaned to
59 # remove indents.
60 appendText = inspect.cleandoc(method.__doc__ or "")
61 parentText = inspect.cleandoc(getattr(klass, methodName).__doc__ or "")
63 if parentText:
64 if appendText:
65 # cleandoc() strips leading and trailing space so it is safe
66 # to add new lines.
67 parentText += "\n\n" + appendText
68 method.__doc__ = parentText
69 else:
70 # Do not update the doc string if there was no parent doc string.
71 pass
72 return method
74 return _tmpDecorator