Merge pull request #10391 from AA-Turner/jsdump

Deprecate `sphinx.util.jsdump`
This commit is contained in:
Takeshi KOMIYA 2022-05-01 15:12:57 +09:00 committed by GitHub
commit 8c7ba8aa0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 24 deletions

View File

@ -22,6 +22,11 @@ The following is a list of deprecated interfaces.
- (will be) Removed
- Alternatives
* - ``sphinx.util.jsdump``
- 5.0
- 7.0
- The standard library ``json`` module.
* - :doc:`Setuptools integration </usage/advanced/setuptools>`
- 5.0
- 7.0

View File

@ -1,7 +1,9 @@
"""Create a full-text search index for offline search."""
import html
import json
import pickle
import re
import warnings
from importlib import import_module
from os import path
from typing import IO, Any, Dict, Iterable, List, Optional, Set, Tuple, Type
@ -10,8 +12,8 @@ from docutils import nodes
from docutils.nodes import Element, Node
from sphinx import addnodes, package_dir
from sphinx.deprecation import RemovedInSphinx70Warning
from sphinx.environment import BuildEnvironment
from sphinx.util import jsdump
class SearchLanguage:
@ -154,14 +156,14 @@ class _JavaScriptIndex:
SUFFIX = ')'
def dumps(self, data: Any) -> str:
return self.PREFIX + jsdump.dumps(data) + self.SUFFIX
return self.PREFIX + json.dumps(data) + self.SUFFIX
def loads(self, s: str) -> Any:
data = s[len(self.PREFIX):-len(self.SUFFIX)]
if not data or not s.startswith(self.PREFIX) or not \
s.endswith(self.SUFFIX):
raise ValueError('invalid data')
return jsdump.loads(data)
return json.loads(data)
def dump(self, data: Any, f: IO) -> None:
f.write(self.dumps(data))
@ -224,7 +226,7 @@ class IndexBuilder:
passed to the `feed` method.
"""
formats = {
'jsdump': jsdump,
'json': json,
'pickle': pickle
}
@ -265,7 +267,11 @@ class IndexBuilder:
def load(self, stream: IO, format: Any) -> None:
"""Reconstruct from frozen data."""
if isinstance(format, str):
if format == "jsdump":
warnings.warn("format=jsdump is deprecated, use json instead",
RemovedInSphinx70Warning, stacklevel=2)
format = self.formats["json"]
elif isinstance(format, str):
format = self.formats[format]
frozen = format.load(stream)
# if an old index is present, we treat it as not existing.
@ -291,7 +297,11 @@ class IndexBuilder:
def dump(self, stream: IO, format: Any) -> None:
"""Dump the frozen index to a stream."""
if isinstance(format, str):
if format == "jsdump":
warnings.warn("format=jsdump is deprecated, use json instead",
RemovedInSphinx70Warning, stacklevel=2)
format = self.formats["json"]
elif isinstance(format, str):
format = self.formats[format]
format.dump(self.freeze(), stream)
@ -417,7 +427,7 @@ class IndexBuilder:
return {
'search_language_stemming_code': self.get_js_stemmer_code(),
'search_language_stop_words': jsdump.dumps(sorted(self.lang.stopwords)),
'search_language_stop_words': json.dumps(sorted(self.lang.stopwords)),
'search_scorer_tool': self.js_scorer_code,
'search_word_splitter_code': js_splitter_code,
}

View File

@ -4,8 +4,14 @@ Uses the basestring encode function from simplejson by Bob Ippolito.
"""
import re
import warnings
from typing import IO, Any, Dict, List, Match, Union
from sphinx.deprecation import RemovedInSphinx70Warning
warnings.warn('"sphinx.util.jsdump" has been deprecated. Please use "json" instead.',
RemovedInSphinx70Warning)
_str_re = re.compile(r'"(\\\\|\\"|[^"])*"')
_int_re = re.compile(r'\d+')
_name_re = re.compile(r'[a-zA-Z_]\w*')

View File

