Coverage for pyquickhelper/helpgen/default_conf.py: 80%

262 statements  

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

1# -*- coding: utf-8 -*- 

2""" 

3@file 

4@brief Default values for the Sphinx configuration. 

5""" 

6import sys 

7import os 

8import datetime 

9import warnings 

10from .style_css_template import style_figure_notebook 

11from .._cst.cst_sphinx import ( 

12 get_epkg_dictionary, latex_preamble, get_intersphinx_mapping) 

13 

14 

15def set_sphinx_variables(fileconf, module_name, author, year, theme, theme_path, ext_locals, 

16 add_extensions=None, bootswatch_theme="spacelab", bootswatch_navbar_links=None, 

17 description_latex="", use_mathjax=False, use_lunrsearch=False, 

18 enable_disabled_parts="enable_disabled_documented_pieces_of_code", 

19 sharepost="facebook-linkedin-twitter-20-body", custom_style=None, 

20 extlinks=None, github_user=None, github_repo=None, title=None, 

21 book=True, link_resolve=None, nblayout='classic', doc_version=None, 

22 branch='master', callback_begin=None): 

23 """ 

24 Defines variables for :epkg:`Sphinx`. 

25 

26 :param fileconf: location of the configuration file 

27 :param module_name: name of the module 

28 :param author: author 

29 :param year: year 

30 :param theme: theme to use 

31 :param theme_path: theme path (sets ``html_theme_path``) 

32 :param ext_locals: context (see `locals 

33 <https://docs.python.org/3/library/functions.html#locals>`_) 

34 :param add_extensions: additional extensions 

35 :param bootswatch_theme: for example, ``spacelab``, look at 

36 `spacelab <https://bootswatch.com/spacelab/>`_ 

37 :param bootswatch_navbar_links: see `sphinx-bootstrap-theme 

38 <https://ryan-roemer.github.io/sphinx-bootstrap-theme/README.html>`_ 

39 :param description_latex: description latex 

40 :param use_mathjax: set up the documentation to use mathjax, 

41 see `sphinx.ext.mathjax 

42 <https://www.sphinx-doc.org/en/master/usage/extensions/math.html>`_, 

43 default option is True 

44 :param use_lunrsearch: suggest autocompletion in sphinx, 

45 see `sphinxcontrib-lunrsearch <https://github.com/rmcgibbo/ 

46 sphinxcontrib-lunrsearch>`_ 

47 :param enable_disabled_parts: @see fn remove_undesired_part_for_documentation 

48 :param sharepost: add share button to share blog post on usual networks 

49 :param custom_style: custom style sheet 

50 :param extlinks: parameter `extlinks 

51 <https://www.sphinx-doc.org/en/master/ext/extlinks.html#confval-extlinks>`_, 

52 example: ``{'issue': ('https://github.com/sdpython/pyquickhelper/issues/%s', 'issue %s')}`` 

53 :param github_user: git(hub) user 

54 :param github_repo: git(hub) project 

55 :param title: if not None, use *title* instead of *module_name* as a title 

56 :param book: the output is a book 

57 :param link_resolve: url where the documentation is published, 

58 used for parameter *linkcode_resolve* 

59 :param nblayout: ``'classic'`` or ``'table'``, specifies the layout for 

60 the notebook gallery 

61 :param doc_version: if not None, overwrites the current version 

62 :param branch: default branch (`'master'` by default) 

63 :param callback_begin: function to call when the documentation is generated 

64 

65 If the parameter *custom_style* is not None, it will call ``app.add_css_file(custom_style)`` 

66 in the setup. 

67 

68 .. exref:: 

69 :title: Simple configuration file for Sphinx 

70 

71 We assume a module is configurated using the same 

72 structure as `pyquickhelper <https://github.com/sdpython/pyquickhelper/>`_. 

73 The file ``conf.py`` could just contain: 

74 

75 :: 

76 

77 # -*- coding: utf-8 -*- 

78 import sys, os, datetime, re 

79 import solar_theme 

80 from pyquickhelper.helpgen.default_conf import set_sphinx_variables 

81 

82 sys.path.insert(0, os.path.abspath(os.path.join(os.path.split(__file__)[0]))) 

83 set_sphinx_variables(__file__, "pyquickhelper", "Xavier Dupré", 2014, 

84 "solar_theme", solar_theme.theme_path, locals()) 

85 

86 # custom settings 

87 ... 

88 

89 *setup.py* must contain a string such as ``__version__ = 3.4``. 

90 Close to the setup, there must be a file ``version.txt``. 

91 You overwrite a value by giving a variable another value after the fucntion is called. 

92 

93 Some parts of the code can be disabled before generating the documentation. 

94 Those parts are surrounded by:: 

95 

96 # -- HELP BEGIN EXCLUDE -- 

97 import module 

98 # -- HELP END EXCLUDE -- 

99 

100 If *enable_disabled_parts* is set to a string, these sections will become:: 

101 

102 # -- HELP BEGIN EXCLUDE -- 

103 if hasattr(sys, <enable_disabled_parts>) and sys.<enable_disabled_parts>: 

104 import module 

105 # -- HELP END EXCLUDE -- 

106 

107 This example shows what variables this functions sets. 

108 

109 .. runpython:: 

110 :showcode: 

111 

112 import alabaster 

113 from pyquickhelper.helpgen.default_conf import set_sphinx_variables 

114 

115 import pyquickhelper # replace by your module 

116 

117 ext_locals = {} 

118 set_sphinx_variables("this_file_conf.py", 

119 "pyquickhelper", # replace by your module 

120 "module_author", 2019, 

121 "readable", alabaster.get_path(), 

122 ext_locals, extlinks=dict(issue=( 

123 'https://github.com/sdpython/module_name/issues/%s', 

124 'issue %s')), 

125 title="module_name") 

126 

127 import pprint 

128 pprint.pprint(ext_locals) 

129 """ 

