Skip to content

Commit c4cb659

Browse files
Merge pull request #65 from dambrosio/55-ignore-parse-exception-print
Adds ability to ignore parse exception console messages
2 parents f8308c4 + 71e7de0 commit c4cb659

File tree

8 files changed

+104
-14
lines changed

8 files changed

+104
-14
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ parsing_profile
44
sphinxcontrib_doxylink.egg-info/
55
dist/
66
build/
7+
examples/my_lib.tag

doc/index.rst

+7
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,13 @@ Configuration values
180180
'qtogre_doxygen.pdf': '/home/matt/qtogre/doxygen.pdf',
181181
}
182182
183+
.. confval:: doxylink_parse_error_ignore_regexes
184+
185+
A list of regular expressions that can be used to ignore specific errors reported from the parser.
186+
Default is ``[]``. This is useful if you have a lot of errors that you know are not important.
187+
For example, you may want to ignore errors related to a specific namespace.
188+
The regular expression is matched against the error message using Python's
189+
`re.search <https://docs.python.org/3/library/re.html#re.search>`_ function.
183190

184191
Bug reports
185192
-----------

examples/conf.py

+1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
doxylink = {
1111
'my_lib': (os.path.abspath('./my_lib.tag'), 'https://examples.com/'),
1212
}
13+
doxylink_parse_error_ignore_regexes = [r"DEFINE.*"]
1314

1415
master_doc = 'index'

examples/my_lib.h

+3
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,6 @@ enum Color { red, green, blue };
4646

4747
// An enum class
4848
enum class Color_c { red, green, blue };
49+
50+
// A function that triggers a warning from the parser
51+
void DEFINE_bool(show, false, "Enable visualization");

sphinxcontrib/doxylink/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
__version__ = "1.12.4"
22

3-
43
def setup(app):
54
from .doxylink import setup_doxylink_roles
65
app.add_config_value('doxylink', {}, 'env')
76
app.add_config_value('doxylink_pdf_files', {}, 'env')
7+
app.add_config_value('doxylink_parse_error_ignore_regexes',
8+
default=[], types=[str], rebuild='env')
89
app.connect('builder-inited', setup_doxylink_roles)
910