@ -1,5 +1,6 @@
"""Test the search index builder."""
import json
from collections import namedtuple
from io import BytesIO
@ -8,7 +9,6 @@ from docutils import frontend, utils
from docutils.parsers import rst
from sphinx.search import IndexBuilder
from sphinx.util import jsdump
DummyEnvironment = namedtuple('DummyEnvironment', ['version', 'domains'])
@ -32,12 +32,12 @@ def setup_module():
parser = rst.Parser()
def jsload(path):
def load_searchindex(path):
searchindex = path.read_text()
assert searchindex.startswith('Search.setIndex(')
assert searchindex.endswith(')')
return jsdump.loads(searchindex[16:-1])
return json.loads(searchindex[16:-1])
def is_registered_term(index, keyword):
@ -57,7 +57,7 @@ test that non-comments are indexed: fermion
@pytest.mark.sphinx(testroot='ext-viewcode')
def test_objects_are_escaped(app, status, warning):
app.builder.build_all()
index = jsload(app.outdir / 'searchindex.js')
index = load_searchindex(app.outdir / 'searchindex.js')
for item in index.get('objects').get(''):
if item[-1] == 'n::Array&lt;T, d&gt;': # n::Array<T,d> is escaped
break
@ -68,7 +68,7 @@ def test_objects_are_escaped(app, status, warning):
@pytest.mark.sphinx(testroot='search')
def test_meta_keys_are_handled_for_language_en(app, status, warning):
app.builder.build_all()
searchindex = jsload(app.outdir / 'searchindex.js')
searchindex = load_searchindex(app.outdir / 'searchindex.js')
assert not is_registered_term(searchindex, 'thisnoteith')
assert is_registered_term(searchindex, 'thisonetoo')
assert is_registered_term(searchindex, 'findthiskei')
@ -81,7 +81,7 @@ def test_meta_keys_are_handled_for_language_en(app, status, warning):
@pytest.mark.sphinx(testroot='search', confoverrides={'html_search_language': 'de'})
def test_meta_keys_are_handled_for_language_de(app, status, warning):
app.builder.build_all()
searchindex = jsload(app.outdir / 'searchindex.js')
searchindex = load_searchindex(app.outdir / 'searchindex.js')
assert not is_registered_term(searchindex, 'thisnoteith')
assert is_registered_term(searchindex, 'thisonetoo')
assert not is_registered_term(searchindex, 'findthiskei')
@ -100,7 +100,7 @@ def test_stemmer_does_not_remove_short_words(app, status, warning):
@pytest.mark.sphinx(testroot='search')
def test_stemmer(app, status, warning):
searchindex = jsload(app.outdir / 'searchindex.js')
searchindex = load_searchindex(app.outdir / 'searchindex.js')
print(searchindex)
assert is_registered_term(searchindex, 'findthisstemmedkei')
assert is_registered_term(searchindex, 'intern')
@ -112,13 +112,13 @@ def test_term_in_heading_and_section(app, status, warning):
# if search term is in the title of one doc and in the text of another
# both documents should be a hit in the search index as a title,
# respectively text hit
assert 'textinhead:2' in searchindex
assert 'textinhead:0' in searchindex
assert '"textinhead": 2' in searchindex
assert '"textinhead": 0' in searchindex
@pytest.mark.sphinx(testroot='search')
def test_term_in_raw_directive(app, status, warning):
searchindex = jsload(app.outdir / 'searchindex.js')
searchindex = load_searchindex(app.outdir / 'searchindex.js')
assert not is_registered_term(searchindex, 'raw')
assert is_registered_term(searchindex, 'rawword')
assert not is_registered_term(searchindex, 'latex_keyword')
@ -255,18 +255,17 @@ def test_IndexBuilder_lookup():
)
def test_search_index_gen_zh(app, status, warning):
app.builder.build_all()
# jsdump fails if search language is 'zh'; hence we just get the text:
searchindex = (app.outdir / 'searchindex.js').read_text()
assert 'chinesetest ' not in searchindex
assert 'chinesetest' in searchindex
assert 'chinesetesttwo' in searchindex
assert 'cas' in searchindex
index = load_searchindex(app.outdir / 'searchindex.js')
assert 'chinesetest ' not in index['terms']
assert 'chinesetest' in index['terms']
assert 'chinesetesttwo' in index['terms']
assert 'cas' in index['terms']
@pytest.mark.sphinx(testroot='search')
def test_nosearch(app):
app.build()
index = jsload(app.outdir / 'searchindex.js')
index = load_searchindex(app.outdir / 'searchindex.js')
assert index['docnames'] == ['index', 'nosearch', 'tocitem']
assert 'latex' not in index['terms']
assert 'zfs' in index['terms']