Skip to content

Commit 07d98b2

Browse files
committed
Use report_warning instead of print; don't combine regexes into a single pattern for robustness; rename config variable
1 parent f396ba7 commit 07d98b2

File tree

4 files changed

+93
-21
lines changed

4 files changed

+93
-21
lines changed

doc/index.rst

+6-2
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,13 @@ Configuration values
180180
'qtogre_doxygen.pdf': '/home/matt/qtogre/doxygen.pdf',
181181
}
182182
183-
.. confval:: doxylink_parse_exception_ignore_regex_list
183+
.. confval:: doxylink_parse_error_ignore_regexes
184184

185-
A list of regular expressions that can be used to ignore specific ``ParseException`` console messages. Default is ``[]``.
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.
186190

187191
Bug reports
188192
-----------

sphinxcontrib/doxylink/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ def setup(app):
44
from .doxylink import setup_doxylink_roles
55
app.add_config_value('doxylink', {}, 'env')
66
app.add_config_value('doxylink_pdf_files', {}, 'env')
7-
app.add_config_value('doxylink_parse_exception_ignore_regex_list',
7+
app.add_config_value('doxylink_parse_error_ignore_regexes',
88
default=[], types=[str], rebuild='env')
99
app.connect('builder-inited', setup_doxylink_roles)
1010

sphinxcontrib/doxylink/doxylink.py

+29-18
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, parse_exception_ignore_pattern: Union['re.Pattern', None] = None) -> None:
138-
entries = parse_tag_file(xml_doc, parse_exception_ignore_pattern)
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, parse_exception_ignore_pattern: Union['re.Pattern', None]) -> 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,13 +290,21 @@ def parse_tag_file(doc: ET.ElementTree, parse_exception_ignore_pattern: Union['r
290290
entries.append(
291291
Entry(name=member_symbol, kind=member_kind, file=member_file, arglist=normalised_arglist))
292292
except ParseException as e:
293-
# Check if the parse exception message matches the ignore regular expression, if it does do not print the message
294293
message = f'Skipping {member_kind} {member_symbol}{arglist}. Error reported from parser was: {e}'
295-
matched = parse_exception_ignore_pattern.match(message) if parse_exception_ignore_pattern else False
296-
297-
if not matched:
298-
print(message)
299-
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
300308
continue
301309
else:
302310
# Put the simple things directly into the list
@@ -309,12 +317,15 @@ def join(*args):
309317
return ''.join(args)
310318

311319

312-
def create_role(app, tag_filename, rootdir, cache_name, pdf=""):
313-
parse_exception_ignore_regex_list = getattr(app.config, 'doxylink_parse_exception_ignore_regex_list')
314-
parse_exception_ignore_pattern = re.compile('|'.join(parse_exception_ignore_regex_list)) if parse_exception_ignore_regex_list else None
320+
def create_role(app: 'sphinx.application.Sphinx',
321+
tag_filename: str,
322+
rootdir: str,
323+
cache_name: str,
324+
pdf: str = "") -> None:
325+
parse_error_ignore_regexes = getattr(app.config, 'doxylink_parse_error_ignore_regexes', [])
315326

316-
if parse_exception_ignore_pattern:
317-
report_info(app.env, f'Ignoring parsing exceptions using `{parse_exception_ignore_pattern}`')
327+
if parse_error_ignore_regexes:
328+
report_info(app.env, f'Using parse error ignore patterns: {", ".join(parse_error_ignore_regexes)}')
318329

319330
# Tidy up the root directory path
320331
if not rootdir.endswith(('/', '\\')):
@@ -343,22 +354,22 @@ def _parse():
343354
if not hasattr(app.env, 'doxylink_cache'):
344355
# no cache present at all, initialise it
345356
report_info(app.env, 'No cache at all, rebuilding...')
346-
mapping = SymbolMap(_parse(), parse_exception_ignore_pattern)
357+
mapping = SymbolMap(_parse(), parse_error_ignore_regexes)
347358
app.env.doxylink_cache = {cache_name: {'mapping': mapping, 'mtime': modification_time, 'version': __version__}}
348359
elif not app.env.doxylink_cache.get(cache_name):
349360
# Main cache is there but the specific sub-cache for this tag file is not
350361
report_info(app.env, 'Sub cache is missing, rebuilding...')
351-
mapping = SymbolMap(_parse(), parse_exception_ignore_pattern)
362+
mapping = SymbolMap(_parse(), parse_error_ignore_regexes)
352363
app.env.doxylink_cache[cache_name] = {'mapping': mapping, 'mtime': modification_time, 'version': __version__}
353364
elif app.env.doxylink_cache[cache_name]['mtime'] < modification_time:
354365
# tag file has been modified since sub-cache creation
355366
report_info(app.env, 'Sub-cache is out of date, rebuilding...')
356-
mapping = SymbolMap(_parse(), parse_exception_ignore_pattern)
367+
mapping = SymbolMap(_parse(), parse_error_ignore_regexes)
357368
app.env.doxylink_cache[cache_name] = {'mapping': mapping, 'mtime': modification_time}
358369
elif not app.env.doxylink_cache[cache_name].get('version') or app.env.doxylink_cache[cache_name].get('version') != __version__:
359370
# sub-cache doesn't have a version or the version doesn't match
360371
report_info(app.env, 'Sub-cache schema version doesn\'t match, rebuilding...')
361-
mapping = SymbolMap(_parse(), parse_exception_ignore_pattern)
372+
mapping = SymbolMap(_parse(), parse_error_ignore_regexes)
362373
app.env.doxylink_cache[cache_name] = {'mapping': mapping, 'mtime': modification_time, 'version': __version__}
363374
else:
364375
# The cache is up to date

tests/test_doxylink.py

+57
Original file line numberDiff line numberDiff line change
@@ -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)

0 commit comments

Comments
 (0)