├── .github └── workflows │ └── build.yml ├── .gitignore ├── MANIFEST.in ├── README.rst ├── docs ├── 404.md ├── CNAME ├── Gemfile ├── _config.yml ├── _layouts │ └── default.html ├── favicon.ico ├── index.md ├── jupinx-logo.png ├── site.css ├── sphinx │ ├── Makefile │ ├── _static │ │ └── theme_overrides.css │ ├── conf.py │ ├── index.rst │ ├── jupinx.rst │ ├── quickstart.rst │ └── sphinxcontrib-jupyter.rst ├── tutorial.md └── windows.md ├── environment.yml ├── jupinx ├── __init__.py ├── cmd │ ├── __init__.py │ ├── build.py │ └── quickstart.py ├── templates │ └── quickstart │ │ ├── Makefile_t │ │ ├── _static │ │ └── fill_demo1.png │ │ ├── conf.py_t │ │ ├── demo_notebook.rst_t │ │ └── master_doc.rst_t ├── theme │ └── minimal │ │ ├── README.md │ │ ├── static │ │ ├── css │ │ │ └── base.css │ │ ├── img │ │ │ └── code-block-fade.png │ │ └── js │ │ │ └── base.js │ │ └── templates │ │ ├── error_report_template.html │ │ ├── html.tpl │ │ └── latex.tpl └── util │ ├── __init__.py │ └── template.py └── setup.py /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [pull_request] 3 | jobs: 4 | build-cache: 5 | name: Build lecture-python-programming 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout 9 | uses: actions/checkout@v2 10 | - name: Setup Anaconda 11 | uses: goanpeca/setup-miniconda@v1 12 | with: 13 | auto-update-conda: true 14 | auto-activate-base: true 15 | miniconda-version: 'latest' 16 | python-version: 3.7 17 | environment-file: environment.yml 18 | activate-environment: test-build 19 | # Useful for tests of mster branch of sphinxcontrib-jupyter 20 | # - name: Checkout sphinxcontrib-jupyter (master) 21 | # uses: actions/checkout@v2 22 | # with: 23 | # repository: QuantEcon/sphinxcontrib-jupyter 24 | # path: ./sphinxcontrib-jupyter 25 | # - name: Install sphinxcontrib-jupyter and remove 26 | # shell: bash -l {0} 27 | # run: | 28 | # cd sphinxcontrib-jupyter 29 | # python setup.py install 30 | # cd ../ && rm -rf sphinxcontrib-jupyter 31 | - name: Install Jupinx 32 | shell: bash -l {0} 33 | run: python setup.py install 34 | - name: Checkout lecture-python-programming 35 | uses: actions/checkout@v2 36 | with: 37 | repository: QuantEcon/lecture-python-programming 38 | path: ./ 39 | - name: Build Coverage 40 | shell: bash -l {0} 41 | run: | 42 | jupinx -t 43 | - name: Build Website 44 | shell: bash -l {0} 45 | run: | 46 | jupinx -w 47 | ls _build/website/jupyter_html/* -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache/ 2 | .idea 3 | Jupinx.egg-info/ 4 | build/ 5 | dist/ 6 | 7 | docs/sphinx/_build/ 8 | docs/_site 9 | docs/Gemfile.lock 10 | 11 | jupinx/cmd/__pycache__/ 12 | jupinx/util/__pycache__/ 13 | jupinx/__pycache__/ 14 | 15 | .DS_Store -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | recursive-include jupinx/templates * 3 | recursive-include jupinx/theme * -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | jupinx 2 | ====== 3 | 4 | Jupyter + Sphinx Utilities and Tools 5 | 6 | Documentation and a Tutorial is available: https://jupinx.quantecon.org 7 | 8 | .. |status-docs| image:: https://readthedocs.org/projects/jupinx/badge/?version=latest 9 | :target: http://jupinx.readthedocs.io/en/latest/?badge=latest 10 | :alt: Documentation Status 11 | 12 | +---------------+ 13 | | |status-docs| | 14 | +---------------+ 15 | 16 | This software has been adapted from the sphinx documentation tools - http://www.sphinx-doc.org/ 17 | -------------------------------------------------------------------------------- /docs/404.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: /404.html 4 | --- 5 | 6 | # 404 7 | Page not found :( 8 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | jupinx.quantecon.org -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'github-pages', group: :jekyll_plugins -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/jupinx/b23b0b2dce576e07ee2345e840b5b09b21c54edc/docs/_config.yml -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | Jupinx 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | {% if page.permalink == '/' %} 49 | 50 | {% else %} 51 | 52 | {% endif %} 53 | 54 | 55 |

Jupinx

56 | 57 |
58 | 59 | 60 | 61 |
62 | 63 | 96 | 97 | 102 | 103 |
104 | 105 |
106 | 107 |
108 | 109 |
110 | 111 |
112 | 113 | 114 | 115 |

Welcome to Jupinx, a build system for lectures.

116 | 117 |

Jupinx is an open source tool for converting ReStructuredText 118 | source files into a website via Jupyter Notebooks.

119 | 120 |

For one example of Jupinx in action, see these lectures.

