22import json
33from uuid import uuid4
44import shutil
5- import tempfile
6- from warnings import warn
75import glob
86import re
9- import nbformat as nbf
107
118from pathlib import Path
129
1916from docutils import nodes
2017
2118from sphinx .application import Sphinx
22- from sphinx .ext .doctest import DoctestDirective
2319from sphinx .util .docutils import SphinxDirective
2420from sphinx .util .fileutil import copy_asset
2521from sphinx .parsers import RSTParser
@@ -370,10 +366,7 @@ class TryExamplesDirective(SphinxDirective):
370366 option_spec = {
371367 "theme" : directives .unchanged ,
372368 "button_text" : directives .unchanged ,
373- "button_css" : directives .unchanged ,
374- "button_hover_css" : directives .unchanged ,
375- "button_horizontal_position" : directives .unchanged ,
376- "button_vertical_position" : directives .unchanged ,
369+ "example_class" : directives .unchanged ,
377370 "min_height" : directives .unchanged ,
378371 }
379372
@@ -387,26 +380,9 @@ def run(self):
387380 )
388381
389382 button_text = self .options .pop ("button_text" , "Try it with Jupyterlite!" )
390- button_css = self .options .pop ("button_css" , "" )
391- button_hover_css = self .options .pop ("button_hover_css" , "" )
392- button_horizontal_position = self .options .pop (
393- "button_horizontal_position" , "right"
394- )
395- button_vertical_position = self .options .pop ("button_vertical_position" , "top" )
383+ example_class = self .options .pop ("example_class" , "" )
396384 min_height = self .options .pop ("min_height" , "200px" )
397385
398- if button_horizontal_position not in ["left" , "center" , "right" ]:
399- raise RuntimeError (
400- "try_examples directive expects button_horizontal_position to be one of"
401- f" 'left', 'center', or 'right', received { button_horizontal_position } ."
402- )
403-
404- if button_vertical_position not in ["bottom" , "top" ]:
405- raise RuntimeError (
406- "try_examples directive expects button_vertical_position to be one of"
407- f" 'top' or 'bottom', received { button_vertical_position } ."
408- )
409-
410386 # We need to get the relative path back to the documentation root from
411387 # whichever file the docstring content is in.
412388 docname = self .env .docname
@@ -454,7 +430,7 @@ def run(self):
454430 # Parent container (initially hidden)
455431 iframe_parent_container_div_start = (
456432 f'<div id="{ iframe_parent_div_id } " '
457- f'class="try_examples_outer_container hidden">'
433+ f'class="try_examples_outer_container { example_class } hidden">'
458434 )
459435
460436 iframe_parent_container_div_end = "</div>"
@@ -487,51 +463,19 @@ def run(self):
487463 try_it_button_node = nodes .raw ("" , try_it_button_html , format = "html" )
488464
489465 # Combine everything
490- if button_vertical_position == "top" :
491- notebook_container_html = (
492- iframe_parent_container_div_start
493- + go_back_button_html
494- + iframe_container_div
495- + iframe_parent_container_div_end
496- )
497- content_container_node += try_it_button_node
498- content_container_node += content_node
499- else :
500- notebook_container_html = (
501- iframe_parent_container_div_start
502- + iframe_container_div
503- + go_back_button_html
504- + iframe_parent_container_div_end
505- )
506- content_container_node += content_node
507- content_container_node += try_it_button_node
508-
509- notebook_container = nodes .raw ("" , notebook_container_html , format = "html" )
510-
511- # Generate css for button based on options.
512- if button_css :
513- button_css = f".try_examples_button {{{ button_css } }}"
514- if button_hover_css :
515- button_hover_css = f".try_examples_button:hover {{{ button_hover_css } }}"
516-
517- justify = {"left" : "flex-start" , "center" : "center" , "right" : "flex-end" }[
518- button_horizontal_position
519- ]
520-
521- button_container_css = (
522- ".try_examples_button_container {"
523- f"display: flex; justify-content: { justify } "
524- "}"
466+ notebook_container_html = (
467+ iframe_parent_container_div_start
468+ + go_back_button_html
469+ + iframe_container_div
470+ + iframe_parent_container_div_end
525471 )
472+ content_container_node += try_it_button_node
473+ content_container_node += content_node
526474
527- complete_button_css = button_css + button_hover_css + button_container_css
528-
529- style_tag = nodes .raw (
530- "" , f"<style>{ complete_button_css } </style>" , format = "html"
531- )
475+ notebook_container = nodes .raw ("" , notebook_container_html , format = "html" )
532476
533- # Search cnofig file allowing for config changes without rebuilding docs.
534- config_path = os .path .join (relative_path_to_root , ". try_examples.json" )
477+ # Search config file allowing for config changes without rebuilding docs.
478+ config_path = os .path .join (relative_path_to_root , "try_examples.json" )
535479 script_html = (
536480 "<script>"
537481 'document.addEventListener("DOMContentLoaded", function() {'
@@ -541,7 +485,7 @@ def run(self):
541485 )
542486 script_node = nodes .raw ("" , script_html , format = "html" )
543487
544- return [content_container_node , notebook_container , style_tag , script_node ]
488+ return [content_container_node , notebook_container , script_node ]
545489
546490
547491def _process_docstring_examples (app , docname , source ):
@@ -554,10 +498,7 @@ def _process_autodoc_docstrings(app, what, name, obj, options, lines):
554498 try_examples_options = {
555499 "theme" : app .config .try_examples_global_theme ,
556500 "button_text" : app .config .try_examples_global_button_text ,
557- "button_css" : app .config .try_examples_global_button_css ,
558- "button_hover_css" : app .config .try_examples_global_button_hover_css ,
559- "button_horizontal_position" : app .config .try_examples_global_button_horizontal_position ,
560- "button_vertical_position" : app .config .try_examples_global_button_vertical_position ,
501+ "example_class" : app .config .try_examples_global_example_class ,
561502 "min_height" : app .config .try_examples_global_min_height ,
562503 }
563504 try_examples_options = {
@@ -574,25 +515,6 @@ def conditional_process_examples(app, config):
574515 app .connect ("autodoc-process-docstring" , _process_autodoc_docstrings )
575516
576517
577- def write_try_examples_runtime_config (app , exception ):
578- """Add default runtime configuration file .try_examples.json.
579-
580- These configuration options can be changed in the deployed docs without
581- rebuilding by replacing this file.
582- """
583- if exception is not None :
584- return
585-
586- config = app .config .try_examples_default_runtime_config
587- if config is None :
588- return
589-
590- output_dir = app .outdir
591- config_path = os .path .join (output_dir , ".try_examples.json" )
592- with open (config_path , "w" ) as f :
593- json .dump (config , f , indent = 4 )
594-
595-
596518def inited (app : Sphinx , config ):
597519 # Create the content dir
598520 os .makedirs (os .path .join (app .srcdir , CONTENT_DIR ), exist_ok = True )
@@ -678,9 +600,6 @@ def setup(app):
678600 # We need to build JupyterLite at the end, when all the content was created
679601 app .connect ("build-finished" , jupyterlite_build )
680602
681- # Write default .try_examples.json after build finishes.
682- app .connect ("build-finished" , write_try_examples_runtime_config )
683-
684603 # Config options
685604 app .add_config_value ("jupyterlite_config" , None , rebuild = "html" )
686605 app .add_config_value ("jupyterlite_dir" , app .srcdir , rebuild = "html" )
@@ -689,27 +608,15 @@ def setup(app):
689608
690609 app .add_config_value ("global_enable_try_examples" , default = False , rebuild = True )
691610 app .add_config_value ("try_examples_global_theme" , default = None , rebuild = True )
692- app .add_config_value ("try_examples_global_button_css" , default = None , rebuild = "html" )
693- app .add_config_value (
694- "try_examples_global_button_hover_css" , default = None , rebuild = "html"
695- )
696- app .add_config_value (
697- "try_examples_global_button_horizontal_position" , default = None , rebuild = "html"
698- )
699611 app .add_config_value (
700- "try_examples_global_button_vertical_position " , default = None , rebuild = "html"
612+ "try_examples_global_example_class " , default = None , rebuild = "html"
701613 )
702614 app .add_config_value ("try_examples_global_min_height" , default = None , rebuild = "html" )
703615 app .add_config_value (
704616 "try_examples_global_button_text" ,
705617 default = None ,
706618 rebuild = "html" ,
707619 )
708- app .add_config_value (
709- "try_examples_default_runtime_config" ,
710- default = None ,
711- rebuild = None ,
712- )
713620
714621 # Initialize NotebookLite and JupyterLite directives
715622 app .add_node (
@@ -768,6 +675,11 @@ def setup(app):
768675
769676 app .add_js_file ("jupyterlite_sphinx.js" )
770677
678+ # Copy optional try examples runtime config if it exists.
679+ try_examples_config_path = Path (app .srcdir ) / "try_examples.json"
680+ if try_examples_config_path .exists ():
681+ copy_asset (str (try_examples_config_path ), app .outdir )
682+
771683
772684def search_params_parser (search_params : str ) -> str :
773685 pattern = re .compile (r"^\[(?:\s*[\"']{1}([^=\s\,&=\?\/]+)[\"']{1}\s*\,?)+\]$" )
0 commit comments