Skip to content

Commit

Permalink
mention type name in "no constructor defined" message (#4481)
Browse files Browse the repository at this point in the history
fixes #4470
  • Loading branch information
birkenfeld committed Aug 24, 2024
1 parent 44c16ec commit ff1b5c4
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 10 deletions.
1 change: 1 addition & 0 deletions newsfragments/4481.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Mention the type name in the exception message when trying to instantiate a class with no constructor defined.
12 changes: 7 additions & 5 deletions pytests/tests/test_pyclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,26 @@ def test_new_classmethod():
_ = AssertingSubClass(expected_type=str)


class ClassWithoutConstructorPy:
class ClassWithoutConstructor:
def __new__(cls):
raise TypeError("No constructor defined")
raise TypeError("No constructor defined for ClassWithoutConstructor")


@pytest.mark.parametrize(
"cls", [pyclasses.ClassWithoutConstructor, ClassWithoutConstructorPy]
"cls", [pyclasses.ClassWithoutConstructor, ClassWithoutConstructor]
)
def test_no_constructor_defined_propagates_cause(cls: Type):
original_error = ValueError("Original message")
with pytest.raises(Exception) as exc_info:
try:
raise original_error
except Exception:
cls() # should raise TypeError("No constructor defined")
cls() # should raise TypeError("No constructor defined for ...")

assert exc_info.type is TypeError
assert exc_info.value.args == ("No constructor defined",)
assert exc_info.value.args == (
"No constructor defined for ClassWithoutConstructor",
)
assert exc_info.value.__context__ is original_error


Expand Down
15 changes: 10 additions & 5 deletions src/pyclass/create_type_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,14 +524,19 @@ fn bpo_45315_workaround(py: Python<'_>, class_name: CString) {

/// Default new implementation
unsafe extern "C" fn no_constructor_defined(
_subtype: *mut ffi::PyTypeObject,
subtype: *mut ffi::PyTypeObject,
_args: *mut ffi::PyObject,
_kwds: *mut ffi::PyObject,
) -> *mut ffi::PyObject {
trampoline(|_| {
Err(crate::exceptions::PyTypeError::new_err(
"No constructor defined",
))
trampoline(|py| {
let tpobj = PyType::from_borrowed_type_ptr(py, subtype);
let name = tpobj
.name()
.map_or_else(|_| "<unknown>".into(), |name| name.to_string());
Err(crate::exceptions::PyTypeError::new_err(format!(
"No constructor defined for {}",
name
)))
})
}

Expand Down

0 comments on commit ff1b5c4

Please sign in to comment.