Skip to content

Commit 194e8f5

Browse files
authored
Show function name in error message (#165)
Closes #164
1 parent 109c839 commit 194e8f5

File tree

4 files changed

+102
-22
lines changed

4 files changed

+102
-22
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ jobs:
8686
path: "./tests/stubs/python-${{ matrix.python }}/pybind11-${{ matrix.pybind11-branch }}.patch"
8787
retention-days: 30
8888
if-no-files-found: ignore
89+
90+
- name: Check error generation
91+
if: ${{ !contains(fromJson('["3.7", "3.8"]'), matrix.python) }}
92+
shell: bash
93+
run: ./tests/check-demo-errors-generation.sh
94+
8995
test-cli-options:
9096
name: "Runs on 🐍 ${{ matrix.python }} • ${{ matrix.test-package }}"
9197
runs-on: ubuntu-latest

pybind11_stubgen/parser/mixins/error_handlers.py

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,45 +12,59 @@
1212
ParserError,
1313
)
1414
from pybind11_stubgen.parser.interface import IParser
15-
from pybind11_stubgen.structs import Class, Module, QualifiedName
15+
from pybind11_stubgen.structs import Class, Function, Method, Module, QualifiedName
16+
17+
18+
class LocalErrors:
19+
def __init__(self, path: QualifiedName, errors: set[str], stack: list[LocalErrors]):
20+
self.path: QualifiedName = path
21+
self.errors: set[str] = errors
22+
self._stack: list[LocalErrors] = stack
23+
24+
def __enter__(self) -> LocalErrors:
25+
self._stack.append(self)
26+
return self
27+
28+
def __exit__(self, exc_type, exc_val, exc_tb):
29+
top = self._stack.pop()
30+
assert top == self
1631

1732

1833
class LoggerData(IParser):
1934
def __init__(self):
2035
super().__init__()
21-
self._seen_errors: set[str] = set()
22-
self.__current_path: QualifiedName | None = None
36+
self.stack: list[LocalErrors] = []
37+
38+
def __new_layer(self, path: QualifiedName) -> LocalErrors:
39+
return LocalErrors(path, errors=set(), stack=self.stack)
2340

2441
def handle_module(
2542
self, path: QualifiedName, module: types.ModuleType
2643
) -> Module | None:
27-
old_errors = self._seen_errors
28-
old_module = self.__current_path
29-
self._seen_errors = set()
30-
self.__current_path = path
31-
result = super().handle_module(path, module)
32-
self._seen_errors = old_errors
33-
self.__current_path = old_module
34-
return result
44+
with self.__new_layer(path):
45+
return super().handle_module(path, module)
3546

3647
def handle_class(self, path: QualifiedName, class_: type) -> Class | None:
37-
old_errors = self._seen_errors
38-
old_module = self.__current_path
39-
self._seen_errors = set()
40-
self.__current_path = path
41-
result = super().handle_class(path, class_)
42-
self._seen_errors = old_errors
43-
self.__current_path = old_module
44-
return result
48+
with self.__new_layer(path):
49+
return super().handle_class(path, class_)
50+
51+
def handle_function(self, path: QualifiedName, class_: type) -> list[Function]:
52+
with self.__new_layer(path):
53+
return super().handle_function(path, class_)
54+
55+
def handle_method(self, path: QualifiedName, class_: type) -> list[Method]:
56+
with self.__new_layer(path):
57+
return super().handle_method(path, class_)
4558

4659
@property
4760
def current_path(self) -> QualifiedName:
48-
assert self.__current_path is not None
49-
return self.__current_path
61+
assert len(self.stack) != 0
62+
return self.stack[-1].path
5063

5164
@property
5265
def reported_errors(self) -> set[str]:
53-
return self._seen_errors
66+
assert len(self.stack) != 0
67+
return self.stack[-1].errors
5468

5569

5670
logger = getLogger("pybind11_stubgen")
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
TESTS_ROOT="$(readlink -m "$(dirname "$0")")"
6+
DEMO_ERRORS_FILE="${TESTS_ROOT}/demo.errors.stderr.txt"
7+
STUBS_DIR="/tmp/out" # Stubs should never be actually written
8+
9+
remove_demo_errors() {
10+
rm -rf "${DEMO_ERRORS_FILE}";
11+
}
12+
13+
check_error_messages() {
14+
(
15+
set -o pipefail ;
16+
git diff --exit-code HEAD -- "${DEMO_ERRORS_FILE}";
17+
)
18+
}
19+
run_stubgen() {
20+
(
21+
set +e ;
22+
pybind11-stubgen \
23+
demo \
24+
--output-dir=${STUBS_DIR} \
25+
--exit-code \
26+
2> "${DEMO_ERRORS_FILE}" \
27+
|| exit 0
28+
) || (
29+
echo "'pybind11-stubgen demo --exit-code' did not exit with code 1"
30+
exit 1
31+
)
32+
}
33+
34+
remove_randomness_in_errors (){
35+
sed -i 's/0x[0-9a-f]*/0x1234abcd5678/gi' "${DEMO_ERRORS_FILE}"
36+
}
37+
38+
main () {
39+
remove_demo_errors
40+
run_stubgen
41+
remove_randomness_in_errors
42+
check_error_messages
43+
}
44+
45+
main "$@"

tests/demo.errors.stderr.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
pybind11_stubgen - [ ERROR] In demo._bindings.aliases.foreign_enum_default : Invalid expression '<ConsoleForegroundColor.Blue: 34>'
2+
pybind11_stubgen - [ ERROR] In demo._bindings.enum.accept_defaulted_enum : Invalid expression '<ConsoleForegroundColor.None_: -1>'
3+
pybind11_stubgen - [ ERROR] In demo._bindings.flawed_bindings.accept_unbound_enum : Invalid expression '(anonymous namespace)::Enum'
4+
pybind11_stubgen - [ ERROR] In demo._bindings.flawed_bindings.accept_unbound_enum_defaulted : Invalid expression '<demo._bindings.flawed_bindings.Enum object at 0x1234abcd5678>'
5+
pybind11_stubgen - [ ERROR] In demo._bindings.flawed_bindings.accept_unbound_type : Invalid expression '(anonymous namespace)::Unbound'
6+
pybind11_stubgen - [ ERROR] In demo._bindings.flawed_bindings.accept_unbound_type_defaulted : Invalid expression '<demo._bindings.flawed_bindings.Unbound object at 0x1234abcd5678>'
7+
pybind11_stubgen - [ ERROR] In demo._bindings.flawed_bindings.get_unbound_type : Invalid expression '(anonymous namespace)::Unbound'
8+
pybind11_stubgen - [WARNING] Enum-like str representations were found with no matching mapping to the enum class location.
9+
Use `--enum-class-locations` to specify full path to the following enum(s):
10+
- ConsoleForegroundColor
11+
pybind11_stubgen - [WARNING] Raw C++ types/values were found in signatures extracted from docstrings.
12+
Please check the corresponding sections of pybind11 documentation to avoid common mistakes in binding code:
13+
- https://pybind11.readthedocs.io/en/latest/advanced/misc.html#avoiding-cpp-types-in-docstrings
14+
- https://pybind11.readthedocs.io/en/latest/advanced/functions.html#default-arguments-revisited
15+
pybind11_stubgen - [ INFO] Terminating due to previous errors

0 commit comments

Comments
 (0)