diff --git a/.gitignore b/.gitignore index cd9b2e4..072dacb 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,8 @@ output/*/index.html _build preparer-test-* +deconstrst/pip-selfcheck.json +deconstrst/pyvenv.cfg + +# Mac stuff +.DS_Store diff --git a/.travis.yml b/.travis.yml index 0c36370..1c0cf04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: python python: -- "3.5.1" +- "3.6.6" install: -- pip install -r requirements.txt +- python setup.py install script: - python test/all.py diff --git a/Dockerfile b/Dockerfile index cab53d5..eb40108 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,28 +1,38 @@ -FROM alpine:3.3 -MAINTAINER Ash Wilson +FROM alpine:3.8 +LABEL author Ash Wilson @smashwilson -RUN apk add --no-cache python3 git -RUN python3 -m ensurepip -RUN ln -s /usr/bin/python3 /usr/bin/python && \ - ln -s /usr/bin/pip3 /usr/bin/pip -RUN pip install --upgrade pip +# Alpine python3 now includes pip +RUN apk add --no-cache --update --virtual .build-deps build-base python3-dev && \ + apk add --no-cache --update git python3 +RUN if [[ ! -e /usr/bin/pip ]]; then ln -s /usr/bin/pip3 /usr/bin/pip ; fi && \ + if [[ ! -e /usr/bin/python ]]; then ln -s /usr/bin/python3 /usr/bin/python; fi RUN adduser -D -g "" -u 1000 preparer RUN mkdir -p /preparer /venv /usr/content-repo RUN chown -R preparer:preparer /preparer /venv -ENV PYTHONPATH /preparer +# ENV PYTHONPATH /preparer -USER preparer +# USER preparer +# RUN python -m venv /venv +# ENV PATH /venv/bin:${PATH} -RUN pyvenv /venv -ENV PATH /venv/bin:${PATH} +# # Use the version of pip integrated in this release of Alpine +# # and don't complain. +# RUN mkdir -p $HOME/.config/pip +# RUN printf "[global]\ndisable-pip-version-check = True\n" \ +# > $HOME/.config/pip/pip.conf -COPY ./requirements.txt /preparer/requirements.txt -RUN pip install --upgrade pip &&\ - pip install -r /preparer/requirements.txt -COPY . /preparer +# COPY ./requirements.txt /preparer/requirements.txt +COPY . . -VOLUME /usr/content-repo -WORKDIR /usr/content-repo +RUN python setup.py install +# RUN python -m pip install --no-cache-dir -r /preparer/requirements.txt +# USER root +# RUN apk del .build-deps +# USER preparer +# COPY . /preparer -CMD ["python", "-m", "deconstrst"] +# VOLUME /usr/content-repo +# WORKDIR /usr/content-repo +ENTRYPOINT ["python", "-m", "deconstrst"] +# CMD ["python", "-m", "deconstrst"] diff --git a/deconstrst/__init__.py b/deconstrst/__init__.py index 9348dd8..6ddeefa 100755 --- a/deconstrst/__init__.py +++ b/deconstrst/__init__.py @@ -2,14 +2,44 @@ import os import sys +import subprocess -from pip import pip +from setuptools import setup from deconstrst.deconstrst import build, get_conf_builder from deconstrst.config import Configuration __author__ = 'Ash Wilson' -__email__ = 'ash.wilson@rackspace.com' -__version__ = '0.1.0' +__email__ = '@smashwilson' +__version__ = '0.2.0' + + +def get_dependencies(): + """ + Install non-colliding dependencies from a "requirements.txt" file found at + the content root. + """ + + reqfile = None + if os.path.exists('deconst-requirements.txt'): + reqfile = 'deconst-requirements.txt' + elif os.path.exists('requirements.txt'): + reqfile = 'requirements.txt' + else: + return + + dependencies = [] + + with open(reqfile, 'r', encoding='utf-8') as rf: + for line in rf: + if line.startswith('#'): + continue + + stripped = line.strip() + if not stripped: + continue + + dependencies.append(stripped) + return dependencies def main(directory=False): @@ -18,7 +48,8 @@ def main(directory=False): if config.content_root: if directory and directory != config.content_root: - print("Warning: Overriding CONTENT_ROOT [{}] with argument [{}].".format(config.content_root, directory)) + print("Warning: Overriding CONTENT_ROOT [{}] with argument [{}]." + .format(config.content_root, directory)) else: os.chdir(config.content_root) elif directory: @@ -52,6 +83,7 @@ def main(directory=False): print(file=sys.stderr) sys.exit(1) + def install_requirements(): """ Install non-colliding dependencies from a "requirements.txt" file found at @@ -79,8 +111,7 @@ def install_requirements(): dependencies.append(stripped) - print("Installing dependencies from {}: {}.".format(reqfile, ', '.join(dependencies))) - pip.main(['install'] + dependencies) - -if __name__ == '__main__': - main() + print("Installing dependencies from {}: {}.".format( + reqfile, ', '.join(dependencies))) + subprocess.check_call( + [sys.executable, '-m', 'pip', 'install', '-r', reqfile]) diff --git a/deconstrst/builders/__init__.py b/deconstrst/builders/__init__.py index 0ea3cf8..eb745ec 100644 --- a/deconstrst/builders/__init__.py +++ b/deconstrst/builders/__init__.py @@ -1,6 +1,7 @@ from sphinx.config import Config -# Tell Sphinx about the deconst_default_layout and deconst_default_unsearchable keys. +# Tell Sphinx about the deconst_default_layout and +# deconst_default_unsearchable keys. Config.config_values["deconst_default_layout"] = ("default", "html") Config.config_values["deconst_default_unsearchable"] = (None, "html") Config.config_values["deconst_categories"] = (None, "html") diff --git a/deconstrst/builders/common.py b/deconstrst/builders/common.py index 46402d0..30aaa5c 100644 --- a/deconstrst/builders/common.py +++ b/deconstrst/builders/common.py @@ -4,11 +4,8 @@ """ import os -import glob from os import path - from deconstrst.config import Configuration -from deconstrst.builders.writer import OffsetHTMLTranslator def init_builder(builder): @@ -16,14 +13,13 @@ def init_builder(builder): Common Builder initialization. """ - builder.translator_class = OffsetHTMLTranslator - builder.deconst_config = Configuration(os.environ) if path.exists('_deconst.json'): with open('_deconst.json', 'r', encoding='utf-8') as cf: builder.deconst_config.apply_file(cf) + def derive_content_id(deconst_config, docname): """ Consistently generate content IDs from document names. diff --git a/deconstrst/builders/envelope.py b/deconstrst/builders/envelope.py index 4a88454..2b5e42c 100644 --- a/deconstrst/builders/envelope.py +++ b/deconstrst/builders/envelope.py @@ -5,7 +5,9 @@ import re from os import path -from .common import derive_content_id +from deconstrst.builders.writer import OffsetHTMLTranslator +from deconstrst.builders.common import derive_content_id + class Envelope: """ @@ -13,7 +15,7 @@ class Envelope: """ def __init__(self, docname, body, title, toc, builder, deconst_config, - per_page_meta, docwriter): + per_page_meta, docwriter=OffsetHTMLTranslator): self.docname = docname self.body = body @@ -48,12 +50,12 @@ def __init__(self, docname, body, title, toc, builder, deconst_config, def set_next(self, n): if not n: return - self.next = { 'url': n['link'], 'title': n['title'] } + self.next = {'url': n['link'], 'title': n['title']} def set_previous(self, p): if not p: return - self.previous = { 'url': p['link'], 'title': p['title'] } + self.previous = {'url': p['link'], 'title': p['title']} def add_addenda(self, addenda_name, addenda_content_id): if self.addenda is None: @@ -65,7 +67,11 @@ def serialization_path(self): Generate the full path at which this envelope should be serialized. """ - envelope_filename = urllib.parse.quote(self.content_id, safe='') + '.json' + envelope_filename = urllib.parse.quote( + self.content_id, + safe='', + encoding='utf-8', + errors='strict') + '.json' return path.join(self.deconst_config.envelope_dir, envelope_filename) def serialization_payload(self): @@ -74,7 +80,7 @@ def serialization_payload(self): of the envelope. """ - payload = { 'body': self.body } + payload = {'body': self.body} if self.title: payload['title'] = self.title if self.toc: @@ -97,7 +103,6 @@ def serialization_payload(self): payload['previous'] = self.previous if self.addenda is not None: payload['addenda'] = self.addenda - return payload def _populate_meta(self): @@ -117,7 +122,8 @@ def _populate_git(self): if self.deconst_config.git_root and self.deconst_config.github_url: full_path = path.join(os.getcwd(), self.builder.env.srcdir, - self.docname + self.builder.config.source_suffix[0]) + self.docname + + self.builder.config.source_suffix[0]) edit_segments = [ self.deconst_config.github_url, @@ -126,15 +132,17 @@ def _populate_git(self): path.relpath(full_path, self.builder.env.srcdir) ] - self.meta['github_edit_url'] = '/'.join(segment.strip('/') for segment in edit_segments) + self.meta['github_edit_url'] = '/'.join( + segment.strip('/') for segment in edit_segments) def _populate_unsearchable(self): """ Populate "unsearchable" from per-page or repository-wide settings. """ - unsearchable = self.per_page_meta.get('deconstunsearchable', - self.builder.config.deconst_default_unsearchable) + unsearchable = self.per_page_meta.get( + 'deconstunsearchable', + self.builder.config.deconst_default_unsearchable) if unsearchable is not None: self.unsearchable = unsearchable in ('true', True) @@ -144,7 +152,8 @@ def _populate_layout_key(self): """ default_layout = self.builder.config.deconst_default_layout - self.layout_key = self.per_page_meta.get('deconstlayout', default_layout) + self.layout_key = self.per_page_meta.get( + 'deconstlayout', default_layout) def _populate_categories(self): """ @@ -164,8 +173,10 @@ def _populate_asset_offsets(self): """ Read stored asset offsets from the docwriter. """ - - self.asset_offsets = self.docwriter.visitor.calculate_offsets() + self.asset_offsets, new_body = self.docwriter.calculate_offsets( + self.docwriter, self.body, + self.deconst_config, self.builder.images) + self.body = new_body def _populate_content_id(self): """ diff --git a/deconstrst/builders/serial.py b/deconstrst/builders/serial.py index 3427d53..ee08a98 100644 --- a/deconstrst/builders/serial.py +++ b/deconstrst/builders/serial.py @@ -9,23 +9,25 @@ from sphinx.util.osutil import relative_uri from .common import init_builder, derive_content_id from .envelope import Envelope +from deconstrst.builders.writer import OffsetHTMLTranslator TOC_DOCNAME = '_toc' + class DeconstSerialJSONBuilder(JSONHTMLBuilder): """ Custom Sphinx builder that generates Deconst-compatible JSON documents. """ implementation = jsonimpl - name = 'deconst' + name = 'deconst-serial' out_suffix = '.json' + translator_class = OffsetHTMLTranslator def init(self): super().init() init_builder(self) - self.toc_envelope = None def prepare_writing(self, docnames): @@ -55,6 +57,11 @@ def finish(self): Also, the search indices and so on aren't necessary. """ + self.finish_tasks.add_task(self.copy_image_files) + self.finish_tasks.add_task(self.copy_download_files) + # self.finish_tasks.add_task(self.copy_static_files) + self.finish_tasks.add_task(self.copy_extra_files) + self.finish_tasks.add_task(self.write_buildinfo) def write_context(self, context): """ @@ -75,11 +82,14 @@ def write_context(self, context): toc=local_toc, builder=self, deconst_config=self.deconst_config, - per_page_meta=per_page_meta, - docwriter=self.docwriter) + per_page_meta=per_page_meta) + # docwriter=self.docwriter) # Omit the TOC envelope. It's handled in prepare_writing(). - if self.toc_envelope and envelope.content_id == self.toc_envelope.content_id: + # I am not sure the first part of this conditional should + # be necesarry + if self.toc_envelope and \ + envelope.content_id == self.toc_envelope.content_id: return envelope.set_next(context.get('next')) @@ -87,7 +97,8 @@ def write_context(self, context): # If this repository has a TOC, reference it as an addenda. if self.toc_envelope: - envelope.add_addenda('repository_toc', self.toc_envelope.content_id) + envelope.add_addenda( + 'repository_toc', self.toc_envelope.content_id) self.dump_context(envelope.serialization_payload(), envelope.serialization_path()) @@ -121,32 +132,42 @@ def _toc_envelope(self): # Identify toctree nodes from the chosen document toctrees = [] for toctreenode in doctree.traverse(addnodes.toctree): - toctree = self.env.resolve_toctree(self.config.master_doc, self, toctreenode, - prune=True, - includehidden=includehidden, - maxdepth=0) - - # Rewrite refuris from this resolved toctree - for refnode in toctree.traverse(nodes.reference): - if 'refuri' not in refnode: - continue - - refstr = refnode['refuri'] - parts = urllib.parse.urlparse(refstr) - - if parts.scheme or parts.netloc: - # Absolute URL - continue - - target = "{{ to('" + derive_content_id(self.deconst_config, parts.path) + "') }}" - if parts.fragment: - target += '#' + parts.fragment - - refnode['refuri'] = target - - toctreenode.replace_self(toctree) - - toctrees.append(toctree) + toctree = self.env.resolve_toctree( + self.config.master_doc, + self, + toctreenode, + prune=True, + includehidden=includehidden, + maxdepth=0) + + if toctree: + # Rewrite refuris from this resolved toctree + for refnode in toctree.traverse(nodes.reference): + if 'refuri' not in refnode: + continue + + refstr = refnode['refuri'] + parts = urllib.parse.urlparse(refstr) + + if parts.scheme or parts.netloc: + # Absolute URL + continue + + # target = "{{ to('" + # + derive_content_id(self.deconst_config, parts.path) + # + "') }}" + target = '{}{}{}'.format( + '{{ to(\'', + derive_content_id(self.deconst_config, parts.path), + '\') }}') + if parts.fragment: + target += '#' + parts.fragment + + refnode['refuri'] = target + + toctreenode.replace_self(toctree) + + toctrees.append(toctree) # No toctree found. if not toctrees: @@ -161,8 +182,11 @@ def _toc_envelope(self): if full_render: self.secnumbers = self.env.toc_secnumbers.get(docname, {}) self.fignumbers = self.env.toc_fignumbers.get(docname, {}) - self.imgpath = relative_uri(self.get_target_uri(docname), '_images') - self.dlpath = relative_uri(self.get_target_uri(docname), '_downloads') + self.imgpath = relative_uri( + self.get_target_uri(docname), '_images') + print(f'!!!~~~The image path: {self.imgpath}~~~!!!') + self.dlpath = relative_uri( + self.get_target_uri(docname), '_downloads') self.current_docname = docname rendered_toc = self.render_partial(doctree)['body'] @@ -176,5 +200,5 @@ def _toc_envelope(self): toc=None, builder=self, deconst_config=self.deconst_config, - per_page_meta={'deconstunsearchable': True}, - docwriter=self._publisher.writer) + per_page_meta={'deconstunsearchable': True}) + # docwriter=self._publisher.writer) diff --git a/deconstrst/builders/single.py b/deconstrst/builders/single.py index 81fd584..c8e3662 100644 --- a/deconstrst/builders/single.py +++ b/deconstrst/builders/single.py @@ -15,10 +15,12 @@ class DeconstSingleJSONBuilder(SingleFileHTMLBuilder): """ name = 'deconst-single' + # translator_class = OffsetHTMLTranslator def init(self): super().init() init_builder(self) + # self.translator_class = OffsetHTMLTranslator(self) def fix_refuris(self, tree): """ @@ -79,8 +81,8 @@ def write_context(self, context): toc=local_toc, builder=self, deconst_config=self.deconst_config, - per_page_meta=per_page_meta, - docwriter=self.docwriter) + per_page_meta=per_page_meta) + # docwriter=OffsetHTMLTranslator(self, context[])) with open(envelope.serialization_path(), 'w', encoding="utf-8") as f: jsonimpl.dump(envelope.serialization_payload(), f) diff --git a/deconstrst/builders/writer.py b/deconstrst/builders/writer.py index 845f0b2..7bb518f 100644 --- a/deconstrst/builders/writer.py +++ b/deconstrst/builders/writer.py @@ -5,33 +5,35 @@ import os from os import path from collections import defaultdict - +# import config from sphinx.writers.html import HTMLTranslator # Regexp to match the source attribute of an tag that's been generated # with a placeholder. RE_SRCATTR = re.compile(r"src\s*=\s*\"(X)\"") + class OffsetHTMLTranslator(HTMLTranslator): """ Hook Sphinx's HTMLTranslator to track the offsets of image nodes within the rendered content. """ - def __init__(self, *args, **kwargs): + def __init__(self, builder, *args, **kwargs): + print('!!!~~~ HERE I AM ~~~!!!') super().__init__(*args, **kwargs) self.asset_offsets = defaultdict(list) dc = self.builder.deconst_config - self.asset_src_root = path.realpath('_images') # This is actually hardcoded in StandaloneHTMLBuilder + # This is actually hardcoded in StandaloneHTMLBuilder + self.asset_src_root = path.realpath('../../_images') self.asset_dest_root = path.realpath(dc.asset_dir) def visit_image(self, node): """ Record the offset for this asset reference. """ - asset_src_path = path.realpath(node['uri']) if asset_src_path.startswith(self.asset_src_root): asset_rel_path = path.relpath(asset_src_path, self.asset_src_root) @@ -42,40 +44,46 @@ def visit_image(self, node): os.makedirs(path.dirname(asset_dest_path), exist_ok=True) shutil.copyfile(asset_src_path, asset_dest_path) node['uri'] = 'X' - super().visit_image(node) - chunk = self.body[-1] chunk_match = RE_SRCATTR.search(chunk) if not chunk_match: - msg = "Unable to find image tag placeholder src attribute within [{}]".format(self.body[-1]) + msg =\ + "Unable to find image tag placeholder src attribute within \ + [{}]".format(self.body[-1]) raise Exception(msg) chunk_index = len(self.body) - 1 chunk_offset = chunk_match.start(1) - self.asset_offsets[asset_rel_path].append(AssetOffset(chunk_index, chunk_offset)) + self.asset_offsets[asset_rel_path].append( + AssetOffset(chunk_index, chunk_offset)) - def calculate_offsets(self): + def calculate_offsets(self, body: str, conf, images): """ Use the final translator state to compute body offsets for all assets. """ - if not self.asset_offsets: - return {} - - total = 0 - - chunk_offsets = [] - for chunk in self.body: - chunk_offsets.append(total) - total += len(chunk) + offset_map = {} + img_tag_pattern = r'alt=\"(.+)\" src=\"(.+)\"' + for img_tag in re.finditer(img_tag_pattern, body): + local_path = img_tag.group(1) + for image in images: + if local_path.endswith(images[image]): + dest_path = image[len('_images/'):] + src_path = image + offset_map[dest_path] = [ + img_tag.start() + len('alt=\"X\" src=\"')] + os.makedirs( + path.dirname( + path.join(conf.asset_dir, dest_path)), + exist_ok=True) + shutil.copyfile(src_path, path.join( + conf.asset_dir, dest_path)) + break + subbed = re.subn(img_tag_pattern, 'alt=\"X\" src=\"X\"', body) + return offset_map, subbed[0] - results = {} - for (asset_rel_path, asset_offsets) in self.asset_offsets.items(): - offsets = [chunk_offsets[o.chunk_index] + o.chunk_offset for o in asset_offsets] - results[asset_rel_path] = offsets - return results class AssetOffset: """ diff --git a/deconstrst/config.py b/deconstrst/config.py index 14b01fc..2e120e7 100644 --- a/deconstrst/config.py +++ b/deconstrst/config.py @@ -30,11 +30,13 @@ def __init__(self, env): self.envelope_dir = env.get("ENVELOPE_DIR", None) if not self.envelope_dir: - self.envelope_dir = path.join(self.content_root, '_build', 'deconst-envelopes') + self.envelope_dir = path.join( + self.content_root, '_build', 'deconst-envelopes') self.asset_dir = env.get("ASSET_DIR", None) if not self.asset_dir: - self.asset_dir = path.join(self.content_root, '_build', 'deconst-assets') + self.asset_dir = path.join( + self.content_root, '_build', 'deconst-assets') self.meta = {} self.github_url = "" @@ -68,7 +70,8 @@ def apply_file(self, f): if "githubUrl" in doc: self.github_url = doc["githubUrl"] - self.github_issues_url = '/'.join(segment.strip('/') for segment in [doc["githubUrl"], 'issues']) + self.github_issues_url = '/'.join( + segment.strip('/') for segment in [doc["githubUrl"], 'issues']) self.meta.update({'github_issues_url': self.github_issues_url}) if "githubBranch" in doc: @@ -92,7 +95,7 @@ def _get_git_root(self, d): def missing_values(self): """ Determine whether or not the current build should result in the - preparation of envelopes. If not, return a list of reasons why it won't. + preparation of envelopes. If not, return a list of reasons why. """ reasons = [] diff --git a/deconstrst/deconstrst.py b/deconstrst/deconstrst.py index 431aadc..7f9c3ed 100755 --- a/deconstrst/deconstrst.py +++ b/deconstrst/deconstrst.py @@ -2,13 +2,11 @@ import sys import os -import urllib.parse -import requests from deconstrst.builders.serial import DeconstSerialJSONBuilder from deconstrst.builders.single import DeconstSingleJSONBuilder +from deconstrst.builders.writer import OffsetHTMLTranslator from sphinx.application import Sphinx -from sphinx.builders import BUILTIN_BUILDERS DEFAULT_BUILDER = 'deconst-serial' @@ -18,10 +16,6 @@ def build(srcdir, destdir): Invoke Sphinx with locked arguments to generate JSON content. """ - # I am a terrible person - BUILTIN_BUILDERS['deconst-serial'] = DeconstSerialJSONBuilder - BUILTIN_BUILDERS['deconst-single'] = DeconstSingleJSONBuilder - conf_builder = get_conf_builder(srcdir) doctreedir = os.path.join(destdir, '.doctrees') @@ -34,6 +28,7 @@ def build(srcdir, destdir): return app.statuscode + def get_conf_builder(srcdir): with open(os.path.join(srcdir, 'conf.py'), encoding="utf-8") as conf_file: conf_data = conf_file.read() @@ -47,3 +42,22 @@ def get_conf_builder(srcdir): """ return locals().get('builder', DEFAULT_BUILDER) + + +def builder_init_handler(app: Sphinx): + """builder_init_handler reports initialization of a builder. + + Arguments: + app {Sphinx} -- the instance of the applicaiton + """ + print('{} successfully initialized.'.format( + app.builder.__getattribute__('name'))) + + +def setup(app: Sphinx): + app.connect('builder-inited', builder_init_handler) + app.setup_extension('sphinx.builders.html') + app.set_translator('OffsetHTMLTranslator', OffsetHTMLTranslator) + app.add_builder(DeconstSerialJSONBuilder) + app.add_builder(DeconstSingleJSONBuilder) + return {} diff --git a/requirements.txt b/requirements.txt index e65dd05..37aa7e9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,19 @@ -alabaster==0.7.7 -Babel==2.3.4 -certifi==2016.2.28 -docutils==0.12 -imagesize==0.7.1 -Jinja2==2.8 -MarkupSafe==0.23 -Pygments==2.1.3 -pytz==2016.4 -requests==2.20.0 -six==1.10.0 +alabaster==0.7.11 +Babel==2.6.0 +certifi==2018.8.24 +docutils==0.14 +imagesize==1.0.0 +Jinja2==2.10 +MarkupSafe==1.0 +pbr==4.2.0 +Pygments==2.2.0 +pytz==2018.5 +PyYAML==3.13 +reno==2.9.2 +requests==2.19.1 +six==1.11.0 snowballstemmer==1.2.1 -Sphinx==1.4.1 -sphinx-rtd-theme==0.1.9 +Sphinx==1.7.8 +sphinx_rtd_theme==0.4.1 termcolor==1.1.0 +unidecode diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..fd7efba --- /dev/null +++ b/setup.py @@ -0,0 +1,48 @@ +from setuptools import setup +import os + + +def get_dependencies(): + """ + Install non-colliding dependencies from a "requirements.txt" file found at + the content root. + """ + + reqfile = None + if os.path.exists('deconst-requirements.txt'): + reqfile = 'deconst-requirements.txt' + elif os.path.exists('requirements.txt'): + reqfile = 'requirements.txt' + else: + return + + dependencies = [] + + with open(reqfile, 'r', encoding='utf-8') as rf: + for line in rf: + if line.startswith('#'): + continue + + stripped = line.strip() + if not stripped: + continue + + dependencies.append(stripped) + return dependencies + + +setup( + name='deconstrst', + author='Patrick Kirchhoff', + author_email='patrick.kirchhoff@rackspace.co.uk', + description='A sphinx extension.', + # Package info + packages=['deconstrst', 'deconstrst.builders'], + install_requires=get_dependencies(), + entry_points={ + 'sphinx.builders': [ + 'deconst-serial = builders.serial:DeconstSerialJSONBuilder', + 'deconst-single = builders.single:DeconstSingleJSONBuilder', + ] + } +) diff --git a/test/all.py b/test/all.py index f321542..aa8fd94 100644 --- a/test/all.py +++ b/test/all.py @@ -6,6 +6,7 @@ import io import sys import traceback +import deconstrst from diff import diff from os import path from shutil import rmtree @@ -14,7 +15,6 @@ sys.path.append(path.join(path.dirname(__file__), '..')) -import deconstrst TESTCASE_ROOT = path.realpath(path.dirname(__file__)) @@ -25,6 +25,7 @@ FAIL = object() ERROR = object() + class Testcase: """ A single pair of input and expected output directories. @@ -35,11 +36,13 @@ def __init__(self, root): self.src_root = path.join(root, 'src') self.expected_root = path.join(root, 'dest') - self.expected_envelope_root = path.join(self.expected_root, 'envelopes') + self.expected_envelope_root = path.join( + self.expected_root, 'envelopes') self.expected_asset_root = path.join(self.expected_root, 'assets') scratch_dir = os.environ.get('SCRATCH_DIR', os.getcwd()) - self.actual_root = path.join(scratch_dir, 'preparer-test-{}'.format(self.name())) + self.actual_root = path.join( + scratch_dir, 'preparer-test-{}'.format(self.name())) self.actual_envelope_root = path.join(self.actual_root, 'envelopes') self.actual_asset_root = path.join(self.actual_root, 'assets') @@ -75,7 +78,8 @@ def run(self): self.output = capture.getvalue() def compare(self): - expected_envelopes = self.envelope_set_from(self.expected_envelope_root) + expected_envelopes = self.envelope_set_from( + self.expected_envelope_root) expected_assets = self.asset_set_from(self.expected_asset_root) actual_envelopes = self.envelope_set_from(self.actual_envelope_root) @@ -92,7 +96,7 @@ def envelope_set_from(self, root): for filename in filenames: fullpath = path.join(dirpath, filename) try: - with open(fullpath, 'r') as ef: + with open(fullpath, 'r', encoding='utf-8') as ef: envelopes[filename] = json.load(ef) except json.JSONDecodeError: pass @@ -119,7 +123,8 @@ def report(self): if header: report.write('\n') - report.write(colored('== Report [{}]'.format(self.name()), attrs=['reverse'])) + report.write(colored('== Report [{}]'.format( + self.name()), attrs=['reverse'])) report.write('\n') if output: diff --git a/test/diff.py b/test/diff.py index 187ec4e..2a0e8fc 100644 --- a/test/diff.py +++ b/test/diff.py @@ -1,23 +1,29 @@ # -*- coding: utf-8 -*- import json +from unidecode import unidecode from termcolor import colored + def diff(actual, expected, keypath=[], indent=''): tp = type(expected) - if tp != type(actual): + if not (tp is type(actual)): return [_unequal(keypath, actual, expected, indent)] - if tp == list: + if tp is list: return _diff_lists(actual, expected, keypath, indent) - if tp == dict: + if tp is dict: return _diff_dicts(actual, expected, keypath, indent) if actual == expected: return [] else: - return [_unequal(keypath, actual, expected, indent)] + return [_unequal(keypath, + unidecode(actual), + unidecode(expected), + indent)] + def _diff_dicts(actual, expected, keypath=[], indent=''): actual_keys = actual.keys() @@ -32,10 +38,12 @@ def _diff_dicts(actual, expected, keypath=[], indent=''): for shared in expected_keys & actual_keys: if expected[shared] != actual[shared]: - diffs += diff(actual[shared], expected[shared], keypath + [shared], indent) + diffs += diff(actual[shared], expected[shared], + keypath + [shared], indent) return diffs + def _diff_lists(actual, expected, keypath=[], indent=''): actual_set = set(actual) expected_set = set(expected) @@ -49,26 +57,33 @@ def _diff_lists(actual, expected, keypath=[], indent=''): return diffs + def _missing(keypath, missing, indent=''): hline = _hline('-', keypath, 'red') return hline + _body(missing, indent) + def _extra(keypath, extra, indent=''): hline = _hline('+', keypath, 'green') return hline + _body(extra, indent) + def _unequal(keypath, actual, expected, indent=''): hline = _hline('~', keypath, 'magenta') - actual_body = '\n' + indent + colored('actual:', attrs=['underline']) + _body(actual, indent) - expected_body = '\n' + indent + colored('expected:', attrs=['underline']) + _body(expected, indent) + actual_body = '\n' + indent + \ + colored('actual:\n', attrs=['underline']) + _body(actual, indent) + expected_body = '\n' + indent + \ + colored('expected:\n', attrs=['underline']) + _body(expected, indent) return hline + actual_body + expected_body + def _hline(op, keypath, color): line = op + ' ' + '.'.join(keypath) return colored(line, color) + def _body(item, indent=''): - body = json.dumps(item, indent=' ') + body = json.dumps(item, indent=' ', ensure_ascii=False) if '\n' in body: # Multiline object. indented_body = body.replace('\n', '\n' + indent) diff --git a/test/requirements/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Frequirements.json b/test/requirements/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Frequirements.json index b9ed722..a29a64d 100644 --- a/test/requirements/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Frequirements.json +++ b/test/requirements/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Frequirements.json @@ -1,11 +1,11 @@ { - "title": "Welcome to Requirements's documentation!", - "body": "
\n

Welcome to Requirements's documentation!

\n
\n

Release Notes

\n
\n

0.0.0

\n

Hey look it's a prelude

\n
\n

New Features

\n
    \n
  • Is now awesome
  • \n
  • Sucks less
  • \n
\n
\n
\n

Known Issues

\n
    \n
  • Completely fictitious
  • \n
\n
\n
\n

Upgrade Notes

\n
    \n
  • Nothing, because it's all made up
  • \n
\n
\n
\n

Deprecation Notes

\n
    \n
  • Everything that worked before is broken
  • \n
\n
\n
\n

Critical Issues

\n
    \n
  • AAAAAAAAAH
  • \n
\n
\n
\n

Security Issues

\n
    \n
  • Posts all of your private keys to the Internets
  • \n
\n
\n
\n

Bug Fixes

\n
    \n
  • 96% fewer crashes to desktop
  • \n
\n
\n
\n

Other Notes

\n
    \n
  • Hooray
  • \n
\n
\n
\n
\n
\n
    \n
\n
\n
\n", - "toc": "\n", + "title": "Welcome to Requirements\u2019s documentation!", + "body": "
\n

Welcome to Requirements\u2019s documentation!\u00b6

\n
\n

Release Notes\u00b6

\n
\n

0.0.0\u00b6

\n
\n

Prelude\u00b6

\n

Hey look it\u2019s a prelude

\n
\n
\n

New Features\u00b6

\n
    \n
  • Is now awesome
  • \n
\n
    \n
  • Sucks less
  • \n
\n
\n
\n

Known Issues\u00b6

\n
    \n
  • Completely fictitious
  • \n
\n
\n
\n

Upgrade Notes\u00b6

\n
    \n
  • Nothing, because it\u2019s all made up
  • \n
\n
\n
\n

Deprecation Notes\u00b6

\n
    \n
  • Everything that worked before is broken
  • \n
\n
\n
\n

Critical Issues\u00b6

\n
    \n
  • AAAAAAAAAH
  • \n
\n
\n
\n

Security Issues\u00b6

\n
    \n
  • Posts all of your private keys to the Internets
  • \n
\n
\n
\n

Bug Fixes\u00b6

\n
    \n
  • 96% fewer crashes to desktop
  • \n
\n
\n
\n

Other Notes\u00b6

\n
    \n
  • Hooray
  • \n
\n
\n
\n
\n
\n
\n
\n", + "toc": "\n", "layout_key": "default", "addenda": { "repository_toc": "https://github.com/tests/requirements/_toc" }, "asset_offsets": {}, "meta": {} -} +} \ No newline at end of file diff --git a/test/requirements/src/conf.py b/test/requirements/src/conf.py index df75352..40cd007 100644 --- a/test/requirements/src/conf.py +++ b/test/requirements/src/conf.py @@ -29,7 +29,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['reno.sphinxext'] +extensions = ['reno.sphinxext', 'deconstrst.deconstrst'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -208,17 +208,17 @@ # -- Options for LaTeX output --------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + # 'papersize': 'letterpaper', -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + # 'pointsize': '10pt', -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # Additional stuff for the LaTeX preamble. + # 'preamble': '', -# Latex figure (float) alignment -#'figure_align': 'htbp', + # Latex figure (float) alignment + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples diff --git a/test/requirements/src/requirements.txt b/test/requirements/src/requirements.txt index b884816..b84f587 100644 --- a/test/requirements/src/requirements.txt +++ b/test/requirements/src/requirements.txt @@ -1,17 +1,18 @@ -alabaster==0.7.7 -Babel==2.3.4 -docutils==0.12 -imagesize==0.7.1 -Jinja2==2.8 -MarkupSafe==0.23 -pbr==1.10.0 -Pygments==2.1.3 -pytz==2016.4 -PyYAML==3.11 -reno==1.6.2 -requests==2.10.0 -six==1.10.0 +alabaster==0.7.11 +Babel==2.6.0 +certifi==2018.8.24 +docutils==0.14 +imagesize==1.0.0 +Jinja2==2.10 +MarkupSafe==1.0 +pbr==4.2.0 +Pygments==2.2.0 +pytz==2018.5 +PyYAML==3.13 +reno==2.9.2 +requests==2.19.1 +six==1.11.0 snowballstemmer==1.2.1 -Sphinx==1.4.1 -sphinx-rtd-theme==0.1.9 +Sphinx==1.7.8 +sphinx_rtd_theme==0.4.1 termcolor==1.1.0 diff --git a/test/serial-explicit-toc/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial-explicit-toc%2Fone.json b/test/serial-explicit-toc/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial-explicit-toc%2Fone.json index cc4bc1f..756877a 100644 --- a/test/serial-explicit-toc/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial-explicit-toc%2Fone.json +++ b/test/serial-explicit-toc/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial-explicit-toc%2Fone.json @@ -11,9 +11,9 @@ }, "previous": { "url": "../", - "title": "Welcome to Serial TOC's documentation!" + "title": "Welcome to Serial TOC\u2019s documentation!" }, "addenda": { "repository_toc": "https://github.com/tests/serial-explicit-toc/_toc" } -} +} \ No newline at end of file diff --git a/test/serial-explicit-toc/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial-explicit-toc.json b/test/serial-explicit-toc/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial-explicit-toc.json index 93b4c44..13f05f0 100644 --- a/test/serial-explicit-toc/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial-explicit-toc.json +++ b/test/serial-explicit-toc/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial-explicit-toc.json @@ -1,6 +1,6 @@ { - "body": "
\n

Welcome to Serial TOC's documentation!

\n

No TOC here.

\n
\n
\n
\n", - "title": "Welcome to Serial TOC's documentation!", + "body": "
\n

Welcome to Serial TOC\u2019s documentation!

\n

No TOC here.

\n
\n
\n
\n", + "title": "Welcome to Serial TOC\u2019s documentation!", "meta": {}, "layout_key": "default", "asset_offsets": {}, @@ -11,4 +11,4 @@ "addenda": { "repository_toc": "https://github.com/tests/serial-explicit-toc/_toc" } -} +} \ No newline at end of file diff --git a/test/serial-explicit-toc/src/conf.py b/test/serial-explicit-toc/src/conf.py index 7d62217..bad443b 100644 --- a/test/serial-explicit-toc/src/conf.py +++ b/test/serial-explicit-toc/src/conf.py @@ -29,7 +29,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [] +extensions = ['deconstrst.deconstrst'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -208,17 +208,17 @@ # -- Options for LaTeX output --------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + # 'papersize': 'letterpaper', -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + # 'pointsize': '10pt', -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # Additional stuff for the LaTeX preamble. + # 'preamble': '', -# Latex figure (float) alignment -#'figure_align': 'htbp', + # Latex figure (float) alignment + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples diff --git a/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Fmorecategories.json b/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Fmorecategories.json index cd877b8..63ba4a0 100644 --- a/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Fmorecategories.json +++ b/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Fmorecategories.json @@ -1,6 +1,6 @@ { "title": "This page has an extra category", - "body": "
\n

This page has an extra category

\n

It should have common category in its categories once and page category as well.

\n
\n", + "body": "
\n

This page has an extra category

\n

It should have common category in its categories once and page category as well.

\n
\n", "meta": { "deconstcategories": "common category, page category" }, @@ -22,4 +22,4 @@ "addenda": { "repository_toc": "https://github.com/tests/serial/_toc" } -} +} \ No newline at end of file diff --git a/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Ftextstyles.json b/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Ftextstyles.json index 4a6c5be..f7c4685 100644 --- a/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Ftextstyles.json +++ b/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Ftextstyles.json @@ -1,6 +1,6 @@ { "title": "Demonstrating Text Styles", - "body": "
\n

Demonstrating Text Styles

\n

This line includes some italic text.

\n

This one does some bolding for more emphasis because why not.

\n

And this line uses monospaced text.

\n
\n", + "body": "
\n

Demonstrating Text Styles

\n

This line includes some italic text.

\n

This one does some bolding for more emphasis because why not.

\n

And this line uses monospaced text.

\n
\n", "meta": {}, "categories": [ "common category", @@ -13,10 +13,10 @@ "url": "../customtitle/" }, "previous": { - "title": "Welcome to Serial Builder Test's documentation!", + "title": "Welcome to Serial Builder Test\u2019s documentation!", "url": "../" }, "addenda": { "repository_toc": "https://github.com/tests/serial/_toc" } -} +} \ No newline at end of file diff --git a/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Funsearchable.json b/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Funsearchable.json index 08bf3e4..e193251 100644 --- a/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Funsearchable.json +++ b/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial%2Funsearchable.json @@ -1,6 +1,6 @@ { "title": "This page will not appear in search results", - "body": "
\n

This page will not appear in search results

\n

Because the deconstunsearchable page attribute is set to "true".

\n
\n", + "body": "
\n

This page will not appear in search results\u00b6

\n

Because the deconstunsearchable page attribute is set to \u201ctrue\u201d.

\n
\n", "meta": { "deconstunsearchable": "true" }, @@ -22,4 +22,4 @@ "addenda": { "repository_toc": "https://github.com/tests/serial/_toc" } -} +} \ No newline at end of file diff --git a/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial.json b/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial.json index f9b8ad5..83ab028 100644 --- a/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial.json +++ b/test/serial/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial.json @@ -1,6 +1,6 @@ { - "title": "Welcome to Serial Builder Test's documentation!", - "body": "
\n

Welcome to Serial Builder Test's documentation!\u00b6

\n

Contents:

\n\n
\n", + "title": "Welcome to Serial Builder Test\u2019s documentation!", + "body": "
\n

Welcome to Serial Builder Test\u2019s documentation!\u00b6

\n

Contents:

\n\n
\n", "meta": {}, "categories": [ "common category", @@ -15,4 +15,4 @@ "addenda": { "repository_toc": "https://github.com/tests/serial/_toc" } -} +} \ No newline at end of file diff --git a/test/serial/src/conf.py b/test/serial/src/conf.py index 95277f3..68166d4 100644 --- a/test/serial/src/conf.py +++ b/test/serial/src/conf.py @@ -30,7 +30,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [] +extensions = ['deconstrst.deconstrst'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -206,25 +206,25 @@ # -- Options for LaTeX output --------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + # 'papersize': 'letterpaper', -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + # 'pointsize': '10pt', -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # Additional stuff for the LaTeX preamble. + # 'preamble': '', -# Latex figure (float) alignment -#'figure_align': 'htbp', + # Latex figure (float) alignment + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'SerialBuilderTest.tex', 'Serial Builder Test Documentation', - 'Ash Wilson', 'manual'), + (master_doc, 'SerialBuilderTest.tex', 'Serial Builder Test Documentation', + 'Ash Wilson', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -267,9 +267,9 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'SerialBuilderTest', 'Serial Builder Test Documentation', - author, 'SerialBuilderTest', 'One line description of project.', - 'Miscellaneous'), + (master_doc, 'SerialBuilderTest', 'Serial Builder Test Documentation', + author, 'SerialBuilderTest', 'One line description of project.', + 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. diff --git a/test/single/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial.json b/test/single/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial.json index 42975bb..66cf028 100644 --- a/test/single/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial.json +++ b/test/single/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Fserial.json @@ -1,16 +1,16 @@ { "asset_offsets": { "somepath/bb8.jpg": [ - 2173 + 2197 ] }, "categories": [ "common category", "global category" ], - "body": "
\n

Welcome to Serial Builder Test's documentation!\u00b6

\n

Contents:

\n
\n
\n

Demonstrating Text Styles\u00b6

\n

This line includes some italic text.

\n

This one does some bolding for more emphasis because why not.

\n

And this line uses monospaced text.

\n
\n
\n

This Page Has a Custom Title\u00b6

\n

Which will do nothing, because we're using the single-page builder.

\n
\n
\n

This page has an extra category\u00b6

\n

But because we're using the single builder, it'll be ignored.

\n
\n
\n

This page will not appear in search results\u00b6

\n

Except that it will because this isn't in index.rst.

\n
\n
\n

This Page References An Asset\u00b6

\n

Ready for the asset? Here it is:

\n\"X\"\n

That sure is an image asset.

\n
\n
\n
\n", + "body": "
\n

Welcome to Serial Builder Test\u2019s documentation!\u00b6

\n

Contents:

\n
\n
\n

Demonstrating Text Styles\u00b6

\n

This line includes some italic text.

\n

This one does some bolding for more emphasis because why not.

\n

And this line uses monospaced text.

\n
\n
\n

This Page Has a Custom Title\u00b6

\n

Which will do nothing, because we\u2019re using the single-page builder.

\n
\n
\n

This page has an extra category\u00b6

\n

But because we\u2019re using the single builder, it\u2019ll be ignored.

\n
\n
\n

This page will not appear in search results\u00b6

\n

Except that it will because this isn\u2019t in index.rst.

\n
\n
\n

This Page References An Asset\u00b6

\n

Ready for the asset? Here it is:

\n\"X\"\n

That sure is an image asset.

\n
\n
\n
\n", "toc": "\n", "meta": {}, - "title": "Welcome to Serial Builder Test's documentation!", + "title": "Welcome to Serial Builder Test\u2019s documentation!", "layout_key": "default" -} +} \ No newline at end of file diff --git a/test/single/src/conf.py b/test/single/src/conf.py index c01ab13..05624ae 100644 --- a/test/single/src/conf.py +++ b/test/single/src/conf.py @@ -30,7 +30,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [] +extensions = ['deconstrst.deconstrst'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -206,25 +206,25 @@ # -- Options for LaTeX output --------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + # 'papersize': 'letterpaper', -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + # 'pointsize': '10pt', -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # Additional stuff for the LaTeX preamble. + # 'preamble': '', -# Latex figure (float) alignment -#'figure_align': 'htbp', + # Latex figure (float) alignment + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'SerialBuilderTest.tex', 'Serial Builder Test Documentation', - 'Ash Wilson', 'manual'), + (master_doc, 'SerialBuilderTest.tex', 'Serial Builder Test Documentation', + 'Ash Wilson', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -267,9 +267,9 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'SerialBuilderTest', 'Serial Builder Test Documentation', - author, 'SerialBuilderTest', 'One line description of project.', - 'Miscellaneous'), + (master_doc, 'SerialBuilderTest', 'Serial Builder Test Documentation', + author, 'SerialBuilderTest', 'One line description of project.', + 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. diff --git a/test/toc-absolute-link/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Ftoc-absolute-link%2Fpage00.json b/test/toc-absolute-link/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Ftoc-absolute-link%2Fpage00.json index 94bdf71..c5a70c1 100644 --- a/test/toc-absolute-link/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Ftoc-absolute-link%2Fpage00.json +++ b/test/toc-absolute-link/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Ftoc-absolute-link%2Fpage00.json @@ -13,7 +13,7 @@ }, "previous": { "url": "../", - "title": "Welcome to TOC Absolute Links's documentation!" + "title": "Welcome to TOC Absolute Links\u2019s documentation!" }, "asset_offsets": {} -} +} \ No newline at end of file diff --git a/test/toc-absolute-link/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Ftoc-absolute-link.json b/test/toc-absolute-link/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Ftoc-absolute-link.json index 15ddfe3..1b0d925 100644 --- a/test/toc-absolute-link/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Ftoc-absolute-link.json +++ b/test/toc-absolute-link/dest/envelopes/https%3A%2F%2Fgithub.com%2Ftests%2Ftoc-absolute-link.json @@ -1,6 +1,6 @@ { - "title": "Welcome to TOC Absolute Links's documentation!", - "body": "\n", + "title": "Welcome to TOC Absolute Links\u2019s documentation!", + "body": "\n", "addenda": { "repository_toc": "https://github.com/tests/toc-absolute-link/_toc" }, @@ -11,4 +11,4 @@ "title": "This is Page Zero" }, "asset_offsets": {} -} +} \ No newline at end of file diff --git a/test/toc-absolute-link/src/conf.py b/test/toc-absolute-link/src/conf.py index b9d04b0..3acdf99 100644 --- a/test/toc-absolute-link/src/conf.py +++ b/test/toc-absolute-link/src/conf.py @@ -29,7 +29,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [] +extensions = ['deconstrst.deconstrst'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -208,17 +208,17 @@ # -- Options for LaTeX output --------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + # 'papersize': 'letterpaper', -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + # 'pointsize': '10pt', -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # Additional stuff for the LaTeX preamble. + # 'preamble': '', -# Latex figure (float) alignment -#'figure_align': 'htbp', + # Latex figure (float) alignment + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples