From 2f433618f2f48e3c5c92c89eb8af595071b6fa73 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 4 Sep 2019 14:42:21 +1000 Subject: [PATCH 01/31] support for general statics for images to builddir/_images --- .../jupyter/writers/translate_all.py | 58 ++++++++++++++++++- sphinxcontrib/jupyter/writers/utils.py | 6 +- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index 0ab9e34a..d705c2c2 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -41,6 +41,7 @@ def __init__(self, builder, document): self.in_list = False self.in_math = False self.in_math_block = False + self.in_image = False self.code_lines = [] self.markdown_lines = [] @@ -173,13 +174,23 @@ def visit_image(self, node): implementation as is done in http://docutils.sourceforge.net/docs/ref/rst/directives.html#image """ + self.in_image = True uri = node.attributes["uri"] - self.images.append(uri) #TODO: list of image files + #check if same uri has been processed already for copying asset + if uri not in self.images: + self.images.append(uri) + uri = self.copy_static_asset(uri, "_images") if self.jupyter_download_nb_image_urlpath: for file_path in self.jupyter_static_file_path: if file_path in uri: uri = uri.replace(file_path +"/", self.jupyter_download_nb_image_urlpath) break #don't need to check other matches + else: + #Update static path to _image location for uri + for file_path in self.jupyter_static_file_path: + if file_path in uri: + uri = uri.replace(file_path +"/", "_images/") + break #don't need to check other matches attrs = node.attributes if self.jupyter_images_markdown: #-Construct MD image @@ -202,6 +213,9 @@ def visit_image(self, node): image = image.rstrip() + ">\n\n" #Add double space for html self.markdown_lines.append(image) + def depart_image(self, node): + self.in_image = False + # math def visit_math(self, node): """inline math""" @@ -818,6 +832,48 @@ def add_markdown_cell(self, slide_type="slide"): self.output["cells"].append(new_md_cell) self.markdown_lines = [] + def copy_static_asset(self, uri, target_dir): + """ + copy static assets utility function to support building + a collection of static assets such as images and downloads + + Parameters + ---------- + uri provided source uri + target specify target directory in build directory + + Returns + ------- + uri an updated reference for the URI + """ + source_file = os.path.join(self.builder.srcdir, uri) + target_dir = os.path.join(self.builder.outdir, target_dir) + source_dir, filename = os.path.split(source_file) + if os.path.isfile(source_file): #Check Source File + target_file = os.path.join(target_dir, filename) + #Check if target directory already contains a file with the same name + if os.path.isfile(target_file): + #-Generate Unique File ID due to name collision-# + base, ext = os.path.splitext(filename) + while os.path.isfile(target_file): + if re.search("-\d*", base): + base, num = base.split("-") + num = str(int(num) + 1) #increment value + filename = base+"-"+num+ext + target_file = os.path.join(target_dir, filename) + else: + filename = base+"-1"+ext + target_file = os.path.join(target_dir, filename) + uri_base, uri_filename = os.path.split(uri) + uri = os.path.join(uri_base, filename) + #Copy File + if not os.path.isdir(target_dir): + os.makedirs(target_dir) + copyfile(source_file, target_file) + else: + raise ValueError("[copy_static_asset] specified file ({}) is not found".format(source)) + return uri + @classmethod def split_uri_id(cls, uri): return re.search(cls.SPLIT_URI_ID_REGEX, uri).groups() diff --git a/sphinxcontrib/jupyter/writers/utils.py b/sphinxcontrib/jupyter/writers/utils.py index 167d8a59..21af30a7 100644 --- a/sphinxcontrib/jupyter/writers/utils.py +++ b/sphinxcontrib/jupyter/writers/utils.py @@ -139,7 +139,7 @@ def _str_to_lines(x): return x -def copy_dependencies(builderSelf, outdir = None): +def copy_dependencies(builderSelf, outdir=None): """ Copies the dependencies of source files or folders specified in the config to their respective output directories """ @@ -157,7 +157,7 @@ def copy_dependencies(builderSelf, outdir = None): full_dest_path = outdir + "/" + key ensuredir(full_dest_path) for dep in deps: - copy(full_src_path + "/" + dep, full_dest_path,follow_symlinks=True) + copy(full_src_path + "/" + dep, full_dest_path, follow_symlinks=True) elif os.path.isfile(full_src_path): ## handling the case of key being a file # removing the filename to get the directory path @@ -168,5 +168,5 @@ def copy_dependencies(builderSelf, outdir = None): full_src_path = srcdir + "/" + key full_dest_path = outdir + "/" + key for dep in deps: - copy(full_src_path + "/" + dep, full_dest_path,follow_symlinks=True) + copy(full_src_path + "/" + dep, full_dest_path, follow_symlinks=True) From 2fa74bda92ab8655818a9f60cf4a62271b568e2d Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 5 Sep 2019 13:34:47 +1000 Subject: [PATCH 02/31] adjust implementation for _images to use a global dictionary for image_library --- sphinxcontrib/jupyter/builders/jupyter.py | 32 ++++++-- .../jupyter/writers/translate_all.py | 73 ++++++------------ tests/base/_static/level1/hood.jpg | Bin 0 -> 76153 bytes tests/base/images.rst | 9 +++ tests/base/ipynb/images.ipynb | 27 +++++-- tests/base/ipynb/simple_notebook.ipynb | 2 +- tests/base/ipynb/slides.ipynb | 2 +- 7 files changed, 80 insertions(+), 65 deletions(-) create mode 100644 tests/base/_static/level1/hood.jpg diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index 7da2bde7..65ac0369 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -15,6 +15,7 @@ from sphinx.util import logging import pdb from ..writers.utils import copy_dependencies +from shutil import copyfile class JupyterBuilder(Builder): """ @@ -83,6 +84,10 @@ def init(self): self.reportdir = self.outdir + '/reports/' self.errordir = self.outdir + "/reports/{}" + self.image_library = { + 'index' : [], + } + def get_outdated_docs(self): for docname in self.env.found_docs: if docname not in self.env.all_docs: @@ -165,20 +170,23 @@ def write_doc(self, docname, doctree): self.logger.warning("error writing file %s: %s" % (outfilename, err)) def copy_static_files(self): - # copy all static files - self.logger.info(bold("copying static files... "), nonl=True) + #copy image objects to _images + self.process_image_library() + + #TODO: review in reference to images + # copy all static files to build folder + self.logger.info(bold("[builder] copying bulk static files... "), nonl=True) ensuredir(os.path.join(self.outdir, '_static')) if (self.config["jupyter_execute_notebooks"]): - self.logger.info(bold("copying static files to executed folder... \n"), nonl=True) + self.logger.info(bold("[builder] copying bulk static files to executed folder... \n"), nonl=True) ensuredir(os.path.join(self.executed_notebook_dir, '_static')) - # excluded = Matcher(self.config.exclude_patterns + ["**/.*"]) for static_path in self.config["jupyter_static_file_path"]: entry = os.path.join(self.confdir, static_path) if not os.path.exists(entry): self.logger.warning( - "jupyter_static_path entry {} does not exist" + "[builder] jupyter_static_path entry {} does not exist" .format(entry)) else: copy_asset(entry, os.path.join(self.outdir, "_static")) @@ -186,6 +194,20 @@ def copy_static_files(self): copy_asset(entry, os.path.join(self.executed_notebook_dir, "_static")) self.logger.info("done") + def process_image_library(self): + """ + Action self.image_library + """ + image_path = os.path.join(self.outdir, "_images") + self.logger.info(bold("[builder] copy images to {}".format(image_path))) + ensuredir(image_path) + for uri in self.image_library.keys(): + if uri == "index": + continue + src = os.path.join(self.srcdir, uri) + target = os.path.join(image_path, self.image_library[uri]) + copyfile(src, target, follow_symlinks=True) + def finish(self): self.finish_tasks.add_task(self.copy_static_files) diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index d705c2c2..85a37fa3 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -176,21 +176,14 @@ def visit_image(self, node): """ self.in_image = True uri = node.attributes["uri"] - #check if same uri has been processed already for copying asset - if uri not in self.images: - self.images.append(uri) - uri = self.copy_static_asset(uri, "_images") - if self.jupyter_download_nb_image_urlpath: - for file_path in self.jupyter_static_file_path: - if file_path in uri: - uri = uri.replace(file_path +"/", self.jupyter_download_nb_image_urlpath) - break #don't need to check other matches + + #add to image libary for builder + if uri not in self.builder.image_library.keys(): + path, filename = self.check_duplicate_files(uri) + self.builder.image_library[uri] = filename else: - #Update static path to _image location for uri - for file_path in self.jupyter_static_file_path: - if file_path in uri: - uri = uri.replace(file_path +"/", "_images/") - break #don't need to check other matches + path, filename = os.path.split(uri) + uri = os.path.join("_images", filename) attrs = node.attributes if self.jupyter_images_markdown: #-Construct MD image @@ -832,47 +825,25 @@ def add_markdown_cell(self, slide_type="slide"): self.output["cells"].append(new_md_cell) self.markdown_lines = [] - def copy_static_asset(self, uri, target_dir): + def check_duplicate_files(self, uri): """ - copy static assets utility function to support building - a collection of static assets such as images and downloads - - Parameters - ---------- - uri provided source uri - target specify target directory in build directory - - Returns - ------- - uri an updated reference for the URI + Parse URI for duplicate files in catalog """ - source_file = os.path.join(self.builder.srcdir, uri) - target_dir = os.path.join(self.builder.outdir, target_dir) - source_dir, filename = os.path.split(source_file) - if os.path.isfile(source_file): #Check Source File - target_file = os.path.join(target_dir, filename) - #Check if target directory already contains a file with the same name - if os.path.isfile(target_file): - #-Generate Unique File ID due to name collision-# + path, filename = os.path.split(uri) + if self.in_image: + #Check for file by the same name in library and increment if found + while filename in self.builder.image_library['index']: base, ext = os.path.splitext(filename) - while os.path.isfile(target_file): - if re.search("-\d*", base): - base, num = base.split("-") - num = str(int(num) + 1) #increment value - filename = base+"-"+num+ext - target_file = os.path.join(target_dir, filename) - else: - filename = base+"-1"+ext - target_file = os.path.join(target_dir, filename) - uri_base, uri_filename = os.path.split(uri) - uri = os.path.join(uri_base, filename) - #Copy File - if not os.path.isdir(target_dir): - os.makedirs(target_dir) - copyfile(source_file, target_file) + if re.search("-\d*", base): + base, num = base.split("-") + num = str(int(num) + 1) #increment value + filename = base+"-"+num+ext + else: + filename = base+"-1"+ext + self.builder.image_library['index'].append(filename) else: - raise ValueError("[copy_static_asset] specified file ({}) is not found".format(source)) - return uri + raise NotImplementedError + return path, filename @classmethod def split_uri_id(cls, uri): diff --git a/tests/base/_static/level1/hood.jpg b/tests/base/_static/level1/hood.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0426a4c550ca90f47f96c0f4cdbd3b3773a375a GIT binary patch literal 76153 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�u*Jdf<#q|A<0TX7BsLHGJ* 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 z
;78W@UNUI~Maw&GH>xv02K>&3Glf@>@6401JqZFA)vWgV|#(AW` zihKs?LJ+OV9102@HL{c}dg78{Vg-XFe8!#ZD+;o>$8pgM~#7bFTm$Rd%6CpgEYCOC@H5QdmN1XuY-6p6VE$^_Z<6a&zSWik8y zG}xOeNpjCGJ?ZR4$yxHCWAUH{tYGurm=?US%Y#zOLPrviMmlpyXl#%!?bz=~q7Z>t zk?Yce7&DUi?M$1Ec$ao@K+!C65CI%wng&d6UpS(}xnAPogW`)4*$k7GAYy?Ig4rZ| zFvt}Qq*#*KB0|bKdeBvo0?1EVKqROeo`!&EgUVCE8Ky;ww^rgYkWVxMMH_@MbZq9O zfm!4$idP+pAefO(yfvOJJIS0zP0VfS_i9 GT>sg+Hzyqc literal 0 HcmV?d00001 diff --git a/tests/base/images.rst b/tests/base/images.rst index 902587a8..19e71e32 100644 --- a/tests/base/images.rst +++ b/tests/base/images.rst @@ -48,3 +48,12 @@ Testing the **.. figure::** directive .. figure:: _static/hood.jpg :scale: 50 % + +File Collisions +--------------- + +Add a figure of the same name in a different folder + +Most basic image directive + +.. image:: _static/level1/hood.jpg \ No newline at end of file diff --git a/tests/base/ipynb/images.ipynb b/tests/base/ipynb/images.ipynb index 3d2cc448..da828f36 100644 --- a/tests/base/ipynb/images.ipynb +++ b/tests/base/ipynb/images.ipynb @@ -19,27 +19,27 @@ "\n", "Most basic image directive\n", "\n", - "\n", + "\n", "\n", "A scaled down version with 25 % width\n", "\n", - "\n", + "\n", "\n", "A height of 50px\n", "\n", - "\n", + "\n", "\n", "Including *alt*\n", "\n", - "\"A\n", + "\"A\n", "\n", "An image with a *right* alignment\n", "\n", - "\n", + "\n", "\n", "An image with a *left* alignment\n", "\n", - "" + "" ] }, { @@ -52,7 +52,20 @@ "\n", "Testing the **.. figure::** directive\n", "\n", - "" + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## File Collisions\n", + "\n", + "Add a figure of the same name in a different folder\n", + "\n", + "Most basic image directive\n", + "\n", + "" ] } ], diff --git a/tests/base/ipynb/simple_notebook.ipynb b/tests/base/ipynb/simple_notebook.ipynb index 34b0f2a4..8efdfd6a 100644 --- a/tests/base/ipynb/simple_notebook.ipynb +++ b/tests/base/ipynb/simple_notebook.ipynb @@ -60,7 +60,7 @@ "source": [ "Figures can be include using the **figure** directive\n", "\n", - "" + "" ] }, { diff --git a/tests/base/ipynb/slides.ipynb b/tests/base/ipynb/slides.ipynb index 376d0b15..e95e0eea 100644 --- a/tests/base/ipynb/slides.ipynb +++ b/tests/base/ipynb/slides.ipynb @@ -89,7 +89,7 @@ "source": [ "We can also include the figures from some folder\n", "\n", - "" + "" ] }, { From 1495ad59f0d8a7fe35451175fdf838ffa19f93f2 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 5 Sep 2019 13:41:12 +1000 Subject: [PATCH 03/31] python27 fix, update index --- sphinxcontrib/jupyter/builders/jupyter.py | 2 +- sphinxcontrib/jupyter/writers/translate_all.py | 1 - tests/base/ipynb/index.ipynb | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index 65ac0369..5e98f1a6 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -206,7 +206,7 @@ def process_image_library(self): continue src = os.path.join(self.srcdir, uri) target = os.path.join(image_path, self.image_library[uri]) - copyfile(src, target, follow_symlinks=True) + copyfile(src, target) def finish(self): diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index 85a37fa3..6e3d98da 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -176,7 +176,6 @@ def visit_image(self, node): """ self.in_image = True uri = node.attributes["uri"] - #add to image libary for builder if uri not in self.builder.image_library.keys(): path, filename = self.check_duplicate_files(uri) diff --git a/tests/base/ipynb/index.ipynb b/tests/base/ipynb/index.ipynb index de6e5678..dc829d4c 100644 --- a/tests/base/ipynb/index.ipynb +++ b/tests/base/ipynb/index.ipynb @@ -24,6 +24,7 @@ "- [Images](images.ipynb)\n", " - [Image](images.ipynb#image)\n", " - [Figure](images.ipynb#figure)\n", + " - [File Collisions](images.ipynb#file-collisions)\n", "- [Inline](inline.ipynb)\n", " - [Code](inline.ipynb#code)\n", " - [Math](inline.ipynb#math)\n", From 1a9fe05fcf9497691afa1391a1bb1effdc5909ce Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 5 Sep 2019 14:15:57 +1000 Subject: [PATCH 04/31] check for non-local images --- sphinxcontrib/jupyter/writers/translate_all.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index 6e3d98da..cd245037 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -176,13 +176,18 @@ def visit_image(self, node): """ self.in_image = True uri = node.attributes["uri"] - #add to image libary for builder - if uri not in self.builder.image_library.keys(): + if '?' in node['candidates']: + # don't rewrite nonlocal image URIs + pass + elif uri not in self.builder.image_library.keys(): + #add files to image libary for builder path, filename = self.check_duplicate_files(uri) self.builder.image_library[uri] = filename + uri = os.path.join("_images", filename) else: + #Already added to image libary for builder to copy asset path, filename = os.path.split(uri) - uri = os.path.join("_images", filename) + uri = os.path.join("_images", filename) attrs = node.attributes if self.jupyter_images_markdown: #-Construct MD image From f82f06a59122f80fcfa796ff6afd45f22c27408e Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 5 Sep 2019 15:15:31 +1000 Subject: [PATCH 05/31] add copy of _images to executed dir --- sphinxcontrib/jupyter/builders/jupyter.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index 5e98f1a6..516ae813 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -171,13 +171,13 @@ def write_doc(self, docname, doctree): def copy_static_files(self): #copy image objects to _images - self.process_image_library() + self.process_image_library(self.outdir) #TODO: review in reference to images # copy all static files to build folder self.logger.info(bold("[builder] copying bulk static files... "), nonl=True) ensuredir(os.path.join(self.outdir, '_static')) - if (self.config["jupyter_execute_notebooks"]): + if self.config["jupyter_execute_notebooks"]: self.logger.info(bold("[builder] copying bulk static files to executed folder... \n"), nonl=True) ensuredir(os.path.join(self.executed_notebook_dir, '_static')) @@ -190,15 +190,16 @@ def copy_static_files(self): .format(entry)) else: copy_asset(entry, os.path.join(self.outdir, "_static")) - if (self.config["jupyter_execute_notebooks"]): + if self.config["jupyter_execute_notebooks"]: + self.process_image_library(self.executed_notebook_dir) copy_asset(entry, os.path.join(self.executed_notebook_dir, "_static")) self.logger.info("done") - def process_image_library(self): + def process_image_library(self, context): """ Action self.image_library """ - image_path = os.path.join(self.outdir, "_images") + image_path = os.path.join(context, "_images") self.logger.info(bold("[builder] copy images to {}".format(image_path))) ensuredir(image_path) for uri in self.image_library.keys(): From 7ace08e4e13155ee0d5a7c1a8eb2bbc2a8abb2d3 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 5 Sep 2019 15:15:50 +1000 Subject: [PATCH 06/31] fix jupyter_download_nb_image_urlpath option --- sphinxcontrib/jupyter/writers/translate_all.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index cd245037..43c397ab 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -188,11 +188,18 @@ def visit_image(self, node): #Already added to image libary for builder to copy asset path, filename = os.path.split(uri) uri = os.path.join("_images", filename) - attrs = node.attributes + #-Parse link updating for jupyter_download_nb_image_urlpath + if self.jupyter_download_nb_image_urlpath: + if '?' in node['candidates']: + pass + else: + uri = uri.replace("_images/", self.jupyter_download_nb_image_urlpath) + #-Write to Markdown-# if self.jupyter_images_markdown: #-Construct MD image image = "![{0}]({0})".format(uri) else: + attrs = node.attributes # Construct HTML image image = ' Date: Thu, 5 Sep 2019 15:31:00 +1000 Subject: [PATCH 07/31] add remote images to images testing --- tests/base/images.rst | 14 +++++++++++++- tests/base/ipynb/images.ipynb | 15 +++++++++++++++ tests/base/ipynb/index.ipynb | 1 + 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/base/images.rst b/tests/base/images.rst index 19e71e32..038d5669 100644 --- a/tests/base/images.rst +++ b/tests/base/images.rst @@ -56,4 +56,16 @@ Add a figure of the same name in a different folder Most basic image directive -.. image:: _static/level1/hood.jpg \ No newline at end of file +.. image:: _static/level1/hood.jpg + +Remote Images +------------- + +Adding a test for remote images specified by url + +.. image:: https://s3-ap-southeast-2.amazonaws.com/assets.quantecon.org/img/sloan_logo.png + +and using figure directive + +.. figure:: https://s3-ap-southeast-2.amazonaws.com/assets.quantecon.org/img/sloan_logo.png + :scale: 50 % \ No newline at end of file diff --git a/tests/base/ipynb/images.ipynb b/tests/base/ipynb/images.ipynb index da828f36..7a28c5dd 100644 --- a/tests/base/ipynb/images.ipynb +++ b/tests/base/ipynb/images.ipynb @@ -67,6 +67,21 @@ "\n", "" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Remote Images\n", + "\n", + "Adding a test for remote images specified by url\n", + "\n", + "\n", + "\n", + "and using figure directive\n", + "\n", + "" + ] } ], "metadata": { diff --git a/tests/base/ipynb/index.ipynb b/tests/base/ipynb/index.ipynb index dc829d4c..7d1958bf 100644 --- a/tests/base/ipynb/index.ipynb +++ b/tests/base/ipynb/index.ipynb @@ -25,6 +25,7 @@ " - [Image](images.ipynb#image)\n", " - [Figure](images.ipynb#figure)\n", " - [File Collisions](images.ipynb#file-collisions)\n", + " - [Remote Images](images.ipynb#remote-images)\n", "- [Inline](inline.ipynb)\n", " - [Code](inline.ipynb#code)\n", " - [Math](inline.ipynb#math)\n", From 04fc2e329257d6b5153f3cb6aef232c40411a907 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 5 Sep 2019 16:19:51 +1000 Subject: [PATCH 08/31] copy _images for jupyter_html --- sphinxcontrib/jupyter/writers/make_site.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sphinxcontrib/jupyter/writers/make_site.py b/sphinxcontrib/jupyter/writers/make_site.py index ae0c0db5..e453a32e 100644 --- a/sphinxcontrib/jupyter/writers/make_site.py +++ b/sphinxcontrib/jupyter/writers/make_site.py @@ -45,6 +45,10 @@ def build_website(self, builderSelf): ## copies all the static files shutil.copytree(builderSelf.outdir + "/_static/", self.websitedir + "_static/", symlinks=True) + ## copies all the image files + image_path = os.path.join(builderSelf.outdir, "_images") + if os.path.exists(image_path): + shutil.copytree(image_path, self.websitedir + "_images/", symlinks=True) ## copies all theme files to _static folder if os.path.exists(staticFolder): @@ -80,4 +84,3 @@ def build_website(self, builderSelf): - From 1f2b217cacc66bf7258224e64fca07fa22685d2f Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 6 Sep 2019 12:28:25 +1000 Subject: [PATCH 09/31] adjustments to use root references for nested folder setups --- sphinxcontrib/jupyter/writers/translate_all.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index 43c397ab..60bf178e 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -183,17 +183,18 @@ def visit_image(self, node): #add files to image libary for builder path, filename = self.check_duplicate_files(uri) self.builder.image_library[uri] = filename - uri = os.path.join("_images", filename) + uri = os.path.join("/_images", filename) else: #Already added to image libary for builder to copy asset path, filename = os.path.split(uri) - uri = os.path.join("_images", filename) + uri = os.path.join("/_images", filename) #-Parse link updating for jupyter_download_nb_image_urlpath if self.jupyter_download_nb_image_urlpath: if '?' in node['candidates']: pass else: - uri = uri.replace("_images/", self.jupyter_download_nb_image_urlpath) + path, filename = os.path.split(uri) + uri = os.path.join(self.jupyter_download_nb_image_urlpath, filename) #-Write to Markdown-# if self.jupyter_images_markdown: #-Construct MD image From a8371dfb2cea027acabe0fdbbdc79108893e18bc Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Tue, 10 Sep 2019 10:34:02 +1000 Subject: [PATCH 10/31] add downloads library --- sphinxcontrib/jupyter/builders/jupyter.py | 19 +++++++++++++ .../jupyter/writers/translate_all.py | 27 +++++++++++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index 516ae813..40466d6b 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -87,6 +87,9 @@ def init(self): self.image_library = { 'index' : [], } + self.download_library = { + 'index' : [], + } def get_outdated_docs(self): for docname in self.env.found_docs: @@ -172,6 +175,7 @@ def write_doc(self, docname, doctree): def copy_static_files(self): #copy image objects to _images self.process_image_library(self.outdir) + self.process_download_library(self.outdir) #TODO: review in reference to images # copy all static files to build folder @@ -192,6 +196,7 @@ def copy_static_files(self): copy_asset(entry, os.path.join(self.outdir, "_static")) if self.config["jupyter_execute_notebooks"]: self.process_image_library(self.executed_notebook_dir) + self.process_download_library(self.executed_notebook_dir) copy_asset(entry, os.path.join(self.executed_notebook_dir, "_static")) self.logger.info("done") @@ -209,6 +214,20 @@ def process_image_library(self, context): target = os.path.join(image_path, self.image_library[uri]) copyfile(src, target) + def process_download_library(self, context): + """ + Action self.download_library + """ + download_path = os.path.join(context, "_downloads") + self.logger.info(bold("[builder] copy downloads to {}".format(download_path))) + ensuredir(download_path) + for fl in self.download_library.keys(): + if fl == "index": + continue + src = os.path.join(self.srcdir, fl) + target = os.path.join(download_path, self.download_library[fl]) + copyfile(src, target) + def finish(self): self.finish_tasks.add_task(self.copy_static_files) diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index 60bf178e..f9229da8 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -396,7 +396,17 @@ def depart_footnote(self, node): def visit_download_reference(self, node): self.in_download_reference = True - html = "".format(node["reftarget"]) + sourcefile = node['reftarget'] + if sourcefile not in self.builder.image_library.keys(): + #add files to download libary for builder + path, filename = self.check_duplicate_files(sourcefile) + self.builder.download_library[sourcefile] = filename + targetfile = os.path.join("/_downloads", filename) + else: + #Already added to image libary for builder to copy asset + path, filename = os.path.split(sourcefile) + targetfile = os.path.join("/_downloads", filename) + html = "".format(targetfile) self.markdown_lines.append(html) def depart_download_reference(self, node): @@ -841,10 +851,9 @@ def check_duplicate_files(self, uri): """ Parse URI for duplicate files in catalog """ - path, filename = os.path.split(uri) - if self.in_image: - #Check for file by the same name in library and increment if found - while filename in self.builder.image_library['index']: + #Check for file by the same name in library and increment if found + def rename_file(filename, library): + while filename in library['index']: base, ext = os.path.splitext(filename) if re.search("-\d*", base): base, num = base.split("-") @@ -852,7 +861,15 @@ def check_duplicate_files(self, uri): filename = base+"-"+num+ext else: filename = base+"-1"+ext + return filename + + path, filename = os.path.split(uri) + if self.in_image: + filename = rename_file(filename, self.builder.image_library) self.builder.image_library['index'].append(filename) + elif self.in_download_reference: + filename = rename_file(filename, self.builder.download_library) + self.builder.download_library['index'].append(filename) else: raise NotImplementedError return path, filename From 31c3eba764f3c0732151e475cfe3e9073b03c0b0 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 11:40:37 +1000 Subject: [PATCH 11/31] adjust make_site and handling of static assets --- sphinxcontrib/jupyter/builders/jupyter.py | 60 +++++----- sphinxcontrib/jupyter/writers/make_site.py | 130 +++++++++++---------- 2 files changed, 99 insertions(+), 91 deletions(-) diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index 40466d6b..06ba21bf 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -130,7 +130,7 @@ def write_doc(self, docname, doctree): ### print an output for downloading notebooks as well with proper links if variable is set if "jupyter_download_nb" in self.config and self.config["jupyter_download_nb"]: - outfilename = os.path.join(self.outdir + "/_downloads", os_path(docname) + self.out_suffix) + outfilename = os.path.join(self.outdir + "/_download_ipynb", os_path(docname) + self.out_suffix) ensuredir(os.path.dirname(outfilename)) self.writer._set_ref_urlpath(self.config["jupyter_download_nb_urlpath"]) self.writer._set_jupyter_download_nb_image_urlpath((self.config["jupyter_download_nb_image_urlpath"])) @@ -173,17 +173,24 @@ def write_doc(self, docname, doctree): self.logger.warning("error writing file %s: %s" % (outfilename, err)) def copy_static_files(self): - #copy image objects to _images + """ + Process Static Files including image and download libraries + """ self.process_image_library(self.outdir) self.process_download_library(self.outdir) - - #TODO: review in reference to images - # copy all static files to build folder - self.logger.info(bold("[builder] copying bulk static files... "), nonl=True) - ensuredir(os.path.join(self.outdir, '_static')) + + if self.config['jupyter_execute_notebooks']: + self.process_image_library(self.executed_notebook_dir) + self.process_download_library(self.executed_notebook_dir) + + # copy all static files to build folder + target = os.path.join(self.outdir, '_static') + self.logger.info(bold("[builder] copying bulk static files to {}\n".format(target)), nonl=True) + ensuredir(target) if self.config["jupyter_execute_notebooks"]: - self.logger.info(bold("[builder] copying bulk static files to executed folder... \n"), nonl=True) - ensuredir(os.path.join(self.executed_notebook_dir, '_static')) + target = os.path.join(self.executed_notebook_dir, '_static') + self.logger.info(bold("[builder] copying bulk static files to {}\n".format(target)), nonl=True) + ensuredir(target) # excluded = Matcher(self.config.exclude_patterns + ["**/.*"]) for static_path in self.config["jupyter_static_file_path"]: @@ -191,14 +198,12 @@ def copy_static_files(self): if not os.path.exists(entry): self.logger.warning( "[builder] jupyter_static_path entry {} does not exist" - .format(entry)) + .format(entry) + ) else: copy_asset(entry, os.path.join(self.outdir, "_static")) if self.config["jupyter_execute_notebooks"]: - self.process_image_library(self.executed_notebook_dir) - self.process_download_library(self.executed_notebook_dir) copy_asset(entry, os.path.join(self.executed_notebook_dir, "_static")) - self.logger.info("done") def process_image_library(self, context): """ @@ -225,31 +230,26 @@ def process_download_library(self, context): if fl == "index": continue src = os.path.join(self.srcdir, fl) - target = os.path.join(download_path, self.download_library[fl]) - copyfile(src, target) - + if not os.path.exists(src): + self.logger.info(bold("[builder] cannot find download: {}".format(src))) + else: + target = os.path.join(download_path, self.download_library[fl]) + copyfile(src, target) def finish(self): self.finish_tasks.add_task(self.copy_static_files) - if (self.config["jupyter_execute_notebooks"]): - # watch progress of the execution of futures - self.logger.info(bold("Starting notebook execution and html conversion(if set in config)...")) - #progress(self.futures) - - # save executed notebook + #-execute notebooks collection-# + if self.config["jupyter_execute_notebooks"]: + self.logger.info(bold("[execute_notebooks] Starting notebook execution and html conversion")) error_results = self._execute_notebook_class.save_executed_notebook(self) - - ##generate coverage if config value set + + #-make coverage reports currently requires jupyter_execute_notebooks=True-# if self.config['jupyter_make_coverage']: - ## produces a JSON file of dask execution self._execute_notebook_class.produce_dask_processing_report(self) - - ## generate the JSON code execution reports file error_results = self._execute_notebook_class.produce_code_execution_report(self, error_results) - self._execute_notebook_class.create_coverage_report(self, error_results) - - ### create a website folder + + # create a complete website from compiled componenents if "jupyter_make_site" in self.config and self.config['jupyter_make_site']: self._make_site_class.build_website(self) diff --git a/sphinxcontrib/jupyter/writers/make_site.py b/sphinxcontrib/jupyter/writers/make_site.py index e453a32e..f1026200 100644 --- a/sphinxcontrib/jupyter/writers/make_site.py +++ b/sphinxcontrib/jupyter/writers/make_site.py @@ -6,81 +6,89 @@ class MakeSiteWriter(): """ - Makes website for each package + Compile website from components """ logger = logging.getLogger(__name__) - def __init__(self, builderSelf): - builddir = builderSelf.outdir + + def __init__(self, builder): + self.builder = builder ## removing the /jupyter from path to get the top directory - index = builddir.rfind('/jupyter') + index = self.builder.outdir.rfind('/jupyter') if index > 0: - builddir = builddir[0:index] + self.builder.outdir = self.builder.outdir[0:index] ## defining directories - self.websitedir = builddir + "/jupyter_html/" - self.downloadipynbdir = self.websitedir + "/_downloads/ipynb/" - - def build_website(self, builderSelf): - if os.path.exists(self.websitedir): - shutil.rmtree(self.websitedir) - - builderSelf.themePath = builderSelf.config['jupyter_theme_path'] - themeFolder = builderSelf.config['jupyter_theme'] - - if themeFolder is not None: - builderSelf.themePath = builderSelf.themePath + "/" + themeFolder - - if os.path.exists(builderSelf.themePath): - pass + self.website_folder = self.builder.outdir + "/jupyter_html/" + self.download_ipynb_folder = self.website_folder + "/_downloads/ipynb/" + + def copy_theme_assets(self): + """ copies theme assets """ + self.theme_path = self.builder.config['jupyter_theme_path'] + self.theme_folder = self.builder.config['jupyter_theme'] + if self.theme_folder is not None: + self.theme_path = self.theme_path + "/" + self.theme_folder + #-Check Theme Path-# + if not os.path.exists(self.theme_path): + self.logger.warning("[copy_theme_assets] the theme directory {} is not found".format(self.theme_path)) + exit(1) + #-Copy HTML theme files to self.website_dir-# + self.html_assets_source = self.theme_path + "/html/" + if os.path.exists(self.html_assets_source): + copy_tree(self.html_assets_source, self.website_folder, preserve_symlinks=1) else: - self.logger.warning("theme directory not found") - exit() - - htmlFolder = builderSelf.themePath + "/html/" - staticFolder = builderSelf.themePath + "/static" - - ## copies the html and downloads folder - shutil.copytree(builderSelf.outdir + "/html/", self.websitedir, symlinks=True) - - ## copies all the static files - shutil.copytree(builderSelf.outdir + "/_static/", self.websitedir + "_static/", symlinks=True) - ## copies all the image files - image_path = os.path.join(builderSelf.outdir, "_images") - if os.path.exists(image_path): - shutil.copytree(image_path, self.websitedir + "_images/", symlinks=True) - - ## copies all theme files to _static folder - if os.path.exists(staticFolder): - copy_tree(staticFolder, self.websitedir + "_static/", preserve_symlinks=1) - else: - self.logger.warning("static folder not present in the themes directory") - - ## copies the helper html files - if os.path.exists(htmlFolder): - copy_tree(htmlFolder, self.websitedir, preserve_symlinks=1) + self.logger.warning("[copy_theme_assets] html folder not present in the themes directory") #@AAKASH will there always be an html folder required in theme folder? + #-Copy other static assets to _static-# + self.static_theme_source = self.theme_path + "/static" + if os.path.exists(self.static_theme_source): + copy_tree(self.static_theme_source, self.website_folder + "_static/", preserve_symlinks=1) else: - self.logger.warning("html folder not present in the themes directory") - + self.logger.warning("[copy_theme_assets] static folder not present in the themes directory") - if "jupyter_coverage_dir" in builderSelf.config and builderSelf.config["jupyter_coverage_dir"]: - if os.path.exists(builderSelf.config['jupyter_coverage_dir']): - self.coveragedir = builderSelf.config['jupyter_coverage_dir'] + def copy_image_library(self): + """ copies image library """ + image_path = os.path.join(self.builder.outdir, "_images") + if os.path.exists(image_path): + shutil.copytree(image_path, self.website_folder + "_images/", symlinks=True) + + def copy_download_library(self): + """ copies download library """ + download_path = os.path.join(self.builder.outdir, "_downloads") + if os.path.exists(download_path): + shutil.copytree(download_path, self.website_folder + "_downloads/", symlinks=True) + + def build_website(self): + # clean old website + if os.path.exists(self.website_folder): + shutil.rmtree(self.website_folder) + + # copies html and downloads folder + shutil.copytree(self.builder.outdir + "/html/", self.website_folder, symlinks=True) + self.copy_image_library() + self.copy_download_library() + self.copy_theme_assets() + + ## copies all the static files (TODO: disable to debug!) + # shutil.copytree(self.builder.outdir + "/_static/", self.website_folder + "_static/", symlinks=True) + + if "jupyter_coverage_dir" in self.builder.config and self.builder.config["jupyter_coverage_dir"]: + if os.path.exists(self.builder.config['jupyter_coverage_dir']): + self.coveragedir = self.builder.config['jupyter_coverage_dir'] ## copies the report of execution results if os.path.exists(self.coveragedir + "/jupyter/reports/code-execution-results.json"): - shutil.copy2(self.coveragedir + "/jupyter/reports/code-execution-results.json", self.websitedir + "_static/") + shutil.copy2(self.coveragedir + "/jupyter/reports/code-execution-results.json", self.website_folder + "_static/") else: - self.logger.error("coverage directory not found. Please ensure to run coverage build before running website build") - else: - self.logger.error(" coverage directory nbot specified. Please specify coverage directory for creating website reports ") - - - ## copies the downloads folder - if "jupyter_download_nb" in builderSelf.config and builderSelf.config["jupyter_download_nb"]: - if os.path.exists(builderSelf.outdir + "/_downloads"): - shutil.copytree(builderSelf.outdir + "/_downloads", self.downloadipynbdir, symlinks=True) + self.logger.error("[coverage] coverage directory {} not found. Please ensure to run coverage build \ + before running website build".format(self.builder.config['jupyter_coverage_dir']) + ) + + ## copies the downloadable ipynb assets to downloads ipynb support folder + if "jupyter_download_nb" in self.builder.config and self.builder.config["jupyter_download_nb"]: + download_ipynb_source = self.builder.outdir + "/_download_ipynb" + if os.path.exists(download_ipynb_source): + shutil.copytree(download_ipynb_source, self.download_ipynb_folder, symlinks=True) else: - self.logger.warning("Downloads folder not created during build") + self.logger.warning("[make_site] IPYNB downloads folder {} not created during build".format(download_ipynb_source)) From 66f8991d1ddec7c788e2a1dfa6aad4559170cf4c Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 12:18:56 +1000 Subject: [PATCH 12/31] update references to images and downloads --- sphinxcontrib/jupyter/writers/translate_all.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index f9229da8..d6c48d40 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -183,11 +183,11 @@ def visit_image(self, node): #add files to image libary for builder path, filename = self.check_duplicate_files(uri) self.builder.image_library[uri] = filename - uri = os.path.join("/_images", filename) + uri = os.path.join("_images", filename) else: #Already added to image libary for builder to copy asset path, filename = os.path.split(uri) - uri = os.path.join("/_images", filename) + uri = os.path.join("_images", filename) #-Parse link updating for jupyter_download_nb_image_urlpath if self.jupyter_download_nb_image_urlpath: if '?' in node['candidates']: @@ -401,11 +401,11 @@ def visit_download_reference(self, node): #add files to download libary for builder path, filename = self.check_duplicate_files(sourcefile) self.builder.download_library[sourcefile] = filename - targetfile = os.path.join("/_downloads", filename) + targetfile = os.path.join("_downloads", filename) else: #Already added to image libary for builder to copy asset path, filename = os.path.split(sourcefile) - targetfile = os.path.join("/_downloads", filename) + targetfile = os.path.join("_downloads", filename) html = "".format(targetfile) self.markdown_lines.append(html) From c03e5227f41fa4c6b14a49321b64916058a8a120 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 12:19:12 +1000 Subject: [PATCH 13/31] comment out bulk copy of static to see what is missing --- sphinxcontrib/jupyter/builders/jupyter.py | 46 +++++++++++------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index 06ba21bf..d65ea7cb 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -52,7 +52,7 @@ def init(self): instructions = overrides.split(",") for instruction in instructions: - if instruction: + if instruction: #TODO: @AAKASH what is this doing? if instruction == 'code_only': self.config["jupyter_conversion_mode"] = "code" else: @@ -90,6 +90,7 @@ def init(self): self.download_library = { 'index' : [], } + import pdb; pdb.set_trace() def get_outdated_docs(self): for docname in self.env.found_docs: @@ -119,7 +120,6 @@ def prepare_writing(self, docnames): copy_dependencies(self) if (self.config["jupyter_execute_notebooks"]): - ## copies the dependencies to the executed folder copy_dependencies(self, self.executedir) def write_doc(self, docname, doctree): @@ -183,27 +183,27 @@ def copy_static_files(self): self.process_image_library(self.executed_notebook_dir) self.process_download_library(self.executed_notebook_dir) - # copy all static files to build folder - target = os.path.join(self.outdir, '_static') - self.logger.info(bold("[builder] copying bulk static files to {}\n".format(target)), nonl=True) - ensuredir(target) - if self.config["jupyter_execute_notebooks"]: - target = os.path.join(self.executed_notebook_dir, '_static') - self.logger.info(bold("[builder] copying bulk static files to {}\n".format(target)), nonl=True) - ensuredir(target) - - # excluded = Matcher(self.config.exclude_patterns + ["**/.*"]) - for static_path in self.config["jupyter_static_file_path"]: - entry = os.path.join(self.confdir, static_path) - if not os.path.exists(entry): - self.logger.warning( - "[builder] jupyter_static_path entry {} does not exist" - .format(entry) - ) - else: - copy_asset(entry, os.path.join(self.outdir, "_static")) - if self.config["jupyter_execute_notebooks"]: - copy_asset(entry, os.path.join(self.executed_notebook_dir, "_static")) + # # copy all static files to build folder + # target = os.path.join(self.outdir, '_static') + # self.logger.info(bold("[builder] copying bulk static files to {}\n".format(target)), nonl=True) + # ensuredir(target) + # if self.config["jupyter_execute_notebooks"]: + # target = os.path.join(self.executed_notebook_dir, '_static') + # self.logger.info(bold("[builder] copying bulk static files to {}\n".format(target)), nonl=True) + # ensuredir(target) + + # # excluded = Matcher(self.config.exclude_patterns + ["**/.*"]) + # for static_path in self.config["jupyter_static_file_path"]: + # entry = os.path.join(self.confdir, static_path) + # if not os.path.exists(entry): + # self.logger.warning( + # "[builder] jupyter_static_path entry {} does not exist" + # .format(entry) + # ) + # else: + # copy_asset(entry, os.path.join(self.outdir, "_static")) + # if self.config["jupyter_execute_notebooks"]: + # copy_asset(entry, os.path.join(self.executed_notebook_dir, "_static")) def process_image_library(self, context): """ From 0ca3e3a5774762b63afdb538b7dc81f6637542ec Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 12:37:39 +1000 Subject: [PATCH 14/31] remove make_site influence on outdir in builder and keep local setting --- sphinxcontrib/jupyter/writers/make_site.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sphinxcontrib/jupyter/writers/make_site.py b/sphinxcontrib/jupyter/writers/make_site.py index f1026200..01a68a20 100644 --- a/sphinxcontrib/jupyter/writers/make_site.py +++ b/sphinxcontrib/jupyter/writers/make_site.py @@ -16,10 +16,10 @@ def __init__(self, builder): ## removing the /jupyter from path to get the top directory index = self.builder.outdir.rfind('/jupyter') if index > 0: - self.builder.outdir = self.builder.outdir[0:index] + self.outdir = self.builder.outdir[0:index] ## defining directories - self.website_folder = self.builder.outdir + "/jupyter_html/" + self.website_folder = self.outdir + "/jupyter_html/" self.download_ipynb_folder = self.website_folder + "/_downloads/ipynb/" def copy_theme_assets(self): @@ -47,13 +47,13 @@ def copy_theme_assets(self): def copy_image_library(self): """ copies image library """ - image_path = os.path.join(self.builder.outdir, "_images") + image_path = os.path.join(self.outdir, "_images") if os.path.exists(image_path): shutil.copytree(image_path, self.website_folder + "_images/", symlinks=True) def copy_download_library(self): """ copies download library """ - download_path = os.path.join(self.builder.outdir, "_downloads") + download_path = os.path.join(self.outdir, "_downloads") if os.path.exists(download_path): shutil.copytree(download_path, self.website_folder + "_downloads/", symlinks=True) @@ -63,13 +63,13 @@ def build_website(self): shutil.rmtree(self.website_folder) # copies html and downloads folder - shutil.copytree(self.builder.outdir + "/html/", self.website_folder, symlinks=True) + shutil.copytree(self.outdir + "/html/", self.website_folder, symlinks=True) self.copy_image_library() self.copy_download_library() self.copy_theme_assets() ## copies all the static files (TODO: disable to debug!) - # shutil.copytree(self.builder.outdir + "/_static/", self.website_folder + "_static/", symlinks=True) + # shutil.copytree(self.outdir + "/_static/", self.website_folder + "_static/", symlinks=True) if "jupyter_coverage_dir" in self.builder.config and self.builder.config["jupyter_coverage_dir"]: if os.path.exists(self.builder.config['jupyter_coverage_dir']): @@ -84,7 +84,7 @@ def build_website(self): ## copies the downloadable ipynb assets to downloads ipynb support folder if "jupyter_download_nb" in self.builder.config and self.builder.config["jupyter_download_nb"]: - download_ipynb_source = self.builder.outdir + "/_download_ipynb" + download_ipynb_source = self.outdir + "/_download_ipynb" if os.path.exists(download_ipynb_source): shutil.copytree(download_ipynb_source, self.download_ipynb_folder, symlinks=True) else: From 28873037ecb09f72573156c81389102bd5957979 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 12:38:29 +1000 Subject: [PATCH 15/31] remove debug statement --- sphinxcontrib/jupyter/builders/jupyter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index d65ea7cb..814b4389 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -90,7 +90,6 @@ def init(self): self.download_library = { 'index' : [], } - import pdb; pdb.set_trace() def get_outdated_docs(self): for docname in self.env.found_docs: From e26df12fecfb89ce016680b2c497b48cf2e307db Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 13:06:43 +1000 Subject: [PATCH 16/31] update reference solution for downloads --- tests/base/ipynb/download.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/base/ipynb/download.ipynb b/tests/base/ipynb/download.ipynb index 84443fd0..26d0af16 100644 --- a/tests/base/ipynb/download.ipynb +++ b/tests/base/ipynb/download.ipynb @@ -6,7 +6,7 @@ "source": [ "# Download\n", "\n", - "Add test for download directive here" + "Add test for download directive here" ] } ], From d5150f94bbc3326d6406d5fe7d35b76960c8c80f Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 13:57:58 +1000 Subject: [PATCH 17/31] bug fix --- sphinxcontrib/jupyter/builders/jupyter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index 814b4389..a1bc2347 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -251,4 +251,4 @@ def finish(self): # create a complete website from compiled componenents if "jupyter_make_site" in self.config and self.config['jupyter_make_site']: - self._make_site_class.build_website(self) + self._make_site_class.build_website() From bb17a7f560fc85ada58474cdcd1e2c7c2dbf64f5 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 14:01:41 +1000 Subject: [PATCH 18/31] bug fix -- source directory incorrect after changes --- sphinxcontrib/jupyter/writers/make_site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinxcontrib/jupyter/writers/make_site.py b/sphinxcontrib/jupyter/writers/make_site.py index 01a68a20..90ec112e 100644 --- a/sphinxcontrib/jupyter/writers/make_site.py +++ b/sphinxcontrib/jupyter/writers/make_site.py @@ -63,7 +63,7 @@ def build_website(self): shutil.rmtree(self.website_folder) # copies html and downloads folder - shutil.copytree(self.outdir + "/html/", self.website_folder, symlinks=True) + shutil.copytree(self.outdir + "jupyter/html/", self.website_folder, symlinks=True) self.copy_image_library() self.copy_download_library() self.copy_theme_assets() From febeae98d89b705aea7936441c238f52d3221aa6 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 14:16:35 +1000 Subject: [PATCH 19/31] fix path --- sphinxcontrib/jupyter/writers/make_site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinxcontrib/jupyter/writers/make_site.py b/sphinxcontrib/jupyter/writers/make_site.py index 90ec112e..3b1ab163 100644 --- a/sphinxcontrib/jupyter/writers/make_site.py +++ b/sphinxcontrib/jupyter/writers/make_site.py @@ -63,7 +63,7 @@ def build_website(self): shutil.rmtree(self.website_folder) # copies html and downloads folder - shutil.copytree(self.outdir + "jupyter/html/", self.website_folder, symlinks=True) + shutil.copytree(self.outdir + "/jupyter/html/", self.website_folder, symlinks=True) self.copy_image_library() self.copy_download_library() self.copy_theme_assets() From c5371e90bb65339228fcedc08f830466ead1d80f Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 15:15:35 +1000 Subject: [PATCH 20/31] fix source build dir paths --- sphinxcontrib/jupyter/writers/make_site.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinxcontrib/jupyter/writers/make_site.py b/sphinxcontrib/jupyter/writers/make_site.py index 3b1ab163..cd0d1677 100644 --- a/sphinxcontrib/jupyter/writers/make_site.py +++ b/sphinxcontrib/jupyter/writers/make_site.py @@ -47,13 +47,13 @@ def copy_theme_assets(self): def copy_image_library(self): """ copies image library """ - image_path = os.path.join(self.outdir, "_images") + image_path = os.path.join(self.builder.outdir, "_images") if os.path.exists(image_path): shutil.copytree(image_path, self.website_folder + "_images/", symlinks=True) def copy_download_library(self): """ copies download library """ - download_path = os.path.join(self.outdir, "_downloads") + download_path = os.path.join(self.builder.outdir, "_downloads") if os.path.exists(download_path): shutil.copytree(download_path, self.website_folder + "_downloads/", symlinks=True) @@ -63,13 +63,13 @@ def build_website(self): shutil.rmtree(self.website_folder) # copies html and downloads folder - shutil.copytree(self.outdir + "/jupyter/html/", self.website_folder, symlinks=True) + shutil.copytree(self.builder.outdir + "/html/", self.website_folder, symlinks=True) self.copy_image_library() self.copy_download_library() self.copy_theme_assets() ## copies all the static files (TODO: disable to debug!) - # shutil.copytree(self.outdir + "/_static/", self.website_folder + "_static/", symlinks=True) + # shutil.copytree(self.builder.outdir + "/_static/", self.website_folder + "_static/", symlinks=True) if "jupyter_coverage_dir" in self.builder.config and self.builder.config["jupyter_coverage_dir"]: if os.path.exists(self.builder.config['jupyter_coverage_dir']): From 17788ef688eb504da616ab395ab55c2893a60aa0 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 16:22:40 +1000 Subject: [PATCH 21/31] fix bug for downloads library --- sphinxcontrib/jupyter/writers/translate_all.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index d6c48d40..af43609e 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -397,13 +397,14 @@ def depart_footnote(self, node): def visit_download_reference(self, node): self.in_download_reference = True sourcefile = node['reftarget'] - if sourcefile not in self.builder.image_library.keys(): + if sourcefile not in self.builder.download_library.keys(): #add files to download libary for builder path, filename = self.check_duplicate_files(sourcefile) self.builder.download_library[sourcefile] = filename targetfile = os.path.join("_downloads", filename) + import pdb; pdb.set_trace() else: - #Already added to image libary for builder to copy asset + #Already added to download libary for builder to copy asset path, filename = os.path.split(sourcefile) targetfile = os.path.join("_downloads", filename) html = "".format(targetfile) From f688d3ecb43e0b352ef30760d3fe9ef504359100 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 16:24:32 +1000 Subject: [PATCH 22/31] remove debug --- sphinxcontrib/jupyter/writers/translate_all.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index af43609e..d8cf4ad5 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -402,7 +402,6 @@ def visit_download_reference(self, node): path, filename = self.check_duplicate_files(sourcefile) self.builder.download_library[sourcefile] = filename targetfile = os.path.join("_downloads", filename) - import pdb; pdb.set_trace() else: #Already added to download libary for builder to copy asset path, filename = os.path.split(sourcefile) From d541230ed451c14b45f79b0a3b01335667f26b11 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 11 Sep 2019 17:04:52 +1000 Subject: [PATCH 23/31] fix relative paths if specified in image uri --- sphinxcontrib/jupyter/writers/translate_all.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index d8cf4ad5..74153f3a 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -176,6 +176,12 @@ def visit_image(self, node): """ self.in_image = True uri = node.attributes["uri"] + #Adjust for Relative References as spphinx returns uri with subfolders before uri provided in rst file + adjust_relative_path = False + if "../" in uri: + adjust_relative_path = True + num_path_steps = uri.count("../") + uri = "/".join(uri.split("/")[num_path_steps:]) #remove leading folders added by sphinx if '?' in node['candidates']: # don't rewrite nonlocal image URIs pass @@ -188,6 +194,8 @@ def visit_image(self, node): #Already added to image libary for builder to copy asset path, filename = os.path.split(uri) uri = os.path.join("_images", filename) + if adjust_relative_path: + uri = "../"*num_path_steps + uri #-Parse link updating for jupyter_download_nb_image_urlpath if self.jupyter_download_nb_image_urlpath: if '?' in node['candidates']: From 266aff9c0c5795878b0b3584918633c39be4b717 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 12 Sep 2019 11:02:52 +1000 Subject: [PATCH 24/31] add test cases for image relatives path fixes and adjustments in translators and buidler --- sphinxcontrib/jupyter/builders/jupyter.py | 11 ++++- .../jupyter/writers/translate_all.py | 18 ++++++-- tests/_static/simple_notebook.png | Bin 0 -> 57163 bytes tests/base/images.rst | 18 +++++++- tests/base/ipynb/images.ipynb | 19 ++++++++ tests/base/ipynb/index.ipynb | 4 +- tests/base/ipynb/section2/images.ipynb | 41 ++++++++++++++++++ tests/base/section2/images.rst | 18 ++++++++ tests/base/section2/index.rst | 1 + 9 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 tests/_static/simple_notebook.png create mode 100644 tests/base/ipynb/section2/images.ipynb create mode 100644 tests/base/section2/images.rst diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index aa168eaa..8cd5dd46 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -246,8 +246,15 @@ def process_image_library(self, context): for uri in self.image_library.keys(): if uri == "index": continue - src = os.path.join(self.srcdir, uri) - target = os.path.join(image_path, self.image_library[uri]) + file, internal_image = self.image_library[uri] + if "../" in uri and internal_image == False: + num_steps = uri.count("../") + srcdir = "/".join(self.srcdir.split("/")[0:-1*num_steps]) + else: + srcdir = self.srcdir + uri = uri.replace("../", "") + src = os.path.join(srcdir, uri) + target = os.path.join(image_path, file) copyfile(src, target) def process_download_library(self, context): diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index 74153f3a..bf79100c 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -176,26 +176,38 @@ def visit_image(self, node): """ self.in_image = True uri = node.attributes["uri"] + internal_image = True + file_depth = len(self.source_file_name.split("/")) + #-Adjust Absolute Path-# + if file_depth > 2 and "../" not in uri: + uri = "../"*(file_depth - 2) + uri #Adjust for Relative References as spphinx returns uri with subfolders before uri provided in rst file adjust_relative_path = False if "../" in uri: adjust_relative_path = True num_path_steps = uri.count("../") - uri = "/".join(uri.split("/")[num_path_steps:]) #remove leading folders added by sphinx + #-Determine if local image-# + if num_path_steps > (file_depth - 2): + internal_image = False + #remove leading folders for subdirectories added by sphinx for internal + uri = "/".join(uri.split("/")[num_path_steps:]) if '?' in node['candidates']: # don't rewrite nonlocal image URIs pass elif uri not in self.builder.image_library.keys(): #add files to image libary for builder path, filename = self.check_duplicate_files(uri) - self.builder.image_library[uri] = filename + self.builder.image_library[uri] = (filename, internal_image) uri = os.path.join("_images", filename) else: #Already added to image libary for builder to copy asset path, filename = os.path.split(uri) uri = os.path.join("_images", filename) + #-Adjustment for nested folders added by sphinx-# if adjust_relative_path: - uri = "../"*num_path_steps + uri + #Note: A depth of 2 is in the root level of the project directory + if file_depth > 2: + uri = "../"*(file_depth-2) + uri #-Parse link updating for jupyter_download_nb_image_urlpath if self.jupyter_download_nb_image_urlpath: if '?' in node['candidates']: diff --git a/tests/_static/simple_notebook.png b/tests/_static/simple_notebook.png new file mode 100644 index 0000000000000000000000000000000000000000..854da1769e06e5c02462490758aa0a3576f226b0 GIT binary patch literal 57163 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 z�xQTf_HF=~~G50Sr_M;p5j|)maLw7H9%E8Y?~IjkVYDC|X>=ir)O)=>ulti3FY?Gbyrv=UG9v4j28(lqR>Co20mfMmmeM@`w>Co1Aa(Q6Y*mWGp6GD+R+mhPo} z1$NO}l&ar#1G=Ny4Io8uJ8G&LY?0F6c-z+F1Rk>f8 zXLd=PxC|d-JOs0OHJ2LB*a+Y~F4+i^2i!tO!7#s>N9oK`|C!oU%ep`K5FnI!rfpk6 zkvjI4L_r}%{2S|dB45J5yD+D@czJ%6i+;d2%-oRT3VB2@{haT)iM_MF?B*KGOd=AZ zHc-6Ld;GaPne|b%n#UQ(v!TlT&OS1CHbHXyLeofPrQE(EJWg_>BENQZG|&piu0q;N zT9Cd9H0r|Gn6R&BXci3qFVQv}1ZoMNbovLH1ry68qC!523MXOib9|cIjW|vxW|1w& zTx&>&{0%jj!tD_Uwsqvb>EY5h(QO{X(>XbxI!I5TplNzvQ6`eq+l57`8lKmY_d)-4 z+2<%iJ%~KSI@ZP2d&v(jPK{0N$_QOs{UYYncE+6pHA+Ag2btR2FF-YD2>?Rj9YWi- zY3J)R{7`u;`8B-Z|1)$06#FUQSWTe+lZW-A{?+AlnaaaIKTPM|{)YEP&jP6)A07f^ zByPf-E~@rRHYgIRBz{DDLF zz5VUpHDWn+2N0{C?7^^^-}KA=m5-`@Yab=A^!*yhhpAtmRk-#je{&gn-jog#-B+?o z7|>lg_s*z%4fgYg?Ih^e%=*U*B-2$WCj52O6Ya-=6h?VpyK+d7Ecz@^G3HY$B~fee z_->dG;$we?71PV%>2AY)Ud+|NR(-Tiyq`jW%)q5OK&p6cYKNvHTu)XvHXcbjv~u;% zG#*=nDD)y2lLT^mcHBfAsN9BQ4ElF`PC|BpDcn_M;EO4iESr%E`# zP~XxQ6viZH?d;4Gujz99Ox65+%UbxY5!}HjT+^uf1Y?sDgoV=$2StOaGv2!DxC(@i z2l0El(wgCNTDiR*<&jY_bvujY0kMX~Lfc~_JIhfkSXTy`>+lzw8A%|0_0>8S|`2|)1iXxS&A`cGu@$oKm82PDSzLa$5du#crJOQ*<$=m+$M_gf34 z4E37gRjL2%O{OewtRCC+k8mStQ`{f_<`u?wgDVbQncA^BDC_tx08wyF*7bnXb}284 z+Kr2>Ug+|t-Tl$~761-Sq>_Q$)4#;)X8n?o)i!@Cv10~zc@_4FG;?Y9lK%OmQ-fXX;I(5=p|oX~W9 zk@q?xPQqKP+L5^wy;s|>a>)f+#(~vSUC+dt)(}(7y<*I6YaEgeBS@XiHUiuvfi4zBI!m!qBq)Werr(+$D6oOv(fb$k0XhaSew`tBK` zuAqn{YGKtL8vrRK2e}jz zB@xE_6PYx2khV2dzb2)`MkC8KUMe z=GwNS`tajNMH!Fa=)G$KDR4ZSS5;Y#d~u%BYjh0-9ODQ%~6dMNip{M|ag7AHTb8g;EImJ%%tAZ9URM{S7aS zyWhpB0{j`0w7RG(bOZmIAAR?90K-bPGAzi<2H=B&S9BSXks51wZn*2CmD;9* z_Fpo7yB+ip`v^Za?q6&FxRqOQfdigb*rj`bOfm%KxIVuWjZAcxyVh%B3Y;uKA!%v@ zH^sPyGR9LJGYk`WA=0Hmz6hsB2H$E5DyprwT;GbNW}4Wy)1|~ zIG6D-{!O2r^#0qi2C&^qnk7dxQ8uq~TY& zQYO|dBZ0n96e9}PpMOr(zL~NBHdYcG11jMB($_NQdeMJAwyo6Tm538-`mKL*;* z7>u7WpG=30!dsY`*bh`?c}9WrjDs~S$D#%!7;T&ABcvKLVls5mwXpQ{3(zp5^X#`@ z-aQ-%#4ZAk9Px_u#JDd(CwR2?KZOC1Ke7MX02(UDjFvG^N~8gW-o9;>5dJ~Lf||5Y62%Otv<~?cCUoj)ntbzKyze?IBKqQr z4J6{LQUST!JPUd#7U^(70fbqZ7llF3*e~TUP{F1@N_T#oE<2^!`nDMil1E(c2WODj z)_Y<-YsGmCjK2!1r|g2a)tW`_uH~TmMfSG9V3L^)GmWjo>xr)Lhu_+mt4OrikGQHGPkS%uQ`deZ&bs|Z4OVsc3E4Rmt7I6Gm4_D`NaX+tg z_Li}NGI)l_pMA$bUo$ha!Sxm3XD3VU&gRpM!*mhP13`+wq99y+|C`yx`-$3S_x>P2 z$S4H|%WWZDh^2e=tcID-@xYdLgeo+QA@E=Qh`_1;x8X_uBd>xCn)vT=O_ZkgHcqDN zKf_;uJTFZDw0Fj&9UHVspC)jQJfU4u<^yur}NDs zV;mRoQ%2^aLJ&(;P+P6)%t_oiK=o&)C8;)k;4!yvI{jTTG~5d?fc{RFeooN4cw6De z9`F2CWV|mTL+_^#QkJ949Gdw9ZF7BlGqx;$UX+*yPl@ma+?F2V{waR~e^QgV!;Jy> zUjQCvgqv4nk<$+0=2_>v@q7O<|FDRklC>kzTtYQ=twX4EMs3JJl;=>d(1(gZ7+~NPlsamyBlB> zbaFxrX8Voz+!;55mk+L@!l@2A_le$l1vJgV_;>}i-mQ%Uho&qHuv>9loP-(#mAd)< zIMqhXJHN~KbV{tQ4L?9Xd;#UP%bH+lC=aW(^d-yMhrJ=oa?F|;ZVhL}$?`Wto~UnN z@P6OnW^8}i1C-NyJDy^|>d7cvAPkwX{DNM!Mo#$I^PO}M|ubJ={OxEN1Ml*`A&fO|DZ(^Q_LBTI@(6N_#u7!A*B7M@}M+`!FY8 z`@+@X53#I<>B;rKw7-aSZDNFImpPm*rox!&PVYzIlF0)Jt5bP(uWr4#FD4PlZwQ50 z+gmn`1ll&66!sf#EjWLPZ7jX3?Gm{xy?@N_<_k^Jvg9}$yntirScxz?Jgsi@v~t9r zhf(n)6yH(tDuEYaQ+**0TGu!412TOIK3}z>|7#Sg`sPE!Ni50mW1Qak)x<%%OY5X; zS@A2P;1^#O2Od>uy~v5I?(OV!LKuM#Ube2!>oD?{;Tk2o1jE0D9+!5nIB0&p&<2_A zllX?R)bd+~U~E3ppIssm#OGFf77F2BY0MA*>5!>LI2)|^U4ME?*MMRti*bd>W}d`2 zd5WcSKo)Y^iw<}|awf20rE75hEfh~yJKMAg?HVYDY~77+6c_BqEPM1O^7d85$M(vj(Bv^HYU$8RUCeG%Mf?2a8-#O%32| zo%VGebhd*{DFxNC%-<64X5b6tM@<4Mf)_5ZD{NDyE_(0SBtp>CoDQ`i;AR)kNKXk| znkMz>ga`Vw9T)K9lz<99oxS*WMO(Q)WBre04?5ASpEuAF%FIkT6-iGeXX$QlE&6@s zJ|MuaryzodK1MCq6vQ_$&|Cc^XJ>fU#T}tWyN?xGj@bpE^<+Lo%gFtK9W<{YO>#49Aj1I+W!;pJxVYflbnm=T)?Dcw zAb=oP?W39WF&YPDoT$c6k{m5w)pu&PZ9!GiB)$dRMArqKjUuCjcR{rs7ZbSRBF?)l z5^oQ97+W)_$62e&)_v-bX*^WL&$3vXXcfpgQOF1og)j|q$v;qRu~jflWw@UDo>2| z9334uQA4At9rvF(;5>DQ8_rc%5BXMmI@Q&hWDiWgDh2UPh`F7wbbLFQxWcBgb44lh z{b90qc(~O(#QyVu3}=@zlYEbA$AOCRo2ys8@6GbX0?jwXO2=$zY5V6pvIwI(VO|Nh z3KP7!0U;fj&dp5-$HhyyK}h~}u!^`i@4~S}je}OeGKhlQl1B$fdw1XjRN85gKdl(l zP1ifc1xB5Eos$mbnDZH+QUHD27BcH0_20X?1P;pH$XT(@CO2@kTW;KB!9&DN8u@&a zjJ6IpH0Jly;=X1n0txCvb^u%a#Fp@mknXF}-KtKEi^}KW&iWuD@?@evSR_y7>PK6$H>rB>y9{`v1QWsn{8d@1vp^zkT{# z^zx|fY0E`*d4>lK%0Q6oeWat`DyvEBA15ziz$(s6-)&gDJMe5l+#OQiXPsRq6 zX7O}p8ocZBMBLwH-R)UfaTSaCA@3t`yCKlxeK1!)T4qrm@|601jZxyNQ=r)y-F7v- z<@ThHv&D}X;aEPoYjV}A(|kQ%{=9OaE#xWU;PC!{`hJlf{8{il{1b@yGYBZ@rxJ)$oIhfo2XjiC zFt>#TG{s| zfO>BZH{HST$`l8LGAMqtM-s41g0vgv4+A`%osWmh4;Em3q>Vo3JJh$W)Dgf&7ZG76 zZd^VIRED`Z?xLRDJ-_*Ls8c-NrfT$8l6TvxtO>nU`#pq3le^S`x5s29`+x|+nx)!< z8%4#yxMvQ`AfE>O6>z;>P+%nguv$OT^?uqai>h*9Bd=mpo4}7Oy}m{L!{*+u3F0~k z<0(JF@$Pap+CX3b`Caes`8{$*l;6#i!_FrR4q<;5Hsk;pYLWzSz{De>Lh{8MjwCX( zz^kOd>B-4Ixzu+MNb}A7;r)i={RT3&=8sSUg-M_iYWZlAqR0?cT}FF?Tg^|=Y++)o^_)wOs7Tb#Y^ z;zXQq9;T-~K|$f9i~!t20EPk2_!Yifa9h;^+q|E;JDUu+BJl^N{9NB63s8YKUa4chydriL2bnL zeNYJa%=zxL|7I7ljA*L8q6N}jP+wszmE5S>B5u0^&!a`Cz2$lDH*EtEi#7#XKw1MN{9iB5ujXf#$3ro8ubbfoSzPUnSf>*|z$FSj8%X zp`uIy5x`6RS9t-5g%&@T5tze$^(l(2A1cZovU?kT?GiT?H`@w-T*PnNfpy|fd=4xi zz*m6M?LP0h;JtZ1X@aOiWWju+9akDoLjv6@#A;ff&yqfU{FsnHavJZAB6&P-kxU$V z_4{A-KMQBE731z?=ndWk+J#l-sm{?E#d|1?>5Sy;O9ypVmCGu0%TmP3eEx3z@ByEK z0K;d{K@j&b>0+mVxA}X^ObN73QZtILd}iCH_ZZx%eV(1M=f^3zt_!}7ODB;O0{W%e z#p6DMVt>plGg~sPTc*I7ZCi0`4^1LOf4xAFRN;mip?tU&eXeR@vHmpRD2N(y*~Meo zpDg5RX>-*R$C#nA34lb}vX2K?)udB9wq(y9uUW`Sac1`c3Teww&ck|+6lI5nrmIF^ zH=C<>Z2>kK`?(pSk`^IVwEL(l;@bjL4GbdVz3Srln77j;g5!s z)6*&PbPOu#g`?Z~Dj5y-vo-ex2Q7$unQ-Fj+S+o%dY9GCNZ>VzD(ul+t1V24k_7r`Oe=JCbVvqIbBhYT<*GvHISviQCB|F%c-3X+w**4FR_EvEb4%Fc z%=H*P^YZa+pQqmVDkoaVsQuJ4u(B%1VS>Su=DJuP0uExZnljxNUvJ>%lLF8bRTSCB zuP|JU)YM|w`id4yf%|;_{{2ohWx!GjlEV~E%eo8@3j!C0Ypd#jdVy>sBC;D8%Y3aj& zz4wGMo6MX^Uh7V#nlO@C9 zXQXh2F5C0y==_=|ade@0>RMVBT%==V7F-IkZo(P-w!8cL?3|p`$&=NzG4judh_o~{ zpH!*5OrgA=M{_FTojkz$>J4nFEdahF^@Dl0(btQYodWllT@nscKR)7}{Kn>-^IY@? zw%R}m;FUr2N{Qy#1PavAOJ(|p~PX*j{lsV;f0M>AoT;C0a7p$!KIz#7~8$qmJ-Q(PCz|;OQ z`(ZZCylGCoNC3U>8_cU)O}U00V458QYm0YH(o9FHVdM&Wfz0Vk2Q-9i8fw?~q{oME zG(4?1uW28m;C%uPG9wHYJ=R4OdV2$@>(Ui~;M7VW!|;Rl8U6P=6T^G!j}PsqCkvT$ ze6XLOyub#))LO>hcCS}tD-Ss_Cm6q505xh>$&r^(!YaR^VuYP57+znXqi_WP54P^8 z*!U?Em*@7KmhB;mIR+3A@cPZOVB2k#$ptzYAvf|ibW{}NO{KHwvJM(@fa|YjNsu{- zz`vQHq<90L5uwY0kDV%h$3VWuD-21(6@~iqUWP!@HSBMHG<_Y(Juy+Zo+BS6B}!BM zy;??&#=Ps*6ADa}dR*k`Dvx2NQYweywN%!Mhd>d!PAX&@NW+`k+|Q-hGL>%}fMfW` zV^fRC_sm^4bXQ;lw*AIOD5P>oIW9ZCPhGdk{+yR?-SOii%GXig;8;@pdYc(na~7SM zpE&?yKwEcKMcSL!k|VrbzpBn!_W>fo2SjqM5~Zh_%9M34VhS9=1gOpFTF1qej&NjY zRjW*Ih8X!Le$euA$Br-}BornS4{=%2-cZ>dZ11;`l%u@x1UmM0W@g5sFVTLX$s17m z3~KDQP0E;hsqc?MZf|b^$ccXcz>LK0n(m6TYqryR6R3h?r3u(K386W4KvBJV*UiL) z1a{pYZ+9n3fkmh&=Dzgnqghu}yftM(Ug1Ux=hOzMiR|urT z)X2z4bnxj_iB$J+CwD){;7=xRg0UOZZ!gh>`Fa0}8BMyrmo#}rMGEDUbBktxyD=sbZ#Zy_1sb zN;$S$Irg%*-(QWE5TAHNM_(_-KUaRwde$1Ft$gqpMF^W+`0K8sqTGb+jr!ik(rvp5+fPi)&KejS z8|&*sJ!qum=?G+GWQd4}+DhV-8A1XD9vHHqQFXh^<{sbQ96m)u zAK7+$Dth!Qib@2NhEX-sZ>Olh*n6EQj9i%2@Eh30&cKbJQhkxQQ5Q(L?RKbhed)4#T^W3^4n@aeKjs2#JPxoHQhip` zZB-f2n-EJ*Ri7TjK6vp5SonpZhy6q8V84*$6!0UIY-Z%;HhXwHuGx7d5%ZJ)%%vjR zli&Y{NFwZkLOq!G{9}>V#hCE9)HlgN; z2VUo8H_F!_VBu=UeT|1#q{Cgmnz4&1D8Q$dQBZy&QHAfZ-T@wu0FQKu>I_20suL)Q znf(Z83sgZ-Q3u@sxN9S>fYk|5aS$p!^x(~FsaTPY2=t5$IWBxOlr>@iKE}`J*UO$P zG=M(uA#$o}pN=L!l*9#8zc;VVJu>0~SPvJDIZR<}ePKCtaSAeO z>IkY0JQ4%OQ-45Caw?urOU!xCi>1__xm>6h18b;g#$0b=+s$V3WwK>pHgm3Dm3hhY zZa}&)Vk#XbAq-ZX2v*#yg`9K!xj> zCxo$d$h@1N>d+ir6B9>Z&*w15JocJ<%N22HxxLqZIsa7!*_i(hF%yV*m4f0jg zXY*yw;HDCwBXF9u1i;w(Ds=4tP$mwi=j1#DH8Otw3WvjMYWNc^FgQdfMx<*F$b$&U zKbCw2llk5ZXs9D1J4{XdjyrG!=DuDjeqmHlXL^<@5!j3_0lXr2p~gOq-*#27tf{Ff zFAuyg^~DM3BVb+wsP}F{fgx^&?Rh7VwEw@rjM&)_0E^9M-#J5bE)N;7Bd5 z#5-&bMA=~h1%<{jO{)Fje@j*bax{l-62SKOLv!a!MV~_8g zKi@vTj>9pQuC<=Io|t!C*ER16GO$Y+K;!dxyTfPd5TCF}5U#!MTKt2`-7^Iuh%7kr zgostPOslcxu{DDK#&q{{|Au|Nrh((gxYjY#>}gOE_iD+4S1dZ>1X$}uWbpUg9^%AW zjO7?rVgCx|+^oR}A3tYN(Jy$J6Yx<}zdpbw#DUm91@7flRK*xMg_yRDr9_BA1k8pw zU^YcWO|4~)lr?@t^^d3U1)kzd4p_$Rn8dV(30a2&rie*Kp375eABy~97T#C$-*5bI zES}98$CQ89wLlB$c>;`zMncNoMY9?#>TV3LD$oFB@C(@Z89ZtGvIV@YXVze(f4?}= z?&_63h3F+2+wm6CrV8^Hza(EH8KCb)Um>5Lg7*?YE%ov9TXk?<^CP9+pgW!csLBMN zt4m-@s*MW&=l}CrBN;Ki;@kX_cx(Xw#ViZ08jG?2f%9PpA{Ylo?y2%8t3CTYS^5Q4 zI9zu?5Ypoe&NXprDte@6ACXespxG-5M%RWBg92B^VrNRk0hySLn%1YpMy2r;#FxoG z<5{Fx$!wiXY{ji<@+|p(e)Zr`vC-dwpLe#%89)OD2tx3_`*XE6$E%&NLB+kxLP8RH}}WU&o#N70!LD7 zIWyLJ2djYg%352@#`9p4VK|L%hg;JkB0$~IFtMuB$z0_Lgi$%n9BlQ$48;J344CBk zii(Qoh;JHTueqm9(^$2G<92N4xS|F`}qGdtU0w>je9o`XXG|lV>SEZ+gcrPGf`1*su6M8 z3l;NUAtHjo1Jx)KWy~vGv0G6ciKcPBb=@Ad3ZNqVv8(|_&h*ix&1{uq{y6YDAKn8@ zHSr^80o`zb4Ki&>0oKHxREKVuWKdcD|;%UMdiOu zSBbemOH^Pmkc>_|`2P=H=!6m#+Z{Wg(s_q4$*@EAIUY ziqF-uA4<#P!>t*YvVwBM+U!lz_~h5_eavvK}A--oHLXic&wa^Cy|50O9t#}An8?Eu?e@kdEjZUiD_R+t}2 zxk$+KlUrBSP#Bvp7z91HVVCJJ>;A?(o-rkS5pJn)ltBaniHHB^?P{+*8sc6`CXme- zV!?(Sy(%fr`7uGd4H0w(Nly>{x7uy0S6ox`+5cPz%*$}$+KdwWsFXfq|s zz@xl7yS?v^e=pB>eqQEt55tK;PW8g-zokHhPH&tH z;H6~L#r{n8uUQf3kFqijY$S6mW`9>+YesA_&q^dqrRR0_AVS3dXlnAjzd5g<>((!K zJKa>HivxLw-qg|lzNLi)ZBYV=*A+1_?!97T`j72x3*&kIN`(bxGRaq8g-^GJr zVy|IW6{Kt--Tdd%YQmv~ghU;2bZYhh zqH=L@5%}Bo3_KA)-PoGDL7}4{V_UwweMuZmDc{nb&Fa!!W{ZM@ZY47E#Fq}BFoGwi zr-Q~0k3MCMhYb^cU?p7fWKwB1t5bOL=PP73C-Nx!G&K4a2;<=j7LH)R-!+rpD{1^Y zGb`*JLl%Hi5zE-oZ>A zj*0kNXkq^?^((F*y=PDUfjUzv^rS!Jq%Y*;+G3*?0oc>23y;S=KMu1{OM+sew#&Pktzk=bkBW4t6V!GNk65Yb)N9on zqAp9E*YI&>vFL@4m@gsmAcZ4B?=m1H5S9>*ieS4m^cvaOK0x#udZcmuS-llPG9;*_ z&m8Nj{c!sI);jHEVXic_Q-<#SkoYqc!2no55Ei%j5_x?2GCne z)QG(*W<@niz4Eyy81!U89yi zZtVsxvaM?YA=J5F>rW5ZeP#X`W32&(O@PaDu}RKzCN^_uP`vB4Nca9-ZKgM|^&!7; z;qiDz$#Laioc3W@C4aaeslZtjGV?+<50V35G{6*sg2dd?62Fc&QN|lE#K7Kx8*Gib z?++=Jf7k8v!)9@=fC_ZeH5*wR-+G7`2FQgh4<#9GPG1V*ELtx#Os*a81CsQ+_&YAA-3g;39g4N9DNJI+ zrNZ!wkyejtTw{OIyhpc?!@`omeiTz+Lk!wvZDhPw}8U<(8PNLOKg_Xdpvn$l15 zylS^Y5052SAjyQ2RO6bRue2Kuws~;QH|P*Q^1kQ&N3gL48zWL4EC zW#wH*?#h`ai|Nvbd}Km?O*J)1g!+v*4Q=o1jfahpEP&R-a!N%E(Wo3lX08EZ3@*3+ zNpz&=>iEv`QDjhz(9qC8HF5Et7DZu=h=lSY1mX(1BMZ{&TfFld);m7s7#q&nc~Xj; z=aplO6p^4@8yt+Lp=Dvb(fR8mf51P+Y;XcMCmSta6M9gN7Qo8u)nFi8`RUUH%hcCz zY1;Y8teLt}l0phmAYuW4p~^tW9ax8EMNLi3Mt}VD^t5yoMnpI1_n=YEc@4>^974_X zi~`p#8hk#rxV2*uy%mJ&`{7>n;TF7p8OdkZ(}eRL8y=%*Czl-Znyw{>H+ZFy4vs*s}JKu55X3ot?$vH~MYS|GxuYAg;Vcd24dL6Lp`2pIJNwxGb z#fFNOXybWKlOT1zgjR}dQLCdYTP?!#tC#)CkEaH+hZFr3O-_4Lb2hCDx;K8OfV zgq?lal*5qe+VexM*$Uvigjy`Z0-RbRwZ&;D-)d@T|5nD3FQ!UThW?KEDEhqXp9?Gp z7nopDr+UZZwEIa z+O75*eK0aiyX+DGR!D&zph=?nBM9;g=PylIah*#SrZ>l|2)6WzCPunv9{;*EdT_Xu{m?xBNUa$7&zCmvDI^ z(%-JW*^#9IwQWM=nxt6_j)b^G8Z_Nz1PlB8xtlx9u;2zx$O+O$r<+PVrYt>eLrv4) z*^?}bJ`kB19{mh{V8!e$`BpL_hH<-_GOx5a(kX_jYrMt@5NaG1fow zgLwD`R{S<%i2E%W6LDv>g1AiNWG(1IoAa zx=CLa-~B_4K*Y$G3OHnO2+=XN5w52O74cnuy3ad2>2U**gpo$9`7p0oYO+-S)21x# z?Ro8%uCgtJ2=Xjm!a!Se(s7S(A&h9zQqHQwR)sWOUbQsF7J)(j7xP2^HlS zOy{4Mpoc^%!g7x)3I#Wv)^e!>ngE03LC?z?i%~Xs2&@olBfm=9P_LG*EAaF?eDwCp z16h%84Twi=~8v>XO)mL+X^lj>W#!EudcMQA%;kx8q)mYneBZssg9pwJUU<8 zV#fk2HvY*iY+r`CFVIh$9yY4vesvS5(T+%b1z8pbXK4G<{mfqzfJ+cb5us0x+zSNL zDg|1dZecGLj#@8scVf{e7~mjP0PcV=45nCYgNHm>x|$N$!g@~2A)^2=lMyO_^whDs zy|_oA8=oj$4QuD^K%d&1EPV>8g7v~;m~mH37UwZdk?7rW}N4j)S9vKoZa<8KV zGQb$DjU~s}o2BLkpF<@V3lGQ#$VUR$#Z-7^KPW42n7yS?5HmSn;FCbu*zTe*i+>s5l`^y404x=y^IQ0Ax4gHiZaBO8u--w^RqKlVbwTt|AAB< z7hsjyGg43tD29<*c&C0ymPAwxAY;^YqH@rtq0-EWF-F%F7L9YPg;N>Q5`8_z+Dxh8 zKirn{aAG@)bb2RB20&=r*3N%xdfiFUe-cz}c3RY42g+uy_4=(e7*N$l?sL^a$Y3A< z&=gSqm6esnlTpLSGPM5$eX`2SkD0^SrVQ1>yVroPk8cjN(bPE`%1mR8b7XSS)=-@q z6eZDo5zf~1so}m~=OOD?4LKA8aN0;O{ARx*5x4(&^OPzkI@!jx>Z zDy8^!Was%@-F9^ShjX<@0eE8PT4?~J0j@|18ly_b4hUwR!#dLUHg){<|3W^6&ZH#( z3JYoH(8dgPZc#9dz3Fl;wE{cgSG_Rs^ANj{g2 zOXuh3d?!7m#mXf~EG9#x0NAxzT3lRw=%XzID3RIt(12m#_>MxltynfRe;hDr&E9q1 z_t|RV^eWnOIWM2PXbPD1Z+YSt%e_XpHWi0-7#k)6w=+)DTH*+ayl(a&%W-mIBhIN)MYnp1 zYdEsk!nRe!^qL!GFxmY`cHqweA*2Eu48)y1$_a?HhsRyV20)VLy&DD)-{wFf%_N&O zz|1|YQwEeV>`KbZ|M)0LJ_&$_^X<YIIkLsqL=i;?mqF8x8 z(~w9!;OK~6!yM)b_JGO5+U}kS({|D;NIVK~3}Zw~8IMCH(>X5bmHq2SAlYobh4a+} zv1`L-yEa4;tHgzfU)3WBWz8KRcV zleQyDNS*$b=u?Q9!$Qs~ZMt2hKl2TNPMXK-)VL@JQ8#d{g0t9X4U|7PKE)z2F|KX% z)sHxCh4ncCT@n{y$01{dMKL#z?^5NlkU1#3IzPJIV7d%nwLB+?d_rUe``tlfWm!$T z;SHIz>N^V-<$0E8ECBh&g^hf3|M$XdDcQ#=O|R;Eu0J#X`RnL$_vUxhVAxlRg5V1{ zXE!=@4Q9fhkC#9lxZ2lw9e@>|aMV&x^X%&r!BT(|`7-ITZu=M~D=8$@u5_${BJD$I zw9SZ*(rFExti6nF7S_vG}F zr;{1=#W-!gRw~?QS) zlaWc{)_D#lv0X0tJd#H6p47J9%XYqc0$HvAf)=@GqwAgg^uwJUx0SD0i>_s0L{>uo+d2A}4wP;WFy?RmfDSC&%enR?tPL zCbO5(gjoQ_>qFKk)$r-FcukiDCy;1#c6Rzl0(u>21BH?$qRs%YzhKu*(D0UU^!jokvqI(TLeE4u9M{Y$Xxx2TA=crai6iWnz2PNZ+o|_?AXXoc;mF!Rq zz%q>%bS@nnyK0tAqdXdaCo8P1WHBHYVi;LXexe%&p!Lb=X%x-&3QL`(#A^!lU^r3e zv-DUaHvskn%m~yb@$d|Qdh-EYcQHlHY;4lGopu2akv)y#g2jpH_~Jm5R6!{J=g*G^ z!Y`z?7Aq>40d6D;g%ip!Q}?U>cA1e)^{U%0iz@Ho4pL{Y?#TiP`wl$lS~$-kb{(i5 z%PJ~P0BzsASK9ahp2^yjhE1%|HQ0x8TGQdRC=_t{v%pUPZ7brdR~Vu@kDq`;d*SyP zRRIcx(UEA1?SR_2+@CoG;NrJYH?3f>cPT1z^(M@Z*mkKk%#Swae03 z&BlVnsp;tUTZQu2l1k_&DWIB~KYnExz_N2KJG=51esbR4-g%jS=3 zISjJlHra?GBy!s6dwaKlBu+MY6tyDlaCS7L|;-e7#0l^WiHOn zOd0p6LhJ!#2zVhgMtQ0b1sxq9uwA72&zhkjxsa@?M5l(v#&2Sz708Cbj{{pZq({O= z_z%-18YGi+2WAOM^%CVhu;=lVK#4zHKM-5xO`4aKmTK2pF94AO%ZIoPSmFXK5&Xg9 zu--3|#pt9=b8R=TX3(s&T|SZF_PVKBuzm#c@CyCTkcXqYe6r|XorjZn<4UemrSFx| z{_`N_=-kdu!+6$*m3<7+YnX)n{=jAld;lKQu+sHsfKvlX+xxs&N9(8VFQ5XsfyvD7 zuZMlS!M$Aax?FhQ^tU}@FA)ci-LekQXq&_7OQWMqwr+sq7;W4awQvj%bb2Gl@G#mZKHe(EhN{?fHQ z-<<@WM|ZPW0mJBYa}dZ_1f`{=S#iC#GXsHQ$Nc&`srcqls>gcIcU3yj+@84Ke$(Ri zH2v|e?HLLy2L~ay<2Ha`ja5`s%&)-|wFlP%YWSM!YCdqsc!y0|*weP$(pnE{=HP^| z>+XO?zgNSinH-@Vz`3wnX4Jyi!)7}AM4}S7BrqL-$PYHD-iB^m9j_H`@bU41cR)gP z9z(5o2>dZnH5s+A3!zfTCjDj{0E8TDJplo)D`Pd_`e9BEok9liQSQzBrwgLDH#c8? zEo-?fC~0bXb`!WX0d)9Y9`tU!gFPGo9R(7aTJPg?+O}EOs(ku1ki^z+%6d^7?g|BXHwIMZ4`AVB2F54y?`0%w%N;FAnA~Wv(CwNILJ~B`Sg7AS)|tVl5b*vTN;l z!ay?Wrn{J+jyD=01Gj-3boBHDpFZg5ECDsYz~e=2YbvvmQ~+XV_gV#AzB%CC0EjP5 zFHiQyx$z#vpCMbmXFzq8l&2VR?(X#n4|YwwZ1K80f=|TX)#IYZMl&!9g zO}T$#|5)31dU663CcDSr%s*Y%xPhLUL2id0P=XpW?HE{w&6yR|KZJIh=9FVsHYGUAWx1gYa(|#R+i>FiR(UB0u zKiF~u@Pxq}mKm?2>8%EWs7b>DDk*t+d7td*G(Ha?$}Iq=gaYUV;?vWQ&fQ_l zZ5TSL@5cr1#~lEa1Y_lnJeF9J2QxnwfIH7NE^Pi4B;^HT(}qB316IP=cwhJHFe9Dr zR}SMM1#E5_i$e2c5>J4A30%%QRDces11v={VceiN0yNz;%(v!9Mn3=@Jez<(Ykj?1 z+{T=B;{mXVhj^cBtW>$n@$?7Bo)%_<18`!uYlM%g%E}kuy))p9B*n$WcT1NHBKT^Y z4`yL87GS;gM=iI^I@s&D|10LymV(ejWC2oQkQq+_6dNq{{Qz^2{AMxQT^{6I$6tQA)Zqh3$LwF;MZL0kaEsD=zKRg zqaG@_RK$dmnui=xu`erm3Zau@k3X>Or+80nG(;^*mQ*az9=Dd>721g-D6SQ1@qR;P zwmMFF%^$e4KMRc*r%kX@MxQ*3|0b88-hT%qjgWOlFyKe!x4o!g%p3;#$&C-MahsNDDs=jw;*R+*E!EUT>I+an?2AS!LT77TDY zNdQQR4#stc-6-s52;5lQ(T?pxIz+J!e;kHiJ~0`T=MW1T#0#02d`?g)_6Jk+T!74< zXcK(f5aY`bs)A%b_4Y9#-OmXm%VFYC2`zZyACr2u394et*Qd2%CRMP`5!mm(3`Lr1 ze9O(q&dzSrFT+W2K(Nq%g|H&buhVu^;lY^~^1D7#02|XZgocQ0x9t2%7#qNq5J7ZQ z#{e;KDNhx2xypQyiT&+do256$G}{g?Ua~zzE-7h|i+QFIbS@y_>(0)73R5w0bjk#m^qitl5E z-Y3xVoG}I>&6cEX8(CsIt80FLc+Az_&31gg^~O#kC9{9-ENgfEZMUzNn3vp3}%6zBT5ErOySaZF>gM|i3>JWS#{Y97=%{1HL-=wDrts?woX*r(fHMAmh5_a*0VbsMSySK(r_ z?@t!jc`}lS@OSokE zWVrCT=g7v{DJ%V}n1wxJhQMV+?n2*%^-8gJISSLV6<%U2=^)e=37p?nPNx(}g~yZ3 z-hn(aOff`B3;eaq75-Xi5s4G^^x77`ZIHPSv_G>kVPIvNlQJ+*?EL+u?o+_9T76}i z(oaCfN{$dVzEz#e@1N~0Pek|EJ2Zks_|IP0E6*5~$pBtu;&ta6*Q7UaQ#+@BUU(X_ zuq_g;G2bEt*U>#B1r1AamQ8lT`BnAr=UN)82Z>SV4`WvI6bknAqAu#3`rSLc$wb&d zPH0v>Y~nk;-`Xo5C7Z0lV4Y5Q&Y&sY==ZLe@o$v7tdP99K(%GhPVmRVPJWMFO#3sdZDyNy;h(ppr`_PS2UrAJ3Wir!HJ?O$rSL~3@n1kj5g+{`$m7+5yIRRj!k#P{ z6p(E!KVlT(dT_{SrEiu-$!4PSlvrFgm1o_!LoPZLdCF}-FP`lzlI2GF7hXo7XKaX* zcD~G515$eVle868GdtCyT8F5a!Gb@k`SYncw{L8{8(9PsWy0Em zjfD}gY#W}Ecx{SM%Rlx9zvhPD@1}!Gbxzl1X3~#ADqvav8K9+?JiMA~PKQBQh@R@b zG?VW0+sf`#8IjZ;n%T8io9>0>N>HsQ9LigM`xH4E^@5Yn$^VUrbjgy{=KU5y{I0;K zi6eVB*YNC=M`M)tuV*^6X+=pGikIG=%oI$B{&X$GMJzaBrqKg zsh6&$0%zpo*`4?lt97c>QjMFw8oJi-b#gD9!&+7Ie)Wl{+5At}u7~ zhwryMF22A94dH7J$+C3wdxhgpvAQ_?n$6>xQ&~YxIxhaxSrUxy&}ctx0 zcs!D8R=9r1KG`YC1!^8G7tL$O!FEiZSsjfg+lAwa$>wEv=8{KvmFB~%Wpu8_+3;=? zdbbk3b95;sZ(Z5*sOedFopb`)O@@WBVyeE+Y^PggT(*b5@i^!->keHXHwc>2pIL0a zUmQtOw*go4tgl%6ys%>JSWSBI@W7`$)njmoPjP=vdh@cC6xXGxX2W%tc~IxP&>lRA zPCQ&N8|KUP`j3Bg6Z|ZmPy$oq_)aPPP>soFCr(>*rZS7$$@v~@tQu9{Wq9W zWq-1f_*WBa6?Ur~?* zlK2@(R6fo8kRga58mw1FD+BdRm6${wd!)qgOi~p_kcDQsUKk@7l{2+S!~~Bx!(#?b zd?k$;l>WY4fXr~h%Tx(e_ZY)0%Aw1l6VNZ6M&GVTosdjwk{JG&+u~sKGy9{aZQ-Cx zBM{T|BYgi=yX-1wNXJU-&z5X@sGsi;*LGahD}p9$icTx$D*R$vh>0SO#Q!5JaaNCm zChM*}+)FgK_V9)y#12Mqkg+K-38OW<;#yg;o?pzuFzREXwBxU|;glm^Db)aQ90u{~ zvb6if?>eesJ8N-&RA`2&5Sf3DT)Mtm$kw&cR)6#_tZ0-5t*Xf*99Pp2+b6Xw646wY zvm(L>os2R?Z=hsP-;bCe>*)_wKO0fTvlHKiTU`IKa`&Aon2{X|=P-(iP8wYpI}VNH zDJ2sB_sYgRoH&Y{@U^RtC8SblBp?0J5S$*)(Og6HsDu&vD=@_2!q-Uo^E>20k5AF< z)~5N4`?FSW?6};(x?0Kn3#rldCM@*MpGd_1SvcPXZliL7P>Y-bOhZCLD1_?@+Wz1O zBN#aSkw`W9cz-`AZlY6$MEk0#Q*G@6&W+|xHRlWVik!X-s*p@YftTh%q{vheMl%!U zBs)IRDC&vjjepefRQeM~6P_{h6Kx~4PjFJjFUgxW#&6#Fqw+6bFf9hnk-;5gR({@C zP35I3j^*Sd?%S*!5lZKf`0*|&tRjN4^Cwx`%il7gnlV3>`+g^JrbjT>54?r`z2fXz z;kNNxxk>to)FI9#EaSiCI{W*h@GhzNy4z<|;YyL^=fb9?4BYmpnQCGPqN42|pLUP# zOEim91sDw~r!R@2eO^QGFfK>EaD@xZ4|oeF3@se?`HmX01=o%$j4*8Xw0wlOn}zO! zX>`Z>dEK6=hcCrbViL6X^DG>mI_ZcE)GNUfBJD}oU=KGJMv--{&v~MRD_Qu&#^2XO zy4sPrm%xMmEAvgj^mIn+m+zycNm5X^mPsg_c|k$wc|VA;@=@#={?J_Y5_*(=JyQf#Ju1dG6rNvt9njJh(A>^ z(2V&Tt97lOdC-$Nc|9K%y&yfo7=GzLqUnfHmhMf`ZRh{<=`b{pC7yoQ0e79d7qb~^b?IxM!0{J9@pRQe~A)r~w{1L+E*MGAU6zJ-? z^$=tj_}*{iLcMX^%4I|Z_28XA2lLyA?wy*SS%T=o1I}1>e-8A}rK#K#1Z33^3G5r` z9@JGvj9jj$g{mfQZXRFdsfBLaxef4Nd_jN7c~IzUUuyE)iapf1aZ()N;6&}E^yJ@a zIhWMn&B6)z*YpAAsl;h(gQbuU2<2P@42|2Td_(NDQ_6I-$Bh7|3i1DRY>_&OFCg7Q9&OZrZwk(Flw5NZ*P3I(^gMSh^Ef z?Pgo_O=bUTp-CJ{2!$8Cb%cR?{9X;SMuJ_(PI{lKlT3+q%T~-g4xyfcVdar)GA=vb z`hS$rD*}135FHp>MCRYNvaMEr>m71yT@ZD9c2VV}M!#BfW2KkQrgi%a5}P4PsRH#J zIkSg3$I5V zn-LYf{*S{DJ=U5dYmROonr59Kkb?FCXRv_7**|g|v;4MMnLAs2W7oCMP`^Ot9R@^K z0>HXG+L~>&e-^Ov@cH*IZ?#I>+Kk^Zya`EJ+V7bD+MdGMKpLzUztD{)j6nDoj+1E> z#Xeqx?O*oMke=zyTh;Ne-?-3heE;BUm!)#m=5Y|I(hay3Ga1vqye7>K;f|Tav#sz) zCB_f>XdK#MWl~n)45a>G2~m$a@32m!g1_mXt=EVo96w6}P+YkjidMui;L0Bf`^+~z zKSLdl(6WTeC{f9US@AcoC8+Q*hj>X(zGnywp!2^$5EGx~b;L=AKs136MR4kks1U0E zY5XXKGR6RM;8*{#AW&a8i zG>z^QW_g=j-AWLwKj8RVaW7&_nRaf;EPv?8F{K-wTV?Ay+4h%%(^H5hv!mFH9(sK( z|B63_+%^ey%{3Bj1f|D8CLiF8DrSNLNlC1V3Yoyo5)~05GhFxXoaj`}lzAIMX^hUY z{4Qx`<&-C2X1ZQ>mv?LTY<8p>2f}~}+C4;OY3J91I$pZ1n;} z@gK%`Af0$BpU7}PtKp~ky=U@eRgb9XsLXj_CU@&N-n%~{1{EF)_wl;R6wmg^*6-xN zvI0^dbiu~8DlJD}TzC8l4H4OqU^KT&KnM=Vvb4HUKqeMhCP`T)!;(hFurT5h7jgU< z@A(l*#L8#d>KS7|MR}n zK^fGsFcVDu*9sU-%Jis({Uh_)&7HYYH-X*kIwTFJwRdVbzOZRW`cXM#Q0|b%osLP* z17U=5zuAIJRSD)Nbx~;~SwumsvglA$>YLT{NiaD=#@N_t@Ye^OX&o-=;%{~s>{Cpg z6NZ*ta>C2!sDjt3&wf~#26is+@FywPjMcmGXsIXP@1>q9bK zUWUM%>U5QN5Wz#BM8Hl`#X?drz7$R0@~h@wJxhsK4X^_1RYvIg87ca07ee;#N+BDz zjRa2uDJ{=)T5cVMYGb~uJ5o*Uo`fJ5(_)`Y8}jbzmeN8-kO4BxNCtqDQ@7OpEn`;)AYE9qZ**${GbhZg8?g=gg-IiabdEIc&ewBf?@Bl}7Lwki)Sd1}ke z#IC#^3#`Hk=-nwtVL@GtC6LE}XX}MsM-M%CxLmnDrL@XnH=2u|hRx`Qokacr^+ody zPkZz+oPJ?^GT8)+{q)VEk`^>4{%Wc`+k=DDIf5hALbIr)uu}xUk2)>7QydIAIgQ@I z0b$`kpXsS7P^Pr*?`x`Tje?`%ClT==8R`E;3@mWbjjN z``XdNIvpSfB|H&V^%!&;kF{SBjHyn?=@Vz$ntlnfH3L{*1rFBFMiRN!X{q$oy*^8a zKLO!LSwtxui2g(fxGB${LYAXoD+jn3_7O#}8yf?Zz)obo1HiccLGJDTXTZY$B`Rrq zTw1*EoU&SQfjrhzWkf$M9`=2*s!h|5^7fMP)>+W%@E00K8zUiZ0zp&o^RVC#-$F!@ zLjB;AwIUBmM9mp|^%^8}oh3|OFcP^_8^3sm`qm9KogE(w6S3Khv#^*nPK_sFT+9njW0pFB-b1H>93I@unB^LBouP_N?(KT zIK%O9ducj!P=#bsoyfZR1{E(9JSLH+751etbs0_m9W&RGhx*r0ICSNN@0grZ7=-dV zo`uuFKJ%Pt9eOIQNH%nFz9>;7%MB=+HaX&L%aSwMwLlKUnODL~F(D}4rm8F1A{Cl& z)>Mw&>=?&8gRLA3pDed^MDre8R2-~bq3dQO51D!|$k8Utt?rhah1r{z-It4;?ml$< z4c&4x0w+lyD6XQh=FYK$s!|m$@`8NDMWAOah0bfkYSeCRWL*Ro%Q~gBKi{13rvoX+R>@0Ap{u&1g#rT4; z@agiskNf%ihXm;mW9R5EoF>EPW8iFOU-NKl^fl%=ohy2;Dq!Hel0Fzh@vd+ARa4Qs za;)*W+Pxsr?kgI#oI-&eMyF()N$>E(sUPFO*t`mwGwhMTJ3H1WY`K-oJR=yN;t8Sa zvrh~PQm%E3J7qnxT3J^smm%wA*5UA-hrS4+`Na*RzX$w@x^TW1gf!_Ut%*x2Pjtq9 z|GY87+C>Z_Gqn5&QcG;r;)337W@0f>U!b##oH0gp{4gk~lF;g)mZe7gqL!uCp)ie- zkx+AZf8*D~ggLEiHsWR{ZlU(sYwr4uwvJrry_`GS49+FA%uBNY0TuM%cbegKdnEXz84d<_D_3 zoKW8uSnKvSGT(*=|E}SGtaPWuIu}*gZ`;|ga)`~JM<$51x?x~xFZx@ZirnJmWH_^v zG@WbX#)D!5=IQCbX3WYl6=W}e&}V1KOwy-CLpmMamqkV!Mi*j9`6gvDYwbm8pNhM3 zumwD(i4*Mv0a(C;gOQTe%YyS;@b*IYU~2AER~46}Xkl|7#Q{n+{H1=a;(>ZXRD#d6EI6!0DL z*I1f6_Of)Hmy3flJ1a_mHc%OI*vDEPV6dY&(JGPc3_mD8Op_T{pHUh+?Tjwd>SZ7_ zFN&&(h;IK8Qj3Ygd(PeOIoFSk#l~{q7Nhc3V*T?5#qY0?DQ(kxBlZTXKT64Y{+_oh zdl?t}=(E?;nf!7*Cav{V#BwJwdbYEHZP;oMi}~n}&#<45RFI-pzuY#HJmNWPWE!JA z_V$<*U+1i`*4qG4IqN^iCCH>CG^BI;6xF&v4B#`hX682~F(c`5a;-z?Xvm6-RfHlD z*d$0uS?Uz=xM{~ys)$~Gdmt>NaiXUzg|l0TxO+GwVXhA9*L3otR&U<1QLRtUiHfHx zWk7>sx^$2Yd$Ns4cLzVumon8}FAyQQvEM>uc5F<+VQ$8fQf*4NGa_e_Z)98eEv0XSP|E&S`fb)Y_dIDlTqA z&n{c(YGJv)x{#-KXM4B)J2p5PT`^R)lGDw8z0c3s?qt0u*8^-^d&%%EOpbv;HVr?m zu5yBPFmO$r@{m;#U0j@UD>+Zi(-x?VUF2;UGp9b%l9m?PnG*{PUN-s4_lTw!P zshTI{!e4I2!`@FfS2j=6wB*Of+g0N5Ir!aE4Idg!8Q7g4=Z?kAeZ6Ox_& zprNVN)wxF*q1`Yo^9?0pQGFMsf|HBeen)$pZV{KD-qFTvElD1HBFDf!cz2FY8h^;Z zHaK?I3@<&H8cMpRC@uf4UgyqWaI-9x)6L7yiEpdy8xnq6LXu8WD+`yKiTBRbcH8pR zr*SYmGJcDz%g$nK_OoY{rNi$R60vcy>)Bf!EgW@q*JnM)=bK$!m;ZJ)g0o+4>+OBG z9UPmu8u@sX#|qB8Wbw;6$Nf-eb_6b)>?wFip)M+KtqRTJ^14tW%w0$G#O2~Mm@25eu?5~*jmzbcH6;X;4-Byj;5W$4X z{&o@{oR@K6ZQ=e1wAW+Rbp0pHVp$aWQFKfs`e720Q|IRcqihS_XA%W8{&Zj$IQu}A zjrITruaLE5qv;9O@nH-16f((_pt|3C6%-_r-*M0+-;@csqthNfZ&RTlZ3yJ%$h<_lh4N|$J= zShXI_`I^NLc_O-`@v?&MZqm%)jnkz3yF~uhnVWOw1}&~ij8av-nw6xD@OCmu63IC7 zF7jXz8%;?l8A&~*w~ee^&emBBKdaSB5t`b!b&0p0GA$ z{?3(@{-Wt}rN5|xA~>jkra$SEc5Ez}w8*EoxkQOdqV$DJpH%CNUj-Mj!7IVNEb6QF zOaA32h#UlK5mac*`Uol~X|%9K(%hFlJOJ_e$tZaeq|*SeH?Kk?;k!_&Jf`ZoqlrD zj#M{!-Ye##&Cow4cpy?ZctU1UR8{^MkbF2gd)2^gzy2aByrV4T6nV&v}5{vuTC zoQrsI)Y`kTD4MFK6J+UDWR*;vzZi^Lhy`CaQ%%>+n21_|uIfG=OfddRjef#9W2Ea@ ztqhA%_m6o^imY!I58GMerF$%LP7CEv<*s*MySMjP9IYi8lW1M?=QCHNmgX<>24|kBt9kk9j#X zO4WSVu=r70M?3&}T}XOlBzr)jU+JQ*Hn%4QT4>vG{)MITZvgd{~ixe{1+&F#d@+IQ2Y{Sk>N&!$b$=uI0)b87$#GqYyx&gV_a6y=Yo zQt6H1ee=P(9LR8~l;#Hx87-DOnTf*U!lcZ?q~xhjoyy`++5Ta3k~fJqy8&jV4bc-M z%&y`bPLze9YM7XJr2l#_xF5T$oPb#_3ylfh;`5M=Lf>#R4CWk42MFczDQpEAa?rq} zp<0|%8BrGV?oIu2*eSQ1gMLL8RfUWw2A0u!w*p7-Q)xYsM=TF(WtOh`o+$04k%r(h z2NIH10@>JFbcdG68KXh=+=23^Q%>iUO2^L!tqZ@FZ1Y!IT8Y=fLDQ|OL8w7DL zu61VJS9SvkV#Bug0`^XN##lRo`?>?DNu^o*vg9-ek(Djm|&p)*VNc@C)>e*<89g>{hRah{>ouqc|M1=bEwmq zSo0}y4a50qP@>E5x70>kYs>xf2xs-S%E5a$jD)QM<^)$LZj9c5lGp zwNm1_w}9od-wd_yYF6o+f*?vW2D8@ zg*em3B@t6<3s5*Ap6jwO)9GOMEsQlD-~cu(XDL*WXWJ96!^J%m!N-)NA~l*H!9($M z>Jbb0rf75vwXEMIR^K|=6~i5`r?UbTi;`D328M<|Tw@X^EYd_A`dI16D6gP&gM*O> zh~NK?wG&H{e_bDFq?&>Jr4q#Hy6u6Fq*DD7Y|<*ei)?Dk??$0U2@B5ABk7)cov~|- z2nnwj<*-_%N&}a~*?v&ljn%CoV?V@j68i(uSUF6cNiUmXA-g>( zywng}Wm0%LtmPa@FcPhAm&)hl`unSpqi5{nCAS-U=YT!jt{#beo5ZECEK-xX5+<>p z9F{Y2$#R(-^KKjMM=H|NF4QW9S|P%7(?wiWk2S&cifNJk_MPAO{lg?!R1t!Y@2PKv zQb_=32&GtwBphE+2v`qu+QxXQ4?!TCB33sFFr&gp=M-y0ul9&ioY@Fnds5Xb4tI?? zK@&W0b=X75;Z>Qr?Aik{g5Wx$m=l)^5NOEC0rrE}Z<{zcO&|JRHA($Ic) zOSU-*7Gwo^z?K~rzj%MBmB-l~^f3sCKxzToZ_MNALqir81X7oHFjB%m4z)%+ESB&} z^|Z8YEMtBa?wd1ERIM)<(RuY`qzJd+?`0LgxEC$7frs1$&q(l(%c2!ci#GasjaxG`7w+0TJ#cfrXX(c(00=T`OA0hgIr;t`Npu%a(5(!zAL+zm zu`=>XoCGZpH+UVeTW_sMnG<5;=CV`QuOxY|lmL$MR}dF>zAn(zySU?Z)MMP17>iOW zb{X7pLj#!YK|yM^)Ulh?G+o^rVK+as2GGk=^7vdf;ntwYoePejC%Sc?+2xZ07X7yn z_6sGzEz;se3B@q(GzR`Q0-{H$T%uI6z_wemGXVwSIZ~8$&eg)G%s{A8-90Xi4yscO z2p+@=(V->_gmmAi#s3_PTBD7e-uta;NfFJiYt!_)T`hTjRj4G+rn4({!Z&8nSV zS+g{K743ALRei!ZBYQkHQH7axvMxuLq6>vP=iYyroMK(ROV?q+TLH~B$yn0JG}?VQ z8I_)Xm@vShoIOk+a?UI+*1!hO=bw6Irr}y9Z;!oD{itxjivjUSW6D0FeiezNm#BXI zw5C0FQff~NYC%44VIRa+rENRQHmZ3(8$UYd>Ex?@B9hnS-iTp?8_VB#SGYI7pLp3Y zmeABg_CwHX^TR@+d0>t64?^8n8fJ_#-<8?$w+3UIjUV2Zt)Ii^nAW<5P}^wW9798L z))hn}BOf+Z>7|KdAOa7-sc_*Ngo*!^C_4YLG=!fnDB0AzQOQ zH9^QNVd-N@tw+B7Q}h{8Ibbq z^4ZA@Ti?k=J3Rxj_w=q~1bXwC_L2&h5}Io{)5=~$OVy;1BcJlb`+)0oCmvT^JW+oM znQwG33ZBFkg6d9hFc=Ia9jm&@P|$JPbV>_Sqfk^WcSA$w6R1ssCp~P;yp%v4R{tRM zi%9-2uK$M>8YA`5!vNpAfgoB(>B$1zODWh&m8zo`q;V8=HB#;Pl3;sL2{O&5jslOV PAdst*2jrz=(5=4!xFp&d literal 0 HcmV?d00001 diff --git a/tests/base/images.rst b/tests/base/images.rst index 038d5669..df0c5d7e 100644 --- a/tests/base/images.rst +++ b/tests/base/images.rst @@ -68,4 +68,20 @@ Adding a test for remote images specified by url and using figure directive .. figure:: https://s3-ap-southeast-2.amazonaws.com/assets.quantecon.org/img/sloan_logo.png - :scale: 50 % \ No newline at end of file + :scale: 50 % + +Supported Image Path Specifications +----------------------------------- + +Adding a relative path image reference + +.. image:: _static/hood.jpg + +Adding a root level path image reference + +.. image:: /_static/hood.jpg + +Adding a path to base level _static folder outside of `base` project folder + +.. image:: ../_static/simple_notebook.png + diff --git a/tests/base/ipynb/images.ipynb b/tests/base/ipynb/images.ipynb index 7a28c5dd..f2bf312a 100644 --- a/tests/base/ipynb/images.ipynb +++ b/tests/base/ipynb/images.ipynb @@ -82,6 +82,25 @@ "\n", "" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Supported Image Path Specifications\n", + "\n", + "Adding a relative path image reference\n", + "\n", + "\n", + "\n", + "Adding a root level path image reference\n", + "\n", + "\n", + "\n", + "Adding a path to base level _static folder outside of base project folder\n", + "\n", + "" + ] } ], "metadata": { diff --git a/tests/base/ipynb/index.ipynb b/tests/base/ipynb/index.ipynb index 7d1958bf..a566c0e2 100644 --- a/tests/base/ipynb/index.ipynb +++ b/tests/base/ipynb/index.ipynb @@ -26,6 +26,7 @@ " - [Figure](images.ipynb#figure)\n", " - [File Collisions](images.ipynb#file-collisions)\n", " - [Remote Images](images.ipynb#remote-images)\n", + " - [Supported Image Path Specifications](images.ipynb#supported-image-path-specifications)\n", "- [Inline](inline.ipynb)\n", " - [Code](inline.ipynb#code)\n", " - [Math](inline.ipynb#math)\n", @@ -84,7 +85,8 @@ "- [Section 2](section2/index.ipynb)\n", " - [Exercise List from section2 (all)](section2/exercise_list_sec2_all.ipynb)\n", " - [Exercise List from section2 (section2 only)](section2/exercise_list_sec2.ipynb)\n", - " - [Exercises in section 2](section2/exercises_section2.ipynb)" + " - [Exercises in section 2](section2/exercises_section2.ipynb)\n", + " - [Images](section2/images.ipynb)" ] }, { diff --git a/tests/base/ipynb/section2/images.ipynb b/tests/base/ipynb/section2/images.ipynb new file mode 100644 index 00000000..198b6914 --- /dev/null +++ b/tests/base/ipynb/section2/images.ipynb @@ -0,0 +1,41 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Images" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Supported Image Path Specifications\n", + "\n", + "Adding a relative path image reference\n", + "\n", + "\n", + "\n", + "Adding a root level path image reference\n", + "\n", + "\n", + "\n", + "Adding a path to base level _static folder outside of base project folder\n", + "\n", + "" + ] + } + ], + "metadata": { + "filename": "images.rst", + "kernelspec": { + "display_name": "Python", + "language": "python3", + "name": "python3" + }, + "title": "Images" + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/tests/base/section2/images.rst b/tests/base/section2/images.rst new file mode 100644 index 00000000..7d09c5b8 --- /dev/null +++ b/tests/base/section2/images.rst @@ -0,0 +1,18 @@ +Images +====== + +Supported Image Path Specifications +----------------------------------- + +Adding a relative path image reference + +.. image:: ../_static/hood.jpg + +Adding a root level path image reference + +.. image:: /_static/hood.jpg + +Adding a path to base level _static folder outside of `base` project folder + +.. image:: ../../_static/simple_notebook.png + diff --git a/tests/base/section2/index.rst b/tests/base/section2/index.rst index 90f08b1e..4047a48c 100644 --- a/tests/base/section2/index.rst +++ b/tests/base/section2/index.rst @@ -13,3 +13,4 @@ This is the index for section2 exercise_list_sec2_all exercise_list_sec2 exercises_section2 + images From 848f7f673f8aea5b2ce12a3bbca1affb1cf33272 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 12 Sep 2019 14:47:43 +1000 Subject: [PATCH 25/31] add file path adjustments for download statics and add test cases --- sphinxcontrib/jupyter/builders/jupyter.py | 11 +++++-- .../jupyter/writers/translate_all.py | 13 ++++++++- tests/_static/test_pwt.csv | 9 ++++++ tests/base/download.rst | 7 ++++- tests/base/ipynb/download.ipynb | 7 ++++- tests/base/ipynb/index.ipynb | 3 +- tests/base/ipynb/section2/download.ipynb | 29 +++++++++++++++++++ tests/base/section2/download.rst | 9 ++++++ tests/base/section2/index.rst | 1 + 9 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 tests/_static/test_pwt.csv create mode 100644 tests/base/ipynb/section2/download.ipynb create mode 100644 tests/base/section2/download.rst diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index 8cd5dd46..db4d76bf 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -267,11 +267,18 @@ def process_download_library(self, context): for fl in self.download_library.keys(): if fl == "index": continue - src = os.path.join(self.srcdir, fl) + filename, internal_file, subfolder_depth = self.download_library[fl] + if "../" in fl and internal_file == False: + num_steps = fl.count("../") + srcdir = "/".join(self.srcdir.split("/")[0:-1*(num_steps - subfolder_depth)]) + else: + srcdir = self.srcdir + fl = fl.replace("../", "") + src = os.path.join(srcdir, fl) if not os.path.exists(src): self.logger.info(bold("[builder] cannot find download: {}".format(src))) else: - target = os.path.join(download_path, self.download_library[fl]) + target = os.path.join(download_path, filename) copyfile(src, target) def finish(self): diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index bf79100c..23766aa1 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -417,15 +417,26 @@ def depart_footnote(self, node): def visit_download_reference(self, node): self.in_download_reference = True sourcefile = node['reftarget'] + internal_file = True + doc_depth = len(self.source_file_name.split("/")) + if sourcefile.startswith("/"): + sourcefile = sourcefile[1:] #this gets evaluated at the root level + if "../" in sourcefile: + num_path_steps = sourcefile.count("../") + if num_path_steps > (doc_depth - 2): + internal_file = False if sourcefile not in self.builder.download_library.keys(): #add files to download libary for builder path, filename = self.check_duplicate_files(sourcefile) - self.builder.download_library[sourcefile] = filename + subfolder_depth = doc_depth - 2 + self.builder.download_library[sourcefile] = (filename, internal_file, subfolder_depth) targetfile = os.path.join("_downloads", filename) else: #Already added to download libary for builder to copy asset path, filename = os.path.split(sourcefile) targetfile = os.path.join("_downloads", filename) + if doc_depth > 2: #Note: A depth of 2 is in the root level of the project directory + targetfile = "../"*(doc_depth-2) + targetfile html = "".format(targetfile) self.markdown_lines.append(html) diff --git a/tests/_static/test_pwt.csv b/tests/_static/test_pwt.csv new file mode 100644 index 00000000..03ae3be0 --- /dev/null +++ b/tests/_static/test_pwt.csv @@ -0,0 +1,9 @@ +"country","country isocode","year","POP","XRAT","tcgdp","cc","cg" +"Argentina","ARG","2000","37335.653","0.9995","295072.21869","75.716805379","5.5788042896" +"Australia","AUS","2000","19053.186","1.72483","541804.6521","67.759025993","6.7200975332" +"India","IND","2000","1006300.297","44.9416","1728144.3748","64.575551328","14.072205773" +"Israel","ISR","2000","6114.57","4.07733","129253.89423","64.436450847","10.266688415" +"Malawi","MWI","2000","11801.505","59.543808333","5026.2217836","74.707624181","11.658954494" +"South Africa","ZAF","2000","45064.098","6.93983","227242.36949","72.718710427","5.7265463933" +"United States","USA","2000","282171.957","1","9898700","72.347054303","6.0324539789" +"Uruguay","URY","2000","3219.793","12.099591667","25255.961693","78.978740282","5.108067988" diff --git a/tests/base/download.rst b/tests/base/download.rst index 347bfe35..f775061c 100644 --- a/tests/base/download.rst +++ b/tests/base/download.rst @@ -1,4 +1,9 @@ Download ======== -Add test for download directive :download:`here <_static/test_pwt.csv>` \ No newline at end of file +Add test for download directive :download:`here <_static/test_pwt.csv>` + +and at a root location specification :download:`root ` + +and referencing a file that is in a different +relative location :download:`second here <../_static/test_pwt.csv>` \ No newline at end of file diff --git a/tests/base/ipynb/download.ipynb b/tests/base/ipynb/download.ipynb index 26d0af16..7c9c21b0 100644 --- a/tests/base/ipynb/download.ipynb +++ b/tests/base/ipynb/download.ipynb @@ -6,7 +6,12 @@ "source": [ "# Download\n", "\n", - "Add test for download directive here" + "Add test for download directive here\n", + "\n", + "and at a root location specification root\n", + "\n", + "and referencing a file that is in a different\n", + "relative location second here" ] } ], diff --git a/tests/base/ipynb/index.ipynb b/tests/base/ipynb/index.ipynb index a566c0e2..375861be 100644 --- a/tests/base/ipynb/index.ipynb +++ b/tests/base/ipynb/index.ipynb @@ -86,7 +86,8 @@ " - [Exercise List from section2 (all)](section2/exercise_list_sec2_all.ipynb)\n", " - [Exercise List from section2 (section2 only)](section2/exercise_list_sec2.ipynb)\n", " - [Exercises in section 2](section2/exercises_section2.ipynb)\n", - " - [Images](section2/images.ipynb)" + " - [Images](section2/images.ipynb)\n", + " - [Download](section2/download.ipynb)" ] }, { diff --git a/tests/base/ipynb/section2/download.ipynb b/tests/base/ipynb/section2/download.ipynb new file mode 100644 index 00000000..4a3a7a67 --- /dev/null +++ b/tests/base/ipynb/section2/download.ipynb @@ -0,0 +1,29 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Download\n", + "\n", + "Add test for download directive here\n", + "\n", + "and at a root location specification root\n", + "\n", + "and referencing a file that is in a different\n", + "relative location second here" + ] + } + ], + "metadata": { + "filename": "download.rst", + "kernelspec": { + "display_name": "Python", + "language": "python3", + "name": "python3" + }, + "title": "Download" + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/tests/base/section2/download.rst b/tests/base/section2/download.rst new file mode 100644 index 00000000..a145cd55 --- /dev/null +++ b/tests/base/section2/download.rst @@ -0,0 +1,9 @@ +Download +======== + +Add test for download directive :download:`here <../_static/test_pwt.csv>` + +and at a root location specification :download:`root ` + +and referencing a file that is in a different +relative location :download:`second here <../../_static/test_pwt.csv>` \ No newline at end of file diff --git a/tests/base/section2/index.rst b/tests/base/section2/index.rst index 4047a48c..20527a79 100644 --- a/tests/base/section2/index.rst +++ b/tests/base/section2/index.rst @@ -14,3 +14,4 @@ This is the index for section2 exercise_list_sec2 exercises_section2 images + download From 03eccb55a7ba6d26f472af5450cb70f12811af01 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 12 Sep 2019 15:50:57 +1000 Subject: [PATCH 26/31] update path for download notebooks --- sphinxcontrib/jupyter/writers/make_site.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinxcontrib/jupyter/writers/make_site.py b/sphinxcontrib/jupyter/writers/make_site.py index 3f84efc7..4023ab5c 100644 --- a/sphinxcontrib/jupyter/writers/make_site.py +++ b/sphinxcontrib/jupyter/writers/make_site.py @@ -85,9 +85,9 @@ def build_website(self): ## copies the downloadable ipynb assets to downloads ipynb support folder if "jupyter_download_nb" in self.builder.config and self.builder.config["jupyter_download_nb"]: if self.builder.config['jupyter_download_nb_execute']: - download_ipynb_source = self.outdir + "/_download_ipynb/executed" + download_ipynb_source = self.outdir + "/jupyter/_download_ipynb/executed" else: - download_ipynb_source = self.outdir + "/_download_ipynb" + download_ipynb_source = self.outdir + "/jupyter/_download_ipynb" if os.path.exists(download_ipynb_source): shutil.copytree(download_ipynb_source, self.download_ipynb_folder, symlinks=True) else: From ca71a5edba2c1d70966429816b1032e41630f29d Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Thu, 12 Sep 2019 16:30:34 +1000 Subject: [PATCH 27/31] update location for executed ipynb downloads --- sphinxcontrib/jupyter/builders/jupyter.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index db4d76bf..fda4c9c3 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -42,8 +42,8 @@ def init(self): self.executedir = self.outdir + '/executed' self.reportdir = self.outdir + '/reports/' self.errordir = self.outdir + "/reports/{}" - self.downloadsdir = self.outdir + "/_downloads" - self.downloadsExecutedir = self.downloadsdir + "/executed" + self.download_ipynb_dir = self.outdir + "/_downloads_ipynb" + self.downloads_ipynb_executed_dir = self.download_ipynb_dir + "/executed" self.client = None # Check default language is defined in the jupyter kernels @@ -102,7 +102,7 @@ def init(self): 'delayed_notebooks': dict(), 'futures': [], 'delayed_futures': [], - 'destination': self.downloadsExecutedir + 'destination': self.downloads_ipynb_executed_dir } self.image_library = { @@ -143,7 +143,7 @@ def prepare_writing(self, docnames): copy_dependencies(self, self.executedir) if (self.config["jupyter_download_nb_execute"]): - copy_dependencies(self, self.downloadsExecutedir) + copy_dependencies(self, self.downloads_ipynb_executed_dir) def write_doc(self, docname, doctree): # work around multiple string % tuple issues in docutils; From 2be8a4e9d8726f26d236123e6213a2539ac04c0c Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 13 Sep 2019 11:53:48 +1000 Subject: [PATCH 28/31] fix path for executed download nb --- sphinxcontrib/jupyter/builders/jupyter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinxcontrib/jupyter/builders/jupyter.py b/sphinxcontrib/jupyter/builders/jupyter.py index fda4c9c3..05f83797 100644 --- a/sphinxcontrib/jupyter/builders/jupyter.py +++ b/sphinxcontrib/jupyter/builders/jupyter.py @@ -153,7 +153,7 @@ def write_doc(self, docname, doctree): ### print an output for downloading notebooks as well with proper links if variable is set if "jupyter_download_nb" in self.config and self.config["jupyter_download_nb"]: - outfilename = os.path.join(self.outdir + "/_download_ipynb", os_path(docname) + self.out_suffix) + outfilename = os.path.join(self.download_ipynb_dir, os_path(docname) + self.out_suffix) ensuredir(os.path.dirname(outfilename)) self.writer._set_ref_urlpath(self.config["jupyter_download_nb_urlpath"]) self.writer._set_jupyter_download_nb_image_urlpath((self.config["jupyter_download_nb_image_urlpath"])) From 8bcbaf53e58e61a0ac13430f21b192fec5e18531 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 13 Sep 2019 12:11:06 +1000 Subject: [PATCH 29/31] update make site path to downloads folder --- sphinxcontrib/jupyter/writers/make_site.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinxcontrib/jupyter/writers/make_site.py b/sphinxcontrib/jupyter/writers/make_site.py index 4023ab5c..d05e6a1d 100644 --- a/sphinxcontrib/jupyter/writers/make_site.py +++ b/sphinxcontrib/jupyter/writers/make_site.py @@ -85,10 +85,10 @@ def build_website(self): ## copies the downloadable ipynb assets to downloads ipynb support folder if "jupyter_download_nb" in self.builder.config and self.builder.config["jupyter_download_nb"]: if self.builder.config['jupyter_download_nb_execute']: - download_ipynb_source = self.outdir + "/jupyter/_download_ipynb/executed" + download_ipynb_source = self.outdir + "/jupyter/_downloads_ipynb/executed" else: - download_ipynb_source = self.outdir + "/jupyter/_download_ipynb" + download_ipynb_source = self.outdir + "/jupyter/_downloads_ipynb" if os.path.exists(download_ipynb_source): shutil.copytree(download_ipynb_source, self.download_ipynb_folder, symlinks=True) else: - self.logger.warning("[make_site] IPYNB downloads folder {} not created during build".format(download_ipynb_source)) + self.logger.warning("[make_site] IPYNB downloads folder {} not created during build".format(download_ipynb_source)) \ No newline at end of file From 9414086ac1384631b7e8b9c0a31fef1c73c0ee3a Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 13 Sep 2019 16:02:50 +1000 Subject: [PATCH 30/31] update reference ipynb solution --- tests/base/ipynb/section2/index.ipynb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/base/ipynb/section2/index.ipynb b/tests/base/ipynb/section2/index.ipynb index 9ac95e0d..9457fcef 100644 --- a/tests/base/ipynb/section2/index.ipynb +++ b/tests/base/ipynb/section2/index.ipynb @@ -12,7 +12,10 @@ "\n", "- [Exercise List from section2 (all)](exercise_list_sec2_all.ipynb)\n", "- [Exercise List from section2 (section2 only)](exercise_list_sec2.ipynb)\n", - "- [Exercises in section 2](exercises_section2.ipynb)" + "- [Exercises in section 2](exercises_section2.ipynb)\n", + "- [Images](images.ipynb)\n", + " - [Supported Image Path Specifications](images.ipynb#supported-image-path-specifications)\n", + "- [Download](download.ipynb)" ] } ], From 6e98e433397300e7efd45103475324a9bd012007 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Mon, 16 Sep 2019 10:50:06 +1000 Subject: [PATCH 31/31] adjustment to absolute reference needed to account for external links --- sphinxcontrib/jupyter/writers/translate_all.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sphinxcontrib/jupyter/writers/translate_all.py b/sphinxcontrib/jupyter/writers/translate_all.py index 477f4dec..29f29251 100644 --- a/sphinxcontrib/jupyter/writers/translate_all.py +++ b/sphinxcontrib/jupyter/writers/translate_all.py @@ -179,7 +179,7 @@ def visit_image(self, node): internal_image = True file_depth = len(self.source_file_name.split("/")) #-Adjust Absolute Path-# - if file_depth > 2 and "../" not in uri: + if "?" not in node['candidates'] and file_depth > 2 and "../" not in uri: uri = "../"*(file_depth - 2) + uri #Adjust for Relative References as spphinx returns uri with subfolders before uri provided in rst file adjust_relative_path = False @@ -193,6 +193,7 @@ def visit_image(self, node): uri = "/".join(uri.split("/")[num_path_steps:]) if '?' in node['candidates']: # don't rewrite nonlocal image URIs + internal_image = False pass elif uri not in self.builder.image_library.keys(): #add files to image libary for builder