Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pybind11
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
pybind11
Commits
1b0bf352
Unverified
Commit
1b0bf352
authored
Jul 07, 2020
by
Dustin Spicuzza
Committed by
GitHub
Jul 07, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Throw TypeError when subclasses forget to call __init__ (#2152)
- Fixes #2103
parent
d54d6d8c
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
53 additions
and
0 deletions
+53
-0
docs/advanced/classes.rst
+5
-0
include/pybind11/detail/class.h
+27
-0
tests/test_class.py
+21
-0
No files found.
docs/advanced/classes.rst
View file @
1b0bf352
...
...
@@ -149,6 +149,11 @@ memory for the C++ portion of the instance will be left uninitialized, which
will generally leave the C++ instance in an invalid state and cause undefined
behavior if the C++ instance is subsequently used.
.. versionadded:: 2.5.1
The default pybind11 metaclass will throw a ``TypeError`` when it detects
that ``__init__`` was not called by a derived class.
Here is an example:
.. code-block:: python
...
...
include/pybind11/detail/class.h
View file @
1b0bf352
...
...
@@ -156,6 +156,31 @@ extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name
}
#endif
/// metaclass `__call__` function that is used to create all pybind11 objects.
extern
"C"
inline
PyObject
*
pybind11_meta_call
(
PyObject
*
type
,
PyObject
*
args
,
PyObject
*
kwargs
)
{
// use the default metaclass call to create/initialize the object
PyObject
*
self
=
PyType_Type
.
tp_call
(
type
,
args
,
kwargs
);
if
(
self
==
nullptr
)
{
return
nullptr
;
}
// This must be a pybind11 instance
auto
instance
=
reinterpret_cast
<
detail
::
instance
*>
(
self
);
// Ensure that the base __init__ function(s) were called
for
(
auto
vh
:
values_and_holders
(
instance
))
{
if
(
!
vh
.
holder_constructed
())
{
PyErr_Format
(
PyExc_TypeError
,
"%.200s.__init__() must be called when overriding __init__"
,
vh
.
type
->
type
->
tp_name
);
Py_DECREF
(
self
);
return
nullptr
;
}
}
return
self
;
}
/** This metaclass is assigned by default to all pybind11 types and is required in order
for static properties to function correctly. Users may override this using `py::metaclass`.
Return value: New reference. */
...
...
@@ -181,6 +206,8 @@ inline PyTypeObject* make_default_metaclass() {
type
->
tp_base
=
type_incref
(
&
PyType_Type
);
type
->
tp_flags
=
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_BASETYPE
|
Py_TPFLAGS_HEAPTYPE
;
type
->
tp_call
=
pybind11_meta_call
;
type
->
tp_setattro
=
pybind11_meta_setattro
;
#if PY_MAJOR_VERSION >= 3
type
->
tp_getattro
=
pybind11_meta_getattro
;
...
...
tests/test_class.py
View file @
1b0bf352
...
...
@@ -101,6 +101,27 @@ def test_inheritance(msg):
assert
"No constructor defined!"
in
str
(
excinfo
.
value
)
def
test_inheritance_init
(
msg
):
# Single base
class
Python
(
m
.
Pet
):
def
__init__
(
self
):
pass
with
pytest
.
raises
(
TypeError
)
as
exc_info
:
Python
()
assert
msg
(
exc_info
.
value
)
==
"m.class_.Pet.__init__() must be called when overriding __init__"
# Multiple bases
class
RabbitHamster
(
m
.
Rabbit
,
m
.
Hamster
):
def
__init__
(
self
):
m
.
Rabbit
.
__init__
(
self
,
"RabbitHamster"
)
with
pytest
.
raises
(
TypeError
)
as
exc_info
:
RabbitHamster
()
expected
=
"m.class_.Hamster.__init__() must be called when overriding __init__"
assert
msg
(
exc_info
.
value
)
==
expected
def
test_automatic_upcasting
():
assert
type
(
m
.
return_class_1
())
.
__name__
==
"DerivedClass1"
assert
type
(
m
.
return_class_2
())
.
__name__
==
"DerivedClass2"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment