Skip to content

Commit 9cc0bb6

Browse files
authored
fix "no constructor defined" messages on PyPy (#5329)
* fix "cannot create '%s' instances" message to match CPython * don't use unlimited C API directly * review feedback * fixup * fixup xfail on PyPy
1 parent 9aa53f4 commit 9cc0bb6

File tree

2 files changed

+15
-30
lines changed

2 files changed

+15
-30
lines changed

pytests/tests/test_pyclasses.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ def __new__(cls):
9696

9797

9898
@pytest.mark.xfail(
99-
platform.python_implementation() == "PyPy" and sys.version_info < (3, 11),
100-
reason="broken on older PyPy due to https://github.com/pypy/pypy/issues/5319 on supported PyPy",
99+
platform.python_implementation() == "PyPy" and sys.version_info[:2] == (3, 11),
100+
reason="broken on PyPy 3.11 due to https://github.com/pypy/pypy/issues/5319, waiting for next release",
101101
)
102102
@pytest.mark.parametrize(
103103
"cls, exc_message",

src/pyclass/create_type_object.rs

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -437,14 +437,13 @@ impl PyTypeBuilder {
437437
unsafe { self.push_slot(ffi::Py_tp_base, self.tp_base) }
438438

439439
if !self.has_new {
440-
// PyPy doesn't respect the flag
441-
// https://github.com/pypy/pypy/issues/5318
442-
#[cfg(not(all(Py_3_10, not(PyPy))))]
440+
// Flag introduced in 3.10, only worked in PyPy on 3.11
441+
#[cfg(not(any(all(Py_3_10, not(PyPy)), all(Py_3_11, PyPy))))]
443442
{
444443
// Safety: This is the correct slot type for Py_tp_new
445444
unsafe { self.push_slot(ffi::Py_tp_new, no_constructor_defined as *mut c_void) }
446445
}
447-
#[cfg(all(Py_3_10, not(PyPy)))]
446+
#[cfg(any(all(Py_3_10, not(PyPy)), all(Py_3_11, PyPy)))]
448447
{
449448
self.class_flags |= ffi::Py_TPFLAGS_DISALLOW_INSTANTIATION;
450449
}
@@ -558,7 +557,7 @@ fn bpo_45315_workaround(py: Python<'_>, class_name: CString) {
558557
}
559558

560559
/// Default new implementation
561-
#[cfg(not(all(Py_3_10, not(PyPy))))]
560+
#[cfg(not(any(all(Py_3_10, not(PyPy)), all(Py_3_11, PyPy))))]
562561
unsafe extern "C" fn no_constructor_defined(
563562
subtype: *mut ffi::PyTypeObject,
564563
_args: *mut ffi::PyObject,
@@ -567,29 +566,15 @@ unsafe extern "C" fn no_constructor_defined(
567566
unsafe {
568567
trampoline(|py| {
569568
let tpobj = PyType::from_borrowed_type_ptr(py, subtype);
570-
#[cfg(not(PyPy))]
571-
{
572-
// unlike `fully_qualified_name`, this always include the module
573-
let module = tpobj
574-
.module()
575-
.map_or_else(|_| "<unknown>".into(), |s| s.to_string());
576-
let qualname = tpobj.qualname();
577-
let qualname = qualname.map_or_else(|_| "<unknown>".into(), |s| s.to_string());
578-
Err(crate::exceptions::PyTypeError::new_err(format!(
579-
"cannot create '{module}.{qualname}' instances"
580-
)))
581-
}
582-
#[cfg(PyPy)]
583-
{
584-
// https://github.com/pypy/pypy/issues/5319
585-
// .qualname() seems wrong on PyPy, includes the module already
586-
let full_name = tpobj
587-
.qualname()
588-
.map_or_else(|_| "<unknown>".into(), |s| s.to_string());
589-
Err(crate::exceptions::PyTypeError::new_err(format!(
590-
"cannot create '{full_name}' instances"
591-
)))
592-
}
569+
// unlike `fully_qualified_name`, this always include the module
570+
let module = tpobj
571+
.module()
572+
.map_or_else(|_| "<unknown>".into(), |s| s.to_string());
573+
let qualname = tpobj.qualname();
574+
let qualname = qualname.map_or_else(|_| "<unknown>".into(), |s| s.to_string());
575+
Err(crate::exceptions::PyTypeError::new_err(format!(
576+
"cannot create '{module}.{qualname}' instances"
577+
)))
593578
})
594579
}
595580
}

0 commit comments

Comments
 (0)