130 # sphinx_gallery only supports matplotlib.use('agg') 

131 # and it must be done first. 

132 try: 

133 import sphinx_gallery 

134 import sphinx_gallery.gen_rst 

135 except ImportError: # pragma: no cover 

136 warnings.warn("ImportError: sphinx-gallery.", ImportWarning) 

137 except ValueError: # pragma: no cover 

138 warnings.warn( 

139 "ImportError: sphinx-gallery.get_rst fails.", ImportWarning) 

140 

141 # version .txt 

142 dirconf = os.path.abspath(os.path.dirname(fileconf)) 

143 version_file = os.path.join(dirconf, "..", "..", "..", "version.txt") 

144 if not os.path.exists(version_file): 

145 warnings.warn( # pragma: no cover 

146 "File '{0}' must contain the commit number (or last part of the version).".format( 

147 version_file), UserWarning) 

148 first_line = "0" # pragma: no cover 

149 else: 

150 first_line = get_first_line(version_file) 

151 

152 # language 

153 language = "en" 

154 

155 # main version 

156 if doc_version is None: 

157 mod = sys.modules.get(module_name, None) 

158 if mod is None: # pragma: no cover 

159 import importlib 

160 try: 

161 mod = importlib.import_module(module_name) 

162 except (ImportError, ModuleNotFoundError): 

163 mod = None 

164 if mod is None: 

165 raise RuntimeError( 

166 "Unknown module version. You should import '{0}' or specify " 

167 "'doc_version'.".format( 

168 module_name)) 

169 try: 

170 version = mod.__version__ 

171 except AttributeError: # pragma: no cover 

172 raise AttributeError("Unable to find attribute '__version__' in module '{}', " 

173 "__file__='{}'\n--PATH--\n{}".format( 

174 module_name, mod.__file__, "\n".join(sys.path))) 

175 else: 

176 version = doc_version # pragma: no cover 

177 

178 # settings sphinx 

179 pygments_style = 'sphinx' 

180 

181 # personnalization 

182 project_var_name = module_name # pylint: disable=W0127 

183 author = author # pylint: disable=W0127 

184 nblayout = nblayout # pylint: disable=W0127 

185 year = str(year) 

186 modindex_common_prefix = [project_var_name + ".", ] 

