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
678d787c
Commit
678d787c
authored
Jan 17, 2016
by
Wenzel Jakob
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
do more work with classes from pytypes.h (especially for STL container casting)
parent
d561cb01
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
124 additions
and
101 deletions
+124
-101
README.md
+7
-7
docs/intro.rst
+7
-7
example/example4.ref
+1
-1
example/run_test.py
+2
-0
include/pybind11/common.h
+3
-0
include/pybind11/pybind11.h
+16
-19
include/pybind11/pytypes.h
+50
-26
include/pybind11/stl.h
+28
-32
include/pybind11/typeid.h
+2
-1
setup.py
+8
-8
No files found.
README.md
View file @
678d787c
...
...
@@ -22,13 +22,13 @@ C++11-compatible compilers are widely available, this heavy machinery has
become an excessively large and unnecessary dependency.
Think of this library as a tiny self-contained version of Boost.Python with
everything stripped away that isn't relevant for binding generation.
The core
header files only require ~2.5K lines of code and depend on Python (2.7 or 3.x)
and the C++ standard library. This compact implementation was possible thanks
to some of the new C++11 language features (specifically: tuples, lambda
functions and variadic templates). Since its creation, this library has grown
beyond Boost.Python in many ways, leading to dramatically simpler binding code
in many common situations.
everything stripped away that isn't relevant for binding generation.
Without
comments, the core header files only require ~2.5K lines of code and depend on
Python (2.7 or 3.x) and the C++ standard library. This compact implementation
was possible thanks to some of the new C++11 language features (specifically:
tuples, lambda functions and variadic templates). Since its creation, this
library has grown beyond Boost.Python in many ways, leading to dramatically
simpler binding code
in many common situations.
Tutorial and reference documentation is provided at
[
http://pybind11.readthedocs.org/en/latest
](
http://pybind11.readthedocs.org/en/latest
)
.
...
...
docs/intro.rst
View file @
678d787c
...
...
@@ -19,13 +19,13 @@ C++11-compatible compilers are widely available, this heavy machinery has
become an excessively large and unnecessary dependency.
Think of this library as a tiny self-contained version of Boost.Python with
everything stripped away that isn't relevant for binding generation.
The core
header files only require ~2.5K lines of code and depend on Python (2.7 or 3.x)
and the C++ standard library. This compact implementation was possible thanks
to some of the new C++11 language features (specifically: tuples, lambda
functions and variadic templates). Since its creation, this library has grown
beyond Boost.Python in many ways, leading to dramatically simpler binding code
in many common situations.
everything stripped away that isn't relevant for binding generation.
Without
comments, the core header files only require ~2.5K lines of code and depend on
Python (2.7 or 3.x) and the C++ standard library. This compact implementation
was possible thanks to some of the new C++11 language features (specifically:
tuples, lambda functions and variadic templates). Since its creation, this
library has grown beyond Boost.Python in many ways, leading to dramatically
simpler binding code
in many common situations.
Core features
*************
...
...
example/example4.ref
View file @
678d787c
...
...
@@ -10,7 +10,7 @@ test_function(enum=1)
None
test_function(enum=2)
None
<class '
Example4
.EMode'>
<class '
example
.EMode'>
EMode.EFirstMode
EMode.EFirstMode
Example4::test_function(enum=1)
...
...
example/run_test.py
View file @
678d787c
...
...
@@ -22,6 +22,8 @@ def sanitize(lines):
line
=
line
.
replace
(
'__builtin__'
,
'builtins'
)
line
=
line
.
replace
(
'example.'
,
''
)
line
=
line
.
replace
(
'unicode'
,
'str'
)
line
=
line
.
replace
(
'Example4.EMode'
,
'EMode'
)
line
=
line
.
replace
(
'example.EMode'
,
'EMode'
)
line
=
line
.
replace
(
'method of builtins.PyCapsule instance'
,
''
)
line
=
line
.
strip
()
if
sys
.
platform
==
'win32'
:
...
...
include/pybind11/common.h
View file @
678d787c
...
...
@@ -271,4 +271,7 @@ struct error_already_set : public std::runtime_error { public: error_already_set
/// Thrown when pybind11::cast or handle::call fail due to a type casting error
struct
cast_error
:
public
std
::
runtime_error
{
public
:
cast_error
(
const
std
::
string
&
w
=
""
)
:
std
::
runtime_error
(
w
)
{}
};
PYBIND11_NOINLINE
inline
void
pybind11_fail
(
const
char
*
reason
)
{
throw
std
::
runtime_error
(
reason
);
}
PYBIND11_NOINLINE
inline
void
pybind11_fail
(
const
std
::
string
&
reason
)
{
throw
std
::
runtime_error
(
reason
);
}
NAMESPACE_END
(
pybind11
)
include/pybind11/pybind11.h
View file @
678d787c
...
...
@@ -24,7 +24,6 @@
#endif
#include "cast.h"
#include <iostream>
NAMESPACE_BEGIN
(
pybind11
)
...
...
@@ -196,7 +195,7 @@ protected:
a
.
value
,
return_value_policy
::
automatic
,
nullptr
);
if
(
obj
==
nullptr
)
throw
std
::
runtime_error
(
"arg(): could not convert default keyword "
pybind11_fail
(
"arg(): could not convert default keyword "
"argument into a Python object (type not "
"registered yet?)"
);
...
...
@@ -490,7 +489,7 @@ protected:
}
else
if
(
c
==
'%'
)
{
const
std
::
type_info
*
t
=
types
[
type_index
++
];
if
(
!
t
)
throw
std
::
runtime_error
(
"Internal error while parsing type signature (1)"
);
pybind11_fail
(
"Internal error while parsing type signature (1)"
);
auto
it
=
registered_types
.
find
(
t
);
if
(
it
!=
registered_types
.
end
())
{
signature
+=
((
const
detail
::
type_info
*
)
it
->
second
)
->
type
->
tp_name
;
...
...
@@ -504,7 +503,7 @@ protected:
}
}
if
(
type_depth
!=
0
||
types
[
type_index
]
!=
nullptr
)
throw
std
::
runtime_error
(
"Internal error while parsing type signature (2)"
);
pybind11_fail
(
"Internal error while parsing type signature (2)"
);
#if !defined(PYBIND11_CPP14)
delete
[]
types
;
...
...
@@ -519,7 +518,7 @@ protected:
#endif
if
(
!
m_entry
->
args
.
empty
()
&&
(
int
)
m_entry
->
args
.
size
()
!=
args
)
throw
std
::
runtime_error
(
pybind11_fail
(
"cpp_function(): function
\"
"
+
std
::
string
(
m_entry
->
name
)
+
"
\"
takes "
+
std
::
to_string
(
args
)
+
" arguments, but "
+
std
::
to_string
(
m_entry
->
args
.
size
())
+
" pybind11::arg entries were specified!"
);
...
...
@@ -555,7 +554,7 @@ protected:
});
m_ptr
=
PyCFunction_New
(
m_entry
->
def
,
entry_capsule
.
ptr
());
if
(
!
m_ptr
)
throw
std
::
runtime_error
(
"cpp_function::cpp_function(): Could not allocate function object"
);
pybind11_fail
(
"cpp_function::cpp_function(): Could not allocate function object"
);
}
else
{
/* Append at the end of the overload chain */
m_ptr
=
m_entry
->
sibling
;
...
...
@@ -597,7 +596,7 @@ protected:
m_ptr
=
PyMethod_New
(
m_ptr
,
nullptr
,
entry
->
class_
);
#endif
if
(
!
m_ptr
)
throw
std
::
runtime_error
(
"cpp_function::cpp_function(): Could not allocate instance method object"
);
pybind11_fail
(
"cpp_function::cpp_function(): Could not allocate instance method object"
);
Py_DECREF
(
func
);
}
}
...
...
@@ -621,7 +620,7 @@ public:
m_ptr
=
Py_InitModule3
(
name
,
nullptr
,
doc
);
#endif
if
(
m_ptr
==
nullptr
)
throw
std
::
runtime_error
(
"Internal error in module::module()"
);
pybind11_fail
(
"Internal error in module::module()"
);
inc_ref
();
}
...
...
@@ -647,7 +646,7 @@ public:
static
module
import
(
const
char
*
name
)
{
PyObject
*
obj
=
PyImport_ImportModule
(
name
);
if
(
!
obj
)
throw
std
::
runtime_error
(
"Module
\"
"
+
std
::
string
(
name
)
+
"
\"
not found!"
);
pybind11_fail
(
"Module
\"
"
+
std
::
string
(
name
)
+
"
\"
not found!"
);
return
module
(
obj
,
false
);
}
};
...
...
@@ -668,7 +667,7 @@ public:
auto
type
=
(
PyHeapTypeObject
*
)
type_holder
.
ptr
();
if
(
!
type_holder
||
!
name
)
throw
std
::
runtime_error
(
"generic_type: unable to create type object!"
);
pybind11_fail
(
"generic_type: unable to create type object!"
);
/* Register supplemental type information in C++ dict */
auto
&
internals
=
get_internals
();
...
...
@@ -732,7 +731,7 @@ public:
}
if
(
PyType_Ready
(
&
type
->
ht_type
)
<
0
)
throw
std
::
runtime_error
(
"generic_type: PyType_Ready failed!"
);
pybind11_fail
(
"generic_type: PyType_Ready failed!"
);
m_ptr
=
type_holder
.
ptr
();
...
...
@@ -756,7 +755,7 @@ protected:
object
type_holder
(
PyType_Type
.
tp_alloc
(
&
PyType_Type
,
0
),
false
);
object
name
(
PYBIND11_FROM_STRING
(
name_
.
c_str
()),
false
);
if
(
!
type_holder
||
!
name
)
throw
std
::
runtime_error
(
"generic_type::metaclass(): unable to create type object!"
);
pybind11_fail
(
"generic_type::metaclass(): unable to create type object!"
);
auto
type
=
(
PyHeapTypeObject
*
)
type_holder
.
ptr
();
type
->
ht_name
=
name
.
release
();
...
...
@@ -767,7 +766,7 @@ protected:
~
Py_TPFLAGS_HAVE_GC
;
if
(
PyType_Ready
(
&
type
->
ht_type
)
<
0
)
throw
std
::
runtime_error
(
"generic_type::metaclass(): PyType_Ready failed!"
);
pybind11_fail
(
"generic_type::metaclass(): PyType_Ready failed!"
);
ob_type
=
(
PyTypeObject
*
)
type_holder
.
release
();
}
...
...
@@ -798,7 +797,7 @@ protected:
auto
&
registered_instances
=
detail
::
get_internals
().
registered_instances
;
auto
it
=
registered_instances
.
find
(
self
->
value
);
if
(
it
==
registered_instances
.
end
())
throw
std
::
runtime_error
(
"generic_type::dealloc(): Tried to deallocate unregistered instance!"
);
pybind11_fail
(
"generic_type::dealloc(): Tried to deallocate unregistered instance!"
);
registered_instances
.
erase
(
it
);
}
Py_XDECREF
(
self
->
parent
);
...
...
@@ -1096,14 +1095,12 @@ PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, PyObject *
handle
patient
(
Patient
>
0
?
PyTuple_GetItem
(
arg
,
Patient
-
1
)
:
ret
);
if
(
!
nurse
||
!
patient
)
throw
std
::
runtime_error
(
"Could not activate keep_alive!"
);
pybind11_fail
(
"Could not activate keep_alive!"
);
cpp_function
disable_lifesupport
(
[
patient
](
handle
weakref
)
{
patient
.
dec_ref
();
weakref
.
dec_ref
();
});
weakref
wr
(
nurse
,
disable_lifesupport
);
if
(
!
wr
)
throw
std
::
runtime_error
(
"Could not allocate weak reference!"
);
patient
.
inc_ref
();
/* reference patient and leak the weak reference */
(
void
)
wr
.
release
();
...
...
@@ -1138,7 +1135,7 @@ template <typename InputType, typename OutputType> void implicitly_convertible()
auto
&
registered_types
=
detail
::
get_internals
().
registered_types_cpp
;
auto
it
=
registered_types
.
find
(
&
typeid
(
OutputType
));
if
(
it
==
registered_types
.
end
())
throw
std
::
runtime_error
(
"implicitly_convertible: Unable to find type "
+
type_id
<
OutputType
>
());
pybind11_fail
(
"implicitly_convertible: Unable to find type "
+
type_id
<
OutputType
>
());
((
detail
::
type_info
*
)
it
->
second
)
->
implicit_conversions
.
push_back
(
implicit_caster
);
}
...
...
@@ -1196,7 +1193,7 @@ inline function get_overload(const void *this_ptr, const char *name) {
#define PYBIND11_OVERLOAD_PURE(ret_type, class_name, name, ...) \
PYBIND11_OVERLOAD_INT(ret_type, class_name, name, __VA_ARGS__) \
throw std::runtime_error
("Tried to call pure virtual function \"" #name "\"");
pybind11::pybind11_fail
("Tried to call pure virtual function \"" #name "\"");
NAMESPACE_END
(
pybind11
)
...
...
include/pybind11/pytypes.h
View file @
678d787c
This diff is collapsed.
Click to expand it.
include/pybind11/stl.h
View file @
678d787c
...
...
@@ -14,7 +14,6 @@
#include <set>
#include <iostream>
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
...
...
@@ -28,14 +27,14 @@ template <typename Value, typename Alloc> struct type_caster<std::vector<Value,
typedef
type_caster
<
Value
>
value_conv
;
public
:
bool
load
(
PyObject
*
src
,
bool
convert
)
{
if
(
!
PyList_Check
(
src
))
list
l
(
src
,
true
);
if
(
!
l
.
check
())
return
false
;
size_t
size
=
(
size_t
)
PyList_GET_SIZE
(
src
);
value
.
reserve
(
size
);
value
.
reserve
(
l
.
size
());
value
.
clear
();
value_conv
conv
;
for
(
size_t
i
=
0
;
i
<
size
;
++
i
)
{
if
(
!
conv
.
load
(
PyList_GetItem
(
src
,
(
ssize_t
)
i
),
convert
))
for
(
auto
it
:
l
)
{
if
(
!
conv
.
load
(
it
.
ptr
(
),
convert
))
return
false
;
value
.
push_back
((
Value
)
conv
);
}
...
...
@@ -43,17 +42,15 @@ public:
}
static
PyObject
*
cast
(
const
type
&
src
,
return_value_policy
policy
,
PyObject
*
parent
)
{
object
list
(
PyList_New
(
src
.
size
()),
false
);
if
(
!
list
)
return
nullptr
;
list
l
(
src
.
size
());
size_t
index
=
0
;
for
(
auto
const
&
value
:
src
)
{
object
value_
(
value_conv
::
cast
(
value
,
policy
,
parent
),
false
);
object
value_
(
value_conv
::
cast
(
value
,
policy
,
parent
),
false
);
if
(
!
value_
)
return
nullptr
;
PyList_SET_ITEM
(
l
ist
.
ptr
(),
index
++
,
value_
.
release
());
// steals a reference
PyList_SET_ITEM
(
l
.
ptr
(),
index
++
,
value_
.
release
());
// steals a reference
}
return
l
ist
.
release
();
return
l
.
release
();
}
PYBIND11_TYPE_CASTER
(
type
,
_
(
"list<"
)
+
value_conv
::
name
()
+
_
(
">"
));
};
...
...
@@ -68,8 +65,8 @@ public:
return
false
;
value
.
clear
();
key_conv
conv
;
for
(
const
object
&
o
:
s
)
{
if
(
!
conv
.
load
(
(
PyObject
*
)
o
.
ptr
(),
convert
))
for
(
auto
entry
:
s
)
{
if
(
!
conv
.
load
(
entry
.
ptr
(),
convert
))
return
false
;
value
.
insert
((
Key
)
conv
);
}
...
...
@@ -77,15 +74,13 @@ public:
}
static
PyObject
*
cast
(
const
type
&
src
,
return_value_policy
policy
,
PyObject
*
parent
)
{
object
set
(
PySet_New
(
nullptr
),
false
);
if
(
!
set
)
return
nullptr
;
pybind11
::
set
s
;
for
(
auto
const
&
value
:
src
)
{
object
value_
(
key_conv
::
cast
(
value
,
policy
,
parent
),
false
);
if
(
!
value_
||
PySet_Add
(
set
.
ptr
(),
value_
.
ptr
())
!=
0
)
if
(
!
value_
||
!
s
.
add
(
value
)
)
return
nullptr
;
}
return
s
et
.
release
();
return
s
.
release
();
}
PYBIND11_TYPE_CASTER
(
type
,
_
(
"set<"
)
+
key_conv
::
name
()
+
_
(
">"
));
};
...
...
@@ -97,16 +92,15 @@ public:
typedef
type_caster
<
Value
>
value_conv
;
bool
load
(
PyObject
*
src
,
bool
convert
)
{
if
(
!
PyDict_Check
(
src
))
dict
d
(
src
,
true
);
if
(
!
d
.
check
())
return
false
;
value
.
clear
();
PyObject
*
key_
,
*
value_
;
ssize_t
pos
=
0
;
key_conv
kconv
;
value_conv
vconv
;
while
(
PyDict_Next
(
src
,
&
pos
,
&
key_
,
&
value_
))
{
if
(
!
kconv
.
load
(
key_
,
convert
)
||
!
vconv
.
load
(
value_
,
convert
))
value
.
clear
();
for
(
auto
it
:
d
)
{
if
(
!
kconv
.
load
(
it
.
first
.
ptr
(),
convert
)
||
!
vconv
.
load
(
it
.
second
.
ptr
(),
convert
))
return
false
;
value
[(
Key
)
kconv
]
=
(
Value
)
vconv
;
}
...
...
@@ -114,16 +108,15 @@ public:
}
static
PyObject
*
cast
(
const
type
&
src
,
return_value_policy
policy
,
PyObject
*
parent
)
{
object
dict
(
PyDict_New
(),
false
);
if
(
!
dict
)
return
nullptr
;
dict
d
;
for
(
auto
const
&
kv
:
src
)
{
object
key
(
key_conv
::
cast
(
kv
.
first
,
policy
,
parent
),
false
);
object
value
(
value_conv
::
cast
(
kv
.
second
,
policy
,
parent
),
false
);
if
(
!
key
||
!
value
||
PyDict_SetItem
(
dict
.
ptr
(),
key
.
ptr
(),
value
.
ptr
())
!=
0
)
if
(
!
key
||
!
value
)
return
nullptr
;
d
[
key
]
=
value
;
}
return
d
ict
.
release
();
return
d
.
release
();
}
PYBIND11_TYPE_CASTER
(
type
,
_
(
"dict<"
)
+
key_conv
::
name
()
+
_
(
", "
)
+
value_conv
::
name
()
+
_
(
">"
));
...
...
@@ -131,7 +124,10 @@ public:
NAMESPACE_END
(
detail
)
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
object
&
obj
)
{
os
<<
(
std
::
string
)
obj
.
str
();
return
os
;
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
handle
&
obj
)
{
os
<<
(
std
::
string
)
obj
.
str
();
return
os
;
}
NAMESPACE_END
(
pybind11
)
...
...
include/pybind11/typeid.h
View file @
678d787c
...
...
@@ -11,6 +11,7 @@
#include <cstdio>
#include <cstdlib>
#if defined(__GNUG__)
#include <cxxabi.h>
#endif
...
...
@@ -26,7 +27,7 @@ inline void erase_all(std::string &string, const std::string &search) {
}
}
inline
void
clean_type_id
(
std
::
string
&
name
)
{
PYBIND11_NOINLINE
inline
void
clean_type_id
(
std
::
string
&
name
)
{
#if defined(__GNUG__)
int
status
=
0
;
std
::
unique_ptr
<
char
,
void
(
*
)(
void
*
)
>
res
{
...
...
setup.py
View file @
678d787c
...
...
@@ -17,6 +17,7 @@ setup(
headers
=
[
'include/pybind11/cast.h'
,
'include/pybind11/complex.h'
,
'include/pybind11/descr.h'
,
'include/pybind11/numpy.h'
,
'include/pybind11/pybind11.h'
,
'include/pybind11/stl.h'
,
...
...
@@ -57,11 +58,10 @@ C++11-compatible compilers are widely available, this heavy machinery has
become an excessively large and unnecessary dependency.
Think of this library as a tiny self-contained version of Boost.Python with
everything stripped away that isn't relevant for binding generation. The whole
codebase requires less than 3000 lines of code and only depends on Python (2.7
or 3.x) and the C++ standard library. This compact implementation was
possible thanks to some of the new C++11 language features (tuples, lambda
functions and variadic templates). Since its creation, this library has
grown beyond Boost.Python in many ways, leading to dramatically simpler binding
code in many common situations."""
,
)
everything stripped away that isn't relevant for binding generation. The core
header files only require ~2.5K lines of code and depend on Python (2.7 or 3.x)
and the C++ standard library. This compact implementation was possible thanks
to some of the new C++11 language features (specifically: tuples, lambda
functions and variadic templates). Since its creation, this library has grown
beyond Boost.Python in many ways, leading to dramatically simpler binding code
in many common situations."""
)
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