From: Vladimír Vondruš Date: Mon, 3 Jan 2022 16:42:57 +0000 (+0100) Subject: documentation/python: don't try to parse pybind objects as enums. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~cjwatson/git?a=commitdiff_plain;h=81399b9bcddc05a2b4c339e65b60da9683d359af;p=blog.git documentation/python: don't try to parse pybind objects as enums. Followup to c6707e1c85a46e8848ebca077ec60eeb27eb5aab, forgot to test on a real-world codebase early enough. And then of course forgot to handle a corner case when accounting for that real-world scenario. --- diff --git a/documentation/python.py b/documentation/python.py index 0955da75..c3b059e8 100755 --- a/documentation/python.py +++ b/documentation/python.py @@ -822,16 +822,15 @@ def _pybind11_extract_default_argument(string): # everything until the colon and discard the rest. It can however be a # part of a rogue C++ type name, so pick the < only if directly at the # start or after a space or bracket, and the > only if at the end - # again. - if c == '<' and (i == 0 or string[i - 1] in [' ', '(', '[']): - name_end = string.find(':', i) - if name_end == -1: - raise SyntaxError("Enum expected to have a value: `{}`".format(string)) + # again. Also ignore stuff like -- a : has to + # be before a >. Ugh maybe I should just use a regex here. + if c == '<' and (i == 0 or string[i - 1] in [' ', '(', '[']) and -1 < string.find(':', i + 1) < string.find('>', i + 1): + name_end = string.index(':', i + 1) default += string[i + 1:name_end] - i = string.find('>', name_end + 1) + 1 + i = string.index('>', name_end + 1) + 1 - if i == -1 or (i < len(string) and string[i] not in [',', ')', ']']): + if i < len(string) and string[i] not in [',', ')', ']']: raise SyntaxError("Unexpected content after enum value: `{}`".format(string[i:])) continue diff --git a/documentation/test_python/test_pybind.py b/documentation/test_python/test_pybind.py index 47574ca8..e8dfe967 100644 --- a/documentation/test_python/test_pybind.py +++ b/documentation/test_python/test_pybind.py @@ -244,12 +244,26 @@ class Signature(unittest.TestCase): ('a', 'Enum', 'Enum', 'Enum_MISSING_DOT') ], None, None)) + # This is how pybind prints various objects, should be passed as-is. + # It should not corrupt any parameters after. + self.assertEqual(parse_pybind_signature(self.state, [], + 'foo(a: FooBar = , b: int = 3)'), + ('foo', '', [ + ('a', 'FooBar', 'FooBar', ''), + ('b', 'int', 'int', '3') + ], None, None)) + + # This is weird and so will be passed as-is. + self.assertEqual(parse_pybind_signature(self.state, [], + 'foo(a: Enum = )'), bad_signature) - self.assertEqual(parse_pybind_signature(self.state, [], 'foo(a: Enum = a)'), bad_signature) - self.assertEqual(parse_pybind_signature(self.state, [], 'foo(a: Enum = <)'), bad_signature) + self.assertEqual(parse_pybind_signature(self.state, [], 'foo(a: Enum = a)'), bad_signature) + self.assertEqual(parse_pybind_signature(self.state, [], 'foo(a: Enum = <)'), bad_signature) def test_bad_return_type(self): bad_signature = ('foo', '', [('…', None, None, None)], None, None)