187 project = (project_var_name + ' documentation') if title is None else title 

188 copyright = str(year) + ", " + author 

189 release = (version if len(version.split('.')) < 3 

190 else f"{version}.{first_line}") 

191 html_title = (f"{project_var_name} {release}" 

192 ) if title is None else title 

193 htmlhelp_basename = f'{project_var_name}_doc' 

194 enable_disabled_parts = enable_disabled_parts # pylint: disable=W0127 

195 

196 # personnalization latex 

197 _proj = project_var_name.replace("_", "\\_") 

198 latex_book = book 

199 latex_use_parts = False 

200 latex_documents = [('index', f'{project_var_name}_doc.tex', 

201 _proj if title is None else title, 

202 author, 'manual', True), ] 

203 latex_docclass = dict(manual='report', howto='report') 

204 man_pages = [('index', f'{project_var_name}_doc', 

205 f'{_proj} Documentation' if title is None else title, 

206 [author], 1)] 

207 texinfo_documents = [ 

208 ('index', (f'{_proj} documentation') 

209 if title is None else title, 

210 f'{_proj}' if title is None else title, 

211 author, 

212 f'{_proj} documentation' if title is None else title, 

213 description_latex, 'Miscellaneous')] 

214 latex_show_pagerefs = True 

215 

216 preamble = latex_preamble() 

217 latex_elements = { 

218 'papersize': 'a4', 

219 'pointsize': '10pt', 

220 'preamble': preamble, 

221 'docclass': 'book', 

222 'title': title} 

223 

224 # pyquickhelper automation 

225 auto_rst_generation = True 

226 

227 # latex_additional_files = ["mfgan-bw.sty", "_static/cover.png"] 

228 

229 # figure 

230 numfig = False 

231 

232 # theme 

233 html_theme = theme 

234 shtml_theme_options = {"bodyfont": "Calibri"} 

235 if theme_path is not None: 

236 if isinstance(theme_path, list): 

237 html_theme_path = theme_path # pragma: no cover 

238 else: 

239 html_theme_path = [theme_path] 

240 

241 # static files 

242 html_static_path = ['_static'] 

243 templates_path = ['phdoc_templates'] 

244 html_logo = os.path.join(html_static_path[0], "project_ico.png") 

245 html_favicon = os.path.join(html_static_path[0], "project_ico.ico") 

246 

247 # extensions, encoding 

248 source_suffix = '.rst' 

249 source_encoding = 'utf-8' 

250 master_doc = 'index' 

251 html_output_encoding = 'utf-8' 

252 

253 # blogs (custom parameter) 

254 blog_background = True 

255 blog_background_page = False 

256 sharepost = sharepost # pylint: disable=W0127 

257 

258 # jupyter_sphinx 

259 # See https://thebelab.readthedocs.io/en/latest/config_reference.html 

260 if github_user: 

261 jupyter_sphinx_thebelab_config = { # pragma: no cover 

262 'requestKernel': True, 

263 'binderOptions': { 

264 'repo': f"sdpython/pyquickhelper/{branch}?filepath=_doc" 

265 # 'repo': "{0}/{1}/master?filepath=_doc%2Fnotebooks".format( 

266 # github_user, module_name) 

267 }} 

268 else: 

269 jupyter_sphinx_thebelab_config = {'requestKernel': True} 

270 

271 # settings 

272 exclude_patterns = ["*.py", "**/*.py"] 

273 html_show_sphinx = False 

274 html_show_copyright = False 

275 __html_last_updated_fmt_dt = datetime.datetime.now() 

276 html_last_updated_fmt = '%04d-%02d-%02d' % ( 

277 __html_last_updated_fmt_dt.year, 

278 __html_last_updated_fmt_dt.month, 

279 __html_last_updated_fmt_dt.day) 

280 autoclass_content = 'both' 

281 autosummary_generate = True 

282 

283 # import helpers to find tools to build the documentation 

284 from .conf_path_tools import find_graphviz_dot, find_dvipng_path 

285 

286 # graphviz 

287 graphviz_output_format = "svg" 

288 graphviz_dot = find_graphviz_dot() 

289 

290 # todo, mathdef, blocref, faqref, exref, nbref 

291 todo_include_todos = True 

292 todoext_include_todosext = True 

293 mathdef_include_mathsext = True 

294 blocref_include_blocrefs = True 

295 faqref_include_faqrefs = True 

296 exref_include_exrefs = True 

297 nbref_include_nbrefs = True 

298 mathdef_link_number = "{first_letter}{number}" 

299 

300 # extensions 

301 extensions = [] 

302 try: 

303 import sphinx_gallery 

304 extensions.append('sphinx_gallery.gen_gallery') 

305 has_sphinx_gallery = True 

306 except ImportError: # pragma: no cover 

307 has_sphinx_gallery = False 

308 

309 if has_sphinx_gallery: 

310 try: 

311 import sphinx_gallery.gen_rst 

312 except ValueError as e: # pragma: no cover 

313 raise ValueError(f"Issue with sphinx-gallery.\n{e}") 

314 

315 extensions.extend([ 

316 'sphinx.ext.autodoc', 

317 'sphinx.ext.autosummary', 

318 'sphinx.ext.coverage', 

319 'sphinx.ext.extlinks', 

320 'sphinx.ext.graphviz', 

321 'sphinx.ext.ifconfig', 

322 'sphinx.ext.inheritance_diagram', 

323 'sphinx.ext.intersphinx', 

324 'sphinx.ext.mathjax' if use_mathjax else 'sphinx.ext.imgmath', 

325 'sphinx.ext.todo', 

326 'jupyter_sphinx.execute', 

327 'pyquickhelper.sphinxext.sphinx_rst_builder', 

328 'pyquickhelper.sphinxext.sphinx_md_builder', 

329 'pyquickhelper.sphinxext.sphinx_latex_builder']) 

330 

331 try: 

332 import matplotlib.sphinxext 

333 assert matplotlib.sphinxext is not None 

334 extensions.append('matplotlib.sphinxext.plot_directive') 

335 plot_include_source = True 

336 plot_html_show_source_link = False 

337 except ImportError: # pragma: no cover 

338 # matplotlib is not installed. 

339 pass 

340 

341 if use_lunrsearch: # pragma: no cover 

342 extensions.append('sphinxcontrib.lunrsearch') 

343 

344 if not use_mathjax: 

345 # extensions.append('matplotlib.sphinxext.mathmpl') 

346 # this extension disables sphinx.ext.imgmath 

347 pass 

348 

349 if not use_mathjax: # pragma: no cover 

350 imgmath_latex, imgmath_dvipng, imgmath_dvisvgm = find_dvipng_path() 

351 imgmath_image_format = 'svg' 

352 imgmath_embed = True 

353 

354 if add_extensions is not None: # pragma: no cover 

355 for a in add_extensions: 

356 if a not in extensions: 

357 extensions.append(a) 

358 

359 # add_function_parentheses = True 

360 # add_module_names = True 

361 # show_authors = False 

362 # html_sidebars = {} 

363 # html_additional_pages = {} 

364 # html_domain_indices = True 

365 # html_use_index = True 

366 # html_split_index = False 

367 # html_show_sourcelink = True 

368 # html_use_opensearch = '' 

369 # html_file_suffix = None 

370 # latex_logo = None 

371 latex_show_urls = 'footnote' 

372 # latex_appendices = [] 

373 # latex_domain_indices = True 

374 # texinfo_appendices = [] 

375 # texinfo_domain_indices = True 

376 # texinfo_show_urls = 'footnote' 

377 

378 # it modifies the set of things to display inside the sidebar 

379 # see https://www.sphinx-doc.org/en/master/config.html#confval-html_sidebars 

380 html_sidebars = { 

381 '[!blog]**': ['searchbox.html', 'moduletoc.html', 

382 'relations.html', 'sourcelink.html', ], 

383 'blog/**': ['searchbox.html', 'blogtoc.html', 

384 'localtoc.html', 'sourcelink.html', ], 

385 } 

386 

387 # tpl_role 

388 from ..sphinxext.documentation_link import python_link_doc 

389 tpl_template = {'py': python_link_doc} 

390 

391 # epkg_role 

392 epkg_dictionary = get_epkg_dictionary() 

393 

394 # latex 

395 math_number_all = False 

396 imgmath_latex_preamble = """ 

397 %% addition by pyquickhelper(2) %% 

398 \\usepackage{epic} 

399 \\newcommand{\\acc}[1]{\\left\\{#1\\right\\}} 

400 \\newcommand{\\cro}[1]{\\left[#1\\right]} 

401 \\newcommand{\\pa}[1]{\\left(#1\\right)} 

402 \\newcommand{\\R}{\\mathbb{R}} 

403 %% addition by pyquickhelper(2) %% 

404 """.replace(" ", "") 

405 # post processing of the full latex file 

406 # it should be a function, None by default 

407 custom_latex_processing = None 

408 

409 # github or git link 

410 if github_user: 

411 releases_issue_uri = "https://github.com/{0}/{1}/issues/%s".format( 

412 github_user, module_name) 

413 githublink_options = dict(user=github_user) 

414 github_anchor = "source on GitHub" 

415 else: 

416 githublink_options = None 

417 if github_repo: 

418 if githublink_options is None: 

419 githublink_options = {} 

420 value = github_repo.strip("/").split("/")[-1] 

421 if value.endswith(".git"): 

422 value = value[:-4] 

423 githublink_options['project'] = value 

424 

425 if 'anchor' not in githublink_options and "github" in github_repo.lower(): 

426 githublink_options['anchor'] = "source on GitHub" 

427 

428 if extlinks is None: 

429 extlinks = dict() 

430 elif 'issue' in extlinks: 

431 issue = extlinks['issue'][0].split('/') 

432 le = len(issue) 

433 if le > 0: 

434 user = issue[-4] 

435 project = issue[-3] 

436 if githublink_options is None: 

437 githublink_options = {} 

438 if 'user' not in githublink_options: 

439 githublink_options["user"] = user 

440 if 'project' not in githublink_options: 

441 githublink_options["project"] = project 

442 if 'anchor' not in githublink_options and 'github' in extlinks['issue'][0].lower(): 

443 githublink_options["anchor"] = 'source on GitHub' 

444 if not github_repo and extlinks['issue'][0].startswith("https://github.com"): 

445 github_repo = f"https://github.com/{user}/{project}.git" 

446 

447 # themes 

448 if html_theme == "bootstrap": # pragma: no cover 

449 if bootswatch_navbar_links is None: 

450 bootswatch_navbar_links = [] 

451 html_logo = "project_ico_small.png" 

452 navbar_links = bootswatch_navbar_links 

453 html_theme_options = { 

454 'navbar_title': "home", 

455 'navbar_site_name': "Site", 

456 'navbar_links': navbar_links, 

457 'navbar_sidebarrel': True, 

458 'navbar_pagenav': True, 

459 'navbar_pagenav_name': "Page", 

460 'globaltoc_depth': 3, 

461 'globaltoc_includehidden': "true", 

462 'navbar_class': "navbar navbar-inverse", 

463 'navbar_fixed_top': "true", 

464 'source_link_position': "footer", 

465 'bootswatch_theme': bootswatch_theme, 

466 'bootstrap_version': "3", 

467 } 

468 elif html_theme == "guzzle_sphinx_theme": # pragma: no cover 

469 html_translator_class = 'guzzle_sphinx_theme.HTMLTranslator' 

470 if "guzzle_sphinx_theme" not in extensions: 

471 extensions.append('guzzle_sphinx_theme') 

472 html_theme_options = { 

473 "project_nav_name": module_name, 

474 # specified, then no sitemap will be built. 

475 # "base_url": "" 

476 # "homepage": "index", 

477 # "projectlink": "https://myproject.url", 

478 } 

479 elif html_theme == "foundation_sphinx_theme": # pragma: no cover 

480 import foundation_sphinx_theme # pylint: disable=E0401 

481 html_theme_path = foundation_sphinx_theme.HTML_THEME_PATH 

482 if "foundation_sphinx_theme" not in extensions: 

483 extensions.append('foundation_sphinx_theme') 