121 | 122 |
123 | 124 | 137 | 138 |
139 | 140 |
141 | 142 |
143 | 144 |
145 | 146 |
147 | 148 | {{ content }} 149 | 150 |
151 | 152 |
153 | 154 |
155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/jupinx/b23b0b2dce576e07ee2345e840b5b09b21c54edc/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: / 3 | layout: default 4 | permalink: / 5 | --- 6 | 7 | * * * 8 | 9 | 10 | # Installation 11 | 12 | To install `Jupinx`, open a terminal and type 13 | 14 | ```bash 15 | pip install jupinx 16 | ``` 17 | 18 | To upgrade your current installation to the latest version, use 19 | 20 | ```bash 21 | pip install jupinx --upgrade 22 | ``` 23 | 24 | # Common Commands 25 | 26 | 27 | Convert RST files in `source_directory` into notebooks: 28 | 29 | 30 | ```bash 31 | jupinx -n 32 | ``` 33 | 34 | View the results using Jupter Notebooks: 35 | 36 | ```bash 37 | jupinx -j 38 | ``` 39 | 40 | Convert RST files into a website: 41 | 42 | ```bash 43 | jupinx -w 44 | ``` 45 | 46 | View the generated website: 47 | 48 | ```bash 49 | jupinx -s 50 | ``` 51 | 52 | Convert RST files into pdf files: 53 | 54 | ```bash 55 | jupinx -p 56 | ``` 57 | 58 | Get help: 59 | 60 | ```bash 61 | jupinx --help 62 | ``` 63 | 64 | More details can be found in the [tutorial](tutorial.md) and the [documentation](https://jupinx.readthedocs.io/). 65 | 66 | -------------------------------------------------------------------------------- /docs/jupinx-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/jupinx/b23b0b2dce576e07ee2345e840b5b09b21c54edc/docs/jupinx-logo.png -------------------------------------------------------------------------------- /docs/site.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} 2 | 3 | /*! HTML5 Boilerplate v7.2.0 | MIT License | https://html5boilerplate.com/ */html{color:#222;font-size:1em;line-height:1.4}::-moz-selection{background:#b3d4fc;text-shadow:none}::selection{background:#b3d4fc;text-shadow:none}hr{display:block;height:1px;border:0;border-top:1px solid #ccc;margin:1em 0;padding:0}audio,canvas,iframe,img,svg,video{vertical-align:middle}fieldset{border:0;margin:0;padding:0}textarea{resize:vertical} 4 | 5 | body { 6 | font-family: 'Quicksand', sans-serif; 7 | color: #444; 8 | background-color: rgba(255, 207, 61, 0.07); 9 | text-rendering: optimizeLegibility; 10 | -webkit-font-smoothing: antialiased; 11 | } 12 | 13 | a { 14 | color: #d8655e; 15 | font-weight: 700; 16 | text-decoration: none; 17 | transition: all .25s linear; 18 | } 19 | 20 | a:hover { 21 | color:#a04a45; 22 | } 23 | 24 | pre { 25 | padding: 0.5rem 1rem; 26 | background-color: rgba(255, 207, 61, 0.07); 27 | border: 1px solid rgba(255, 207, 61, 0.3); 28 | font-size: 0.9rem; 29 | overflow-x: auto; 30 | white-space: pre; 31 | word-wrap: normal; 32 | } 33 | 34 | img { 35 | max-width: 100%; 36 | } 37 | 38 | .button { 39 | display: block; 40 | background-color: #d8655e; 41 | font-size: 0.9rem; 42 | padding: 0.25rem 1rem; 43 | color: #fff; 44 | border-radius: .25rem; 45 | border: 1px solid rgba(0,0,0,.2); 46 | text-decoration: none; 47 | transition: all .15s ease-in; 48 | } 49 | 50 | .button:hover { 51 | color:#fff; 52 | background-color: #a04a45; 53 | } 54 | 55 | .wrapper { 56 | max-width:960px; 57 | margin:0 auto; 58 | padding:2rem 4rem; 59 | } 60 | 61 | .header { 62 | text-align: center; 63 | } 64 | 65 | .header .wrapper { 66 | padding:1rem 4rem; 67 | } 68 | 69 | .home .header .wrapper { 70 | padding: 2rem 4rem; 71 | } 72 | 73 | .header-branding { 74 | 75 | } 76 | 77 | .header-logo img { 78 | max-width: 350px; 79 | } 80 | 81 | .home .header-logo img { 82 | max-width: none; 83 | } 84 | 85 | .header-tagline { 86 | font-size: 1.4rem; 87 | color: #7a7a7a; 88 | } 89 | 90 | .header-description { 91 | display: none; 92 | } 93 | 94 | .home .header-description { 95 | display: block; 96 | } 97 | 98 | .header-links { 99 | margin: 2rem 0 0 0; 100 | } 101 | 102 | .header-links ul { 103 | margin:0; 104 | padding:0; 105 | list-style: none; 106 | text-align: center; 107 | } 108 | 109 | .header-links ul li { 110 | margin:0 0.5rem 1rem 0.5rem; 111 | display: inline-block; 112 | min-width: 150px; 113 | } 114 | 115 | .header-links ul li.active a { 116 | color:#fff; 117 | background-color: #a04a45; 118 | cursor: default; 119 | } 120 | 121 | .section h1 { 122 | text-align: center; 123 | font-size: 2.5rem; 124 | margin: 1rem 0 4rem 0; 125 | color: #d8655e; 126 | } 127 | 128 | .section h2 { 129 | text-align: center; 130 | font-size: 2rem; 131 | font-weight: normal; 132 | color: #d8655e; 133 | } 134 | 135 | @media (max-width: 1023px) { 136 | .wrapper { 137 | padding: 2rem 2rem; 138 | } 139 | .header .wrapper { 140 | display: block; 141 | } 142 | .header-branding { 143 | width:auto; 144 | text-align: center; 145 | } 146 | .header-logo { 147 | left:0; 148 | } 149 | .header-links { 150 | width:auto; 151 | justify-content: space-around; 152 | } 153 | .header-links ul { 154 | display: block; 155 | text-align: center; 156 | } 157 | .header-links ul li { 158 | margin:1rem 1rem; 159 | } 160 | } 161 | 162 | /*Helper classes*/.hidden{display:none!important}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.sr-only.focusable:active,.sr-only.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;white-space:inherit;width:auto}.invisible{visibility:hidden}.clearfix:after,.clearfix:before{content:" ";display:table}.clearfix:after{clear:both}@media print{*,:after,:before{background:0 0!important;color:#000!important;-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}} 163 | -------------------------------------------------------------------------------- /docs/sphinx/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = jupinx 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/sphinx/_static/theme_overrides.css: -------------------------------------------------------------------------------- 1 | /* override table width restrictions */ 2 | @media screen and (min-width: 767px) { 3 | 4 | .wy-table-responsive table td { 5 | /* !important prevents the common CSS stylesheets from overriding 6 | this as on RTD they are loaded after this stylesheet */ 7 | white-space: normal !important; 8 | } 9 | 10 | .wy-table-responsive { 11 | overflow: visible !important; 12 | } 13 | } -------------------------------------------------------------------------------- /docs/sphinx/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # jupinx documentation build configuration file, created by 5 | # sphinx-quickstart 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | # 20 | # import os 21 | # import sys 22 | # sys.path.insert(0, os.path.abspath('.')) 23 | 24 | 25 | # -- General configuration ------------------------------------------------ 26 | 27 | # If your documentation needs a minimal Sphinx version, state it here. 28 | # 29 | # needs_sphinx = '1.0' 30 | 31 | # Add any Sphinx extension module names here, as strings. They can be 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 33 | # ones. 34 | extensions = ['sphinx.ext.autodoc', 35 | 'sphinx.ext.todo', 36 | 'sphinx.ext.mathjax'] 37 | 38 | # Add any paths that contain templates here, relative to this directory. 39 | templates_path = ['_templates'] 40 | 41 | # The suffix(es) of source filenames. 42 | # You can specify multiple suffix as a list of string: 43 | # 44 | # source_suffix = ['.rst', '.md'] 45 | source_suffix = '.rst' 46 | 47 | # The master toctree document. 48 | master_doc = 'index' 49 | 50 | # General information about the project. 51 | project = 'jupinx' 52 | copyright = '2019, QuantEcon Development Team' 53 | author = 'QuantEcon Development Team' 54 | 55 | # The version info for the project you're documenting, acts as replacement for 56 | # |version| and |release|, also used in various other places throughout the 57 | # built documents. 58 | # 59 | # The short X.Y version. 60 | version = '0.0.1' 61 | # The full version, including alpha/beta/rc tags. 62 | release = '0.0.1' 63 | 64 | # The language for content autogenerated by Sphinx. Refer to documentation 65 | # for a list of supported languages. 66 | # 67 | # This is also used if you do content translation via gettext catalogs. 68 | # Usually you set "language" from the command line for these cases. 69 | language = None 70 | 71 | # List of patterns, relative to source directory, that match files and 72 | # directories to ignore when looking for source files. 73 | # This patterns also effect to html_static_path and html_extra_path 74 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 75 | 76 | # The name of the Pygments (syntax highlighting) style to use. 77 | pygments_style = 'sphinx' 78 | 79 | # If true, `todo` and `todoList` produce output, else they produce nothing. 80 | todo_include_todos = True 81 | 82 | 83 | # -- Options for HTML output ---------------------------------------------- 84 | 85 | # The theme to use for HTML and HTML Help pages. See the documentation for 86 | # a list of builtin themes. 87 | # 88 | html_theme = "sphinx_rtd_theme" 89 | 90 | # Theme options are theme-specific and customize the look and feel of a theme 91 | # further. For a list of options available for each theme, see the 92 | # documentation. 93 | # 94 | # html_theme_options = {} 95 | 96 | # Add any paths that contain custom static files (such as style sheets) here, 97 | # relative to this directory. They are copied after the builtin static files, 98 | # so a file named "default.css" will overwrite the builtin "default.css". 99 | html_static_path = ['_static'] 100 | 101 | html_context = { 102 | 'css_files': [ 103 | '_static/theme_overrides.css', # override wide tables in RTD theme 104 | ], 105 | } 106 | 107 | # -- Options for HTMLHelp output ------------------------------------------ 108 | 109 | # Output file base name for HTML help builder. 110 | htmlhelp_basename = 'sphinxcontrib-jupyterdoc' 111 | 112 | 113 | # -- Options for LaTeX output --------------------------------------------- 114 | 115 | latex_elements = { 116 | # The paper size ('letterpaper' or 'a4paper'). 117 | # 118 | # 'papersize': 'letterpaper', 119 | 120 | # The font size ('10pt', '11pt' or '12pt'). 121 | # 122 | # 'pointsize': '10pt', 123 | 124 | # Additional stuff for the LaTeX preamble. 125 | # 126 | # 'preamble': '', 127 | 128 | # Latex figure (float) alignment 129 | # 130 | # 'figure_align': 'htbp', 131 | } 132 | 133 | # Grouping the document tree into LaTeX files. List of tuples 134 | # (source start file, target name, title, 135 | # author, documentclass [howto, manual, or own class]). 136 | latex_documents = [ 137 | (master_doc, 'jupinx.tex', 'Jupinx Documentation', 138 | 'QuantEcon Development Team', 'manual'), 139 | ] 140 | 141 | 142 | # -- Options for manual page output --------------------------------------- 143 | 144 | # One entry per manual page. List of tuples 145 | # (source start file, name, description, authors, manual section). 146 | man_pages = [ 147 | (master_doc, 'jupinx', 'Jupinx Documentation', 148 | [author], 1) 149 | ] 150 | 151 | 152 | # -- Options for Texinfo output ------------------------------------------- 153 | 154 | # Grouping the document tree into Texinfo files. List of tuples 155 | # (source start file, target name, title, author, 156 | # dir menu entry, description, category) 157 | texinfo_documents = [ 158 | (master_doc, 'jupinx', 'Jupinx Documentation', 159 | author, 'jupinx', 'Jupyter + Sphinx Utilities and Tools', 160 | 'Miscellaneous'), 161 | ] 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /docs/sphinx/index.rst: -------------------------------------------------------------------------------- 1 | ``Jupinx`` Documentation 2 | ======================== 3 | 4 | Jupinx is a collection of utilities and tools for Jupyter and Sphinx 5 | 6 | .. toctree:: 7 | :maxdepth: 1 8 | :caption: Contents: 9 | 10 | quickstart 11 | jupinx 12 | sphinxcontrib-jupyter 13 | 14 | 15 | Credits 16 | ------- 17 | 18 | This project is supported by `QuantEcon `__ 19 | 20 | Many thanks to the lead developers of this project. 21 | 22 | * `@AakashGfude `__ 23 | 24 | LICENSE 25 | ======= 26 | 27 | Copyright © 2019 QuantEcon Development Team: BSD-3 All rights reserved. 28 | 29 | Redistribution and use in source and binary forms, with or without 30 | modification, are permitted provided that the following conditions are 31 | met: 32 | 33 | 1. Redistributions of source code must retain the above copyright 34 | notice, this list of conditions and the following disclaimer. 35 | 36 | 2. Redistributions in binary form must reproduce the above copyright 37 | notice, this list of conditions and the following disclaimer in the 38 | documentation and/or other materials provided with the distribution. 39 | 40 | 3. Neither the name of the copyright holder nor the names of its 41 | contributors may be used to endorse or promote products derived from 42 | this software without specific prior written permission. 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 45 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 46 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 48 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 49 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 50 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 51 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 52 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 53 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 54 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 | 56 | Indices and tables 57 | ================== 58 | 59 | * :ref:`genindex` 60 | * :ref:`modindex` 61 | * :ref:`search` 62 | -------------------------------------------------------------------------------- /docs/sphinx/jupinx.rst: -------------------------------------------------------------------------------- 1 | .. _jupinx: 2 | 3 | Jupinx `cmd` line utility 4 | ========================= 5 | 6 | .. contents:: 7 | :depth: 1 8 | :local: 9 | 10 | The `jupinx` command line utility. 11 | 12 | .. note:: 13 | 14 | this utility currently takes a zero-configuration approach. If you need 15 | to modify the behaviour of `sphinxcontrib-jupyter` then you need to update 16 | `conf.py` file in your sphinx project. 17 | 18 | Installation 19 | ------------ 20 | 21 | To install `jupinx`: 22 | 23 | .. code-block:: bash 24 | 25 | pip install jupinx 26 | 27 | 28 | to upgrade your current installation to the latest version: 29 | 30 | .. code-block:: bash 31 | 32 | pip install jupinx --upgrade 33 | 34 | Usage 35 | ----- 36 | 37 | To build a collection of notebooks using `jupinx`: 38 | 39 | .. code-block:: bash 40 | 41 | jupinx --notebooks 42 | 43 | or 44 | 45 | .. code-block:: bash 46 | 47 | jupinx -n 48 | 49 | .. note:: 50 | 51 | Many users will run `jupinx` at the root level of a repository. 52 | this can be done by specifying :code:`jupinx --notebooks`. The 53 | directory specification is optional in this case. 54 | 55 | It is also possible to build a full website. This option makes 56 | use of Jupyter Notebooks ability to execute code so output is 57 | not required in any of the source files. The website can be 58 | completely built (including all code and generated components). 59 | 60 | .. code-block:: bash 61 | 62 | jupinx --website 63 | 64 | .. note:: 65 | 66 | There is currently **no** default template provided for constructing websites. 67 | This needs to be provided in the future to allow building websites out of 68 | the box with a default theme. 69 | 70 | or 71 | 72 | .. code-block:: bash 73 | 74 | jupinx -w 75 | 76 | documentation regarding options for building websites can be found 77 | `here `__ 78 | 79 | All command line options available can be listed using the help flag: 80 | 81 | .. code-block:: bash 82 | 83 | jupinx --help 84 | 85 | or 86 | 87 | .. code-block:: bash 88 | 89 | jupinx -h 90 | 91 | Options 92 | ------- 93 | 94 | The typical usage for ``jupinx`` is: 95 | 96 | .. code-block:: bash 97 | 98 | jupinx [OPTIONS] [ADDITIONAL OPTIONS] 99 | 100 | The following **options** are provided: 101 | 102 | -h, --help show this help message and exit 103 | -c, --clean clean build directory 104 | -j, --jupyternb open jupyter to view notebooks 105 | -n, --notebooks compile RST files to Jupyter notebooks 106 | -d, --pdf compile RST files to PDF files 107 | -s, --server open html server to view website 108 | -t, --coverage-tests compile coverage report for project 109 | -w, --website compile website 110 | --version show program's version number and exit 111 | 112 | The following **additional options** are provided: 113 | 114 | -p [PARALLEL], --parallel [PARALLEL] 115 | Specify the number of workers for parallel execution 116 | (Default: --parallel will result in --parallel=2) 117 | -f [FILES [FILES ...]], --files [FILES [FILES ...]] 118 | specify files for compilation 119 | -------------------------------------------------------------------------------- /docs/sphinx/quickstart.rst: -------------------------------------------------------------------------------- 1 | .. _quickstart: 2 | 3 | jupinx-quickstart 4 | ================= 5 | 6 | A quickstart utility has been developed to help users get setup quickly 7 | with Sphinx, configured in a way to get building collections of Jupyter notebooks 8 | quickly. 9 | 10 | .. contents:: 11 | :depth: 1 12 | :local: 13 | 14 | Installation 15 | ------------ 16 | 17 | To install `jupinx `__: 18 | 19 | .. code-block:: bash 20 | 21 | pip install jupinx 22 | 23 | or you can upgrade to the latest version using: 24 | 25 | .. code-block:: bash 26 | 27 | pip install --upgrade jupinx 28 | 29 | .. note:: 30 | 31 | ``Windows`` is currently not tested or supported. 32 | See `Issue #7 `_ 33 | 34 | Running :code:`jupinx-quickstart` 35 | --------------------------------- 36 | 37 | Once, ``jupinx`` is installed, to run the jupinx quickstart program you can run: 38 | 39 | .. code-block:: bash 40 | 41 | jupinx-quickstart 42 | 43 | on a terminal. 44 | 45 | The ``jupinx-quickstart`` will: 46 | 47 | #. setup a `directory structure `_ for your project 48 | #. check for ``sphinxcontrib-jupyter`` and ``sphinxcontrib-bibtex`` installation 49 | #. construct ``Makefile`` and ``conf.py`` files 50 | #. construct a parent document ``source/index.rst`` 51 | #. setup the project to use the ``minimal`` theme 52 | 53 | after running the quickstart you may run: 54 | 55 | #. ``make jupyter`` to build the project as notebooks 56 | #. ``make website`` to build the project as a website (via sphinxcontrib-jupyter) 57 | #. ``make pdf`` to build the project as a pdf (via sphinxcontrib-jupyter) 58 | 59 | .. note:: 60 | 61 | The ``quickstart`` sets up the `Makefile` with some `conf.py` setting overrides to 62 | enable building `jupyter` and `website` (rather than via a specific builder) 63 | 64 | Directory structure 65 | ------------------- 66 | 67 | The following directory structure is adopted during the setup: 68 | 69 | - ``./`` 70 | - ``source``: where source RST files should be added 71 | - ``source/_static``: where _static assets such as figures and images are kept 72 | - ``theme``: allows you to customise builders using themes and templates 73 | - ``Makefile``: provides ``make`` commands for compiling the project 74 | - ``conf.py``: provides configuration for ``sphinx-build`` 75 | 76 | .. note:: 77 | 78 | ``sphinx`` is quite flexible in setting up a project in a way 79 | that suits your workflow. If you want to change directory structure this 80 | is likely possible but you will need to update your ``Makefile`` after the 81 | quickstart is finished. Please refer to `sphinx docs `__ 82 | for further information. -------------------------------------------------------------------------------- /docs/sphinx/sphinxcontrib-jupyter.rst: -------------------------------------------------------------------------------- 1 | .. _sphinxcontrib-jupyter: 2 | 3 | Custom Configuration through `sphinxcontrib-jupyter `__ 4 | =========================================================================================================== 5 | 6 | This project depends on `sphinxcontrib-jupyter `__ 7 | to enhance ``sphinx`` to build and work with Jupyter notebooks. 8 | 9 | Full documentation for the extension can be found `here `__ 10 | 11 | There are many configuration settings that can adjust the compilation behaviour of your project. 12 | 13 | An Example 14 | ---------- 15 | 16 | Let's say you have a collection of notebooks that you would like pre-executed. 17 | You can do this by modifying the ``conf.py`` file to enable notebook execution. 18 | 19 | Add the following in the ``conf.py`` in the `jupyter` options section: 20 | 21 | .. code-block:: python 22 | 23 | jupyter_execute_notebooks = True 24 | 25 | as documented `here `__ 26 | 27 | and let's imagine some of your documents produce a file required by a future 28 | document in your collection. An execution dependency can be added to your project by 29 | specifying: 30 | 31 | .. code-block:: python 32 | 33 | jupyter_dependency_lists = { 34 | 'lecture2' : ['lecture1'] 35 | 'lecture3' : ['lecture1'] 36 | } 37 | 38 | in the ``conf.py`` file as documented `here `__ -------------------------------------------------------------------------------- /docs/tutorial.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tutorial 3 | layout: default 4 | permalink: /tutorial.html 5 | --- 6 | 7 | # Tutorial: Setting up a Project 8 | 9 | This tutorial will take you through the steps needed to get up and running 10 | with `jupinx`. 11 | 12 | For a guide on how to use `jupinx` on a Windows system, see [this page](/windows.html). 13 | 14 | ## Installation 15 | 16 | Make sure you have `jupinx` installed: 17 | 18 | ```bash 19 | pip install --upgrade jupinx 20 | ``` 21 | 22 | 23 | ## Understanding Source Directories 24 | 25 | The `jupinx` command line tool converts RST files in a **source directory** 26 | into 27 | 28 | 1. a set of Jupyter Notebooks 29 | 2. a website, and/or 30 | 3. pdf files 31 | 32 | A valid source directory must contain 33 | 34 | * some RST files, including one called `index.rst` and 35 | 36 | * a configuration file called `conf.py` 37 | 38 | * a jupinx compatible `Makefile` 39 | 40 | 41 | ## Creating a Source Directory 42 | 43 | One way to set up a valid source directory is via the `jupinx-quickstart` executable. 44 | 45 | To use it, first create a folder for your project 46 | 47 | ```bash 48 | mkdir jupinx-project 49 | ``` 50 | 51 | Now type 52 | 53 | ```bash 54 | cd jupinx-project 55 | jupinx-quickstart 56 | ``` 57 | 58 | (You can also specify a target folder as long as that folder already exists.) 59 | 60 | The `quickstart-utility` will take you through a series of questions: 61 | 62 | ```bash 63 | Welcome to the Jupinx 0.0.1 quickstart utility. 64 | 65 | Please enter values for the following settings (just press Enter to 66 | accept a default value, if one is given in brackets). 67 | 68 | Enter the root path for documentation. 69 | > Root path for the documentation [.]: 70 | 71 | The project name will occur in several places in the built documentation. 72 | > Project name: First Jupinx Project 73 | > Author name(s): QuantEcon 74 | 75 | Jupinx has the notion of a "version" and a "release" for the 76 | software. Each version can have multiple releases. For example, for 77 | Python the version is something like 2.5 or 3.0, while the release is 78 | something like 2.5.1 or 3.0a1. If you don\'t need this dual structure, 79 | just set both to the same value. 80 | > Project version []: 0.1 81 | > Project release [0.1]: 82 | 83 | If the documents are to be written in a language other than English, 84 | you can select a language here by its language code. Sphinx will then 85 | translate text that it generates into that language. 86 | 87 | For a list of supported codes, see 88 | https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-language. 89 | > Project language [en]: 90 | 91 | Select the kernels which you want for your jupyter notebook conversion 92 | > Do you want to have python3 in your kernel list? (y/n) [y]: 93 | > Do you want to have python2 in your kernel list? (y/n) [y]: n 94 | > Do you want to have julia-1.1 in your kernel list? (y/n) [y]: n 95 | Indicate which of the following Sphinx extensions should be installed: 96 | > sphinxcontrib-jupyter package has been found in your system. Would you like to upgrade it? (y/n) [y]: n 97 | > sphinxcontrib-bibtex package has been found in your system. Would you like to upgrade it? (y/n) [y]: n 98 | 99 | Creating file ./conf.py. 100 | Creating file ./source/index.rst. 101 | Creating file ./Makefile. 102 | 103 | Finished: An initial directory structure has been created. 104 | 105 | You should now populate your master file ./source/index.rst and create other documentation 106 | source files. Use the Makefile to build the docs, like so: 107 | make builder 108 | where "builder" is one of the supported builders, e.g. jupyter, website or pdf. 109 | ``` 110 | 111 | You should now see the following files and folders in your directory: 112 | 113 | ```bash 114 | ls jupinx-project 115 | 116 | > Makefile _build conf.py source theme 117 | ``` 118 | 119 | .. note:: 120 | 121 | ``jupinx-quickstart`` includes a `minimal` theme to enable html and pdf 122 | construction. 123 | 124 | Now let's create our first source file. 125 | 126 | 127 | ## Writing an RST Source File 128 | 129 | The `source` directory is the place that should contain all your source `rst` files. 130 | 131 | Let's create a file `first_notebook.rst` in the `source` directory and add the following: 132 | 133 | ```rst 134 | First Notebook 135 | ============== 136 | 137 | This is our first notebook and it will contain the following code-block. 138 | 139 | .. code-block:: python 140 | 141 | import matplotlib 142 | import matplotlib.pyplot as plt 143 | import numpy as np 144 | 145 | # Data for plotting 146 | t = np.arange(0.0, 2.0, 0.01) 147 | s = 1 + np.sin(2 * np.pi * t) 148 | 149 | fig, ax = plt.subplots() 150 | ax.plot(t, s) 151 | 152 | ax.set(xlabel='time (s)', ylabel='voltage (mV)', 153 | title='About as simple as it gets, folks') 154 | ax.grid() 155 | 156 | ``` 157 | 158 | You will need to also add `first_notebook` to the `toctree` in your `source/index.rst` file. 159 | 160 | 161 | ## Building and Viewing 162 | 163 | Let's have a look at our project. 164 | 165 | With `jupinx-project` in the present working directory, type 166 | 167 | ```bash 168 | jupinx --notebooks jupinx-project 169 | ``` 170 | 171 | Alternatively, you can use the full path: 172 | 173 | ```bash 174 | jupinx --notebooks /home/full/path/jupinx-project 175 | ``` 176 | 177 | You can also shorten to 178 | 179 | ```bash 180 | jupinx -n jupinx-project 181 | ``` 182 | 183 | (Or, if you are at the root level of `jupinx-project`, you can just type `jupinx -n`.) 184 | 185 | This generates notebooks from the `rst` files and puts them in `_build/jupyter/` 186 | 187 | To view the results using Jupyter Notebooks, type 188 | 189 | ``` 190 | jupinx -j jupinx-project 191 | ``` 192 | 193 | To convert the RST files into a website, use 194 | 195 | ``` 196 | jupinx -w jupinx-project 197 | ``` 198 | 199 | To view this website, use 200 | 201 | ``` 202 | jupinx -s jupinx-project 203 | ``` 204 | 205 | To see more detail on these commands, type 206 | 207 | ``` 208 | jupinx --help 209 | ``` 210 | 211 | More details can be found in the [documentation](https://jupinx.readthedocs.io/). 212 | 213 | 214 | ## Advanced Configuration 215 | 216 | Much of the heavy lifting for `jupinx` is done by a Sphinx extension called 217 | [sphinxcontrib-jupyter](https://github.com/QuantEcon/sphinxcontrib-jupyter/) 218 | 219 | For details on advanced configuration, see the [sphinxcontrib-jupyter documentation](https://sphinxcontrib-jupyter.readthedocs.io/en/latest/config-project.html). 220 | 221 | As one example, we can set generated notebooks to execute by enabling the execution option in the `conf.py` file. 222 | 223 | Open `conf.py` file and at the bottom of this file you will find sphinxcontrib-jupyter options. You can add: 224 | 225 | ```python 226 | jupyter_execute_notebooks = True 227 | ``` 228 | 229 | This will now build notebooks and then execute them for you with results stored in `_build/jupyter/executed`. You can test this by: 230 | 231 | ```bash 232 | jupinx --clean --notebooks 233 | ``` 234 | 235 | 236 | -------------------------------------------------------------------------------- /docs/windows.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Windows 3 | layout: default 4 | permalink: /windows.html 5 | --- 6 | 7 | # Tutorial: Using Jupinx with Windows 8 | 9 | This tutorial will take you through some recommended steps to get `jupinx` running on a Windows system. 10 | 11 | ## Introduction 12 | 13 | Jupinx is not natively supported in Windows, but it is possible to run Jupinx on a Linux subsystem using WSL (Windows Subsystem for Linux). Jupinx can be installed normally on the Linux subsystem, but will require some extra steps to work properly with Windows. 14 | 15 | Note: Windows 10 is required to use WSL. 16 | 17 | ## Step 1: Set up Ubuntu on WSL 18 | We suggest you follow a tutorial like [this one by Microsoft](https://docs.microsoft.com/en-us/windows/wsl/install-win10). You can choose which Linux distro to use - we recommend Ubuntu simply because it was used in making this guide and we know it works. The rest of this guide assumes you are using Ubuntu. 19 | 20 | ## Step 2: Install Anaconda on Ubuntu 21 | 1. Open a web browser in Windows and navigate to Anaconda's download/distribution page [here](https://www.anaconda.com/distribution/). Your (Windows) operating system will be detected and you will be recommended the Windows installer. Don't download this one - you want the Linux version. 22 | 2. Right click on the Linux download link for Python 3 and and click Copy Link or Copy Link Location. 23 | 3. Open a Linux terminal (if using Ubuntu, simply search for Ubuntu in the Windows search bar). To download the Anaconda install files, type: 24 | 25 | ```bash 26 | wget 27 | ``` 28 | 29 | for example: 30 | 31 | ```bash 32 | wget https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.sh 33 | ``` 34 | 35 | 4. To install, run the installation script for whichever version of Anaconda you've got downloaded: 36 | 37 | ```bash 38 | bash Anaconda3.sh 39 | ``` 40 | 41 | for example: 42 | 43 | ```bash 44 | bash Anaconda3-2019.10-Linux-x86_64.sh 45 | ``` 46 | 47 | ## Step 3: Install Jupinx on the Ubuntu subsystem 48 | Open an Ubuntu terminal and follow the instructions [here](/tutorial.html) for installing Jupinx. 49 | 50 | Check that the install has worked with: 51 | 52 | ```bash 53 | jupinx --version 54 | ``` 55 | Jupinx should now be working on Ubuntu, but you may encounter errors if editing .rst source files in Windows. Step 4 should resolve this problem. 56 | ### Viewing Jupyter notebooks 57 | Jupyter notebooks usually launch in a browser, but will not find Windows browsers from the Ubuntu subsystem. Try typing 58 | 59 | ```bash 60 | jupyter notebook 61 | ``` 62 | 63 | If everything is working properly, you should be provided with a URL you can enter in a Windows web browser to view the notebooks in your current directory, if there are any. 64 | 65 | ## Step 4: Use Visual Studio Code extension 'Remote-WSL' to edit source .rst files 66 | 67 | To avoid potential problems caused by differences in Windows and Linux file systems, we recommend you edit Jupinx source files in the Ubuntu system. One way to do this is with the VSCode 'Remote-WSL' extension. 68 | 69 | 1. Install VSCode 70 | 2. Install the Remote-WSL extension 71 | 3. To open a file called filename.rst in the VSCode Remote-WSL editor from Ubuntu, type the following in an Ubuntu terminal: 72 | 73 | ```bash 74 | code filename.rst 75 | ``` 76 | You can also open an Ubuntu-side VSCode window through the menus. 77 | 78 | >## Note 79 | > 80 | >A good rule of thumb is that wherever possible you should do things in Ubuntu, not Windows, to avoid compatibility problems. **If working with git, for instance, use it through the Ubuntu terminal** (not with a separate Windows installation of git). 81 | 82 | ## See Also 83 | * [These instructions](https://github.com/QuantEcon/lecture-source-jl#usage) for editing the QuantEcon lectures using Jupinx on a Windows system 84 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: test-build 2 | channels: 3 | - default 4 | - conda-forge 5 | dependencies: 6 | - pip 7 | - python 8 | - jupyter 9 | - jupyterlab 10 | - nbconvert 11 | - pandoc 12 | - pandas 13 | - numba 14 | - numpy 15 | - matplotlib 16 | - networkx 17 | - sphinx=2.4.4 18 | - pip: 19 | - quantecon 20 | - joblib 21 | -------------------------------------------------------------------------------- /jupinx/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Jupinx 3 | ~~~~~~ 4 | 5 | The Jupinx documentation toolchain. 6 | """ 7 | 8 | import os 9 | import subprocess 10 | import warnings 11 | from os import path 12 | from subprocess import PIPE 13 | 14 | __version__ = '0.2.3' 15 | 16 | package_dir = path.abspath(path.dirname(__file__)) 17 | 18 | __display_version__ = __version__ # used for command line version 19 | -------------------------------------------------------------------------------- /jupinx/cmd/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | jupinx.cmd 3 | ~~~~~~~~~~ 4 | 5 | Modules for command line executables. 6 | """ -------------------------------------------------------------------------------- /jupinx/cmd/build.py: -------------------------------------------------------------------------------- 1 | """ 2 | jupinx.cmd.build 3 | ~~~~~~~~~~~~~~~~ 4 | 5 | jupinx command-line handling. 6 | 7 | """ 8 | 9 | import argparse 10 | import os 11 | import subprocess 12 | import sys 13 | import copy 14 | from typing import Dict, List 15 | 16 | import locale 17 | import sphinx.locale 18 | from sphinx.locale import __ 19 | from jupinx import __display_version__, package_dir 20 | import logging 21 | import webbrowser 22 | import textwrap 23 | from notebook import notebookapp 24 | from traitlets.config import Config 25 | from distutils.spawn import find_executable 26 | 27 | ADDITIONAL_OPTIONS = [ 28 | 'directory', 29 | 'parallel', 30 | 'files' 31 | ] 32 | 33 | logging.basicConfig(format='%(levelname)s: %(message)s') 34 | ### This is a full blown manual and help tool which describes the functionality and usage of jupinx cmd 35 | def get_parser() -> argparse.ArgumentParser: 36 | description = __( 37 | "\n" 38 | "Jupinx command line tool.\n" 39 | "\n" 40 | "Provides a collection of utilities for Jupyter and Sphinx Projects.\n" 41 | "If you would like to setup a new project please use: jupinx-quickstart.\n" 42 | "\n" 43 | ) 44 | epilog = __( 45 | "\n" 46 | "Examples:\n" 47 | " jupinx --notebooks (within a project directory)\n" 48 | " jupinx -n lecture-source-py (specify path to project directory)\n" 49 | " jupinx -n lecture-source-py -f source/lecture1.rst" 50 | "\n" 51 | "Further documentation is available: https://quantecon.github.io/jupinx/.\n" 52 | ) 53 | parser = argparse.ArgumentParser( 54 | usage='%(prog)s [OPTIONS] [ADDITIONAL OPTIONS]', 55 | formatter_class=argparse.RawTextHelpFormatter, 56 | description=description, 57 | epilog=epilog, 58 | ) 59 | parser.add_argument('directory', nargs='?', type=str, default='./', action='store', 60 | help=textwrap.dedent(""" 61 | provide path to a project directory 62 | (Optional: the current working directory (./) is the default) 63 | """.lstrip("\n")) 64 | ) 65 | parser.add_argument('-c', '--clean', action='store_true', dest='clean', 66 | help=textwrap.dedent(""" 67 | clean build directory 68 | """.lstrip("\n")) 69 | ) 70 | parser.add_argument('-j', '--jupyternb', action='store_true', dest='jupyternb', 71 | help=textwrap.dedent(""" 72 | open jupyter to view notebooks 73 | """.lstrip("\n")) 74 | ) 75 | parser.add_argument('-n', '--notebooks', action='store_true', dest='jupyter', 76 | help=textwrap.dedent(""" 77 | compile RST files to Jupyter notebooks 78 | """.lstrip("\n")) 79 | ) 80 | parser.add_argument('-p', '--pdf', action='store_true', dest='pdf', 81 | help=textwrap.dedent(""" 82 | compile RST files to PDF files 83 | """.lstrip("\n")) 84 | ) 85 | parser.add_argument('-s', '--server', action='store_true', dest='html-server', 86 | help=textwrap.dedent(""" 87 | open html server to view website 88 | """.lstrip("\n")) 89 | ) 90 | parser.add_argument('-t', '--coverage-tests', action='store_true', dest='coverage', 91 | help=textwrap.dedent(""" 92 | compile coverage report for project 93 | """.lstrip("\n")) 94 | ) 95 | parser.add_argument('-w', '--website', action='store_true', dest='website', 96 | help=textwrap.dedent(""" 97 | compile website 98 | """.lstrip("\n")) 99 | ) 100 | parser.add_argument('--version', action='version', dest='show_version', 101 | version='%%(prog)s %s' % __display_version__) 102 | group = parser.add_argument_group(__('additional options')) 103 | group.add_argument('--parallel', dest='parallel', nargs='?', type=int, const='2', action='store', 104 | help=textwrap.dedent(""" 105 | Specify the number of workers for parallel execution 106 | (Default: --parallel will result in --parallel=2) 107 | """.lstrip("\n")) 108 | ) 109 | group.add_argument('--files', nargs="*", dest='files', 110 | help=textwrap.dedent(""" 111 | specify files for compilation 112 | """.lstrip("\n")) 113 | ) 114 | return parser 115 | 116 | def check_directory_makefile(arg_dict): 117 | dir = None 118 | try: 119 | dir = arg_dict['directory'] 120 | except: 121 | logging.error("Please specify a directory") 122 | return False 123 | 124 | if os.path.exists(dir) is False: 125 | logging.error("Specified directory does not exist") 126 | return False 127 | if os.path.isfile(dir + "/Makefile") is False: 128 | logging.error("Makefile not found in the directory") 129 | return False 130 | 131 | def check_view_result_directory(target, arg_dict): 132 | if target == "notebooks": 133 | dir = arg_dict['directory'] + "_build/jupyter/" 134 | elif target == "website": 135 | dir = arg_dict['directory'] + "_build/website/jupyter_html/" 136 | elif target == "pdf": 137 | dir = arg_dict['directory'] + "_build/jupyterpdf/pdf" 138 | else: 139 | pass 140 | if os.path.exists(dir) is False: 141 | if target == "notebooks": 142 | logging.error("Results directory: {} does not exist!\nPlease run jupinx -n to build notebooks".format(dir)) 143 | elif target == "website": 144 | logging.error("Results directory: {} does not exist.\n Please run jupinx -w to build website".format(dir)) 145 | elif target == "pdf": 146 | logging.error("Results directory: {} does not exist.\n Please run jupinx -p to build pdf".format(dir)) 147 | return False 148 | return True 149 | 150 | def handle_make_parallel(cmd, arg_dict): 151 | if check_directory_makefile(arg_dict) is False: 152 | exit() 153 | if 'parallel' in arg_dict: 154 | cmd = ['make', cmd, 'parallel=' + str(arg_dict['parallel'])] 155 | print("Running: " + " ".join(cmd)) 156 | else: 157 | cmd = ['make', cmd] 158 | print("Running: " + " ".join(cmd)) 159 | if 'files' in arg_dict: 160 | cmd = cmd + ['FILES='+ ' '.join(arg_dict['files'])] 161 | subprocess.run(cmd, cwd=arg_dict['directory']) 162 | if 'pdf' in cmd: 163 | print("PDF files can be found in: {}_build/jupyterpdf/pdf/".format(arg_dict['directory'])) 164 | 165 | def handle_make_jupyternb(arg_dict): 166 | """ Launch Jupyter notebook server """ 167 | if check_directory_makefile(arg_dict) is False: 168 | exit() 169 | if check_view_result_directory("notebooks", arg_dict) is False: 170 | exit() 171 | 172 | ## getting the build folder 173 | build_folder = arg_dict['directory'] + '_build/jupyter/' 174 | 175 | ## Note: we can support launching of individual files in the future ## 176 | 177 | cfg = Config() 178 | # cfg.NotebookApp.file_to_run = os.path.abspath(filename) 179 | cfg.NotebookApp.notebook_dir = build_folder 180 | cfg.NotebookApp.open_browser = True 181 | notebookapp.launch_new_instance(config=cfg, 182 | argv=[], # Avoid it seeing our own argv 183 | ) 184 | 185 | def handle_make_htmlserver(arg_dict): 186 | """ Launch HTML Server (PORT = 8901) """ 187 | from http.server import HTTPServer, SimpleHTTPRequestHandler 188 | import threading 189 | 190 | PORT = 8901 191 | webdir = arg_dict['directory'] + "_build/website/jupyter_html/" 192 | 193 | def start_server(httpd): 194 | httpd.serve_forever() 195 | 196 | class Handler(SimpleHTTPRequestHandler): 197 | def __init__(self, *args, **kwargs): 198 | super().__init__(*args, directory=webdir, **kwargs) 199 | 200 | if check_directory_makefile(arg_dict) is False: 201 | exit() 202 | if check_view_result_directory("website", arg_dict) is False: 203 | exit() 204 | httpd = HTTPServer(("", PORT), Handler) 205 | print("Serving at http://localhost:{}".format(PORT)) 206 | x = threading.Thread(target=start_server, args=(httpd,)) 207 | x.start() 208 | webbrowser.open("http://localhost:{}".format(PORT)) 209 | try: 210 | response = input("\nTo close the server please use Ctrl-C\n\n") 211 | except KeyboardInterrupt: 212 | print("Shutting down http server ...") 213 | httpd.shutdown() 214 | 215 | def make_file_actions(arg_dict: Dict): 216 | """ 217 | Current Approach is to trigger calls to the Makefile contained in the project 218 | directory for sphinx-build using subprocesses. 219 | 220 | .. todo:: 221 | 222 | Support sphinx-build directly using Invoke or some other library in the future 223 | will allow for advanced configuration options to be available through this tool. 224 | """ 225 | if 'clean' in arg_dict: 226 | if sys.version_info.major == 2: 227 | cmd = ['make', 'clean'] 228 | print("Running: " + " ".join(cmd)) 229 | subprocess.call(cmd, cwd=arg_dict['directory']) 230 | else: 231 | cmd = ['make', 'clean'] 232 | print("Running: " + " ".join(cmd)) 233 | subprocess.run(cmd, cwd=arg_dict['directory']) 234 | 235 | if 'coverage' in arg_dict: 236 | handle_make_parallel('coverage', arg_dict) 237 | 238 | if 'website' in arg_dict: 239 | handle_make_parallel('website', arg_dict) 240 | 241 | if 'jupyter' in arg_dict: 242 | handle_make_parallel('jupyter', arg_dict) 243 | 244 | if 'jupyternb' in arg_dict: 245 | handle_make_jupyternb(arg_dict) 246 | 247 | if 'html-server' in arg_dict: 248 | handle_make_htmlserver(arg_dict) 249 | 250 | if 'pdf' in arg_dict: 251 | check_xelatex_installed() 252 | handle_make_parallel('pdf', arg_dict) 253 | 254 | def check_xelatex_installed(): 255 | if not find_executable('xelatex'): 256 | logging.error( 257 | "Cannot find a xelatex executable for pdf compilation.\n" + 258 | "If you need to install tex it is recommended to install texlive: https://www.tug.org/texlive/" 259 | ) 260 | exit(1) 261 | else: 262 | print("Using xelatex from: {}".format(find_executable('xelatex'))) 263 | 264 | def check_project_path(path): 265 | """ Check supplied project directory is valid and complete """ 266 | path = os.path.normpath(path) + "/" 267 | if os.path.isdir(path): 268 | return path 269 | else: 270 | logging.error("The supplied project directory {} is not found".format(path)) 271 | exit(1) 272 | 273 | def deleteDefaultValues(d): 274 | valid = False 275 | 276 | # delete None or False value and handle int and str for argparse const 277 | d = {k: v for k, v in d.items() if v is (not False) or (type(v) == int) or (type(v) == str) or isinstance(v, list)} 278 | temp = copy.deepcopy(d) 279 | 280 | # remove any additional options 281 | for option in ADDITIONAL_OPTIONS: 282 | if option in temp: 283 | del temp[option] 284 | 285 | if len(temp) > 0: 286 | valid = True 287 | 288 | return [d, valid] 289 | 290 | def main(argv: List[str] = sys.argv[1:]) -> int: 291 | sphinx.locale.setlocale(locale.LC_ALL, '') 292 | sphinx.locale.init_console(os.path.join(package_dir, 'locale'), 'sphinx') 293 | 294 | ## parse options 295 | parser = get_parser() 296 | try: 297 | args = parser.parse_args(argv) 298 | except SystemExit as err: 299 | return err.code 300 | 301 | d = vars(args) 302 | [d, valid] = deleteDefaultValues(d) 303 | 304 | ## no option specified then show help tool 305 | if valid is False: 306 | parser.print_help() 307 | else: 308 | d['directory'] = check_project_path(d['directory']) 309 | make_file_actions(d) 310 | 311 | if __name__ == '__main__': 312 | sys.exit(main(sys.argv[1:])) 313 | -------------------------------------------------------------------------------- /jupinx/cmd/quickstart.py: -------------------------------------------------------------------------------- 1 | """ 2 | jupinx.cmd.quickstart 3 | ~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Quickly setup documentation source to work with Jupinx. 6 | """ 7 | 8 | import argparse 9 | import locale 10 | import os 11 | import subprocess 12 | import sys 13 | import pip 14 | 15 | import time 16 | import warnings 17 | import importlib 18 | from collections import OrderedDict 19 | from os import path 20 | from typing import Any, Callable, Dict, List, Pattern, Union 21 | import json 22 | from distutils.dir_util import copy_tree 23 | 24 | # try to import readline, unix specific enhancement 25 | try: 26 | import readline 27 | if readline.__doc__ and 'libedit' in readline.__doc__: 28 | readline.parse_and_bind("bind ^I rl_complete") 29 | USE_LIBEDIT = True 30 | else: 31 | readline.parse_and_bind("tab: complete") 32 | USE_LIBEDIT = False 33 | except ImportError: 34 | USE_LIBEDIT = False 35 | 36 | from docutils.utils import column_width 37 | 38 | import sphinx.locale 39 | from jupinx import __display_version__, package_dir 40 | 41 | from sphinx.deprecation import RemovedInSphinx40Warning 42 | from sphinx.locale import __ 43 | from sphinx.util.console import ( # type: ignore 44 | colorize, bold, red, turquoise, nocolor, color_terminal 45 | ) 46 | from sphinx.util.osutil import ensuredir 47 | from jupinx.util.template import SphinxRenderer 48 | 49 | TERM_ENCODING = getattr(sys.stdin, 'encoding', None) # RemovedInSphinx40Warning 50 | 51 | EXTENSIONS = OrderedDict([ 52 | ('sphinxcontrib-jupyter', __('A Sphinx Extension for Generating Jupyter Notebooks')), 53 | ('sphinxcontrib-bibtex', __('A Sphinx extension for BibTeX style citations')) 54 | ]) 55 | 56 | PROMPT_PREFIX = '> ' 57 | 58 | if sys.platform == 'win32': 59 | # On Windows, show questions as bold because of color scheme of PowerShell (refs: #5294). 60 | COLOR_QUESTION = 'bold' 61 | else: 62 | COLOR_QUESTION = 'purple' 63 | 64 | KERNELLIST = OrderedDict([ 65 | ('python3', { 66 | "kernelspec": { 67 | "display_name": "Python", 68 | "language": "python3", 69 | "name": "python3" 70 | }, 71 | "file_extension": ".py", 72 | }), 73 | ('python2', { 74 | "kernelspec": { 75 | "display_name": "Python", 76 | "language": "python2", 77 | "name": "python2" 78 | }, 79 | "file_extension": ".py", 80 | }), 81 | ('julia-1.1', { 82 | "kernelspec": { 83 | "display_name": "Julia 1.1", 84 | "language": "julia", 85 | "name": "julia-1.1" 86 | }, 87 | "file_extension": ".jl" 88 | }), 89 | ('julia-1.2', { 90 | "kernelspec": { 91 | "display_name": "Julia 1.2", 92 | "language": "julia", 93 | "name": "julia-1.2" 94 | }, 95 | "file_extension": ".jl" 96 | }) 97 | ]) 98 | 99 | # function to get input from terminal -- overridden by the test suite 100 | def term_input(prompt: str) -> str: 101 | if sys.platform == 'win32': 102 | # Important: On windows, readline is not enabled by default. In these 103 | # environment, escape sequences have been broken. To avoid the 104 | # problem, quickstart uses ``print()`` to show prompt. 105 | print(prompt, end='') 106 | return input('') 107 | else: 108 | return input(prompt) 109 | 110 | 111 | class ValidationError(Exception): 112 | """Raised for validation errors.""" 113 | 114 | 115 | def is_path(x: str) -> str: 116 | x = path.expanduser(x) 117 | if not path.isdir(x): 118 | raise ValidationError(__("Please enter a valid path name.")) 119 | return x 120 | 121 | 122 | def allow_empty(x: str) -> str: 123 | return x 124 | 125 | 126 | def nonempty(x: str) -> str: 127 | if not x: 128 | raise ValidationError(__("Please enter some text.")) 129 | return x 130 | 131 | 132 | def choice(*l: str) -> Callable[[str], str]: 133 | def val(x: str) -> str: 134 | if x not in l: 135 | raise ValidationError(__('Please enter one of %s.') % ', '.join(l)) 136 | return x 137 | return val 138 | 139 | 140 | def boolean(x: str) -> bool: 141 | if x.upper() not in ('Y', 'YES', 'N', 'NO'): 142 | raise ValidationError(__("Please enter either 'y' or 'n'.")) 143 | return x.upper() in ('Y', 'YES') 144 | 145 | 146 | def ok(x: str) -> str: 147 | return x 148 | 149 | 150 | def term_decode(text: Union[bytes, str]) -> str: 151 | warnings.warn('term_decode() is deprecated.', 152 | RemovedInSphinx40Warning, stacklevel=2) 153 | 154 | if isinstance(text, str): 155 | return text 156 | 157 | # Use the known encoding, if possible 158 | if TERM_ENCODING: 159 | return text.decode(TERM_ENCODING) 160 | 161 | # If ascii is safe, use it with no warning 162 | if text.decode('ascii', 'replace').encode('ascii', 'replace') == text: 163 | return text.decode('ascii') 164 | 165 | print(turquoise(__('* Note: non-ASCII characters entered ' 166 | 'and terminal encoding unknown -- assuming ' 167 | 'UTF-8 or Latin-1.'))) 168 | try: 169 | return text.decode() 170 | except UnicodeDecodeError: 171 | return text.decode('latin1') 172 | 173 | 174 | def do_prompt(text: str, default: str = None, validator: Callable[[str], Any] = nonempty) -> Union[str, bool]: # NOQA 175 | while True: 176 | if default is not None: 177 | prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default) 178 | else: 179 | prompt = PROMPT_PREFIX + text + ': ' 180 | if USE_LIBEDIT: 181 | # Note: libedit has a problem for combination of ``input()`` and escape 182 | # sequence (see #5335). To avoid the problem, all prompts are not colored 183 | # on libedit. 184 | pass 185 | else: 186 | prompt = colorize(COLOR_QUESTION, prompt, input_mode=True) 187 | x = term_input(prompt).strip() 188 | if default and not x: 189 | x = default 190 | try: 191 | x = validator(x) 192 | except ValidationError as err: 193 | print(red('* ' + str(err))) 194 | continue 195 | break 196 | return x 197 | 198 | 199 | class QuickstartRenderer(SphinxRenderer): 200 | def __init__(self) -> None: 201 | super().__init__() 202 | 203 | def render(self, template_name: str, context: Dict) -> str: 204 | user_template = path.basename(template_name) 205 | return super().render(template_name, context) 206 | 207 | 208 | def ask_user(d: Dict) -> None: 209 | """Ask the user for quickstart values missing from *d*. 210 | 211 | Values are: 212 | 213 | * path: root path 214 | * project: project name 215 | * author: author names 216 | * version: version of project 217 | * release: release of project 218 | * language: document language 219 | * kernels: jupyter kernels 220 | * extensions: extensions to use (list) 221 | """ 222 | 223 | print(bold(__('Welcome to the Jupinx %s quickstart utility.')) % __display_version__) 224 | print() 225 | print(__('Please enter values for the following settings (just press Enter to\n' 226 | 'accept a default value, if one is given in brackets).')) 227 | 228 | if 'path' in d: 229 | print() 230 | print(bold(__('Selected root path: %s')) % d['path']) 231 | else: 232 | print() 233 | print(__('Enter the root path for documentation.')) 234 | d['path'] = do_prompt(__('Root path for the documentation'), '.', is_path) 235 | 236 | while path.isfile(path.join(d['path'], 'conf.py')): 237 | print() 238 | print(bold(__('Error: an existing conf.py has been found in the ' 239 | 'selected root path.'))) 240 | print(__('jupinx-quickstart will not overwrite existing Jupinx projects.')) 241 | print() 242 | 243 | #### Will need to check if the below code is necessary 244 | # d['path'] = do_prompt(__('Press Enter to exit'), 245 | # '', is_path) 246 | if not d['path']: 247 | sys.exit(1) 248 | 249 | if 'project' not in d: 250 | print() 251 | print(__('The project name will occur in several places in the built documentation.')) 252 | d['project'] = do_prompt(__('Project name')) 253 | if 'author' not in d: 254 | d['author'] = do_prompt(__('Author name(s)')) 255 | 256 | if 'version' not in d: 257 | print() 258 | print(__('Jupinx has the notion of a "version" and a "release" for the\n' 259 | 'software. Each version can have multiple releases. For example, for\n' 260 | 'Python the version is something like 2.5 or 3.0, while the release is\n' 261 | 'something like 2.5.1 or 3.0a1. If you don\'t need this dual structure,\n' 262 | 'just set both to the same value.')) 263 | d['version'] = do_prompt(__('Project version'), '', allow_empty) 264 | if 'release' not in d: 265 | d['release'] = do_prompt(__('Project release'), d['version'], allow_empty) 266 | 267 | if 'language' not in d: 268 | print() 269 | print(__('If the documents are to be written in a language other than English,\n' 270 | 'you can select a language here by its language code. Sphinx will then\n' 271 | 'translate text that it generates into that language.\n' 272 | '\n' 273 | 'For a list of supported codes, see\n' 274 | 'https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-language.')) # NOQA 275 | d['language'] = do_prompt(__('Project language'), 'en') 276 | if d['language'] == 'en': 277 | d['language'] = None 278 | 279 | #### DO WE NEED A DIFFERENT SUFFIX ? 280 | # if 'suffix' not in d: 281 | # print() 282 | # print(__('The file name suffix for source files. Commonly, this is either ".txt"\n' 283 | # 'or ".rst". Only files with this suffix are considered documents.')) 284 | # d['suffix'] = do_prompt(__('Source file suffix'), '.rst', suffix) 285 | 286 | #### DO WE NEED A DIFFERENT FILENAME THEN MASTER 287 | # if 'master' not in d: 288 | # print() 289 | # print(__('One document is special in that it is considered the top node of the\n' 290 | # '"contents tree", that is, it is the root of the hierarchical structure\n' 291 | # 'of the documents. Normally, this is "index", but if your "index"\n' 292 | # 'document is a custom template, you can also set this to another filename.')) 293 | # d['master'] = do_prompt(__('Name of your master document (without suffix)'), 'index') 294 | 295 | while path.isfile(path.join(d['path'], d['master'] + d['suffix'])) or \ 296 | path.isfile(path.join(d['path'], 'source', d['master'] + d['suffix'])): 297 | print() 298 | print(bold(__('Error: the master file %s has already been found in the ' 299 | 'selected root path.') % (d['master'] + d['suffix']))) 300 | print(__('jupinx-quickstart will not overwrite the existing file.')) 301 | print() 302 | d['master'] = do_prompt(__('Please enter a new file name, or rename the ' 303 | 'existing file and press Enter'), d['master']) 304 | 305 | ## Ask for kernels to include 306 | print() 307 | print(__('Select the kernels which you want for your jupyter notebook conversion')) 308 | for (key, value) in KERNELLIST.items(): 309 | d['kernels'][key] = do_prompt('Do you want to have %s in your kernel list? (y/n)' % (key), 'y', boolean) 310 | 311 | # list of extensions to include in the conf file 312 | d['extensions'] = [] 313 | 314 | # list of extensions which require installation 315 | d['toinstall'] = [] 316 | 317 | ## Ask for sphinx extensions to be installed 318 | print(__('Indicate which of the following Sphinx extensions should be installed:')) 319 | for name, description in EXTENSIONS.items(): 320 | moduleName = name.replace('-','.') 321 | try: 322 | importlib.import_module(moduleName) 323 | if do_prompt('%s package has been found in your system. Would you like to upgrade it? (y/n)' % (name), 'y', boolean): 324 | d['toinstall'].append(name) 325 | d['extensions'].append(moduleName) 326 | 327 | except ImportError as e: 328 | if name == 'sphinxcontrib-jupyter': 329 | ## the extensions to install forcefully 330 | d['extensions'].append(moduleName) 331 | d['toinstall'].append(name) 332 | else: 333 | ## the extensions which are optional 334 | if do_prompt('%s: %s (y/n)' % (name, description), 'y', boolean): 335 | d['extensions'].append(moduleName) 336 | d['toinstall'].append(name) 337 | 338 | # # Handle conflicting options 339 | # if {'sphinx.ext.imgmath', 'sphinx.ext.mathjax'}.issubset(d['extensions']): 340 | # print(__('Note: imgmath and mathjax cannot be enabled at the same time. ' 341 | # 'imgmath has been deselected.')) 342 | # d['extensions'].remove('sphinx.ext.imgmath') 343 | print() 344 | 345 | 346 | def generate(d: Dict, overwrite: bool = True, silent: bool = False 347 | ) -> None: 348 | """Generate project based on values in *d*.""" 349 | template = QuickstartRenderer() 350 | if 'mastertoctree' not in d: 351 | d['mastertoctree'] = '' 352 | if 'mastertocmaxdepth' not in d: 353 | d['mastertocmaxdepth'] = 2 354 | 355 | d['now'] = time.asctime() 356 | d['project_underline'] = column_width(d['project']) * '=' 357 | d['copyright'] = time.strftime('%Y') + ', ' + d['author'] 358 | 359 | ensuredir(d['path']) 360 | 361 | basepath = d['path'] 362 | 363 | srcdir = path.join(d['path'], 'source') 364 | 365 | ensuredir(srcdir) 366 | 367 | builddir = path.join(d['path'], '_build') 368 | d['exclude_patterns'] = '' 369 | ensuredir(builddir) 370 | 371 | themedir = path.join(d['path'], 'theme') 372 | ensuredir(themedir) 373 | ensuredir(path.join(srcdir + '/_static')) 374 | 375 | ## copying the html template files 376 | DEFAULT_THEME = "minimal" 377 | source_theme_path = os.path.join(package_dir, 'theme', DEFAULT_THEME) 378 | target_theme_path = os.path.join(themedir, DEFAULT_THEME) 379 | copy_tree(source_theme_path + "/", target_theme_path , preserve_symlinks=1) 380 | 381 | for (key, value) in KERNELLIST.items(): 382 | if d['kernels'][key] is True: 383 | d['kernels'][key] = value 384 | else: 385 | del d['kernels'][key] #No need to include 'n' responses in conf.py 386 | 387 | ## pretty print the json 388 | d['kernels'] = json.dumps(d['kernels'], sort_keys=True, indent=4) 389 | 390 | def write_file(fpath: str, content: str, newline: str = None) -> None: 391 | if overwrite or not path.isfile(fpath): 392 | if 'quiet' not in d: 393 | print(__('Creating file %s.') % fpath) 394 | with open(fpath, 'wt', encoding='utf-8', newline=newline) as f: 395 | f.write(content) 396 | else: 397 | if 'quiet' not in d: 398 | print(__('File %s already exists, skipping.') % fpath) 399 | 400 | ## specifying the conf_path at present 401 | conf_path = os.path.join(package_dir, 'templates', 'quickstart', 'conf.py_t') 402 | with open(conf_path) as f: 403 | conf_text = f.read() 404 | 405 | write_file(path.join(basepath, 'conf.py'), template.render_string(conf_text, d)) 406 | 407 | ## forming a minimal template of index.rst here 408 | masterfile = path.join(srcdir, d['master'] + d['suffix']) 409 | write_file(masterfile, template.render('quickstart/master_doc.rst_t', d)) 410 | demofile = path.join(srcdir, 'demo_notebook.rst') 411 | write_file(demofile, template.render('quickstart/demo_notebook.rst_t', d)) 412 | copy_tree(package_dir + '/templates/quickstart/_static/', srcdir + '/_static/') 413 | 414 | ## taking the minimal Makefile 415 | makefile_template = 'quickstart/Makefile_t' 416 | 417 | d['rsrcdir'] = 'source' 418 | d['rbuilddir'] = '_build' 419 | # use binary mode, to avoid writing \r\n on Windows 420 | write_file(path.join(d['path'], 'Makefile'), 421 | template.render(makefile_template, d), '\n') 422 | 423 | ## install all the extensions specified in the extensions list 424 | for extension in d['toinstall']: 425 | install(extension) 426 | 427 | if silent: 428 | return 429 | print() 430 | print(bold(__('Finished: An initial directory structure has been created.'))) 431 | print() 432 | print(__('You should now populate your master file %s and create other documentation\n' 433 | 'source files. ') % masterfile, end='') 434 | print(__('Use the Makefile to build the docs, like so:\n' 435 | ' make builder')) 436 | print(__('where "builder" is one of the supported builders, ' 437 | 'e.g. jupyter, website or pdf.')) 438 | print() 439 | 440 | 441 | def valid_dir(d: Dict) -> bool: 442 | dir = d['path'] 443 | if not path.exists(dir): 444 | return True 445 | if not path.isdir(dir): 446 | return False 447 | 448 | if {'Makefile', 'make.bat'} & set(os.listdir(dir)): 449 | return False 450 | 451 | reserved_names = [ 452 | 'conf.py', 453 | d['dot'] + 'static', 454 | d['dot'] + 'templates', 455 | d['master'] + d['suffix'], 456 | ] 457 | if set(reserved_names) & set(os.listdir(dir)): 458 | return False 459 | 460 | return True 461 | 462 | 463 | # NEED TO ITERATE ON WHICH PARSER VARIABLES SHOULD BE NEEDED 464 | def get_parser() -> argparse.ArgumentParser: 465 | description = __( 466 | "\n" 467 | "Generate required files for a Jupinx project.\n" 468 | "\n" 469 | "jupinx-quickstart is an interactive tool that asks some questions about your\n" 470 | "project and then generates a complete documentation directory and sample\n" 471 | "Makefile to be used with jupinx-build.\n" 472 | ) 473 | parser = argparse.ArgumentParser( 474 | usage='%(prog)s', 475 | epilog=__("For more information, visit ."), 476 | description=description) 477 | return parser 478 | 479 | ## function to install packages via pip 480 | def install(package): 481 | subprocess.call([sys.executable, "-m", "pip", "install", package]) 482 | 483 | def main(argv: List[str] = sys.argv[1:]) -> int: 484 | sphinx.locale.setlocale(locale.LC_ALL, '') 485 | sphinx.locale.init_console(os.path.join(package_dir, 'locale'), 'sphinx') 486 | 487 | if not color_terminal(): 488 | nocolor() 489 | 490 | ## parse options 491 | parser = get_parser() 492 | try: 493 | args = parser.parse_args(argv) 494 | except SystemExit as err: 495 | return err.code 496 | 497 | d = vars(args) 498 | # delete None or False value 499 | d = {k: v for k, v in d.items() if v is not None} 500 | 501 | d.setdefault('extensions', []) 502 | # handle use of CSV-style extension values 503 | d.setdefault('toinstall', []) 504 | for ext in d['toinstall'][:]: 505 | if ',' in ext: 506 | d['toinstall'].remove(ext) 507 | d['toinstall'].extend(ext.split(',')) 508 | 509 | ## Supporting .rst as the default suffix 510 | d.setdefault('suffix','.rst') 511 | d.setdefault('master','index') 512 | 513 | ## specifying kernels 514 | kernel_obj = { 515 | 'python3': False, 516 | 'python2': False, 517 | 'julia-1.1': False 518 | } 519 | d.setdefault('kernels', kernel_obj) 520 | 521 | 522 | try: 523 | ask_user(d) 524 | except (KeyboardInterrupt, EOFError): 525 | print() 526 | print('[Interrupted.]') 527 | return 130 # 128 + SIGINT 528 | 529 | generate(d, overwrite=False) 530 | return 0 531 | 532 | 533 | if __name__ == '__main__': 534 | sys.exit(main(sys.argv[1:])) 535 | -------------------------------------------------------------------------------- /jupinx/templates/quickstart/Makefile_t: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Jupinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS = -c "./" 7 | SPHINXBUILD = python -msphinx 8 | SOURCEDIR = {{ rsrcdir }} 9 | BUILDDIR = {{ rbuilddir }} 10 | BUILDWEBSITE = {{ rbuilddir }}/website 11 | BUILDCOVERAGE = {{ rbuilddir }}/coverage 12 | BUILDPDF = {{ rbuilddir }}/pdf 13 | PORT = 8888 14 | FILES = 15 | 16 | # Put it first so that "make" without argument is like "make help". 17 | help: 18 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(FILES) $(SPHINXOPTS) $(O) 19 | 20 | .PHONY: help Makefile 21 | 22 | preview: 23 | ifneq (,$(filter $(target),website Website)) 24 | cd $(BUILDWEBSITE)/jupyter_html && python -m http.server $(PORT) 25 | else 26 | ifdef lecture 27 | cd $(BUILDDIR)/jupyter/ && jupyter notebook --port $(PORT) --port-retries=0 $(basename $(lecture)).ipynb 28 | else 29 | cd $(BUILDDIR)/jupyter/ && jupyter notebook --port $(PORT) --port-retries=0 30 | endif 31 | endif 32 | 33 | coverage: 34 | ifneq ($(strip $(parallel)),) 35 | @$(SPHINXBUILD) -M jupyter "$(SOURCEDIR)" "$(BUILDCOVERAGE)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_make_coverage=1 -D jupyter_execute_notebooks=1 -D jupyter_ignore_skip_test=0 -D jupyter_number_workers=$(parallel) 36 | else 37 | @$(SPHINXBUILD) -M jupyter "$(SOURCEDIR)" "$(BUILDCOVERAGE)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_make_coverage=1 -D jupyter_execute_notebooks=1 -D jupyter_ignore_skip_test=0 38 | endif 39 | 40 | website: 41 | ifneq ($(strip $(parallel)),) 42 | @$(SPHINXBUILD) -M jupyter "$(SOURCEDIR)" "$(BUILDWEBSITE)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_make_site=1 -D jupyter_generate_html=1 -D jupyter_download_nb=1 -D jupyter_execute_notebooks=1 -D jupyter_target_html=1 -D jupyter_images_markdown=0 -D jupyter_html_template="html.tpl" -D jupyter_coverage_dir=$(BUILDCOVERAGE) -D jupyter_number_workers=$(parallel) 43 | else 44 | @$(SPHINXBUILD) -M jupyter "$(SOURCEDIR)" "$(BUILDWEBSITE)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_make_site=1 -D jupyter_generate_html=1 -D jupyter_download_nb=1 -D jupyter_execute_notebooks=1 -D jupyter_target_html=1 -D jupyter_images_markdown=0 -D jupyter_html_template="html.tpl" -D jupyter_coverage_dir=$(BUILDCOVERAGE) 45 | endif 46 | 47 | pdf: 48 | ifneq ($(strip $(parallel)),) 49 | @$(SPHINXBUILD) -M jupyterpdf "$(SOURCEDIR)" "$(BUILDDIR)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_latex_template="latex.tpl" -D jupyter_images_markdown=1 -D jupyter_execute_notebooks=1 -D jupyter_target_pdf=1 -D jupyter_number_workers=$(parallel) 50 | else 51 | @$(SPHINXBUILD) -M jupyterpdf "$(SOURCEDIR)" "$(BUILDDIR)" $(FILES) $(SPHINXOPTS) $(O) -D jupyter_latex_template="latex.tpl" -D jupyter_images_markdown=1 -D jupyter_execute_notebooks=1 -D jupyter_target_pdf=1 52 | endif 53 | 54 | # Catch-all target: route all unknown targets to Sphinx using the new 55 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 56 | %: Makefile 57 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(FILES) $(SPHINXOPTS) $(O) 58 | 59 | -------------------------------------------------------------------------------- /jupinx/templates/quickstart/_static/fill_demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/jupinx/b23b0b2dce576e07ee2345e840b5b09b21c54edc/jupinx/templates/quickstart/_static/fill_demo1.png -------------------------------------------------------------------------------- /jupinx/templates/quickstart/conf.py_t: -------------------------------------------------------------------------------- 1 | # Configuration file for the Jupinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # http://www.sphinx-doc.org/en/master/config 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | {% if append_syspath -%} 14 | import os 15 | import sys 16 | sys.path.insert(0, {{ module_path | repr }}) 17 | {% else -%} 18 | # import os 19 | # import sys 20 | {% if module_path -%} 21 | # sys.path.insert(0, {{ module_path | repr }}) 22 | {% else -%} 23 | # sys.path.insert(0, os.path.abspath('.')) 24 | {% endif -%} 25 | {% endif %} 26 | 27 | # -- Project information ----------------------------------------------------- 28 | 29 | project = {{ project | repr }} 30 | copyright = {{ copyright | repr }} 31 | author = {{ author | repr }} 32 | 33 | {%- if version %} 34 | 35 | # The short X.Y version 36 | version = {{ version | repr }} 37 | {%- endif %} 38 | {%- if release %} 39 | 40 | # The full version, including alpha/beta/rc tags 41 | release = {{ release | repr }} 42 | {%- endif %} 43 | 44 | 45 | # -- General configuration --------------------------------------------------- 46 | 47 | # Add any Sphinx extension module names here, as strings. They can be 48 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 49 | # ones. 50 | extensions = [ 51 | {%- for ext in extensions %} 52 | '{{ ext }}', 53 | {%- endfor %} 54 | ] 55 | 56 | # Add any paths that contain templates here, relative to this directory. 57 | templates_path = ['{{ dot }}templates'] 58 | 59 | # The suffix(es) of source filenames. 60 | # You can specify multiple suffix as a list of string: 61 | # 62 | # source_suffix = ['.rst', '.md'] 63 | source_suffix = {{ suffix | repr }} 64 | 65 | # The master toctree document. 66 | master_doc = {{ master | repr }} 67 | 68 | {% if language -%} 69 | # The language for content autogenerated by Sphinx. Refer to documentation 70 | # for a list of supported languages. 71 | # 72 | # This is also used if you do content translation via gettext catalogs. 73 | # Usually you set "language" from the command line for these cases. 74 | language = {{ language | repr }} 75 | 76 | {% endif -%} 77 | # List of patterns, relative to source directory, that match files and 78 | # directories to ignore when looking for source files. 79 | # This pattern also affects html_static_path and html_extra_path. 80 | exclude_patterns = [{{ exclude_patterns }}] 81 | 82 | 83 | # -- Options for HTML output ------------------------------------------------- 84 | 85 | # The theme to use for HTML and HTML Help pages. See the documentation for 86 | # a list of builtin themes. 87 | # 88 | html_theme = 'alabaster' 89 | 90 | # Add any paths that contain custom static files (such as style sheets) here, 91 | # relative to this directory. They are copied after the builtin static files, 92 | # so a file named "default.css" will overwrite the builtin "default.css". 93 | html_static_path = ['{{ dot }}static'] 94 | {%- if extensions %} 95 | 96 | 97 | # -- Extension configuration ------------------------------------------------- 98 | {%- endif %} 99 | {%- if 'sphinx.ext.intersphinx' in extensions %} 100 | 101 | # -- Options for intersphinx extension --------------------------------------- 102 | 103 | # Example configuration for intersphinx: refer to the Python standard library. 104 | intersphinx_mapping = {'https://docs.python.org/': None} 105 | {%- endif %} 106 | {%- if 'sphinx.ext.todo' in extensions %} 107 | 108 | # -- Options for todo extension ---------------------------------------------- 109 | 110 | # If true, `todo` and `todoList` produce output, else they produce nothing. 111 | todo_include_todos = True 112 | {%- endif %} 113 | 114 | # -- jupyter build configuration --------------------------------------------------- 115 | jupyter_kernels = {{ kernels }} 116 | 117 | 118 | # -------------------------------------------- 119 | # jupyter Sphinx Extension conversion settings 120 | # -------------------------------------------- 121 | 122 | # Conversion Mode Settings 123 | # If "all", convert codes and texts into notebook 124 | # If "code", convert codes only 125 | jupyter_conversion_mode = "all" 126 | 127 | jupyter_write_metadata = False 128 | 129 | # Location for _static folder 130 | jupyter_static_file_path = ["source/_static"] 131 | 132 | # Configure jupyter headers 133 | jupyter_headers = { 134 | "python3": [ 135 | # nbformat.v4.new_code_cell("%autosave 0") #@mmcky please make this an option 136 | ], 137 | "julia": [ 138 | ], 139 | } 140 | 141 | # Filename for the file containing the welcome block 142 | jupyter_welcome_block = "" 143 | 144 | #Adjust links to target html (rather than ipynb) 145 | jupyter_target_html = False 146 | 147 | #path to download notebooks from 148 | jupyter_download_nb_urlpath = None 149 | 150 | #allow downloading of notebooks 151 | jupyter_download_nb = False 152 | 153 | #Use urlprefix images 154 | jupyter_images_urlpath = None 155 | 156 | #Allow ipython as a language synonym for blocks to be ipython highlighted 157 | jupyter_lang_synonyms = ["ipython"] 158 | 159 | #Execute skip-test code blocks for rendering of website (this will need to be ignored in coverage testing) 160 | jupyter_ignore_skip_test = True 161 | 162 | #allow execution of notebooks 163 | jupyter_execute_notebooks = False 164 | 165 | # Location of template folder for coverage reports 166 | jupyter_template_coverage_file_path = False 167 | 168 | # generate html from IPYNB files 169 | jupyter_generate_html = False 170 | 171 | # theme path 172 | jupyter_theme_path = "theme/minimal" 173 | 174 | # template path 175 | jupyter_template_path = "theme/minimal/templates" 176 | 177 | #make website 178 | jupyter_make_site = False 179 | 180 | #force markdown image inclusion 181 | jupyter_images_markdown = True 182 | 183 | #This is set true by default to pass html to the notebooks 184 | jupyter_allow_html_only=True 185 | -------------------------------------------------------------------------------- /jupinx/templates/quickstart/demo_notebook.rst_t: -------------------------------------------------------------------------------- 1 | Simple Notebook Example 2 | ======================= 3 | 4 | This provides a notebook that demonstrates the different 5 | features available in the `sphinxcontrib.jupyter `__ 6 | extension. 7 | 8 | Text will appear as a markdown cell in the notebook split by code-blocks. 9 | 10 | To add a code block you can use ``code-block`` directives such as: 11 | 12 | .. code-block:: python3 13 | 14 | %matplotlib inline 15 | 16 | .. code-block:: python3 17 | 18 | """ 19 | ================== 20 | A simple Fill plot 21 | ================== 22 | 23 | This example showcases the most basic fill plot a user can do with matplotlib. 24 | """ 25 | import numpy as np 26 | import matplotlib.pyplot as plt 27 | 28 | x = np.linspace(0, 1, 500) 29 | y = np.sin(4 * np.pi * x) * np.exp(-5 * x) 30 | 31 | fig, ax = plt.subplots() 32 | 33 | ax.fill(x, y, zorder=10) 34 | ax.grid(True, zorder=5) 35 | plt.show() 36 | 37 | Figures can be include using the **figure** directive 38 | 39 | .. figure:: _static/fill_demo1.png 40 | 41 | Math 42 | ---- 43 | 44 | Math will flow through to the Jupyter notebook and will be rendered in place by mathjax 45 | 46 | .. math:: 47 | 48 | \mathbb P\{z = v \mid x \} 49 | = \begin{cases} 50 | f_0(v) & \mbox{if } x = x_0, \\ 51 | f_1(v) & \mbox{if } x = x_1 52 | \end{cases} 53 | 54 | Tables 55 | ------ 56 | 57 | The extension supports the conversion of **simple** rst tables. 58 | 59 | +------------+------------+-----------+ 60 | | Header 1 | Header 2 | Header 3 | 61 | +============+============+===========+ 62 | | body row 1 | column 2 | column 3 | 63 | +------------+------------+-----------+ 64 | | body row 2 | column 2 | column 3 | 65 | +------------+------------+-----------+ -------------------------------------------------------------------------------- /jupinx/templates/quickstart/master_doc.rst_t: -------------------------------------------------------------------------------- 1 | .. {{ project }} documentation master file, created by 2 | sphinx-quickstart on {{ now }}. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to {{ project }}'s documentation! 7 | ==========={{ project_underline }}================= 8 | 9 | .. toctree:: 10 | :maxdepth: {{ mastertocmaxdepth }} 11 | :caption: Contents: 12 | 13 | demo_notebook 14 | {{ mastertoctree }} 15 | 16 | Indices and tables 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | 23 | -------------------------------------------------------------------------------- /jupinx/theme/minimal/README.md: -------------------------------------------------------------------------------- 1 | # Minimal Theme 2 | 3 | This provides a minimal theme for sphinx-quickstart which will allow 4 | 5 | 1. `html`, and 6 | 2. `pdf` 7 | 8 | conversion. -------------------------------------------------------------------------------- /jupinx/theme/minimal/static/css/base.css: -------------------------------------------------------------------------------- 1 | /* base.css v1.0 */ 2 | 3 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} 4 | /*! HTML5 Boilerplate v7.2.0 | MIT License | https://html5boilerplate.com/ */html{color:#222;font-size:1em;line-height:1.4}::-moz-selection{background:#b3d4fc;text-shadow:none}::selection{background:#b3d4fc;text-shadow:none}hr{display:block;height:1px;border:0;border-top:1px solid #ccc;margin:1em 0;padding:0}audio,canvas,iframe,img,svg,video{vertical-align:middle}fieldset{border:0;margin:0;padding:0}textarea{resize:vertical}.browserupgrade{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.hidden{display:none!important}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.sr-only.focusable:active,.sr-only.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;white-space:inherit;width:auto}.invisible{visibility:hidden}.clearfix:after,.clearfix:before{content:" ";display:table}.clearfix:after{clear:both}@media print{*,:after,:before{background:0 0!important;color:#000!important;-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}} 5 | 6 | /* Elements */ 7 | body { 8 | color:#444; 9 | background: #FFFFFF; 10 | font-family: Georgia, serif; 11 | font-size:1rem; 12 | line-height: 1.4; 13 | text-rendering: optimizeLegibility; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | ul li, ol li { 18 | margin: 0.5em 0; 19 | } 20 | a { 21 | overflow-wrap: break-word; 22 | } 23 | pre { 24 | white-space: pre-wrap; 25 | word-wrap: break-word; 26 | } 27 | cite, code, tt { 28 | font-family: monospace; 29 | letter-spacing: 0.01em; 30 | background-color: #efefef; 31 | font-style: normal; 32 | border: 1px dotted #cccccc; 33 | border-radius: 2px; 34 | padding: 0 2px; 35 | font-size: 0.9em; 36 | overflow-wrap: break-word; 37 | } 38 | 39 | /* Framing elements */ 40 | .wrapper { 41 | position: relative; 42 | } 43 | .content { 44 | padding: 2rem 4rem; 45 | position: relative; 46 | max-width: 1024px; 47 | margin: 0 auto; 48 | box-sizing: border-box; 49 | } 50 | 51 | /* Header */ 52 | .header { 53 | padding: 2rem 4rem; 54 | border-bottom: 1px solid #444; 55 | } 56 | .site-title { 57 | font-size:2.5em; 58 | margin:0 0 0 0; 59 | line-height: 1; 60 | text-align: center; 61 | } 62 | .site-title a { 63 | color:#444; 64 | text-decoration: none; 65 | } 66 | .header-badge { 67 | text-align: right; 68 | } 69 | 70 | /* Footer */ 71 | .footer { 72 | font-size:0.8em; 73 | border-top: 1px solid #444; 74 | position: relative; 75 | padding: 2rem 4rem; 76 | margin: 0 auto; 77 | } 78 | 79 | /* Footnotes */ 80 | .footnote-reference { 81 | vertical-align: super; 82 | font-size: 0.9em; 83 | line-height: 1; 84 | } 85 | 86 | /* Tables */ 87 | .content table { 88 | max-width: 100%; 89 | border-collapse: collapse; 90 | border:0; 91 | background-color: transparent; 92 | } 93 | .content table tbody tr:nth-child(odd) { 94 | background-color: #f7f7f7; 95 | } 96 | .content table td, .content table th { 97 | padding: .25rem 0.75rem; 98 | text-align: left; 99 | vertical-align: top; 100 | border:0; 101 | } 102 | .content table th { 103 | font-weight: bold; 104 | } 105 | .content table thead tr th { 106 | text-align:left !important; 107 | } 108 | .content table thead th, .content table thead td { 109 | vertical-align: bottom; 110 | border:0; 111 | border-top:0; 112 | border-bottom: 1px solid #e1e1e1; 113 | } 114 | div.content-table ~ table { 115 | border: 0; 116 | border-collapse: collapse; 117 | } 118 | div.content-table ~ table td, div.content-table ~ table th { 119 | padding: 1px 8px 1px 5px; 120 | border-top: 0; 121 | border-left: 0; 122 | border-right: 0; 123 | border-bottom: 1px solid #aaa; 124 | } 125 | 126 | /* Collapsable code blocks */ 127 | div[class^='collapse'] .highlight { 128 | height: 22.4em; 129 | overflow: hidden; 130 | margin-bottom: 0; 131 | } 132 | div[class^='collapse'].expanded .highlight { 133 | height:auto; 134 | } 135 | div[class^='collapse'] .highlight:after { 136 | content : ""; 137 | position : absolute; 138 | z-index : 1; 139 | bottom : 0; 140 | left : 0; 141 | pointer-events : none; 142 | background: url(/_static/img/code-block-fade.png) repeat-x bottom left; 143 | width : 100%; 144 | height : 100%; 145 | } 146 | div[class^='collapse'].expanded .highlight:after { 147 | content: none; 148 | } 149 | div[class^='collapse'] .toggle { 150 | display: block; 151 | border: 1px solid #ddd; 152 | border-width: 0px 1px 1px 1px; 153 | padding: 0.5rem 25px; 154 | outline: 0; 155 | position: relative; 156 | text-align: center; 157 | } 158 | div[class^='collapse'] .toggle:hover { 159 | text-decoration: none; 160 | background: #f7f7f7; 161 | } 162 | div[class^='collapse'] .toggle span { 163 | color: #444; 164 | position: relative; 165 | top: 3px; 166 | left: -5px; 167 | } 168 | div[class^='collapse'] .toggle em { 169 | font-style: normal; 170 | } 171 | div.collapse-5 .highlight {height:7em;}div.collapse-6 .highlight {height:8.4em;}div.collapse-7 .highlight {height:9.8em;}div.collapse-8 .highlight {height:11.2em;}div.collapse-9 .highlight {height:12.6em;}div.collapse-10 .highlight {height:14em;}div.collapse-11 .highlight {height:15.4em;}div.collapse-12 .highlight {height:16.8em;}div.collapse-13 .highlight {height:18.2em;}div.collapse-14 .highlight {height:19.6em;}div.collapse-15 .highlight {height:21em;}div.collapse-16 .highlight {height:22.4em;}div.collapse-17 .highlight {height:23.8em;}div.collapse-18 .highlight {height:25.2em;}div.collapse-19 .highlight {height:26.6em;}div.collapse-20 .highlight {height:28em;}div.collapse-21 .highlight {height:29.4em;}div.collapse-22 .highlight {height:30.8em;}div.collapse-23 .highlight {height:32.2em;}div.collapse-24 .highlight {height:33.6em;}div.collapse-25 .highlight {height:35em;} 172 | 173 | /* Lecture page hide TOC heading "Contents" and style list below */ 174 | #Contents {border: 0;clip: rect(0 0 0 0);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;} 175 | #Contents + ul {list-style:none;padding: 0 !important; border: 1px solid #ddd !important; border-width: 0 0 0 1px !important;margin:0 0 0 20px !important;} 176 | #Contents + ul>li {margin:0;} 177 | #Contents + ul>li>a {display: none;} 178 | #Contents + ul>li>ul {list-style: disc;} 179 | #Contents + ul>li>ul>li {margin:0;} 180 | 181 | /* Lecture heading anchor links */ 182 | .anchor-link {visibility: hidden;text-decoration: none;color:#555;margin-left: 6px;padding: 0 4px 0 4px;font-family: "Source Sans Pro", sans-serif;font-size: 0.8em;} 183 | .anchor-link:hover {color:#555;} 184 | *:hover>.anchor-link {visibility: visible;} 185 | 186 | /* Output cell styling with "In" "Out" placement */ 187 | .cell .input, .cell .output {position: relative;} 188 | .cell .output .prompt, .cell .input .prompt {visibility:hidden;position: absolute;top:0rem;left: -55px;width:45px;} 189 | .cell .output .prompt:before, .cell .input .prompt:before {visibility:visible;position:absolute;top:0rem;right:0;content:"Out"; font-weight: bold;font-size: 16px;text-align: right;color:#D84315;font-family:monospace, serif;font-weight: 400;} 190 | .cell .input .prompt:before {content:"In";color:#303F9F;top:0.25rem;} 191 | 192 | /* Anchor link on headings, hidden until hover */ 193 | .headerlink {visibility: hidden;text-decoration: none;color:#555;margin-left: 6px;padding: 0 4px 0 4px;font-family: "Source Sans Pro", sans-serif;font-size: 0.8em;} 194 | .headerlink:hover {color:#555;} 195 | *:hover>.headerlink {visibility: visible;} 196 | 197 | /* Prevent images from breaking out of their container */ 198 | .rendered_html img {max-width: 100%;display: block;margin: 0 auto;} 199 | .output_png img {max-width: 100%;display: block;margin: 0 auto;} 200 | 201 | /* Maths */ 202 | .math {color:#333;margin: 2em 0;} 203 | a .math {color: #0072bc;} 204 | span.math {font-size:0.92rem;} 205 | .MathJax {color:#333;margin: 2em 0;} 206 | a .MathJax {color: #0072bc;} 207 | span.MathJax {font-size:0.92rem;} 208 | 209 | /* Status page */ 210 | .status-table { 211 | width:100%; 212 | border:0; 213 | } 214 | .status-table tr:nth-of-type(even) { 215 | background-color: #f9f9f9; 216 | } 217 | .status-table tr th { 218 | vertical-align: bottom; 219 | border-bottom: 2px solid #ddd; 220 | padding: 8px; 221 | line-height: 1.42857143; 222 | text-align: left; 223 | font-weight: bold; 224 | } 225 | .status-table tr td { 226 | padding: 8px; 227 | line-height: 1.42857143; 228 | vertical-align: top; 229 | border-top: 1px solid #ddd; 230 | } 231 | 232 | /* Device media styles */ 233 | @media only screen and (max-width: 1024px) { 234 | } 235 | @media only screen and (max-width: 768px) { 236 | .cell .output .prompt:before, .cell .input .prompt:before { 237 | font-size: 14px; 238 | } 239 | .status-table-container { 240 | overflow-x: scroll; 241 | } 242 | .status-table tr th { 243 | display: none; 244 | } 245 | .status-table tr td { 246 | display: block; 247 | } 248 | } 249 | 250 | /* Syntax highlighting */ 251 | .highlight {padding:0 10px;border:1px solid #e1e1e1;margin:0.5rem 0;background:#f7f7f7;border-radius: 2px;} 252 | .highlight {position: relative;} 253 | .highlight:before {position: absolute;top:0.25rem;left:-40px;font-weight: bold;width:25px;text-align: left;color:#303F9F;font-family:monospace, serif;font-weight: 400;} 254 | .highlight-none .highlight:before {content: "Out";color: #D84315;top:0rem;} 255 | .highlight-none .highlight {background:#ffffff;border:0;padding:0;margin:0rem 0 1.5rem 0;} 256 | .highlight pre {overflow-x: auto;white-space: pre;word-wrap: normal;margin:0.25rem 0;} 257 | .highlight .hll { background-color: #ffffcc } 258 | .highlight .c { color: #60a0b0; font-style: italic } /* Comment */ 259 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 260 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 261 | .highlight .o { color: #666666 } /* Operator */ 262 | .highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */ 263 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 264 | .highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */ 265 | .highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */ 266 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 267 | .highlight .ge { font-style: italic } /* Generic.Emph */ 268 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 269 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 270 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 271 | .highlight .go { color: #888888 } /* Generic.Output */ 272 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 273 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 274 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 275 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 276 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 277 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 278 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 279 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 280 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 281 | .highlight .kt { color: #902000 } /* Keyword.Type */ 282 | .highlight .m { color: #40a070 } /* Literal.Number */ 283 | .highlight .s { color: #4070a0 } /* Literal.String */ 284 | .highlight .na { color: #4070a0 } /* Name.Attribute */ 285 | .highlight .nb { color: #007020 } /* Name.Builtin */ 286 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 287 | .highlight .no { color: #60add5 } /* Name.Constant */ 288 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 289 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 290 | .highlight .ne { color: #007020 } /* Name.Exception */ 291 | .highlight .nf { color: #06287e } /* Name.Function */ 292 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 293 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 294 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 295 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ 296 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 297 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 298 | .highlight .mf { color: #40a070 } /* Literal.Number.Float */ 299 | .highlight .mh { color: #40a070 } /* Literal.Number.Hex */ 300 | .highlight .mi { color: #40a070 } /* Literal.Number.Integer */ 301 | .highlight .mo { color: #40a070 } /* Literal.Number.Oct */ 302 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 303 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 304 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 305 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 306 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 307 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 308 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 309 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 310 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 311 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 312 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 313 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 314 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 315 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 316 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 317 | .highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */ 318 | 319 | /* CSS font colors for translated ANSI colors. */ 320 | .ansi-bold,.ansibold{font-weight:700}.ansi-black-fg{color:#3E424D}.ansi-black-bg{background-color:#3E424D}.ansi-black-intense-fg{color:#282C36}.ansi-black-intense-bg{background-color:#282C36}.ansi-red-fg{color:#E75C58}.ansi-red-bg{background-color:#E75C58}.ansi-red-intense-fg{color:#B22B31}.ansi-red-intense-bg{background-color:#B22B31}.ansi-green-fg{color:#00A250}.ansi-green-bg{background-color:#00A250}.ansi-green-intense-fg{color:#007427}.ansi-green-intense-bg{background-color:#007427}.ansi-yellow-fg{color:#DDB62B}.ansi-yellow-bg{background-color:#DDB62B}.ansi-yellow-intense-fg{color:#B27D12}.ansi-yellow-intense-bg{background-color:#B27D12}.ansi-blue-fg{color:#208FFB}.ansi-blue-bg{background-color:#208FFB}.ansi-blue-intense-fg{color:#0065CA}.ansi-blue-intense-bg{background-color:#0065CA}.ansi-magenta-fg{color:#D160C4}.ansi-magenta-bg{background-color:#D160C4}.ansi-magenta-intense-fg{color:#A03196}.ansi-magenta-intense-bg{background-color:#A03196}.ansi-cyan-fg{color:#60C6C8}.ansi-cyan-bg{background-color:#60C6C8}.ansi-cyan-intense-fg{color:#258F8F}.ansi-cyan-intense-bg{background-color:#258F8F}.ansi-white-fg{color:#C5C1B4}.ansi-white-bg{background-color:#C5C1B4}.ansi-white-intense-fg{color:#A1A6B2}.ansi-white-intense-bg{background-color:#A1A6B2}.ansi-default-inverse-bg,.ansibgblack{background-color:#000}.ansi-default-inverse-fg{color:#FFF}.ansi-underline{text-decoration:underline}.ansi-inverse{outline:dotted .5px}.ansiblack{color:#000}.ansired{color:#8b0000}.ansigreen{color:#006400}.ansiyellow{color:#c4a000}.ansiblue{color:#00008b}.ansipurple{color:#9400d3}.ansicyan{color:#4682b4}.ansigray{color:gray}.ansibgred{background-color:red}.ansibggreen{background-color:green}.ansibgyellow{background-color:#ff0}.ansibgblue{background-color:#00f}.ansibgpurple{background-color:#ff00ff}.ansibgcyan{background-color:#0ff}.ansibggray{background-color:gray} 321 | -------------------------------------------------------------------------------- /jupinx/theme/minimal/static/img/code-block-fade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/jupinx/b23b0b2dce576e07ee2345e840b5b09b21c54edc/jupinx/theme/minimal/static/img/code-block-fade.png -------------------------------------------------------------------------------- /jupinx/theme/minimal/static/js/base.js: -------------------------------------------------------------------------------- 1 | // base.js v1.0 2 | 3 | 4 | // Declare MathJax Macros for the Appropriate Macros 5 | MathJax.Hub.Config({ 6 | TeX: { 7 | Macros: { 8 | Var: "\\mathop{\\mathrm{Var}}", 9 | trace: "\\mathop{\\mathrm{trace}}", 10 | argmax: "\\mathop{\\mathrm{arg\\,max}}", 11 | argmin: "\\mathop{\\mathrm{arg\\,min}}", 12 | proj: "\\mathop{\\mathrm{proj}}", 13 | col: "\\mathop{\\mathrm{col}}", 14 | Span: "\\mathop{\\mathrm{span}}", 15 | epsilon: "\\varepsilon", 16 | EE: "\\mathbb{E}", 17 | PP: "\\mathbb{P}", 18 | RR: "\\mathbb{R}", 19 | NN: "\\mathbb{N}", 20 | ZZ: "\\mathbb{Z}", 21 | aA: "\\mathcal{A}", 22 | bB: "\\mathcal{B}", 23 | cC: "\\mathcal{C}", 24 | dD: "\\mathcal{D}", 25 | eE: "\\mathcal{E}", 26 | fF: "\\mathcal{F}", 27 | gG: "\\mathcal{G}", 28 | hH: "\\mathcal{H}", 29 | } 30 | } 31 | }); 32 | MathJax.Hub.Config({ 33 | tex2jax: { 34 | inlineMath: [ ['$','$'], ['\\(','\\)'] ], 35 | processEscapes: true 36 | } 37 | }); 38 | 39 | 40 | /* Collapsed code block */ 41 | 42 | const collapsableCodeBlocks = document.querySelectorAll("div[class^='collapse'] .highlight"); 43 | for (var i = 0; i < collapsableCodeBlocks.length; i++) { 44 | const toggleContainer = document.createElement('div'); 45 | toggleContainer.innerHTML = 'Show more...'; 46 | collapsableCodeBlocks[i].parentNode.insertBefore(toggleContainer, collapsableCodeBlocks[i].nextSibling); 47 | } 48 | 49 | const collapsableCodeToggles = document.querySelectorAll("div[class^='collapse'] .toggle"); 50 | for (var i = 0; i < collapsableCodeToggles.length; i++) { 51 | collapsableCodeToggles[i].addEventListener('click', function(e) { 52 | e.preventDefault(); 53 | var codeBlock = this.closest('div[class^="collapse"]'); 54 | if ( codeBlock.classList.contains('expanded') ) { 55 | codeBlock.classList.remove('expanded'); 56 | this.style.display = 'none'; 57 | this.nextSibling.style.display = 'block'; 58 | } else { 59 | codeBlock.classList.add('expanded'); 60 | this.style.display = 'none'; 61 | this.previousSibling.style.display = 'block'; 62 | } 63 | }); 64 | } 65 | 66 | 67 | /* Wrap container around all tables allowing hirizontal scroll */ 68 | 69 | const contentTables = document.querySelectorAll(".content table"); 70 | for (var i = 0; i < contentTables.length; i++) { 71 | var wrapper = document.createElement('div'); 72 | wrapper.classList.add('table-container'); 73 | contentTables[i].parentNode.insertBefore(wrapper, contentTables[i]); 74 | wrapper.appendChild(contentTables[i]); 75 | } 76 | 77 | 78 | // Populate status page from code execution results JSON 79 | 80 | function loadCodeExecutionJSON(callback) { 81 | var xobj = new XMLHttpRequest(); 82 | xobj.overrideMimeType("application/json"); 83 | xobj.open('GET', '_static/code-execution-results.json', true); // Replace 'appDataServices' with the path to your file 84 | xobj.onreadystatechange = function () { 85 | if (xobj.readyState == 4 && xobj.status == "200") { 86 | // Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode 87 | callback(xobj.responseText); 88 | } 89 | }; 90 | xobj.send(null); 91 | } 92 | 93 | if ( document.getElementById('status_table') ) { 94 | 95 | loadCodeExecutionJSON(function(response) { 96 | // Parsing JSON string into object 97 | var data = JSON.parse(response); 98 | var status_data = []; 99 | var last_test_time = data.run_time; 100 | document.getElementById('last_test_time').textContent = last_test_time; 101 | for (var key in data.results) 102 | { 103 | var new_record = {}; 104 | new_record['name'] = data.results[key].filename; 105 | new_record['runtime'] = data.results[key].runtime; 106 | new_record['extension'] = data.results[key].extension; 107 | new_record['result'] = data.results[key].num_errors; 108 | new_record['language'] = data.results[key].language; 109 | 110 | status_data.push(new_record); 111 | } 112 | 113 | // empty the table 114 | var table = document.getElementById("status_table"); 115 | while (table.firstChild) 116 | table.removeChild(table.firstChild); 117 | var rawHTML = "Lecture FileLanguageRunning Time"; 118 | table.innerHTML = rawHTML; 119 | // add the data 120 | for (var i = 0; i < status_data.length; i ++) 121 | { 122 | var table = document.getElementById("status_table"); 123 | var row = table.insertRow(-1); 124 | row.setAttribute("id", status_data[i]['name'], 0); 125 | 126 | // Insert new cells ( elements) at the 1st and 2nd position of the "new" element: 127 | var lectureCell = row.insertCell(0); 128 | var langCell = row.insertCell(1); 129 | var runtimeCell = row.insertCell(2); 130 | var statusCell = row.insertCell(3); 131 | var badge, status, color, lang, link; 132 | 133 | if (status_data[i]['result'] === 0) 134 | { 135 | status = "Passing"; 136 | color = "brightgreen"; 137 | } 138 | else if (status_data[i]['result'] === 1) 139 | { 140 | status = "Failing"; 141 | color = "red"; 142 | } 143 | else if (status_data[i]['result'] === -1) { 144 | status = "Not available"; 145 | color = "lightgrey"; 146 | } 147 | 148 | link = '/' + status_data[i]['name'] + '.html'; 149 | 150 | badge = ''; 151 | 152 | // Add some text to the new cells: 153 | lectureCell.innerHTML = status_data[i]['name']; 154 | langCell.innerHTML = status_data[i]['language']; 155 | runtimeCell.innerHTML = status_data[i]['runtime']; 156 | statusCell.innerHTML = badge; 157 | 158 | 159 | } 160 | }) 161 | } 162 | 163 | 164 | // Show executability status badge in header 165 | 166 | const LECTURE_OK = 0; 167 | const LECTURE_FAILED = 1; 168 | const LECTURE_ERROR = -1; 169 | 170 | function update_page_badge(page_status) 171 | { 172 | var badge = document.getElementById("executability_status_badge"); 173 | var status, color; 174 | 175 | if (page_status === LECTURE_OK) 176 | { 177 | status = "Passing"; 178 | color = "brightgreen"; 179 | } 180 | else if (page_status == LECTURE_FAILED) 181 | { 182 | status = "Failing"; 183 | color = "red"; 184 | } 185 | else if (page_status == LECTURE_ERROR) 186 | { 187 | status = "Not available"; 188 | color = "lightgrey"; 189 | } 190 | else 191 | { 192 | console.log("Panic! Invalid parameter passed to update_page_badge()."); 193 | } 194 | 195 | badge.innerHTML = ''; 196 | 197 | //badge.style.display="block"; 198 | 199 | return; 200 | } 201 | 202 | function determine_page_status(status_data) 203 | { 204 | var path = window.location.pathname; 205 | var filename_parts = path.split("/"); 206 | var filename = filename_parts.pop(); 207 | 208 | var lecture_name = filename.split(".")[0].toLowerCase(); 209 | 210 | var res = LECTURE_ERROR; 211 | 212 | for (var i = 0; i < status_data.length; i ++) 213 | { 214 | if (status_data[i]['name'].split('/').pop() === lecture_name) 215 | { 216 | if (status_data[i]['result'] === 0) 217 | { 218 | res = LECTURE_OK; 219 | } 220 | else 221 | { 222 | res = LECTURE_FAILED; 223 | } 224 | } 225 | } 226 | return res; 227 | } 228 | 229 | function load_this_page_badge() 230 | { 231 | loadCodeExecutionJSON(function(response) { 232 | // Parsing JSON string into object 233 | var data = JSON.parse(response); 234 | status_data = []; 235 | for (var key in data.results) 236 | { 237 | var new_record = {}; 238 | new_record['name'] = data.results[key].filename; 239 | new_record['runtime'] = data.results[key].runtime; 240 | new_record['extension'] = data.results[key].extension; 241 | new_record['result'] = data.results[key].num_errors; 242 | new_record['language'] = data.results[key].language; 243 | status_data.push(new_record); 244 | } 245 | var page_status = determine_page_status(status_data); 246 | update_page_badge(page_status); 247 | }); 248 | } 249 | 250 | function get_badge(percentage) 251 | { 252 | var color, badge; 253 | 254 | if (percentage > -1) 255 | { 256 | if ( percentage < 50 ) { 257 | color = 'red'; 258 | } else { 259 | color = 'brightgreen'; 260 | } 261 | badge = 'https://img.shields.io/badge/Total%20coverage-' + percentage + '%25-' + color + '.svg'; 262 | } else { 263 | badge = 'https://img.shields.io/badge/Total%20coverage-not%20available-lightgrey.svg>'; 264 | } 265 | return badge; 266 | } 267 | 268 | function load_percentages() 269 | { 270 | var number_of_lectures = {}; 271 | var number_which_passed = {}; 272 | var keys_list = []; 273 | var combined_percentage; 274 | 275 | loadCodeExecutionJSON(function(response) { 276 | // Parsing JSON string into object 277 | var data = JSON.parse(response); 278 | for (var key in data.results) 279 | { 280 | if (data.results[key].num_errors === 0) 281 | { 282 | if (!(data.results[key].extension in number_which_passed)) 283 | { 284 | number_which_passed[data.results[key].extension] = 0; 285 | keys_list.push(data.results[key].extension); 286 | } 287 | number_which_passed[data.results[key].extension] += 1; 288 | } 289 | 290 | if (!(data.results[key].extension in number_of_lectures)) 291 | { 292 | number_of_lectures[data.results[key].extension] = 0; 293 | } 294 | number_of_lectures[data.results[key].extension] += 1; 295 | } 296 | 297 | var percentages = {}; 298 | var total_lectures = 0; 299 | var total_passing = 0; 300 | for (var k in keys_list) 301 | { 302 | key = keys_list[k]; 303 | 304 | percentages[key] = 0; 305 | if (number_of_lectures[key] === 0) 306 | { 307 | // An appropriate value for this is yet to be determined. 308 | percentages[key] = 100; 309 | } 310 | else 311 | { 312 | percentages[key] = Math.floor(100 * number_which_passed[key] / number_of_lectures[key]); 313 | } 314 | 315 | // Sensible boundary checking. 316 | if (percentages[key] < 0 || percentages[key] > 100) 317 | { 318 | percentages[key] = -1; 319 | } 320 | 321 | total_lectures += number_of_lectures[key]; 322 | total_passing += number_which_passed[key]; 323 | } 324 | 325 | if (total_lectures === 0) 326 | { 327 | combined_percentage = 0; 328 | } 329 | else 330 | { 331 | combined_percentage = Math.floor(100 * total_passing / total_lectures); 332 | } 333 | 334 | var badge = document.getElementById("coverage_badge"); 335 | badge.innerHTML = ''; 336 | 337 | }); 338 | 339 | } 340 | 341 | if ( document.getElementById('executability_status_badge') ) { 342 | load_this_page_badge(); 343 | } 344 | 345 | if ( document.getElementById('coverage_badge') ) { 346 | load_percentages(); 347 | } -------------------------------------------------------------------------------- /jupinx/theme/minimal/templates/error_report_template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Jupyter Script Test Execution - Error Report 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Error Report - Generated {DATETIME}

