Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/docutils/transforms/misc.py: 44%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

57 statements  

1# $Id: misc.py 10300 2026-02-06 09:09:27Z milde $ 

2# Author: David Goodger <goodger@python.org> 

3# Copyright: This module has been placed in the public domain. 

4 

5""" 

6Miscellaneous transforms. 

7""" 

8 

9from __future__ import annotations 

10 

11__docformat__ = 'reStructuredText' 

12 

13from docutils import nodes 

14from docutils.transforms import Transform 

15 

16 

17class CallBack(Transform): 

18 

19 """ 

20 Inserts a callback into a document. The callback is called when the 

21 transform is applied, which is determined by its priority. 

22 

23 For use with `nodes.pending` elements. Requires a ``details['callback']`` 

24 entry, a bound method or function which takes one parameter: the pending 

25 node. Other data can be stored in the ``details`` attribute or in the 

26 object hosting the callback method. 

27 """ 

28 

29 default_priority = 990 

30 

31 def apply(self) -> None: 

32 pending = self.startnode 

33 pending.details['callback'](pending) 

34 pending.parent.remove(pending) 

35 

36 

37class ClassAttribute(Transform): 

38 

39 """ 

40 Move the "class" attribute specified in the "pending" node into the 

41 next visible element. 

42 """ 

43 

44 default_priority = 210 

45 

46 def apply(self) -> None: 

47 pending = self.startnode 

48 for element in pending.findall(include_self=False, descend=False, 

49 siblings=True, ascend=True): 

50 if isinstance(element, (nodes.Invisible, nodes.system_message)): 

51 continue 

52 element['classes'] += pending.details['class'] 

53 pending.parent.remove(pending) 

54 return 

55 

56 error = self.document.reporter.error( 

57 'No suitable element following "%s" directive' 

58 % pending.details['directive'], 

59 nodes.literal_block(pending.rawsource, pending.rawsource), 

60 line=pending.line) 

61 pending.replace_self(error) 

62 

63 

64class Transitions(Transform): 

65 """ 

66 Post-process <transition> elements. 

67 

68 Move transitions at the end of sections up the tree. 

69 Warn on transitions at the beginning or end of the document or 

70 a section (ignoring title, decoration, or invisible elements), 

71 and after another transition. 

72 

73 For example, transform this:: 

74 

75 <section> 

76 ... 

77 <transition> 

78 <section> 

79 ... 

80 

81 into this:: 

82 

83 <section> 

84 ... 

85 <transition> 

86 <section> 

87 ... 

88 """ 

89 

90 default_priority = 830 

91 

92 def apply(self) -> None: 

93 for node in self.document.findall(nodes.transition): 

94 self.visit_transition(node) 

95 

96 def visit_transition(self, node) -> None: 

97 msg = '' 

98 if not isinstance(node.parent, (nodes.document, nodes.section)): 

99 self.warn('Transition only valid as child of <document> ' 

100 'or <section>.', node) 

101 else: 

102 try: 

103 node.validate_position() 

104 except nodes.ValidationError as e: 

105 msg = str(e) 

106 if 'may not end' in msg: 

107 # Move transition up the tree. 

108 sibling = node.parent # get new predecessor node 

109 parent = sibling.parent 

110 while parent is not None: 

111 index = parent.index(sibling) 

112 if index < len(parent) - 1: 

113 node.parent.remove(node) 

114 parent.insert(index + 1, node) 

115 break 

116 sibling = sibling.parent 

117 parent = sibling.parent 

118 else: 

119 self.warn('Transition at the end of the document.', node) 

120 if 'may not begin' in msg: 

121 self.warn(f'Transition at the start of the {node.parent.tagname}.', 

122 node) 

123 elif 'may not directly follow' in msg: 

124 self.warn('At least one body element should separate transitions.', 

125 node) 

126 

127 def warn(self, msg, node) -> None: 

128 # create a warning message, insert it if valid 

129 warning = self.document.reporter.warning(msg, base_node=node) 

130 if 'nodes.Body' in repr(node.parent.content_model): 

131 node.parent.insert(node.parent.index(node)+1, warning)