Coverage for pyquickhelper/helpgen/_single_file_html_builder.py: 48%

107 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-03 02:21 +0200

1""" 

2@file 

3@brief Copy of `singlehtml.py <https://github.com/sphinx-doc/sphinx/blob/3.x/sphinx/builders/singlehtml.py>`_ 

4 

5Single HTML builders. 

6 

7:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. 

8:license: BSD, see LICENSE for details. 

9""" 

10 

11from os import path 

12from typing import Any, Dict, Tuple 

13from docutils import nodes 

14from docutils.nodes import Node 

15from sphinx.builders.html import StandaloneHTMLBuilder 

16from sphinx.environment.adapters.toctree import TocTree 

17from sphinx.locale import __ 

18from sphinx.util import logging 

19try: 

20 from sphinx.util.display import progress_message 

21except ImportError: 

22 from sphinx.util import progress_message 

23from sphinx.util.console import darkgreen # type: ignore 

24from sphinx.util.nodes import inline_all_toctrees 

25 

26 

27class CustomSingleFileHTMLBuilder(StandaloneHTMLBuilder): 

28 """ 

29 A StandaloneHTMLBuilder subclass that puts the whole document tree on one 

30 HTML page. 

31 """ 

32 name = 'singlehtml' 

33 epilog = __('The HTML page is in %(outdir)s.') 

34 

35 copysource = False 

36 

37 def get_outdated_docs(self): 

38 return 'all documents' 

39 

40 def get_target_uri(self, docname: str, typ: str = None) -> str: 

41 if docname in self.env.all_docs: 

42 # all references are on the same page... 

43 return self.config.master_doc + self.out_suffix + \ 

44 '#document-' + docname 

45 else: 

46 # chances are this is a html_additional_page 

47 return docname + self.out_suffix 

48 

49 def get_relative_uri(self, from_: str, to: str, typ: str = None) -> str: 

50 # ignore source 

51 return self.get_target_uri(to, typ) 

52 

53 def fix_refuris(self, tree: Node) -> None: 

54 # fix refuris with double anchor 

55 fname = self.config.master_doc + self.out_suffix 

56 for refnode in tree.traverse(nodes.reference): 

57 if 'refuri' not in refnode: 

58 continue 

59 refuri = refnode['refuri'] 

60 hashindex = refuri.find('#') 

61 if hashindex < 0: 

62 continue 

63 hashindex = refuri.find('#', hashindex + 1) 

64 if hashindex >= 0: 

65 refnode['refuri'] = fname + refuri[hashindex:] 

66 

67 def _get_local_toctree(self, docname: str, collapse: bool = True, **kwargs: Any) -> str: 

68 if 'includehidden' not in kwargs: 

69 kwargs['includehidden'] = False 

70 toctree = TocTree(self.env).get_toctree_for( 

71 docname, self, collapse, **kwargs) 

72 if toctree is not None: 

73 self.fix_refuris(toctree) 

74 return self.render_partial(toctree)['fragment'] 

75 

76 def assemble_doctree(self) -> nodes.document: 

77 master = self.config.master_doc 

78 tree = self.env.get_doctree(master) 

79 tree = inline_all_toctrees( 

80 self, set(), master, tree, darkgreen, [master]) 

81 tree['docname'] = master 

82 self.env.resolve_references(tree, master, self) 

83 self.fix_refuris(tree) 

84 return tree 

85 

86 def assemble_toc_secnumbers(self) -> Dict[str, Dict[str, Tuple[int, ...]]]: 

87 # Assemble toc_secnumbers to resolve section numbers on SingleHTML. 

88 # Merge all secnumbers to single secnumber. 

89 # 

90 # Note: current Sphinx has refid confliction in singlehtml mode. 

91 # To avoid the problem, it replaces key of secnumbers to 

92 # tuple of docname and refid. 

93 # 

94 # There are related codes in inline_all_toctres() and 

95 # HTMLTranslter#add_secnumber(). 

96 new_secnumbers = {} # type: Dict[str, Tuple[int, ...]] 