11 | 12 |

13 | Overview 14 |

15 | 16 | {ERROR_SUMMARY} 17 | 18 | {NOTEBOOK_LOOP} 19 | 20 | 21 | -------------------------------------------------------------------------------- /jupinx/theme/minimal/templates/html.tpl: -------------------------------------------------------------------------------- 1 | {%- extends 'display_priority.tpl' -%} 2 | 3 | {% set site_title = 'Documentation' %} 4 | {% set nb_title = nb.metadata.get('title', '') %} 5 | {% set nb_filename = nb.metadata.get('filename', '') %} 6 | {% set nb_filename_with_path = nb.metadata.get('filename_with_path','') %} 7 | {% set indexPage = nb_filename.startswith('index') %} 8 | {% set download_nb = nb.metadata.get('download_nb','') %} 9 | {% set download_nb_path = nb.metadata.get('download_nb_path','') %} 10 | {% if nb_filename.endswith('.rst') %} 11 | {% set nb_filename = nb_filename[:-4] %} 12 | {% endif %} 13 | 14 | {%- block header %} 15 | 16 | 17 | 18 | 19 | {% if nb_filename == 'index' %} 20 | {{ site_title }} 21 | {% else %} 22 | {{nb_title}} – {{ site_title }} 23 | {% endif %} 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
38 | 39 |
40 | 41 |

