From c1a70397e1b3dd3e4a4b144f8ef63f24091a24ff Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 2 Mar 2017 23:48:05 +0900 Subject: [PATCH] Add InventoryFile.dump() --- sphinx/builders/html.py | 28 ++-------------------------- sphinx/util/inventory.py | 37 +++++++++++++++++++++++++++++++++++++ tests/test_build_html.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 80f1327fd..697514718 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -31,6 +31,7 @@ from docutils.readers.doctree import Reader as DoctreeReader from sphinx import package_dir, __display_version__ from sphinx.util import jsonimpl, logging, status_iterator from sphinx.util.i18n import format_date +from sphinx.util.inventory import InventoryFile from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \ movefile, copyfile from sphinx.util.nodes import inline_all_toctrees @@ -896,33 +897,8 @@ class StandaloneHTMLBuilder(Builder): def dump_inventory(self): # type: () -> None - def safe_name(string): - return re.sub("\s+", " ", string) - logger.info(bold('dumping object inventory... '), nonl=True) - with open(path.join(self.outdir, INVENTORY_FILENAME), 'wb') as f: - f.write((u'# Sphinx inventory version 2\n' - u'# Project: %s\n' - u'# Version: %s\n' - u'# The remainder of this file is compressed using zlib.\n' - % (safe_name(self.config.project), - safe_name(self.config.version))).encode('utf-8')) - compressor = zlib.compressobj(9) - for domainname, domain in sorted(self.env.domains.items()): - for name, dispname, type, docname, anchor, prio in \ - sorted(domain.get_objects()): - if anchor.endswith(name): - # this can shorten the inventory by as much as 25% - anchor = anchor[:-len(name)] + '$' - uri = self.get_target_uri(docname) - if anchor: - uri += '#' + anchor - if dispname == name: - dispname = u'-' - f.write(compressor.compress( - (u'%s %s:%s %s %s %s\n' % (name, domainname, type, - prio, uri, dispname)).encode('utf-8'))) - f.write(compressor.flush()) + InventoryFile.dump(path.join(self.outdir, INVENTORY_FILENAME), self.env, self) logger.info('done') def dump_search_index(self): diff --git a/sphinx/util/inventory.py b/sphinx/util/inventory.py index 9c79f47ab..a74a74964 100644 --- a/sphinx/util/inventory.py +++ b/sphinx/util/inventory.py @@ -9,11 +9,14 @@ :license: BSD, see LICENSE for details. """ import re +import os import zlib import codecs from six import PY3 +from sphinx.util import logging + if False: # For type annotation from typing import Callable, Dict, IO, Iterator, Tuple # NOQA @@ -27,6 +30,8 @@ if False: BUFSIZE = 16 * 1024 UTF8StreamReader = codecs.lookup('utf-8')[2] +logger = logging.getLogger(__name__) + class ZlibReader(object): """Compressed file reader.""" @@ -121,3 +126,35 @@ class InventoryFile(object): invdata.setdefault(type, {})[name] = (projname, version, location, dispname) return invdata + + @classmethod + def dump(cls, filename, env, builder): + # type: (unicode, BuildEnvironment, Builder) -> None + def escape(string): + # type: (unicode) -> unicode + return re.sub("\s+", " ", string).encode('utf-8') + + with open(os.path.join(filename), 'wb') as f: + # header + f.write('# Sphinx inventory version 2\n') + f.write('# Project: %s\n' % escape(env.config.project)) + f.write('# Version: %s\n' % escape(env.config.version)) + f.write('# The remainder of this file is compressed using zlib.\n') + + # body + compressor = zlib.compressobj(9) + for domainname, domain in sorted(env.domains.items()): + for name, dispname, typ, docname, anchor, prio in \ + sorted(domain.get_objects()): + if anchor.endswith(name): + # this can shorten the inventory by as much as 25% + anchor = anchor[:-len(name)] + '$' + uri = builder.get_target_uri(docname) + if anchor: + uri += '#' + anchor + if dispname == name: + dispname = u'-' + entry = (u'%s %s:%s %s %s %s\n' % + (name, domainname, typ, prio, uri, dispname)) + f.write(compressor.compress(entry.encode('utf-8'))) + f.write(compressor.flush()) diff --git a/tests/test_build_html.py b/tests/test_build_html.py index ab228c13c..68442bd3f 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -16,6 +16,8 @@ from itertools import cycle, chain from six import PY3 from sphinx import __display_version__ +from sphinx.util.inventory import InventoryFile + from util import remove_unicode_literals, strip_escseq import xml.etree.cElementTree as ElementTree from html5lib import getTreeBuilder, HTMLParser @@ -1149,3 +1151,29 @@ def test_html_entity(app): content = (app.outdir / 'index.html').text() for entity in re.findall(r'&([a-z]+);', content, re.M): assert entity not in valid_entities + + +@pytest.mark.sphinx('html', testroot='basic') +def test_html_inventory(app): + app.builder.build_all() + with open(app.outdir / 'objects.inv') as f: + invdata = InventoryFile.load(f, 'http://example.com', os.path.join) + assert invdata.keys() == ['std:label', 'std:doc'] + assert invdata['std:label'].keys() == ['modindex', 'genindex', 'search'] + assert invdata['std:label']['modindex'] == ('Python', + '', + 'http://example.com/py-modindex.html', + 'Module Index') + assert invdata['std:label']['genindex'] == ('Python', + '', + 'http://example.com/genindex.html', + 'Index') + assert invdata['std:label']['search'] == ('Python', + '', + 'http://example.com/search.html', + 'Search Page') + assert invdata['std:doc'].keys() == ['index'] + assert invdata['std:doc']['index'] == ('Python', + '', + 'http://example.com/index.html', + 'The basic Sphinx documentation for testing')