97 for docname, secnums in self.env.toc_secnumbers.items(): 

98 for id, secnum in secnums.items(): 

99 alias = f"{docname}/{id}" 

100 new_secnumbers[alias] = secnum 

101 

102 return {self.config.master_doc: new_secnumbers} 

103 

104 def assemble_toc_fignumbers(self) -> Dict[str, Dict[str, Dict[str, Tuple[int, ...]]]]: 

105 # Assemble toc_fignumbers to resolve figure numbers on SingleHTML. 

106 # Merge all fignumbers to single fignumber. 

107 # 

108 # Note: current Sphinx has refid confliction in singlehtml mode. 

109 # To avoid the problem, it replaces key of secnumbers to 

110 # tuple of docname and refid. 

111 # 

112 # There are related codes in inline_all_toctres() and 

113 # HTMLTranslter#add_fignumber(). 

114 new_fignumbers = {} # type: Dict[str, Dict[str, Tuple[int, ...]]] 

115 # {'foo': {'figure': {'id2': (2,), 'id1': (1,)}}, 'bar': {'figure': {'id1': (3,)}}} 

116 for docname, fignumlist in self.env.toc_fignumbers.items(): 

117 for figtype, fignums in fignumlist.items(): 

118 alias = f"{docname}/{figtype}" 

119 new_fignumbers.setdefault(alias, {}) 

120 for id, fignum in fignums.items(): 

121 new_fignumbers[alias][id] = fignum 

122 

123 return {self.config.master_doc: new_fignumbers} 

124 

125 def get_doc_context(self, docname: str, body: str, metatags: str) -> Dict: 

126 # no relation links... 

127 toctree = TocTree(self.env).get_toctree_for( 

128 self.config.master_doc, self, False) 

129 # if there is no toctree, toc is None 

130 if toctree: 

131 self.fix_refuris(toctree) 

132 toc = self.render_partial(toctree)['fragment'] 

133 display_toc = True 

134 else: 

135 toc = '' 

136 display_toc = False 

137 return { 

138 'parents': [], 

139 'prev': None, 

140 'next': None, 

141 'docstitle': None, 

142 'title': self.config.html_title, 

143 'meta': None, 

144 'body': body, 

145 'metatags': metatags, 

146 'rellinks': [], 

147 'sourcename': '', 

148 'toc': toc, 

149 'display_toc': display_toc, 

150 } 

151 

152 def write(self, *ignored: Any) -> None: # pylint: disable=W0221,W0222 

153 docnames = self.env.all_docs 

154 

155 with progress_message(__('preparing documents')): 

156 self.prepare_writing(docnames) # type: ignore 

157 

158 with progress_message(__('assembling single document')): 

159 doctree = self.assemble_doctree() 

160 self.env.toc_secnumbers = self.assemble_toc_secnumbers() 

161 self.env.toc_fignumbers = self.assemble_toc_fignumbers() 

162 

163 with progress_message(__('writing')): 

164 self.write_doc_serialized(self.config.master_doc, doctree) 

165 self.write_doc(self.config.master_doc, doctree) 

166 

167 def finish(self) -> None: 

168 self.write_additional_files() 

169 self.copy_image_files() 

170 self.copy_download_files() 

171 self.copy_static_files() 

172 self.copy_extra_files() 

173 self.write_buildinfo() 

174 self.dump_inventory() 

175 

176 @progress_message(__('writing additional files')) 

177 def write_additional_files(self) -> None: 

178 # no indices or search pages are supported 

179 logger = logging.getLogger(__name__) 

180 

181 # additional pages from conf.py 

182 for pagename, template in self.config.html_additional_pages.items(): 

183 logger.info(' ' + pagename) 

184 self.handle_page(pagename, {}, template) 

185 

186 if self.config.html_use_opensearch: 

187 logger.info(' opensearch') 

188 fn = path.join(self.outdir, '_static', 'opensearch.xml') 

189 self.handle_page('opensearch', {}, 

190 'opensearch.xml', outfilename=fn)