Skip to content
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
4 changes: 4 additions & 0 deletions include/pybind11/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ class options {

options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; }


// Getter methods (return the global state):

static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; }

static bool show_function_signatures() { return global_state().show_function_signatures; }


// This type is not meant to be allocated on the heap.
void* operator new(size_t) = delete;

Expand All @@ -52,6 +54,8 @@ class options {
struct state {
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
bool show_function_signatures = true; //< Include auto-generated function signatures in docstrings.
bool type_error_print_repr = true; //< If true, if args mismatch __repr__ of argument is shown if true,
//< else __str__ is used
};

static state &global_state() {
Expand Down
12 changes: 10 additions & 2 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,12 @@ class cpp_function : public function {
for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) {
if (!some_args) some_args = true;
else msg += ", ";
msg += pybind11::repr(args_[ti]);
const std::string argRepr = pybind11::repr(args_[ti]);
if(argRepr.size() > 100){
msg += pybind11::str("{:.100} ...[truncated by pybind11]").format(argRepr);
}
else
msg += argRepr;
}
if (kwargs_in) {
auto kwargs = reinterpret_borrow<dict>(kwargs_in);
Expand All @@ -692,7 +697,10 @@ class cpp_function : public function {
for (auto kwarg : kwargs) {
if (first) first = false;
else msg += ", ";
msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second);
const std::string argRepr = pybind11::repr( kwarg.second);
if(argRepr.size()>100){
msg += pybind11::str("{}={!r:.100} ...[truncated by pybind11]").format(kwarg.first, argRepr);
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ set(PYBIND11_TEST_FILES
test_smart_ptr.cpp
test_stl_binders.cpp
test_virtual_functions.cpp
test_type_error_truncation.cpp
)

# Invoking cmake with something like:
Expand Down
45 changes: 45 additions & 0 deletions tests/test_type_error_truncation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
tests/test_type_error_truncation.cpp -- exception translation

Copyright (c) 2017 Thorsten Beier <[email protected]>

All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/

#include "pybind11_tests.h"
#include <string>


// A type that should be raised as an exeption in Python
struct TypeWithLongRepr {
TypeWithLongRepr(const uint32_t reprSize = 100)
: reprSize_(reprSize){

}
std::string repr()const{
std::string ret(reprSize_,'*');
ret[0] = '<';
ret[reprSize_-1] = '>';
return ret;
}
void foo(const TypeWithLongRepr & , const std::string )const{

}
uint32_t reprSize_;
};



test_initializer type_error_truncation([](py::module &m) {

py::class_<TypeWithLongRepr>(m, "TypeWithLongRepr")
.def(py::init<const uint32_t >())
.def("__repr__", &TypeWithLongRepr::repr)
.def("foo",&TypeWithLongRepr::foo,
py::arg("arg1"),
py::arg("arg2")
)
;

});
67 changes: 67 additions & 0 deletions tests/test_type_error_truncation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import pytest
import pybind11_tests






def test_type_error_truncation():
from pybind11_tests import TypeWithLongRepr

size_of_repr = 200
objA = TypeWithLongRepr(200)
objB = TypeWithLongRepr(50)
objC = TypeWithLongRepr(150)
reprStrA = repr(objA)
reprStrB = repr(objB)
reprStrC = repr(objC)
#print(reprStr)
assert len(reprStrA) == 200
assert len(reprStrB) == 50
assert len(reprStrC) == 150


assert reprStrA.startswith('<')
assert reprStrA.endswith('>')



with pytest.raises(TypeError) as excinfo:
objA.foo(objC, objC)
typeErrorMsg = str(excinfo.value)
print(typeErrorMsg)
assert len(typeErrorMsg) < 3 * 200
assert typeErrorMsg.contains('...[truncated by pybind11]')


with pytest.raises(TypeError) as excinfo:
objB.foo(objB, objB)
typeErrorMsg = str(excinfo.value)
print(typeErrorMsg)
assert len(typeErrorMsg) < 3 * 200
assert not typeErrorMsg.contains('...[truncated by pybind11]')





with pytest.raises(TypeError) as excinfo:
objA.foo(objC, arg2=objC)
typeErrorMsg = str(excinfo.value)
print(typeErrorMsg)
assert len(typeErrorMsg) < 3 * 200
assert typeErrorMsg.contains('...[truncated by pybind11]')


with pytest.raises(TypeError) as excinfo:
objB.foo(objB, objB)
typeErrorMsg = str(excinfo.value)
print(typeErrorMsg)
assert len(typeErrorMsg) < 3 * 200
assert not typeErrorMsg.contains('...[truncated by pybind11]')




test_type_error_truncation()