Coverage for python/lsst/utils/inheritDoc.py: 92%

18 statements  

« prev     ^ index     » next       coverage.py v7.4.3, created at 2024-03-01 11:56 +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. 

11 

12from __future__ import annotations 

13 

14__all__ = ("inheritDoc",) 

15 

16import inspect 

17from collections.abc import Callable 

18 

19 

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. 

23 

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. 

28 

29 Parameters 

30 ---------- 

31 klass : object 

32 The class to inherit documentation from. 

33 

34 Returns 

35 ------- 

36 decorator : callable 

37 Intermediate decorator used in the documentation process. 

38 

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. 

45 

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 """ 

51 

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") 

57 

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 "") 

62 

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 

73 

74 return _tmpDecorator