From 6a55c8eafcac3d8233b50871b5d8138809bc4b81 Mon Sep 17 00:00:00 2001 From: jce Date: Mon, 20 Sep 2021 16:52:25 +0200 Subject: [PATCH 01/13] Add feature to download remote pdf files --- doc/index.rst | 24 +++++++++++++++++++++++- sphinxcontrib/doxylink/__init__.py | 3 ++- sphinxcontrib/doxylink/doxylink.py | 19 +++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index 74538b7..6e93706 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -131,7 +131,9 @@ Configuration values .. confval:: doxylink The environment is set up with a dictionary mapping the interpreted text role to a tuple of tag file and prefix. - The keys of this dictionary must be lower-case. + The keys of this dictionary must be lower-case. The prefix can be an absolute path or a path relative to `Sphinx' + output directory`_. It may be a path to the directory that contains your *index.html* or a path to your Doxygen pdf + file. .. code-block:: python @@ -140,10 +142,30 @@ Configuration values 'qtogre' : ('/home/matt/QtOgre.tag', '/home/matt/QtOgre/html/'), } + The second element of the tuple may also be a + +.. _`Sphinx' output directory`: https://www.sphinx-doc.org/en/master/extdev/appapi.html#sphinx.application.Sphinx.outdir + .. confval:: add_function_parentheses A boolean that decides whether parentheses are appended to function and method role text. Default is ``True``. +.. confval:: doxylink_remote_pdf_files + + Doxylink can be configured to download remote Doxygen pdf files. You should use the URL as the second + element of the value of the ``doxylink`` dictionary **and** as key in the ``doxylink_remote_pdf_files`` dictionary, + which should contain the relative or absolute path for the output location as value. If the pdf file already exists + locally, it will not be downloaded and overwritten. + + .. code-block:: python + + doxylink = { + 'polyvox' : ('/home/matt/PolyVox.tag', url_to_remote_doxygen_pdf), + } + doxylink_remote_pdf_files = { + url_to_remote_doxygen_pdf: '/home/matt/PolyVox/latex/polyvox_doxygen.pdf', + } + Bug reports ----------- diff --git a/sphinxcontrib/doxylink/__init__.py b/sphinxcontrib/doxylink/__init__.py index c11a631..61e31de 100644 --- a/sphinxcontrib/doxylink/__init__.py +++ b/sphinxcontrib/doxylink/__init__.py @@ -1,7 +1,8 @@ -__version__ = '1.10' +__version__ = '1.11' def setup(app): from .doxylink import setup_doxylink_roles app.add_config_value('doxylink', {}, 'env') + app.add_config_value('doxylink_remote_pdf_files', {}, 'env') app.connect('builder-inited', setup_doxylink_roles) diff --git a/sphinxcontrib/doxylink/doxylink.py b/sphinxcontrib/doxylink/doxylink.py index 25651ae..4e3909c 100644 --- a/sphinxcontrib/doxylink/doxylink.py +++ b/sphinxcontrib/doxylink/doxylink.py @@ -354,6 +354,25 @@ def find_doxygen_link(name, rawtext, text, lineno, inliner, options={}, content= return find_doxygen_link +def download_file(app, url, output_location): + if not os.path.isabs(output_location): + output_location = os.path.join(app.outdir, output_location) + if os.path.exists(output_location): + return + response = requests.get(url, allow_redirects=True) + if response.status_code != 200: + report_warning(app.env, + standout("Could not find file %s. Make sure your `doxylink_remote_pdf_files` config variable is " + "set correctly." % url)) + return + os.makedirs(os.path.dirname(output_location), exist_ok=True) + with open(output_location, 'wb') as file: + file.write(response.content) + + def setup_doxylink_roles(app): for name, (tag_filename, rootdir) in app.config.doxylink.items(): app.add_role(name, create_role(app, tag_filename, rootdir, name)) + if rootdir in app.config.doxylink_remote_pdf_files: + output_location = app.config.doxylink_remote_pdf_files[rootdir] + download_file(app, rootdir, output_location) From 8deef72e8f25615b7d82837370a298cd12d5b772 Mon Sep 17 00:00:00 2001 From: jce Date: Mon, 20 Sep 2021 16:57:09 +0200 Subject: [PATCH 02/13] Document changes in 1.11 --- CHANGES.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 66d4ea6..22f52e4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,8 @@ +1.11 (Sep 20, 2021) +================== + +- Add feature to download remote pdf files [PR #35] + 1.10 (Sep 10, 2021) ================== From 352a95f3bc556837011f17d7bf6b13760c925eac Mon Sep 17 00:00:00 2001 From: jce Date: Mon, 20 Sep 2021 17:45:20 +0200 Subject: [PATCH 03/13] Clarify how linking to pdf file can be configured --- doc/index.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index 6e93706..ce31bb6 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -132,8 +132,8 @@ Configuration values The environment is set up with a dictionary mapping the interpreted text role to a tuple of tag file and prefix. The keys of this dictionary must be lower-case. The prefix can be an absolute path or a path relative to `Sphinx' - output directory`_. It may be a path to the directory that contains your *index.html* or a path to your Doxygen pdf - file. + output directory`_. It may be a path to the directory that contains your *index.html* or the name of your Doxygen + pdf file. .. code-block:: python @@ -142,8 +142,6 @@ Configuration values 'qtogre' : ('/home/matt/QtOgre.tag', '/home/matt/QtOgre/html/'), } - The second element of the tuple may also be a - .. _`Sphinx' output directory`: https://www.sphinx-doc.org/en/master/extdev/appapi.html#sphinx.application.Sphinx.outdir .. confval:: add_function_parentheses From beade09bed093af9c339be978df0e1fb06fd95fa Mon Sep 17 00:00:00 2001 From: jce Date: Mon, 20 Sep 2021 17:51:21 +0200 Subject: [PATCH 04/13] Use local pdf file name as key and remote URL as value --- doc/index.rst | 10 +++++----- sphinxcontrib/doxylink/doxylink.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index ce31bb6..bb6fdde 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -150,18 +150,18 @@ Configuration values .. confval:: doxylink_remote_pdf_files - Doxylink can be configured to download remote Doxygen pdf files. You should use the URL as the second + Doxylink can be configured to download remote Doxygen pdf files. You should use the output file name as the second element of the value of the ``doxylink`` dictionary **and** as key in the ``doxylink_remote_pdf_files`` dictionary, - which should contain the relative or absolute path for the output location as value. If the pdf file already exists - locally, it will not be downloaded and overwritten. + which should contain the URL to the remote location as value. If the pdf file already exists locally, it will not + be downloaded. .. code-block:: python doxylink = { - 'polyvox' : ('/home/matt/PolyVox.tag', url_to_remote_doxygen_pdf), + 'polyvox' : ('/home/matt/PolyVox.tag', 'polyvox_doxygen.pdf'), } doxylink_remote_pdf_files = { - url_to_remote_doxygen_pdf: '/home/matt/PolyVox/latex/polyvox_doxygen.pdf', + 'polyvox_doxygen.pdf': url_to_remote_doxygen_pdf, } Bug reports diff --git a/sphinxcontrib/doxylink/doxylink.py b/sphinxcontrib/doxylink/doxylink.py index 4e3909c..ac4c0b2 100644 --- a/sphinxcontrib/doxylink/doxylink.py +++ b/sphinxcontrib/doxylink/doxylink.py @@ -374,5 +374,5 @@ def setup_doxylink_roles(app): for name, (tag_filename, rootdir) in app.config.doxylink.items(): app.add_role(name, create_role(app, tag_filename, rootdir, name)) if rootdir in app.config.doxylink_remote_pdf_files: - output_location = app.config.doxylink_remote_pdf_files[rootdir] - download_file(app, rootdir, output_location) + url = app.config.doxylink_remote_pdf_files[rootdir] + download_file(app, url, rootdir) From 01a01ae30febac5dc876f6937be582abe6b2bef2 Mon Sep 17 00:00:00 2001 From: jce Date: Mon, 20 Sep 2021 17:54:30 +0200 Subject: [PATCH 05/13] Report warning when value of doxylink_remote_pdf_files is not a URL --- sphinxcontrib/doxylink/doxylink.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sphinxcontrib/doxylink/doxylink.py b/sphinxcontrib/doxylink/doxylink.py index ac4c0b2..9903be6 100644 --- a/sphinxcontrib/doxylink/doxylink.py +++ b/sphinxcontrib/doxylink/doxylink.py @@ -375,4 +375,9 @@ def setup_doxylink_roles(app): app.add_role(name, create_role(app, tag_filename, rootdir, name)) if rootdir in app.config.doxylink_remote_pdf_files: url = app.config.doxylink_remote_pdf_files[rootdir] - download_file(app, url, rootdir) + if is_url(url): + download_file(app, url, rootdir) + else: + report_warning(app.env, + standout("Expected a URL as value for `doxylink_remote_pdf_files` config variable; " + "got %s" % url)) From c273ab9bb4d9f34fec9cc1d97fcea70f0d018069 Mon Sep 17 00:00:00 2001 From: jce Date: Mon, 20 Sep 2021 17:58:19 +0200 Subject: [PATCH 06/13] Use __repr__ to include strings in warning messages --- sphinxcontrib/doxylink/doxylink.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinxcontrib/doxylink/doxylink.py b/sphinxcontrib/doxylink/doxylink.py index 9903be6..dd61e61 100644 --- a/sphinxcontrib/doxylink/doxylink.py +++ b/sphinxcontrib/doxylink/doxylink.py @@ -362,7 +362,7 @@ def download_file(app, url, output_location): response = requests.get(url, allow_redirects=True) if response.status_code != 200: report_warning(app.env, - standout("Could not find file %s. Make sure your `doxylink_remote_pdf_files` config variable is " + standout("Could not find file %r. Make sure your `doxylink_remote_pdf_files` config variable is " "set correctly." % url)) return os.makedirs(os.path.dirname(output_location), exist_ok=True) @@ -380,4 +380,4 @@ def setup_doxylink_roles(app): else: report_warning(app.env, standout("Expected a URL as value for `doxylink_remote_pdf_files` config variable; " - "got %s" % url)) + "got %r" % url)) From f6425fad87e2dd415e1b2bfca6f36ae68b04288c Mon Sep 17 00:00:00 2001 From: jce Date: Thu, 23 Sep 2021 18:50:08 +0200 Subject: [PATCH 07/13] Allow three elements as value for doxylink var and warn about incompatibilities --- sphinxcontrib/doxylink/__init__.py | 2 +- sphinxcontrib/doxylink/doxylink.py | 115 ++++++++++++++++++++++------- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/sphinxcontrib/doxylink/__init__.py b/sphinxcontrib/doxylink/__init__.py index 61e31de..e8df0cf 100644 --- a/sphinxcontrib/doxylink/__init__.py +++ b/sphinxcontrib/doxylink/__init__.py @@ -4,5 +4,5 @@ def setup(app): from .doxylink import setup_doxylink_roles app.add_config_value('doxylink', {}, 'env') - app.add_config_value('doxylink_remote_pdf_files', {}, 'env') + app.add_config_value('doxylink_pdf_files', {}, 'env') app.connect('builder-inited', setup_doxylink_roles) diff --git a/sphinxcontrib/doxylink/doxylink.py b/sphinxcontrib/doxylink/doxylink.py index dd61e61..7018bb7 100644 --- a/sphinxcontrib/doxylink/doxylink.py +++ b/sphinxcontrib/doxylink/doxylink.py @@ -3,6 +3,7 @@ import os import re import requests +import shutil import time import xml.etree.ElementTree as ET import urllib.parse @@ -258,9 +259,9 @@ def join(*args): return ''.join(args) -def create_role(app, tag_filename, rootdir, cache_name): +def create_role(app, tag_filename, rootdir, cache_name, pdf=""): # Tidy up the root directory path - if not rootdir.endswith(('/', '\\')) and not rootdir.endswith('.pdf'): + if not rootdir.endswith(('/', '\\')): rootdir = join(rootdir, os.sep) try: @@ -332,14 +333,14 @@ def find_doxygen_link(name, rawtext, text, lineno, inliner, options={}, content= 'Error reported was: %s' % (part, error), line=lineno) return [nodes.inline(title, title)], [] + if pdf: + full_url = join(pdf, '#', url.file) + full_url = full_url.replace('.html#', '_') # for links to variables and functions + full_url = full_url.replace('.html', '') # for links to files # If it's an absolute path then the link will work regardless of the document directory # Also check if it is a URL (i.e. it has a 'scheme' like 'http' or 'file') - if os.path.isabs(rootdir) or urllib.parse.urlparse(rootdir).scheme: + elif os.path.isabs(rootdir) or urllib.parse.urlparse(rootdir).scheme: full_url = join(rootdir, url.file) - elif rootdir.endswith('.pdf'): - full_url = join(rootdir, '#', url.file) - full_url = full_url.replace('.html#', '_') # for links to variables and functions - full_url = full_url.replace('.html', '') # for links to files # But otherwise we need to add the relative path of the current document to the root source directory to the link else: relative_path_to_docsrc = os.path.relpath(app.env.srcdir, os.path.dirname(inliner.document.attributes['source'])) @@ -354,30 +355,88 @@ def find_doxygen_link(name, rawtext, text, lineno, inliner, options={}, content= return find_doxygen_link -def download_file(app, url, output_location): - if not os.path.isabs(output_location): - output_location = os.path.join(app.outdir, output_location) - if os.path.exists(output_location): +def fetch_file(app, source, output_path): + """Fetches file and puts it in the desired location if it does not exist yet. + + Local files will be copied and remote files will be downloaded. + Directories in the ``output_path`` get created if needed. + + Args: + app: Sphinx' application instance + source (str): Path to local file or URL to remote file + output_path (str): Path with filename to copy/download the source to, relative to Sphinx' output directory + """ + if not os.path.isabs(output_path): + output_path = os.path.join(app.outdir, output_path) + if os.path.exists(output_path): return - response = requests.get(url, allow_redirects=True) - if response.status_code != 200: + os.makedirs(os.path.dirname(output_path), exist_ok=True) + if is_url(source): + response = requests.get(source, allow_redirects=True) + if response.status_code != 200: + report_warning(app.env, + standout("Could not find file %r. Make sure your `doxylink_pdf_files` config variable is " + "set correctly." % source)) + return + with open(output_path, 'wb') as file: + file.write(response.content) + else: + if not os.path.isabs(source): + source = os.path.join(app.outdir, source) + if os.path.exists(source): + shutil.copy(source, output_path) + else: + report_warning(app.env, + standout("Expected a URL or a path that exists as value for `doxylink_pdf_files` " + "config variable; got %r" % source)) + + +def process_configuration(app, tag_filename, rootdir, pdf_filename): + """Processes the configured values for ``doxylink`` and ``doxylink_pdf_files`` and warns about potential issues. + + The type of builder decides which values shall be used. + + Args: + app: Sphinx' application instance + tag_filename (str): Path to the Doxygen tag file + rootdir (str): Path to the root directory of Doxygen HTML documentation + pdf_filename (str): Path to the pdf file; may be empty when LaTeX builder is not used + """ + if app.builder.format == 'latex': + if not pdf_filename: + if is_url(rootdir): + report_warning(app.env, + "Linking from PDF to remote Doxygen html is not supported yet; got %r." + "Consider linking to a Doxygen pdf file instead as " + "third element of the tuple in the `doxylink` config variable." % rootdir) + else: + report_warning(app.env, + "Linking from PDF to local Doxygen html is not possible; got %r." + "Consider linking to a Doxygen pdf file instead as third element of the tuple in the " + "`doxylink` config variable." % rootdir) + elif pdf_filename in app.config.doxylink_pdf_files: + source = app.config.doxylink_pdf_files[pdf_filename] + fetch_file(app, source, pdf_filename) + elif pdf_filename and not rootdir: report_warning(app.env, - standout("Could not find file %r. Make sure your `doxylink_remote_pdf_files` config variable is " - "set correctly." % url)) - return - os.makedirs(os.path.dirname(output_location), exist_ok=True) - with open(output_location, 'wb') as file: - file.write(response.content) + "Linking from HTML to Doxygen pdf (%r) is not supported. Consider setting " + "the root directory of Doxygen's HTML output as value instead." % pdf_filename) def setup_doxylink_roles(app): - for name, (tag_filename, rootdir) in app.config.doxylink.items(): - app.add_role(name, create_role(app, tag_filename, rootdir, name)) - if rootdir in app.config.doxylink_remote_pdf_files: - url = app.config.doxylink_remote_pdf_files[rootdir] - if is_url(url): - download_file(app, url, rootdir) + for name, values in app.config.doxylink.items(): + if len(values) == 3: + tag_filename, rootdir, pdf_filename = values + elif len(values) == 2: + tag_filename = values[0] + if values[1].endswith('.pdf'): + pdf_filename = values[1] + rootdir = "" else: - report_warning(app.env, - standout("Expected a URL as value for `doxylink_remote_pdf_files` config variable; " - "got %r" % url)) + rootdir = values[1] + pdf_filename = "" + else: + raise ValueError("Config variable `doxylink` is incorrectly configured. Expected a tuple with 2 to 3 " + "elements; got %s" % values) + process_configuration(app, tag_filename, rootdir, pdf_filename) + app.add_role(name, create_role(app, tag_filename, rootdir, name, pdf=pdf_filename)) From dc0f8ba789de3256336ae1da499be754c446be35 Mon Sep 17 00:00:00 2001 From: jce Date: Thu, 23 Sep 2021 19:23:15 +0200 Subject: [PATCH 08/13] Update doc for doxylink and doxylink_pdf_files --- doc/index.rst | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index bb6fdde..646f3ee 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -132,38 +132,43 @@ Configuration values The environment is set up with a dictionary mapping the interpreted text role to a tuple of tag file and prefix. The keys of this dictionary must be lower-case. The prefix can be an absolute path or a path relative to `Sphinx' - output directory`_. It may be a path to the directory that contains your *index.html* or the name of your Doxygen - pdf file. + output directory`_. An optional third element with the name of a Doxygen pdf file may be added. This will be used + when Sphinx uses the LaTeX builder. Otherwise, the second element of the tuple will be used to link to. .. code-block:: python doxylink = { - 'polyvox' : ('/home/matt/PolyVox.tag', '/home/matt/PolyVox/html/'), - 'qtogre' : ('/home/matt/QtOgre.tag', '/home/matt/QtOgre/html/'), + 'polyvox' : ('/home/matt/PolyVox.tag', '/home/matt/PolyVox/html/', 'polyvox_doxygen.pdf'), + 'qtogre' : ('/home/matt/QtOgre.tag', '/home/matt/QtOgre/html/', 'qtogre_doxygen.pdf'), } + .. note:: + + The links in your pdf document to your Doxygen pdf file(s) may not work (properly) in a browser or a basic + PDF-reader. They should work in Adobe Reader for example. + .. _`Sphinx' output directory`: https://www.sphinx-doc.org/en/master/extdev/appapi.html#sphinx.application.Sphinx.outdir .. confval:: add_function_parentheses A boolean that decides whether parentheses are appended to function and method role text. Default is ``True``. -.. confval:: doxylink_remote_pdf_files +.. confval:: doxylink_pdf_files - Doxylink can be configured to download remote Doxygen pdf files. You should use the output file name as the second - element of the value of the ``doxylink`` dictionary **and** as key in the ``doxylink_remote_pdf_files`` dictionary, - which should contain the URL to the remote location as value. If the pdf file already exists locally, it will not - be downloaded. + Doxylink can be configured to download remote Doxygen pdf files or copy them from a local location. + You should use the output file name as the third + element of the value of the ``doxylink`` dictionary **and** as key in the ``doxylink_pdf_files`` dictionary, + which should contain the URL to the remote location or local location as value. + If the pdf file already exists locally, it will not be downloaded or overwritten. .. code-block:: python - doxylink = { - 'polyvox' : ('/home/matt/PolyVox.tag', 'polyvox_doxygen.pdf'), - } - doxylink_remote_pdf_files = { + doxylink_pdf_files = { 'polyvox_doxygen.pdf': url_to_remote_doxygen_pdf, + 'qtogre_doxygen.pdf': '/home/matt/qtogre/doxygen.pdf', } + Bug reports ----------- From d80bcdbf9850513f3ae3dccc74e84c1f8a43e04f Mon Sep 17 00:00:00 2001 From: jce Date: Thu, 23 Sep 2021 19:23:52 +0200 Subject: [PATCH 09/13] Update changelog after adding support for local pdf files --- CHANGES.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 22f52e4..ece8a47 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,7 +1,7 @@ -1.11 (Sep 20, 2021) +1.11 (Sep 22, 2021) ================== -- Add feature to download remote pdf files [PR #35] +- Add feature to download remote and copy local pdf files [PR #35] 1.10 (Sep 10, 2021) ================== From 6be9be902c1d9a1f3cddf47b141f96ea40ae66c9 Mon Sep 17 00:00:00 2001 From: JasperCraeghs <28319872+JasperCraeghs@users.noreply.github.com> Date: Fri, 24 Sep 2021 21:45:04 +0200 Subject: [PATCH 10/13] Clarify condition for overwriting locally stored pdf file Co-authored-by: Crt Mori --- doc/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index.rst b/doc/index.rst index 646f3ee..ba6d695 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -159,7 +159,7 @@ Configuration values You should use the output file name as the third element of the value of the ``doxylink`` dictionary **and** as key in the ``doxylink_pdf_files`` dictionary, which should contain the URL to the remote location or local location as value. - If the pdf file already exists locally, it will not be downloaded or overwritten. + If the pdf file already exists locally in Sphinx' output directory, it will not be downloaded or overwritten. .. code-block:: python From a120ffee024e12530469e775e86c1619287b6f16 Mon Sep 17 00:00:00 2001 From: jce Date: Fri, 24 Sep 2021 23:17:16 +0200 Subject: [PATCH 11/13] Refactoring for better testability --- sphinxcontrib/doxylink/doxylink.py | 31 +++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/sphinxcontrib/doxylink/doxylink.py b/sphinxcontrib/doxylink/doxylink.py index 7018bb7..f70f1af 100644 --- a/sphinxcontrib/doxylink/doxylink.py +++ b/sphinxcontrib/doxylink/doxylink.py @@ -355,6 +355,23 @@ def find_doxygen_link(name, rawtext, text, lineno, inliner, options={}, content= return find_doxygen_link +def extract_configuration(values): + if len(values) == 3: + tag_filename, rootdir, pdf_filename = values + elif len(values) == 2: + tag_filename = values[0] + if values[1].endswith('.pdf'): + pdf_filename = values[1] + rootdir = "" + else: + rootdir = values[1] + pdf_filename = "" + else: + raise ValueError("Config variable `doxylink` is incorrectly configured. Expected a tuple with 2 to 3 " + "elements; got %s" % values) + return tag_filename, rootdir, pdf_filename + + def fetch_file(app, source, output_path): """Fetches file and puts it in the desired location if it does not exist yet. @@ -425,18 +442,6 @@ def process_configuration(app, tag_filename, rootdir, pdf_filename): def setup_doxylink_roles(app): for name, values in app.config.doxylink.items(): - if len(values) == 3: - tag_filename, rootdir, pdf_filename = values - elif len(values) == 2: - tag_filename = values[0] - if values[1].endswith('.pdf'): - pdf_filename = values[1] - rootdir = "" - else: - rootdir = values[1] - pdf_filename = "" - else: - raise ValueError("Config variable `doxylink` is incorrectly configured. Expected a tuple with 2 to 3 " - "elements; got %s" % values) + tag_filename, rootdir, pdf_filename = extract_configuration(values) process_configuration(app, tag_filename, rootdir, pdf_filename) app.add_role(name, create_role(app, tag_filename, rootdir, name, pdf=pdf_filename)) From 2c84c42553d649966e2b716c6d3266cda7061d68 Mon Sep 17 00:00:00 2001 From: jce Date: Fri, 24 Sep 2021 23:18:24 +0200 Subject: [PATCH 12/13] Test validity of configuration variable 'doxylink' --- test-requirements.txt | 1 + tests/test_doxylink.py | 55 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/test-requirements.txt b/test-requirements.txt index e079f8a..6565ec3 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1 +1,2 @@ pytest +testfixtures diff --git a/tests/test_doxylink.py b/tests/test_doxylink.py index fb00fc2..f4c3700 100644 --- a/tests/test_doxylink.py +++ b/tests/test_doxylink.py @@ -4,8 +4,10 @@ import os.path import subprocess import xml.etree.ElementTree as ET +from unittest.mock import Mock import pytest +from testfixtures import LogCapture from sphinxcontrib.doxylink import doxylink @@ -131,3 +133,56 @@ def test_find_url_piecewise(examples_tag_file, symbol, expected_matches): def test_is_url(str_to_validate, expected): result = doxylink.is_url(str_to_validate) assert result == expected + + +@pytest.mark.parametrize('values, out_rootdir, out_pdf', [ + (['doxygen/project.tag', 'https://example.com'], 'https://example.com', ''), + (['doxygen/project.tag', 'https://example.com', ''], 'https://example.com', ''), + (['doxygen/project.tag', 'doxygen.pdf'], '', 'doxygen.pdf'), + (['doxygen/project.tag', 'https://example.com', 'doxygen.pdf'], 'https://example.com', 'doxygen.pdf'), +]) +def test_extract_configuration_pass(values, out_rootdir, out_pdf): + tag_filename, rootdir, pdf_filename = doxylink.extract_configuration(values) + assert rootdir == out_rootdir + assert pdf_filename == out_pdf + + +@pytest.mark.parametrize('values', [ + (['doxygen/project.tag']), + (['doxygen/project.tag', 'https://example.com', 'doxygen.pdf', 'fail']), +]) +def test_extract_configuration_fail(values): + with pytest.raises(ValueError): + doxylink.extract_configuration(values) + + +@pytest.mark.parametrize('tag_filename, rootdir, pdf_filename, builder', [ + ('doxygen/project.tag', 'https://example.com', '', 'html'), + ('doxygen/project.tag', '.', '', 'latex'), + ('doxygen/project.tag', 'html/doxygen', 'doxygen.pdf', 'latex'), +]) +def test_process_configuration_pass(tag_filename, rootdir, pdf_filename, builder): + app = Mock() + app.builder.format == builder + with LogCapture() as l: + doxylink.process_configuration(app, tag_filename, rootdir, pdf_filename) + l.check() + + +@pytest.mark.parametrize('rootdir, pdf_filename, builder, msg', [ + ('', 'doxygen.pdf', 'html', + "Linking from HTML to Doxygen pdf ('doxygen.pdf') is not supported. " + "Consider setting the root directory of Doxygen's HTML output as value instead."), + ('https://example.com', '', 'latex', + "Linking from PDF to remote Doxygen html is not supported yet; got 'https://example.com'." + "Consider linking to a Doxygen pdf file instead as third element of the tuple in the `doxylink` config variable."), + ('html/doxygen', '', 'latex', + "Linking from PDF to local Doxygen html is not possible; got 'html/doxygen'." + "Consider linking to a Doxygen pdf file instead as third element of the tuple in the `doxylink` config variable."), +]) +def test_process_configuration_warn(rootdir, pdf_filename, builder, msg): + app = Mock() + app.builder.format = builder + with LogCapture() as l: + doxylink.process_configuration(app, 'doxygen/project.tag', rootdir, pdf_filename) + l.check(('sphinx.sphinxcontrib.doxylink.doxylink', 'WARNING', msg)) From e3695d59e5b8cfeb4d5b700248cb5e193db8da4f Mon Sep 17 00:00:00 2001 From: Jasper Craeghs Date: Sun, 26 Sep 2021 15:33:52 +0200 Subject: [PATCH 13/13] Fix newly added tests --- tests/test_doxylink.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_doxylink.py b/tests/test_doxylink.py index f4c3700..a027488 100644 --- a/tests/test_doxylink.py +++ b/tests/test_doxylink.py @@ -4,7 +4,7 @@ import os.path import subprocess import xml.etree.ElementTree as ET -from unittest.mock import Mock +from unittest.mock import MagicMock import pytest from testfixtures import LogCapture @@ -158,12 +158,12 @@ def test_extract_configuration_fail(values): @pytest.mark.parametrize('tag_filename, rootdir, pdf_filename, builder', [ ('doxygen/project.tag', 'https://example.com', '', 'html'), - ('doxygen/project.tag', '.', '', 'latex'), + ('doxygen/project.tag', '', 'doxygen.pdf', 'latex'), ('doxygen/project.tag', 'html/doxygen', 'doxygen.pdf', 'latex'), ]) def test_process_configuration_pass(tag_filename, rootdir, pdf_filename, builder): - app = Mock() - app.builder.format == builder + app = MagicMock() + app.builder.format = builder with LogCapture() as l: doxylink.process_configuration(app, tag_filename, rootdir, pdf_filename) l.check() @@ -181,7 +181,7 @@ def test_process_configuration_pass(tag_filename, rootdir, pdf_filename, builder "Consider linking to a Doxygen pdf file instead as third element of the tuple in the `doxylink` config variable."), ]) def test_process_configuration_warn(rootdir, pdf_filename, builder, msg): - app = Mock() + app = MagicMock() app.builder.format = builder with LogCapture() as l: doxylink.process_configuration(app, 'doxygen/project.tag', rootdir, pdf_filename)