Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
pybind11
Commits
03764178
Commit
03764178
authored
Dec 20, 2022
by
Henry Schreiner
Browse files
Merge branch 'master' into v2.10
parents
80dc998e
0694ec6a
Changes
62
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1024 additions
and
208 deletions
+1024
-208
include/pybind11/eigen/tensor.h
include/pybind11/eigen/tensor.h
+509
-0
include/pybind11/embed.h
include/pybind11/embed.h
+80
-42
include/pybind11/functional.h
include/pybind11/functional.h
+9
-2
include/pybind11/numpy.h
include/pybind11/numpy.h
+9
-8
include/pybind11/options.h
include/pybind11/options.h
+16
-0
include/pybind11/pybind11.h
include/pybind11/pybind11.h
+81
-57
include/pybind11/pytypes.h
include/pybind11/pytypes.h
+19
-19
include/pybind11/stl_bind.h
include/pybind11/stl_bind.h
+107
-47
pybind11/_version.py
pybind11/_version.py
+1
-1
setup.cfg
setup.cfg
+2
-2
tests/CMakeLists.txt
tests/CMakeLists.txt
+28
-3
tests/conftest.py
tests/conftest.py
+18
-0
tests/eigen_tensor_avoid_stl_array.cpp
tests/eigen_tensor_avoid_stl_array.cpp
+14
-0
tests/extra_python_package/test_files.py
tests/extra_python_package/test_files.py
+7
-1
tests/test_builtin_casters.cpp
tests/test_builtin_casters.cpp
+7
-2
tests/test_callbacks.cpp
tests/test_callbacks.cpp
+37
-0
tests/test_callbacks.py
tests/test_callbacks.py
+13
-0
tests/test_class.cpp
tests/test_class.cpp
+1
-3
tests/test_constants_and_functions.cpp
tests/test_constants_and_functions.cpp
+13
-21
tests/test_docstring_options.cpp
tests/test_docstring_options.cpp
+53
-0
No files found.
include/pybind11/eigen/tensor.h
0 → 100644
View file @
03764178
/*
pybind11/eigen/tensor.h: Transparent conversion for Eigen tensors
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "../numpy.h"
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
static_assert
(
__GNUC__
>
5
,
"Eigen Tensor support in pybind11 requires GCC > 5.0"
);
#endif
// Disable warnings for Eigen
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_MSVC
(
4554
)
PYBIND11_WARNING_DISABLE_MSVC
(
4127
)
PYBIND11_WARNING_DISABLE_GCC
(
"-Wmaybe-uninitialized"
)
#include <unsupported/Eigen/CXX11/Tensor>
PYBIND11_WARNING_POP
static_assert
(
EIGEN_VERSION_AT_LEAST
(
3
,
3
,
0
),
"Eigen Tensor support in pybind11 requires Eigen >= 3.3.0"
);
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
PYBIND11_WARNING_DISABLE_MSVC
(
4127
)
PYBIND11_NAMESPACE_BEGIN
(
detail
)
inline
bool
is_tensor_aligned
(
const
void
*
data
)
{
return
(
reinterpret_cast
<
std
::
size_t
>
(
data
)
%
EIGEN_DEFAULT_ALIGN_BYTES
)
==
0
;
}
template
<
typename
T
>
constexpr
int
compute_array_flag_from_tensor
()
{
static_assert
((
static_cast
<
int
>
(
T
::
Layout
)
==
static_cast
<
int
>
(
Eigen
::
RowMajor
))
||
(
static_cast
<
int
>
(
T
::
Layout
)
==
static_cast
<
int
>
(
Eigen
::
ColMajor
)),
"Layout must be row or column major"
);
return
(
static_cast
<
int
>
(
T
::
Layout
)
==
static_cast
<
int
>
(
Eigen
::
RowMajor
))
?
array
::
c_style
:
array
::
f_style
;
}
template
<
typename
T
>
struct
eigen_tensor_helper
{};
template
<
typename
Scalar_
,
int
NumIndices_
,
int
Options_
,
typename
IndexType
>
struct
eigen_tensor_helper
<
Eigen
::
Tensor
<
Scalar_
,
NumIndices_
,
Options_
,
IndexType
>>
{
using
Type
=
Eigen
::
Tensor
<
Scalar_
,
NumIndices_
,
Options_
,
IndexType
>
;
using
ValidType
=
void
;
static
Eigen
::
DSizes
<
typename
Type
::
Index
,
Type
::
NumIndices
>
get_shape
(
const
Type
&
f
)
{
return
f
.
dimensions
();
}
static
constexpr
bool
is_correct_shape
(
const
Eigen
::
DSizes
<
typename
Type
::
Index
,
Type
::
NumIndices
>
&
/*shape*/
)
{
return
true
;
}
template
<
typename
T
>
struct
helper
{};
template
<
size_t
...
Is
>
struct
helper
<
index_sequence
<
Is
...
>>
{
static
constexpr
auto
value
=
concat
(
const_name
(((
void
)
Is
,
"?"
))...);
};
static
constexpr
auto
dimensions_descriptor
=
helper
<
decltype
(
make_index_sequence
<
Type
::
NumIndices
>
())
>::
value
;
template
<
typename
...
Args
>
static
Type
*
alloc
(
Args
&&
...
args
)
{
return
new
Type
(
std
::
forward
<
Args
>
(
args
)...);
}
static
void
free
(
Type
*
tensor
)
{
delete
tensor
;
}
};
template
<
typename
Scalar_
,
typename
std
::
ptrdiff_t
...
Indices
,
int
Options_
,
typename
IndexType
>
struct
eigen_tensor_helper
<
Eigen
::
TensorFixedSize
<
Scalar_
,
Eigen
::
Sizes
<
Indices
...
>
,
Options_
,
IndexType
>>
{
using
Type
=
Eigen
::
TensorFixedSize
<
Scalar_
,
Eigen
::
Sizes
<
Indices
...
>
,
Options_
,
IndexType
>
;
using
ValidType
=
void
;
static
constexpr
Eigen
::
DSizes
<
typename
Type
::
Index
,
Type
::
NumIndices
>
get_shape
(
const
Type
&
/*f*/
)
{
return
get_shape
();
}
static
constexpr
Eigen
::
DSizes
<
typename
Type
::
Index
,
Type
::
NumIndices
>
get_shape
()
{
return
Eigen
::
DSizes
<
typename
Type
::
Index
,
Type
::
NumIndices
>
(
Indices
...);
}
static
bool
is_correct_shape
(
const
Eigen
::
DSizes
<
typename
Type
::
Index
,
Type
::
NumIndices
>
&
shape
)
{
return
get_shape
()
==
shape
;
}
static
constexpr
auto
dimensions_descriptor
=
concat
(
const_name
<
Indices
>
()...);
template
<
typename
...
Args
>
static
Type
*
alloc
(
Args
&&
...
args
)
{
Eigen
::
aligned_allocator
<
Type
>
allocator
;
return
::
new
(
allocator
.
allocate
(
1
))
Type
(
std
::
forward
<
Args
>
(
args
)...);
}
static
void
free
(
Type
*
tensor
)
{
Eigen
::
aligned_allocator
<
Type
>
allocator
;
tensor
->~
Type
();
allocator
.
deallocate
(
tensor
,
1
);
}
};
template
<
typename
Type
,
bool
ShowDetails
,
bool
NeedsWriteable
=
false
>
struct
get_tensor_descriptor
{
static
constexpr
auto
details
=
const_name
<
NeedsWriteable
>
(
", flags.writeable"
,
""
)
+
const_name
<
static_cast
<
int
>
(
Type
::
Layout
)
==
static_cast
<
int
>
(
Eigen
::
RowMajor
)
>
(
", flags.c_contiguous"
,
", flags.f_contiguous"
);
static
constexpr
auto
value
=
const_name
(
"numpy.ndarray["
)
+
npy_format_descriptor
<
typename
Type
::
Scalar
>::
name
+
const_name
(
"["
)
+
eigen_tensor_helper
<
remove_cv_t
<
Type
>>::
dimensions_descriptor
+
const_name
(
"]"
)
+
const_name
<
ShowDetails
>
(
details
,
const_name
(
""
))
+
const_name
(
"]"
);
};
// When EIGEN_AVOID_STL_ARRAY is defined, Eigen::DSizes<T, 0> does not have the begin() member
// function. Falling back to a simple loop works around this issue.
//
// We need to disable the type-limits warning for the inner loop when size = 0.
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_GCC
(
"-Wtype-limits"
)
template
<
typename
T
,
int
size
>
std
::
vector
<
T
>
convert_dsizes_to_vector
(
const
Eigen
::
DSizes
<
T
,
size
>
&
arr
)
{
std
::
vector
<
T
>
result
(
size
);
for
(
size_t
i
=
0
;
i
<
size
;
i
++
)
{
result
[
i
]
=
arr
[
i
];
}
return
result
;
}
template
<
typename
T
,
int
size
>
Eigen
::
DSizes
<
T
,
size
>
get_shape_for_array
(
const
array
&
arr
)
{
Eigen
::
DSizes
<
T
,
size
>
result
;
const
T
*
shape
=
arr
.
shape
();
for
(
size_t
i
=
0
;
i
<
size
;
i
++
)
{
result
[
i
]
=
shape
[
i
];
}
return
result
;
}
PYBIND11_WARNING_POP
template
<
typename
Type
>
struct
type_caster
<
Type
,
typename
eigen_tensor_helper
<
Type
>::
ValidType
>
{
using
Helper
=
eigen_tensor_helper
<
Type
>
;
static
constexpr
auto
temp_name
=
get_tensor_descriptor
<
Type
,
false
>::
value
;
PYBIND11_TYPE_CASTER
(
Type
,
temp_name
);
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
convert
)
{
if
(
!
isinstance
<
array
>
(
src
))
{
return
false
;
}
array
temp
=
array
::
ensure
(
src
);
if
(
!
temp
)
{
return
false
;
}
if
(
!
convert
&&
!
temp
.
dtype
().
is
(
dtype
::
of
<
typename
Type
::
Scalar
>
()))
{
return
false
;
}
}
array_t
<
typename
Type
::
Scalar
,
compute_array_flag_from_tensor
<
Type
>
()
>
arr
(
reinterpret_borrow
<
object
>
(
src
));
if
(
arr
.
ndim
()
!=
Type
::
NumIndices
)
{
return
false
;
}
auto
shape
=
get_shape_for_array
<
typename
Type
::
Index
,
Type
::
NumIndices
>
(
arr
);
if
(
!
Helper
::
is_correct_shape
(
shape
))
{
return
false
;
}
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
auto
data_pointer
=
arr
.
data
();
#else
// Handle Eigen bug
auto
data_pointer
=
const_cast
<
typename
Type
::
Scalar
*>
(
arr
.
data
());
#endif
if
(
is_tensor_aligned
(
arr
.
data
()))
{
value
=
Eigen
::
TensorMap
<
const
Type
,
Eigen
::
Aligned
>
(
data_pointer
,
shape
);
}
else
{
value
=
Eigen
::
TensorMap
<
const
Type
>
(
data_pointer
,
shape
);
}
return
true
;
}
static
handle
cast
(
Type
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
reference
||
policy
==
return_value_policy
::
reference_internal
)
{
pybind11_fail
(
"Cannot use a reference return value policy for an rvalue"
);
}
return
cast_impl
(
&
src
,
return_value_policy
::
move
,
parent
);
}
static
handle
cast
(
const
Type
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
reference
||
policy
==
return_value_policy
::
reference_internal
)
{
pybind11_fail
(
"Cannot use a reference return value policy for an rvalue"
);
}
return
cast_impl
(
&
src
,
return_value_policy
::
move
,
parent
);
}
static
handle
cast
(
Type
&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
{
policy
=
return_value_policy
::
copy
;
}
return
cast_impl
(
&
src
,
policy
,
parent
);
}
static
handle
cast
(
const
Type
&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
{
policy
=
return_value_policy
::
copy
;
}
return
cast
(
&
src
,
policy
,
parent
);
}
static
handle
cast
(
Type
*
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
)
{
policy
=
return_value_policy
::
take_ownership
;
}
else
if
(
policy
==
return_value_policy
::
automatic_reference
)
{
policy
=
return_value_policy
::
reference
;
}
return
cast_impl
(
src
,
policy
,
parent
);
}
static
handle
cast
(
const
Type
*
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
)
{
policy
=
return_value_policy
::
take_ownership
;
}
else
if
(
policy
==
return_value_policy
::
automatic_reference
)
{
policy
=
return_value_policy
::
reference
;
}
return
cast_impl
(
src
,
policy
,
parent
);
}
template
<
typename
C
>
static
handle
cast_impl
(
C
*
src
,
return_value_policy
policy
,
handle
parent
)
{
object
parent_object
;
bool
writeable
=
false
;
switch
(
policy
)
{
case
return_value_policy
::
move
:
if
(
std
::
is_const
<
C
>::
value
)
{
pybind11_fail
(
"Cannot move from a constant reference"
);
}
src
=
Helper
::
alloc
(
std
::
move
(
*
src
));
parent_object
=
capsule
(
src
,
[](
void
*
ptr
)
{
Helper
::
free
(
reinterpret_cast
<
Type
*>
(
ptr
));
});
writeable
=
true
;
break
;
case
return_value_policy
::
take_ownership
:
if
(
std
::
is_const
<
C
>::
value
)
{
// This cast is ugly, and might be UB in some cases, but we don't have an
// alternative here as we must free that memory
Helper
::
free
(
const_cast
<
Type
*>
(
src
));
pybind11_fail
(
"Cannot take ownership of a const reference"
);
}
parent_object
=
capsule
(
src
,
[](
void
*
ptr
)
{
Helper
::
free
(
reinterpret_cast
<
Type
*>
(
ptr
));
});
writeable
=
true
;
break
;
case
return_value_policy
::
copy
:
writeable
=
true
;
break
;
case
return_value_policy
::
reference
:
parent_object
=
none
();
writeable
=
!
std
::
is_const
<
C
>::
value
;
break
;
case
return_value_policy
::
reference_internal
:
// Default should do the right thing
if
(
!
parent
)
{
pybind11_fail
(
"Cannot use reference internal when there is no parent"
);
}
parent_object
=
reinterpret_borrow
<
object
>
(
parent
);
writeable
=
!
std
::
is_const
<
C
>::
value
;
break
;
default:
pybind11_fail
(
"pybind11 bug in eigen.h, please file a bug report"
);
}
auto
result
=
array_t
<
typename
Type
::
Scalar
,
compute_array_flag_from_tensor
<
Type
>
()
>
(
convert_dsizes_to_vector
(
Helper
::
get_shape
(
*
src
)),
src
->
data
(),
parent_object
);
if
(
!
writeable
)
{
array_proxy
(
result
.
ptr
())
->
flags
&=
~
detail
::
npy_api
::
NPY_ARRAY_WRITEABLE_
;
}
return
result
.
release
();
}
};
template
<
typename
StoragePointerType
,
bool
needs_writeable
,
enable_if_t
<!
needs_writeable
,
bool
>
=
true
>
StoragePointerType
get_array_data_for_type
(
array
&
arr
)
{
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
return
reinterpret_cast
<
StoragePointerType
>
(
arr
.
data
());
#else
// Handle Eigen bug
return
reinterpret_cast
<
StoragePointerType
>
(
const_cast
<
void
*>
(
arr
.
data
()));
#endif
}
template
<
typename
StoragePointerType
,
bool
needs_writeable
,
enable_if_t
<
needs_writeable
,
bool
>
=
true
>
StoragePointerType
get_array_data_for_type
(
array
&
arr
)
{
return
reinterpret_cast
<
StoragePointerType
>
(
arr
.
mutable_data
());
}
template
<
typename
T
,
typename
=
void
>
struct
get_storage_pointer_type
;
template
<
typename
MapType
>
struct
get_storage_pointer_type
<
MapType
,
void_t
<
typename
MapType
::
StoragePointerType
>>
{
using
SPT
=
typename
MapType
::
StoragePointerType
;
};
template
<
typename
MapType
>
struct
get_storage_pointer_type
<
MapType
,
void_t
<
typename
MapType
::
PointerArgType
>>
{
using
SPT
=
typename
MapType
::
PointerArgType
;
};
template
<
typename
Type
,
int
Options
>
struct
type_caster
<
Eigen
::
TensorMap
<
Type
,
Options
>
,
typename
eigen_tensor_helper
<
remove_cv_t
<
Type
>>::
ValidType
>
{
using
MapType
=
Eigen
::
TensorMap
<
Type
,
Options
>
;
using
Helper
=
eigen_tensor_helper
<
remove_cv_t
<
Type
>>
;
bool
load
(
handle
src
,
bool
/*convert*/
)
{
// Note that we have a lot more checks here as we want to make sure to avoid copies
if
(
!
isinstance
<
array
>
(
src
))
{
return
false
;
}
auto
arr
=
reinterpret_borrow
<
array
>
(
src
);
if
((
arr
.
flags
()
&
compute_array_flag_from_tensor
<
Type
>
())
==
0
)
{
return
false
;
}
if
(
!
arr
.
dtype
().
is
(
dtype
::
of
<
typename
Type
::
Scalar
>
()))
{
return
false
;
}
if
(
arr
.
ndim
()
!=
Type
::
NumIndices
)
{
return
false
;
}
constexpr
bool
is_aligned
=
(
Options
&
Eigen
::
Aligned
)
!=
0
;
if
(
is_aligned
&&
!
is_tensor_aligned
(
arr
.
data
()))
{
return
false
;
}
auto
shape
=
get_shape_for_array
<
typename
Type
::
Index
,
Type
::
NumIndices
>
(
arr
);
if
(
!
Helper
::
is_correct_shape
(
shape
))
{
return
false
;
}
if
(
needs_writeable
&&
!
arr
.
writeable
())
{
return
false
;
}
auto
result
=
get_array_data_for_type
<
typename
get_storage_pointer_type
<
MapType
>::
SPT
,
needs_writeable
>
(
arr
);
value
.
reset
(
new
MapType
(
std
::
move
(
result
),
std
::
move
(
shape
)));
return
true
;
}
static
handle
cast
(
MapType
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
return
cast_impl
(
&
src
,
policy
,
parent
);
}
static
handle
cast
(
const
MapType
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
return
cast_impl
(
&
src
,
policy
,
parent
);
}
static
handle
cast
(
MapType
&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
{
policy
=
return_value_policy
::
copy
;
}
return
cast_impl
(
&
src
,
policy
,
parent
);
}
static
handle
cast
(
const
MapType
&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
{
policy
=
return_value_policy
::
copy
;
}
return
cast
(
&
src
,
policy
,
parent
);
}
static
handle
cast
(
MapType
*
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
)
{
policy
=
return_value_policy
::
take_ownership
;
}
else
if
(
policy
==
return_value_policy
::
automatic_reference
)
{
policy
=
return_value_policy
::
reference
;
}
return
cast_impl
(
src
,
policy
,
parent
);
}
static
handle
cast
(
const
MapType
*
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
)
{
policy
=
return_value_policy
::
take_ownership
;
}
else
if
(
policy
==
return_value_policy
::
automatic_reference
)
{
policy
=
return_value_policy
::
reference
;
}
return
cast_impl
(
src
,
policy
,
parent
);
}
template
<
typename
C
>
static
handle
cast_impl
(
C
*
src
,
return_value_policy
policy
,
handle
parent
)
{
object
parent_object
;
constexpr
bool
writeable
=
!
std
::
is_const
<
C
>::
value
;
switch
(
policy
)
{
case
return_value_policy
::
reference
:
parent_object
=
none
();
break
;
case
return_value_policy
::
reference_internal
:
// Default should do the right thing
if
(
!
parent
)
{
pybind11_fail
(
"Cannot use reference internal when there is no parent"
);
}
parent_object
=
reinterpret_borrow
<
object
>
(
parent
);
break
;
case
return_value_policy
::
take_ownership
:
delete
src
;
// fallthrough
default:
// move, take_ownership don't make any sense for a ref/map:
pybind11_fail
(
"Invalid return_value_policy for Eigen Map type, must be either "
"reference or reference_internal"
);
}
auto
result
=
array_t
<
typename
Type
::
Scalar
,
compute_array_flag_from_tensor
<
Type
>
()
>
(
convert_dsizes_to_vector
(
Helper
::
get_shape
(
*
src
)),
src
->
data
(),
std
::
move
(
parent_object
));
if
(
!
writeable
)
{
array_proxy
(
result
.
ptr
())
->
flags
&=
~
detail
::
npy_api
::
NPY_ARRAY_WRITEABLE_
;
}
return
result
.
release
();
}
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
static
constexpr
bool
needs_writeable
=
!
std
::
is_const
<
typename
std
::
remove_pointer
<
typename
get_storage_pointer_type
<
MapType
>::
SPT
>::
type
>::
value
;
#else
// Handle Eigen bug
static
constexpr
bool
needs_writeable
=
!
std
::
is_const
<
Type
>::
value
;
#endif
protected:
// TODO: Move to std::optional once std::optional has more support
std
::
unique_ptr
<
MapType
>
value
;
public:
static
constexpr
auto
name
=
get_tensor_descriptor
<
Type
,
true
,
needs_writeable
>::
value
;
explicit
operator
MapType
*
()
{
return
value
.
get
();
}
explicit
operator
MapType
&
()
{
return
*
value
;
}
explicit
operator
MapType
&&
()
&&
{
return
std
::
move
(
*
value
);
}
template
<
typename
T_
>
using
cast_op_type
=
::
pybind11
::
detail
::
movable_cast_op_type
<
T_
>
;
};
PYBIND11_NAMESPACE_END
(
detail
)
PYBIND11_NAMESPACE_END
(
PYBIND11_NAMESPACE
)
include/pybind11/embed.h
View file @
03764178
...
...
@@ -86,38 +86,26 @@ inline wchar_t *widen_chars(const char *safe_arg) {
return
widened_arg
;
}
PYBIND11_NAMESPACE_END
(
detail
)
/** \rst
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
optional `init_signal_handlers` parameter can be used to skip the registration of
signal handlers (see the `Python documentation`_ for details). Calling this function
again after the interpreter has already been initialized is a fatal error.
If initializing the Python interpreter fails, then the program is terminated. (This
is controlled by the CPython runtime and is an exception to pybind11's normal behavior
of throwing exceptions on errors.)
The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are
used to populate ``sys.argv`` and ``sys.path``.
See the |PySys_SetArgvEx documentation|_ for details.
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
.. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation
.. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx
\endrst */
inline
void
initialize_interpreter
(
bool
init_signal_handlers
=
true
,
int
argc
=
0
,
const
char
*
const
*
argv
=
nullptr
,
bool
add_program_dir_to_path
=
true
)
{
inline
void
precheck_interpreter
()
{
if
(
Py_IsInitialized
()
!=
0
)
{
pybind11_fail
(
"The interpreter is already running"
);
}
}
#if PY_VERSION_HEX < 0x030B0000
#if !defined(PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX)
# define PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX (0x03080000)
#endif
#if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
inline
void
initialize_interpreter_pre_pyconfig
(
bool
init_signal_handlers
,
int
argc
,
const
char
*
const
*
argv
,
bool
add_program_dir_to_path
)
{
detail
::
precheck_interpreter
();
Py_InitializeEx
(
init_signal_handlers
?
1
:
0
);
# if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000
PyEval_InitThreads
();
# endif
// Before it was special-cased in python 3.8, passing an empty or null argv
// caused a segfault, so we have to reimplement the special case ourselves.
...
...
@@ -147,26 +135,30 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
auto
*
pysys_argv
=
widened_argv
.
get
();
PySys_SetArgvEx
(
argc
,
pysys_argv
,
static_cast
<
int
>
(
add_program_dir_to_path
));
#else
PyConfig
config
;
PyConfig_InitIsolatedConfig
(
&
config
);
config
.
isolated
=
0
;
config
.
use_environment
=
1
;
config
.
install_signal_handlers
=
init_signal_handlers
?
1
:
0
;
}
#endif
PyStatus
status
=
PyConfig_SetBytesArgv
(
&
config
,
argc
,
const_cast
<
char
*
const
*>
(
argv
));
if
(
PyStatus_Exception
(
status
))
{
PYBIND11_NAMESPACE_END
(
detail
)
#if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
inline
void
initialize_interpreter
(
PyConfig
*
config
,
int
argc
=
0
,
const
char
*
const
*
argv
=
nullptr
,
bool
add_program_dir_to_path
=
true
)
{
detail
::
precheck_interpreter
();
PyStatus
status
=
PyConfig_SetBytesArgv
(
config
,
argc
,
const_cast
<
char
*
const
*>
(
argv
));
if
(
PyStatus_Exception
(
status
)
!=
0
)
{
// A failure here indicates a character-encoding failure or the python
// interpreter out of memory. Give up.
PyConfig_Clear
(
&
config
);
throw
std
::
runtime_error
(
PyStatus_IsError
(
status
)
?
status
.
err_msg
:
"Failed to prepare CPython"
);
PyConfig_Clear
(
config
);
throw
std
::
runtime_error
(
PyStatus_IsError
(
status
)
!=
0
?
status
.
err_msg
:
"Failed to prepare CPython"
);
}
status
=
Py_InitializeFromConfig
(
&
config
);
PyConfig_Clear
(
&
config
);
if
(
PyStatus_Exception
(
status
))
{
throw
std
::
runtime_error
(
PyStatus_IsError
(
status
)
?
status
.
err_msg
:
"Failed to init CPython"
);
status
=
Py_InitializeFromConfig
(
config
);
if
(
PyStatus_Exception
(
status
)
!=
0
)
{
PyConfig_Clear
(
config
);
throw
std
::
runtime_error
(
PyStatus_IsError
(
status
)
!=
0
?
status
.
err_msg
:
"Failed to init CPython"
);
}
if
(
add_program_dir_to_path
)
{
PyRun_SimpleString
(
"import sys, os.path; "
...
...
@@ -174,6 +166,43 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
"os.path.abspath(os.path.dirname(sys.argv[0])) "
"if sys.argv and os.path.exists(sys.argv[0]) else '')"
);
}
PyConfig_Clear
(
config
);
}
#endif
/** \rst
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
optional `init_signal_handlers` parameter can be used to skip the registration of
signal handlers (see the `Python documentation`_ for details). Calling this function
again after the interpreter has already been initialized is a fatal error.
If initializing the Python interpreter fails, then the program is terminated. (This
is controlled by the CPython runtime and is an exception to pybind11's normal behavior
of throwing exceptions on errors.)
The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are
used to populate ``sys.argv`` and ``sys.path``.
See the |PySys_SetArgvEx documentation|_ for details.
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
.. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation
.. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx
\endrst */
inline
void
initialize_interpreter
(
bool
init_signal_handlers
=
true
,
int
argc
=
0
,
const
char
*
const
*
argv
=
nullptr
,
bool
add_program_dir_to_path
=
true
)
{
#if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
detail
::
initialize_interpreter_pre_pyconfig
(
init_signal_handlers
,
argc
,
argv
,
add_program_dir_to_path
);
#else
PyConfig
config
;
PyConfig_InitIsolatedConfig
(
&
config
);
config
.
isolated
=
0
;
config
.
use_environment
=
1
;
config
.
install_signal_handlers
=
init_signal_handlers
?
1
:
0
;
initialize_interpreter
(
&
config
,
argc
,
argv
,
add_program_dir_to_path
);
#endif
}
...
...
@@ -261,6 +290,15 @@ public:
initialize_interpreter
(
init_signal_handlers
,
argc
,
argv
,
add_program_dir_to_path
);
}
#if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
explicit
scoped_interpreter
(
PyConfig
*
config
,
int
argc
=
0
,
const
char
*
const
*
argv
=
nullptr
,
bool
add_program_dir_to_path
=
true
)
{
initialize_interpreter
(
config
,
argc
,
argv
,
add_program_dir_to_path
);
}
#endif
scoped_interpreter
(
const
scoped_interpreter
&
)
=
delete
;
scoped_interpreter
(
scoped_interpreter
&&
other
)
noexcept
{
other
.
is_valid
=
false
;
}
scoped_interpreter
&
operator
=
(
const
scoped_interpreter
&
)
=
delete
;
...
...
include/pybind11/functional.h
View file @
03764178
...
...
@@ -48,9 +48,16 @@ public:
*/
if
(
auto
cfunc
=
func
.
cpp_function
())
{
auto
*
cfunc_self
=
PyCFunction_GET_SELF
(
cfunc
.
ptr
());
if
(
isinstance
<
capsule
>
(
cfunc_self
))
{
if
(
cfunc_self
==
nullptr
)
{
PyErr_Clear
();
}
else
if
(
isinstance
<
capsule
>
(
cfunc_self
))
{
auto
c
=
reinterpret_borrow
<
capsule
>
(
cfunc_self
);
auto
*
rec
=
(
function_record
*
)
c
;
function_record
*
rec
=
nullptr
;
// Check that we can safely reinterpret the capsule into a function_record
if
(
detail
::
is_function_record_capsule
(
c
))
{
rec
=
c
.
get_pointer
<
function_record
>
();
}
while
(
rec
!=
nullptr
)
{
if
(
rec
->
is_stateless
...
...
include/pybind11/numpy.h
View file @
03764178
...
...
@@ -36,6 +36,8 @@ static_assert(std::is_signed<Py_intptr_t>::value, "Py_intptr_t must be signed");
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
PYBIND11_WARNING_DISABLE_MSVC
(
4127
)
class
array
;
// Forward declaration
PYBIND11_NAMESPACE_BEGIN
(
detail
)
...
...
@@ -875,7 +877,7 @@ public:
*/
template
<
typename
T
,
ssize_t
Dims
=
-
1
>
detail
::
unchecked_mutable_reference
<
T
,
Dims
>
mutable_unchecked
()
&
{
if
(
PYBIND11_SILENCE_MSVC_C4127
(
Dims
>=
0
)
&&
ndim
()
!=
Dims
)
{
if
(
Dims
>=
0
&&
ndim
()
!=
Dims
)
{
throw
std
::
domain_error
(
"array has incorrect number of dimensions: "
+
std
::
to_string
(
ndim
())
+
"; expected "
+
std
::
to_string
(
Dims
));
...
...
@@ -893,7 +895,7 @@ public:
*/
template
<
typename
T
,
ssize_t
Dims
=
-
1
>
detail
::
unchecked_reference
<
T
,
Dims
>
unchecked
()
const
&
{
if
(
PYBIND11_SILENCE_MSVC_C4127
(
Dims
>=
0
)
&&
ndim
()
!=
Dims
)
{
if
(
Dims
>=
0
&&
ndim
()
!=
Dims
)
{
throw
std
::
domain_error
(
"array has incorrect number of dimensions: "
+
std
::
to_string
(
ndim
())
+
"; expected "
+
std
::
to_string
(
Dims
));
...
...
@@ -1469,7 +1471,7 @@ private:
}
// Extract name, offset and format descriptor for a struct field
# define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #
Field)
# define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field)
// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro
// (C) William Swanson, Paul Fultz
...
...
@@ -1865,9 +1867,10 @@ private:
}
auto
result
=
returned_array
::
create
(
trivial
,
shape
);
PYBIND11_WARNING_PUSH
#ifdef PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wreturn-std-move"
PYBIND11_WARNING_DISABLE_CLANG
(
"-Wreturn-std-move"
)
#endif
if
(
size
==
0
)
{
...
...
@@ -1883,9 +1886,7 @@ private:
}
return
result
;
#ifdef PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING
# pragma clang diagnostic pop
#endif
PYBIND11_WARNING_POP
}
template
<
size_t
...
Index
,
size_t
...
VIndex
,
size_t
...
BIndex
>
...
...
include/pybind11/options.h
View file @
03764178
...
...
@@ -47,6 +47,16 @@ public:
return
*
this
;
}
options
&
disable_enum_members_docstring
()
&
{
global_state
().
show_enum_members_docstring
=
false
;
return
*
this
;
}
options
&
enable_enum_members_docstring
()
&
{
global_state
().
show_enum_members_docstring
=
true
;
return
*
this
;
}
// Getter methods (return the global state):
static
bool
show_user_defined_docstrings
()
{
...
...
@@ -55,6 +65,10 @@ public:
static
bool
show_function_signatures
()
{
return
global_state
().
show_function_signatures
;
}
static
bool
show_enum_members_docstring
()
{
return
global_state
().
show_enum_members_docstring
;
}
// This type is not meant to be allocated on the heap.
void
*
operator
new
(
size_t
)
=
delete
;
...
...
@@ -63,6 +77,8 @@ private:
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
show_enum_members_docstring
=
true
;
//< Include auto-generated member list in enum
// docstrings.
};
static
state
&
global_state
()
{
...
...
include/pybind11/pybind11.h
View file @
03764178
...
...
@@ -35,6 +35,8 @@
# include <cxxabi.h>
#endif
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
/* https://stackoverflow.com/questions/46798456/handling-gccs-noexcept-type-warning
This warning is about ABI compatibility, not code health.
It is only actually needed in a couple places, but apparently GCC 7 "generates this warning if
...
...
@@ -43,11 +45,10 @@
No other GCC version generates this warning.
*/
#if defined(__GNUC__) && __GNUC__ == 7
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnoexcept-type"
PYBIND11_WARNING_DISABLE_GCC
(
"-Wnoexcept-type"
)
#endif
PYBIND11_
NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
PYBIND11_
WARNING_DISABLE_MSVC
(
4127
)
PYBIND11_NAMESPACE_BEGIN
(
detail
)
...
...
@@ -177,22 +178,22 @@ protected:
auto
*
rec
=
unique_rec
.
get
();
/* Store the capture object directly in the function record if there is enough space */
if
(
PYBIND11_SILENCE_MSVC_C4127
(
sizeof
(
capture
)
<=
sizeof
(
rec
->
data
))
)
{
if
(
sizeof
(
capture
)
<=
sizeof
(
rec
->
data
))
{
/* Without these pragmas, GCC warns that there might not be
enough space to use the placement new operator. However, the
'if' statement above ensures that this is the case. */
#if defined(__GNUG__) && __GNUC__ >= 6 && !defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wplacement-new"
PYBIND11_WARNING_PUSH
#if defined(__GNUG__) && __GNUC__ >= 6
PYBIND11_WARNING_DISABLE_GCC
(
"-Wplacement-new"
)
#endif
new
((
capture
*
)
&
rec
->
data
)
capture
{
std
::
forward
<
Func
>
(
f
)};
#if defined(__GNUG__) && __GNUC__ >= 6 && !defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic pop
#endif
#if defined(__GNUG__) && !PYBIND11_HAS_STD_LAUNDER && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
#if !PYBIND11_HAS_STD_LAUNDER
PYBIND11_WARNING_DISABLE_GCC
(
"-Wstrict-aliasing"
)
#endif
// UB without std::launder, but without breaking ABI and/or
// a significant refactoring it's "impossible" to solve.
if
(
!
std
::
is_trivially_destructible
<
capture
>::
value
)
{
...
...
@@ -202,9 +203,7 @@ protected:
data
->~
capture
();
};
}
#if defined(__GNUG__) && !PYBIND11_HAS_STD_LAUNDER && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic pop
#endif
PYBIND11_WARNING_POP
}
else
{
rec
->
data
[
0
]
=
new
capture
{
std
::
forward
<
Func
>
(
f
)};
rec
->
free_data
=
[](
function_record
*
r
)
{
delete
((
capture
*
)
r
->
data
[
0
]);
};
...
...
@@ -468,13 +467,20 @@ protected:
if
(
rec
->
sibling
)
{
if
(
PyCFunction_Check
(
rec
->
sibling
.
ptr
()))
{
auto
*
self
=
PyCFunction_GET_SELF
(
rec
->
sibling
.
ptr
());
capsule
rec_capsule
=
isinstance
<
capsule
>
(
self
)
?
reinterpret_borrow
<
capsule
>
(
self
)
:
capsule
(
self
);
chain
=
(
detail
::
function_record
*
)
rec_capsule
;
/* Never append a method to an overload chain of a parent class;
instead, hide the parent's overloads in this case */
if
(
!
chain
->
scope
.
is
(
rec
->
scope
))
{
if
(
!
isinstance
<
capsule
>
(
self
))
{
chain
=
nullptr
;
}
else
{
auto
rec_capsule
=
reinterpret_borrow
<
capsule
>
(
self
);
if
(
detail
::
is_function_record_capsule
(
rec_capsule
))
{
chain
=
rec_capsule
.
get_pointer
<
detail
::
function_record
>
();
/* Never append a method to an overload chain of a parent class;
instead, hide the parent's overloads in this case */
if
(
!
chain
->
scope
.
is
(
rec
->
scope
))
{
chain
=
nullptr
;
}
}
else
{
chain
=
nullptr
;
}
}
}
// Don't trigger for things like the default __init__, which are wrapper_descriptors
...
...
@@ -496,6 +502,7 @@ protected:
capsule
rec_capsule
(
unique_rec
.
release
(),
[](
void
*
ptr
)
{
destruct
((
detail
::
function_record
*
)
ptr
);
});
rec_capsule
.
set_name
(
detail
::
get_function_record_capsule_name
());
guarded_strdup
.
release
();
object
scope_module
;
...
...
@@ -661,10 +668,13 @@ protected:
/// Main dispatch logic for calls to functions bound using pybind11
static
PyObject
*
dispatcher
(
PyObject
*
self
,
PyObject
*
args_in
,
PyObject
*
kwargs_in
)
{
using
namespace
detail
;
assert
(
isinstance
<
capsule
>
(
self
));
/* Iterator over the list of potentially admissible overloads */
const
function_record
*
overloads
=
(
function_record
*
)
PyCapsule_GetPointer
(
self
,
nullptr
),
const
function_record
*
overloads
=
reinterpret_cast
<
function_record
*>
(
PyCapsule_GetPointer
(
self
,
get_function_record_capsule_name
())),
*
it
=
overloads
;
assert
(
overloads
!=
nullptr
);
/* Need to know how many arguments + keyword arguments there are to pick the right
overload */
...
...
@@ -1416,9 +1426,9 @@ template <typename T, enable_if_t<has_operator_delete<T>::value, int> = 0>
void
call_operator_delete
(
T
*
p
,
size_t
,
size_t
)
{
T
::
operator
delete
(
p
);
}
template
<
typename
T
,
enable_if_t
<!
has_operator_delete
<
T
>
::
value
&&
has_operator_delete_size
<
T
>::
value
,
int
>
=
0
>
template
<
typename
T
,
enable_if_t
<!
has_operator_delete
<
T
>
::
value
&&
has_operator_delete_size
<
T
>::
value
,
int
>
=
0
>
void
call_operator_delete
(
T
*
p
,
size_t
s
,
size_t
)
{
T
::
operator
delete
(
p
,
s
);
}
...
...
@@ -1830,8 +1840,7 @@ private:
if
(
holder_ptr
)
{
init_holder_from_existing
(
v_h
,
holder_ptr
,
std
::
is_copy_constructible
<
holder_type
>
());
v_h
.
set_holder_constructed
();
}
else
if
(
PYBIND11_SILENCE_MSVC_C4127
(
detail
::
always_construct_holder
<
holder_type
>::
value
)
||
inst
->
owned
)
{
}
else
if
(
detail
::
always_construct_holder
<
holder_type
>::
value
||
inst
->
owned
)
{
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
()))
holder_type
(
v_h
.
value_ptr
<
type
>
());
v_h
.
set_holder_constructed
();
}
...
...
@@ -1871,9 +1880,22 @@ private:
static
detail
::
function_record
*
get_function_record
(
handle
h
)
{
h
=
detail
::
get_function
(
h
);
return
h
?
(
detail
::
function_record
*
)
reinterpret_borrow
<
capsule
>
(
PyCFunction_GET_SELF
(
h
.
ptr
()))
:
nullptr
;
if
(
!
h
)
{
return
nullptr
;
}
handle
func_self
=
PyCFunction_GET_SELF
(
h
.
ptr
());
if
(
!
func_self
)
{
throw
error_already_set
();
}
if
(
!
isinstance
<
capsule
>
(
func_self
))
{
return
nullptr
;
}
auto
cap
=
reinterpret_borrow
<
capsule
>
(
func_self
);
if
(
!
detail
::
is_function_record_capsule
(
cap
))
{
return
nullptr
;
}
return
cap
.
get_pointer
<
detail
::
function_record
>
();
}
};
...
...
@@ -1950,29 +1972,35 @@ struct enum_base {
name
(
"name"
),
is_method
(
m_base
));
m_base
.
attr
(
"__doc__"
)
=
static_property
(
cpp_function
(
[](
handle
arg
)
->
std
::
string
{
std
::
string
docstring
;
dict
entries
=
arg
.
attr
(
"__entries"
);
if
(((
PyTypeObject
*
)
arg
.
ptr
())
->
tp_doc
)
{
docstring
+=
std
::
string
(((
PyTypeObject
*
)
arg
.
ptr
())
->
tp_doc
)
+
"
\n\n
"
;
}
docstring
+=
"Members:"
;
for
(
auto
kv
:
entries
)
{
auto
key
=
std
::
string
(
pybind11
::
str
(
kv
.
first
));
auto
comment
=
kv
.
second
[
int_
(
1
)];
docstring
+=
"
\n\n
"
+
key
;
if
(
!
comment
.
is_none
())
{
docstring
+=
" : "
+
(
std
::
string
)
pybind11
::
str
(
comment
);
if
(
options
::
show_enum_members_docstring
())
{
m_base
.
attr
(
"__doc__"
)
=
static_property
(
cpp_function
(
[](
handle
arg
)
->
std
::
string
{
std
::
string
docstring
;
dict
entries
=
arg
.
attr
(
"__entries"
);
if
(((
PyTypeObject
*
)
arg
.
ptr
())
->
tp_doc
)
{
docstring
+=
std
::
string
(
reinterpret_cast
<
PyTypeObject
*>
(
arg
.
ptr
())
->
tp_doc
);
docstring
+=
"
\n\n
"
;
}
}
return
docstring
;
},
name
(
"__doc__"
)),
none
(),
none
(),
""
);
docstring
+=
"Members:"
;
for
(
auto
kv
:
entries
)
{
auto
key
=
std
::
string
(
pybind11
::
str
(
kv
.
first
));
auto
comment
=
kv
.
second
[
int_
(
1
)];
docstring
+=
"
\n\n
"
;
docstring
+=
key
;
if
(
!
comment
.
is_none
())
{
docstring
+=
" : "
;
docstring
+=
pybind11
::
str
(
comment
).
cast
<
std
::
string
>
();
}
}
return
docstring
;
},
name
(
"__doc__"
)),
none
(),
none
(),
""
);
}
m_base
.
attr
(
"__members__"
)
=
static_property
(
cpp_function
(
[](
handle
arg
)
->
dict
{
...
...
@@ -2852,7 +2880,3 @@ inline function get_overload(const T *this_ptr, const char *name) {
PYBIND11_OVERRIDE_PURE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__);
PYBIND11_NAMESPACE_END
(
PYBIND11_NAMESPACE
)
#if defined(__GNUC__) && __GNUC__ == 7
# pragma GCC diagnostic pop // -Wnoexcept-type
#endif
include/pybind11/pytypes.h
View file @
03764178
...
...
@@ -33,6 +33,8 @@
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
PYBIND11_WARNING_DISABLE_MSVC
(
4127
)
/* A few forward declarations */
class
handle
;
class
object
;
...
...
@@ -230,7 +232,8 @@ public:
detail
::
enable_if_t
<
detail
::
all_of
<
detail
::
none_of
<
std
::
is_base_of
<
handle
,
T
>,
detail
::
is_pyobj_ptr_or_nullptr_t
<
T
>>
,
std
::
is_convertible
<
T
,
PyObject
*>>::
value
,
int
>
=
0
>
int
>
=
0
>
// NOLINTNEXTLINE(google-explicit-constructor)
handle
(
T
&
obj
)
:
m_ptr
(
obj
)
{}
...
...
@@ -246,6 +249,11 @@ public:
const
handle
&
inc_ref
()
const
&
{
#ifdef PYBIND11_HANDLE_REF_DEBUG
inc_ref_counter
(
1
);
#endif
#if defined(PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF)
if
(
m_ptr
!=
nullptr
&&
!
PyGILState_Check
())
{
throw
std
::
runtime_error
(
"pybind11::handle::inc_ref() PyGILState_Check() failure."
);
}
#endif
Py_XINCREF
(
m_ptr
);
return
*
this
;
...
...
@@ -257,6 +265,11 @@ public:
this function automatically. Returns a reference to itself.
\endrst */
const
handle
&
dec_ref
()
const
&
{
#if defined(PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF)
if
(
m_ptr
!=
nullptr
&&
!
PyGILState_Check
())
{
throw
std
::
runtime_error
(
"pybind11::handle::dec_ref() PyGILState_Check() failure."
);
}
#endif
Py_XDECREF
(
m_ptr
);
return
*
this
;
}
...
...
@@ -623,12 +636,6 @@ inline std::string error_string() {
PYBIND11_NAMESPACE_END
(
detail
)
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4275 4251)
// warning C4275: An exported class was derived from a class that wasn't exported.
// Can be ignored when derived from a STL class.
#endif
/// Fetch and hold an error which was already set in Python. An instance of this is typically
/// thrown to propagate python-side errors back through C++ which can either be caught manually or
/// else falls back to the function dispatcher (which then raises the captured error back to
...
...
@@ -688,9 +695,6 @@ private:
/// crashes (undefined behavior) if the Python interpreter is finalizing.
static
void
m_fetched_error_deleter
(
detail
::
error_fetch_and_normalize
*
raw_ptr
);
};
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
/// Replaces the current Python error indicator with the chosen error, performing a
/// 'raise from' to indicate that the chosen error was caused by the original error.
...
...
@@ -893,10 +897,8 @@ object object_or_cast(T &&o);
// Match a PyObject*, which we want to convert directly to handle via its converting constructor
inline
handle
object_or_cast
(
PyObject
*
ptr
)
{
return
ptr
;
}
#if defined(_MSC_VER) && _MSC_VER < 1920
# pragma warning(push)
# pragma warning(disable : 4522) // warning C4522: multiple assignment operators specified
#endif
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_MSVC
(
4522
)
// warning C4522: multiple assignment operators specified
template
<
typename
Policy
>
class
accessor
:
public
object_api
<
accessor
<
Policy
>>
{
using
key_type
=
typename
Policy
::
key_type
;
...
...
@@ -960,9 +962,7 @@ private:
key_type
key
;
mutable
object
cache
;
};
#if defined(_MSC_VER) && _MSC_VER < 1920
# pragma warning(pop)
#endif
PYBIND11_WARNING_POP
PYBIND11_NAMESPACE_BEGIN
(
accessor_policies
)
struct
obj_attr
{
...
...
@@ -1702,7 +1702,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
template
<
typename
Unsigned
>
Unsigned
as_unsigned
(
PyObject
*
o
)
{
if
(
PYBIND11_SILENCE_MSVC_C4127
(
sizeof
(
Unsigned
)
<=
sizeof
(
unsigned
long
))
)
{
if
(
sizeof
(
Unsigned
)
<=
sizeof
(
unsigned
long
))
{
unsigned
long
v
=
PyLong_AsUnsignedLong
(
o
);
return
v
==
(
unsigned
long
)
-
1
&&
PyErr_Occurred
()
?
(
Unsigned
)
-
1
:
(
Unsigned
)
v
;
}
...
...
@@ -1719,7 +1719,7 @@ public:
template
<
typename
T
,
detail
::
enable_if_t
<
std
::
is_integral
<
T
>
::
value
,
int
>
=
0
>
// NOLINTNEXTLINE(google-explicit-constructor)
int_
(
T
value
)
{
if
(
PYBIND11_SILENCE_MSVC_C4127
(
sizeof
(
T
)
<=
sizeof
(
long
))
)
{
if
(
sizeof
(
T
)
<=
sizeof
(
long
))
{
if
(
std
::
is_signed
<
T
>::
value
)
{
m_ptr
=
PyLong_FromLong
((
long
)
value
);
}
else
{
...
...
include/pybind11/stl_bind.h
View file @
03764178
...
...
@@ -10,10 +10,13 @@
#pragma once
#include "detail/common.h"
#include "detail/type_caster_base.h"
#include "cast.h"
#include "operators.h"
#include <algorithm>
#include <sstream>
#include <type_traits>
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
PYBIND11_NAMESPACE_BEGIN
(
detail
)
...
...
@@ -636,18 +639,52 @@ auto map_if_insertion_operator(Class_ &cl, std::string const &name)
"Return the canonical string representation of this map."
);
}
template
<
typename
Map
>
template
<
typename
KeyType
>
struct
keys_view
{
Map
&
map
;
virtual
size_t
len
()
=
0
;
virtual
iterator
iter
()
=
0
;
virtual
bool
contains
(
const
KeyType
&
k
)
=
0
;
virtual
bool
contains
(
const
object
&
k
)
=
0
;
virtual
~
keys_view
()
=
default
;
};
template
<
typename
Map
>
template
<
typename
Map
pedType
>
struct
values_view
{
Map
&
map
;
virtual
size_t
len
()
=
0
;
virtual
iterator
iter
()
=
0
;
virtual
~
values_view
()
=
default
;
};
template
<
typename
Map
>
template
<
typename
KeyType
,
typename
MappedType
>
struct
items_view
{
virtual
size_t
len
()
=
0
;
virtual
iterator
iter
()
=
0
;
virtual
~
items_view
()
=
default
;
};
template
<
typename
Map
,
typename
KeysView
>
struct
KeysViewImpl
:
public
KeysView
{
explicit
KeysViewImpl
(
Map
&
map
)
:
map
(
map
)
{}
size_t
len
()
override
{
return
map
.
size
();
}
iterator
iter
()
override
{
return
make_key_iterator
(
map
.
begin
(),
map
.
end
());
}
bool
contains
(
const
typename
Map
::
key_type
&
k
)
override
{
return
map
.
find
(
k
)
!=
map
.
end
();
}
bool
contains
(
const
object
&
)
override
{
return
false
;
}
Map
&
map
;
};
template
<
typename
Map
,
typename
ValuesView
>
struct
ValuesViewImpl
:
public
ValuesView
{
explicit
ValuesViewImpl
(
Map
&
map
)
:
map
(
map
)
{}
size_t
len
()
override
{
return
map
.
size
();
}
iterator
iter
()
override
{
return
make_value_iterator
(
map
.
begin
(),
map
.
end
());
}
Map
&
map
;
};
template
<
typename
Map
,
typename
ItemsView
>
struct
ItemsViewImpl
:
public
ItemsView
{
explicit
ItemsViewImpl
(
Map
&
map
)
:
map
(
map
)
{}
size_t
len
()
override
{
return
map
.
size
();
}
iterator
iter
()
override
{
return
make_iterator
(
map
.
begin
(),
map
.
end
());
}
Map
&
map
;
};
...
...
@@ -657,9 +694,11 @@ template <typename Map, typename holder_type = std::unique_ptr<Map>, typename...
class_
<
Map
,
holder_type
>
bind_map
(
handle
scope
,
const
std
::
string
&
name
,
Args
&&
...
args
)
{
using
KeyType
=
typename
Map
::
key_type
;
using
MappedType
=
typename
Map
::
mapped_type
;
using
KeysView
=
detail
::
keys_view
<
Map
>
;
using
ValuesView
=
detail
::
values_view
<
Map
>
;
using
ItemsView
=
detail
::
items_view
<
Map
>
;
using
StrippedKeyType
=
detail
::
remove_cvref_t
<
KeyType
>
;
using
StrippedMappedType
=
detail
::
remove_cvref_t
<
MappedType
>
;
using
KeysView
=
detail
::
keys_view
<
StrippedKeyType
>
;
using
ValuesView
=
detail
::
values_view
<
StrippedMappedType
>
;
using
ItemsView
=
detail
::
items_view
<
StrippedKeyType
,
StrippedMappedType
>
;
using
Class_
=
class_
<
Map
,
holder_type
>
;
// If either type is a non-module-local bound type then make the map binding non-local as well;
...
...
@@ -673,12 +712,57 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
}
Class_
cl
(
scope
,
name
.
c_str
(),
pybind11
::
module_local
(
local
),
std
::
forward
<
Args
>
(
args
)...);
class_
<
KeysView
>
keys_view
(
scope
,
(
"KeysView["
+
name
+
"]"
).
c_str
(),
pybind11
::
module_local
(
local
));
class_
<
ValuesView
>
values_view
(
scope
,
(
"ValuesView["
+
name
+
"]"
).
c_str
(),
pybind11
::
module_local
(
local
));
class_
<
ItemsView
>
items_view
(
scope
,
(
"ItemsView["
+
name
+
"]"
).
c_str
(),
pybind11
::
module_local
(
local
));
static
constexpr
auto
key_type_descr
=
detail
::
make_caster
<
KeyType
>::
name
;
static
constexpr
auto
mapped_type_descr
=
detail
::
make_caster
<
MappedType
>::
name
;
std
::
string
key_type_name
(
key_type_descr
.
text
),
mapped_type_name
(
mapped_type_descr
.
text
);
// If key type isn't properly wrapped, fall back to C++ names
if
(
key_type_name
==
"%"
)
{
key_type_name
=
detail
::
type_info_description
(
typeid
(
KeyType
));
}
// Similarly for value type:
if
(
mapped_type_name
==
"%"
)
{
mapped_type_name
=
detail
::
type_info_description
(
typeid
(
MappedType
));
}
// Wrap KeysView[KeyType] if it wasn't already wrapped
if
(
!
detail
::
get_type_info
(
typeid
(
KeysView
)))
{
class_
<
KeysView
>
keys_view
(
scope
,
(
"KeysView["
+
key_type_name
+
"]"
).
c_str
(),
pybind11
::
module_local
(
local
));
keys_view
.
def
(
"__len__"
,
&
KeysView
::
len
);
keys_view
.
def
(
"__iter__"
,
&
KeysView
::
iter
,
keep_alive
<
0
,
1
>
()
/* Essential: keep view alive while iterator exists */
);
keys_view
.
def
(
"__contains__"
,
static_cast
<
bool
(
KeysView
::*
)(
const
KeyType
&
)
>
(
&
KeysView
::
contains
));
// Fallback for when the object is not of the key type
keys_view
.
def
(
"__contains__"
,
static_cast
<
bool
(
KeysView
::*
)(
const
object
&
)
>
(
&
KeysView
::
contains
));
}
// Similarly for ValuesView:
if
(
!
detail
::
get_type_info
(
typeid
(
ValuesView
)))
{
class_
<
ValuesView
>
values_view
(
scope
,
(
"ValuesView["
+
mapped_type_name
+
"]"
).
c_str
(),
pybind11
::
module_local
(
local
));
values_view
.
def
(
"__len__"
,
&
ValuesView
::
len
);
values_view
.
def
(
"__iter__"
,
&
ValuesView
::
iter
,
keep_alive
<
0
,
1
>
()
/* Essential: keep view alive while iterator exists */
);
}
// Similarly for ItemsView:
if
(
!
detail
::
get_type_info
(
typeid
(
ItemsView
)))
{
class_
<
ItemsView
>
items_view
(
scope
,
(
"ItemsView["
+
key_type_name
+
", "
).
append
(
mapped_type_name
+
"]"
).
c_str
(),
pybind11
::
module_local
(
local
));
items_view
.
def
(
"__len__"
,
&
ItemsView
::
len
);
items_view
.
def
(
"__iter__"
,
&
ItemsView
::
iter
,
keep_alive
<
0
,
1
>
()
/* Essential: keep view alive while iterator exists */
);
}
cl
.
def
(
init
<>
());
...
...
@@ -698,19 +782,25 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
cl
.
def
(
"keys"
,
[](
Map
&
m
)
{
return
KeysView
{
m
};
},
[](
Map
&
m
)
{
return
std
::
unique_ptr
<
KeysView
>
(
new
detail
::
KeysViewImpl
<
Map
,
KeysView
>
(
m
));
},
keep_alive
<
0
,
1
>
()
/* Essential: keep map alive while view exists */
);
cl
.
def
(
"values"
,
[](
Map
&
m
)
{
return
ValuesView
{
m
};
},
[](
Map
&
m
)
{
return
std
::
unique_ptr
<
ValuesView
>
(
new
detail
::
ValuesViewImpl
<
Map
,
ValuesView
>
(
m
));
},
keep_alive
<
0
,
1
>
()
/* Essential: keep map alive while view exists */
);
cl
.
def
(
"items"
,
[](
Map
&
m
)
{
return
ItemsView
{
m
};
},
[](
Map
&
m
)
{
return
std
::
unique_ptr
<
ItemsView
>
(
new
detail
::
ItemsViewImpl
<
Map
,
ItemsView
>
(
m
));
},
keep_alive
<
0
,
1
>
()
/* Essential: keep map alive while view exists */
);
...
...
@@ -749,36 +839,6 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
cl
.
def
(
"__len__"
,
&
Map
::
size
);
keys_view
.
def
(
"__len__"
,
[](
KeysView
&
view
)
{
return
view
.
map
.
size
();
});
keys_view
.
def
(
"__iter__"
,
[](
KeysView
&
view
)
{
return
make_key_iterator
(
view
.
map
.
begin
(),
view
.
map
.
end
());
},
keep_alive
<
0
,
1
>
()
/* Essential: keep view alive while iterator exists */
);
keys_view
.
def
(
"__contains__"
,
[](
KeysView
&
view
,
const
KeyType
&
k
)
->
bool
{
auto
it
=
view
.
map
.
find
(
k
);
if
(
it
==
view
.
map
.
end
())
{
return
false
;
}
return
true
;
});
// Fallback for when the object is not of the key type
keys_view
.
def
(
"__contains__"
,
[](
KeysView
&
,
const
object
&
)
->
bool
{
return
false
;
});
values_view
.
def
(
"__len__"
,
[](
ValuesView
&
view
)
{
return
view
.
map
.
size
();
});
values_view
.
def
(
"__iter__"
,
[](
ValuesView
&
view
)
{
return
make_value_iterator
(
view
.
map
.
begin
(),
view
.
map
.
end
());
},
keep_alive
<
0
,
1
>
()
/* Essential: keep view alive while iterator exists */
);
items_view
.
def
(
"__len__"
,
[](
ItemsView
&
view
)
{
return
view
.
map
.
size
();
});
items_view
.
def
(
"__iter__"
,
[](
ItemsView
&
view
)
{
return
make_iterator
(
view
.
map
.
begin
(),
view
.
map
.
end
());
},
keep_alive
<
0
,
1
>
()
/* Essential: keep view alive while iterator exists */
);
return
cl
;
}
...
...
pybind11/_version.py
View file @
03764178
...
...
@@ -8,5 +8,5 @@ def _to_int(s: str) -> Union[int, str]:
return
s
__version__
=
"2.10.
1
"
__version__
=
"2.10.
2
"
version_info
=
tuple
(
_to_int
(
s
)
for
s
in
__version__
.
split
(
"."
))
setup.cfg
View file @
03764178
...
...
@@ -46,5 +46,5 @@ zip_safe = False
max-line-length = 120
show_source = True
exclude = .git, __pycache__, build, dist, docs, tools, venv
extend-ignore = E203, E722
, B903, B950
extend-select = B9
extend-ignore = E203, E722
extend-select = B9
02, B904
tests/CMakeLists.txt
View file @
03764178
...
...
@@ -128,7 +128,8 @@ set(PYBIND11_TEST_FILES
test_custom_type_casters
test_custom_type_setup
test_docstring_options
test_eigen
test_eigen_matrix
test_eigen_tensor
test_enum
test_eval
test_exceptions
...
...
@@ -233,7 +234,10 @@ list(GET PYBIND11_EIGEN_VERSION_AND_HASH 1 PYBIND11_EIGEN_VERSION_HASH)
# Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but
# keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed"
# skip message).
list
(
FIND PYBIND11_TEST_FILES test_eigen.cpp PYBIND11_TEST_FILES_EIGEN_I
)
list
(
FIND PYBIND11_TEST_FILES test_eigen_matrix.cpp PYBIND11_TEST_FILES_EIGEN_I
)
if
(
PYBIND11_TEST_FILES_EIGEN_I EQUAL -1
)
list
(
FIND PYBIND11_TEST_FILES test_eigen_tensor.cpp PYBIND11_TEST_FILES_EIGEN_I
)
endif
()
if
(
PYBIND11_TEST_FILES_EIGEN_I GREATER -1
)
# Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake).
# Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also
...
...
@@ -288,13 +292,34 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
set
(
EIGEN3_VERSION
${
EIGEN3_VERSION_STRING
}
)
endif
()
message
(
STATUS
"Building tests with Eigen v
${
EIGEN3_VERSION
}
"
)
if
(
NOT
(
CMAKE_CXX_COMPILER_ID STREQUAL
"GNU"
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0
))
tests_extra_targets
(
"test_eigen_tensor.py"
"eigen_tensor_avoid_stl_array"
)
endif
()
else
()
list
(
REMOVE_AT PYBIND11_TEST_FILES
${
PYBIND11_TEST_FILES_EIGEN_I
}
)
list
(
FIND PYBIND11_TEST_FILES test_eigen_matrix.cpp PYBIND11_TEST_FILES_EIGEN_I
)
if
(
PYBIND11_TEST_FILES_EIGEN_I GREATER -1
)
list
(
REMOVE_AT PYBIND11_TEST_FILES
${
PYBIND11_TEST_FILES_EIGEN_I
}
)
endif
()
list
(
FIND PYBIND11_TEST_FILES test_eigen_tensor.cpp PYBIND11_TEST_FILES_EIGEN_I
)
if
(
PYBIND11_TEST_FILES_EIGEN_I GREATER -1
)
list
(
REMOVE_AT PYBIND11_TEST_FILES
${
PYBIND11_TEST_FILES_EIGEN_I
}
)
endif
()
message
(
STATUS
"Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON on CMake 3.11+ to download"
)
endif
()
endif
()
# Some code doesn't support gcc 4
if
(
CMAKE_CXX_COMPILER_ID STREQUAL
"GNU"
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0
)
list
(
FIND PYBIND11_TEST_FILES test_eigen_tensor.cpp PYBIND11_TEST_FILES_EIGEN_I
)
if
(
PYBIND11_TEST_FILES_EIGEN_I GREATER -1
)
list
(
REMOVE_AT PYBIND11_TEST_FILES
${
PYBIND11_TEST_FILES_EIGEN_I
}
)
endif
()
endif
()
# Optional dependency for some tests (boost::variant is only supported with version >= 1.56)
find_package
(
Boost 1.56
)
...
...
tests/conftest.py
View file @
03764178
...
...
@@ -7,6 +7,8 @@ Adds docstring and exceptions message sanitizers.
import
contextlib
import
difflib
import
gc
import
multiprocessing
import
os
import
re
import
textwrap
...
...
@@ -15,6 +17,22 @@ import pytest
# Early diagnostic for failed imports
import
pybind11_tests
@
pytest
.
fixture
(
scope
=
"session"
,
autouse
=
True
)
def
always_forkserver_on_unix
():
if
os
.
name
==
"nt"
:
return
# Full background: https://github.com/pybind/pybind11/issues/4105#issuecomment-1301004592
# In a nutshell: fork() after starting threads == flakiness in the form of deadlocks.
# It is actually a well-known pitfall, unfortunately without guard rails.
# "forkserver" is more performant than "spawn" (~9s vs ~13s for tests/test_gil_scoped.py,
# visit the issuecomment link above for details).
# Windows does not have fork() and the associated pitfall, therefore it is best left
# running with defaults.
multiprocessing
.
set_start_method
(
"forkserver"
)
_long_marker
=
re
.
compile
(
r
"([0-9])L"
)
_hexadecimal
=
re
.
compile
(
r
"0x[0-9a-fA-F]+"
)
...
...
tests/eigen_tensor_avoid_stl_array.cpp
0 → 100644
View file @
03764178
/*
tests/eigen_tensor.cpp -- automatic conversion of Eigen Tensor
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#ifndef EIGEN_AVOID_STL_ARRAY
# define EIGEN_AVOID_STL_ARRAY
#endif
#include "test_eigen_tensor.inl"
PYBIND11_MODULE
(
eigen_tensor_avoid_stl_array
,
m
)
{
eigen_tensor_test
::
test_module
(
m
);
}
tests/extra_python_package/test_files.py
View file @
03764178
...
...
@@ -55,6 +55,11 @@ detail_headers = {
"include/pybind11/detail/typeid.h"
,
}
eigen_headers
=
{
"include/pybind11/eigen/matrix.h"
,
"include/pybind11/eigen/tensor.h"
,
}
stl_headers
=
{
"include/pybind11/stl/filesystem.h"
,
}
...
...
@@ -82,7 +87,7 @@ py_files = {
"setup_helpers.py"
,
}
headers
=
main_headers
|
detail_headers
|
stl_headers
headers
=
main_headers
|
detail_headers
|
eigen_headers
|
stl_headers
src_files
=
headers
|
cmake_files
|
pkgconfig_files
all_files
=
src_files
|
py_files
...
...
@@ -92,6 +97,7 @@ sdist_files = {
"pybind11/include"
,
"pybind11/include/pybind11"
,
"pybind11/include/pybind11/detail"
,
"pybind11/include/pybind11/eigen"
,
"pybind11/include/pybind11/stl"
,
"pybind11/share"
,
"pybind11/share/cmake"
,
...
...
tests/test_builtin_casters.cpp
View file @
03764178
...
...
@@ -73,6 +73,9 @@ PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END
(
pybind11
)
TEST_SUBMODULE
(
builtin_casters
,
m
)
{
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_MSVC
(
4127
)
// test_simple_string
m
.
def
(
"string_roundtrip"
,
[](
const
char
*
s
)
{
return
s
;
});
...
...
@@ -86,7 +89,7 @@ TEST_SUBMODULE(builtin_casters, m) {
std
::
wstring
wstr
;
wstr
.
push_back
(
0x61
);
// a
wstr
.
push_back
(
0x2e18
);
// ⸘
if
(
PYBIND11_SILENCE_MSVC_C4127
(
sizeof
(
wchar_t
)
==
2
)
)
{
if
(
sizeof
(
wchar_t
)
==
2
)
{
wstr
.
push_back
(
mathbfA16_1
);
wstr
.
push_back
(
mathbfA16_2
);
}
// 𝐀, utf16
...
...
@@ -113,7 +116,7 @@ TEST_SUBMODULE(builtin_casters, m) {
// Under Python 2.7, invalid unicode UTF-32 characters didn't appear to trigger
// UnicodeDecodeError
m
.
def
(
"bad_utf32_string"
,
[
=
]()
{
return
std
::
u32string
({
a32
,
char32_t
(
0xd800
),
z32
});
});
if
(
PYBIND11_SILENCE_MSVC_C4127
(
sizeof
(
wchar_t
)
==
2
)
)
{
if
(
sizeof
(
wchar_t
)
==
2
)
{
m
.
def
(
"bad_wchar_string"
,
[
=
]()
{
return
std
::
wstring
({
wchar_t
(
0x61
),
wchar_t
(
0xd800
)});
});
...
...
@@ -384,4 +387,6 @@ TEST_SUBMODULE(builtin_casters, m) {
m
.
def
(
"takes_const_ref"
,
[](
const
ConstRefCasted
&
x
)
{
return
x
.
tag
;
});
m
.
def
(
"takes_const_ref_wrap"
,
[](
std
::
reference_wrapper
<
const
ConstRefCasted
>
x
)
{
return
x
.
get
().
tag
;
});
PYBIND11_WARNING_POP
}
tests/test_callbacks.cpp
View file @
03764178
...
...
@@ -240,4 +240,41 @@ TEST_SUBMODULE(callbacks, m) {
f
();
}
});
auto
*
custom_def
=
[]()
{
static
PyMethodDef
def
;
def
.
ml_name
=
"example_name"
;
def
.
ml_doc
=
"Example doc"
;
def
.
ml_meth
=
[](
PyObject
*
,
PyObject
*
args
)
->
PyObject
*
{
if
(
PyTuple_Size
(
args
)
!=
1
)
{
throw
std
::
runtime_error
(
"Invalid number of arguments for example_name"
);
}
PyObject
*
first
=
PyTuple_GetItem
(
args
,
0
);
if
(
!
PyLong_Check
(
first
))
{
throw
std
::
runtime_error
(
"Invalid argument to example_name"
);
}
auto
result
=
py
::
cast
(
PyLong_AsLong
(
first
)
*
9
);
return
result
.
release
().
ptr
();
};
def
.
ml_flags
=
METH_VARARGS
;
return
&
def
;
}();
// rec_capsule with name that has the same value (but not pointer) as our internal one
// This capsule should be detected by our code as foreign and not inspected as the pointers
// shouldn't match
constexpr
const
char
*
rec_capsule_name
=
pybind11
::
detail
::
internals_function_record_capsule_name
;
py
::
capsule
rec_capsule
(
std
::
malloc
(
1
),
[](
void
*
data
)
{
std
::
free
(
data
);
});
rec_capsule
.
set_name
(
rec_capsule_name
);
m
.
add_object
(
"custom_function"
,
PyCFunction_New
(
custom_def
,
rec_capsule
.
ptr
()));
// This test requires a new ABI version to pass
#if PYBIND11_INTERNALS_VERSION > 4
// rec_capsule with nullptr name
py
::
capsule
rec_capsule2
(
std
::
malloc
(
1
),
[](
void
*
data
)
{
std
::
free
(
data
);
});
m
.
add_object
(
"custom_function2"
,
PyCFunction_New
(
custom_def
,
rec_capsule2
.
ptr
()));
#else
m
.
add_object
(
"custom_function2"
,
py
::
none
());
#endif
}
tests/test_callbacks.py
View file @
03764178
...
...
@@ -193,3 +193,16 @@ def test_callback_num_times():
if
len
(
rates
)
>
1
:
print
(
"Min Mean Max"
)
print
(
f
"
{
min
(
rates
):
6.3
f
}
{
sum
(
rates
)
/
len
(
rates
):
6.3
f
}
{
max
(
rates
):
6.3
f
}
"
)
def
test_custom_func
():
assert
m
.
custom_function
(
4
)
==
36
assert
m
.
roundtrip
(
m
.
custom_function
)(
4
)
==
36
@
pytest
.
mark
.
skipif
(
m
.
custom_function2
is
None
,
reason
=
"Current PYBIND11_INTERNALS_VERSION too low"
)
def
test_custom_func2
():
assert
m
.
custom_function2
(
3
)
==
27
assert
m
.
roundtrip
(
m
.
custom_function2
)(
3
)
==
27
tests/test_class.cpp
View file @
03764178
...
...
@@ -22,10 +22,8 @@
#include <utility>
#if defined(_MSC_VER)
# pragma warning(disable : 4324)
PYBIND11_WARNING_DISABLE_MSVC
(
4324
)
// warning C4324: structure was padded due to alignment specifier
#endif
// test_brace_initialization
struct
NoBraceInitialization
{
...
...
tests/test_constants_and_functions.cpp
View file @
03764178
...
...
@@ -52,15 +52,12 @@ int f1(int x) noexcept { return x + 1; }
#endif
int
f2
(
int
x
)
noexcept
(
true
)
{
return
x
+
2
;
}
int
f3
(
int
x
)
noexcept
(
false
)
{
return
x
+
3
;
}
#if defined(__GNUG__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated"
#endif
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_GCC
(
"-Wdeprecated"
)
PYBIND11_WARNING_DISABLE_CLANG
(
"-Wdeprecated"
)
// NOLINTNEXTLINE(modernize-use-noexcept)
int
f4
(
int
x
)
throw
()
{
return
x
+
4
;
}
// Deprecated equivalent to noexcept(true)
#if defined(__GNUG__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic pop
#endif
PYBIND11_WARNING_POP
struct
C
{
int
m1
(
int
x
)
noexcept
{
return
x
-
1
;
}
int
m2
(
int
x
)
const
noexcept
{
return
x
-
2
;
}
...
...
@@ -68,17 +65,14 @@ struct C {
int
m4
(
int
x
)
const
noexcept
(
true
)
{
return
x
-
4
;
}
int
m5
(
int
x
)
noexcept
(
false
)
{
return
x
-
5
;
}
int
m6
(
int
x
)
const
noexcept
(
false
)
{
return
x
-
6
;
}
#if defined(__GNUG__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated"
#endif
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_GCC
(
"-Wdeprecated"
)
PYBIND11_WARNING_DISABLE_CLANG
(
"-Wdeprecated"
)
// NOLINTNEXTLINE(modernize-use-noexcept)
int
m7
(
int
x
)
throw
()
{
return
x
-
7
;
}
// NOLINTNEXTLINE(modernize-use-noexcept)
int
m8
(
int
x
)
const
throw
()
{
return
x
-
8
;
}
#if defined(__GNUG__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic pop
#endif
PYBIND11_WARNING_POP
};
}
// namespace test_exc_sp
...
...
@@ -126,14 +120,12 @@ TEST_SUBMODULE(constants_and_functions, m) {
.
def
(
"m8"
,
&
C
::
m8
);
m
.
def
(
"f1"
,
f1
);
m
.
def
(
"f2"
,
f2
);
#if defined(__INTEL_COMPILER)
# pragma warning push
# pragma warning disable 878 // incompatible exception specifications
#endif
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_INTEL
(
878
)
// incompatible exception specifications
m
.
def
(
"f3"
,
f3
);
#if defined(__INTEL_COMPILER)
# pragma warning pop
#endif
PYBIND11_WARNING_POP
m
.
def
(
"f4"
,
f4
);
// test_function_record_leaks
...
...
tests/test_docstring_options.cpp
View file @
03764178
...
...
@@ -85,4 +85,57 @@ TEST_SUBMODULE(docstring_options, m) {
&
DocstringTestFoo
::
setValue
,
"This is a property docstring"
);
}
{
enum
class
DocstringTestEnum1
{
Member1
,
Member2
};
py
::
enum_
<
DocstringTestEnum1
>
(
m
,
"DocstringTestEnum1"
,
"Enum docstring"
)
.
value
(
"Member1"
,
DocstringTestEnum1
::
Member1
)
.
value
(
"Member2"
,
DocstringTestEnum1
::
Member2
);
}
{
py
::
options
options
;
options
.
enable_enum_members_docstring
();
enum
class
DocstringTestEnum2
{
Member1
,
Member2
};
py
::
enum_
<
DocstringTestEnum2
>
(
m
,
"DocstringTestEnum2"
,
"Enum docstring"
)
.
value
(
"Member1"
,
DocstringTestEnum2
::
Member1
)
.
value
(
"Member2"
,
DocstringTestEnum2
::
Member2
);
}
{
py
::
options
options
;
options
.
disable_enum_members_docstring
();
enum
class
DocstringTestEnum3
{
Member1
,
Member2
};
py
::
enum_
<
DocstringTestEnum3
>
(
m
,
"DocstringTestEnum3"
,
"Enum docstring"
)
.
value
(
"Member1"
,
DocstringTestEnum3
::
Member1
)
.
value
(
"Member2"
,
DocstringTestEnum3
::
Member2
);
}
{
py
::
options
options
;
options
.
disable_user_defined_docstrings
();
enum
class
DocstringTestEnum4
{
Member1
,
Member2
};
py
::
enum_
<
DocstringTestEnum4
>
(
m
,
"DocstringTestEnum4"
,
"Enum docstring"
)
.
value
(
"Member1"
,
DocstringTestEnum4
::
Member1
)
.
value
(
"Member2"
,
DocstringTestEnum4
::
Member2
);
}
{
py
::
options
options
;
options
.
disable_user_defined_docstrings
();
options
.
disable_enum_members_docstring
();
enum
class
DocstringTestEnum5
{
Member1
,
Member2
};
py
::
enum_
<
DocstringTestEnum5
>
(
m
,
"DocstringTestEnum5"
,
"Enum docstring"
)
.
value
(
"Member1"
,
DocstringTestEnum5
::
Member1
)
.
value
(
"Member2"
,
DocstringTestEnum5
::
Member2
);
}
}
Prev
1
2
3
4
Next
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