484 html_theme_options = { 

485 'logo_screen': 'project_ico.png', 

486 'logo_mobile': 'project_ico.ico', 

487 'favicon': 'project_ico.ico', 

488 'github_user': github_user, 

489 'github_repo': github_repo, 

490 } 

491 pygments_style = 'monokai' 

492 elif html_theme == "pydata_sphinx_theme": # pragma: no cover 

493 import pydata_sphinx_theme # pylint: disable=E0401 

494 html_theme_options = { 

495 "github_user": github_user, 

496 "github_repo": github_repo, 

497 "github_version": branch, 

498 "collapse_navigation": True, 

499 "show_nav_level": 2, 

500 "logo": { 

501 "text": project_var_name, 

502 "image_light": html_favicon, 

503 "image_dark": html_favicon, 

504 "alt_text": project_var_name, 

505 }, 

506 } 

507 

508 # mapping 

509 

510 intersphinx_mapping = get_intersphinx_mapping() 

511 

512 # information about code 

513 def linkcode_resolve_function(domain, info): 

514 if link_resolve is None: 

515 return None 

516 if domain != 'py': 

517 return None 

518 if not info['module']: 

519 return None 

520 filename = info['module'].replace('.', '/') 

521 return f"{link_resolve}/{filename}.py" 

522 

523 if link_resolve is not None: 

524 linkcode_resolve = linkcode_resolve_function 

525 extensions.append("sphinx.ext.linkcode") 

526 

527 # commit modification 

528 def modify_commit_function(nbch, date, author, comment): 

529 if author is not None and "@" in author: 

530 author = author.split("@")[0] 

531 return nbch, date, author, comment 

532 

533 modify_commit = modify_commit_function 

534 

535 # sphinx gallery 

536 backreferences_dir = "modules/generated" 

537 dirname = os.path.dirname(fileconf) 

538 exa = os.path.join(dirname, "..", "..", "..", "_doc", "examples") 

539 if os.path.exists(exa): 

540 exa = os.path.normpath(exa) 

541 import pathlib 

542 pp = pathlib.Path(exa) 

543 readmes = pp.glob("**/README.txt") 

544 examples_dirs = [] 

545 gallery_dirs = [] 

546 for res in readmes: 

547 if not has_sphinx_gallery: 

548 raise ImportError( # pragma: no cover 

549 f"sphinx_gallery is not present for gallery '{exa}'") 

550 last = res.parts[-2] 

551 if last.startswith("temp_"): 

552 continue # pragma: no cover 

553 parts = last.replace("\\", "/").split("/") 

554 if any(filter(lambda x: x.startswith("temp_"), parts)): 

555 continue # pragma: no cover 

556 nn = res.parent 

557 

558 # We check that a readme.txt is not present in the parent folder. 

559 nn_parent_read = os.path.join(os.path.split(nn)[0], "README.txt") 

560 if os.path.exists(nn_parent_read): 

561 continue # pragma: no cover 

562 

563 # Main gallery. 

564 examples_dirs.append(str(nn)) 

565 if last in ("notebooks", "examples"): 

566 last = "gy" + last 

567 dest = os.path.join(dirname, last) 

568 if dest in gallery_dirs: 

569 raise ValueError( # pragma: no cover 

570 f"Gallery '{dest}' already exists (source='{nn}', last={last}).") 

571 gallery_dirs.append(dest) 

572 if len(examples_dirs) == 0: 

573 raise ValueError( # pragma: no cover 

574 f"Unable to find any 'README.txt' in '{exa}'.") 

575 reference_url = {k: v[0] for k, v in intersphinx_mapping.items()} 

576 example_dir = os.path.join(dirname, "gallery") 

577 if not os.path.exists(example_dir): 

578 os.makedirs(example_dir) 

579 sphinx_gallery_conf = { 

580 'doc_module': (module_name), 

581 'examples_dirs': examples_dirs, 

582 'gallery_dirs': gallery_dirs, 

583 'backreferences_dir': example_dir, 

584 'expected_failing_examples': [], 

585 'capture_repr': ('_repr_html_', '__repr__'), 

586 'ignore_repr_types': r'matplotlib[text, axes]', 

587 'inspect_global_variables': False, 

588 'remove_config_comments': True, 

589 } 