1011
return {

sphinxcontrib/doxylink/doxylink.py

+28-8
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ def is_url(str_to_validate: str) -> bool:
134134

135135
class SymbolMap:
136136
"""A SymbolMap maps symbols to Entries."""
137-
def __init__(self, xml_doc: ET.ElementTree) -> None:
138-
entries = parse_tag_file(xml_doc)
137+
def __init__(self, xml_doc: ET.ElementTree, parse_error_ignore_regexes: Optional[List[str]] = None) -> None:
138+
entries = parse_tag_file(xml_doc, parse_error_ignore_regexes)
139139

140140
# Sort the entry list for use with bisect
141141
self._entries = sorted(entries)
@@ -225,7 +225,7 @@ def __getitem__(self, item: str) -> Entry:
225225
return self._disambiguate(symbol, candidates)
226226

227227

228-
def parse_tag_file(doc: ET.ElementTree) -> List[Entry]:
228+
def parse_tag_file(doc: ET.ElementTree, parse_error_ignore_regexes: Optional[List[str]]) -> List[Entry]:
229229
"""
230230
Takes in an XML tree from a Doxygen tag file and returns a list that looks something like:
231231
@@ -290,7 +290,22 @@ def parse_tag_file(doc: ET.ElementTree) -> List[Entry]:
290290
entries.append(
291291
Entry(name=member_symbol, kind=member_kind, file=member_file, arglist=normalised_arglist))
292292
except ParseException as e:
293-
print(f'Skipping {member_kind} {member_symbol}{arglist}. Error reported from parser was: {e}')
293+
message = f'Skipping {member_kind} {member_symbol}{arglist}. Error reported from parser was: {e}'
294+
should_report = True
295+
296+
if parse_error_ignore_regexes:
297+
for pattern in parse_error_ignore_regexes:
298+
try:
299+
if re.search(pattern, message):
300+
should_report = False
301+
break
302+
except re.error:
303+
# Invalid regex pattern - ignore it
304+
continue
305+
306+
if should_report:
307+
report_warning(None, message) # Use None as env since we don't have access to it here
308+
continue
294309
else:
295310
# Put the simple things directly into the list
296311
entries.append(Entry(name=member_symbol, kind=member_kind, file=member_file, arglist=None))
@@ -303,6 +318,11 @@ def join(*args):
303318

304319

305320
def create_role(app, tag_filename, rootdir, cache_name, pdf=""):
321+
parse_error_ignore_regexes = getattr(app.config, 'doxylink_parse_error_ignore_regexes', [])
322+
323+
if parse_error_ignore_regexes:
324+
report_info(app.env, f'Using parse error ignore patterns: {", ".join(parse_error_ignore_regexes)}')
325+
306326
# Tidy up the root directory path
307327
if not rootdir.endswith(('/', '\\')):
308328
rootdir = join(rootdir, os.sep)
@@ -330,22 +350,22 @@ def _parse():
330350
if not hasattr(app.env, 'doxylink_cache'):
331351
# no cache present at all, initialise it
332352
report_info(app.env, 'No cache at all, rebuilding...')
333-
mapping = SymbolMap(_parse())
353+
mapping = SymbolMap(_parse(), parse_error_ignore_regexes)
334354
app.env.doxylink_cache = {cache_name: {'mapping': mapping, 'mtime': modification_time, 'version': __version__}}
335355
elif not app.env.doxylink_cache.get(cache_name):
336356
# Main cache is there but the specific sub-cache for this tag file is not
337357
report_info(app.env, 'Sub cache is missing, rebuilding...')
338-
mapping = SymbolMap(_parse())
358+
mapping = SymbolMap(_parse(), parse_error_ignore_regexes)
339359
app.env.doxylink_cache[cache_name] = {'mapping': mapping, 'mtime': modification_time, 'version': __version__}
340360
elif app.env.doxylink_cache[cache_name]['mtime'] < modification_time:
341361
# tag file has been modified since sub-cache creation
342362
report_info(app.env, 'Sub-cache is out of date, rebuilding...')
343-
mapping = SymbolMap(_parse())
363+
mapping = SymbolMap(_parse(), parse_error_ignore_regexes)
344364
app.env.doxylink_cache[cache_name] = {'mapping': mapping, 'mtime': modification_time}
345365
elif not app.env.doxylink_cache[cache_name].get('version') or app.env.doxylink_cache[cache_name].get('version') != __version__:
346366
# sub-cache doesn't have a version or the version doesn't match
347367
report_info(app.env, 'Sub-cache schema version doesn\'t match, rebuilding...')
348-
mapping = SymbolMap(_parse())
368+
mapping = SymbolMap(_parse(), parse_error_ignore_regexes)
349369
app.env.doxylink_cache[cache_name] = {'mapping': mapping, 'mtime': modification_time, 'version': __version__}
350370
else:
351371
# The cache is up to date

tests/test_doxylink.py

+58-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def test_file_different(examples_tag_file, symbol1, symbol2):
9090

9191
def test_parse_tag_file(examples_tag_file):
9292
tag_file = ET.parse(examples_tag_file)
93-
mapping = doxylink.parse_tag_file(tag_file)
93+
mapping = doxylink.parse_tag_file(tag_file, None)
9494

9595
def has_entry(name):
9696
"""
@@ -197,3 +197,60 @@ def test_process_configuration_warn(rootdir, pdf_filename, builder, msg):
197197
with LogCapture() as l:
198198
doxylink.process_configuration(app, 'doxygen/project.tag', rootdir, pdf_filename)
199199
l.check(('sphinx.sphinxcontrib.doxylink.doxylink', 'WARNING', msg))
200+
201+
202+
def test_parse_error_ignore_regexes():
203+
# Create a modified tag file content with problematic entries
204+
problematic_xml = """<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
205+
<tagfile>
206+
<compound kind="file">
207+
<name>test.h</name>
208+
<filename>test_8h</filename>
209+
<member kind="function">
210+
<name>foo</name>
211+
<arglist>(transform_pb2.Rotation2f a)</arglist>
212+
<anchor>1234</anchor>
213+
</member>
214+
<member kind="function">
215+
<name>bad</name>
216+
<arglist>(*int i)</arglist>
217+
<anchor>5678</anchor>
218+
</member>
219+
<member kind="function">
220+
<name>baz</name>
221+
<arglist>(int i, float f)</arglist>
222+
<anchor>9012</anchor>
223+
</member>
224+
<member kind="function">
225+
<name>unexpected</name>
226+
<arglist>(*int i)</arglist>
227+
<anchor>5678</anchor>
228+
</member>
229+
</compound>
230+
</tagfile>"""
231+
232+
# Write temporary tag file
233+
test_tag_file = 'test_temp.tag'
234+
with open(test_tag_file, 'w') as f:
235+
f.write(problematic_xml)
236+
237+
try:
238+
tag_file = ET.parse(test_tag_file)
239+
patterns = [r'kipping function test\.h::foo', r'kipping.*bad']
240+
241+
with LogCapture() as log:
242+
mapping = doxylink.parse_tag_file(tag_file, patterns)
243+
244+
# Verify that the mapping still contains valid entries
245+
assert any(entry.name.endswith('baz') for entry in mapping)
246+
247+
# Verify that messages matching our patterns were not logged
248+
assert not any('test.h::foo' in record.msg for record in log.records)
249+
assert not any('bar' in record.msg for record in log.records)
250+
251+
# Verify other error messages were logged
252+
assert any('Skipping' in record.msg for record in log.records)
253+
254+
finally:
255+
if os.path.exists(test_tag_file):
256+
os.unlink(test_tag_file)

tox.ini

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ envlist = benchmark, test, examples, doc
33
isolated_build = True
44

55
[testenv:benchmark]
6-
whitelist_externals = poetry
6+
allowlist_externals = poetry
77
commands=
88
poetry install
99
python tests/test_parser.py
1010

1111
[testenv:examples]
1212
changedir = examples
13-
whitelist_externals =
13+
allowlist_externals =
1414
doxygen
1515
poetry
1616
commands=
@@ -19,13 +19,13 @@ commands=
1919
sphinx-build -W -b html . {envtmpdir}/examples/_build
2020

2121
[testenv:test]
22-
whitelist_externals = poetry
22+
allowlist_externals = poetry
2323
commands=
2424
poetry install
2525
pytest
2626

2727
[testenv:doc]
28-
whitelist_externals = poetry
28+
allowlist_externals = poetry
2929
commands=
3030
poetry install
3131
sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees doc {envtmpdir}/linkcheck

0 commit comments

Comments
 (0)