Skip to content

feat: Be more lenient on errors if app.config.sphinxjs_lax is set #116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@ Configuration Reference
``jsdoc_cache``
Path to a file where jsdoc output will be cached. If omitted, jsdoc will be run every time Sphinx is. If you have a large number of source files, it may be beneficial to configure this value. But be careful: the cache is not automatically flushed if your source code changes; you must delete it manually.

``sphinx_js_lax``
If `True`, doclet conflicts and parsing errors will result in warnings instead of exceptions.
Useful when starting to use sphinx-js on an existing project where you do not want to fix
all errors upfront.

Example
=======

Expand Down
1 change: 1 addition & 0 deletions requirements_dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ recommonmark==0.4.0
# with regard to how it emits class names and em dashes from
# time to time:
Sphinx==1.7.2
mock==3.0.5
15 changes: 14 additions & 1 deletion sphinx_js/doclets.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
import subprocess
from tempfile import TemporaryFile, NamedTemporaryFile

from parsimonious.exceptions import ParseError
from six import string_types
from sphinx.errors import SphinxError
from sphinx.util.logging import getLogger

from .parsers import path_and_formal_params, PathVisitor
from .suffix_tree import PathTaken, SuffixTree
from .typedoc import parse_typedoc

logger = getLogger(__name__)


def gather_doclets(app):
"""Run JSDoc or another analysis tool across a whole codebase, and squirrel
Expand Down Expand Up @@ -46,8 +50,17 @@ def gather_doclets(app):
d)
except PathTaken as conflict:
conflicts.append(conflict.segments)
except ParseError as e:
if not app.config.sphinx_js_lax:
raise
else:
logger.warning('Could not parse path correctly %s' % e.text)
if conflicts:
raise PathsTaken(conflicts)
exception = PathsTaken(conflicts)
if not app.config.sphinx_js_lax:
raise exception
else:
logger.warning('%s' % exception)

# Build lookup table for autoclass's :members: option. This will also
# pick up members of functions (inner variables), but it will instantly
Expand Down
124 changes: 123 additions & 1 deletion tests/test_doclets.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
# -*- coding: utf-8 -*-
from os.path import abspath

try:
from unittest.mock import Mock, patch
except ImportError:
from mock import Mock, patch

import pytest
from sphinx.errors import SphinxError

from sphinx_js.doclets import doclet_full_path, root_or_fallback
from sphinx_js.doclets import doclet_full_path, root_or_fallback, gather_doclets, PathsTaken


def test_doclet_full_path():
Expand Down Expand Up @@ -34,3 +39,120 @@ def test_relative_path_root():
with pytest.raises(SphinxError):
root_or_fallback(None, ['a', 'b'])
assert root_or_fallback('smoo', ['a']) == abspath('smoo')


CONFLICTED_DOCLETS = [
{
'comment': True,
'undocumented': False,
'longname': 'best#thing~yeah',
'meta': {
'filename': 'utils.jsm',
'path': '/boogie/smoo/Checkouts/fathom'
}
},
{
'comment': True,
'undocumented': False,
'longname': 'best#thing~yeah',
'meta': {
'filename': 'utils.jsm',
'path': '/boogie/smoo/Checkouts/fathom'
}
},
{
'comment': True,
'undocumented': False,
'longname': 'best#thing~woot',
'meta': {
'filename': 'utils.jsm',
'path': '/boogie/smoo/Checkouts/fathom'
}
},
{
'comment': True,
'undocumented': False,
'longname': 'best#thing~woot',
'meta': {
'filename': 'utils.jsm',
'path': '/boogie/smoo/Checkouts/fathom'
}
}
]


def mock_analyze_jsdoc(doclets):
def analyze(source_paths, app):
return doclets
return analyze


@patch(
'sphinx_js.doclets.ANALYZERS', {
'javascript': mock_analyze_jsdoc(CONFLICTED_DOCLETS)
}
)
def test_gather_doclets_conflicted_lax():
app = Mock()
app.config.js_language = 'javascript'
app.config.js_source_path = 'source-path'
app.config.root_for_relative_js_paths = '/boogie/smoo/Checkouts/fathom'

with patch('sphinx_js.doclets.logger', Mock()) as logger_mock:
gather_doclets(app)

message, = logger_mock.warning.call_args_list[0][0]
assert './utils.best#thing~yeah' in message
assert './utils.best#thing~woot' in message


@patch(
'sphinx_js.doclets.ANALYZERS', {
'javascript': mock_analyze_jsdoc(CONFLICTED_DOCLETS)
}
)
def test_gather_doclets_conflicted():
app = Mock()
app.config.js_language = 'javascript'
app.config.js_source_path = 'source-path'
app.config.root_for_relative_js_paths = '/boogie/smoo/Checkouts/fathom'
app.config.sphinx_js_lax = False

with pytest.raises(PathsTaken) as e:
gather_doclets(app)
message = str(e.value)
assert './utils.best#thing~yeah' in message
assert './utils.best#thing~woot' in message


def test_gather_doclets_parse_error():
app = Mock()
app.config.js_language = 'javascript'
app.config.js_source_path = 'source-path'
app.config.root_for_relative_js_paths = '/boogie/smoo/Checkouts/fathom'
app.config.sphinx_js_lax = True

parse_error_doclet = {
'comment': True,
'undocumented': False,
'longname': 'best#thing~yeah',
'meta': {
'filename': 'utils.jsm',
'path': '../boogie/smoo/Checkouts/fathom'
}
}

def patch_logger():
return patch('sphinx_js.doclets.logger', Mock())

def patch_analyze():
return patch('sphinx_js.doclets.ANALYZERS', {
'javascript': mock_analyze_jsdoc([parse_error_doclet])
})

with patch_logger() as logger_mock, patch_analyze():
gather_doclets(app)

message, = logger_mock.warning.call_args_list[0][0]
assert 'Could not parse path correctly' in message
assert 'boogie/smoo/Checkouts/fathom/utils.best#thing~yeah' in message