590 

591 if github_repo is not None and github_user is not None: 

592 sphinx_gallery_conf['binder'] = { 

593 'org': github_user, 

594 'repo': github_repo, 

595 'binderhub_url': 'https://mybinder.org', 

596 'branch': branch, 

597 'dependencies': os.path.abspath( 

598 os.path.join(os.path.dirname(version_file), 'requirements.txt')), 

599 'use_jupyter_lab': True, 

600 } 

601 

602 sphinx_gallery_conf['show_memory'] = False 

603 else: 

604 skipset = {"sphinx_gallery.gen_gallery"} 

605 extensions = [_ for _ in extensions if _ not in skipset] 

606 

607 # notebooks replacements (post-process) 

608 notebook_replacements = {'html': [('\\mathbb{1}_', '\\mathbf{1\\!\\!1}_')]} 

609 

610 # notebooks snippets 

611 notebook_custom_snippet_folder = 'notebooks_snippets' 

612 

613 ########################### 

614 # collect local variables 

615 ########################### 

616 # do not add anything after this 

617 loc = locals() 

618 for k, v in loc.items(): 

619 if not k.startswith("_") and k not in {'app', 'ext_locals', 'domains'}: 

620 ext_locals[k] = v 

621 

622 if custom_style is not None: # pragma: no cover 

623 ex = False 

624 for st in html_static_path: 

625 full = os.path.join(dirconf, st, custom_style) 

626 if os.path.exists(full): 

627 ex = True 

628 break 

629 if not ex: 

630 raise FileNotFoundError("unable to find {0} in\n{1}\nand\n{2}".format( 

631 custom_style, dirconf, "\n".join(html_static_path))) 

632 

633 def this_setup(app): # pragma: no cover 

634 if custom_style is not None: 

635 app.add_css_file(custom_style) 

636 if callback_begin is not None: 

637 callback_begin() 

638 return custom_setup(app, author) 

639 

640 ext_locals["setup"] = this_setup 

641 

642 

643################# 

644# custom functions 

645################# 

646 

647 

648def get_first_line(filename): 

649 """ 

650 Expects to find a text file with a line, 

651 the function extracts and returns this line. 

652 """ 

653 try: 

654 with open(filename, "r") as ff: 

655 first_line = ff.readlines()[0].strip(" \n\r") 

656 except FileNotFoundError: # pragma: no cover 

657 first_line = "xxx" 

658 return first_line 

659 

660 

661################# 

662# sphinx functions 

663################# 

664 

665 

666def _skip(app, what, name, obj, skip, options): 

667 """ 

668 To skip some functions, 

669 see `Skipping members 

670 <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html>`_. 

671 """ 

672 if name.startswith("_") and name not in \ 

673 ["__qualname__", 

674 "__module__", 

675 "__dict__", 

676 "__doc__", 

677 "__weakref__", 

678 ]: 

679 return False 

680 return skip 

681 

682 

683def custom_setup(app, author): 

684 """ 

685 See `Sphinx core events <https://www.sphinx-doc.org/en/master/#sphinx-core-events>`_. 

686 """ 

687 from ..sphinxext.sphinx_bigger_extension import setup as setup_bigger 

688 from ..sphinxext.sphinx_githublink_extension import setup as setup_githublink 

689 from ..sphinxext.sphinx_blog_extension import setup as setup_blogpost 

690 from ..sphinxext.sphinx_blocref_extension import setup as setup_blocref 

691 from ..sphinxext.sphinx_exref_extension import setup as setup_exref 

692 from ..sphinxext.sphinx_faqref_extension import setup as setup_faqref 

693 from ..sphinxext.sphinx_gitlog_extension import setup as setup_gitlog 

694 from ..sphinxext.sphinx_mathdef_extension import setup as setup_mathdef 

695 from ..sphinxext.sphinx_quote_extension import setup as setup_quote 

696 from ..sphinxext.sphinx_nbref_extension import setup as setup_nbref 