{{ site_title }}

42 | 43 |

Skip to content

44 | 45 |
46 | 47 |
48 | 49 | {% if indexPage or nb_filename == 'status' %} 50 |
51 | {% else %} 52 |
53 | {% endif %} 54 | 55 |
56 | 57 |
58 | 59 |
60 | 61 |
62 | 63 | 64 | 65 |
66 | 67 | {%- endblock header-%} 68 | 69 | {% block codecell %} 70 | {% set html_class = cell['metadata'].get('html-class', {}) %} 71 |
72 | {{ super() }} 73 |
74 | {%- endblock codecell %} 75 | 76 | {% block input_group -%} 77 |
78 | {{ super() }} 79 |
80 | {% endblock input_group %} 81 | 82 | {% block output_group %} 83 |
84 |
85 | {{ super() }} 86 |
87 |
88 | {% endblock output_group %} 89 | 90 | {% block in_prompt -%} 91 |
92 | {%- if cell.execution_count is defined -%} 93 | In [{{ cell.execution_count|replace(None, " ") }}]: 94 | {%- else -%} 95 | In [ ]: 96 | {%- endif -%} 97 |
98 | {%- endblock in_prompt %} 99 | 100 | {% block empty_in_prompt -%} 101 |
102 |
103 | {%- endblock empty_in_prompt %} 104 | 105 | {# 106 | output_prompt doesn't do anything in HTML, 107 | because there is a prompt div in each output area (see output block) 108 | #} 109 | {% block output_prompt %} 110 | {% endblock output_prompt %} 111 | 112 | {% block input %} 113 |
114 |
115 | {{ cell.source | highlight_code(metadata=cell.metadata) }} 116 |
117 |
118 | {%- endblock input %} 119 | 120 | {% block output_area_prompt %} 121 | {%- if output.output_type == 'execute_result' -%} 122 |
123 | {%- if cell.execution_count is defined -%} 124 | Out[{{ cell.execution_count|replace(None, " ") }}]: 125 | {%- else -%} 126 | Out[ ]: 127 | {%- endif -%} 128 | {%- else -%} 129 |
130 | {%- endif -%} 131 |
132 | {% endblock output_area_prompt %} 133 | 134 | {% block output %} 135 |
136 | {% if resources.global_content_filter.include_output_prompt %} 137 | {{ self.output_area_prompt() }} 138 | {% endif %} 139 | {{ super() }} 140 |
141 | {% endblock output %} 142 | 143 | {% block markdowncell scoped %} 144 | {% set html_class = cell['metadata'].get('html-class', {}) %} 145 |
146 | {%- if resources.global_content_filter.include_input_prompt-%} 147 | {{ self.empty_in_prompt() }} 148 | {%- endif -%} 149 |
150 |
151 | {{ cell.source | markdown2html | strip_files_prefix }} 152 |
153 |
154 |
155 | {%- endblock markdowncell %} 156 | 157 | {% block unknowncell scoped %} 158 | unknown type {{ cell.type }} 159 | {% endblock unknowncell %} 160 | 161 | {% block execute_result -%} 162 | {%- set extra_class="output_execute_result" -%} 163 | {% block data_priority scoped %} 164 | {{ super() }} 165 | {% endblock data_priority %} 166 | {%- set extra_class="" -%} 167 | {%- endblock execute_result %} 168 | 169 | {% block stream_stdout -%} 170 |
171 |
172 | {{- output.text | ansi2html -}}
173 | 
174 |
175 | {%- endblock stream_stdout %} 176 | 177 | {% block stream_stderr -%} 178 |
179 |
180 | {{- output.text | ansi2html -}}
181 | 
182 |
183 | {%- endblock stream_stderr %} 184 | 185 | {% block data_svg scoped -%} 186 |
187 | {%- if output.svg_filename %} 188 | 193 | {%- endblock data_svg %} 194 | 195 | {% block data_html scoped -%} 196 |
197 | {{ output.data['text/html'] }} 198 |
199 | {%- endblock data_html %} 200 | 201 | {% block data_markdown scoped -%} 202 |
203 | {{ output.data['text/markdown'] | markdown2html }} 204 |
205 | {%- endblock data_markdown %} 206 | 207 | {% block data_png scoped %} 208 |
209 | {%- if 'image/png' in output.metadata.get('filenames', {}) %} 210 | 226 |
227 | {%- endblock data_png %} 228 | 229 | {% block data_jpg scoped %} 230 |
231 | {%- if 'image/jpeg' in output.metadata.get('filenames', {}) %} 232 | 248 |
249 | {%- endblock data_jpg %} 250 | 251 | {% block data_latex scoped %} 252 |
253 | {{ output.data['text/latex'] }} 254 |
255 | {%- endblock data_latex %} 256 | 257 | {% block error -%} 258 |
259 |
260 | {{- super() -}}
261 | 
262 |
263 | {%- endblock error %} 264 | 265 | {%- block traceback_line %} 266 | {{ line | ansi2html }} 267 | {%- endblock traceback_line %} 268 | 269 | {%- block data_text scoped %} 270 |
271 |
272 | {{- output.data['text/plain'] | ansi2html -}}
273 | 
274 |
275 | {%- endblock -%} 276 | 277 | {%- block data_javascript scoped %} 278 | {% set div_id = uuid4() %} 279 |
280 |
281 | 285 |
286 | {%- endblock -%} 287 | 288 | {%- block data_widget_state scoped %} 289 | {% set div_id = uuid4() %} 290 | {% set datatype_list = output.data | filter_data_type %} 291 | {% set datatype = datatype_list[0]%} 292 |
293 |
294 | 297 | 300 |
301 | {%- endblock data_widget_state -%} 302 | 303 | {%- block data_widget_view scoped %} 304 | {% set div_id = uuid4() %} 305 | {% set datatype_list = output.data | filter_data_type %} 306 | {% set datatype = datatype_list[0]%} 307 |
308 |
309 | 312 | 315 |
316 | {%- endblock data_widget_view -%} 317 | 318 | {%- block footer %} 319 | {% set mimetype = 'application/vnd.jupyter.widget-state+json'%} 320 | {% if mimetype in nb.metadata.get("widgets",{})%} 321 | 324 | {% endif %} 325 | {{ super() }} 326 | 327 | 328 |
329 | 330 |
331 | 332 |
333 | 334 |
335 | 336 |

© Copyright , Built using the minimal jupinx template.

337 | 338 |
339 | 340 |
341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | {%- endblock footer-%} 350 | -------------------------------------------------------------------------------- /jupinx/theme/minimal/templates/latex.tpl: -------------------------------------------------------------------------------- 1 | ((*- extends 'article.tplx' -*)) 2 | 3 | % See http://blog.juliusschulz.de/blog/ultimate-ipython-notebook#templates 4 | % for some useful tips 5 | 6 | %=============================================================================== 7 | % Document class 8 | %=============================================================================== 9 | 10 | ((* block docclass *)) 11 | \documentclass[11pt, twoside, a4paper]{article} 12 | ((* endblock docclass *)) 13 | 14 | %=============================================================================== 15 | % Packages 16 | %=============================================================================== 17 | 18 | ((* block packages *)) 19 | \usepackage[T1]{fontenc} 20 | \usepackage{graphicx} 21 | \usepackage[breakable]{tcolorbox} 22 | % We will generate all images so they have a width \maxwidth. This means 23 | % that they will get their normal width if they fit onto the page, but 24 | % are scaled down if they would overflow the margins. 25 | \makeatletter 26 | \def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth 27 | \else\Gin@nat@width\fi} 28 | \makeatother 29 | \let\Oldincludegraphics\includegraphics 30 | 31 | % propose delete% 32 | % Ensure that by default, figures have no caption (until we provide a 33 | % proper Figure object with a Caption API and a way to capture that 34 | % in the conversion process - todo). 35 | % \usepackage{caption} 36 | % \DeclareCaptionLabelFormat{empty}{} 37 | %\captionsetup{format=empty,aboveskip=0pt,belowskip=0pt} 38 | % end - propose delete% 39 | 40 | % float figure settings% 41 | \usepackage{float} 42 | \floatplacement{figure}{H} % used to force figures for placement in text 43 | 44 | \usepackage{adjustbox} % Used to constrain images to a maximum size 45 | \usepackage{xcolor} % Allow colors to be defined 46 | \usepackage{enumerate} % Needed for markdown enumerations to work 47 | \usepackage{geometry} % Used to adjust the document margins 48 | \usepackage{amsmath} % Equations 49 | \usepackage{amssymb} % Equations 50 | \usepackage{textcomp} % defines textquotesingle 51 | % Hack from http://tex.stackexchange.com/a/47451/13684: 52 | \AtBeginDocument{% 53 | \def\PYZsq{\textquotesingle}% Upright quotes in Pygmentized code 54 | } 55 | \usepackage{upquote} % Upright quotes for verbatim code 56 | \usepackage{eurosym} % defines \euro 57 | \usepackage[mathletters]{ucs} % Extended unicode (utf-8) support 58 | \usepackage[utf8x]{inputenc} % Allow utf-8 characters in the tex document 59 | \usepackage{fancyvrb} % verbatim replacement that allows latex 60 | \usepackage{grffile} % extends the file name processing of package graphics 61 | % to support a larger range 62 | % The hyperref package gives us a pdf with properly built 63 | % internal navigation ('pdf bookmarks' for the table of contents, 64 | % internal cross-reference links, web links for URLs, etc.) 65 | \usepackage{hyperref} 66 | \usepackage{longtable} % longtable support required by pandoc >1.10 67 | \usepackage{booktabs} % table support for pandoc > 1.12.2 68 | \usepackage[inline]{enumitem} % IRkernel/repr support (it uses the enumerate* environment) 69 | \usepackage[normalem]{ulem} % ulem is needed to support strikethroughs (\sout) 70 | % normalem makes italics be italics, not underlines 71 | \usepackage{braket} 72 | \usepackage{mathrsfs} 73 | \usepackage{natbib} 74 | \usepackage[document]{ragged2e} 75 | \usepackage{fontspec, unicode-math} 76 | \usepackage[greek,english]{babel} 77 | \usepackage{xunicode} 78 | \usepackage{letltxmacro} 79 | \setmonofont{LiberationMono} 80 | \newcommand{\argmax}{\operatornamewithlimits{argmax}} 81 | \newcommand{\argmin}{\operatornamewithlimits{argmin}} 82 | \DeclareMathOperator{\col}{col} 83 | \setlength{\parskip}{1.5ex plus0.5ex minus0.5ex} 84 | \setlength{\parindent}{0pt} 85 | 86 | \usepackage{letltxmacro} 87 | % https://tex.stackexchange.com/q/88001/5764 88 | \LetLtxMacro\oldttfamily\ttfamily 89 | \DeclareRobustCommand{\ttfamily}{\oldttfamily\csname ttsize\endcsname} 90 | \newcommand{\setttsize}[1]{\def\ttsize{#1}}% 91 | 92 | \DeclareTextFontCommand{\texttt}{\ttfamily} 93 | 94 | % renew commands % 95 | % Set max figure width to be 80% of text width, for now hardcoded. 96 | \renewcommand{\includegraphics}[1]{\begin{center}\Oldincludegraphics[width=.8\maxwidth]{#1}\end{center}} 97 | \renewcommand \caption [2][]{} % removes captions from all figures 98 | ((* endblock packages *)) 99 | 100 | % Colors for the hyperref package 101 | \definecolor{urlcolor}{rgb}{0,.145,.698} 102 | \definecolor{linkcolor}{rgb}{.71,0.21,0.01} 103 | \definecolor{citecolor}{rgb}{.12,.54,.11} 104 | 105 | % ANSI colors 106 | \definecolor{ansi-black}{HTML}{3E424D} 107 | \definecolor{ansi-black-intense}{HTML}{282C36} 108 | \definecolor{ansi-red}{HTML}{E75C58} 109 | \definecolor{ansi-red-intense}{HTML}{B22B31} 110 | \definecolor{ansi-green}{HTML}{00A250} 111 | \definecolor{ansi-green-intense}{HTML}{007427} 112 | \definecolor{ansi-yellow}{HTML}{DDB62B} 113 | \definecolor{ansi-yellow-intense}{HTML}{B27D12} 114 | \definecolor{ansi-blue}{HTML}{208FFB} 115 | \definecolor{ansi-blue-intense}{HTML}{0065CA} 116 | \definecolor{ansi-magenta}{HTML}{D160C4} 117 | \definecolor{ansi-magenta-intense}{HTML}{A03196} 118 | \definecolor{ansi-cyan}{HTML}{60C6C8} 119 | \definecolor{ansi-cyan-intense}{HTML}{258F8F} 120 | \definecolor{ansi-white}{HTML}{C5C1B4} 121 | \definecolor{ansi-white-intense}{HTML}{A1A6B2} 122 | \definecolor{ansi-default-inverse-fg}{HTML}{FFFFFF} 123 | \definecolor{ansi-default-inverse-bg}{HTML}{000000} 124 | 125 | 126 | % commands and environments needed by pandoc snippets 127 | % extracted from the output of `pandoc -s` 128 | \providecommand{\tightlist}{% 129 | \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} 130 | \DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}} 131 | % Add ',fontsize=\small' for more characters per line 132 | \newenvironment{Shaded}{}{} 133 | \newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}} 134 | \newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{{#1}}} 135 | \newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}} 136 | \newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}} 137 | \newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}} 138 | \newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}} 139 | \newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}} 140 | \newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{{#1}}}} 141 | \newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{{#1}}} 142 | \newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}} 143 | \newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{{#1}}} 144 | \newcommand{\RegionMarkerTok}[1]{{#1}} 145 | \newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}} 146 | \newcommand{\NormalTok}[1]{{#1}} 147 | 148 | % Additional commands for more recent versions of Pandoc 149 | \newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.53,0.00,0.00}{{#1}}} 150 | \newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}} 151 | \newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}} 152 | \newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.73,0.40,0.53}{{#1}}} 153 | \newcommand{\ImportTok}[1]{{#1}} 154 | \newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.73,0.13,0.13}{\textit{{#1}}}} 155 | \newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}} 156 | \newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}} 157 | \newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{{#1}}} 158 | \newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}} 159 | \newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.40,0.40,0.40}{{#1}}} 160 | \newcommand{\BuiltInTok}[1]{{#1}} 161 | \newcommand{\ExtensionTok}[1]{{#1}} 162 | \newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.74,0.48,0.00}{{#1}}} 163 | \newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.49,0.56,0.16}{{#1}}} 164 | \newcommand{\InformationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}} 165 | \newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}} 166 | 167 | 168 | % Define a nice break command that doesn't care if a line doesn't already 169 | % exist. 170 | \def\br{\hspace*{\fill} \\* } 171 | % Math Jax compatibility definitions 172 | \def\gt{>} 173 | \def\lt{<} 174 | \let\Oldtex\TeX 175 | \let\Oldlatex\LaTeX 176 | \renewcommand{\TeX}{\textrm{\Oldtex}} 177 | \renewcommand{\LaTeX}{\textrm{\Oldlatex} 178 | 179 | %=============================================================================== 180 | % Title Page 181 | %=============================================================================== 182 | 183 | ((* block maketitle *)) 184 | \setttsize{\footnotesize} 185 | 186 | \title{((( nb.metadata.get("latex_metadata", {}).get("title", "") | escape_latex )))} 187 | 188 | ((*- if nb.metadata.get("latex_metadata", {}).get("author", ""): -*)) 189 | \author{((( nb.metadata["latex_metadata"]["author"] )))} 190 | ((*- endif *)) 191 | 192 | ((*- if nb.metadata.get("latex_metadata", {}).get("affiliation", ""): -*)) 193 | \affiliation{((( nb.metadata["latex_metadata"]["affiliation"] )))} 194 | ((*- endif *)) 195 | 196 | \date{\today} 197 | \maketitle 198 | 199 | ((*- if nb.metadata.get("latex_metadata", {}).get("logo", ""): -*)) 200 | \begin{center} 201 | \adjustimage{max size={0.6\linewidth}{0.6\paperheight}}{((( nb.metadata["latex_metadata"]["logo"] )))} 202 | \end{center} 203 | ((*- endif -*)) 204 | 205 | ((* endblock maketitle *)) 206 | 207 | 208 | %=============================================================================== 209 | % Input 210 | %=============================================================================== 211 | 212 | % Input cells can be hidden using the "Hide input" and "Hide input all" 213 | % nbextensions (which set the hide_input metadata flags) 214 | 215 | ((* block input scoped *)) 216 | ((( cell.metadata.get("hide_input", "") ))) 217 | ((*- if cell.metadata.hide_input or nb.metadata.hide_input or cell.metadata.get("hide_input", ""): -*)) 218 | ((*- else -*)) 219 | ((( custom_add_prompt(cell.source | wrap_text(88) | highlight_code(strip_verbatim=True), cell, 'In ', 'incolor', 'plain') ))) 220 | ((*- endif *)) 221 | ((* endblock input *)) 222 | 223 | 224 | %=============================================================================== 225 | % Output 226 | %=============================================================================== 227 | 228 | ((* block output_group -*)) 229 | ((*- if cell.metadata.hide_output: -*)) 230 | ((*- else -*)) 231 | ((( super() ))) 232 | ((*- endif -*)) 233 | ((* endblock output_group *)) 234 | 235 | ((* block execute_result scoped *)) 236 | ((*- for type in output.data | filter_data_type -*)) 237 | ((*- if type in ['text/plain']*)) 238 | ((( custom_add_prompt(output.data['text/plain'] | wrap_text(88) | escape_latex | ansi2latex, cell, 'Out', 'outcolor', 'plain') ))) 239 | ((*- elif type in ['text/latex']*)) 240 | ((( custom_add_prompt(output.data['text/latex'] | wrap_text(88) | ansi2latex, cell, 'Out', 'outcolor', 'latex') ))) 241 | ((* else -*)) 242 | ((( " " ))) 243 | ((( draw_prompt(cell, 'Out', 'outcolor','') )))((( super() ))) 244 | ((*- endif -*)) 245 | ((*- endfor -*)) 246 | ((* endblock execute_result *)) 247 | 248 | % Display stream ouput with coloring 249 | ((* block stream *)) 250 | \begin{Verbatim}[commandchars=\\\{\}, fontsize=\footnotesize] 251 | ((( output.text | wrap_text(86) | escape_latex | ansi2latex ))) 252 | \end{Verbatim} 253 | %((* endblock stream *)) 254 | 255 | %============================================================================== 256 | % Define macro custom_add_prompt() (derived from add_prompt() macro in style_ipython.tplx) 257 | %============================================================================== 258 | 259 | ((* macro custom_add_prompt(text, cell, prompt, prompt_color, type) -*)) 260 | ((*- if cell.execution_count is defined -*)) 261 | ((*- set execution_count = "" ~ (cell.execution_count | replace(None, " ")) -*)) 262 | ((*- else -*)) 263 | ((*- set execution_count = "" -*)) 264 | ((*- endif -*)) 265 | ((*- set indention = " " * (execution_count | length + 7) -*)) 266 | \begin{Verbatim}[mathescape, commandchars=\\\{\}, fontsize=\small, xleftmargin=-3.9em] 267 | ((( text.replace('$$','').replace('$','') | add_prompts(first='{\color{' ~ prompt_color ~ '}' ~ prompt ~ '[{\\color{' ~ prompt_color ~ '}' ~ execution_count ~ '}]:} ', cont=indention) ))) 268 | \end{Verbatim} 269 | ((*- endmacro *)) 270 | 271 | %============================================================================== 272 | % Support Macros 273 | %============================================================================== 274 | 275 | % Name: draw_prompt 276 | % Purpose: Renders an output/input prompt 277 | ((* macro draw_prompt(cell, prompt, prompt_color, extra_space) -*)) 278 | ((*- if cell.execution_count is defined -*)) 279 | ((*- set execution_count = "" ~ (cell.execution_count | replace(None, " ")) -*)) 280 | ((*- else -*))((*- set execution_count = " " -*))((*- endif *)) 281 | 282 | ((*- if (resources.global_content_filter.include_output_prompt and prompt == 'Out') 283 | or (resources.global_content_filter.include_input_prompt and prompt == 'In' ) *)) 284 | \prompt{(((prompt)))}{(((prompt_color)))}{(((execution_count)))}{(((extra_space)))} 285 | ((*- endif -*)) 286 | ((*- endmacro *)) 287 | 288 | 289 | %============================================================================== 290 | % Bibliography 291 | %============================================================================== 292 | 293 | % Insert citations in markdown as e.g. 294 | % [DevoretS2013] 295 | % requires file references.bib in current directory (or the file set as "bib" in the latex_metadata) 296 | 297 | 298 | ((* block bibliography *)) 299 | ((*- if nb.metadata.get("latex_metadata", {}).get("bib_include", ""): -*)) 300 | % Add a bibliography block to the postdoc 301 | \bibliographystyle{plain} 302 | \bibliography{((( nb.metadata.get("latex_metadata", {}).get("bib", "references") )))} 303 | ((*- endif -*)) 304 | ((* endblock bibliography *)) 305 | -------------------------------------------------------------------------------- /jupinx/util/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | jupinx.util 3 | ~~~~~~~~~~~ 4 | 5 | Utility functions for Jupinx. 6 | """ -------------------------------------------------------------------------------- /jupinx/util/template.py: -------------------------------------------------------------------------------- 1 | """ 2 | jupinx.util.template 3 | ~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Templates utility functions for Jupinx. 6 | 7 | Adapted from Sphinx Template utility - sphinx.util.template 8 | """ 9 | 10 | import os 11 | from typing import Dict, List, Union 12 | 13 | from jinja2.loaders import BaseLoader 14 | from jinja2.sandbox import SandboxedEnvironment 15 | 16 | from jupinx import package_dir 17 | from sphinx.jinja2glue import SphinxFileSystemLoader 18 | from sphinx.locale import get_translator 19 | from sphinx.util import rst, texescape 20 | 21 | 22 | class BaseRenderer: 23 | def __init__(self, loader: BaseLoader = None) -> None: 24 | self.env = SandboxedEnvironment(loader=loader, extensions=['jinja2.ext.i18n']) 25 | self.env.filters['repr'] = repr 26 | self.env.install_gettext_translations(get_translator()) # type: ignore 27 | 28 | def render(self, template_name: str, context: Dict) -> str: 29 | return self.env.get_template(template_name).render(context) 30 | 31 | def render_string(self, source: str, context: Dict) -> str: 32 | return self.env.from_string(source).render(context) 33 | 34 | 35 | class FileRenderer(BaseRenderer): 36 | def __init__(self, search_path: Union[str, List[str]]) -> None: 37 | if isinstance(search_path, str): 38 | search_path = [search_path] 39 | else: 40 | # filter "None" paths 41 | search_path = list(filter(None, search_path)) 42 | 43 | loader = SphinxFileSystemLoader(search_path) 44 | super().__init__(loader) 45 | 46 | @classmethod 47 | def render_from_file(cls, filename: str, context: Dict) -> str: 48 | dirname = os.path.dirname(filename) 49 | basename = os.path.basename(filename) 50 | print(dirname, "dirname", basename, "basename -- ") 51 | return cls(dirname).render(basename, context) 52 | 53 | 54 | class SphinxRenderer(FileRenderer): 55 | def __init__(self, template_path: Union[str, List[str]] = None) -> None: 56 | if template_path is None: 57 | template_path = os.path.join(package_dir, 'templates') 58 | super().__init__(template_path) 59 | 60 | @classmethod 61 | def render_from_file(cls, filename: str, context: Dict) -> str: 62 | return FileRenderer.render_from_file(filename, context) 63 | 64 | 65 | class LaTeXRenderer(SphinxRenderer): 66 | def __init__(self, template_path: str = None) -> None: 67 | if template_path is None: 68 | template_path = os.path.join(package_dir, 'templates', 'latex') 69 | super().__init__(template_path) 70 | 71 | # use texescape as escape filter 72 | self.env.filters['e'] = texescape.escape 73 | self.env.filters['escape'] = texescape.escape 74 | self.env.filters['eabbr'] = texescape.escape_abbr 75 | 76 | # use JSP/eRuby like tagging instead because curly bracket; the default 77 | # tagging of jinja2 is not good for LaTeX sources. 78 | self.env.variable_start_string = '<%=' 79 | self.env.variable_end_string = '%>' 80 | self.env.block_start_string = '<%' 81 | self.env.block_end_string = '%>' 82 | 83 | 84 | class ReSTRenderer(SphinxRenderer): 85 | def __init__(self, template_path: Union[str, List[str]] = None, language: str = None) -> None: # NOQA 86 | super().__init__(template_path) 87 | 88 | # add language to environment 89 | self.env.extend(language=language) 90 | 91 | # use texescape as escape filter 92 | self.env.filters['e'] = rst.escape 93 | self.env.filters['escape'] = rst.escape 94 | self.env.filters['heading'] = rst.heading 95 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import jupinx 4 | 5 | from setuptools import setup, find_packages 6 | 7 | LONG_DESCRIPTION = ''' 8 | This package contains the Jupinx cmd and quickstart utilities. 9 | 10 | Documentation and a tutorial can be found `here `_. 11 | 12 | This project is maintained and supported by `QuantEcon `_. 13 | ''' 14 | VERSION = jupinx.__version__ 15 | 16 | INSTALL_REQUIRES = [ 17 | 'docutils', 18 | 'nbformat', 19 | 'sphinx>=1.8.5', 20 | 'dask', 21 | 'dask[distributed]', 22 | 'ipython', 23 | 'nbconvert', 24 | 'notebook', 25 | 'jupyter_client', 26 | 'pyzmq>=17.1.3', 27 | 'sphinxcontrib-bibtex', 28 | 'sphinxcontrib-jupyter>=0.5.6' 29 | ] 30 | 31 | setup( 32 | name='jupinx', 33 | version=VERSION, 34 | url='https://github.com/QuantEcon/jupinx', 35 | download_url='https://github.com/QuantEcon/jupinx/archive/{}.tar.gz'.format(VERSION), 36 | license='BSD', 37 | author='QuantEcon', 38 | author_email='admin@quantecon.org', 39 | description='Jupinx extension: Convert your RST files into into different formats like notebook, pdf, html.', 40 | long_description=LONG_DESCRIPTION, 41 | zip_safe=False, 42 | classifiers=[ 43 | 'Development Status :: 4 - Beta', 44 | 'Environment :: Console', 45 | 'Environment :: Web Environment', 46 | 'Framework :: Sphinx', 47 | 'Intended Audience :: Developers', 48 | 'License :: OSI Approved :: BSD License', 49 | 'Operating System :: OS Independent', 50 | 'Programming Language :: Python :: 2', 51 | 'Programming Language :: Python :: 3', 52 | 'Framework :: Sphinx :: Extension', 53 | 'Topic :: Documentation', 54 | 'Topic :: Utilities', 55 | ], 56 | platforms='any', 57 | packages=find_packages(), 58 | include_package_data=True, 59 | entry_points={ 60 | 'console_scripts': [ 61 | 'jupinx-quickstart = jupinx.cmd.quickstart:main', 62 | 'jupinx = jupinx.cmd.build:main' 63 | ] 64 | }, 65 | install_requires=INSTALL_REQUIRES 66 | ) 67 | --------------------------------------------------------------------------------