697 from ..sphinxext.sphinx_runpython_extension import setup as setup_runpython 

698 from ..sphinxext.sphinx_downloadlink_extension import setup as setup_downloadlink 

699 from ..sphinxext.sphinx_video_extension import setup as setup_video 

700 from ..sphinxext.sphinx_image_extension import setup as setup_simpleimage 

701 from ..sphinxext.sphinx_todoext_extension import setup as setup_todoext 

702 from ..sphinxext.sphinx_docassert_extension import setup as setup_docassert 

703 from ..sphinxext.sphinx_autosignature import setup as setup_signature 

704 from ..sphinxext.sphinx_template_extension import setup as setup_tpl 

705 from ..sphinxext.sphinx_cmdref_extension import setup as setup_cmdref 

706 from ..sphinxext.sphinx_postcontents_extension import setup as setup_postcontents 

707 from ..sphinxext.sphinx_tocdelay_extension import setup as setup_tocdelay 

708 from ..sphinxext.sphinx_sharenet_extension import setup as setup_sharenet 

709 from ..sphinxext.sphinx_youtube_extension import setup as setup_youtube 

710 from ..sphinxext.sphinx_epkg_extension import setup as setup_epkg 

711 from ..sphinxext import setup_image 

712 from ..sphinxext.sphinx_toctree_extension import setup as setup_toctree 

713 from ..sphinxext.sphinx_collapse_extension import setup as setup_collapse 

714 from ..sphinxext.sphinx_gdot_extension import setup as setup_gdot 

715 

716 # delayed import to speed up import time 

717 from sphinx.errors import ExtensionError 

718 from sphinx.extension import Extension 

719 

720 try: 

721 app.connect("autodoc-skip-member", _skip) 

722 except ExtensionError as e: # pragma: no cover 

723 # No event autodoc-skip-member. 

724 warnings.warn(f"Sphinx extension error {e}", RuntimeError) 

725 if 'author' not in app.config.values: 

726 app.add_config_value('author', author, True) 

727 

728 exts = [setup_toctree, setup_runpython, setup_bigger, 

729 setup_githublink, setup_sharenet, setup_video, 

730 setup_simpleimage, setup_todoext, setup_blogpost, 

731 setup_mathdef, setup_blocref, setup_exref, 

732 setup_faqref, setup_nbref, setup_cmdref, 

733 setup_signature, setup_docassert, setup_postcontents, 

734 setup_tocdelay, setup_youtube, setup_tpl, 

735 setup_epkg, setup_image, setup_collapse, setup_gdot, 

736 setup_downloadlink, setup_quote, setup_gitlog] 

737 

738 for ext in exts: 

739 meta = ext(app) 

740 name = ext.__name__.rsplit('.', maxsplit=1)[-1].replace("setup_", "") 

741 if name == "image": 

742 name = "pyquickhelper.sphinxext.sphinximages.sphinxtrib.images" 

743 else: 

744 name = f'pyquickhelper.sphinxext.sphinx_{name}_extension' 

745 app.extensions[name] = Extension(name, ext.__module__, **meta) 

746 

747 # from sphinx.util.texescape import tex_replacements 

748 # tex_replacements += [('oe', '\\oe '), ] 

749 app.add_js_file("require.js") 

750 

751 # style for notebooks 

752 app.add_css_file(style_figure_notebook[0]) 

753 return app 

754 

755 

756def get_default_stylesheet(css=None): 

757 """ 

758 Returns the style of additional style sheets. 

759 

760 @param css additional css files 

761 @return list of files 

762 """ 

763 # delayed import to speed up time 

764 from sphinx.builders.html import Stylesheet 

765 rel = "_static/" + style_figure_notebook[0] 

766 res = [Stylesheet(rel="stylesheet", filename=rel)] 

767 if css is not None: 

768 for cs in css: 

769 res.append(Stylesheet(rel="stylesheet", filename=cs)) 

770 return res 

771 

772 

773def get_default_javascript(): 

774 """ 

775 Returns the style of additional style sheets 

776 

777 @return list of files 

778 """ 

779 return ["_static/require.js"]