Spaces:
Sleeping
Sleeping
Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/applypatch-msg.sample +15 -15
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/commit-msg.sample +24 -24
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/fsmonitor-watchman.sample +174 -174
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/post-update.sample +8 -8
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-applypatch.sample +14 -14
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-commit.sample +49 -49
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-merge-commit.sample +13 -13
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-push.sample +53 -53
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-rebase.sample +169 -169
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-receive.sample +24 -24
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/prepare-commit-msg.sample +42 -42
- third_party/CityFlow/extern/pybind11/.git.bak/hooks/push-to-checkout.sample +78 -78
- third_party/CityFlow/extern/pybind11/tests/test_async.py +24 -24
- third_party/CityFlow/extern/pybind11/tests/test_buffers.cpp +259 -259
- third_party/CityFlow/extern/pybind11/tests/test_buffers.py +228 -228
- third_party/CityFlow/extern/pybind11/tests/test_builtin_casters.cpp +392 -392
- third_party/CityFlow/extern/pybind11/tests/test_builtin_casters.py +528 -528
- third_party/CityFlow/extern/pybind11/tests/test_call_policies.cpp +115 -115
- third_party/CityFlow/extern/pybind11/tests/test_call_policies.py +247 -247
- third_party/CityFlow/extern/pybind11/tests/test_callbacks.cpp +280 -280
- third_party/CityFlow/extern/pybind11/tests/test_callbacks.py +225 -225
- third_party/CityFlow/extern/pybind11/tests/test_chrono.cpp +81 -81
- third_party/CityFlow/extern/pybind11/tests/test_chrono.py +205 -205
- third_party/CityFlow/extern/pybind11/tests/test_class.cpp +657 -657
- third_party/CityFlow/extern/pybind11/tests/test_class.py +499 -499
- third_party/CityFlow/extern/pybind11/tests/test_const_name.cpp +55 -55
- third_party/CityFlow/extern/pybind11/tests/test_const_name.py +29 -29
- third_party/CityFlow/extern/pybind11/tests/test_constants_and_functions.cpp +158 -158
- third_party/CityFlow/extern/pybind11/tests/test_constants_and_functions.py +56 -56
- third_party/CityFlow/extern/pybind11/tests/test_copy_move.cpp +533 -533
- third_party/CityFlow/extern/pybind11/tests/test_copy_move.py +132 -132
- third_party/CityFlow/extern/pybind11/tests/test_custom_type_casters.cpp +221 -221
- third_party/CityFlow/extern/pybind11/tests/test_custom_type_casters.py +122 -122
- third_party/CityFlow/extern/pybind11/tests/test_custom_type_setup.cpp +41 -41
- third_party/CityFlow/extern/pybind11/tests/test_custom_type_setup.py +48 -48
- third_party/CityFlow/extern/pybind11/tests/test_docstring_options.cpp +141 -141
- third_party/CityFlow/extern/pybind11/tests/test_docstring_options.py +64 -64
- third_party/CityFlow/extern/pybind11/tests/test_eigen_matrix.cpp +445 -445
- third_party/CityFlow/extern/pybind11/tests/test_eigen_matrix.py +814 -814
- third_party/CityFlow/extern/pybind11/tests/test_eigen_tensor.cpp +18 -18
- third_party/CityFlow/extern/pybind11/tests/test_eigen_tensor.inl +333 -333
- third_party/CityFlow/extern/pybind11/tests/test_eigen_tensor.py +288 -288
- third_party/CityFlow/extern/pybind11/tests/test_enum.cpp +133 -133
- third_party/CityFlow/extern/pybind11/tests/test_enum.py +269 -269
- third_party/CityFlow/extern/pybind11/tests/test_eval.cpp +118 -118
- third_party/CityFlow/extern/pybind11/tests/test_eval.py +50 -50
- third_party/CityFlow/extern/pybind11/tests/test_eval_call.py +4 -4
- third_party/CityFlow/extern/pybind11/tests/test_exceptions.cpp +388 -388
- third_party/CityFlow/extern/pybind11/tests/test_exceptions.h +13 -13
- third_party/CityFlow/extern/pybind11/tests/test_exceptions.py +432 -432
third_party/CityFlow/extern/pybind11/.git.bak/hooks/applypatch-msg.sample
CHANGED
|
@@ -1,15 +1,15 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
#
|
| 3 |
-
# An example hook script to check the commit log message taken by
|
| 4 |
-
# applypatch from an e-mail message.
|
| 5 |
-
#
|
| 6 |
-
# The hook should exit with non-zero status after issuing an
|
| 7 |
-
# appropriate message if it wants to stop the commit. The hook is
|
| 8 |
-
# allowed to edit the commit message file.
|
| 9 |
-
#
|
| 10 |
-
# To enable this hook, rename this file to "applypatch-msg".
|
| 11 |
-
|
| 12 |
-
. git-sh-setup
|
| 13 |
-
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
| 14 |
-
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
| 15 |
-
:
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
#
|
| 3 |
+
# An example hook script to check the commit log message taken by
|
| 4 |
+
# applypatch from an e-mail message.
|
| 5 |
+
#
|
| 6 |
+
# The hook should exit with non-zero status after issuing an
|
| 7 |
+
# appropriate message if it wants to stop the commit. The hook is
|
| 8 |
+
# allowed to edit the commit message file.
|
| 9 |
+
#
|
| 10 |
+
# To enable this hook, rename this file to "applypatch-msg".
|
| 11 |
+
|
| 12 |
+
. git-sh-setup
|
| 13 |
+
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
| 14 |
+
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
| 15 |
+
:
|
third_party/CityFlow/extern/pybind11/.git.bak/hooks/commit-msg.sample
CHANGED
|
@@ -1,24 +1,24 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
#
|
| 3 |
-
# An example hook script to check the commit log message.
|
| 4 |
-
# Called by "git commit" with one argument, the name of the file
|
| 5 |
-
# that has the commit message. The hook should exit with non-zero
|
| 6 |
-
# status after issuing an appropriate message if it wants to stop the
|
| 7 |
-
# commit. The hook is allowed to edit the commit message file.
|
| 8 |
-
#
|
| 9 |
-
# To enable this hook, rename this file to "commit-msg".
|
| 10 |
-
|
| 11 |
-
# Uncomment the below to add a Signed-off-by line to the message.
|
| 12 |
-
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
| 13 |
-
# hook is more suited to it.
|
| 14 |
-
#
|
| 15 |
-
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
| 16 |
-
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
| 17 |
-
|
| 18 |
-
# This example catches duplicate Signed-off-by lines.
|
| 19 |
-
|
| 20 |
-
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
| 21 |
-
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
| 22 |
-
echo >&2 Duplicate Signed-off-by lines.
|
| 23 |
-
exit 1
|
| 24 |
-
}
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
#
|
| 3 |
+
# An example hook script to check the commit log message.
|
| 4 |
+
# Called by "git commit" with one argument, the name of the file
|
| 5 |
+
# that has the commit message. The hook should exit with non-zero
|
| 6 |
+
# status after issuing an appropriate message if it wants to stop the
|
| 7 |
+
# commit. The hook is allowed to edit the commit message file.
|
| 8 |
+
#
|
| 9 |
+
# To enable this hook, rename this file to "commit-msg".
|
| 10 |
+
|
| 11 |
+
# Uncomment the below to add a Signed-off-by line to the message.
|
| 12 |
+
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
| 13 |
+
# hook is more suited to it.
|
| 14 |
+
#
|
| 15 |
+
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
| 16 |
+
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
| 17 |
+
|
| 18 |
+
# This example catches duplicate Signed-off-by lines.
|
| 19 |
+
|
| 20 |
+
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
| 21 |
+
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
| 22 |
+
echo >&2 Duplicate Signed-off-by lines.
|
| 23 |
+
exit 1
|
| 24 |
+
}
|
third_party/CityFlow/extern/pybind11/.git.bak/hooks/fsmonitor-watchman.sample
CHANGED
|
@@ -1,174 +1,174 @@
|
|
| 1 |
-
#!/usr/bin/perl
|
| 2 |
-
|
| 3 |
-
use strict;
|
| 4 |
-
use warnings;
|
| 5 |
-
use IPC::Open2;
|
| 6 |
-
|
| 7 |
-
# An example hook script to integrate Watchman
|
| 8 |
-
# (https://facebook.github.io/watchman/) with git to speed up detecting
|
| 9 |
-
# new and modified files.
|
| 10 |
-
#
|
| 11 |
-
# The hook is passed a version (currently 2) and last update token
|
| 12 |
-
# formatted as a string and outputs to stdout a new update token and
|
| 13 |
-
# all files that have been modified since the update token. Paths must
|
| 14 |
-
# be relative to the root of the working tree and separated by a single NUL.
|
| 15 |
-
#
|
| 16 |
-
# To enable this hook, rename this file to "query-watchman" and set
|
| 17 |
-
# 'git config core.fsmonitor .git/hooks/query-watchman'
|
| 18 |
-
#
|
| 19 |
-
my ($version, $last_update_token) = @ARGV;
|
| 20 |
-
|
| 21 |
-
# Uncomment for debugging
|
| 22 |
-
# print STDERR "$0 $version $last_update_token\n";
|
| 23 |
-
|
| 24 |
-
# Check the hook interface version
|
| 25 |
-
if ($version ne 2) {
|
| 26 |
-
die "Unsupported query-fsmonitor hook version '$version'.\n" .
|
| 27 |
-
"Falling back to scanning...\n";
|
| 28 |
-
}
|
| 29 |
-
|
| 30 |
-
my $git_work_tree = get_working_dir();
|
| 31 |
-
|
| 32 |
-
my $retry = 1;
|
| 33 |
-
|
| 34 |
-
my $json_pkg;
|
| 35 |
-
eval {
|
| 36 |
-
require JSON::XS;
|
| 37 |
-
$json_pkg = "JSON::XS";
|
| 38 |
-
1;
|
| 39 |
-
} or do {
|
| 40 |
-
require JSON::PP;
|
| 41 |
-
$json_pkg = "JSON::PP";
|
| 42 |
-
};
|
| 43 |
-
|
| 44 |
-
launch_watchman();
|
| 45 |
-
|
| 46 |
-
sub launch_watchman {
|
| 47 |
-
my $o = watchman_query();
|
| 48 |
-
if (is_work_tree_watched($o)) {
|
| 49 |
-
output_result($o->{clock}, @{$o->{files}});
|
| 50 |
-
}
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
sub output_result {
|
| 54 |
-
my ($clockid, @files) = @_;
|
| 55 |
-
|
| 56 |
-
# Uncomment for debugging watchman output
|
| 57 |
-
# open (my $fh, ">", ".git/watchman-output.out");
|
| 58 |
-
# binmode $fh, ":utf8";
|
| 59 |
-
# print $fh "$clockid\n@files\n";
|
| 60 |
-
# close $fh;
|
| 61 |
-
|
| 62 |
-
binmode STDOUT, ":utf8";
|
| 63 |
-
print $clockid;
|
| 64 |
-
print "\0";
|
| 65 |
-
local $, = "\0";
|
| 66 |
-
print @files;
|
| 67 |
-
}
|
| 68 |
-
|
| 69 |
-
sub watchman_clock {
|
| 70 |
-
my $response = qx/watchman clock "$git_work_tree"/;
|
| 71 |
-
die "Failed to get clock id on '$git_work_tree'.\n" .
|
| 72 |
-
"Falling back to scanning...\n" if $? != 0;
|
| 73 |
-
|
| 74 |
-
return $json_pkg->new->utf8->decode($response);
|
| 75 |
-
}
|
| 76 |
-
|
| 77 |
-
sub watchman_query {
|
| 78 |
-
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
|
| 79 |
-
or die "open2() failed: $!\n" .
|
| 80 |
-
"Falling back to scanning...\n";
|
| 81 |
-
|
| 82 |
-
# In the query expression below we're asking for names of files that
|
| 83 |
-
# changed since $last_update_token but not from the .git folder.
|
| 84 |
-
#
|
| 85 |
-
# To accomplish this, we're using the "since" generator to use the
|
| 86 |
-
# recency index to select candidate nodes and "fields" to limit the
|
| 87 |
-
# output to file names only. Then we're using the "expression" term to
|
| 88 |
-
# further constrain the results.
|
| 89 |
-
my $last_update_line = "";
|
| 90 |
-
if (substr($last_update_token, 0, 1) eq "c") {
|
| 91 |
-
$last_update_token = "\"$last_update_token\"";
|
| 92 |
-
$last_update_line = qq[\n"since": $last_update_token,];
|
| 93 |
-
}
|
| 94 |
-
my $query = <<" END";
|
| 95 |
-
["query", "$git_work_tree", {$last_update_line
|
| 96 |
-
"fields": ["name"],
|
| 97 |
-
"expression": ["not", ["dirname", ".git"]]
|
| 98 |
-
}]
|
| 99 |
-
END
|
| 100 |
-
|
| 101 |
-
# Uncomment for debugging the watchman query
|
| 102 |
-
# open (my $fh, ">", ".git/watchman-query.json");
|
| 103 |
-
# print $fh $query;
|
| 104 |
-
# close $fh;
|
| 105 |
-
|
| 106 |
-
print CHLD_IN $query;
|
| 107 |
-
close CHLD_IN;
|
| 108 |
-
my $response = do {local $/; <CHLD_OUT>};
|
| 109 |
-
|
| 110 |
-
# Uncomment for debugging the watch response
|
| 111 |
-
# open ($fh, ">", ".git/watchman-response.json");
|
| 112 |
-
# print $fh $response;
|
| 113 |
-
# close $fh;
|
| 114 |
-
|
| 115 |
-
die "Watchman: command returned no output.\n" .
|
| 116 |
-
"Falling back to scanning...\n" if $response eq "";
|
| 117 |
-
die "Watchman: command returned invalid output: $response\n" .
|
| 118 |
-
"Falling back to scanning...\n" unless $response =~ /^\{/;
|
| 119 |
-
|
| 120 |
-
return $json_pkg->new->utf8->decode($response);
|
| 121 |
-
}
|
| 122 |
-
|
| 123 |
-
sub is_work_tree_watched {
|
| 124 |
-
my ($output) = @_;
|
| 125 |
-
my $error = $output->{error};
|
| 126 |
-
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
|
| 127 |
-
$retry--;
|
| 128 |
-
my $response = qx/watchman watch "$git_work_tree"/;
|
| 129 |
-
die "Failed to make watchman watch '$git_work_tree'.\n" .
|
| 130 |
-
"Falling back to scanning...\n" if $? != 0;
|
| 131 |
-
$output = $json_pkg->new->utf8->decode($response);
|
| 132 |
-
$error = $output->{error};
|
| 133 |
-
die "Watchman: $error.\n" .
|
| 134 |
-
"Falling back to scanning...\n" if $error;
|
| 135 |
-
|
| 136 |
-
# Uncomment for debugging watchman output
|
| 137 |
-
# open (my $fh, ">", ".git/watchman-output.out");
|
| 138 |
-
# close $fh;
|
| 139 |
-
|
| 140 |
-
# Watchman will always return all files on the first query so
|
| 141 |
-
# return the fast "everything is dirty" flag to git and do the
|
| 142 |
-
# Watchman query just to get it over with now so we won't pay
|
| 143 |
-
# the cost in git to look up each individual file.
|
| 144 |
-
my $o = watchman_clock();
|
| 145 |
-
$error = $output->{error};
|
| 146 |
-
|
| 147 |
-
die "Watchman: $error.\n" .
|
| 148 |
-
"Falling back to scanning...\n" if $error;
|
| 149 |
-
|
| 150 |
-
output_result($o->{clock}, ("/"));
|
| 151 |
-
$last_update_token = $o->{clock};
|
| 152 |
-
|
| 153 |
-
eval { launch_watchman() };
|
| 154 |
-
return 0;
|
| 155 |
-
}
|
| 156 |
-
|
| 157 |
-
die "Watchman: $error.\n" .
|
| 158 |
-
"Falling back to scanning...\n" if $error;
|
| 159 |
-
|
| 160 |
-
return 1;
|
| 161 |
-
}
|
| 162 |
-
|
| 163 |
-
sub get_working_dir {
|
| 164 |
-
my $working_dir;
|
| 165 |
-
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
|
| 166 |
-
$working_dir = Win32::GetCwd();
|
| 167 |
-
$working_dir =~ tr/\\/\//;
|
| 168 |
-
} else {
|
| 169 |
-
require Cwd;
|
| 170 |
-
$working_dir = Cwd::cwd();
|
| 171 |
-
}
|
| 172 |
-
|
| 173 |
-
return $working_dir;
|
| 174 |
-
}
|
|
|
|
| 1 |
+
#!/usr/bin/perl
|
| 2 |
+
|
| 3 |
+
use strict;
|
| 4 |
+
use warnings;
|
| 5 |
+
use IPC::Open2;
|
| 6 |
+
|
| 7 |
+
# An example hook script to integrate Watchman
|
| 8 |
+
# (https://facebook.github.io/watchman/) with git to speed up detecting
|
| 9 |
+
# new and modified files.
|
| 10 |
+
#
|
| 11 |
+
# The hook is passed a version (currently 2) and last update token
|
| 12 |
+
# formatted as a string and outputs to stdout a new update token and
|
| 13 |
+
# all files that have been modified since the update token. Paths must
|
| 14 |
+
# be relative to the root of the working tree and separated by a single NUL.
|
| 15 |
+
#
|
| 16 |
+
# To enable this hook, rename this file to "query-watchman" and set
|
| 17 |
+
# 'git config core.fsmonitor .git/hooks/query-watchman'
|
| 18 |
+
#
|
| 19 |
+
my ($version, $last_update_token) = @ARGV;
|
| 20 |
+
|
| 21 |
+
# Uncomment for debugging
|
| 22 |
+
# print STDERR "$0 $version $last_update_token\n";
|
| 23 |
+
|
| 24 |
+
# Check the hook interface version
|
| 25 |
+
if ($version ne 2) {
|
| 26 |
+
die "Unsupported query-fsmonitor hook version '$version'.\n" .
|
| 27 |
+
"Falling back to scanning...\n";
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
my $git_work_tree = get_working_dir();
|
| 31 |
+
|
| 32 |
+
my $retry = 1;
|
| 33 |
+
|
| 34 |
+
my $json_pkg;
|
| 35 |
+
eval {
|
| 36 |
+
require JSON::XS;
|
| 37 |
+
$json_pkg = "JSON::XS";
|
| 38 |
+
1;
|
| 39 |
+
} or do {
|
| 40 |
+
require JSON::PP;
|
| 41 |
+
$json_pkg = "JSON::PP";
|
| 42 |
+
};
|
| 43 |
+
|
| 44 |
+
launch_watchman();
|
| 45 |
+
|
| 46 |
+
sub launch_watchman {
|
| 47 |
+
my $o = watchman_query();
|
| 48 |
+
if (is_work_tree_watched($o)) {
|
| 49 |
+
output_result($o->{clock}, @{$o->{files}});
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
sub output_result {
|
| 54 |
+
my ($clockid, @files) = @_;
|
| 55 |
+
|
| 56 |
+
# Uncomment for debugging watchman output
|
| 57 |
+
# open (my $fh, ">", ".git/watchman-output.out");
|
| 58 |
+
# binmode $fh, ":utf8";
|
| 59 |
+
# print $fh "$clockid\n@files\n";
|
| 60 |
+
# close $fh;
|
| 61 |
+
|
| 62 |
+
binmode STDOUT, ":utf8";
|
| 63 |
+
print $clockid;
|
| 64 |
+
print "\0";
|
| 65 |
+
local $, = "\0";
|
| 66 |
+
print @files;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
sub watchman_clock {
|
| 70 |
+
my $response = qx/watchman clock "$git_work_tree"/;
|
| 71 |
+
die "Failed to get clock id on '$git_work_tree'.\n" .
|
| 72 |
+
"Falling back to scanning...\n" if $? != 0;
|
| 73 |
+
|
| 74 |
+
return $json_pkg->new->utf8->decode($response);
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
sub watchman_query {
|
| 78 |
+
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
|
| 79 |
+
or die "open2() failed: $!\n" .
|
| 80 |
+
"Falling back to scanning...\n";
|
| 81 |
+
|
| 82 |
+
# In the query expression below we're asking for names of files that
|
| 83 |
+
# changed since $last_update_token but not from the .git folder.
|
| 84 |
+
#
|
| 85 |
+
# To accomplish this, we're using the "since" generator to use the
|
| 86 |
+
# recency index to select candidate nodes and "fields" to limit the
|
| 87 |
+
# output to file names only. Then we're using the "expression" term to
|
| 88 |
+
# further constrain the results.
|
| 89 |
+
my $last_update_line = "";
|
| 90 |
+
if (substr($last_update_token, 0, 1) eq "c") {
|
| 91 |
+
$last_update_token = "\"$last_update_token\"";
|
| 92 |
+
$last_update_line = qq[\n"since": $last_update_token,];
|
| 93 |
+
}
|
| 94 |
+
my $query = <<" END";
|
| 95 |
+
["query", "$git_work_tree", {$last_update_line
|
| 96 |
+
"fields": ["name"],
|
| 97 |
+
"expression": ["not", ["dirname", ".git"]]
|
| 98 |
+
}]
|
| 99 |
+
END
|
| 100 |
+
|
| 101 |
+
# Uncomment for debugging the watchman query
|
| 102 |
+
# open (my $fh, ">", ".git/watchman-query.json");
|
| 103 |
+
# print $fh $query;
|
| 104 |
+
# close $fh;
|
| 105 |
+
|
| 106 |
+
print CHLD_IN $query;
|
| 107 |
+
close CHLD_IN;
|
| 108 |
+
my $response = do {local $/; <CHLD_OUT>};
|
| 109 |
+
|
| 110 |
+
# Uncomment for debugging the watch response
|
| 111 |
+
# open ($fh, ">", ".git/watchman-response.json");
|
| 112 |
+
# print $fh $response;
|
| 113 |
+
# close $fh;
|
| 114 |
+
|
| 115 |
+
die "Watchman: command returned no output.\n" .
|
| 116 |
+
"Falling back to scanning...\n" if $response eq "";
|
| 117 |
+
die "Watchman: command returned invalid output: $response\n" .
|
| 118 |
+
"Falling back to scanning...\n" unless $response =~ /^\{/;
|
| 119 |
+
|
| 120 |
+
return $json_pkg->new->utf8->decode($response);
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
sub is_work_tree_watched {
|
| 124 |
+
my ($output) = @_;
|
| 125 |
+
my $error = $output->{error};
|
| 126 |
+
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
|
| 127 |
+
$retry--;
|
| 128 |
+
my $response = qx/watchman watch "$git_work_tree"/;
|
| 129 |
+
die "Failed to make watchman watch '$git_work_tree'.\n" .
|
| 130 |
+
"Falling back to scanning...\n" if $? != 0;
|
| 131 |
+
$output = $json_pkg->new->utf8->decode($response);
|
| 132 |
+
$error = $output->{error};
|
| 133 |
+
die "Watchman: $error.\n" .
|
| 134 |
+
"Falling back to scanning...\n" if $error;
|
| 135 |
+
|
| 136 |
+
# Uncomment for debugging watchman output
|
| 137 |
+
# open (my $fh, ">", ".git/watchman-output.out");
|
| 138 |
+
# close $fh;
|
| 139 |
+
|
| 140 |
+
# Watchman will always return all files on the first query so
|
| 141 |
+
# return the fast "everything is dirty" flag to git and do the
|
| 142 |
+
# Watchman query just to get it over with now so we won't pay
|
| 143 |
+
# the cost in git to look up each individual file.
|
| 144 |
+
my $o = watchman_clock();
|
| 145 |
+
$error = $output->{error};
|
| 146 |
+
|
| 147 |
+
die "Watchman: $error.\n" .
|
| 148 |
+
"Falling back to scanning...\n" if $error;
|
| 149 |
+
|
| 150 |
+
output_result($o->{clock}, ("/"));
|
| 151 |
+
$last_update_token = $o->{clock};
|
| 152 |
+
|
| 153 |
+
eval { launch_watchman() };
|
| 154 |
+
return 0;
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
die "Watchman: $error.\n" .
|
| 158 |
+
"Falling back to scanning...\n" if $error;
|
| 159 |
+
|
| 160 |
+
return 1;
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
sub get_working_dir {
|
| 164 |
+
my $working_dir;
|
| 165 |
+
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
|
| 166 |
+
$working_dir = Win32::GetCwd();
|
| 167 |
+
$working_dir =~ tr/\\/\//;
|
| 168 |
+
} else {
|
| 169 |
+
require Cwd;
|
| 170 |
+
$working_dir = Cwd::cwd();
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
return $working_dir;
|
| 174 |
+
}
|
third_party/CityFlow/extern/pybind11/.git.bak/hooks/post-update.sample
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
#
|
| 3 |
-
# An example hook script to prepare a packed repository for use over
|
| 4 |
-
# dumb transports.
|
| 5 |
-
#
|
| 6 |
-
# To enable this hook, rename this file to "post-update".
|
| 7 |
-
|
| 8 |
-
exec git update-server-info
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
#
|
| 3 |
+
# An example hook script to prepare a packed repository for use over
|
| 4 |
+
# dumb transports.
|
| 5 |
+
#
|
| 6 |
+
# To enable this hook, rename this file to "post-update".
|
| 7 |
+
|
| 8 |
+
exec git update-server-info
|
third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-applypatch.sample
CHANGED
|
@@ -1,14 +1,14 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
#
|
| 3 |
-
# An example hook script to verify what is about to be committed
|
| 4 |
-
# by applypatch from an e-mail message.
|
| 5 |
-
#
|
| 6 |
-
# The hook should exit with non-zero status after issuing an
|
| 7 |
-
# appropriate message if it wants to stop the commit.
|
| 8 |
-
#
|
| 9 |
-
# To enable this hook, rename this file to "pre-applypatch".
|
| 10 |
-
|
| 11 |
-
. git-sh-setup
|
| 12 |
-
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
| 13 |
-
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
| 14 |
-
:
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
#
|
| 3 |
+
# An example hook script to verify what is about to be committed
|
| 4 |
+
# by applypatch from an e-mail message.
|
| 5 |
+
#
|
| 6 |
+
# The hook should exit with non-zero status after issuing an
|
| 7 |
+
# appropriate message if it wants to stop the commit.
|
| 8 |
+
#
|
| 9 |
+
# To enable this hook, rename this file to "pre-applypatch".
|
| 10 |
+
|
| 11 |
+
. git-sh-setup
|
| 12 |
+
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
| 13 |
+
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
| 14 |
+
:
|
third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-commit.sample
CHANGED
|
@@ -1,49 +1,49 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
#
|
| 3 |
-
# An example hook script to verify what is about to be committed.
|
| 4 |
-
# Called by "git commit" with no arguments. The hook should
|
| 5 |
-
# exit with non-zero status after issuing an appropriate message if
|
| 6 |
-
# it wants to stop the commit.
|
| 7 |
-
#
|
| 8 |
-
# To enable this hook, rename this file to "pre-commit".
|
| 9 |
-
|
| 10 |
-
if git rev-parse --verify HEAD >/dev/null 2>&1
|
| 11 |
-
then
|
| 12 |
-
against=HEAD
|
| 13 |
-
else
|
| 14 |
-
# Initial commit: diff against an empty tree object
|
| 15 |
-
against=$(git hash-object -t tree /dev/null)
|
| 16 |
-
fi
|
| 17 |
-
|
| 18 |
-
# If you want to allow non-ASCII filenames set this variable to true.
|
| 19 |
-
allownonascii=$(git config --type=bool hooks.allownonascii)
|
| 20 |
-
|
| 21 |
-
# Redirect output to stderr.
|
| 22 |
-
exec 1>&2
|
| 23 |
-
|
| 24 |
-
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
| 25 |
-
# them from being added to the repository. We exploit the fact that the
|
| 26 |
-
# printable range starts at the space character and ends with tilde.
|
| 27 |
-
if [ "$allownonascii" != "true" ] &&
|
| 28 |
-
# Note that the use of brackets around a tr range is ok here, (it's
|
| 29 |
-
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
| 30 |
-
# the square bracket bytes happen to fall in the designated range.
|
| 31 |
-
test $(git diff-index --cached --name-only --diff-filter=A -z $against |
|
| 32 |
-
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
| 33 |
-
then
|
| 34 |
-
cat <<\EOF
|
| 35 |
-
Error: Attempt to add a non-ASCII file name.
|
| 36 |
-
|
| 37 |
-
This can cause problems if you want to work with people on other platforms.
|
| 38 |
-
|
| 39 |
-
To be portable it is advisable to rename the file.
|
| 40 |
-
|
| 41 |
-
If you know what you are doing you can disable this check using:
|
| 42 |
-
|
| 43 |
-
git config hooks.allownonascii true
|
| 44 |
-
EOF
|
| 45 |
-
exit 1
|
| 46 |
-
fi
|
| 47 |
-
|
| 48 |
-
# If there are whitespace errors, print the offending file names and fail.
|
| 49 |
-
exec git diff-index --check --cached $against --
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
#
|
| 3 |
+
# An example hook script to verify what is about to be committed.
|
| 4 |
+
# Called by "git commit" with no arguments. The hook should
|
| 5 |
+
# exit with non-zero status after issuing an appropriate message if
|
| 6 |
+
# it wants to stop the commit.
|
| 7 |
+
#
|
| 8 |
+
# To enable this hook, rename this file to "pre-commit".
|
| 9 |
+
|
| 10 |
+
if git rev-parse --verify HEAD >/dev/null 2>&1
|
| 11 |
+
then
|
| 12 |
+
against=HEAD
|
| 13 |
+
else
|
| 14 |
+
# Initial commit: diff against an empty tree object
|
| 15 |
+
against=$(git hash-object -t tree /dev/null)
|
| 16 |
+
fi
|
| 17 |
+
|
| 18 |
+
# If you want to allow non-ASCII filenames set this variable to true.
|
| 19 |
+
allownonascii=$(git config --type=bool hooks.allownonascii)
|
| 20 |
+
|
| 21 |
+
# Redirect output to stderr.
|
| 22 |
+
exec 1>&2
|
| 23 |
+
|
| 24 |
+
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
| 25 |
+
# them from being added to the repository. We exploit the fact that the
|
| 26 |
+
# printable range starts at the space character and ends with tilde.
|
| 27 |
+
if [ "$allownonascii" != "true" ] &&
|
| 28 |
+
# Note that the use of brackets around a tr range is ok here, (it's
|
| 29 |
+
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
| 30 |
+
# the square bracket bytes happen to fall in the designated range.
|
| 31 |
+
test $(git diff-index --cached --name-only --diff-filter=A -z $against |
|
| 32 |
+
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
| 33 |
+
then
|
| 34 |
+
cat <<\EOF
|
| 35 |
+
Error: Attempt to add a non-ASCII file name.
|
| 36 |
+
|
| 37 |
+
This can cause problems if you want to work with people on other platforms.
|
| 38 |
+
|
| 39 |
+
To be portable it is advisable to rename the file.
|
| 40 |
+
|
| 41 |
+
If you know what you are doing you can disable this check using:
|
| 42 |
+
|
| 43 |
+
git config hooks.allownonascii true
|
| 44 |
+
EOF
|
| 45 |
+
exit 1
|
| 46 |
+
fi
|
| 47 |
+
|
| 48 |
+
# If there are whitespace errors, print the offending file names and fail.
|
| 49 |
+
exec git diff-index --check --cached $against --
|
third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-merge-commit.sample
CHANGED
|
@@ -1,13 +1,13 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
#
|
| 3 |
-
# An example hook script to verify what is about to be committed.
|
| 4 |
-
# Called by "git merge" with no arguments. The hook should
|
| 5 |
-
# exit with non-zero status after issuing an appropriate message to
|
| 6 |
-
# stderr if it wants to stop the merge commit.
|
| 7 |
-
#
|
| 8 |
-
# To enable this hook, rename this file to "pre-merge-commit".
|
| 9 |
-
|
| 10 |
-
. git-sh-setup
|
| 11 |
-
test -x "$GIT_DIR/hooks/pre-commit" &&
|
| 12 |
-
exec "$GIT_DIR/hooks/pre-commit"
|
| 13 |
-
:
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
#
|
| 3 |
+
# An example hook script to verify what is about to be committed.
|
| 4 |
+
# Called by "git merge" with no arguments. The hook should
|
| 5 |
+
# exit with non-zero status after issuing an appropriate message to
|
| 6 |
+
# stderr if it wants to stop the merge commit.
|
| 7 |
+
#
|
| 8 |
+
# To enable this hook, rename this file to "pre-merge-commit".
|
| 9 |
+
|
| 10 |
+
. git-sh-setup
|
| 11 |
+
test -x "$GIT_DIR/hooks/pre-commit" &&
|
| 12 |
+
exec "$GIT_DIR/hooks/pre-commit"
|
| 13 |
+
:
|
third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-push.sample
CHANGED
|
@@ -1,53 +1,53 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
|
| 3 |
-
# An example hook script to verify what is about to be pushed. Called by "git
|
| 4 |
-
# push" after it has checked the remote status, but before anything has been
|
| 5 |
-
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
| 6 |
-
#
|
| 7 |
-
# This hook is called with the following parameters:
|
| 8 |
-
#
|
| 9 |
-
# $1 -- Name of the remote to which the push is being done
|
| 10 |
-
# $2 -- URL to which the push is being done
|
| 11 |
-
#
|
| 12 |
-
# If pushing without using a named remote those arguments will be equal.
|
| 13 |
-
#
|
| 14 |
-
# Information about the commits which are being pushed is supplied as lines to
|
| 15 |
-
# the standard input in the form:
|
| 16 |
-
#
|
| 17 |
-
# <local ref> <local oid> <remote ref> <remote oid>
|
| 18 |
-
#
|
| 19 |
-
# This sample shows how to prevent push of commits where the log message starts
|
| 20 |
-
# with "WIP" (work in progress).
|
| 21 |
-
|
| 22 |
-
remote="$1"
|
| 23 |
-
url="$2"
|
| 24 |
-
|
| 25 |
-
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
| 26 |
-
|
| 27 |
-
while read local_ref local_oid remote_ref remote_oid
|
| 28 |
-
do
|
| 29 |
-
if test "$local_oid" = "$zero"
|
| 30 |
-
then
|
| 31 |
-
# Handle delete
|
| 32 |
-
:
|
| 33 |
-
else
|
| 34 |
-
if test "$remote_oid" = "$zero"
|
| 35 |
-
then
|
| 36 |
-
# New branch, examine all commits
|
| 37 |
-
range="$local_oid"
|
| 38 |
-
else
|
| 39 |
-
# Update to existing branch, examine new commits
|
| 40 |
-
range="$remote_oid..$local_oid"
|
| 41 |
-
fi
|
| 42 |
-
|
| 43 |
-
# Check for WIP commit
|
| 44 |
-
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
|
| 45 |
-
if test -n "$commit"
|
| 46 |
-
then
|
| 47 |
-
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
| 48 |
-
exit 1
|
| 49 |
-
fi
|
| 50 |
-
fi
|
| 51 |
-
done
|
| 52 |
-
|
| 53 |
-
exit 0
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
|
| 3 |
+
# An example hook script to verify what is about to be pushed. Called by "git
|
| 4 |
+
# push" after it has checked the remote status, but before anything has been
|
| 5 |
+
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
| 6 |
+
#
|
| 7 |
+
# This hook is called with the following parameters:
|
| 8 |
+
#
|
| 9 |
+
# $1 -- Name of the remote to which the push is being done
|
| 10 |
+
# $2 -- URL to which the push is being done
|
| 11 |
+
#
|
| 12 |
+
# If pushing without using a named remote those arguments will be equal.
|
| 13 |
+
#
|
| 14 |
+
# Information about the commits which are being pushed is supplied as lines to
|
| 15 |
+
# the standard input in the form:
|
| 16 |
+
#
|
| 17 |
+
# <local ref> <local oid> <remote ref> <remote oid>
|
| 18 |
+
#
|
| 19 |
+
# This sample shows how to prevent push of commits where the log message starts
|
| 20 |
+
# with "WIP" (work in progress).
|
| 21 |
+
|
| 22 |
+
remote="$1"
|
| 23 |
+
url="$2"
|
| 24 |
+
|
| 25 |
+
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
| 26 |
+
|
| 27 |
+
while read local_ref local_oid remote_ref remote_oid
|
| 28 |
+
do
|
| 29 |
+
if test "$local_oid" = "$zero"
|
| 30 |
+
then
|
| 31 |
+
# Handle delete
|
| 32 |
+
:
|
| 33 |
+
else
|
| 34 |
+
if test "$remote_oid" = "$zero"
|
| 35 |
+
then
|
| 36 |
+
# New branch, examine all commits
|
| 37 |
+
range="$local_oid"
|
| 38 |
+
else
|
| 39 |
+
# Update to existing branch, examine new commits
|
| 40 |
+
range="$remote_oid..$local_oid"
|
| 41 |
+
fi
|
| 42 |
+
|
| 43 |
+
# Check for WIP commit
|
| 44 |
+
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
|
| 45 |
+
if test -n "$commit"
|
| 46 |
+
then
|
| 47 |
+
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
| 48 |
+
exit 1
|
| 49 |
+
fi
|
| 50 |
+
fi
|
| 51 |
+
done
|
| 52 |
+
|
| 53 |
+
exit 0
|
third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-rebase.sample
CHANGED
|
@@ -1,169 +1,169 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
#
|
| 3 |
-
# Copyright (c) 2006, 2008 Junio C Hamano
|
| 4 |
-
#
|
| 5 |
-
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
| 6 |
-
# its job, and can prevent the command from running by exiting with
|
| 7 |
-
# non-zero status.
|
| 8 |
-
#
|
| 9 |
-
# The hook is called with the following parameters:
|
| 10 |
-
#
|
| 11 |
-
# $1 -- the upstream the series was forked from.
|
| 12 |
-
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
| 13 |
-
#
|
| 14 |
-
# This sample shows how to prevent topic branches that are already
|
| 15 |
-
# merged to 'next' branch from getting rebased, because allowing it
|
| 16 |
-
# would result in rebasing already published history.
|
| 17 |
-
|
| 18 |
-
publish=next
|
| 19 |
-
basebranch="$1"
|
| 20 |
-
if test "$#" = 2
|
| 21 |
-
then
|
| 22 |
-
topic="refs/heads/$2"
|
| 23 |
-
else
|
| 24 |
-
topic=`git symbolic-ref HEAD` ||
|
| 25 |
-
exit 0 ;# we do not interrupt rebasing detached HEAD
|
| 26 |
-
fi
|
| 27 |
-
|
| 28 |
-
case "$topic" in
|
| 29 |
-
refs/heads/??/*)
|
| 30 |
-
;;
|
| 31 |
-
*)
|
| 32 |
-
exit 0 ;# we do not interrupt others.
|
| 33 |
-
;;
|
| 34 |
-
esac
|
| 35 |
-
|
| 36 |
-
# Now we are dealing with a topic branch being rebased
|
| 37 |
-
# on top of master. Is it OK to rebase it?
|
| 38 |
-
|
| 39 |
-
# Does the topic really exist?
|
| 40 |
-
git show-ref -q "$topic" || {
|
| 41 |
-
echo >&2 "No such branch $topic"
|
| 42 |
-
exit 1
|
| 43 |
-
}
|
| 44 |
-
|
| 45 |
-
# Is topic fully merged to master?
|
| 46 |
-
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
| 47 |
-
if test -z "$not_in_master"
|
| 48 |
-
then
|
| 49 |
-
echo >&2 "$topic is fully merged to master; better remove it."
|
| 50 |
-
exit 1 ;# we could allow it, but there is no point.
|
| 51 |
-
fi
|
| 52 |
-
|
| 53 |
-
# Is topic ever merged to next? If so you should not be rebasing it.
|
| 54 |
-
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
| 55 |
-
only_next_2=`git rev-list ^master ${publish} | sort`
|
| 56 |
-
if test "$only_next_1" = "$only_next_2"
|
| 57 |
-
then
|
| 58 |
-
not_in_topic=`git rev-list "^$topic" master`
|
| 59 |
-
if test -z "$not_in_topic"
|
| 60 |
-
then
|
| 61 |
-
echo >&2 "$topic is already up to date with master"
|
| 62 |
-
exit 1 ;# we could allow it, but there is no point.
|
| 63 |
-
else
|
| 64 |
-
exit 0
|
| 65 |
-
fi
|
| 66 |
-
else
|
| 67 |
-
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
| 68 |
-
/usr/bin/perl -e '
|
| 69 |
-
my $topic = $ARGV[0];
|
| 70 |
-
my $msg = "* $topic has commits already merged to public branch:\n";
|
| 71 |
-
my (%not_in_next) = map {
|
| 72 |
-
/^([0-9a-f]+) /;
|
| 73 |
-
($1 => 1);
|
| 74 |
-
} split(/\n/, $ARGV[1]);
|
| 75 |
-
for my $elem (map {
|
| 76 |
-
/^([0-9a-f]+) (.*)$/;
|
| 77 |
-
[$1 => $2];
|
| 78 |
-
} split(/\n/, $ARGV[2])) {
|
| 79 |
-
if (!exists $not_in_next{$elem->[0]}) {
|
| 80 |
-
if ($msg) {
|
| 81 |
-
print STDERR $msg;
|
| 82 |
-
undef $msg;
|
| 83 |
-
}
|
| 84 |
-
print STDERR " $elem->[1]\n";
|
| 85 |
-
}
|
| 86 |
-
}
|
| 87 |
-
' "$topic" "$not_in_next" "$not_in_master"
|
| 88 |
-
exit 1
|
| 89 |
-
fi
|
| 90 |
-
|
| 91 |
-
<<\DOC_END
|
| 92 |
-
|
| 93 |
-
This sample hook safeguards topic branches that have been
|
| 94 |
-
published from being rewound.
|
| 95 |
-
|
| 96 |
-
The workflow assumed here is:
|
| 97 |
-
|
| 98 |
-
* Once a topic branch forks from "master", "master" is never
|
| 99 |
-
merged into it again (either directly or indirectly).
|
| 100 |
-
|
| 101 |
-
* Once a topic branch is fully cooked and merged into "master",
|
| 102 |
-
it is deleted. If you need to build on top of it to correct
|
| 103 |
-
earlier mistakes, a new topic branch is created by forking at
|
| 104 |
-
the tip of the "master". This is not strictly necessary, but
|
| 105 |
-
it makes it easier to keep your history simple.
|
| 106 |
-
|
| 107 |
-
* Whenever you need to test or publish your changes to topic
|
| 108 |
-
branches, merge them into "next" branch.
|
| 109 |
-
|
| 110 |
-
The script, being an example, hardcodes the publish branch name
|
| 111 |
-
to be "next", but it is trivial to make it configurable via
|
| 112 |
-
$GIT_DIR/config mechanism.
|
| 113 |
-
|
| 114 |
-
With this workflow, you would want to know:
|
| 115 |
-
|
| 116 |
-
(1) ... if a topic branch has ever been merged to "next". Young
|
| 117 |
-
topic branches can have stupid mistakes you would rather
|
| 118 |
-
clean up before publishing, and things that have not been
|
| 119 |
-
merged into other branches can be easily rebased without
|
| 120 |
-
affecting other people. But once it is published, you would
|
| 121 |
-
not want to rewind it.
|
| 122 |
-
|
| 123 |
-
(2) ... if a topic branch has been fully merged to "master".
|
| 124 |
-
Then you can delete it. More importantly, you should not
|
| 125 |
-
build on top of it -- other people may already want to
|
| 126 |
-
change things related to the topic as patches against your
|
| 127 |
-
"master", so if you need further changes, it is better to
|
| 128 |
-
fork the topic (perhaps with the same name) afresh from the
|
| 129 |
-
tip of "master".
|
| 130 |
-
|
| 131 |
-
Let's look at this example:
|
| 132 |
-
|
| 133 |
-
o---o---o---o---o---o---o---o---o---o "next"
|
| 134 |
-
/ / / /
|
| 135 |
-
/ a---a---b A / /
|
| 136 |
-
/ / / /
|
| 137 |
-
/ / c---c---c---c B /
|
| 138 |
-
/ / / \ /
|
| 139 |
-
/ / / b---b C \ /
|
| 140 |
-
/ / / / \ /
|
| 141 |
-
---o---o---o---o---o---o---o---o---o---o---o "master"
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
A, B and C are topic branches.
|
| 145 |
-
|
| 146 |
-
* A has one fix since it was merged up to "next".
|
| 147 |
-
|
| 148 |
-
* B has finished. It has been fully merged up to "master" and "next",
|
| 149 |
-
and is ready to be deleted.
|
| 150 |
-
|
| 151 |
-
* C has not merged to "next" at all.
|
| 152 |
-
|
| 153 |
-
We would want to allow C to be rebased, refuse A, and encourage
|
| 154 |
-
B to be deleted.
|
| 155 |
-
|
| 156 |
-
To compute (1):
|
| 157 |
-
|
| 158 |
-
git rev-list ^master ^topic next
|
| 159 |
-
git rev-list ^master next
|
| 160 |
-
|
| 161 |
-
if these match, topic has not merged in next at all.
|
| 162 |
-
|
| 163 |
-
To compute (2):
|
| 164 |
-
|
| 165 |
-
git rev-list master..topic
|
| 166 |
-
|
| 167 |
-
if this is empty, it is fully merged to "master".
|
| 168 |
-
|
| 169 |
-
DOC_END
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
#
|
| 3 |
+
# Copyright (c) 2006, 2008 Junio C Hamano
|
| 4 |
+
#
|
| 5 |
+
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
| 6 |
+
# its job, and can prevent the command from running by exiting with
|
| 7 |
+
# non-zero status.
|
| 8 |
+
#
|
| 9 |
+
# The hook is called with the following parameters:
|
| 10 |
+
#
|
| 11 |
+
# $1 -- the upstream the series was forked from.
|
| 12 |
+
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
| 13 |
+
#
|
| 14 |
+
# This sample shows how to prevent topic branches that are already
|
| 15 |
+
# merged to 'next' branch from getting rebased, because allowing it
|
| 16 |
+
# would result in rebasing already published history.
|
| 17 |
+
|
| 18 |
+
publish=next
|
| 19 |
+
basebranch="$1"
|
| 20 |
+
if test "$#" = 2
|
| 21 |
+
then
|
| 22 |
+
topic="refs/heads/$2"
|
| 23 |
+
else
|
| 24 |
+
topic=`git symbolic-ref HEAD` ||
|
| 25 |
+
exit 0 ;# we do not interrupt rebasing detached HEAD
|
| 26 |
+
fi
|
| 27 |
+
|
| 28 |
+
case "$topic" in
|
| 29 |
+
refs/heads/??/*)
|
| 30 |
+
;;
|
| 31 |
+
*)
|
| 32 |
+
exit 0 ;# we do not interrupt others.
|
| 33 |
+
;;
|
| 34 |
+
esac
|
| 35 |
+
|
| 36 |
+
# Now we are dealing with a topic branch being rebased
|
| 37 |
+
# on top of master. Is it OK to rebase it?
|
| 38 |
+
|
| 39 |
+
# Does the topic really exist?
|
| 40 |
+
git show-ref -q "$topic" || {
|
| 41 |
+
echo >&2 "No such branch $topic"
|
| 42 |
+
exit 1
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
# Is topic fully merged to master?
|
| 46 |
+
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
| 47 |
+
if test -z "$not_in_master"
|
| 48 |
+
then
|
| 49 |
+
echo >&2 "$topic is fully merged to master; better remove it."
|
| 50 |
+
exit 1 ;# we could allow it, but there is no point.
|
| 51 |
+
fi
|
| 52 |
+
|
| 53 |
+
# Is topic ever merged to next? If so you should not be rebasing it.
|
| 54 |
+
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
| 55 |
+
only_next_2=`git rev-list ^master ${publish} | sort`
|
| 56 |
+
if test "$only_next_1" = "$only_next_2"
|
| 57 |
+
then
|
| 58 |
+
not_in_topic=`git rev-list "^$topic" master`
|
| 59 |
+
if test -z "$not_in_topic"
|
| 60 |
+
then
|
| 61 |
+
echo >&2 "$topic is already up to date with master"
|
| 62 |
+
exit 1 ;# we could allow it, but there is no point.
|
| 63 |
+
else
|
| 64 |
+
exit 0
|
| 65 |
+
fi
|
| 66 |
+
else
|
| 67 |
+
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
| 68 |
+
/usr/bin/perl -e '
|
| 69 |
+
my $topic = $ARGV[0];
|
| 70 |
+
my $msg = "* $topic has commits already merged to public branch:\n";
|
| 71 |
+
my (%not_in_next) = map {
|
| 72 |
+
/^([0-9a-f]+) /;
|
| 73 |
+
($1 => 1);
|
| 74 |
+
} split(/\n/, $ARGV[1]);
|
| 75 |
+
for my $elem (map {
|
| 76 |
+
/^([0-9a-f]+) (.*)$/;
|
| 77 |
+
[$1 => $2];
|
| 78 |
+
} split(/\n/, $ARGV[2])) {
|
| 79 |
+
if (!exists $not_in_next{$elem->[0]}) {
|
| 80 |
+
if ($msg) {
|
| 81 |
+
print STDERR $msg;
|
| 82 |
+
undef $msg;
|
| 83 |
+
}
|
| 84 |
+
print STDERR " $elem->[1]\n";
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
' "$topic" "$not_in_next" "$not_in_master"
|
| 88 |
+
exit 1
|
| 89 |
+
fi
|
| 90 |
+
|
| 91 |
+
<<\DOC_END
|
| 92 |
+
|
| 93 |
+
This sample hook safeguards topic branches that have been
|
| 94 |
+
published from being rewound.
|
| 95 |
+
|
| 96 |
+
The workflow assumed here is:
|
| 97 |
+
|
| 98 |
+
* Once a topic branch forks from "master", "master" is never
|
| 99 |
+
merged into it again (either directly or indirectly).
|
| 100 |
+
|
| 101 |
+
* Once a topic branch is fully cooked and merged into "master",
|
| 102 |
+
it is deleted. If you need to build on top of it to correct
|
| 103 |
+
earlier mistakes, a new topic branch is created by forking at
|
| 104 |
+
the tip of the "master". This is not strictly necessary, but
|
| 105 |
+
it makes it easier to keep your history simple.
|
| 106 |
+
|
| 107 |
+
* Whenever you need to test or publish your changes to topic
|
| 108 |
+
branches, merge them into "next" branch.
|
| 109 |
+
|
| 110 |
+
The script, being an example, hardcodes the publish branch name
|
| 111 |
+
to be "next", but it is trivial to make it configurable via
|
| 112 |
+
$GIT_DIR/config mechanism.
|
| 113 |
+
|
| 114 |
+
With this workflow, you would want to know:
|
| 115 |
+
|
| 116 |
+
(1) ... if a topic branch has ever been merged to "next". Young
|
| 117 |
+
topic branches can have stupid mistakes you would rather
|
| 118 |
+
clean up before publishing, and things that have not been
|
| 119 |
+
merged into other branches can be easily rebased without
|
| 120 |
+
affecting other people. But once it is published, you would
|
| 121 |
+
not want to rewind it.
|
| 122 |
+
|
| 123 |
+
(2) ... if a topic branch has been fully merged to "master".
|
| 124 |
+
Then you can delete it. More importantly, you should not
|
| 125 |
+
build on top of it -- other people may already want to
|
| 126 |
+
change things related to the topic as patches against your
|
| 127 |
+
"master", so if you need further changes, it is better to
|
| 128 |
+
fork the topic (perhaps with the same name) afresh from the
|
| 129 |
+
tip of "master".
|
| 130 |
+
|
| 131 |
+
Let's look at this example:
|
| 132 |
+
|
| 133 |
+
o---o---o---o---o---o---o---o---o---o "next"
|
| 134 |
+
/ / / /
|
| 135 |
+
/ a---a---b A / /
|
| 136 |
+
/ / / /
|
| 137 |
+
/ / c---c---c---c B /
|
| 138 |
+
/ / / \ /
|
| 139 |
+
/ / / b---b C \ /
|
| 140 |
+
/ / / / \ /
|
| 141 |
+
---o---o---o---o---o---o---o---o---o---o---o "master"
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
A, B and C are topic branches.
|
| 145 |
+
|
| 146 |
+
* A has one fix since it was merged up to "next".
|
| 147 |
+
|
| 148 |
+
* B has finished. It has been fully merged up to "master" and "next",
|
| 149 |
+
and is ready to be deleted.
|
| 150 |
+
|
| 151 |
+
* C has not merged to "next" at all.
|
| 152 |
+
|
| 153 |
+
We would want to allow C to be rebased, refuse A, and encourage
|
| 154 |
+
B to be deleted.
|
| 155 |
+
|
| 156 |
+
To compute (1):
|
| 157 |
+
|
| 158 |
+
git rev-list ^master ^topic next
|
| 159 |
+
git rev-list ^master next
|
| 160 |
+
|
| 161 |
+
if these match, topic has not merged in next at all.
|
| 162 |
+
|
| 163 |
+
To compute (2):
|
| 164 |
+
|
| 165 |
+
git rev-list master..topic
|
| 166 |
+
|
| 167 |
+
if this is empty, it is fully merged to "master".
|
| 168 |
+
|
| 169 |
+
DOC_END
|
third_party/CityFlow/extern/pybind11/.git.bak/hooks/pre-receive.sample
CHANGED
|
@@ -1,24 +1,24 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
#
|
| 3 |
-
# An example hook script to make use of push options.
|
| 4 |
-
# The example simply echoes all push options that start with 'echoback='
|
| 5 |
-
# and rejects all pushes when the "reject" push option is used.
|
| 6 |
-
#
|
| 7 |
-
# To enable this hook, rename this file to "pre-receive".
|
| 8 |
-
|
| 9 |
-
if test -n "$GIT_PUSH_OPTION_COUNT"
|
| 10 |
-
then
|
| 11 |
-
i=0
|
| 12 |
-
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
|
| 13 |
-
do
|
| 14 |
-
eval "value=\$GIT_PUSH_OPTION_$i"
|
| 15 |
-
case "$value" in
|
| 16 |
-
echoback=*)
|
| 17 |
-
echo "echo from the pre-receive-hook: ${value#*=}" >&2
|
| 18 |
-
;;
|
| 19 |
-
reject)
|
| 20 |
-
exit 1
|
| 21 |
-
esac
|
| 22 |
-
i=$((i + 1))
|
| 23 |
-
done
|
| 24 |
-
fi
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
#
|
| 3 |
+
# An example hook script to make use of push options.
|
| 4 |
+
# The example simply echoes all push options that start with 'echoback='
|
| 5 |
+
# and rejects all pushes when the "reject" push option is used.
|
| 6 |
+
#
|
| 7 |
+
# To enable this hook, rename this file to "pre-receive".
|
| 8 |
+
|
| 9 |
+
if test -n "$GIT_PUSH_OPTION_COUNT"
|
| 10 |
+
then
|
| 11 |
+
i=0
|
| 12 |
+
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
|
| 13 |
+
do
|
| 14 |
+
eval "value=\$GIT_PUSH_OPTION_$i"
|
| 15 |
+
case "$value" in
|
| 16 |
+
echoback=*)
|
| 17 |
+
echo "echo from the pre-receive-hook: ${value#*=}" >&2
|
| 18 |
+
;;
|
| 19 |
+
reject)
|
| 20 |
+
exit 1
|
| 21 |
+
esac
|
| 22 |
+
i=$((i + 1))
|
| 23 |
+
done
|
| 24 |
+
fi
|
third_party/CityFlow/extern/pybind11/.git.bak/hooks/prepare-commit-msg.sample
CHANGED
|
@@ -1,42 +1,42 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
#
|
| 3 |
-
# An example hook script to prepare the commit log message.
|
| 4 |
-
# Called by "git commit" with the name of the file that has the
|
| 5 |
-
# commit message, followed by the description of the commit
|
| 6 |
-
# message's source. The hook's purpose is to edit the commit
|
| 7 |
-
# message file. If the hook fails with a non-zero status,
|
| 8 |
-
# the commit is aborted.
|
| 9 |
-
#
|
| 10 |
-
# To enable this hook, rename this file to "prepare-commit-msg".
|
| 11 |
-
|
| 12 |
-
# This hook includes three examples. The first one removes the
|
| 13 |
-
# "# Please enter the commit message..." help message.
|
| 14 |
-
#
|
| 15 |
-
# The second includes the output of "git diff --name-status -r"
|
| 16 |
-
# into the message, just before the "git status" output. It is
|
| 17 |
-
# commented because it doesn't cope with --amend or with squashed
|
| 18 |
-
# commits.
|
| 19 |
-
#
|
| 20 |
-
# The third example adds a Signed-off-by line to the message, that can
|
| 21 |
-
# still be edited. This is rarely a good idea.
|
| 22 |
-
|
| 23 |
-
COMMIT_MSG_FILE=$1
|
| 24 |
-
COMMIT_SOURCE=$2
|
| 25 |
-
SHA1=$3
|
| 26 |
-
|
| 27 |
-
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
|
| 28 |
-
|
| 29 |
-
# case "$COMMIT_SOURCE,$SHA1" in
|
| 30 |
-
# ,|template,)
|
| 31 |
-
# /usr/bin/perl -i.bak -pe '
|
| 32 |
-
# print "\n" . `git diff --cached --name-status -r`
|
| 33 |
-
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
|
| 34 |
-
# *) ;;
|
| 35 |
-
# esac
|
| 36 |
-
|
| 37 |
-
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
| 38 |
-
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
|
| 39 |
-
# if test -z "$COMMIT_SOURCE"
|
| 40 |
-
# then
|
| 41 |
-
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
|
| 42 |
-
# fi
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
#
|
| 3 |
+
# An example hook script to prepare the commit log message.
|
| 4 |
+
# Called by "git commit" with the name of the file that has the
|
| 5 |
+
# commit message, followed by the description of the commit
|
| 6 |
+
# message's source. The hook's purpose is to edit the commit
|
| 7 |
+
# message file. If the hook fails with a non-zero status,
|
| 8 |
+
# the commit is aborted.
|
| 9 |
+
#
|
| 10 |
+
# To enable this hook, rename this file to "prepare-commit-msg".
|
| 11 |
+
|
| 12 |
+
# This hook includes three examples. The first one removes the
|
| 13 |
+
# "# Please enter the commit message..." help message.
|
| 14 |
+
#
|
| 15 |
+
# The second includes the output of "git diff --name-status -r"
|
| 16 |
+
# into the message, just before the "git status" output. It is
|
| 17 |
+
# commented because it doesn't cope with --amend or with squashed
|
| 18 |
+
# commits.
|
| 19 |
+
#
|
| 20 |
+
# The third example adds a Signed-off-by line to the message, that can
|
| 21 |
+
# still be edited. This is rarely a good idea.
|
| 22 |
+
|
| 23 |
+
COMMIT_MSG_FILE=$1
|
| 24 |
+
COMMIT_SOURCE=$2
|
| 25 |
+
SHA1=$3
|
| 26 |
+
|
| 27 |
+
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
|
| 28 |
+
|
| 29 |
+
# case "$COMMIT_SOURCE,$SHA1" in
|
| 30 |
+
# ,|template,)
|
| 31 |
+
# /usr/bin/perl -i.bak -pe '
|
| 32 |
+
# print "\n" . `git diff --cached --name-status -r`
|
| 33 |
+
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
|
| 34 |
+
# *) ;;
|
| 35 |
+
# esac
|
| 36 |
+
|
| 37 |
+
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
| 38 |
+
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
|
| 39 |
+
# if test -z "$COMMIT_SOURCE"
|
| 40 |
+
# then
|
| 41 |
+
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
|
| 42 |
+
# fi
|
third_party/CityFlow/extern/pybind11/.git.bak/hooks/push-to-checkout.sample
CHANGED
|
@@ -1,78 +1,78 @@
|
|
| 1 |
-
#!/bin/sh
|
| 2 |
-
|
| 3 |
-
# An example hook script to update a checked-out tree on a git push.
|
| 4 |
-
#
|
| 5 |
-
# This hook is invoked by git-receive-pack(1) when it reacts to git
|
| 6 |
-
# push and updates reference(s) in its repository, and when the push
|
| 7 |
-
# tries to update the branch that is currently checked out and the
|
| 8 |
-
# receive.denyCurrentBranch configuration variable is set to
|
| 9 |
-
# updateInstead.
|
| 10 |
-
#
|
| 11 |
-
# By default, such a push is refused if the working tree and the index
|
| 12 |
-
# of the remote repository has any difference from the currently
|
| 13 |
-
# checked out commit; when both the working tree and the index match
|
| 14 |
-
# the current commit, they are updated to match the newly pushed tip
|
| 15 |
-
# of the branch. This hook is to be used to override the default
|
| 16 |
-
# behaviour; however the code below reimplements the default behaviour
|
| 17 |
-
# as a starting point for convenient modification.
|
| 18 |
-
#
|
| 19 |
-
# The hook receives the commit with which the tip of the current
|
| 20 |
-
# branch is going to be updated:
|
| 21 |
-
commit=$1
|
| 22 |
-
|
| 23 |
-
# It can exit with a non-zero status to refuse the push (when it does
|
| 24 |
-
# so, it must not modify the index or the working tree).
|
| 25 |
-
die () {
|
| 26 |
-
echo >&2 "$*"
|
| 27 |
-
exit 1
|
| 28 |
-
}
|
| 29 |
-
|
| 30 |
-
# Or it can make any necessary changes to the working tree and to the
|
| 31 |
-
# index to bring them to the desired state when the tip of the current
|
| 32 |
-
# branch is updated to the new commit, and exit with a zero status.
|
| 33 |
-
#
|
| 34 |
-
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
|
| 35 |
-
# in order to emulate git fetch that is run in the reverse direction
|
| 36 |
-
# with git push, as the two-tree form of git read-tree -u -m is
|
| 37 |
-
# essentially the same as git switch or git checkout that switches
|
| 38 |
-
# branches while keeping the local changes in the working tree that do
|
| 39 |
-
# not interfere with the difference between the branches.
|
| 40 |
-
|
| 41 |
-
# The below is a more-or-less exact translation to shell of the C code
|
| 42 |
-
# for the default behaviour for git's push-to-checkout hook defined in
|
| 43 |
-
# the push_to_deploy() function in builtin/receive-pack.c.
|
| 44 |
-
#
|
| 45 |
-
# Note that the hook will be executed from the repository directory,
|
| 46 |
-
# not from the working tree, so if you want to perform operations on
|
| 47 |
-
# the working tree, you will have to adapt your code accordingly, e.g.
|
| 48 |
-
# by adding "cd .." or using relative paths.
|
| 49 |
-
|
| 50 |
-
if ! git update-index -q --ignore-submodules --refresh
|
| 51 |
-
then
|
| 52 |
-
die "Up-to-date check failed"
|
| 53 |
-
fi
|
| 54 |
-
|
| 55 |
-
if ! git diff-files --quiet --ignore-submodules --
|
| 56 |
-
then
|
| 57 |
-
die "Working directory has unstaged changes"
|
| 58 |
-
fi
|
| 59 |
-
|
| 60 |
-
# This is a rough translation of:
|
| 61 |
-
#
|
| 62 |
-
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
|
| 63 |
-
if git cat-file -e HEAD 2>/dev/null
|
| 64 |
-
then
|
| 65 |
-
head=HEAD
|
| 66 |
-
else
|
| 67 |
-
head=$(git hash-object -t tree --stdin </dev/null)
|
| 68 |
-
fi
|
| 69 |
-
|
| 70 |
-
if ! git diff-index --quiet --cached --ignore-submodules $head --
|
| 71 |
-
then
|
| 72 |
-
die "Working directory has staged changes"
|
| 73 |
-
fi
|
| 74 |
-
|
| 75 |
-
if ! git read-tree -u -m "$commit"
|
| 76 |
-
then
|
| 77 |
-
die "Could not update working tree to new HEAD"
|
| 78 |
-
fi
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
|
| 3 |
+
# An example hook script to update a checked-out tree on a git push.
|
| 4 |
+
#
|
| 5 |
+
# This hook is invoked by git-receive-pack(1) when it reacts to git
|
| 6 |
+
# push and updates reference(s) in its repository, and when the push
|
| 7 |
+
# tries to update the branch that is currently checked out and the
|
| 8 |
+
# receive.denyCurrentBranch configuration variable is set to
|
| 9 |
+
# updateInstead.
|
| 10 |
+
#
|
| 11 |
+
# By default, such a push is refused if the working tree and the index
|
| 12 |
+
# of the remote repository has any difference from the currently
|
| 13 |
+
# checked out commit; when both the working tree and the index match
|
| 14 |
+
# the current commit, they are updated to match the newly pushed tip
|
| 15 |
+
# of the branch. This hook is to be used to override the default
|
| 16 |
+
# behaviour; however the code below reimplements the default behaviour
|
| 17 |
+
# as a starting point for convenient modification.
|
| 18 |
+
#
|
| 19 |
+
# The hook receives the commit with which the tip of the current
|
| 20 |
+
# branch is going to be updated:
|
| 21 |
+
commit=$1
|
| 22 |
+
|
| 23 |
+
# It can exit with a non-zero status to refuse the push (when it does
|
| 24 |
+
# so, it must not modify the index or the working tree).
|
| 25 |
+
die () {
|
| 26 |
+
echo >&2 "$*"
|
| 27 |
+
exit 1
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
# Or it can make any necessary changes to the working tree and to the
|
| 31 |
+
# index to bring them to the desired state when the tip of the current
|
| 32 |
+
# branch is updated to the new commit, and exit with a zero status.
|
| 33 |
+
#
|
| 34 |
+
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
|
| 35 |
+
# in order to emulate git fetch that is run in the reverse direction
|
| 36 |
+
# with git push, as the two-tree form of git read-tree -u -m is
|
| 37 |
+
# essentially the same as git switch or git checkout that switches
|
| 38 |
+
# branches while keeping the local changes in the working tree that do
|
| 39 |
+
# not interfere with the difference between the branches.
|
| 40 |
+
|
| 41 |
+
# The below is a more-or-less exact translation to shell of the C code
|
| 42 |
+
# for the default behaviour for git's push-to-checkout hook defined in
|
| 43 |
+
# the push_to_deploy() function in builtin/receive-pack.c.
|
| 44 |
+
#
|
| 45 |
+
# Note that the hook will be executed from the repository directory,
|
| 46 |
+
# not from the working tree, so if you want to perform operations on
|
| 47 |
+
# the working tree, you will have to adapt your code accordingly, e.g.
|
| 48 |
+
# by adding "cd .." or using relative paths.
|
| 49 |
+
|
| 50 |
+
if ! git update-index -q --ignore-submodules --refresh
|
| 51 |
+
then
|
| 52 |
+
die "Up-to-date check failed"
|
| 53 |
+
fi
|
| 54 |
+
|
| 55 |
+
if ! git diff-files --quiet --ignore-submodules --
|
| 56 |
+
then
|
| 57 |
+
die "Working directory has unstaged changes"
|
| 58 |
+
fi
|
| 59 |
+
|
| 60 |
+
# This is a rough translation of:
|
| 61 |
+
#
|
| 62 |
+
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
|
| 63 |
+
if git cat-file -e HEAD 2>/dev/null
|
| 64 |
+
then
|
| 65 |
+
head=HEAD
|
| 66 |
+
else
|
| 67 |
+
head=$(git hash-object -t tree --stdin </dev/null)
|
| 68 |
+
fi
|
| 69 |
+
|
| 70 |
+
if ! git diff-index --quiet --cached --ignore-submodules $head --
|
| 71 |
+
then
|
| 72 |
+
die "Working directory has staged changes"
|
| 73 |
+
fi
|
| 74 |
+
|
| 75 |
+
if ! git read-tree -u -m "$commit"
|
| 76 |
+
then
|
| 77 |
+
die "Could not update working tree to new HEAD"
|
| 78 |
+
fi
|
third_party/CityFlow/extern/pybind11/tests/test_async.py
CHANGED
|
@@ -1,24 +1,24 @@
|
|
| 1 |
-
import pytest
|
| 2 |
-
|
| 3 |
-
asyncio = pytest.importorskip("asyncio")
|
| 4 |
-
m = pytest.importorskip("pybind11_tests.async_module")
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
@pytest.fixture()
|
| 8 |
-
def event_loop():
|
| 9 |
-
loop = asyncio.new_event_loop()
|
| 10 |
-
yield loop
|
| 11 |
-
loop.close()
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
async def get_await_result(x):
|
| 15 |
-
return await x
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
def test_await(event_loop):
|
| 19 |
-
assert event_loop.run_until_complete(get_await_result(m.SupportsAsync())) == 5
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
def test_await_missing(event_loop):
|
| 23 |
-
with pytest.raises(TypeError):
|
| 24 |
-
event_loop.run_until_complete(get_await_result(m.DoesNotSupportAsync()))
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
asyncio = pytest.importorskip("asyncio")
|
| 4 |
+
m = pytest.importorskip("pybind11_tests.async_module")
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
@pytest.fixture()
|
| 8 |
+
def event_loop():
|
| 9 |
+
loop = asyncio.new_event_loop()
|
| 10 |
+
yield loop
|
| 11 |
+
loop.close()
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
async def get_await_result(x):
|
| 15 |
+
return await x
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def test_await(event_loop):
|
| 19 |
+
assert event_loop.run_until_complete(get_await_result(m.SupportsAsync())) == 5
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def test_await_missing(event_loop):
|
| 23 |
+
with pytest.raises(TypeError):
|
| 24 |
+
event_loop.run_until_complete(get_await_result(m.DoesNotSupportAsync()))
|
third_party/CityFlow/extern/pybind11/tests/test_buffers.cpp
CHANGED
|
@@ -1,259 +1,259 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_buffers.cpp -- supporting Pythons' buffer protocol
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#include <pybind11/complex.h>
|
| 11 |
-
#include <pybind11/stl.h>
|
| 12 |
-
|
| 13 |
-
#include "constructor_stats.h"
|
| 14 |
-
#include "pybind11_tests.h"
|
| 15 |
-
|
| 16 |
-
TEST_SUBMODULE(buffers, m) {
|
| 17 |
-
m.attr("long_double_and_double_have_same_size") = (sizeof(long double) == sizeof(double));
|
| 18 |
-
|
| 19 |
-
m.def("format_descriptor_format_buffer_info_equiv",
|
| 20 |
-
[](const std::string &cpp_name, const py::buffer &buffer) {
|
| 21 |
-
// https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
|
| 22 |
-
static auto *format_table = new std::map<std::string, std::string>;
|
| 23 |
-
static auto *equiv_table
|
| 24 |
-
= new std::map<std::string, bool (py::buffer_info::*)() const>;
|
| 25 |
-
if (format_table->empty()) {
|
| 26 |
-
#define PYBIND11_ASSIGN_HELPER(...) \
|
| 27 |
-
(*format_table)[#__VA_ARGS__] = py::format_descriptor<__VA_ARGS__>::format(); \
|
| 28 |
-
(*equiv_table)[#__VA_ARGS__] = &py::buffer_info::item_type_is_equivalent_to<__VA_ARGS__>;
|
| 29 |
-
PYBIND11_ASSIGN_HELPER(PyObject *)
|
| 30 |
-
PYBIND11_ASSIGN_HELPER(bool)
|
| 31 |
-
PYBIND11_ASSIGN_HELPER(std::int8_t)
|
| 32 |
-
PYBIND11_ASSIGN_HELPER(std::uint8_t)
|
| 33 |
-
PYBIND11_ASSIGN_HELPER(std::int16_t)
|
| 34 |
-
PYBIND11_ASSIGN_HELPER(std::uint16_t)
|
| 35 |
-
PYBIND11_ASSIGN_HELPER(std::int32_t)
|
| 36 |
-
PYBIND11_ASSIGN_HELPER(std::uint32_t)
|
| 37 |
-
PYBIND11_ASSIGN_HELPER(std::int64_t)
|
| 38 |
-
PYBIND11_ASSIGN_HELPER(std::uint64_t)
|
| 39 |
-
PYBIND11_ASSIGN_HELPER(float)
|
| 40 |
-
PYBIND11_ASSIGN_HELPER(double)
|
| 41 |
-
PYBIND11_ASSIGN_HELPER(long double)
|
| 42 |
-
PYBIND11_ASSIGN_HELPER(std::complex<float>)
|
| 43 |
-
PYBIND11_ASSIGN_HELPER(std::complex<double>)
|
| 44 |
-
PYBIND11_ASSIGN_HELPER(std::complex<long double>)
|
| 45 |
-
#undef PYBIND11_ASSIGN_HELPER
|
| 46 |
-
}
|
| 47 |
-
return std::pair<std::string, bool>(
|
| 48 |
-
(*format_table)[cpp_name], (buffer.request().*((*equiv_table)[cpp_name]))());
|
| 49 |
-
});
|
| 50 |
-
|
| 51 |
-
// test_from_python / test_to_python:
|
| 52 |
-
class Matrix {
|
| 53 |
-
public:
|
| 54 |
-
Matrix(py::ssize_t rows, py::ssize_t cols) : m_rows(rows), m_cols(cols) {
|
| 55 |
-
print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
| 56 |
-
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
| 57 |
-
m_data = new float[(size_t) (rows * cols)];
|
| 58 |
-
memset(m_data, 0, sizeof(float) * (size_t) (rows * cols));
|
| 59 |
-
}
|
| 60 |
-
|
| 61 |
-
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
|
| 62 |
-
print_copy_created(this,
|
| 63 |
-
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
| 64 |
-
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
| 65 |
-
m_data = new float[(size_t) (m_rows * m_cols)];
|
| 66 |
-
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
|
| 67 |
-
}
|
| 68 |
-
|
| 69 |
-
Matrix(Matrix &&s) noexcept : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
|
| 70 |
-
print_move_created(this);
|
| 71 |
-
s.m_rows = 0;
|
| 72 |
-
s.m_cols = 0;
|
| 73 |
-
s.m_data = nullptr;
|
| 74 |
-
}
|
| 75 |
-
|
| 76 |
-
~Matrix() {
|
| 77 |
-
print_destroyed(this,
|
| 78 |
-
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
| 79 |
-
delete[] m_data;
|
| 80 |
-
}
|
| 81 |
-
|
| 82 |
-
Matrix &operator=(const Matrix &s) {
|
| 83 |
-
if (this == &s) {
|
| 84 |
-
return *this;
|
| 85 |
-
}
|
| 86 |
-
print_copy_assigned(this,
|
| 87 |
-
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
| 88 |
-
delete[] m_data;
|
| 89 |
-
m_rows = s.m_rows;
|
| 90 |
-
m_cols = s.m_cols;
|
| 91 |
-
m_data = new float[(size_t) (m_rows * m_cols)];
|
| 92 |
-
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
|
| 93 |
-
return *this;
|
| 94 |
-
}
|
| 95 |
-
|
| 96 |
-
Matrix &operator=(Matrix &&s) noexcept {
|
| 97 |
-
print_move_assigned(this,
|
| 98 |
-
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
| 99 |
-
if (&s != this) {
|
| 100 |
-
delete[] m_data;
|
| 101 |
-
m_rows = s.m_rows;
|
| 102 |
-
m_cols = s.m_cols;
|
| 103 |
-
m_data = s.m_data;
|
| 104 |
-
s.m_rows = 0;
|
| 105 |
-
s.m_cols = 0;
|
| 106 |
-
s.m_data = nullptr;
|
| 107 |
-
}
|
| 108 |
-
return *this;
|
| 109 |
-
}
|
| 110 |
-
|
| 111 |
-
float operator()(py::ssize_t i, py::ssize_t j) const {
|
| 112 |
-
return m_data[(size_t) (i * m_cols + j)];
|
| 113 |
-
}
|
| 114 |
-
|
| 115 |
-
float &operator()(py::ssize_t i, py::ssize_t j) {
|
| 116 |
-
return m_data[(size_t) (i * m_cols + j)];
|
| 117 |
-
}
|
| 118 |
-
|
| 119 |
-
float *data() { return m_data; }
|
| 120 |
-
|
| 121 |
-
py::ssize_t rows() const { return m_rows; }
|
| 122 |
-
py::ssize_t cols() const { return m_cols; }
|
| 123 |
-
|
| 124 |
-
private:
|
| 125 |
-
py::ssize_t m_rows;
|
| 126 |
-
py::ssize_t m_cols;
|
| 127 |
-
float *m_data;
|
| 128 |
-
};
|
| 129 |
-
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
|
| 130 |
-
.def(py::init<py::ssize_t, py::ssize_t>())
|
| 131 |
-
/// Construct from a buffer
|
| 132 |
-
.def(py::init([](const py::buffer &b) {
|
| 133 |
-
py::buffer_info info = b.request();
|
| 134 |
-
if (info.format != py::format_descriptor<float>::format() || info.ndim != 2) {
|
| 135 |
-
throw std::runtime_error("Incompatible buffer format!");
|
| 136 |
-
}
|
| 137 |
-
|
| 138 |
-
auto *v = new Matrix(info.shape[0], info.shape[1]);
|
| 139 |
-
memcpy(v->data(), info.ptr, sizeof(float) * (size_t) (v->rows() * v->cols()));
|
| 140 |
-
return v;
|
| 141 |
-
}))
|
| 142 |
-
|
| 143 |
-
.def("rows", &Matrix::rows)
|
| 144 |
-
.def("cols", &Matrix::cols)
|
| 145 |
-
|
| 146 |
-
/// Bare bones interface
|
| 147 |
-
.def("__getitem__",
|
| 148 |
-
[](const Matrix &m, std::pair<py::ssize_t, py::ssize_t> i) {
|
| 149 |
-
if (i.first >= m.rows() || i.second >= m.cols()) {
|
| 150 |
-
throw py::index_error();
|
| 151 |
-
}
|
| 152 |
-
return m(i.first, i.second);
|
| 153 |
-
})
|
| 154 |
-
.def("__setitem__",
|
| 155 |
-
[](Matrix &m, std::pair<py::ssize_t, py::ssize_t> i, float v) {
|
| 156 |
-
if (i.first >= m.rows() || i.second >= m.cols()) {
|
| 157 |
-
throw py::index_error();
|
| 158 |
-
}
|
| 159 |
-
m(i.first, i.second) = v;
|
| 160 |
-
})
|
| 161 |
-
/// Provide buffer access
|
| 162 |
-
.def_buffer([](Matrix &m) -> py::buffer_info {
|
| 163 |
-
return py::buffer_info(
|
| 164 |
-
m.data(), /* Pointer to buffer */
|
| 165 |
-
{m.rows(), m.cols()}, /* Buffer dimensions */
|
| 166 |
-
{sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */
|
| 167 |
-
sizeof(float)});
|
| 168 |
-
});
|
| 169 |
-
|
| 170 |
-
// test_inherited_protocol
|
| 171 |
-
class SquareMatrix : public Matrix {
|
| 172 |
-
public:
|
| 173 |
-
explicit SquareMatrix(py::ssize_t n) : Matrix(n, n) {}
|
| 174 |
-
};
|
| 175 |
-
// Derived classes inherit the buffer protocol and the buffer access function
|
| 176 |
-
py::class_<SquareMatrix, Matrix>(m, "SquareMatrix").def(py::init<py::ssize_t>());
|
| 177 |
-
|
| 178 |
-
// test_pointer_to_member_fn
|
| 179 |
-
// Tests that passing a pointer to member to the base class works in
|
| 180 |
-
// the derived class.
|
| 181 |
-
struct Buffer {
|
| 182 |
-
int32_t value = 0;
|
| 183 |
-
|
| 184 |
-
py::buffer_info get_buffer_info() {
|
| 185 |
-
return py::buffer_info(
|
| 186 |
-
&value, sizeof(value), py::format_descriptor<int32_t>::format(), 1);
|
| 187 |
-
}
|
| 188 |
-
};
|
| 189 |
-
py::class_<Buffer>(m, "Buffer", py::buffer_protocol())
|
| 190 |
-
.def(py::init<>())
|
| 191 |
-
.def_readwrite("value", &Buffer::value)
|
| 192 |
-
.def_buffer(&Buffer::get_buffer_info);
|
| 193 |
-
|
| 194 |
-
class ConstBuffer {
|
| 195 |
-
std::unique_ptr<int32_t> value;
|
| 196 |
-
|
| 197 |
-
public:
|
| 198 |
-
int32_t get_value() const { return *value; }
|
| 199 |
-
void set_value(int32_t v) { *value = v; }
|
| 200 |
-
|
| 201 |
-
py::buffer_info get_buffer_info() const {
|
| 202 |
-
return py::buffer_info(
|
| 203 |
-
value.get(), sizeof(*value), py::format_descriptor<int32_t>::format(), 1);
|
| 204 |
-
}
|
| 205 |
-
|
| 206 |
-
ConstBuffer() : value(new int32_t{0}) {}
|
| 207 |
-
};
|
| 208 |
-
py::class_<ConstBuffer>(m, "ConstBuffer", py::buffer_protocol())
|
| 209 |
-
.def(py::init<>())
|
| 210 |
-
.def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value)
|
| 211 |
-
.def_buffer(&ConstBuffer::get_buffer_info);
|
| 212 |
-
|
| 213 |
-
struct DerivedBuffer : public Buffer {};
|
| 214 |
-
py::class_<DerivedBuffer>(m, "DerivedBuffer", py::buffer_protocol())
|
| 215 |
-
.def(py::init<>())
|
| 216 |
-
.def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value)
|
| 217 |
-
.def_buffer(&DerivedBuffer::get_buffer_info);
|
| 218 |
-
|
| 219 |
-
struct BufferReadOnly {
|
| 220 |
-
const uint8_t value = 0;
|
| 221 |
-
explicit BufferReadOnly(uint8_t value) : value(value) {}
|
| 222 |
-
|
| 223 |
-
py::buffer_info get_buffer_info() { return py::buffer_info(&value, 1); }
|
| 224 |
-
};
|
| 225 |
-
py::class_<BufferReadOnly>(m, "BufferReadOnly", py::buffer_protocol())
|
| 226 |
-
.def(py::init<uint8_t>())
|
| 227 |
-
.def_buffer(&BufferReadOnly::get_buffer_info);
|
| 228 |
-
|
| 229 |
-
struct BufferReadOnlySelect {
|
| 230 |
-
uint8_t value = 0;
|
| 231 |
-
bool readonly = false;
|
| 232 |
-
|
| 233 |
-
py::buffer_info get_buffer_info() { return py::buffer_info(&value, 1, readonly); }
|
| 234 |
-
};
|
| 235 |
-
py::class_<BufferReadOnlySelect>(m, "BufferReadOnlySelect", py::buffer_protocol())
|
| 236 |
-
.def(py::init<>())
|
| 237 |
-
.def_readwrite("value", &BufferReadOnlySelect::value)
|
| 238 |
-
.def_readwrite("readonly", &BufferReadOnlySelect::readonly)
|
| 239 |
-
.def_buffer(&BufferReadOnlySelect::get_buffer_info);
|
| 240 |
-
|
| 241 |
-
// Expose buffer_info for testing.
|
| 242 |
-
py::class_<py::buffer_info>(m, "buffer_info")
|
| 243 |
-
.def(py::init<>())
|
| 244 |
-
.def_readonly("itemsize", &py::buffer_info::itemsize)
|
| 245 |
-
.def_readonly("size", &py::buffer_info::size)
|
| 246 |
-
.def_readonly("format", &py::buffer_info::format)
|
| 247 |
-
.def_readonly("ndim", &py::buffer_info::ndim)
|
| 248 |
-
.def_readonly("shape", &py::buffer_info::shape)
|
| 249 |
-
.def_readonly("strides", &py::buffer_info::strides)
|
| 250 |
-
.def_readonly("readonly", &py::buffer_info::readonly)
|
| 251 |
-
.def("__repr__", [](py::handle self) {
|
| 252 |
-
return py::str("itemsize={0.itemsize!r}, size={0.size!r}, format={0.format!r}, "
|
| 253 |
-
"ndim={0.ndim!r}, shape={0.shape!r}, strides={0.strides!r}, "
|
| 254 |
-
"readonly={0.readonly!r}")
|
| 255 |
-
.format(self);
|
| 256 |
-
});
|
| 257 |
-
|
| 258 |
-
m.def("get_buffer_info", [](const py::buffer &buffer) { return buffer.request(); });
|
| 259 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_buffers.cpp -- supporting Pythons' buffer protocol
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#include <pybind11/complex.h>
|
| 11 |
+
#include <pybind11/stl.h>
|
| 12 |
+
|
| 13 |
+
#include "constructor_stats.h"
|
| 14 |
+
#include "pybind11_tests.h"
|
| 15 |
+
|
| 16 |
+
TEST_SUBMODULE(buffers, m) {
|
| 17 |
+
m.attr("long_double_and_double_have_same_size") = (sizeof(long double) == sizeof(double));
|
| 18 |
+
|
| 19 |
+
m.def("format_descriptor_format_buffer_info_equiv",
|
| 20 |
+
[](const std::string &cpp_name, const py::buffer &buffer) {
|
| 21 |
+
// https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
|
| 22 |
+
static auto *format_table = new std::map<std::string, std::string>;
|
| 23 |
+
static auto *equiv_table
|
| 24 |
+
= new std::map<std::string, bool (py::buffer_info::*)() const>;
|
| 25 |
+
if (format_table->empty()) {
|
| 26 |
+
#define PYBIND11_ASSIGN_HELPER(...) \
|
| 27 |
+
(*format_table)[#__VA_ARGS__] = py::format_descriptor<__VA_ARGS__>::format(); \
|
| 28 |
+
(*equiv_table)[#__VA_ARGS__] = &py::buffer_info::item_type_is_equivalent_to<__VA_ARGS__>;
|
| 29 |
+
PYBIND11_ASSIGN_HELPER(PyObject *)
|
| 30 |
+
PYBIND11_ASSIGN_HELPER(bool)
|
| 31 |
+
PYBIND11_ASSIGN_HELPER(std::int8_t)
|
| 32 |
+
PYBIND11_ASSIGN_HELPER(std::uint8_t)
|
| 33 |
+
PYBIND11_ASSIGN_HELPER(std::int16_t)
|
| 34 |
+
PYBIND11_ASSIGN_HELPER(std::uint16_t)
|
| 35 |
+
PYBIND11_ASSIGN_HELPER(std::int32_t)
|
| 36 |
+
PYBIND11_ASSIGN_HELPER(std::uint32_t)
|
| 37 |
+
PYBIND11_ASSIGN_HELPER(std::int64_t)
|
| 38 |
+
PYBIND11_ASSIGN_HELPER(std::uint64_t)
|
| 39 |
+
PYBIND11_ASSIGN_HELPER(float)
|
| 40 |
+
PYBIND11_ASSIGN_HELPER(double)
|
| 41 |
+
PYBIND11_ASSIGN_HELPER(long double)
|
| 42 |
+
PYBIND11_ASSIGN_HELPER(std::complex<float>)
|
| 43 |
+
PYBIND11_ASSIGN_HELPER(std::complex<double>)
|
| 44 |
+
PYBIND11_ASSIGN_HELPER(std::complex<long double>)
|
| 45 |
+
#undef PYBIND11_ASSIGN_HELPER
|
| 46 |
+
}
|
| 47 |
+
return std::pair<std::string, bool>(
|
| 48 |
+
(*format_table)[cpp_name], (buffer.request().*((*equiv_table)[cpp_name]))());
|
| 49 |
+
});
|
| 50 |
+
|
| 51 |
+
// test_from_python / test_to_python:
|
| 52 |
+
class Matrix {
|
| 53 |
+
public:
|
| 54 |
+
Matrix(py::ssize_t rows, py::ssize_t cols) : m_rows(rows), m_cols(cols) {
|
| 55 |
+
print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
| 56 |
+
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
| 57 |
+
m_data = new float[(size_t) (rows * cols)];
|
| 58 |
+
memset(m_data, 0, sizeof(float) * (size_t) (rows * cols));
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
|
| 62 |
+
print_copy_created(this,
|
| 63 |
+
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
| 64 |
+
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
| 65 |
+
m_data = new float[(size_t) (m_rows * m_cols)];
|
| 66 |
+
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
Matrix(Matrix &&s) noexcept : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
|
| 70 |
+
print_move_created(this);
|
| 71 |
+
s.m_rows = 0;
|
| 72 |
+
s.m_cols = 0;
|
| 73 |
+
s.m_data = nullptr;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
~Matrix() {
|
| 77 |
+
print_destroyed(this,
|
| 78 |
+
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
| 79 |
+
delete[] m_data;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
Matrix &operator=(const Matrix &s) {
|
| 83 |
+
if (this == &s) {
|
| 84 |
+
return *this;
|
| 85 |
+
}
|
| 86 |
+
print_copy_assigned(this,
|
| 87 |
+
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
| 88 |
+
delete[] m_data;
|
| 89 |
+
m_rows = s.m_rows;
|
| 90 |
+
m_cols = s.m_cols;
|
| 91 |
+
m_data = new float[(size_t) (m_rows * m_cols)];
|
| 92 |
+
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
|
| 93 |
+
return *this;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
Matrix &operator=(Matrix &&s) noexcept {
|
| 97 |
+
print_move_assigned(this,
|
| 98 |
+
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
| 99 |
+
if (&s != this) {
|
| 100 |
+
delete[] m_data;
|
| 101 |
+
m_rows = s.m_rows;
|
| 102 |
+
m_cols = s.m_cols;
|
| 103 |
+
m_data = s.m_data;
|
| 104 |
+
s.m_rows = 0;
|
| 105 |
+
s.m_cols = 0;
|
| 106 |
+
s.m_data = nullptr;
|
| 107 |
+
}
|
| 108 |
+
return *this;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
float operator()(py::ssize_t i, py::ssize_t j) const {
|
| 112 |
+
return m_data[(size_t) (i * m_cols + j)];
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
float &operator()(py::ssize_t i, py::ssize_t j) {
|
| 116 |
+
return m_data[(size_t) (i * m_cols + j)];
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
float *data() { return m_data; }
|
| 120 |
+
|
| 121 |
+
py::ssize_t rows() const { return m_rows; }
|
| 122 |
+
py::ssize_t cols() const { return m_cols; }
|
| 123 |
+
|
| 124 |
+
private:
|
| 125 |
+
py::ssize_t m_rows;
|
| 126 |
+
py::ssize_t m_cols;
|
| 127 |
+
float *m_data;
|
| 128 |
+
};
|
| 129 |
+
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
|
| 130 |
+
.def(py::init<py::ssize_t, py::ssize_t>())
|
| 131 |
+
/// Construct from a buffer
|
| 132 |
+
.def(py::init([](const py::buffer &b) {
|
| 133 |
+
py::buffer_info info = b.request();
|
| 134 |
+
if (info.format != py::format_descriptor<float>::format() || info.ndim != 2) {
|
| 135 |
+
throw std::runtime_error("Incompatible buffer format!");
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
auto *v = new Matrix(info.shape[0], info.shape[1]);
|
| 139 |
+
memcpy(v->data(), info.ptr, sizeof(float) * (size_t) (v->rows() * v->cols()));
|
| 140 |
+
return v;
|
| 141 |
+
}))
|
| 142 |
+
|
| 143 |
+
.def("rows", &Matrix::rows)
|
| 144 |
+
.def("cols", &Matrix::cols)
|
| 145 |
+
|
| 146 |
+
/// Bare bones interface
|
| 147 |
+
.def("__getitem__",
|
| 148 |
+
[](const Matrix &m, std::pair<py::ssize_t, py::ssize_t> i) {
|
| 149 |
+
if (i.first >= m.rows() || i.second >= m.cols()) {
|
| 150 |
+
throw py::index_error();
|
| 151 |
+
}
|
| 152 |
+
return m(i.first, i.second);
|
| 153 |
+
})
|
| 154 |
+
.def("__setitem__",
|
| 155 |
+
[](Matrix &m, std::pair<py::ssize_t, py::ssize_t> i, float v) {
|
| 156 |
+
if (i.first >= m.rows() || i.second >= m.cols()) {
|
| 157 |
+
throw py::index_error();
|
| 158 |
+
}
|
| 159 |
+
m(i.first, i.second) = v;
|
| 160 |
+
})
|
| 161 |
+
/// Provide buffer access
|
| 162 |
+
.def_buffer([](Matrix &m) -> py::buffer_info {
|
| 163 |
+
return py::buffer_info(
|
| 164 |
+
m.data(), /* Pointer to buffer */
|
| 165 |
+
{m.rows(), m.cols()}, /* Buffer dimensions */
|
| 166 |
+
{sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */
|
| 167 |
+
sizeof(float)});
|
| 168 |
+
});
|
| 169 |
+
|
| 170 |
+
// test_inherited_protocol
|
| 171 |
+
class SquareMatrix : public Matrix {
|
| 172 |
+
public:
|
| 173 |
+
explicit SquareMatrix(py::ssize_t n) : Matrix(n, n) {}
|
| 174 |
+
};
|
| 175 |
+
// Derived classes inherit the buffer protocol and the buffer access function
|
| 176 |
+
py::class_<SquareMatrix, Matrix>(m, "SquareMatrix").def(py::init<py::ssize_t>());
|
| 177 |
+
|
| 178 |
+
// test_pointer_to_member_fn
|
| 179 |
+
// Tests that passing a pointer to member to the base class works in
|
| 180 |
+
// the derived class.
|
| 181 |
+
struct Buffer {
|
| 182 |
+
int32_t value = 0;
|
| 183 |
+
|
| 184 |
+
py::buffer_info get_buffer_info() {
|
| 185 |
+
return py::buffer_info(
|
| 186 |
+
&value, sizeof(value), py::format_descriptor<int32_t>::format(), 1);
|
| 187 |
+
}
|
| 188 |
+
};
|
| 189 |
+
py::class_<Buffer>(m, "Buffer", py::buffer_protocol())
|
| 190 |
+
.def(py::init<>())
|
| 191 |
+
.def_readwrite("value", &Buffer::value)
|
| 192 |
+
.def_buffer(&Buffer::get_buffer_info);
|
| 193 |
+
|
| 194 |
+
class ConstBuffer {
|
| 195 |
+
std::unique_ptr<int32_t> value;
|
| 196 |
+
|
| 197 |
+
public:
|
| 198 |
+
int32_t get_value() const { return *value; }
|
| 199 |
+
void set_value(int32_t v) { *value = v; }
|
| 200 |
+
|
| 201 |
+
py::buffer_info get_buffer_info() const {
|
| 202 |
+
return py::buffer_info(
|
| 203 |
+
value.get(), sizeof(*value), py::format_descriptor<int32_t>::format(), 1);
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
ConstBuffer() : value(new int32_t{0}) {}
|
| 207 |
+
};
|
| 208 |
+
py::class_<ConstBuffer>(m, "ConstBuffer", py::buffer_protocol())
|
| 209 |
+
.def(py::init<>())
|
| 210 |
+
.def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value)
|
| 211 |
+
.def_buffer(&ConstBuffer::get_buffer_info);
|
| 212 |
+
|
| 213 |
+
struct DerivedBuffer : public Buffer {};
|
| 214 |
+
py::class_<DerivedBuffer>(m, "DerivedBuffer", py::buffer_protocol())
|
| 215 |
+
.def(py::init<>())
|
| 216 |
+
.def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value)
|
| 217 |
+
.def_buffer(&DerivedBuffer::get_buffer_info);
|
| 218 |
+
|
| 219 |
+
struct BufferReadOnly {
|
| 220 |
+
const uint8_t value = 0;
|
| 221 |
+
explicit BufferReadOnly(uint8_t value) : value(value) {}
|
| 222 |
+
|
| 223 |
+
py::buffer_info get_buffer_info() { return py::buffer_info(&value, 1); }
|
| 224 |
+
};
|
| 225 |
+
py::class_<BufferReadOnly>(m, "BufferReadOnly", py::buffer_protocol())
|
| 226 |
+
.def(py::init<uint8_t>())
|
| 227 |
+
.def_buffer(&BufferReadOnly::get_buffer_info);
|
| 228 |
+
|
| 229 |
+
struct BufferReadOnlySelect {
|
| 230 |
+
uint8_t value = 0;
|
| 231 |
+
bool readonly = false;
|
| 232 |
+
|
| 233 |
+
py::buffer_info get_buffer_info() { return py::buffer_info(&value, 1, readonly); }
|
| 234 |
+
};
|
| 235 |
+
py::class_<BufferReadOnlySelect>(m, "BufferReadOnlySelect", py::buffer_protocol())
|
| 236 |
+
.def(py::init<>())
|
| 237 |
+
.def_readwrite("value", &BufferReadOnlySelect::value)
|
| 238 |
+
.def_readwrite("readonly", &BufferReadOnlySelect::readonly)
|
| 239 |
+
.def_buffer(&BufferReadOnlySelect::get_buffer_info);
|
| 240 |
+
|
| 241 |
+
// Expose buffer_info for testing.
|
| 242 |
+
py::class_<py::buffer_info>(m, "buffer_info")
|
| 243 |
+
.def(py::init<>())
|
| 244 |
+
.def_readonly("itemsize", &py::buffer_info::itemsize)
|
| 245 |
+
.def_readonly("size", &py::buffer_info::size)
|
| 246 |
+
.def_readonly("format", &py::buffer_info::format)
|
| 247 |
+
.def_readonly("ndim", &py::buffer_info::ndim)
|
| 248 |
+
.def_readonly("shape", &py::buffer_info::shape)
|
| 249 |
+
.def_readonly("strides", &py::buffer_info::strides)
|
| 250 |
+
.def_readonly("readonly", &py::buffer_info::readonly)
|
| 251 |
+
.def("__repr__", [](py::handle self) {
|
| 252 |
+
return py::str("itemsize={0.itemsize!r}, size={0.size!r}, format={0.format!r}, "
|
| 253 |
+
"ndim={0.ndim!r}, shape={0.shape!r}, strides={0.strides!r}, "
|
| 254 |
+
"readonly={0.readonly!r}")
|
| 255 |
+
.format(self);
|
| 256 |
+
});
|
| 257 |
+
|
| 258 |
+
m.def("get_buffer_info", [](const py::buffer &buffer) { return buffer.request(); });
|
| 259 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_buffers.py
CHANGED
|
@@ -1,228 +1,228 @@
|
|
| 1 |
-
import ctypes
|
| 2 |
-
import io
|
| 3 |
-
import struct
|
| 4 |
-
|
| 5 |
-
import pytest
|
| 6 |
-
|
| 7 |
-
import env
|
| 8 |
-
from pybind11_tests import ConstructorStats
|
| 9 |
-
from pybind11_tests import buffers as m
|
| 10 |
-
|
| 11 |
-
np = pytest.importorskip("numpy")
|
| 12 |
-
|
| 13 |
-
if m.long_double_and_double_have_same_size:
|
| 14 |
-
# Determined by the compiler used to build the pybind11 tests
|
| 15 |
-
# (e.g. MSVC gets here, but MinGW might not).
|
| 16 |
-
np_float128 = None
|
| 17 |
-
np_complex256 = None
|
| 18 |
-
else:
|
| 19 |
-
# Determined by the compiler used to build numpy (e.g. MinGW).
|
| 20 |
-
np_float128 = getattr(np, *["float128"] * 2)
|
| 21 |
-
np_complex256 = getattr(np, *["complex256"] * 2)
|
| 22 |
-
|
| 23 |
-
CPP_NAME_FORMAT_NP_DTYPE_TABLE = [
|
| 24 |
-
("PyObject *", "O", object),
|
| 25 |
-
("bool", "?", np.bool_),
|
| 26 |
-
("std::int8_t", "b", np.int8),
|
| 27 |
-
("std::uint8_t", "B", np.uint8),
|
| 28 |
-
("std::int16_t", "h", np.int16),
|
| 29 |
-
("std::uint16_t", "H", np.uint16),
|
| 30 |
-
("std::int32_t", "i", np.int32),
|
| 31 |
-
("std::uint32_t", "I", np.uint32),
|
| 32 |
-
("std::int64_t", "q", np.int64),
|
| 33 |
-
("std::uint64_t", "Q", np.uint64),
|
| 34 |
-
("float", "f", np.float32),
|
| 35 |
-
("double", "d", np.float64),
|
| 36 |
-
("long double", "g", np_float128),
|
| 37 |
-
("std::complex<float>", "Zf", np.complex64),
|
| 38 |
-
("std::complex<double>", "Zd", np.complex128),
|
| 39 |
-
("std::complex<long double>", "Zg", np_complex256),
|
| 40 |
-
]
|
| 41 |
-
CPP_NAME_FORMAT_TABLE = [
|
| 42 |
-
(cpp_name, format)
|
| 43 |
-
for cpp_name, format, np_dtype in CPP_NAME_FORMAT_NP_DTYPE_TABLE
|
| 44 |
-
if np_dtype is not None
|
| 45 |
-
]
|
| 46 |
-
CPP_NAME_NP_DTYPE_TABLE = [
|
| 47 |
-
(cpp_name, np_dtype) for cpp_name, _, np_dtype in CPP_NAME_FORMAT_NP_DTYPE_TABLE
|
| 48 |
-
]
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
@pytest.mark.parametrize(("cpp_name", "np_dtype"), CPP_NAME_NP_DTYPE_TABLE)
|
| 52 |
-
def test_format_descriptor_format_buffer_info_equiv(cpp_name, np_dtype):
|
| 53 |
-
if np_dtype is None:
|
| 54 |
-
pytest.skip(
|
| 55 |
-
f"cpp_name=`{cpp_name}`: `long double` and `double` have same size."
|
| 56 |
-
)
|
| 57 |
-
if isinstance(np_dtype, str):
|
| 58 |
-
pytest.skip(f"np.{np_dtype} does not exist.")
|
| 59 |
-
np_array = np.array([], dtype=np_dtype)
|
| 60 |
-
for other_cpp_name, expected_format in CPP_NAME_FORMAT_TABLE:
|
| 61 |
-
format, np_array_is_matching = m.format_descriptor_format_buffer_info_equiv(
|
| 62 |
-
other_cpp_name, np_array
|
| 63 |
-
)
|
| 64 |
-
assert format == expected_format
|
| 65 |
-
if other_cpp_name == cpp_name:
|
| 66 |
-
assert np_array_is_matching
|
| 67 |
-
else:
|
| 68 |
-
assert not np_array_is_matching
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
def test_from_python():
|
| 72 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 73 |
-
m.Matrix(np.array([1, 2, 3])) # trying to assign a 1D array
|
| 74 |
-
assert str(excinfo.value) == "Incompatible buffer format!"
|
| 75 |
-
|
| 76 |
-
m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32)
|
| 77 |
-
m4 = m.Matrix(m3)
|
| 78 |
-
|
| 79 |
-
for i in range(m4.rows()):
|
| 80 |
-
for j in range(m4.cols()):
|
| 81 |
-
assert m3[i, j] == m4[i, j]
|
| 82 |
-
|
| 83 |
-
cstats = ConstructorStats.get(m.Matrix)
|
| 84 |
-
assert cstats.alive() == 1
|
| 85 |
-
del m3, m4
|
| 86 |
-
assert cstats.alive() == 0
|
| 87 |
-
assert cstats.values() == ["2x3 matrix"]
|
| 88 |
-
assert cstats.copy_constructions == 0
|
| 89 |
-
# assert cstats.move_constructions >= 0 # Don't invoke any
|
| 90 |
-
assert cstats.copy_assignments == 0
|
| 91 |
-
assert cstats.move_assignments == 0
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
# https://foss.heptapod.net/pypy/pypy/-/issues/2444
|
| 95 |
-
# TODO: fix on recent PyPy
|
| 96 |
-
@pytest.mark.xfail(
|
| 97 |
-
env.PYPY, reason="PyPy 7.3.7 doesn't clear this anymore", strict=False
|
| 98 |
-
)
|
| 99 |
-
def test_to_python():
|
| 100 |
-
mat = m.Matrix(5, 4)
|
| 101 |
-
assert memoryview(mat).shape == (5, 4)
|
| 102 |
-
|
| 103 |
-
assert mat[2, 3] == 0
|
| 104 |
-
mat[2, 3] = 4.0
|
| 105 |
-
mat[3, 2] = 7.0
|
| 106 |
-
assert mat[2, 3] == 4
|
| 107 |
-
assert mat[3, 2] == 7
|
| 108 |
-
assert struct.unpack_from("f", mat, (3 * 4 + 2) * 4) == (7,)
|
| 109 |
-
assert struct.unpack_from("f", mat, (2 * 4 + 3) * 4) == (4,)
|
| 110 |
-
|
| 111 |
-
mat2 = np.array(mat, copy=False)
|
| 112 |
-
assert mat2.shape == (5, 4)
|
| 113 |
-
assert abs(mat2).sum() == 11
|
| 114 |
-
assert mat2[2, 3] == 4
|
| 115 |
-
assert mat2[3, 2] == 7
|
| 116 |
-
mat2[2, 3] = 5
|
| 117 |
-
assert mat2[2, 3] == 5
|
| 118 |
-
|
| 119 |
-
cstats = ConstructorStats.get(m.Matrix)
|
| 120 |
-
assert cstats.alive() == 1
|
| 121 |
-
del mat
|
| 122 |
-
pytest.gc_collect()
|
| 123 |
-
assert cstats.alive() == 1
|
| 124 |
-
del mat2 # holds a mat reference
|
| 125 |
-
pytest.gc_collect()
|
| 126 |
-
assert cstats.alive() == 0
|
| 127 |
-
assert cstats.values() == ["5x4 matrix"]
|
| 128 |
-
assert cstats.copy_constructions == 0
|
| 129 |
-
# assert cstats.move_constructions >= 0 # Don't invoke any
|
| 130 |
-
assert cstats.copy_assignments == 0
|
| 131 |
-
assert cstats.move_assignments == 0
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
def test_inherited_protocol():
|
| 135 |
-
"""SquareMatrix is derived from Matrix and inherits the buffer protocol"""
|
| 136 |
-
|
| 137 |
-
matrix = m.SquareMatrix(5)
|
| 138 |
-
assert memoryview(matrix).shape == (5, 5)
|
| 139 |
-
assert np.asarray(matrix).shape == (5, 5)
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
def test_pointer_to_member_fn():
|
| 143 |
-
for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]:
|
| 144 |
-
buf = cls()
|
| 145 |
-
buf.value = 0x12345678
|
| 146 |
-
value = struct.unpack("i", bytearray(buf))[0]
|
| 147 |
-
assert value == 0x12345678
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
def test_readonly_buffer():
|
| 151 |
-
buf = m.BufferReadOnly(0x64)
|
| 152 |
-
view = memoryview(buf)
|
| 153 |
-
assert view[0] == 0x64
|
| 154 |
-
assert view.readonly
|
| 155 |
-
with pytest.raises(TypeError):
|
| 156 |
-
view[0] = 0
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
def test_selective_readonly_buffer():
|
| 160 |
-
buf = m.BufferReadOnlySelect()
|
| 161 |
-
|
| 162 |
-
memoryview(buf)[0] = 0x64
|
| 163 |
-
assert buf.value == 0x64
|
| 164 |
-
|
| 165 |
-
io.BytesIO(b"A").readinto(buf)
|
| 166 |
-
assert buf.value == ord(b"A")
|
| 167 |
-
|
| 168 |
-
buf.readonly = True
|
| 169 |
-
with pytest.raises(TypeError):
|
| 170 |
-
memoryview(buf)[0] = 0
|
| 171 |
-
with pytest.raises(TypeError):
|
| 172 |
-
io.BytesIO(b"1").readinto(buf)
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
def test_ctypes_array_1d():
|
| 176 |
-
char1d = (ctypes.c_char * 10)()
|
| 177 |
-
int1d = (ctypes.c_int * 15)()
|
| 178 |
-
long1d = (ctypes.c_long * 7)()
|
| 179 |
-
|
| 180 |
-
for carray in (char1d, int1d, long1d):
|
| 181 |
-
info = m.get_buffer_info(carray)
|
| 182 |
-
assert info.itemsize == ctypes.sizeof(carray._type_)
|
| 183 |
-
assert info.size == len(carray)
|
| 184 |
-
assert info.ndim == 1
|
| 185 |
-
assert info.shape == [info.size]
|
| 186 |
-
assert info.strides == [info.itemsize]
|
| 187 |
-
assert not info.readonly
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
def test_ctypes_array_2d():
|
| 191 |
-
char2d = ((ctypes.c_char * 10) * 4)()
|
| 192 |
-
int2d = ((ctypes.c_int * 15) * 3)()
|
| 193 |
-
long2d = ((ctypes.c_long * 7) * 2)()
|
| 194 |
-
|
| 195 |
-
for carray in (char2d, int2d, long2d):
|
| 196 |
-
info = m.get_buffer_info(carray)
|
| 197 |
-
assert info.itemsize == ctypes.sizeof(carray[0]._type_)
|
| 198 |
-
assert info.size == len(carray) * len(carray[0])
|
| 199 |
-
assert info.ndim == 2
|
| 200 |
-
assert info.shape == [len(carray), len(carray[0])]
|
| 201 |
-
assert info.strides == [info.itemsize * len(carray[0]), info.itemsize]
|
| 202 |
-
assert not info.readonly
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
def test_ctypes_from_buffer():
|
| 206 |
-
test_pystr = b"0123456789"
|
| 207 |
-
for pyarray in (test_pystr, bytearray(test_pystr)):
|
| 208 |
-
pyinfo = m.get_buffer_info(pyarray)
|
| 209 |
-
|
| 210 |
-
if pyinfo.readonly:
|
| 211 |
-
cbytes = (ctypes.c_char * len(pyarray)).from_buffer_copy(pyarray)
|
| 212 |
-
cinfo = m.get_buffer_info(cbytes)
|
| 213 |
-
else:
|
| 214 |
-
cbytes = (ctypes.c_char * len(pyarray)).from_buffer(pyarray)
|
| 215 |
-
cinfo = m.get_buffer_info(cbytes)
|
| 216 |
-
|
| 217 |
-
assert cinfo.size == pyinfo.size
|
| 218 |
-
assert cinfo.ndim == pyinfo.ndim
|
| 219 |
-
assert cinfo.shape == pyinfo.shape
|
| 220 |
-
assert cinfo.strides == pyinfo.strides
|
| 221 |
-
assert not cinfo.readonly
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
def test_buffer_docstring():
|
| 225 |
-
assert (
|
| 226 |
-
m.get_buffer_info.__doc__.strip()
|
| 227 |
-
== "get_buffer_info(arg0: Buffer) -> pybind11_tests.buffers.buffer_info"
|
| 228 |
-
)
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
import io
|
| 3 |
+
import struct
|
| 4 |
+
|
| 5 |
+
import pytest
|
| 6 |
+
|
| 7 |
+
import env
|
| 8 |
+
from pybind11_tests import ConstructorStats
|
| 9 |
+
from pybind11_tests import buffers as m
|
| 10 |
+
|
| 11 |
+
np = pytest.importorskip("numpy")
|
| 12 |
+
|
| 13 |
+
if m.long_double_and_double_have_same_size:
|
| 14 |
+
# Determined by the compiler used to build the pybind11 tests
|
| 15 |
+
# (e.g. MSVC gets here, but MinGW might not).
|
| 16 |
+
np_float128 = None
|
| 17 |
+
np_complex256 = None
|
| 18 |
+
else:
|
| 19 |
+
# Determined by the compiler used to build numpy (e.g. MinGW).
|
| 20 |
+
np_float128 = getattr(np, *["float128"] * 2)
|
| 21 |
+
np_complex256 = getattr(np, *["complex256"] * 2)
|
| 22 |
+
|
| 23 |
+
CPP_NAME_FORMAT_NP_DTYPE_TABLE = [
|
| 24 |
+
("PyObject *", "O", object),
|
| 25 |
+
("bool", "?", np.bool_),
|
| 26 |
+
("std::int8_t", "b", np.int8),
|
| 27 |
+
("std::uint8_t", "B", np.uint8),
|
| 28 |
+
("std::int16_t", "h", np.int16),
|
| 29 |
+
("std::uint16_t", "H", np.uint16),
|
| 30 |
+
("std::int32_t", "i", np.int32),
|
| 31 |
+
("std::uint32_t", "I", np.uint32),
|
| 32 |
+
("std::int64_t", "q", np.int64),
|
| 33 |
+
("std::uint64_t", "Q", np.uint64),
|
| 34 |
+
("float", "f", np.float32),
|
| 35 |
+
("double", "d", np.float64),
|
| 36 |
+
("long double", "g", np_float128),
|
| 37 |
+
("std::complex<float>", "Zf", np.complex64),
|
| 38 |
+
("std::complex<double>", "Zd", np.complex128),
|
| 39 |
+
("std::complex<long double>", "Zg", np_complex256),
|
| 40 |
+
]
|
| 41 |
+
CPP_NAME_FORMAT_TABLE = [
|
| 42 |
+
(cpp_name, format)
|
| 43 |
+
for cpp_name, format, np_dtype in CPP_NAME_FORMAT_NP_DTYPE_TABLE
|
| 44 |
+
if np_dtype is not None
|
| 45 |
+
]
|
| 46 |
+
CPP_NAME_NP_DTYPE_TABLE = [
|
| 47 |
+
(cpp_name, np_dtype) for cpp_name, _, np_dtype in CPP_NAME_FORMAT_NP_DTYPE_TABLE
|
| 48 |
+
]
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
@pytest.mark.parametrize(("cpp_name", "np_dtype"), CPP_NAME_NP_DTYPE_TABLE)
|
| 52 |
+
def test_format_descriptor_format_buffer_info_equiv(cpp_name, np_dtype):
|
| 53 |
+
if np_dtype is None:
|
| 54 |
+
pytest.skip(
|
| 55 |
+
f"cpp_name=`{cpp_name}`: `long double` and `double` have same size."
|
| 56 |
+
)
|
| 57 |
+
if isinstance(np_dtype, str):
|
| 58 |
+
pytest.skip(f"np.{np_dtype} does not exist.")
|
| 59 |
+
np_array = np.array([], dtype=np_dtype)
|
| 60 |
+
for other_cpp_name, expected_format in CPP_NAME_FORMAT_TABLE:
|
| 61 |
+
format, np_array_is_matching = m.format_descriptor_format_buffer_info_equiv(
|
| 62 |
+
other_cpp_name, np_array
|
| 63 |
+
)
|
| 64 |
+
assert format == expected_format
|
| 65 |
+
if other_cpp_name == cpp_name:
|
| 66 |
+
assert np_array_is_matching
|
| 67 |
+
else:
|
| 68 |
+
assert not np_array_is_matching
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def test_from_python():
|
| 72 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 73 |
+
m.Matrix(np.array([1, 2, 3])) # trying to assign a 1D array
|
| 74 |
+
assert str(excinfo.value) == "Incompatible buffer format!"
|
| 75 |
+
|
| 76 |
+
m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32)
|
| 77 |
+
m4 = m.Matrix(m3)
|
| 78 |
+
|
| 79 |
+
for i in range(m4.rows()):
|
| 80 |
+
for j in range(m4.cols()):
|
| 81 |
+
assert m3[i, j] == m4[i, j]
|
| 82 |
+
|
| 83 |
+
cstats = ConstructorStats.get(m.Matrix)
|
| 84 |
+
assert cstats.alive() == 1
|
| 85 |
+
del m3, m4
|
| 86 |
+
assert cstats.alive() == 0
|
| 87 |
+
assert cstats.values() == ["2x3 matrix"]
|
| 88 |
+
assert cstats.copy_constructions == 0
|
| 89 |
+
# assert cstats.move_constructions >= 0 # Don't invoke any
|
| 90 |
+
assert cstats.copy_assignments == 0
|
| 91 |
+
assert cstats.move_assignments == 0
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
# https://foss.heptapod.net/pypy/pypy/-/issues/2444
|
| 95 |
+
# TODO: fix on recent PyPy
|
| 96 |
+
@pytest.mark.xfail(
|
| 97 |
+
env.PYPY, reason="PyPy 7.3.7 doesn't clear this anymore", strict=False
|
| 98 |
+
)
|
| 99 |
+
def test_to_python():
|
| 100 |
+
mat = m.Matrix(5, 4)
|
| 101 |
+
assert memoryview(mat).shape == (5, 4)
|
| 102 |
+
|
| 103 |
+
assert mat[2, 3] == 0
|
| 104 |
+
mat[2, 3] = 4.0
|
| 105 |
+
mat[3, 2] = 7.0
|
| 106 |
+
assert mat[2, 3] == 4
|
| 107 |
+
assert mat[3, 2] == 7
|
| 108 |
+
assert struct.unpack_from("f", mat, (3 * 4 + 2) * 4) == (7,)
|
| 109 |
+
assert struct.unpack_from("f", mat, (2 * 4 + 3) * 4) == (4,)
|
| 110 |
+
|
| 111 |
+
mat2 = np.array(mat, copy=False)
|
| 112 |
+
assert mat2.shape == (5, 4)
|
| 113 |
+
assert abs(mat2).sum() == 11
|
| 114 |
+
assert mat2[2, 3] == 4
|
| 115 |
+
assert mat2[3, 2] == 7
|
| 116 |
+
mat2[2, 3] = 5
|
| 117 |
+
assert mat2[2, 3] == 5
|
| 118 |
+
|
| 119 |
+
cstats = ConstructorStats.get(m.Matrix)
|
| 120 |
+
assert cstats.alive() == 1
|
| 121 |
+
del mat
|
| 122 |
+
pytest.gc_collect()
|
| 123 |
+
assert cstats.alive() == 1
|
| 124 |
+
del mat2 # holds a mat reference
|
| 125 |
+
pytest.gc_collect()
|
| 126 |
+
assert cstats.alive() == 0
|
| 127 |
+
assert cstats.values() == ["5x4 matrix"]
|
| 128 |
+
assert cstats.copy_constructions == 0
|
| 129 |
+
# assert cstats.move_constructions >= 0 # Don't invoke any
|
| 130 |
+
assert cstats.copy_assignments == 0
|
| 131 |
+
assert cstats.move_assignments == 0
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def test_inherited_protocol():
|
| 135 |
+
"""SquareMatrix is derived from Matrix and inherits the buffer protocol"""
|
| 136 |
+
|
| 137 |
+
matrix = m.SquareMatrix(5)
|
| 138 |
+
assert memoryview(matrix).shape == (5, 5)
|
| 139 |
+
assert np.asarray(matrix).shape == (5, 5)
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def test_pointer_to_member_fn():
|
| 143 |
+
for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]:
|
| 144 |
+
buf = cls()
|
| 145 |
+
buf.value = 0x12345678
|
| 146 |
+
value = struct.unpack("i", bytearray(buf))[0]
|
| 147 |
+
assert value == 0x12345678
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def test_readonly_buffer():
|
| 151 |
+
buf = m.BufferReadOnly(0x64)
|
| 152 |
+
view = memoryview(buf)
|
| 153 |
+
assert view[0] == 0x64
|
| 154 |
+
assert view.readonly
|
| 155 |
+
with pytest.raises(TypeError):
|
| 156 |
+
view[0] = 0
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
def test_selective_readonly_buffer():
|
| 160 |
+
buf = m.BufferReadOnlySelect()
|
| 161 |
+
|
| 162 |
+
memoryview(buf)[0] = 0x64
|
| 163 |
+
assert buf.value == 0x64
|
| 164 |
+
|
| 165 |
+
io.BytesIO(b"A").readinto(buf)
|
| 166 |
+
assert buf.value == ord(b"A")
|
| 167 |
+
|
| 168 |
+
buf.readonly = True
|
| 169 |
+
with pytest.raises(TypeError):
|
| 170 |
+
memoryview(buf)[0] = 0
|
| 171 |
+
with pytest.raises(TypeError):
|
| 172 |
+
io.BytesIO(b"1").readinto(buf)
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
def test_ctypes_array_1d():
|
| 176 |
+
char1d = (ctypes.c_char * 10)()
|
| 177 |
+
int1d = (ctypes.c_int * 15)()
|
| 178 |
+
long1d = (ctypes.c_long * 7)()
|
| 179 |
+
|
| 180 |
+
for carray in (char1d, int1d, long1d):
|
| 181 |
+
info = m.get_buffer_info(carray)
|
| 182 |
+
assert info.itemsize == ctypes.sizeof(carray._type_)
|
| 183 |
+
assert info.size == len(carray)
|
| 184 |
+
assert info.ndim == 1
|
| 185 |
+
assert info.shape == [info.size]
|
| 186 |
+
assert info.strides == [info.itemsize]
|
| 187 |
+
assert not info.readonly
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
def test_ctypes_array_2d():
|
| 191 |
+
char2d = ((ctypes.c_char * 10) * 4)()
|
| 192 |
+
int2d = ((ctypes.c_int * 15) * 3)()
|
| 193 |
+
long2d = ((ctypes.c_long * 7) * 2)()
|
| 194 |
+
|
| 195 |
+
for carray in (char2d, int2d, long2d):
|
| 196 |
+
info = m.get_buffer_info(carray)
|
| 197 |
+
assert info.itemsize == ctypes.sizeof(carray[0]._type_)
|
| 198 |
+
assert info.size == len(carray) * len(carray[0])
|
| 199 |
+
assert info.ndim == 2
|
| 200 |
+
assert info.shape == [len(carray), len(carray[0])]
|
| 201 |
+
assert info.strides == [info.itemsize * len(carray[0]), info.itemsize]
|
| 202 |
+
assert not info.readonly
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
def test_ctypes_from_buffer():
|
| 206 |
+
test_pystr = b"0123456789"
|
| 207 |
+
for pyarray in (test_pystr, bytearray(test_pystr)):
|
| 208 |
+
pyinfo = m.get_buffer_info(pyarray)
|
| 209 |
+
|
| 210 |
+
if pyinfo.readonly:
|
| 211 |
+
cbytes = (ctypes.c_char * len(pyarray)).from_buffer_copy(pyarray)
|
| 212 |
+
cinfo = m.get_buffer_info(cbytes)
|
| 213 |
+
else:
|
| 214 |
+
cbytes = (ctypes.c_char * len(pyarray)).from_buffer(pyarray)
|
| 215 |
+
cinfo = m.get_buffer_info(cbytes)
|
| 216 |
+
|
| 217 |
+
assert cinfo.size == pyinfo.size
|
| 218 |
+
assert cinfo.ndim == pyinfo.ndim
|
| 219 |
+
assert cinfo.shape == pyinfo.shape
|
| 220 |
+
assert cinfo.strides == pyinfo.strides
|
| 221 |
+
assert not cinfo.readonly
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
def test_buffer_docstring():
|
| 225 |
+
assert (
|
| 226 |
+
m.get_buffer_info.__doc__.strip()
|
| 227 |
+
== "get_buffer_info(arg0: Buffer) -> pybind11_tests.buffers.buffer_info"
|
| 228 |
+
)
|
third_party/CityFlow/extern/pybind11/tests/test_builtin_casters.cpp
CHANGED
|
@@ -1,392 +1,392 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_builtin_casters.cpp -- Casters available without any additional headers
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#include <pybind11/complex.h>
|
| 11 |
-
|
| 12 |
-
#include "pybind11_tests.h"
|
| 13 |
-
|
| 14 |
-
struct ConstRefCasted {
|
| 15 |
-
int tag;
|
| 16 |
-
};
|
| 17 |
-
|
| 18 |
-
PYBIND11_NAMESPACE_BEGIN(pybind11)
|
| 19 |
-
PYBIND11_NAMESPACE_BEGIN(detail)
|
| 20 |
-
template <>
|
| 21 |
-
class type_caster<ConstRefCasted> {
|
| 22 |
-
public:
|
| 23 |
-
static constexpr auto name = const_name<ConstRefCasted>();
|
| 24 |
-
|
| 25 |
-
// Input is unimportant, a new value will always be constructed based on the
|
| 26 |
-
// cast operator.
|
| 27 |
-
bool load(handle, bool) { return true; }
|
| 28 |
-
|
| 29 |
-
explicit operator ConstRefCasted &&() {
|
| 30 |
-
value = {1};
|
| 31 |
-
// NOLINTNEXTLINE(performance-move-const-arg)
|
| 32 |
-
return std::move(value);
|
| 33 |
-
}
|
| 34 |
-
explicit operator ConstRefCasted &() {
|
| 35 |
-
value = {2};
|
| 36 |
-
return value;
|
| 37 |
-
}
|
| 38 |
-
explicit operator ConstRefCasted *() {
|
| 39 |
-
value = {3};
|
| 40 |
-
return &value;
|
| 41 |
-
}
|
| 42 |
-
|
| 43 |
-
explicit operator const ConstRefCasted &() {
|
| 44 |
-
value = {4};
|
| 45 |
-
return value;
|
| 46 |
-
}
|
| 47 |
-
explicit operator const ConstRefCasted *() {
|
| 48 |
-
value = {5};
|
| 49 |
-
return &value;
|
| 50 |
-
}
|
| 51 |
-
|
| 52 |
-
// custom cast_op to explicitly propagate types to the conversion operators.
|
| 53 |
-
template <typename T_>
|
| 54 |
-
using cast_op_type =
|
| 55 |
-
/// const
|
| 56 |
-
conditional_t<
|
| 57 |
-
std::is_same<remove_reference_t<T_>, const ConstRefCasted *>::value,
|
| 58 |
-
const ConstRefCasted *,
|
| 59 |
-
conditional_t<
|
| 60 |
-
std::is_same<T_, const ConstRefCasted &>::value,
|
| 61 |
-
const ConstRefCasted &,
|
| 62 |
-
/// non-const
|
| 63 |
-
conditional_t<std::is_same<remove_reference_t<T_>, ConstRefCasted *>::value,
|
| 64 |
-
ConstRefCasted *,
|
| 65 |
-
conditional_t<std::is_same<T_, ConstRefCasted &>::value,
|
| 66 |
-
ConstRefCasted &,
|
| 67 |
-
/* else */ ConstRefCasted &&>>>>;
|
| 68 |
-
|
| 69 |
-
private:
|
| 70 |
-
ConstRefCasted value = {0};
|
| 71 |
-
};
|
| 72 |
-
PYBIND11_NAMESPACE_END(detail)
|
| 73 |
-
PYBIND11_NAMESPACE_END(pybind11)
|
| 74 |
-
|
| 75 |
-
TEST_SUBMODULE(builtin_casters, m) {
|
| 76 |
-
PYBIND11_WARNING_PUSH
|
| 77 |
-
PYBIND11_WARNING_DISABLE_MSVC(4127)
|
| 78 |
-
|
| 79 |
-
// test_simple_string
|
| 80 |
-
m.def("string_roundtrip", [](const char *s) { return s; });
|
| 81 |
-
|
| 82 |
-
// test_unicode_conversion
|
| 83 |
-
// Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null
|
| 84 |
-
// byte
|
| 85 |
-
char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/,
|
| 86 |
-
mathbfA32 = 0x1d400 /*𝐀*/;
|
| 87 |
-
char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82,
|
| 88 |
-
mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00;
|
| 89 |
-
std::wstring wstr;
|
| 90 |
-
wstr.push_back(0x61); // a
|
| 91 |
-
wstr.push_back(0x2e18); // ⸘
|
| 92 |
-
if (sizeof(wchar_t) == 2) {
|
| 93 |
-
wstr.push_back(mathbfA16_1);
|
| 94 |
-
wstr.push_back(mathbfA16_2);
|
| 95 |
-
} // 𝐀, utf16
|
| 96 |
-
else {
|
| 97 |
-
wstr.push_back((wchar_t) mathbfA32);
|
| 98 |
-
} // 𝐀, utf32
|
| 99 |
-
wstr.push_back(0x7a); // z
|
| 100 |
-
|
| 101 |
-
m.def("good_utf8_string", []() {
|
| 102 |
-
return std::string((const char *) u8"Say utf8\u203d \U0001f382 \U0001d400");
|
| 103 |
-
}); // Say utf8‽ 🎂 𝐀
|
| 104 |
-
m.def("good_utf16_string", [=]() {
|
| 105 |
-
return std::u16string({b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16});
|
| 106 |
-
}); // b‽🎂𝐀z
|
| 107 |
-
m.def("good_utf32_string", [=]() {
|
| 108 |
-
return std::u32string({a32, mathbfA32, cake32, ib32, z32});
|
| 109 |
-
}); // a𝐀🎂‽z
|
| 110 |
-
m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z
|
| 111 |
-
m.def("bad_utf8_string", []() {
|
| 112 |
-
return std::string("abc\xd0"
|
| 113 |
-
"def");
|
| 114 |
-
});
|
| 115 |
-
m.def("bad_utf16_string", [=]() { return std::u16string({b16, char16_t(0xd800), z16}); });
|
| 116 |
-
// Under Python 2.7, invalid unicode UTF-32 characters didn't appear to trigger
|
| 117 |
-
// UnicodeDecodeError
|
| 118 |
-
m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
|
| 119 |
-
if (sizeof(wchar_t) == 2) {
|
| 120 |
-
m.def("bad_wchar_string", [=]() {
|
| 121 |
-
return std::wstring({wchar_t(0x61), wchar_t(0xd800)});
|
| 122 |
-
});
|
| 123 |
-
}
|
| 124 |
-
m.def("u8_Z", []() -> char { return 'Z'; });
|
| 125 |
-
m.def("u8_eacute", []() -> char { return '\xe9'; });
|
| 126 |
-
m.def("u16_ibang", [=]() -> char16_t { return ib16; });
|
| 127 |
-
m.def("u32_mathbfA", [=]() -> char32_t { return mathbfA32; });
|
| 128 |
-
m.def("wchar_heart", []() -> wchar_t { return 0x2665; });
|
| 129 |
-
|
| 130 |
-
// test_single_char_arguments
|
| 131 |
-
m.attr("wchar_size") = py::cast(sizeof(wchar_t));
|
| 132 |
-
m.def("ord_char", [](char c) -> int { return static_cast<unsigned char>(c); });
|
| 133 |
-
m.def("ord_char_lv", [](char &c) -> int { return static_cast<unsigned char>(c); });
|
| 134 |
-
m.def("ord_char16", [](char16_t c) -> uint16_t { return c; });
|
| 135 |
-
m.def("ord_char16_lv", [](char16_t &c) -> uint16_t { return c; });
|
| 136 |
-
m.def("ord_char32", [](char32_t c) -> uint32_t { return c; });
|
| 137 |
-
m.def("ord_wchar", [](wchar_t c) -> int { return c; });
|
| 138 |
-
|
| 139 |
-
// test_bytes_to_string
|
| 140 |
-
m.def("strlen", [](char *s) { return strlen(s); });
|
| 141 |
-
m.def("string_length", [](const std::string &s) { return s.length(); });
|
| 142 |
-
|
| 143 |
-
#ifdef PYBIND11_HAS_U8STRING
|
| 144 |
-
m.attr("has_u8string") = true;
|
| 145 |
-
m.def("good_utf8_u8string", []() {
|
| 146 |
-
return std::u8string(u8"Say utf8\u203d \U0001f382 \U0001d400");
|
| 147 |
-
}); // Say utf8‽ 🎂 𝐀
|
| 148 |
-
m.def("bad_utf8_u8string", []() {
|
| 149 |
-
return std::u8string((const char8_t *) "abc\xd0"
|
| 150 |
-
"def");
|
| 151 |
-
});
|
| 152 |
-
|
| 153 |
-
m.def("u8_char8_Z", []() -> char8_t { return u8'Z'; });
|
| 154 |
-
|
| 155 |
-
// test_single_char_arguments
|
| 156 |
-
m.def("ord_char8", [](char8_t c) -> int { return static_cast<unsigned char>(c); });
|
| 157 |
-
m.def("ord_char8_lv", [](char8_t &c) -> int { return static_cast<unsigned char>(c); });
|
| 158 |
-
#endif
|
| 159 |
-
|
| 160 |
-
// test_string_view
|
| 161 |
-
#ifdef PYBIND11_HAS_STRING_VIEW
|
| 162 |
-
m.attr("has_string_view") = true;
|
| 163 |
-
m.def("string_view_print", [](std::string_view s) { py::print(s, s.size()); });
|
| 164 |
-
m.def("string_view16_print", [](std::u16string_view s) { py::print(s, s.size()); });
|
| 165 |
-
m.def("string_view32_print", [](std::u32string_view s) { py::print(s, s.size()); });
|
| 166 |
-
m.def("string_view_chars", [](std::string_view s) {
|
| 167 |
-
py::list l;
|
| 168 |
-
for (auto c : s) {
|
| 169 |
-
l.append((std::uint8_t) c);
|
| 170 |
-
}
|
| 171 |
-
return l;
|
| 172 |
-
});
|
| 173 |
-
m.def("string_view16_chars", [](std::u16string_view s) {
|
| 174 |
-
py::list l;
|
| 175 |
-
for (auto c : s) {
|
| 176 |
-
l.append((int) c);
|
| 177 |
-
}
|
| 178 |
-
return l;
|
| 179 |
-
});
|
| 180 |
-
m.def("string_view32_chars", [](std::u32string_view s) {
|
| 181 |
-
py::list l;
|
| 182 |
-
for (auto c : s) {
|
| 183 |
-
l.append((int) c);
|
| 184 |
-
}
|
| 185 |
-
return l;
|
| 186 |
-
});
|
| 187 |
-
m.def("string_view_return",
|
| 188 |
-
[]() { return std::string_view((const char *) u8"utf8 secret \U0001f382"); });
|
| 189 |
-
m.def("string_view16_return",
|
| 190 |
-
[]() { return std::u16string_view(u"utf16 secret \U0001f382"); });
|
| 191 |
-
m.def("string_view32_return",
|
| 192 |
-
[]() { return std::u32string_view(U"utf32 secret \U0001f382"); });
|
| 193 |
-
|
| 194 |
-
// The inner lambdas here are to also test implicit conversion
|
| 195 |
-
using namespace std::literals;
|
| 196 |
-
m.def("string_view_bytes",
|
| 197 |
-
[]() { return [](py::bytes b) { return b; }("abc \x80\x80 def"sv); });
|
| 198 |
-
m.def("string_view_str",
|
| 199 |
-
[]() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); });
|
| 200 |
-
m.def("string_view_from_bytes",
|
| 201 |
-
[](const py::bytes &b) { return [](std::string_view s) { return s; }(b); });
|
| 202 |
-
m.def("string_view_memoryview", []() {
|
| 203 |
-
static constexpr auto val = "Have some \360\237\216\202"sv;
|
| 204 |
-
return py::memoryview::from_memory(val);
|
| 205 |
-
});
|
| 206 |
-
|
| 207 |
-
# ifdef PYBIND11_HAS_U8STRING
|
| 208 |
-
m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
|
| 209 |
-
m.def("string_view8_chars", [](std::u8string_view s) {
|
| 210 |
-
py::list l;
|
| 211 |
-
for (auto c : s)
|
| 212 |
-
l.append((std::uint8_t) c);
|
| 213 |
-
return l;
|
| 214 |
-
});
|
| 215 |
-
m.def("string_view8_return", []() { return std::u8string_view(u8"utf8 secret \U0001f382"); });
|
| 216 |
-
m.def("string_view8_str", []() { return py::str{std::u8string_view{u8"abc ‽ def"}}; });
|
| 217 |
-
# endif
|
| 218 |
-
|
| 219 |
-
struct TypeWithBothOperatorStringAndStringView {
|
| 220 |
-
// NOLINTNEXTLINE(google-explicit-constructor)
|
| 221 |
-
operator std::string() const { return "success"; }
|
| 222 |
-
// NOLINTNEXTLINE(google-explicit-constructor)
|
| 223 |
-
operator std::string_view() const { return "failure"; }
|
| 224 |
-
};
|
| 225 |
-
m.def("bytes_from_type_with_both_operator_string_and_string_view",
|
| 226 |
-
[]() { return py::bytes(TypeWithBothOperatorStringAndStringView()); });
|
| 227 |
-
m.def("str_from_type_with_both_operator_string_and_string_view",
|
| 228 |
-
[]() { return py::str(TypeWithBothOperatorStringAndStringView()); });
|
| 229 |
-
#endif
|
| 230 |
-
|
| 231 |
-
// test_integer_casting
|
| 232 |
-
m.def("i32_str", [](std::int32_t v) { return std::to_string(v); });
|
| 233 |
-
m.def("u32_str", [](std::uint32_t v) { return std::to_string(v); });
|
| 234 |
-
m.def("i64_str", [](std::int64_t v) { return std::to_string(v); });
|
| 235 |
-
m.def("u64_str", [](std::uint64_t v) { return std::to_string(v); });
|
| 236 |
-
|
| 237 |
-
// test_int_convert
|
| 238 |
-
m.def("int_passthrough", [](int arg) { return arg; });
|
| 239 |
-
m.def(
|
| 240 |
-
"int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
|
| 241 |
-
|
| 242 |
-
// test_tuple
|
| 243 |
-
m.def(
|
| 244 |
-
"pair_passthrough",
|
| 245 |
-
[](const std::pair<bool, std::string> &input) {
|
| 246 |
-
return std::make_pair(input.second, input.first);
|
| 247 |
-
},
|
| 248 |
-
"Return a pair in reversed order");
|
| 249 |
-
m.def(
|
| 250 |
-
"tuple_passthrough",
|
| 251 |
-
[](std::tuple<bool, std::string, int> input) {
|
| 252 |
-
return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
|
| 253 |
-
},
|
| 254 |
-
"Return a triple in reversed order");
|
| 255 |
-
m.def("empty_tuple", []() { return std::tuple<>(); });
|
| 256 |
-
static std::pair<RValueCaster, RValueCaster> lvpair;
|
| 257 |
-
static std::tuple<RValueCaster, RValueCaster, RValueCaster> lvtuple;
|
| 258 |
-
static std::pair<RValueCaster, std::tuple<RValueCaster, std::pair<RValueCaster, RValueCaster>>>
|
| 259 |
-
lvnested;
|
| 260 |
-
m.def("rvalue_pair", []() { return std::make_pair(RValueCaster{}, RValueCaster{}); });
|
| 261 |
-
m.def("lvalue_pair", []() -> const decltype(lvpair) & { return lvpair; });
|
| 262 |
-
m.def("rvalue_tuple",
|
| 263 |
-
[]() { return std::make_tuple(RValueCaster{}, RValueCaster{}, RValueCaster{}); });
|
| 264 |
-
m.def("lvalue_tuple", []() -> const decltype(lvtuple) & { return lvtuple; });
|
| 265 |
-
m.def("rvalue_nested", []() {
|
| 266 |
-
return std::make_pair(
|
| 267 |
-
RValueCaster{},
|
| 268 |
-
std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{})));
|
| 269 |
-
});
|
| 270 |
-
m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
|
| 271 |
-
|
| 272 |
-
m.def(
|
| 273 |
-
"int_string_pair",
|
| 274 |
-
[]() {
|
| 275 |
-
// Using no-destructor idiom to side-step warnings from overzealous compilers.
|
| 276 |
-
static auto *int_string_pair = new std::pair<int, std::string>{2, "items"};
|
| 277 |
-
return int_string_pair;
|
| 278 |
-
},
|
| 279 |
-
py::return_value_policy::reference);
|
| 280 |
-
|
| 281 |
-
// test_builtins_cast_return_none
|
| 282 |
-
m.def("return_none_string", []() -> std::string * { return nullptr; });
|
| 283 |
-
m.def("return_none_char", []() -> const char * { return nullptr; });
|
| 284 |
-
m.def("return_none_bool", []() -> bool * { return nullptr; });
|
| 285 |
-
m.def("return_none_int", []() -> int * { return nullptr; });
|
| 286 |
-
m.def("return_none_float", []() -> float * { return nullptr; });
|
| 287 |
-
m.def("return_none_pair", []() -> std::pair<int, int> * { return nullptr; });
|
| 288 |
-
|
| 289 |
-
// test_none_deferred
|
| 290 |
-
m.def("defer_none_cstring", [](char *) { return false; });
|
| 291 |
-
m.def("defer_none_cstring", [](const py::none &) { return true; });
|
| 292 |
-
m.def("defer_none_custom", [](UserType *) { return false; });
|
| 293 |
-
m.def("defer_none_custom", [](const py::none &) { return true; });
|
| 294 |
-
m.def("nodefer_none_void", [](void *) { return true; });
|
| 295 |
-
m.def("nodefer_none_void", [](const py::none &) { return false; });
|
| 296 |
-
|
| 297 |
-
// test_void_caster
|
| 298 |
-
m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile
|
| 299 |
-
m.def("cast_nullptr_t", []() { return std::nullptr_t{}; });
|
| 300 |
-
|
| 301 |
-
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
| 302 |
-
|
| 303 |
-
// test_bool_caster
|
| 304 |
-
m.def("bool_passthrough", [](bool arg) { return arg; });
|
| 305 |
-
m.def(
|
| 306 |
-
"bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
|
| 307 |
-
|
| 308 |
-
// TODO: This should be disabled and fixed in future Intel compilers
|
| 309 |
-
#if !defined(__INTEL_COMPILER)
|
| 310 |
-
// Test "bool_passthrough_noconvert" again, but using () instead of {} to construct py::arg
|
| 311 |
-
// When compiled with the Intel compiler, this results in segmentation faults when importing
|
| 312 |
-
// the module. Tested with icc (ICC) 2021.1 Beta 20200827, this should be tested again when
|
| 313 |
-
// a newer version of icc is available.
|
| 314 |
-
m.def(
|
| 315 |
-
"bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert());
|
| 316 |
-
#endif
|
| 317 |
-
|
| 318 |
-
// test_reference_wrapper
|
| 319 |
-
m.def("refwrap_builtin", [](std::reference_wrapper<int> p) { return 10 * p.get(); });
|
| 320 |
-
m.def("refwrap_usertype", [](std::reference_wrapper<UserType> p) { return p.get().value(); });
|
| 321 |
-
m.def("refwrap_usertype_const",
|
| 322 |
-
[](std::reference_wrapper<const UserType> p) { return p.get().value(); });
|
| 323 |
-
|
| 324 |
-
m.def("refwrap_lvalue", []() -> std::reference_wrapper<UserType> {
|
| 325 |
-
static UserType x(1);
|
| 326 |
-
return std::ref(x);
|
| 327 |
-
});
|
| 328 |
-
m.def("refwrap_lvalue_const", []() -> std::reference_wrapper<const UserType> {
|
| 329 |
-
static UserType x(1);
|
| 330 |
-
return std::cref(x);
|
| 331 |
-
});
|
| 332 |
-
|
| 333 |
-
// Not currently supported (std::pair caster has return-by-value cast operator);
|
| 334 |
-
// triggers static_assert failure.
|
| 335 |
-
// m.def("refwrap_pair", [](std::reference_wrapper<std::pair<int, int>>) { });
|
| 336 |
-
|
| 337 |
-
m.def(
|
| 338 |
-
"refwrap_list",
|
| 339 |
-
[](bool copy) {
|
| 340 |
-
static IncType x1(1), x2(2);
|
| 341 |
-
py::list l;
|
| 342 |
-
for (const auto &f : {std::ref(x1), std::ref(x2)}) {
|
| 343 |
-
l.append(py::cast(
|
| 344 |
-
f, copy ? py::return_value_policy::copy : py::return_value_policy::reference));
|
| 345 |
-
}
|
| 346 |
-
return l;
|
| 347 |
-
},
|
| 348 |
-
"copy"_a);
|
| 349 |
-
|
| 350 |
-
m.def("refwrap_iiw", [](const IncType &w) { return w.value(); });
|
| 351 |
-
m.def("refwrap_call_iiw", [](IncType &w, const py::function &f) {
|
| 352 |
-
py::list l;
|
| 353 |
-
l.append(f(std::ref(w)));
|
| 354 |
-
l.append(f(std::cref(w)));
|
| 355 |
-
IncType x(w.value());
|
| 356 |
-
l.append(f(std::ref(x)));
|
| 357 |
-
IncType y(w.value());
|
| 358 |
-
auto r3 = std::ref(y);
|
| 359 |
-
l.append(f(r3));
|
| 360 |
-
return l;
|
| 361 |
-
});
|
| 362 |
-
|
| 363 |
-
// test_complex
|
| 364 |
-
m.def("complex_cast", [](float x) { return "{}"_s.format(x); });
|
| 365 |
-
m.def("complex_cast",
|
| 366 |
-
[](std::complex<float> x) { return "({}, {})"_s.format(x.real(), x.imag()); });
|
| 367 |
-
|
| 368 |
-
// test int vs. long (Python 2)
|
| 369 |
-
m.def("int_cast", []() { return (int) 42; });
|
| 370 |
-
m.def("long_cast", []() { return (long) 42; });
|
| 371 |
-
m.def("longlong_cast", []() { return ULLONG_MAX; });
|
| 372 |
-
|
| 373 |
-
/// test void* cast operator
|
| 374 |
-
m.def("test_void_caster", []() -> bool {
|
| 375 |
-
void *v = (void *) 0xabcd;
|
| 376 |
-
py::object o = py::cast(v);
|
| 377 |
-
return py::cast<void *>(o) == v;
|
| 378 |
-
});
|
| 379 |
-
|
| 380 |
-
// Tests const/non-const propagation in cast_op.
|
| 381 |
-
m.def("takes", [](ConstRefCasted x) { return x.tag; });
|
| 382 |
-
m.def("takes_move", [](ConstRefCasted &&x) { return x.tag; });
|
| 383 |
-
m.def("takes_ptr", [](ConstRefCasted *x) { return x->tag; });
|
| 384 |
-
m.def("takes_ref", [](ConstRefCasted &x) { return x.tag; });
|
| 385 |
-
m.def("takes_ref_wrap", [](std::reference_wrapper<ConstRefCasted> x) { return x.get().tag; });
|
| 386 |
-
m.def("takes_const_ptr", [](const ConstRefCasted *x) { return x->tag; });
|
| 387 |
-
m.def("takes_const_ref", [](const ConstRefCasted &x) { return x.tag; });
|
| 388 |
-
m.def("takes_const_ref_wrap",
|
| 389 |
-
[](std::reference_wrapper<const ConstRefCasted> x) { return x.get().tag; });
|
| 390 |
-
|
| 391 |
-
PYBIND11_WARNING_POP
|
| 392 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_builtin_casters.cpp -- Casters available without any additional headers
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#include <pybind11/complex.h>
|
| 11 |
+
|
| 12 |
+
#include "pybind11_tests.h"
|
| 13 |
+
|
| 14 |
+
struct ConstRefCasted {
|
| 15 |
+
int tag;
|
| 16 |
+
};
|
| 17 |
+
|
| 18 |
+
PYBIND11_NAMESPACE_BEGIN(pybind11)
|
| 19 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
| 20 |
+
template <>
|
| 21 |
+
class type_caster<ConstRefCasted> {
|
| 22 |
+
public:
|
| 23 |
+
static constexpr auto name = const_name<ConstRefCasted>();
|
| 24 |
+
|
| 25 |
+
// Input is unimportant, a new value will always be constructed based on the
|
| 26 |
+
// cast operator.
|
| 27 |
+
bool load(handle, bool) { return true; }
|
| 28 |
+
|
| 29 |
+
explicit operator ConstRefCasted &&() {
|
| 30 |
+
value = {1};
|
| 31 |
+
// NOLINTNEXTLINE(performance-move-const-arg)
|
| 32 |
+
return std::move(value);
|
| 33 |
+
}
|
| 34 |
+
explicit operator ConstRefCasted &() {
|
| 35 |
+
value = {2};
|
| 36 |
+
return value;
|
| 37 |
+
}
|
| 38 |
+
explicit operator ConstRefCasted *() {
|
| 39 |
+
value = {3};
|
| 40 |
+
return &value;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
explicit operator const ConstRefCasted &() {
|
| 44 |
+
value = {4};
|
| 45 |
+
return value;
|
| 46 |
+
}
|
| 47 |
+
explicit operator const ConstRefCasted *() {
|
| 48 |
+
value = {5};
|
| 49 |
+
return &value;
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
// custom cast_op to explicitly propagate types to the conversion operators.
|
| 53 |
+
template <typename T_>
|
| 54 |
+
using cast_op_type =
|
| 55 |
+
/// const
|
| 56 |
+
conditional_t<
|
| 57 |
+
std::is_same<remove_reference_t<T_>, const ConstRefCasted *>::value,
|
| 58 |
+
const ConstRefCasted *,
|
| 59 |
+
conditional_t<
|
| 60 |
+
std::is_same<T_, const ConstRefCasted &>::value,
|
| 61 |
+
const ConstRefCasted &,
|
| 62 |
+
/// non-const
|
| 63 |
+
conditional_t<std::is_same<remove_reference_t<T_>, ConstRefCasted *>::value,
|
| 64 |
+
ConstRefCasted *,
|
| 65 |
+
conditional_t<std::is_same<T_, ConstRefCasted &>::value,
|
| 66 |
+
ConstRefCasted &,
|
| 67 |
+
/* else */ ConstRefCasted &&>>>>;
|
| 68 |
+
|
| 69 |
+
private:
|
| 70 |
+
ConstRefCasted value = {0};
|
| 71 |
+
};
|
| 72 |
+
PYBIND11_NAMESPACE_END(detail)
|
| 73 |
+
PYBIND11_NAMESPACE_END(pybind11)
|
| 74 |
+
|
| 75 |
+
TEST_SUBMODULE(builtin_casters, m) {
|
| 76 |
+
PYBIND11_WARNING_PUSH
|
| 77 |
+
PYBIND11_WARNING_DISABLE_MSVC(4127)
|
| 78 |
+
|
| 79 |
+
// test_simple_string
|
| 80 |
+
m.def("string_roundtrip", [](const char *s) { return s; });
|
| 81 |
+
|
| 82 |
+
// test_unicode_conversion
|
| 83 |
+
// Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null
|
| 84 |
+
// byte
|
| 85 |
+
char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/,
|
| 86 |
+
mathbfA32 = 0x1d400 /*𝐀*/;
|
| 87 |
+
char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82,
|
| 88 |
+
mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00;
|
| 89 |
+
std::wstring wstr;
|
| 90 |
+
wstr.push_back(0x61); // a
|
| 91 |
+
wstr.push_back(0x2e18); // ⸘
|
| 92 |
+
if (sizeof(wchar_t) == 2) {
|
| 93 |
+
wstr.push_back(mathbfA16_1);
|
| 94 |
+
wstr.push_back(mathbfA16_2);
|
| 95 |
+
} // 𝐀, utf16
|
| 96 |
+
else {
|
| 97 |
+
wstr.push_back((wchar_t) mathbfA32);
|
| 98 |
+
} // 𝐀, utf32
|
| 99 |
+
wstr.push_back(0x7a); // z
|
| 100 |
+
|
| 101 |
+
m.def("good_utf8_string", []() {
|
| 102 |
+
return std::string((const char *) u8"Say utf8\u203d \U0001f382 \U0001d400");
|
| 103 |
+
}); // Say utf8‽ 🎂 𝐀
|
| 104 |
+
m.def("good_utf16_string", [=]() {
|
| 105 |
+
return std::u16string({b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16});
|
| 106 |
+
}); // b‽🎂𝐀z
|
| 107 |
+
m.def("good_utf32_string", [=]() {
|
| 108 |
+
return std::u32string({a32, mathbfA32, cake32, ib32, z32});
|
| 109 |
+
}); // a𝐀🎂‽z
|
| 110 |
+
m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z
|
| 111 |
+
m.def("bad_utf8_string", []() {
|
| 112 |
+
return std::string("abc\xd0"
|
| 113 |
+
"def");
|
| 114 |
+
});
|
| 115 |
+
m.def("bad_utf16_string", [=]() { return std::u16string({b16, char16_t(0xd800), z16}); });
|
| 116 |
+
// Under Python 2.7, invalid unicode UTF-32 characters didn't appear to trigger
|
| 117 |
+
// UnicodeDecodeError
|
| 118 |
+
m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
|
| 119 |
+
if (sizeof(wchar_t) == 2) {
|
| 120 |
+
m.def("bad_wchar_string", [=]() {
|
| 121 |
+
return std::wstring({wchar_t(0x61), wchar_t(0xd800)});
|
| 122 |
+
});
|
| 123 |
+
}
|
| 124 |
+
m.def("u8_Z", []() -> char { return 'Z'; });
|
| 125 |
+
m.def("u8_eacute", []() -> char { return '\xe9'; });
|
| 126 |
+
m.def("u16_ibang", [=]() -> char16_t { return ib16; });
|
| 127 |
+
m.def("u32_mathbfA", [=]() -> char32_t { return mathbfA32; });
|
| 128 |
+
m.def("wchar_heart", []() -> wchar_t { return 0x2665; });
|
| 129 |
+
|
| 130 |
+
// test_single_char_arguments
|
| 131 |
+
m.attr("wchar_size") = py::cast(sizeof(wchar_t));
|
| 132 |
+
m.def("ord_char", [](char c) -> int { return static_cast<unsigned char>(c); });
|
| 133 |
+
m.def("ord_char_lv", [](char &c) -> int { return static_cast<unsigned char>(c); });
|
| 134 |
+
m.def("ord_char16", [](char16_t c) -> uint16_t { return c; });
|
| 135 |
+
m.def("ord_char16_lv", [](char16_t &c) -> uint16_t { return c; });
|
| 136 |
+
m.def("ord_char32", [](char32_t c) -> uint32_t { return c; });
|
| 137 |
+
m.def("ord_wchar", [](wchar_t c) -> int { return c; });
|
| 138 |
+
|
| 139 |
+
// test_bytes_to_string
|
| 140 |
+
m.def("strlen", [](char *s) { return strlen(s); });
|
| 141 |
+
m.def("string_length", [](const std::string &s) { return s.length(); });
|
| 142 |
+
|
| 143 |
+
#ifdef PYBIND11_HAS_U8STRING
|
| 144 |
+
m.attr("has_u8string") = true;
|
| 145 |
+
m.def("good_utf8_u8string", []() {
|
| 146 |
+
return std::u8string(u8"Say utf8\u203d \U0001f382 \U0001d400");
|
| 147 |
+
}); // Say utf8‽ 🎂 𝐀
|
| 148 |
+
m.def("bad_utf8_u8string", []() {
|
| 149 |
+
return std::u8string((const char8_t *) "abc\xd0"
|
| 150 |
+
"def");
|
| 151 |
+
});
|
| 152 |
+
|
| 153 |
+
m.def("u8_char8_Z", []() -> char8_t { return u8'Z'; });
|
| 154 |
+
|
| 155 |
+
// test_single_char_arguments
|
| 156 |
+
m.def("ord_char8", [](char8_t c) -> int { return static_cast<unsigned char>(c); });
|
| 157 |
+
m.def("ord_char8_lv", [](char8_t &c) -> int { return static_cast<unsigned char>(c); });
|
| 158 |
+
#endif
|
| 159 |
+
|
| 160 |
+
// test_string_view
|
| 161 |
+
#ifdef PYBIND11_HAS_STRING_VIEW
|
| 162 |
+
m.attr("has_string_view") = true;
|
| 163 |
+
m.def("string_view_print", [](std::string_view s) { py::print(s, s.size()); });
|
| 164 |
+
m.def("string_view16_print", [](std::u16string_view s) { py::print(s, s.size()); });
|
| 165 |
+
m.def("string_view32_print", [](std::u32string_view s) { py::print(s, s.size()); });
|
| 166 |
+
m.def("string_view_chars", [](std::string_view s) {
|
| 167 |
+
py::list l;
|
| 168 |
+
for (auto c : s) {
|
| 169 |
+
l.append((std::uint8_t) c);
|
| 170 |
+
}
|
| 171 |
+
return l;
|
| 172 |
+
});
|
| 173 |
+
m.def("string_view16_chars", [](std::u16string_view s) {
|
| 174 |
+
py::list l;
|
| 175 |
+
for (auto c : s) {
|
| 176 |
+
l.append((int) c);
|
| 177 |
+
}
|
| 178 |
+
return l;
|
| 179 |
+
});
|
| 180 |
+
m.def("string_view32_chars", [](std::u32string_view s) {
|
| 181 |
+
py::list l;
|
| 182 |
+
for (auto c : s) {
|
| 183 |
+
l.append((int) c);
|
| 184 |
+
}
|
| 185 |
+
return l;
|
| 186 |
+
});
|
| 187 |
+
m.def("string_view_return",
|
| 188 |
+
[]() { return std::string_view((const char *) u8"utf8 secret \U0001f382"); });
|
| 189 |
+
m.def("string_view16_return",
|
| 190 |
+
[]() { return std::u16string_view(u"utf16 secret \U0001f382"); });
|
| 191 |
+
m.def("string_view32_return",
|
| 192 |
+
[]() { return std::u32string_view(U"utf32 secret \U0001f382"); });
|
| 193 |
+
|
| 194 |
+
// The inner lambdas here are to also test implicit conversion
|
| 195 |
+
using namespace std::literals;
|
| 196 |
+
m.def("string_view_bytes",
|
| 197 |
+
[]() { return [](py::bytes b) { return b; }("abc \x80\x80 def"sv); });
|
| 198 |
+
m.def("string_view_str",
|
| 199 |
+
[]() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); });
|
| 200 |
+
m.def("string_view_from_bytes",
|
| 201 |
+
[](const py::bytes &b) { return [](std::string_view s) { return s; }(b); });
|
| 202 |
+
m.def("string_view_memoryview", []() {
|
| 203 |
+
static constexpr auto val = "Have some \360\237\216\202"sv;
|
| 204 |
+
return py::memoryview::from_memory(val);
|
| 205 |
+
});
|
| 206 |
+
|
| 207 |
+
# ifdef PYBIND11_HAS_U8STRING
|
| 208 |
+
m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
|
| 209 |
+
m.def("string_view8_chars", [](std::u8string_view s) {
|
| 210 |
+
py::list l;
|
| 211 |
+
for (auto c : s)
|
| 212 |
+
l.append((std::uint8_t) c);
|
| 213 |
+
return l;
|
| 214 |
+
});
|
| 215 |
+
m.def("string_view8_return", []() { return std::u8string_view(u8"utf8 secret \U0001f382"); });
|
| 216 |
+
m.def("string_view8_str", []() { return py::str{std::u8string_view{u8"abc ‽ def"}}; });
|
| 217 |
+
# endif
|
| 218 |
+
|
| 219 |
+
struct TypeWithBothOperatorStringAndStringView {
|
| 220 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
| 221 |
+
operator std::string() const { return "success"; }
|
| 222 |
+
// NOLINTNEXTLINE(google-explicit-constructor)
|
| 223 |
+
operator std::string_view() const { return "failure"; }
|
| 224 |
+
};
|
| 225 |
+
m.def("bytes_from_type_with_both_operator_string_and_string_view",
|
| 226 |
+
[]() { return py::bytes(TypeWithBothOperatorStringAndStringView()); });
|
| 227 |
+
m.def("str_from_type_with_both_operator_string_and_string_view",
|
| 228 |
+
[]() { return py::str(TypeWithBothOperatorStringAndStringView()); });
|
| 229 |
+
#endif
|
| 230 |
+
|
| 231 |
+
// test_integer_casting
|
| 232 |
+
m.def("i32_str", [](std::int32_t v) { return std::to_string(v); });
|
| 233 |
+
m.def("u32_str", [](std::uint32_t v) { return std::to_string(v); });
|
| 234 |
+
m.def("i64_str", [](std::int64_t v) { return std::to_string(v); });
|
| 235 |
+
m.def("u64_str", [](std::uint64_t v) { return std::to_string(v); });
|
| 236 |
+
|
| 237 |
+
// test_int_convert
|
| 238 |
+
m.def("int_passthrough", [](int arg) { return arg; });
|
| 239 |
+
m.def(
|
| 240 |
+
"int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
|
| 241 |
+
|
| 242 |
+
// test_tuple
|
| 243 |
+
m.def(
|
| 244 |
+
"pair_passthrough",
|
| 245 |
+
[](const std::pair<bool, std::string> &input) {
|
| 246 |
+
return std::make_pair(input.second, input.first);
|
| 247 |
+
},
|
| 248 |
+
"Return a pair in reversed order");
|
| 249 |
+
m.def(
|
| 250 |
+
"tuple_passthrough",
|
| 251 |
+
[](std::tuple<bool, std::string, int> input) {
|
| 252 |
+
return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
|
| 253 |
+
},
|
| 254 |
+
"Return a triple in reversed order");
|
| 255 |
+
m.def("empty_tuple", []() { return std::tuple<>(); });
|
| 256 |
+
static std::pair<RValueCaster, RValueCaster> lvpair;
|
| 257 |
+
static std::tuple<RValueCaster, RValueCaster, RValueCaster> lvtuple;
|
| 258 |
+
static std::pair<RValueCaster, std::tuple<RValueCaster, std::pair<RValueCaster, RValueCaster>>>
|
| 259 |
+
lvnested;
|
| 260 |
+
m.def("rvalue_pair", []() { return std::make_pair(RValueCaster{}, RValueCaster{}); });
|
| 261 |
+
m.def("lvalue_pair", []() -> const decltype(lvpair) & { return lvpair; });
|
| 262 |
+
m.def("rvalue_tuple",
|
| 263 |
+
[]() { return std::make_tuple(RValueCaster{}, RValueCaster{}, RValueCaster{}); });
|
| 264 |
+
m.def("lvalue_tuple", []() -> const decltype(lvtuple) & { return lvtuple; });
|
| 265 |
+
m.def("rvalue_nested", []() {
|
| 266 |
+
return std::make_pair(
|
| 267 |
+
RValueCaster{},
|
| 268 |
+
std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{})));
|
| 269 |
+
});
|
| 270 |
+
m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
|
| 271 |
+
|
| 272 |
+
m.def(
|
| 273 |
+
"int_string_pair",
|
| 274 |
+
[]() {
|
| 275 |
+
// Using no-destructor idiom to side-step warnings from overzealous compilers.
|
| 276 |
+
static auto *int_string_pair = new std::pair<int, std::string>{2, "items"};
|
| 277 |
+
return int_string_pair;
|
| 278 |
+
},
|
| 279 |
+
py::return_value_policy::reference);
|
| 280 |
+
|
| 281 |
+
// test_builtins_cast_return_none
|
| 282 |
+
m.def("return_none_string", []() -> std::string * { return nullptr; });
|
| 283 |
+
m.def("return_none_char", []() -> const char * { return nullptr; });
|
| 284 |
+
m.def("return_none_bool", []() -> bool * { return nullptr; });
|
| 285 |
+
m.def("return_none_int", []() -> int * { return nullptr; });
|
| 286 |
+
m.def("return_none_float", []() -> float * { return nullptr; });
|
| 287 |
+
m.def("return_none_pair", []() -> std::pair<int, int> * { return nullptr; });
|
| 288 |
+
|
| 289 |
+
// test_none_deferred
|
| 290 |
+
m.def("defer_none_cstring", [](char *) { return false; });
|
| 291 |
+
m.def("defer_none_cstring", [](const py::none &) { return true; });
|
| 292 |
+
m.def("defer_none_custom", [](UserType *) { return false; });
|
| 293 |
+
m.def("defer_none_custom", [](const py::none &) { return true; });
|
| 294 |
+
m.def("nodefer_none_void", [](void *) { return true; });
|
| 295 |
+
m.def("nodefer_none_void", [](const py::none &) { return false; });
|
| 296 |
+
|
| 297 |
+
// test_void_caster
|
| 298 |
+
m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile
|
| 299 |
+
m.def("cast_nullptr_t", []() { return std::nullptr_t{}; });
|
| 300 |
+
|
| 301 |
+
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
| 302 |
+
|
| 303 |
+
// test_bool_caster
|
| 304 |
+
m.def("bool_passthrough", [](bool arg) { return arg; });
|
| 305 |
+
m.def(
|
| 306 |
+
"bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
|
| 307 |
+
|
| 308 |
+
// TODO: This should be disabled and fixed in future Intel compilers
|
| 309 |
+
#if !defined(__INTEL_COMPILER)
|
| 310 |
+
// Test "bool_passthrough_noconvert" again, but using () instead of {} to construct py::arg
|
| 311 |
+
// When compiled with the Intel compiler, this results in segmentation faults when importing
|
| 312 |
+
// the module. Tested with icc (ICC) 2021.1 Beta 20200827, this should be tested again when
|
| 313 |
+
// a newer version of icc is available.
|
| 314 |
+
m.def(
|
| 315 |
+
"bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert());
|
| 316 |
+
#endif
|
| 317 |
+
|
| 318 |
+
// test_reference_wrapper
|
| 319 |
+
m.def("refwrap_builtin", [](std::reference_wrapper<int> p) { return 10 * p.get(); });
|
| 320 |
+
m.def("refwrap_usertype", [](std::reference_wrapper<UserType> p) { return p.get().value(); });
|
| 321 |
+
m.def("refwrap_usertype_const",
|
| 322 |
+
[](std::reference_wrapper<const UserType> p) { return p.get().value(); });
|
| 323 |
+
|
| 324 |
+
m.def("refwrap_lvalue", []() -> std::reference_wrapper<UserType> {
|
| 325 |
+
static UserType x(1);
|
| 326 |
+
return std::ref(x);
|
| 327 |
+
});
|
| 328 |
+
m.def("refwrap_lvalue_const", []() -> std::reference_wrapper<const UserType> {
|
| 329 |
+
static UserType x(1);
|
| 330 |
+
return std::cref(x);
|
| 331 |
+
});
|
| 332 |
+
|
| 333 |
+
// Not currently supported (std::pair caster has return-by-value cast operator);
|
| 334 |
+
// triggers static_assert failure.
|
| 335 |
+
// m.def("refwrap_pair", [](std::reference_wrapper<std::pair<int, int>>) { });
|
| 336 |
+
|
| 337 |
+
m.def(
|
| 338 |
+
"refwrap_list",
|
| 339 |
+
[](bool copy) {
|
| 340 |
+
static IncType x1(1), x2(2);
|
| 341 |
+
py::list l;
|
| 342 |
+
for (const auto &f : {std::ref(x1), std::ref(x2)}) {
|
| 343 |
+
l.append(py::cast(
|
| 344 |
+
f, copy ? py::return_value_policy::copy : py::return_value_policy::reference));
|
| 345 |
+
}
|
| 346 |
+
return l;
|
| 347 |
+
},
|
| 348 |
+
"copy"_a);
|
| 349 |
+
|
| 350 |
+
m.def("refwrap_iiw", [](const IncType &w) { return w.value(); });
|
| 351 |
+
m.def("refwrap_call_iiw", [](IncType &w, const py::function &f) {
|
| 352 |
+
py::list l;
|
| 353 |
+
l.append(f(std::ref(w)));
|
| 354 |
+
l.append(f(std::cref(w)));
|
| 355 |
+
IncType x(w.value());
|
| 356 |
+
l.append(f(std::ref(x)));
|
| 357 |
+
IncType y(w.value());
|
| 358 |
+
auto r3 = std::ref(y);
|
| 359 |
+
l.append(f(r3));
|
| 360 |
+
return l;
|
| 361 |
+
});
|
| 362 |
+
|
| 363 |
+
// test_complex
|
| 364 |
+
m.def("complex_cast", [](float x) { return "{}"_s.format(x); });
|
| 365 |
+
m.def("complex_cast",
|
| 366 |
+
[](std::complex<float> x) { return "({}, {})"_s.format(x.real(), x.imag()); });
|
| 367 |
+
|
| 368 |
+
// test int vs. long (Python 2)
|
| 369 |
+
m.def("int_cast", []() { return (int) 42; });
|
| 370 |
+
m.def("long_cast", []() { return (long) 42; });
|
| 371 |
+
m.def("longlong_cast", []() { return ULLONG_MAX; });
|
| 372 |
+
|
| 373 |
+
/// test void* cast operator
|
| 374 |
+
m.def("test_void_caster", []() -> bool {
|
| 375 |
+
void *v = (void *) 0xabcd;
|
| 376 |
+
py::object o = py::cast(v);
|
| 377 |
+
return py::cast<void *>(o) == v;
|
| 378 |
+
});
|
| 379 |
+
|
| 380 |
+
// Tests const/non-const propagation in cast_op.
|
| 381 |
+
m.def("takes", [](ConstRefCasted x) { return x.tag; });
|
| 382 |
+
m.def("takes_move", [](ConstRefCasted &&x) { return x.tag; });
|
| 383 |
+
m.def("takes_ptr", [](ConstRefCasted *x) { return x->tag; });
|
| 384 |
+
m.def("takes_ref", [](ConstRefCasted &x) { return x.tag; });
|
| 385 |
+
m.def("takes_ref_wrap", [](std::reference_wrapper<ConstRefCasted> x) { return x.get().tag; });
|
| 386 |
+
m.def("takes_const_ptr", [](const ConstRefCasted *x) { return x->tag; });
|
| 387 |
+
m.def("takes_const_ref", [](const ConstRefCasted &x) { return x.tag; });
|
| 388 |
+
m.def("takes_const_ref_wrap",
|
| 389 |
+
[](std::reference_wrapper<const ConstRefCasted> x) { return x.get().tag; });
|
| 390 |
+
|
| 391 |
+
PYBIND11_WARNING_POP
|
| 392 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_builtin_casters.py
CHANGED
|
@@ -1,528 +1,528 @@
|
|
| 1 |
-
import sys
|
| 2 |
-
|
| 3 |
-
import pytest
|
| 4 |
-
|
| 5 |
-
import env
|
| 6 |
-
from pybind11_tests import IncType, UserType
|
| 7 |
-
from pybind11_tests import builtin_casters as m
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
def test_simple_string():
|
| 11 |
-
assert m.string_roundtrip("const char *") == "const char *"
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
def test_unicode_conversion():
|
| 15 |
-
"""Tests unicode conversion and error reporting."""
|
| 16 |
-
assert m.good_utf8_string() == "Say utf8‽ 🎂 𝐀"
|
| 17 |
-
assert m.good_utf16_string() == "b‽🎂𝐀z"
|
| 18 |
-
assert m.good_utf32_string() == "a𝐀🎂‽z"
|
| 19 |
-
assert m.good_wchar_string() == "a⸘𝐀z"
|
| 20 |
-
if hasattr(m, "has_u8string"):
|
| 21 |
-
assert m.good_utf8_u8string() == "Say utf8‽ 🎂 𝐀"
|
| 22 |
-
|
| 23 |
-
with pytest.raises(UnicodeDecodeError):
|
| 24 |
-
m.bad_utf8_string()
|
| 25 |
-
|
| 26 |
-
with pytest.raises(UnicodeDecodeError):
|
| 27 |
-
m.bad_utf16_string()
|
| 28 |
-
|
| 29 |
-
# These are provided only if they actually fail (they don't when 32-bit)
|
| 30 |
-
if hasattr(m, "bad_utf32_string"):
|
| 31 |
-
with pytest.raises(UnicodeDecodeError):
|
| 32 |
-
m.bad_utf32_string()
|
| 33 |
-
if hasattr(m, "bad_wchar_string"):
|
| 34 |
-
with pytest.raises(UnicodeDecodeError):
|
| 35 |
-
m.bad_wchar_string()
|
| 36 |
-
if hasattr(m, "has_u8string"):
|
| 37 |
-
with pytest.raises(UnicodeDecodeError):
|
| 38 |
-
m.bad_utf8_u8string()
|
| 39 |
-
|
| 40 |
-
assert m.u8_Z() == "Z"
|
| 41 |
-
assert m.u8_eacute() == "é"
|
| 42 |
-
assert m.u16_ibang() == "‽"
|
| 43 |
-
assert m.u32_mathbfA() == "𝐀"
|
| 44 |
-
assert m.wchar_heart() == "♥"
|
| 45 |
-
if hasattr(m, "has_u8string"):
|
| 46 |
-
assert m.u8_char8_Z() == "Z"
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
def test_single_char_arguments():
|
| 50 |
-
"""Tests failures for passing invalid inputs to char-accepting functions"""
|
| 51 |
-
|
| 52 |
-
def toobig_message(r):
|
| 53 |
-
return f"Character code point not in range({r:#x})"
|
| 54 |
-
|
| 55 |
-
toolong_message = "Expected a character, but multi-character string found"
|
| 56 |
-
|
| 57 |
-
assert m.ord_char("a") == 0x61 # simple ASCII
|
| 58 |
-
assert m.ord_char_lv("b") == 0x62
|
| 59 |
-
assert (
|
| 60 |
-
m.ord_char("é") == 0xE9
|
| 61 |
-
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
| 62 |
-
with pytest.raises(ValueError) as excinfo:
|
| 63 |
-
assert m.ord_char("Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
| 64 |
-
assert str(excinfo.value) == toobig_message(0x100)
|
| 65 |
-
with pytest.raises(ValueError) as excinfo:
|
| 66 |
-
assert m.ord_char("ab")
|
| 67 |
-
assert str(excinfo.value) == toolong_message
|
| 68 |
-
|
| 69 |
-
assert m.ord_char16("a") == 0x61
|
| 70 |
-
assert m.ord_char16("é") == 0xE9
|
| 71 |
-
assert m.ord_char16_lv("ê") == 0xEA
|
| 72 |
-
assert m.ord_char16("Ā") == 0x100
|
| 73 |
-
assert m.ord_char16("‽") == 0x203D
|
| 74 |
-
assert m.ord_char16("♥") == 0x2665
|
| 75 |
-
assert m.ord_char16_lv("♡") == 0x2661
|
| 76 |
-
with pytest.raises(ValueError) as excinfo:
|
| 77 |
-
assert m.ord_char16("🎂") == 0x1F382 # requires surrogate pair
|
| 78 |
-
assert str(excinfo.value) == toobig_message(0x10000)
|
| 79 |
-
with pytest.raises(ValueError) as excinfo:
|
| 80 |
-
assert m.ord_char16("aa")
|
| 81 |
-
assert str(excinfo.value) == toolong_message
|
| 82 |
-
|
| 83 |
-
assert m.ord_char32("a") == 0x61
|
| 84 |
-
assert m.ord_char32("é") == 0xE9
|
| 85 |
-
assert m.ord_char32("Ā") == 0x100
|
| 86 |
-
assert m.ord_char32("‽") == 0x203D
|
| 87 |
-
assert m.ord_char32("♥") == 0x2665
|
| 88 |
-
assert m.ord_char32("🎂") == 0x1F382
|
| 89 |
-
with pytest.raises(ValueError) as excinfo:
|
| 90 |
-
assert m.ord_char32("aa")
|
| 91 |
-
assert str(excinfo.value) == toolong_message
|
| 92 |
-
|
| 93 |
-
assert m.ord_wchar("a") == 0x61
|
| 94 |
-
assert m.ord_wchar("é") == 0xE9
|
| 95 |
-
assert m.ord_wchar("Ā") == 0x100
|
| 96 |
-
assert m.ord_wchar("‽") == 0x203D
|
| 97 |
-
assert m.ord_wchar("♥") == 0x2665
|
| 98 |
-
if m.wchar_size == 2:
|
| 99 |
-
with pytest.raises(ValueError) as excinfo:
|
| 100 |
-
assert m.ord_wchar("🎂") == 0x1F382 # requires surrogate pair
|
| 101 |
-
assert str(excinfo.value) == toobig_message(0x10000)
|
| 102 |
-
else:
|
| 103 |
-
assert m.ord_wchar("🎂") == 0x1F382
|
| 104 |
-
with pytest.raises(ValueError) as excinfo:
|
| 105 |
-
assert m.ord_wchar("aa")
|
| 106 |
-
assert str(excinfo.value) == toolong_message
|
| 107 |
-
|
| 108 |
-
if hasattr(m, "has_u8string"):
|
| 109 |
-
assert m.ord_char8("a") == 0x61 # simple ASCII
|
| 110 |
-
assert m.ord_char8_lv("b") == 0x62
|
| 111 |
-
assert (
|
| 112 |
-
m.ord_char8("é") == 0xE9
|
| 113 |
-
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
| 114 |
-
with pytest.raises(ValueError) as excinfo:
|
| 115 |
-
assert m.ord_char8("Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
| 116 |
-
assert str(excinfo.value) == toobig_message(0x100)
|
| 117 |
-
with pytest.raises(ValueError) as excinfo:
|
| 118 |
-
assert m.ord_char8("ab")
|
| 119 |
-
assert str(excinfo.value) == toolong_message
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
def test_bytes_to_string():
|
| 123 |
-
"""Tests the ability to pass bytes to C++ string-accepting functions. Note that this is
|
| 124 |
-
one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
|
| 125 |
-
# Issue #816
|
| 126 |
-
|
| 127 |
-
assert m.strlen(b"hi") == 2
|
| 128 |
-
assert m.string_length(b"world") == 5
|
| 129 |
-
assert m.string_length(b"a\x00b") == 3
|
| 130 |
-
assert m.strlen(b"a\x00b") == 1 # C-string limitation
|
| 131 |
-
|
| 132 |
-
# passing in a utf8 encoded string should work
|
| 133 |
-
assert m.string_length("💩".encode()) == 4
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
def test_bytearray_to_string():
|
| 137 |
-
"""Tests the ability to pass bytearray to C++ string-accepting functions"""
|
| 138 |
-
assert m.string_length(bytearray(b"Hi")) == 2
|
| 139 |
-
assert m.strlen(bytearray(b"bytearray")) == 9
|
| 140 |
-
assert m.string_length(bytearray()) == 0
|
| 141 |
-
assert m.string_length(bytearray("🦜", "utf-8", "strict")) == 4
|
| 142 |
-
assert m.string_length(bytearray(b"\x80")) == 1
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
|
| 146 |
-
def test_string_view(capture):
|
| 147 |
-
"""Tests support for C++17 string_view arguments and return values"""
|
| 148 |
-
assert m.string_view_chars("Hi") == [72, 105]
|
| 149 |
-
assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
| 150 |
-
assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
|
| 151 |
-
assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874]
|
| 152 |
-
if hasattr(m, "has_u8string"):
|
| 153 |
-
assert m.string_view8_chars("Hi") == [72, 105]
|
| 154 |
-
assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
| 155 |
-
|
| 156 |
-
assert m.string_view_return() == "utf8 secret 🎂"
|
| 157 |
-
assert m.string_view16_return() == "utf16 secret 🎂"
|
| 158 |
-
assert m.string_view32_return() == "utf32 secret 🎂"
|
| 159 |
-
if hasattr(m, "has_u8string"):
|
| 160 |
-
assert m.string_view8_return() == "utf8 secret 🎂"
|
| 161 |
-
|
| 162 |
-
with capture:
|
| 163 |
-
m.string_view_print("Hi")
|
| 164 |
-
m.string_view_print("utf8 🎂")
|
| 165 |
-
m.string_view16_print("utf16 🎂")
|
| 166 |
-
m.string_view32_print("utf32 🎂")
|
| 167 |
-
assert (
|
| 168 |
-
capture
|
| 169 |
-
== """
|
| 170 |
-
Hi 2
|
| 171 |
-
utf8 🎂 9
|
| 172 |
-
utf16 🎂 8
|
| 173 |
-
utf32 🎂 7
|
| 174 |
-
"""
|
| 175 |
-
)
|
| 176 |
-
if hasattr(m, "has_u8string"):
|
| 177 |
-
with capture:
|
| 178 |
-
m.string_view8_print("Hi")
|
| 179 |
-
m.string_view8_print("utf8 🎂")
|
| 180 |
-
assert (
|
| 181 |
-
capture
|
| 182 |
-
== """
|
| 183 |
-
Hi 2
|
| 184 |
-
utf8 🎂 9
|
| 185 |
-
"""
|
| 186 |
-
)
|
| 187 |
-
|
| 188 |
-
with capture:
|
| 189 |
-
m.string_view_print("Hi, ascii")
|
| 190 |
-
m.string_view_print("Hi, utf8 🎂")
|
| 191 |
-
m.string_view16_print("Hi, utf16 🎂")
|
| 192 |
-
m.string_view32_print("Hi, utf32 🎂")
|
| 193 |
-
assert (
|
| 194 |
-
capture
|
| 195 |
-
== """
|
| 196 |
-
Hi, ascii 9
|
| 197 |
-
Hi, utf8 🎂 13
|
| 198 |
-
Hi, utf16 🎂 12
|
| 199 |
-
Hi, utf32 🎂 11
|
| 200 |
-
"""
|
| 201 |
-
)
|
| 202 |
-
if hasattr(m, "has_u8string"):
|
| 203 |
-
with capture:
|
| 204 |
-
m.string_view8_print("Hi, ascii")
|
| 205 |
-
m.string_view8_print("Hi, utf8 🎂")
|
| 206 |
-
assert (
|
| 207 |
-
capture
|
| 208 |
-
== """
|
| 209 |
-
Hi, ascii 9
|
| 210 |
-
Hi, utf8 🎂 13
|
| 211 |
-
"""
|
| 212 |
-
)
|
| 213 |
-
|
| 214 |
-
assert m.string_view_bytes() == b"abc \x80\x80 def"
|
| 215 |
-
assert m.string_view_str() == "abc ‽ def"
|
| 216 |
-
assert m.string_view_from_bytes("abc ‽ def".encode()) == "abc ‽ def"
|
| 217 |
-
if hasattr(m, "has_u8string"):
|
| 218 |
-
assert m.string_view8_str() == "abc ‽ def"
|
| 219 |
-
assert m.string_view_memoryview() == "Have some 🎂".encode()
|
| 220 |
-
|
| 221 |
-
assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success"
|
| 222 |
-
assert m.str_from_type_with_both_operator_string_and_string_view() == "success"
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
def test_integer_casting():
|
| 226 |
-
"""Issue #929 - out-of-range integer values shouldn't be accepted"""
|
| 227 |
-
assert m.i32_str(-1) == "-1"
|
| 228 |
-
assert m.i64_str(-1) == "-1"
|
| 229 |
-
assert m.i32_str(2000000000) == "2000000000"
|
| 230 |
-
assert m.u32_str(2000000000) == "2000000000"
|
| 231 |
-
assert m.i64_str(-999999999999) == "-999999999999"
|
| 232 |
-
assert m.u64_str(999999999999) == "999999999999"
|
| 233 |
-
|
| 234 |
-
with pytest.raises(TypeError) as excinfo:
|
| 235 |
-
m.u32_str(-1)
|
| 236 |
-
assert "incompatible function arguments" in str(excinfo.value)
|
| 237 |
-
with pytest.raises(TypeError) as excinfo:
|
| 238 |
-
m.u64_str(-1)
|
| 239 |
-
assert "incompatible function arguments" in str(excinfo.value)
|
| 240 |
-
with pytest.raises(TypeError) as excinfo:
|
| 241 |
-
m.i32_str(-3000000000)
|
| 242 |
-
assert "incompatible function arguments" in str(excinfo.value)
|
| 243 |
-
with pytest.raises(TypeError) as excinfo:
|
| 244 |
-
m.i32_str(3000000000)
|
| 245 |
-
assert "incompatible function arguments" in str(excinfo.value)
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
def test_int_convert():
|
| 249 |
-
class Int:
|
| 250 |
-
def __int__(self):
|
| 251 |
-
return 42
|
| 252 |
-
|
| 253 |
-
class NotInt:
|
| 254 |
-
pass
|
| 255 |
-
|
| 256 |
-
class Float:
|
| 257 |
-
def __float__(self):
|
| 258 |
-
return 41.99999
|
| 259 |
-
|
| 260 |
-
class Index:
|
| 261 |
-
def __index__(self):
|
| 262 |
-
return 42
|
| 263 |
-
|
| 264 |
-
class IntAndIndex:
|
| 265 |
-
def __int__(self):
|
| 266 |
-
return 42
|
| 267 |
-
|
| 268 |
-
def __index__(self):
|
| 269 |
-
return 0
|
| 270 |
-
|
| 271 |
-
class RaisingTypeErrorOnIndex:
|
| 272 |
-
def __index__(self):
|
| 273 |
-
raise TypeError
|
| 274 |
-
|
| 275 |
-
def __int__(self):
|
| 276 |
-
return 42
|
| 277 |
-
|
| 278 |
-
class RaisingValueErrorOnIndex:
|
| 279 |
-
def __index__(self):
|
| 280 |
-
raise ValueError
|
| 281 |
-
|
| 282 |
-
def __int__(self):
|
| 283 |
-
return 42
|
| 284 |
-
|
| 285 |
-
convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
|
| 286 |
-
|
| 287 |
-
def requires_conversion(v):
|
| 288 |
-
pytest.raises(TypeError, noconvert, v)
|
| 289 |
-
|
| 290 |
-
def cant_convert(v):
|
| 291 |
-
pytest.raises(TypeError, convert, v)
|
| 292 |
-
|
| 293 |
-
assert convert(7) == 7
|
| 294 |
-
assert noconvert(7) == 7
|
| 295 |
-
cant_convert(3.14159)
|
| 296 |
-
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
| 297 |
-
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
| 298 |
-
if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
|
| 299 |
-
with env.deprecated_call():
|
| 300 |
-
assert convert(Int()) == 42
|
| 301 |
-
else:
|
| 302 |
-
assert convert(Int()) == 42
|
| 303 |
-
requires_conversion(Int())
|
| 304 |
-
cant_convert(NotInt())
|
| 305 |
-
cant_convert(Float())
|
| 306 |
-
|
| 307 |
-
# Before Python 3.8, `PyLong_AsLong` does not pick up on `obj.__index__`,
|
| 308 |
-
# but pybind11 "backports" this behavior.
|
| 309 |
-
assert convert(Index()) == 42
|
| 310 |
-
assert noconvert(Index()) == 42
|
| 311 |
-
assert convert(IntAndIndex()) == 0 # Fishy; `int(DoubleThought)` == 42
|
| 312 |
-
assert noconvert(IntAndIndex()) == 0
|
| 313 |
-
assert convert(RaisingTypeErrorOnIndex()) == 42
|
| 314 |
-
requires_conversion(RaisingTypeErrorOnIndex())
|
| 315 |
-
assert convert(RaisingValueErrorOnIndex()) == 42
|
| 316 |
-
requires_conversion(RaisingValueErrorOnIndex())
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
def test_numpy_int_convert():
|
| 320 |
-
np = pytest.importorskip("numpy")
|
| 321 |
-
|
| 322 |
-
convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
|
| 323 |
-
|
| 324 |
-
def require_implicit(v):
|
| 325 |
-
pytest.raises(TypeError, noconvert, v)
|
| 326 |
-
|
| 327 |
-
# `np.intc` is an alias that corresponds to a C++ `int`
|
| 328 |
-
assert convert(np.intc(42)) == 42
|
| 329 |
-
assert noconvert(np.intc(42)) == 42
|
| 330 |
-
|
| 331 |
-
# The implicit conversion from np.float32 is undesirable but currently accepted.
|
| 332 |
-
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
| 333 |
-
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
| 334 |
-
# https://github.com/pybind/pybind11/issues/3408
|
| 335 |
-
if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
|
| 336 |
-
with env.deprecated_call():
|
| 337 |
-
assert convert(np.float32(3.14159)) == 3
|
| 338 |
-
else:
|
| 339 |
-
assert convert(np.float32(3.14159)) == 3
|
| 340 |
-
require_implicit(np.float32(3.14159))
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
def test_tuple(doc):
|
| 344 |
-
"""std::pair <-> tuple & std::tuple <-> tuple"""
|
| 345 |
-
assert m.pair_passthrough((True, "test")) == ("test", True)
|
| 346 |
-
assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True)
|
| 347 |
-
# Any sequence can be cast to a std::pair or std::tuple
|
| 348 |
-
assert m.pair_passthrough([True, "test"]) == ("test", True)
|
| 349 |
-
assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True)
|
| 350 |
-
assert m.empty_tuple() == ()
|
| 351 |
-
|
| 352 |
-
assert (
|
| 353 |
-
doc(m.pair_passthrough)
|
| 354 |
-
== """
|
| 355 |
-
pair_passthrough(arg0: tuple[bool, str]) -> tuple[str, bool]
|
| 356 |
-
|
| 357 |
-
Return a pair in reversed order
|
| 358 |
-
"""
|
| 359 |
-
)
|
| 360 |
-
assert (
|
| 361 |
-
doc(m.tuple_passthrough)
|
| 362 |
-
== """
|
| 363 |
-
tuple_passthrough(arg0: tuple[bool, str, int]) -> tuple[int, str, bool]
|
| 364 |
-
|
| 365 |
-
Return a triple in reversed order
|
| 366 |
-
"""
|
| 367 |
-
)
|
| 368 |
-
|
| 369 |
-
assert m.rvalue_pair() == ("rvalue", "rvalue")
|
| 370 |
-
assert m.lvalue_pair() == ("lvalue", "lvalue")
|
| 371 |
-
assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
|
| 372 |
-
assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue")
|
| 373 |
-
assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue")))
|
| 374 |
-
assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue")))
|
| 375 |
-
|
| 376 |
-
assert m.int_string_pair() == (2, "items")
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
def test_builtins_cast_return_none():
|
| 380 |
-
"""Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
|
| 381 |
-
assert m.return_none_string() is None
|
| 382 |
-
assert m.return_none_char() is None
|
| 383 |
-
assert m.return_none_bool() is None
|
| 384 |
-
assert m.return_none_int() is None
|
| 385 |
-
assert m.return_none_float() is None
|
| 386 |
-
assert m.return_none_pair() is None
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
def test_none_deferred():
|
| 390 |
-
"""None passed as various argument types should defer to other overloads"""
|
| 391 |
-
assert not m.defer_none_cstring("abc")
|
| 392 |
-
assert m.defer_none_cstring(None)
|
| 393 |
-
assert not m.defer_none_custom(UserType())
|
| 394 |
-
assert m.defer_none_custom(None)
|
| 395 |
-
assert m.nodefer_none_void(None)
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
def test_void_caster():
|
| 399 |
-
assert m.load_nullptr_t(None) is None
|
| 400 |
-
assert m.cast_nullptr_t() is None
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
def test_reference_wrapper():
|
| 404 |
-
"""std::reference_wrapper for builtin and user types"""
|
| 405 |
-
assert m.refwrap_builtin(42) == 420
|
| 406 |
-
assert m.refwrap_usertype(UserType(42)) == 42
|
| 407 |
-
assert m.refwrap_usertype_const(UserType(42)) == 42
|
| 408 |
-
|
| 409 |
-
with pytest.raises(TypeError) as excinfo:
|
| 410 |
-
m.refwrap_builtin(None)
|
| 411 |
-
assert "incompatible function arguments" in str(excinfo.value)
|
| 412 |
-
|
| 413 |
-
with pytest.raises(TypeError) as excinfo:
|
| 414 |
-
m.refwrap_usertype(None)
|
| 415 |
-
assert "incompatible function arguments" in str(excinfo.value)
|
| 416 |
-
|
| 417 |
-
assert m.refwrap_lvalue().value == 1
|
| 418 |
-
assert m.refwrap_lvalue_const().value == 1
|
| 419 |
-
|
| 420 |
-
a1 = m.refwrap_list(copy=True)
|
| 421 |
-
a2 = m.refwrap_list(copy=True)
|
| 422 |
-
assert [x.value for x in a1] == [2, 3]
|
| 423 |
-
assert [x.value for x in a2] == [2, 3]
|
| 424 |
-
assert a1[0] is not a2[0]
|
| 425 |
-
assert a1[1] is not a2[1]
|
| 426 |
-
|
| 427 |
-
b1 = m.refwrap_list(copy=False)
|
| 428 |
-
b2 = m.refwrap_list(copy=False)
|
| 429 |
-
assert [x.value for x in b1] == [1, 2]
|
| 430 |
-
assert [x.value for x in b2] == [1, 2]
|
| 431 |
-
assert b1[0] is b2[0]
|
| 432 |
-
assert b1[1] is b2[1]
|
| 433 |
-
|
| 434 |
-
assert m.refwrap_iiw(IncType(5)) == 5
|
| 435 |
-
assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10]
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
def test_complex_cast():
|
| 439 |
-
"""std::complex casts"""
|
| 440 |
-
assert m.complex_cast(1) == "1.0"
|
| 441 |
-
assert m.complex_cast(2j) == "(0.0, 2.0)"
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
def test_bool_caster():
|
| 445 |
-
"""Test bool caster implicit conversions."""
|
| 446 |
-
convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
|
| 447 |
-
|
| 448 |
-
def require_implicit(v):
|
| 449 |
-
pytest.raises(TypeError, noconvert, v)
|
| 450 |
-
|
| 451 |
-
def cant_convert(v):
|
| 452 |
-
pytest.raises(TypeError, convert, v)
|
| 453 |
-
|
| 454 |
-
# straight up bool
|
| 455 |
-
assert convert(True) is True
|
| 456 |
-
assert convert(False) is False
|
| 457 |
-
assert noconvert(True) is True
|
| 458 |
-
assert noconvert(False) is False
|
| 459 |
-
|
| 460 |
-
# None requires implicit conversion
|
| 461 |
-
require_implicit(None)
|
| 462 |
-
assert convert(None) is False
|
| 463 |
-
|
| 464 |
-
class A:
|
| 465 |
-
def __init__(self, x):
|
| 466 |
-
self.x = x
|
| 467 |
-
|
| 468 |
-
def __nonzero__(self):
|
| 469 |
-
return self.x
|
| 470 |
-
|
| 471 |
-
def __bool__(self):
|
| 472 |
-
return self.x
|
| 473 |
-
|
| 474 |
-
class B:
|
| 475 |
-
pass
|
| 476 |
-
|
| 477 |
-
# Arbitrary objects are not accepted
|
| 478 |
-
cant_convert(object())
|
| 479 |
-
cant_convert(B())
|
| 480 |
-
|
| 481 |
-
# Objects with __nonzero__ / __bool__ defined can be converted
|
| 482 |
-
require_implicit(A(True))
|
| 483 |
-
assert convert(A(True)) is True
|
| 484 |
-
assert convert(A(False)) is False
|
| 485 |
-
|
| 486 |
-
|
| 487 |
-
def test_numpy_bool():
|
| 488 |
-
np = pytest.importorskip("numpy")
|
| 489 |
-
|
| 490 |
-
convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
|
| 491 |
-
|
| 492 |
-
def cant_convert(v):
|
| 493 |
-
pytest.raises(TypeError, convert, v)
|
| 494 |
-
|
| 495 |
-
# np.bool_ is not considered implicit
|
| 496 |
-
assert convert(np.bool_(True)) is True
|
| 497 |
-
assert convert(np.bool_(False)) is False
|
| 498 |
-
assert noconvert(np.bool_(True)) is True
|
| 499 |
-
assert noconvert(np.bool_(False)) is False
|
| 500 |
-
cant_convert(np.zeros(2, dtype="int"))
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
def test_int_long():
|
| 504 |
-
assert isinstance(m.int_cast(), int)
|
| 505 |
-
assert isinstance(m.long_cast(), int)
|
| 506 |
-
assert isinstance(m.longlong_cast(), int)
|
| 507 |
-
|
| 508 |
-
|
| 509 |
-
def test_void_caster_2():
|
| 510 |
-
assert m.test_void_caster()
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
def test_const_ref_caster():
|
| 514 |
-
"""Verifies that const-ref is propagated through type_caster cast_op.
|
| 515 |
-
The returned ConstRefCasted type is a minimal type that is constructed to
|
| 516 |
-
reference the casting mode used.
|
| 517 |
-
"""
|
| 518 |
-
x = False
|
| 519 |
-
assert m.takes(x) == 1
|
| 520 |
-
assert m.takes_move(x) == 1
|
| 521 |
-
|
| 522 |
-
assert m.takes_ptr(x) == 3
|
| 523 |
-
assert m.takes_ref(x) == 2
|
| 524 |
-
assert m.takes_ref_wrap(x) == 2
|
| 525 |
-
|
| 526 |
-
assert m.takes_const_ptr(x) == 5
|
| 527 |
-
assert m.takes_const_ref(x) == 4
|
| 528 |
-
assert m.takes_const_ref_wrap(x) == 4
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
import env
|
| 6 |
+
from pybind11_tests import IncType, UserType
|
| 7 |
+
from pybind11_tests import builtin_casters as m
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def test_simple_string():
|
| 11 |
+
assert m.string_roundtrip("const char *") == "const char *"
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def test_unicode_conversion():
|
| 15 |
+
"""Tests unicode conversion and error reporting."""
|
| 16 |
+
assert m.good_utf8_string() == "Say utf8‽ 🎂 𝐀"
|
| 17 |
+
assert m.good_utf16_string() == "b‽🎂𝐀z"
|
| 18 |
+
assert m.good_utf32_string() == "a𝐀🎂‽z"
|
| 19 |
+
assert m.good_wchar_string() == "a⸘𝐀z"
|
| 20 |
+
if hasattr(m, "has_u8string"):
|
| 21 |
+
assert m.good_utf8_u8string() == "Say utf8‽ 🎂 𝐀"
|
| 22 |
+
|
| 23 |
+
with pytest.raises(UnicodeDecodeError):
|
| 24 |
+
m.bad_utf8_string()
|
| 25 |
+
|
| 26 |
+
with pytest.raises(UnicodeDecodeError):
|
| 27 |
+
m.bad_utf16_string()
|
| 28 |
+
|
| 29 |
+
# These are provided only if they actually fail (they don't when 32-bit)
|
| 30 |
+
if hasattr(m, "bad_utf32_string"):
|
| 31 |
+
with pytest.raises(UnicodeDecodeError):
|
| 32 |
+
m.bad_utf32_string()
|
| 33 |
+
if hasattr(m, "bad_wchar_string"):
|
| 34 |
+
with pytest.raises(UnicodeDecodeError):
|
| 35 |
+
m.bad_wchar_string()
|
| 36 |
+
if hasattr(m, "has_u8string"):
|
| 37 |
+
with pytest.raises(UnicodeDecodeError):
|
| 38 |
+
m.bad_utf8_u8string()
|
| 39 |
+
|
| 40 |
+
assert m.u8_Z() == "Z"
|
| 41 |
+
assert m.u8_eacute() == "é"
|
| 42 |
+
assert m.u16_ibang() == "‽"
|
| 43 |
+
assert m.u32_mathbfA() == "𝐀"
|
| 44 |
+
assert m.wchar_heart() == "♥"
|
| 45 |
+
if hasattr(m, "has_u8string"):
|
| 46 |
+
assert m.u8_char8_Z() == "Z"
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def test_single_char_arguments():
|
| 50 |
+
"""Tests failures for passing invalid inputs to char-accepting functions"""
|
| 51 |
+
|
| 52 |
+
def toobig_message(r):
|
| 53 |
+
return f"Character code point not in range({r:#x})"
|
| 54 |
+
|
| 55 |
+
toolong_message = "Expected a character, but multi-character string found"
|
| 56 |
+
|
| 57 |
+
assert m.ord_char("a") == 0x61 # simple ASCII
|
| 58 |
+
assert m.ord_char_lv("b") == 0x62
|
| 59 |
+
assert (
|
| 60 |
+
m.ord_char("é") == 0xE9
|
| 61 |
+
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
| 62 |
+
with pytest.raises(ValueError) as excinfo:
|
| 63 |
+
assert m.ord_char("Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
| 64 |
+
assert str(excinfo.value) == toobig_message(0x100)
|
| 65 |
+
with pytest.raises(ValueError) as excinfo:
|
| 66 |
+
assert m.ord_char("ab")
|
| 67 |
+
assert str(excinfo.value) == toolong_message
|
| 68 |
+
|
| 69 |
+
assert m.ord_char16("a") == 0x61
|
| 70 |
+
assert m.ord_char16("é") == 0xE9
|
| 71 |
+
assert m.ord_char16_lv("ê") == 0xEA
|
| 72 |
+
assert m.ord_char16("Ā") == 0x100
|
| 73 |
+
assert m.ord_char16("‽") == 0x203D
|
| 74 |
+
assert m.ord_char16("♥") == 0x2665
|
| 75 |
+
assert m.ord_char16_lv("♡") == 0x2661
|
| 76 |
+
with pytest.raises(ValueError) as excinfo:
|
| 77 |
+
assert m.ord_char16("🎂") == 0x1F382 # requires surrogate pair
|
| 78 |
+
assert str(excinfo.value) == toobig_message(0x10000)
|
| 79 |
+
with pytest.raises(ValueError) as excinfo:
|
| 80 |
+
assert m.ord_char16("aa")
|
| 81 |
+
assert str(excinfo.value) == toolong_message
|
| 82 |
+
|
| 83 |
+
assert m.ord_char32("a") == 0x61
|
| 84 |
+
assert m.ord_char32("é") == 0xE9
|
| 85 |
+
assert m.ord_char32("Ā") == 0x100
|
| 86 |
+
assert m.ord_char32("‽") == 0x203D
|
| 87 |
+
assert m.ord_char32("♥") == 0x2665
|
| 88 |
+
assert m.ord_char32("🎂") == 0x1F382
|
| 89 |
+
with pytest.raises(ValueError) as excinfo:
|
| 90 |
+
assert m.ord_char32("aa")
|
| 91 |
+
assert str(excinfo.value) == toolong_message
|
| 92 |
+
|
| 93 |
+
assert m.ord_wchar("a") == 0x61
|
| 94 |
+
assert m.ord_wchar("é") == 0xE9
|
| 95 |
+
assert m.ord_wchar("Ā") == 0x100
|
| 96 |
+
assert m.ord_wchar("‽") == 0x203D
|
| 97 |
+
assert m.ord_wchar("♥") == 0x2665
|
| 98 |
+
if m.wchar_size == 2:
|
| 99 |
+
with pytest.raises(ValueError) as excinfo:
|
| 100 |
+
assert m.ord_wchar("🎂") == 0x1F382 # requires surrogate pair
|
| 101 |
+
assert str(excinfo.value) == toobig_message(0x10000)
|
| 102 |
+
else:
|
| 103 |
+
assert m.ord_wchar("🎂") == 0x1F382
|
| 104 |
+
with pytest.raises(ValueError) as excinfo:
|
| 105 |
+
assert m.ord_wchar("aa")
|
| 106 |
+
assert str(excinfo.value) == toolong_message
|
| 107 |
+
|
| 108 |
+
if hasattr(m, "has_u8string"):
|
| 109 |
+
assert m.ord_char8("a") == 0x61 # simple ASCII
|
| 110 |
+
assert m.ord_char8_lv("b") == 0x62
|
| 111 |
+
assert (
|
| 112 |
+
m.ord_char8("é") == 0xE9
|
| 113 |
+
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
| 114 |
+
with pytest.raises(ValueError) as excinfo:
|
| 115 |
+
assert m.ord_char8("Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
| 116 |
+
assert str(excinfo.value) == toobig_message(0x100)
|
| 117 |
+
with pytest.raises(ValueError) as excinfo:
|
| 118 |
+
assert m.ord_char8("ab")
|
| 119 |
+
assert str(excinfo.value) == toolong_message
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def test_bytes_to_string():
|
| 123 |
+
"""Tests the ability to pass bytes to C++ string-accepting functions. Note that this is
|
| 124 |
+
one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
|
| 125 |
+
# Issue #816
|
| 126 |
+
|
| 127 |
+
assert m.strlen(b"hi") == 2
|
| 128 |
+
assert m.string_length(b"world") == 5
|
| 129 |
+
assert m.string_length(b"a\x00b") == 3
|
| 130 |
+
assert m.strlen(b"a\x00b") == 1 # C-string limitation
|
| 131 |
+
|
| 132 |
+
# passing in a utf8 encoded string should work
|
| 133 |
+
assert m.string_length("💩".encode()) == 4
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def test_bytearray_to_string():
|
| 137 |
+
"""Tests the ability to pass bytearray to C++ string-accepting functions"""
|
| 138 |
+
assert m.string_length(bytearray(b"Hi")) == 2
|
| 139 |
+
assert m.strlen(bytearray(b"bytearray")) == 9
|
| 140 |
+
assert m.string_length(bytearray()) == 0
|
| 141 |
+
assert m.string_length(bytearray("🦜", "utf-8", "strict")) == 4
|
| 142 |
+
assert m.string_length(bytearray(b"\x80")) == 1
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
|
| 146 |
+
def test_string_view(capture):
|
| 147 |
+
"""Tests support for C++17 string_view arguments and return values"""
|
| 148 |
+
assert m.string_view_chars("Hi") == [72, 105]
|
| 149 |
+
assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
| 150 |
+
assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
|
| 151 |
+
assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874]
|
| 152 |
+
if hasattr(m, "has_u8string"):
|
| 153 |
+
assert m.string_view8_chars("Hi") == [72, 105]
|
| 154 |
+
assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
| 155 |
+
|
| 156 |
+
assert m.string_view_return() == "utf8 secret 🎂"
|
| 157 |
+
assert m.string_view16_return() == "utf16 secret 🎂"
|
| 158 |
+
assert m.string_view32_return() == "utf32 secret 🎂"
|
| 159 |
+
if hasattr(m, "has_u8string"):
|
| 160 |
+
assert m.string_view8_return() == "utf8 secret 🎂"
|
| 161 |
+
|
| 162 |
+
with capture:
|
| 163 |
+
m.string_view_print("Hi")
|
| 164 |
+
m.string_view_print("utf8 🎂")
|
| 165 |
+
m.string_view16_print("utf16 🎂")
|
| 166 |
+
m.string_view32_print("utf32 🎂")
|
| 167 |
+
assert (
|
| 168 |
+
capture
|
| 169 |
+
== """
|
| 170 |
+
Hi 2
|
| 171 |
+
utf8 🎂 9
|
| 172 |
+
utf16 🎂 8
|
| 173 |
+
utf32 🎂 7
|
| 174 |
+
"""
|
| 175 |
+
)
|
| 176 |
+
if hasattr(m, "has_u8string"):
|
| 177 |
+
with capture:
|
| 178 |
+
m.string_view8_print("Hi")
|
| 179 |
+
m.string_view8_print("utf8 🎂")
|
| 180 |
+
assert (
|
| 181 |
+
capture
|
| 182 |
+
== """
|
| 183 |
+
Hi 2
|
| 184 |
+
utf8 🎂 9
|
| 185 |
+
"""
|
| 186 |
+
)
|
| 187 |
+
|
| 188 |
+
with capture:
|
| 189 |
+
m.string_view_print("Hi, ascii")
|
| 190 |
+
m.string_view_print("Hi, utf8 🎂")
|
| 191 |
+
m.string_view16_print("Hi, utf16 🎂")
|
| 192 |
+
m.string_view32_print("Hi, utf32 🎂")
|
| 193 |
+
assert (
|
| 194 |
+
capture
|
| 195 |
+
== """
|
| 196 |
+
Hi, ascii 9
|
| 197 |
+
Hi, utf8 🎂 13
|
| 198 |
+
Hi, utf16 🎂 12
|
| 199 |
+
Hi, utf32 🎂 11
|
| 200 |
+
"""
|
| 201 |
+
)
|
| 202 |
+
if hasattr(m, "has_u8string"):
|
| 203 |
+
with capture:
|
| 204 |
+
m.string_view8_print("Hi, ascii")
|
| 205 |
+
m.string_view8_print("Hi, utf8 🎂")
|
| 206 |
+
assert (
|
| 207 |
+
capture
|
| 208 |
+
== """
|
| 209 |
+
Hi, ascii 9
|
| 210 |
+
Hi, utf8 🎂 13
|
| 211 |
+
"""
|
| 212 |
+
)
|
| 213 |
+
|
| 214 |
+
assert m.string_view_bytes() == b"abc \x80\x80 def"
|
| 215 |
+
assert m.string_view_str() == "abc ‽ def"
|
| 216 |
+
assert m.string_view_from_bytes("abc ‽ def".encode()) == "abc ‽ def"
|
| 217 |
+
if hasattr(m, "has_u8string"):
|
| 218 |
+
assert m.string_view8_str() == "abc ‽ def"
|
| 219 |
+
assert m.string_view_memoryview() == "Have some 🎂".encode()
|
| 220 |
+
|
| 221 |
+
assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success"
|
| 222 |
+
assert m.str_from_type_with_both_operator_string_and_string_view() == "success"
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
def test_integer_casting():
|
| 226 |
+
"""Issue #929 - out-of-range integer values shouldn't be accepted"""
|
| 227 |
+
assert m.i32_str(-1) == "-1"
|
| 228 |
+
assert m.i64_str(-1) == "-1"
|
| 229 |
+
assert m.i32_str(2000000000) == "2000000000"
|
| 230 |
+
assert m.u32_str(2000000000) == "2000000000"
|
| 231 |
+
assert m.i64_str(-999999999999) == "-999999999999"
|
| 232 |
+
assert m.u64_str(999999999999) == "999999999999"
|
| 233 |
+
|
| 234 |
+
with pytest.raises(TypeError) as excinfo:
|
| 235 |
+
m.u32_str(-1)
|
| 236 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
| 237 |
+
with pytest.raises(TypeError) as excinfo:
|
| 238 |
+
m.u64_str(-1)
|
| 239 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
| 240 |
+
with pytest.raises(TypeError) as excinfo:
|
| 241 |
+
m.i32_str(-3000000000)
|
| 242 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
| 243 |
+
with pytest.raises(TypeError) as excinfo:
|
| 244 |
+
m.i32_str(3000000000)
|
| 245 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
def test_int_convert():
|
| 249 |
+
class Int:
|
| 250 |
+
def __int__(self):
|
| 251 |
+
return 42
|
| 252 |
+
|
| 253 |
+
class NotInt:
|
| 254 |
+
pass
|
| 255 |
+
|
| 256 |
+
class Float:
|
| 257 |
+
def __float__(self):
|
| 258 |
+
return 41.99999
|
| 259 |
+
|
| 260 |
+
class Index:
|
| 261 |
+
def __index__(self):
|
| 262 |
+
return 42
|
| 263 |
+
|
| 264 |
+
class IntAndIndex:
|
| 265 |
+
def __int__(self):
|
| 266 |
+
return 42
|
| 267 |
+
|
| 268 |
+
def __index__(self):
|
| 269 |
+
return 0
|
| 270 |
+
|
| 271 |
+
class RaisingTypeErrorOnIndex:
|
| 272 |
+
def __index__(self):
|
| 273 |
+
raise TypeError
|
| 274 |
+
|
| 275 |
+
def __int__(self):
|
| 276 |
+
return 42
|
| 277 |
+
|
| 278 |
+
class RaisingValueErrorOnIndex:
|
| 279 |
+
def __index__(self):
|
| 280 |
+
raise ValueError
|
| 281 |
+
|
| 282 |
+
def __int__(self):
|
| 283 |
+
return 42
|
| 284 |
+
|
| 285 |
+
convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
|
| 286 |
+
|
| 287 |
+
def requires_conversion(v):
|
| 288 |
+
pytest.raises(TypeError, noconvert, v)
|
| 289 |
+
|
| 290 |
+
def cant_convert(v):
|
| 291 |
+
pytest.raises(TypeError, convert, v)
|
| 292 |
+
|
| 293 |
+
assert convert(7) == 7
|
| 294 |
+
assert noconvert(7) == 7
|
| 295 |
+
cant_convert(3.14159)
|
| 296 |
+
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
| 297 |
+
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
| 298 |
+
if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
|
| 299 |
+
with env.deprecated_call():
|
| 300 |
+
assert convert(Int()) == 42
|
| 301 |
+
else:
|
| 302 |
+
assert convert(Int()) == 42
|
| 303 |
+
requires_conversion(Int())
|
| 304 |
+
cant_convert(NotInt())
|
| 305 |
+
cant_convert(Float())
|
| 306 |
+
|
| 307 |
+
# Before Python 3.8, `PyLong_AsLong` does not pick up on `obj.__index__`,
|
| 308 |
+
# but pybind11 "backports" this behavior.
|
| 309 |
+
assert convert(Index()) == 42
|
| 310 |
+
assert noconvert(Index()) == 42
|
| 311 |
+
assert convert(IntAndIndex()) == 0 # Fishy; `int(DoubleThought)` == 42
|
| 312 |
+
assert noconvert(IntAndIndex()) == 0
|
| 313 |
+
assert convert(RaisingTypeErrorOnIndex()) == 42
|
| 314 |
+
requires_conversion(RaisingTypeErrorOnIndex())
|
| 315 |
+
assert convert(RaisingValueErrorOnIndex()) == 42
|
| 316 |
+
requires_conversion(RaisingValueErrorOnIndex())
|
| 317 |
+
|
| 318 |
+
|
| 319 |
+
def test_numpy_int_convert():
|
| 320 |
+
np = pytest.importorskip("numpy")
|
| 321 |
+
|
| 322 |
+
convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
|
| 323 |
+
|
| 324 |
+
def require_implicit(v):
|
| 325 |
+
pytest.raises(TypeError, noconvert, v)
|
| 326 |
+
|
| 327 |
+
# `np.intc` is an alias that corresponds to a C++ `int`
|
| 328 |
+
assert convert(np.intc(42)) == 42
|
| 329 |
+
assert noconvert(np.intc(42)) == 42
|
| 330 |
+
|
| 331 |
+
# The implicit conversion from np.float32 is undesirable but currently accepted.
|
| 332 |
+
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
| 333 |
+
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
| 334 |
+
# https://github.com/pybind/pybind11/issues/3408
|
| 335 |
+
if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
|
| 336 |
+
with env.deprecated_call():
|
| 337 |
+
assert convert(np.float32(3.14159)) == 3
|
| 338 |
+
else:
|
| 339 |
+
assert convert(np.float32(3.14159)) == 3
|
| 340 |
+
require_implicit(np.float32(3.14159))
|
| 341 |
+
|
| 342 |
+
|
| 343 |
+
def test_tuple(doc):
|
| 344 |
+
"""std::pair <-> tuple & std::tuple <-> tuple"""
|
| 345 |
+
assert m.pair_passthrough((True, "test")) == ("test", True)
|
| 346 |
+
assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True)
|
| 347 |
+
# Any sequence can be cast to a std::pair or std::tuple
|
| 348 |
+
assert m.pair_passthrough([True, "test"]) == ("test", True)
|
| 349 |
+
assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True)
|
| 350 |
+
assert m.empty_tuple() == ()
|
| 351 |
+
|
| 352 |
+
assert (
|
| 353 |
+
doc(m.pair_passthrough)
|
| 354 |
+
== """
|
| 355 |
+
pair_passthrough(arg0: tuple[bool, str]) -> tuple[str, bool]
|
| 356 |
+
|
| 357 |
+
Return a pair in reversed order
|
| 358 |
+
"""
|
| 359 |
+
)
|
| 360 |
+
assert (
|
| 361 |
+
doc(m.tuple_passthrough)
|
| 362 |
+
== """
|
| 363 |
+
tuple_passthrough(arg0: tuple[bool, str, int]) -> tuple[int, str, bool]
|
| 364 |
+
|
| 365 |
+
Return a triple in reversed order
|
| 366 |
+
"""
|
| 367 |
+
)
|
| 368 |
+
|
| 369 |
+
assert m.rvalue_pair() == ("rvalue", "rvalue")
|
| 370 |
+
assert m.lvalue_pair() == ("lvalue", "lvalue")
|
| 371 |
+
assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
|
| 372 |
+
assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue")
|
| 373 |
+
assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue")))
|
| 374 |
+
assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue")))
|
| 375 |
+
|
| 376 |
+
assert m.int_string_pair() == (2, "items")
|
| 377 |
+
|
| 378 |
+
|
| 379 |
+
def test_builtins_cast_return_none():
|
| 380 |
+
"""Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
|
| 381 |
+
assert m.return_none_string() is None
|
| 382 |
+
assert m.return_none_char() is None
|
| 383 |
+
assert m.return_none_bool() is None
|
| 384 |
+
assert m.return_none_int() is None
|
| 385 |
+
assert m.return_none_float() is None
|
| 386 |
+
assert m.return_none_pair() is None
|
| 387 |
+
|
| 388 |
+
|
| 389 |
+
def test_none_deferred():
|
| 390 |
+
"""None passed as various argument types should defer to other overloads"""
|
| 391 |
+
assert not m.defer_none_cstring("abc")
|
| 392 |
+
assert m.defer_none_cstring(None)
|
| 393 |
+
assert not m.defer_none_custom(UserType())
|
| 394 |
+
assert m.defer_none_custom(None)
|
| 395 |
+
assert m.nodefer_none_void(None)
|
| 396 |
+
|
| 397 |
+
|
| 398 |
+
def test_void_caster():
|
| 399 |
+
assert m.load_nullptr_t(None) is None
|
| 400 |
+
assert m.cast_nullptr_t() is None
|
| 401 |
+
|
| 402 |
+
|
| 403 |
+
def test_reference_wrapper():
|
| 404 |
+
"""std::reference_wrapper for builtin and user types"""
|
| 405 |
+
assert m.refwrap_builtin(42) == 420
|
| 406 |
+
assert m.refwrap_usertype(UserType(42)) == 42
|
| 407 |
+
assert m.refwrap_usertype_const(UserType(42)) == 42
|
| 408 |
+
|
| 409 |
+
with pytest.raises(TypeError) as excinfo:
|
| 410 |
+
m.refwrap_builtin(None)
|
| 411 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
| 412 |
+
|
| 413 |
+
with pytest.raises(TypeError) as excinfo:
|
| 414 |
+
m.refwrap_usertype(None)
|
| 415 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
| 416 |
+
|
| 417 |
+
assert m.refwrap_lvalue().value == 1
|
| 418 |
+
assert m.refwrap_lvalue_const().value == 1
|
| 419 |
+
|
| 420 |
+
a1 = m.refwrap_list(copy=True)
|
| 421 |
+
a2 = m.refwrap_list(copy=True)
|
| 422 |
+
assert [x.value for x in a1] == [2, 3]
|
| 423 |
+
assert [x.value for x in a2] == [2, 3]
|
| 424 |
+
assert a1[0] is not a2[0]
|
| 425 |
+
assert a1[1] is not a2[1]
|
| 426 |
+
|
| 427 |
+
b1 = m.refwrap_list(copy=False)
|
| 428 |
+
b2 = m.refwrap_list(copy=False)
|
| 429 |
+
assert [x.value for x in b1] == [1, 2]
|
| 430 |
+
assert [x.value for x in b2] == [1, 2]
|
| 431 |
+
assert b1[0] is b2[0]
|
| 432 |
+
assert b1[1] is b2[1]
|
| 433 |
+
|
| 434 |
+
assert m.refwrap_iiw(IncType(5)) == 5
|
| 435 |
+
assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10]
|
| 436 |
+
|
| 437 |
+
|
| 438 |
+
def test_complex_cast():
|
| 439 |
+
"""std::complex casts"""
|
| 440 |
+
assert m.complex_cast(1) == "1.0"
|
| 441 |
+
assert m.complex_cast(2j) == "(0.0, 2.0)"
|
| 442 |
+
|
| 443 |
+
|
| 444 |
+
def test_bool_caster():
|
| 445 |
+
"""Test bool caster implicit conversions."""
|
| 446 |
+
convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
|
| 447 |
+
|
| 448 |
+
def require_implicit(v):
|
| 449 |
+
pytest.raises(TypeError, noconvert, v)
|
| 450 |
+
|
| 451 |
+
def cant_convert(v):
|
| 452 |
+
pytest.raises(TypeError, convert, v)
|
| 453 |
+
|
| 454 |
+
# straight up bool
|
| 455 |
+
assert convert(True) is True
|
| 456 |
+
assert convert(False) is False
|
| 457 |
+
assert noconvert(True) is True
|
| 458 |
+
assert noconvert(False) is False
|
| 459 |
+
|
| 460 |
+
# None requires implicit conversion
|
| 461 |
+
require_implicit(None)
|
| 462 |
+
assert convert(None) is False
|
| 463 |
+
|
| 464 |
+
class A:
|
| 465 |
+
def __init__(self, x):
|
| 466 |
+
self.x = x
|
| 467 |
+
|
| 468 |
+
def __nonzero__(self):
|
| 469 |
+
return self.x
|
| 470 |
+
|
| 471 |
+
def __bool__(self):
|
| 472 |
+
return self.x
|
| 473 |
+
|
| 474 |
+
class B:
|
| 475 |
+
pass
|
| 476 |
+
|
| 477 |
+
# Arbitrary objects are not accepted
|
| 478 |
+
cant_convert(object())
|
| 479 |
+
cant_convert(B())
|
| 480 |
+
|
| 481 |
+
# Objects with __nonzero__ / __bool__ defined can be converted
|
| 482 |
+
require_implicit(A(True))
|
| 483 |
+
assert convert(A(True)) is True
|
| 484 |
+
assert convert(A(False)) is False
|
| 485 |
+
|
| 486 |
+
|
| 487 |
+
def test_numpy_bool():
|
| 488 |
+
np = pytest.importorskip("numpy")
|
| 489 |
+
|
| 490 |
+
convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
|
| 491 |
+
|
| 492 |
+
def cant_convert(v):
|
| 493 |
+
pytest.raises(TypeError, convert, v)
|
| 494 |
+
|
| 495 |
+
# np.bool_ is not considered implicit
|
| 496 |
+
assert convert(np.bool_(True)) is True
|
| 497 |
+
assert convert(np.bool_(False)) is False
|
| 498 |
+
assert noconvert(np.bool_(True)) is True
|
| 499 |
+
assert noconvert(np.bool_(False)) is False
|
| 500 |
+
cant_convert(np.zeros(2, dtype="int"))
|
| 501 |
+
|
| 502 |
+
|
| 503 |
+
def test_int_long():
|
| 504 |
+
assert isinstance(m.int_cast(), int)
|
| 505 |
+
assert isinstance(m.long_cast(), int)
|
| 506 |
+
assert isinstance(m.longlong_cast(), int)
|
| 507 |
+
|
| 508 |
+
|
| 509 |
+
def test_void_caster_2():
|
| 510 |
+
assert m.test_void_caster()
|
| 511 |
+
|
| 512 |
+
|
| 513 |
+
def test_const_ref_caster():
|
| 514 |
+
"""Verifies that const-ref is propagated through type_caster cast_op.
|
| 515 |
+
The returned ConstRefCasted type is a minimal type that is constructed to
|
| 516 |
+
reference the casting mode used.
|
| 517 |
+
"""
|
| 518 |
+
x = False
|
| 519 |
+
assert m.takes(x) == 1
|
| 520 |
+
assert m.takes_move(x) == 1
|
| 521 |
+
|
| 522 |
+
assert m.takes_ptr(x) == 3
|
| 523 |
+
assert m.takes_ref(x) == 2
|
| 524 |
+
assert m.takes_ref_wrap(x) == 2
|
| 525 |
+
|
| 526 |
+
assert m.takes_const_ptr(x) == 5
|
| 527 |
+
assert m.takes_const_ref(x) == 4
|
| 528 |
+
assert m.takes_const_ref_wrap(x) == 4
|
third_party/CityFlow/extern/pybind11/tests/test_call_policies.cpp
CHANGED
|
@@ -1,115 +1,115 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_call_policies.cpp -- keep_alive and call_guard
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#include "pybind11_tests.h"
|
| 11 |
-
|
| 12 |
-
struct CustomGuard {
|
| 13 |
-
static bool enabled;
|
| 14 |
-
|
| 15 |
-
CustomGuard() { enabled = true; }
|
| 16 |
-
~CustomGuard() { enabled = false; }
|
| 17 |
-
|
| 18 |
-
static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
|
| 19 |
-
};
|
| 20 |
-
bool CustomGuard::enabled = false;
|
| 21 |
-
|
| 22 |
-
struct DependentGuard {
|
| 23 |
-
static bool enabled;
|
| 24 |
-
|
| 25 |
-
DependentGuard() { enabled = CustomGuard::enabled; }
|
| 26 |
-
~DependentGuard() { enabled = false; }
|
| 27 |
-
|
| 28 |
-
static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
|
| 29 |
-
};
|
| 30 |
-
bool DependentGuard::enabled = false;
|
| 31 |
-
|
| 32 |
-
TEST_SUBMODULE(call_policies, m) {
|
| 33 |
-
// Parent/Child are used in:
|
| 34 |
-
// test_keep_alive_argument, test_keep_alive_return_value, test_alive_gc_derived,
|
| 35 |
-
// test_alive_gc_multi_derived, test_return_none, test_keep_alive_constructor
|
| 36 |
-
class Child {
|
| 37 |
-
public:
|
| 38 |
-
Child() { py::print("Allocating child."); }
|
| 39 |
-
Child(const Child &) = default;
|
| 40 |
-
Child(Child &&) = default;
|
| 41 |
-
~Child() { py::print("Releasing child."); }
|
| 42 |
-
};
|
| 43 |
-
py::class_<Child>(m, "Child").def(py::init<>());
|
| 44 |
-
|
| 45 |
-
class Parent {
|
| 46 |
-
public:
|
| 47 |
-
Parent() { py::print("Allocating parent."); }
|
| 48 |
-
Parent(const Parent &parent) = default;
|
| 49 |
-
~Parent() { py::print("Releasing parent."); }
|
| 50 |
-
void addChild(Child *) {}
|
| 51 |
-
Child *returnChild() { return new Child(); }
|
| 52 |
-
Child *returnNullChild() { return nullptr; }
|
| 53 |
-
static Child *staticFunction(Parent *) { return new Child(); }
|
| 54 |
-
};
|
| 55 |
-
py::class_<Parent>(m, "Parent")
|
| 56 |
-
.def(py::init<>())
|
| 57 |
-
.def(py::init([](Child *) { return new Parent(); }), py::keep_alive<1, 2>())
|
| 58 |
-
.def("addChild", &Parent::addChild)
|
| 59 |
-
.def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>())
|
| 60 |
-
.def("returnChild", &Parent::returnChild)
|
| 61 |
-
.def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
|
| 62 |
-
.def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
|
| 63 |
-
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>())
|
| 64 |
-
.def_static("staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
|
| 65 |
-
|
| 66 |
-
m.def(
|
| 67 |
-
"free_function", [](Parent *, Child *) {}, py::keep_alive<1, 2>());
|
| 68 |
-
m.def(
|
| 69 |
-
"invalid_arg_index", [] {}, py::keep_alive<0, 1>());
|
| 70 |
-
|
| 71 |
-
#if !defined(PYPY_VERSION)
|
| 72 |
-
// test_alive_gc
|
| 73 |
-
class ParentGC : public Parent {
|
| 74 |
-
public:
|
| 75 |
-
using Parent::Parent;
|
| 76 |
-
};
|
| 77 |
-
py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr()).def(py::init<>());
|
| 78 |
-
#endif
|
| 79 |
-
|
| 80 |
-
// test_call_guard
|
| 81 |
-
m.def("unguarded_call", &CustomGuard::report_status);
|
| 82 |
-
m.def("guarded_call", &CustomGuard::report_status, py::call_guard<CustomGuard>());
|
| 83 |
-
|
| 84 |
-
m.def(
|
| 85 |
-
"multiple_guards_correct_order",
|
| 86 |
-
[]() {
|
| 87 |
-
return CustomGuard::report_status() + std::string(" & ")
|
| 88 |
-
+ DependentGuard::report_status();
|
| 89 |
-
},
|
| 90 |
-
py::call_guard<CustomGuard, DependentGuard>());
|
| 91 |
-
|
| 92 |
-
m.def(
|
| 93 |
-
"multiple_guards_wrong_order",
|
| 94 |
-
[]() {
|
| 95 |
-
return DependentGuard::report_status() + std::string(" & ")
|
| 96 |
-
+ CustomGuard::report_status();
|
| 97 |
-
},
|
| 98 |
-
py::call_guard<DependentGuard, CustomGuard>());
|
| 99 |
-
|
| 100 |
-
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
|
| 101 |
-
// `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
|
| 102 |
-
// but it's unclear how to test it without `PyGILState_GetThisThreadState`.
|
| 103 |
-
auto report_gil_status = []() {
|
| 104 |
-
auto is_gil_held = false;
|
| 105 |
-
if (auto *tstate = py::detail::get_thread_state_unchecked()) {
|
| 106 |
-
is_gil_held = (tstate == PyGILState_GetThisThreadState());
|
| 107 |
-
}
|
| 108 |
-
|
| 109 |
-
return is_gil_held ? "GIL held" : "GIL released";
|
| 110 |
-
};
|
| 111 |
-
|
| 112 |
-
m.def("with_gil", report_gil_status);
|
| 113 |
-
m.def("without_gil", report_gil_status, py::call_guard<py::gil_scoped_release>());
|
| 114 |
-
#endif
|
| 115 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_call_policies.cpp -- keep_alive and call_guard
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#include "pybind11_tests.h"
|
| 11 |
+
|
| 12 |
+
struct CustomGuard {
|
| 13 |
+
static bool enabled;
|
| 14 |
+
|
| 15 |
+
CustomGuard() { enabled = true; }
|
| 16 |
+
~CustomGuard() { enabled = false; }
|
| 17 |
+
|
| 18 |
+
static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
|
| 19 |
+
};
|
| 20 |
+
bool CustomGuard::enabled = false;
|
| 21 |
+
|
| 22 |
+
struct DependentGuard {
|
| 23 |
+
static bool enabled;
|
| 24 |
+
|
| 25 |
+
DependentGuard() { enabled = CustomGuard::enabled; }
|
| 26 |
+
~DependentGuard() { enabled = false; }
|
| 27 |
+
|
| 28 |
+
static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
|
| 29 |
+
};
|
| 30 |
+
bool DependentGuard::enabled = false;
|
| 31 |
+
|
| 32 |
+
TEST_SUBMODULE(call_policies, m) {
|
| 33 |
+
// Parent/Child are used in:
|
| 34 |
+
// test_keep_alive_argument, test_keep_alive_return_value, test_alive_gc_derived,
|
| 35 |
+
// test_alive_gc_multi_derived, test_return_none, test_keep_alive_constructor
|
| 36 |
+
class Child {
|
| 37 |
+
public:
|
| 38 |
+
Child() { py::print("Allocating child."); }
|
| 39 |
+
Child(const Child &) = default;
|
| 40 |
+
Child(Child &&) = default;
|
| 41 |
+
~Child() { py::print("Releasing child."); }
|
| 42 |
+
};
|
| 43 |
+
py::class_<Child>(m, "Child").def(py::init<>());
|
| 44 |
+
|
| 45 |
+
class Parent {
|
| 46 |
+
public:
|
| 47 |
+
Parent() { py::print("Allocating parent."); }
|
| 48 |
+
Parent(const Parent &parent) = default;
|
| 49 |
+
~Parent() { py::print("Releasing parent."); }
|
| 50 |
+
void addChild(Child *) {}
|
| 51 |
+
Child *returnChild() { return new Child(); }
|
| 52 |
+
Child *returnNullChild() { return nullptr; }
|
| 53 |
+
static Child *staticFunction(Parent *) { return new Child(); }
|
| 54 |
+
};
|
| 55 |
+
py::class_<Parent>(m, "Parent")
|
| 56 |
+
.def(py::init<>())
|
| 57 |
+
.def(py::init([](Child *) { return new Parent(); }), py::keep_alive<1, 2>())
|
| 58 |
+
.def("addChild", &Parent::addChild)
|
| 59 |
+
.def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>())
|
| 60 |
+
.def("returnChild", &Parent::returnChild)
|
| 61 |
+
.def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
|
| 62 |
+
.def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
|
| 63 |
+
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>())
|
| 64 |
+
.def_static("staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
|
| 65 |
+
|
| 66 |
+
m.def(
|
| 67 |
+
"free_function", [](Parent *, Child *) {}, py::keep_alive<1, 2>());
|
| 68 |
+
m.def(
|
| 69 |
+
"invalid_arg_index", [] {}, py::keep_alive<0, 1>());
|
| 70 |
+
|
| 71 |
+
#if !defined(PYPY_VERSION)
|
| 72 |
+
// test_alive_gc
|
| 73 |
+
class ParentGC : public Parent {
|
| 74 |
+
public:
|
| 75 |
+
using Parent::Parent;
|
| 76 |
+
};
|
| 77 |
+
py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr()).def(py::init<>());
|
| 78 |
+
#endif
|
| 79 |
+
|
| 80 |
+
// test_call_guard
|
| 81 |
+
m.def("unguarded_call", &CustomGuard::report_status);
|
| 82 |
+
m.def("guarded_call", &CustomGuard::report_status, py::call_guard<CustomGuard>());
|
| 83 |
+
|
| 84 |
+
m.def(
|
| 85 |
+
"multiple_guards_correct_order",
|
| 86 |
+
[]() {
|
| 87 |
+
return CustomGuard::report_status() + std::string(" & ")
|
| 88 |
+
+ DependentGuard::report_status();
|
| 89 |
+
},
|
| 90 |
+
py::call_guard<CustomGuard, DependentGuard>());
|
| 91 |
+
|
| 92 |
+
m.def(
|
| 93 |
+
"multiple_guards_wrong_order",
|
| 94 |
+
[]() {
|
| 95 |
+
return DependentGuard::report_status() + std::string(" & ")
|
| 96 |
+
+ CustomGuard::report_status();
|
| 97 |
+
},
|
| 98 |
+
py::call_guard<DependentGuard, CustomGuard>());
|
| 99 |
+
|
| 100 |
+
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
|
| 101 |
+
// `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
|
| 102 |
+
// but it's unclear how to test it without `PyGILState_GetThisThreadState`.
|
| 103 |
+
auto report_gil_status = []() {
|
| 104 |
+
auto is_gil_held = false;
|
| 105 |
+
if (auto *tstate = py::detail::get_thread_state_unchecked()) {
|
| 106 |
+
is_gil_held = (tstate == PyGILState_GetThisThreadState());
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
return is_gil_held ? "GIL held" : "GIL released";
|
| 110 |
+
};
|
| 111 |
+
|
| 112 |
+
m.def("with_gil", report_gil_status);
|
| 113 |
+
m.def("without_gil", report_gil_status, py::call_guard<py::gil_scoped_release>());
|
| 114 |
+
#endif
|
| 115 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_call_policies.py
CHANGED
|
@@ -1,247 +1,247 @@
|
|
| 1 |
-
import pytest
|
| 2 |
-
|
| 3 |
-
import env # noqa: F401
|
| 4 |
-
from pybind11_tests import ConstructorStats
|
| 5 |
-
from pybind11_tests import call_policies as m
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
@pytest.mark.xfail("env.PYPY", reason="sometimes comes out 1 off on PyPy", strict=False)
|
| 9 |
-
def test_keep_alive_argument(capture):
|
| 10 |
-
n_inst = ConstructorStats.detail_reg_inst()
|
| 11 |
-
with capture:
|
| 12 |
-
p = m.Parent()
|
| 13 |
-
assert capture == "Allocating parent."
|
| 14 |
-
with capture:
|
| 15 |
-
p.addChild(m.Child())
|
| 16 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
| 17 |
-
assert (
|
| 18 |
-
capture
|
| 19 |
-
== """
|
| 20 |
-
Allocating child.
|
| 21 |
-
Releasing child.
|
| 22 |
-
"""
|
| 23 |
-
)
|
| 24 |
-
with capture:
|
| 25 |
-
del p
|
| 26 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 27 |
-
assert capture == "Releasing parent."
|
| 28 |
-
|
| 29 |
-
with capture:
|
| 30 |
-
p = m.Parent()
|
| 31 |
-
assert capture == "Allocating parent."
|
| 32 |
-
with capture:
|
| 33 |
-
p.addChildKeepAlive(m.Child())
|
| 34 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 35 |
-
assert capture == "Allocating child."
|
| 36 |
-
with capture:
|
| 37 |
-
del p
|
| 38 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 39 |
-
assert (
|
| 40 |
-
capture
|
| 41 |
-
== """
|
| 42 |
-
Releasing parent.
|
| 43 |
-
Releasing child.
|
| 44 |
-
"""
|
| 45 |
-
)
|
| 46 |
-
|
| 47 |
-
p = m.Parent()
|
| 48 |
-
c = m.Child()
|
| 49 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 50 |
-
m.free_function(p, c)
|
| 51 |
-
del c
|
| 52 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 53 |
-
del p
|
| 54 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 55 |
-
|
| 56 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 57 |
-
m.invalid_arg_index()
|
| 58 |
-
assert str(excinfo.value) == "Could not activate keep_alive!"
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
def test_keep_alive_return_value(capture):
|
| 62 |
-
n_inst = ConstructorStats.detail_reg_inst()
|
| 63 |
-
with capture:
|
| 64 |
-
p = m.Parent()
|
| 65 |
-
assert capture == "Allocating parent."
|
| 66 |
-
with capture:
|
| 67 |
-
p.returnChild()
|
| 68 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
| 69 |
-
assert (
|
| 70 |
-
capture
|
| 71 |
-
== """
|
| 72 |
-
Allocating child.
|
| 73 |
-
Releasing child.
|
| 74 |
-
"""
|
| 75 |
-
)
|
| 76 |
-
with capture:
|
| 77 |
-
del p
|
| 78 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 79 |
-
assert capture == "Releasing parent."
|
| 80 |
-
|
| 81 |
-
with capture:
|
| 82 |
-
p = m.Parent()
|
| 83 |
-
assert capture == "Allocating parent."
|
| 84 |
-
with capture:
|
| 85 |
-
p.returnChildKeepAlive()
|
| 86 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 87 |
-
assert capture == "Allocating child."
|
| 88 |
-
with capture:
|
| 89 |
-
del p
|
| 90 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 91 |
-
assert (
|
| 92 |
-
capture
|
| 93 |
-
== """
|
| 94 |
-
Releasing parent.
|
| 95 |
-
Releasing child.
|
| 96 |
-
"""
|
| 97 |
-
)
|
| 98 |
-
|
| 99 |
-
p = m.Parent()
|
| 100 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
| 101 |
-
with capture:
|
| 102 |
-
m.Parent.staticFunction(p)
|
| 103 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 104 |
-
assert capture == "Allocating child."
|
| 105 |
-
with capture:
|
| 106 |
-
del p
|
| 107 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 108 |
-
assert (
|
| 109 |
-
capture
|
| 110 |
-
== """
|
| 111 |
-
Releasing parent.
|
| 112 |
-
Releasing child.
|
| 113 |
-
"""
|
| 114 |
-
)
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
# https://foss.heptapod.net/pypy/pypy/-/issues/2447
|
| 118 |
-
@pytest.mark.xfail("env.PYPY", reason="_PyObject_GetDictPtr is unimplemented")
|
| 119 |
-
def test_alive_gc(capture):
|
| 120 |
-
n_inst = ConstructorStats.detail_reg_inst()
|
| 121 |
-
p = m.ParentGC()
|
| 122 |
-
p.addChildKeepAlive(m.Child())
|
| 123 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 124 |
-
lst = [p]
|
| 125 |
-
lst.append(lst) # creates a circular reference
|
| 126 |
-
with capture:
|
| 127 |
-
del p, lst
|
| 128 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 129 |
-
assert (
|
| 130 |
-
capture
|
| 131 |
-
== """
|
| 132 |
-
Releasing parent.
|
| 133 |
-
Releasing child.
|
| 134 |
-
"""
|
| 135 |
-
)
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
def test_alive_gc_derived(capture):
|
| 139 |
-
class Derived(m.Parent):
|
| 140 |
-
pass
|
| 141 |
-
|
| 142 |
-
n_inst = ConstructorStats.detail_reg_inst()
|
| 143 |
-
p = Derived()
|
| 144 |
-
p.addChildKeepAlive(m.Child())
|
| 145 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 146 |
-
lst = [p]
|
| 147 |
-
lst.append(lst) # creates a circular reference
|
| 148 |
-
with capture:
|
| 149 |
-
del p, lst
|
| 150 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 151 |
-
assert (
|
| 152 |
-
capture
|
| 153 |
-
== """
|
| 154 |
-
Releasing parent.
|
| 155 |
-
Releasing child.
|
| 156 |
-
"""
|
| 157 |
-
)
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
def test_alive_gc_multi_derived(capture):
|
| 161 |
-
class Derived(m.Parent, m.Child):
|
| 162 |
-
def __init__(self):
|
| 163 |
-
m.Parent.__init__(self)
|
| 164 |
-
m.Child.__init__(self)
|
| 165 |
-
|
| 166 |
-
n_inst = ConstructorStats.detail_reg_inst()
|
| 167 |
-
p = Derived()
|
| 168 |
-
p.addChildKeepAlive(m.Child())
|
| 169 |
-
# +3 rather than +2 because Derived corresponds to two registered instances
|
| 170 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 3
|
| 171 |
-
lst = [p]
|
| 172 |
-
lst.append(lst) # creates a circular reference
|
| 173 |
-
with capture:
|
| 174 |
-
del p, lst
|
| 175 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 176 |
-
assert (
|
| 177 |
-
capture
|
| 178 |
-
== """
|
| 179 |
-
Releasing parent.
|
| 180 |
-
Releasing child.
|
| 181 |
-
Releasing child.
|
| 182 |
-
"""
|
| 183 |
-
)
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
def test_return_none(capture):
|
| 187 |
-
n_inst = ConstructorStats.detail_reg_inst()
|
| 188 |
-
with capture:
|
| 189 |
-
p = m.Parent()
|
| 190 |
-
assert capture == "Allocating parent."
|
| 191 |
-
with capture:
|
| 192 |
-
p.returnNullChildKeepAliveChild()
|
| 193 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
| 194 |
-
assert capture == ""
|
| 195 |
-
with capture:
|
| 196 |
-
del p
|
| 197 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 198 |
-
assert capture == "Releasing parent."
|
| 199 |
-
|
| 200 |
-
with capture:
|
| 201 |
-
p = m.Parent()
|
| 202 |
-
assert capture == "Allocating parent."
|
| 203 |
-
with capture:
|
| 204 |
-
p.returnNullChildKeepAliveParent()
|
| 205 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
| 206 |
-
assert capture == ""
|
| 207 |
-
with capture:
|
| 208 |
-
del p
|
| 209 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 210 |
-
assert capture == "Releasing parent."
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
def test_keep_alive_constructor(capture):
|
| 214 |
-
n_inst = ConstructorStats.detail_reg_inst()
|
| 215 |
-
|
| 216 |
-
with capture:
|
| 217 |
-
p = m.Parent(m.Child())
|
| 218 |
-
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 219 |
-
assert (
|
| 220 |
-
capture
|
| 221 |
-
== """
|
| 222 |
-
Allocating child.
|
| 223 |
-
Allocating parent.
|
| 224 |
-
"""
|
| 225 |
-
)
|
| 226 |
-
with capture:
|
| 227 |
-
del p
|
| 228 |
-
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 229 |
-
assert (
|
| 230 |
-
capture
|
| 231 |
-
== """
|
| 232 |
-
Releasing parent.
|
| 233 |
-
Releasing child.
|
| 234 |
-
"""
|
| 235 |
-
)
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
def test_call_guard():
|
| 239 |
-
assert m.unguarded_call() == "unguarded"
|
| 240 |
-
assert m.guarded_call() == "guarded"
|
| 241 |
-
|
| 242 |
-
assert m.multiple_guards_correct_order() == "guarded & guarded"
|
| 243 |
-
assert m.multiple_guards_wrong_order() == "unguarded & guarded"
|
| 244 |
-
|
| 245 |
-
if hasattr(m, "with_gil"):
|
| 246 |
-
assert m.with_gil() == "GIL held"
|
| 247 |
-
assert m.without_gil() == "GIL released"
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
import env # noqa: F401
|
| 4 |
+
from pybind11_tests import ConstructorStats
|
| 5 |
+
from pybind11_tests import call_policies as m
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
@pytest.mark.xfail("env.PYPY", reason="sometimes comes out 1 off on PyPy", strict=False)
|
| 9 |
+
def test_keep_alive_argument(capture):
|
| 10 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
| 11 |
+
with capture:
|
| 12 |
+
p = m.Parent()
|
| 13 |
+
assert capture == "Allocating parent."
|
| 14 |
+
with capture:
|
| 15 |
+
p.addChild(m.Child())
|
| 16 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
| 17 |
+
assert (
|
| 18 |
+
capture
|
| 19 |
+
== """
|
| 20 |
+
Allocating child.
|
| 21 |
+
Releasing child.
|
| 22 |
+
"""
|
| 23 |
+
)
|
| 24 |
+
with capture:
|
| 25 |
+
del p
|
| 26 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 27 |
+
assert capture == "Releasing parent."
|
| 28 |
+
|
| 29 |
+
with capture:
|
| 30 |
+
p = m.Parent()
|
| 31 |
+
assert capture == "Allocating parent."
|
| 32 |
+
with capture:
|
| 33 |
+
p.addChildKeepAlive(m.Child())
|
| 34 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 35 |
+
assert capture == "Allocating child."
|
| 36 |
+
with capture:
|
| 37 |
+
del p
|
| 38 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 39 |
+
assert (
|
| 40 |
+
capture
|
| 41 |
+
== """
|
| 42 |
+
Releasing parent.
|
| 43 |
+
Releasing child.
|
| 44 |
+
"""
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
+
p = m.Parent()
|
| 48 |
+
c = m.Child()
|
| 49 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 50 |
+
m.free_function(p, c)
|
| 51 |
+
del c
|
| 52 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 53 |
+
del p
|
| 54 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 55 |
+
|
| 56 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 57 |
+
m.invalid_arg_index()
|
| 58 |
+
assert str(excinfo.value) == "Could not activate keep_alive!"
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def test_keep_alive_return_value(capture):
|
| 62 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
| 63 |
+
with capture:
|
| 64 |
+
p = m.Parent()
|
| 65 |
+
assert capture == "Allocating parent."
|
| 66 |
+
with capture:
|
| 67 |
+
p.returnChild()
|
| 68 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
| 69 |
+
assert (
|
| 70 |
+
capture
|
| 71 |
+
== """
|
| 72 |
+
Allocating child.
|
| 73 |
+
Releasing child.
|
| 74 |
+
"""
|
| 75 |
+
)
|
| 76 |
+
with capture:
|
| 77 |
+
del p
|
| 78 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 79 |
+
assert capture == "Releasing parent."
|
| 80 |
+
|
| 81 |
+
with capture:
|
| 82 |
+
p = m.Parent()
|
| 83 |
+
assert capture == "Allocating parent."
|
| 84 |
+
with capture:
|
| 85 |
+
p.returnChildKeepAlive()
|
| 86 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 87 |
+
assert capture == "Allocating child."
|
| 88 |
+
with capture:
|
| 89 |
+
del p
|
| 90 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 91 |
+
assert (
|
| 92 |
+
capture
|
| 93 |
+
== """
|
| 94 |
+
Releasing parent.
|
| 95 |
+
Releasing child.
|
| 96 |
+
"""
|
| 97 |
+
)
|
| 98 |
+
|
| 99 |
+
p = m.Parent()
|
| 100 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
| 101 |
+
with capture:
|
| 102 |
+
m.Parent.staticFunction(p)
|
| 103 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 104 |
+
assert capture == "Allocating child."
|
| 105 |
+
with capture:
|
| 106 |
+
del p
|
| 107 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 108 |
+
assert (
|
| 109 |
+
capture
|
| 110 |
+
== """
|
| 111 |
+
Releasing parent.
|
| 112 |
+
Releasing child.
|
| 113 |
+
"""
|
| 114 |
+
)
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
# https://foss.heptapod.net/pypy/pypy/-/issues/2447
|
| 118 |
+
@pytest.mark.xfail("env.PYPY", reason="_PyObject_GetDictPtr is unimplemented")
|
| 119 |
+
def test_alive_gc(capture):
|
| 120 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
| 121 |
+
p = m.ParentGC()
|
| 122 |
+
p.addChildKeepAlive(m.Child())
|
| 123 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 124 |
+
lst = [p]
|
| 125 |
+
lst.append(lst) # creates a circular reference
|
| 126 |
+
with capture:
|
| 127 |
+
del p, lst
|
| 128 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 129 |
+
assert (
|
| 130 |
+
capture
|
| 131 |
+
== """
|
| 132 |
+
Releasing parent.
|
| 133 |
+
Releasing child.
|
| 134 |
+
"""
|
| 135 |
+
)
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def test_alive_gc_derived(capture):
|
| 139 |
+
class Derived(m.Parent):
|
| 140 |
+
pass
|
| 141 |
+
|
| 142 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
| 143 |
+
p = Derived()
|
| 144 |
+
p.addChildKeepAlive(m.Child())
|
| 145 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 146 |
+
lst = [p]
|
| 147 |
+
lst.append(lst) # creates a circular reference
|
| 148 |
+
with capture:
|
| 149 |
+
del p, lst
|
| 150 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 151 |
+
assert (
|
| 152 |
+
capture
|
| 153 |
+
== """
|
| 154 |
+
Releasing parent.
|
| 155 |
+
Releasing child.
|
| 156 |
+
"""
|
| 157 |
+
)
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
def test_alive_gc_multi_derived(capture):
|
| 161 |
+
class Derived(m.Parent, m.Child):
|
| 162 |
+
def __init__(self):
|
| 163 |
+
m.Parent.__init__(self)
|
| 164 |
+
m.Child.__init__(self)
|
| 165 |
+
|
| 166 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
| 167 |
+
p = Derived()
|
| 168 |
+
p.addChildKeepAlive(m.Child())
|
| 169 |
+
# +3 rather than +2 because Derived corresponds to two registered instances
|
| 170 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 3
|
| 171 |
+
lst = [p]
|
| 172 |
+
lst.append(lst) # creates a circular reference
|
| 173 |
+
with capture:
|
| 174 |
+
del p, lst
|
| 175 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 176 |
+
assert (
|
| 177 |
+
capture
|
| 178 |
+
== """
|
| 179 |
+
Releasing parent.
|
| 180 |
+
Releasing child.
|
| 181 |
+
Releasing child.
|
| 182 |
+
"""
|
| 183 |
+
)
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
def test_return_none(capture):
|
| 187 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
| 188 |
+
with capture:
|
| 189 |
+
p = m.Parent()
|
| 190 |
+
assert capture == "Allocating parent."
|
| 191 |
+
with capture:
|
| 192 |
+
p.returnNullChildKeepAliveChild()
|
| 193 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
| 194 |
+
assert capture == ""
|
| 195 |
+
with capture:
|
| 196 |
+
del p
|
| 197 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 198 |
+
assert capture == "Releasing parent."
|
| 199 |
+
|
| 200 |
+
with capture:
|
| 201 |
+
p = m.Parent()
|
| 202 |
+
assert capture == "Allocating parent."
|
| 203 |
+
with capture:
|
| 204 |
+
p.returnNullChildKeepAliveParent()
|
| 205 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
| 206 |
+
assert capture == ""
|
| 207 |
+
with capture:
|
| 208 |
+
del p
|
| 209 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 210 |
+
assert capture == "Releasing parent."
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
def test_keep_alive_constructor(capture):
|
| 214 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
| 215 |
+
|
| 216 |
+
with capture:
|
| 217 |
+
p = m.Parent(m.Child())
|
| 218 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
| 219 |
+
assert (
|
| 220 |
+
capture
|
| 221 |
+
== """
|
| 222 |
+
Allocating child.
|
| 223 |
+
Allocating parent.
|
| 224 |
+
"""
|
| 225 |
+
)
|
| 226 |
+
with capture:
|
| 227 |
+
del p
|
| 228 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
| 229 |
+
assert (
|
| 230 |
+
capture
|
| 231 |
+
== """
|
| 232 |
+
Releasing parent.
|
| 233 |
+
Releasing child.
|
| 234 |
+
"""
|
| 235 |
+
)
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
def test_call_guard():
|
| 239 |
+
assert m.unguarded_call() == "unguarded"
|
| 240 |
+
assert m.guarded_call() == "guarded"
|
| 241 |
+
|
| 242 |
+
assert m.multiple_guards_correct_order() == "guarded & guarded"
|
| 243 |
+
assert m.multiple_guards_wrong_order() == "unguarded & guarded"
|
| 244 |
+
|
| 245 |
+
if hasattr(m, "with_gil"):
|
| 246 |
+
assert m.with_gil() == "GIL held"
|
| 247 |
+
assert m.without_gil() == "GIL released"
|
third_party/CityFlow/extern/pybind11/tests/test_callbacks.cpp
CHANGED
|
@@ -1,280 +1,280 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_callbacks.cpp -- callbacks
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#include <pybind11/functional.h>
|
| 11 |
-
|
| 12 |
-
#include "constructor_stats.h"
|
| 13 |
-
#include "pybind11_tests.h"
|
| 14 |
-
|
| 15 |
-
#include <thread>
|
| 16 |
-
|
| 17 |
-
int dummy_function(int i) { return i + 1; }
|
| 18 |
-
|
| 19 |
-
TEST_SUBMODULE(callbacks, m) {
|
| 20 |
-
// test_callbacks, test_function_signatures
|
| 21 |
-
m.def("test_callback1", [](const py::object &func) { return func(); });
|
| 22 |
-
m.def("test_callback2", [](const py::object &func) { return func("Hello", 'x', true, 5); });
|
| 23 |
-
m.def("test_callback3", [](const std::function<int(int)> &func) {
|
| 24 |
-
return "func(43) = " + std::to_string(func(43));
|
| 25 |
-
});
|
| 26 |
-
m.def("test_callback4",
|
| 27 |
-
[]() -> std::function<int(int)> { return [](int i) { return i + 1; }; });
|
| 28 |
-
m.def("test_callback5",
|
| 29 |
-
[]() { return py::cpp_function([](int i) { return i + 1; }, py::arg("number")); });
|
| 30 |
-
|
| 31 |
-
// test_keyword_args_and_generalized_unpacking
|
| 32 |
-
m.def("test_tuple_unpacking", [](const py::function &f) {
|
| 33 |
-
auto t1 = py::make_tuple(2, 3);
|
| 34 |
-
auto t2 = py::make_tuple(5, 6);
|
| 35 |
-
return f("positional", 1, *t1, 4, *t2);
|
| 36 |
-
});
|
| 37 |
-
|
| 38 |
-
m.def("test_dict_unpacking", [](const py::function &f) {
|
| 39 |
-
auto d1 = py::dict("key"_a = "value", "a"_a = 1);
|
| 40 |
-
auto d2 = py::dict();
|
| 41 |
-
auto d3 = py::dict("b"_a = 2);
|
| 42 |
-
return f("positional", 1, **d1, **d2, **d3);
|
| 43 |
-
});
|
| 44 |
-
|
| 45 |
-
m.def("test_keyword_args", [](const py::function &f) { return f("x"_a = 10, "y"_a = 20); });
|
| 46 |
-
|
| 47 |
-
m.def("test_unpacking_and_keywords1", [](const py::function &f) {
|
| 48 |
-
auto args = py::make_tuple(2);
|
| 49 |
-
auto kwargs = py::dict("d"_a = 4);
|
| 50 |
-
return f(1, *args, "c"_a = 3, **kwargs);
|
| 51 |
-
});
|
| 52 |
-
|
| 53 |
-
m.def("test_unpacking_and_keywords2", [](const py::function &f) {
|
| 54 |
-
auto kwargs1 = py::dict("a"_a = 1);
|
| 55 |
-
auto kwargs2 = py::dict("c"_a = 3, "d"_a = 4);
|
| 56 |
-
return f("positional",
|
| 57 |
-
*py::make_tuple(1),
|
| 58 |
-
2,
|
| 59 |
-
*py::make_tuple(3, 4),
|
| 60 |
-
5,
|
| 61 |
-
"key"_a = "value",
|
| 62 |
-
**kwargs1,
|
| 63 |
-
"b"_a = 2,
|
| 64 |
-
**kwargs2,
|
| 65 |
-
"e"_a = 5);
|
| 66 |
-
});
|
| 67 |
-
|
| 68 |
-
m.def("test_unpacking_error1", [](const py::function &f) {
|
| 69 |
-
auto kwargs = py::dict("x"_a = 3);
|
| 70 |
-
return f("x"_a = 1, "y"_a = 2, **kwargs); // duplicate ** after keyword
|
| 71 |
-
});
|
| 72 |
-
|
| 73 |
-
m.def("test_unpacking_error2", [](const py::function &f) {
|
| 74 |
-
auto kwargs = py::dict("x"_a = 3);
|
| 75 |
-
return f(**kwargs, "x"_a = 1); // duplicate keyword after **
|
| 76 |
-
});
|
| 77 |
-
|
| 78 |
-
m.def("test_arg_conversion_error1",
|
| 79 |
-
[](const py::function &f) { f(234, UnregisteredType(), "kw"_a = 567); });
|
| 80 |
-
|
| 81 |
-
m.def("test_arg_conversion_error2", [](const py::function &f) {
|
| 82 |
-
f(234, "expected_name"_a = UnregisteredType(), "kw"_a = 567);
|
| 83 |
-
});
|
| 84 |
-
|
| 85 |
-
// test_lambda_closure_cleanup
|
| 86 |
-
struct Payload {
|
| 87 |
-
Payload() { print_default_created(this); }
|
| 88 |
-
~Payload() { print_destroyed(this); }
|
| 89 |
-
Payload(const Payload &) { print_copy_created(this); }
|
| 90 |
-
Payload(Payload &&) noexcept { print_move_created(this); }
|
| 91 |
-
};
|
| 92 |
-
// Export the payload constructor statistics for testing purposes:
|
| 93 |
-
m.def("payload_cstats", &ConstructorStats::get<Payload>);
|
| 94 |
-
m.def("test_lambda_closure_cleanup", []() -> std::function<void()> {
|
| 95 |
-
Payload p;
|
| 96 |
-
|
| 97 |
-
// In this situation, `Func` in the implementation of
|
| 98 |
-
// `cpp_function::initialize` is NOT trivially destructible.
|
| 99 |
-
return [p]() {
|
| 100 |
-
/* p should be cleaned up when the returned function is garbage collected */
|
| 101 |
-
(void) p;
|
| 102 |
-
};
|
| 103 |
-
});
|
| 104 |
-
|
| 105 |
-
class CppCallable {
|
| 106 |
-
public:
|
| 107 |
-
CppCallable() { track_default_created(this); }
|
| 108 |
-
~CppCallable() { track_destroyed(this); }
|
| 109 |
-
CppCallable(const CppCallable &) { track_copy_created(this); }
|
| 110 |
-
CppCallable(CppCallable &&) noexcept { track_move_created(this); }
|
| 111 |
-
void operator()() {}
|
| 112 |
-
};
|
| 113 |
-
|
| 114 |
-
m.def("test_cpp_callable_cleanup", []() {
|
| 115 |
-
// Related issue: https://github.com/pybind/pybind11/issues/3228
|
| 116 |
-
// Related PR: https://github.com/pybind/pybind11/pull/3229
|
| 117 |
-
py::list alive_counts;
|
| 118 |
-
ConstructorStats &stat = ConstructorStats::get<CppCallable>();
|
| 119 |
-
alive_counts.append(stat.alive());
|
| 120 |
-
{
|
| 121 |
-
CppCallable cpp_callable;
|
| 122 |
-
alive_counts.append(stat.alive());
|
| 123 |
-
{
|
| 124 |
-
// In this situation, `Func` in the implementation of
|
| 125 |
-
// `cpp_function::initialize` IS trivially destructible,
|
| 126 |
-
// only `capture` is not.
|
| 127 |
-
py::cpp_function py_func(cpp_callable);
|
| 128 |
-
py::detail::silence_unused_warnings(py_func);
|
| 129 |
-
alive_counts.append(stat.alive());
|
| 130 |
-
}
|
| 131 |
-
alive_counts.append(stat.alive());
|
| 132 |
-
{
|
| 133 |
-
py::cpp_function py_func(std::move(cpp_callable));
|
| 134 |
-
py::detail::silence_unused_warnings(py_func);
|
| 135 |
-
alive_counts.append(stat.alive());
|
| 136 |
-
}
|
| 137 |
-
alive_counts.append(stat.alive());
|
| 138 |
-
}
|
| 139 |
-
alive_counts.append(stat.alive());
|
| 140 |
-
return alive_counts;
|
| 141 |
-
});
|
| 142 |
-
|
| 143 |
-
// test_cpp_function_roundtrip
|
| 144 |
-
/* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
|
| 145 |
-
m.def("dummy_function", &dummy_function);
|
| 146 |
-
m.def("dummy_function_overloaded", [](int i, int j) { return i + j; });
|
| 147 |
-
m.def("dummy_function_overloaded", &dummy_function);
|
| 148 |
-
m.def("dummy_function2", [](int i, int j) { return i + j; });
|
| 149 |
-
m.def(
|
| 150 |
-
"roundtrip",
|
| 151 |
-
[](std::function<int(int)> f, bool expect_none = false) {
|
| 152 |
-
if (expect_none && f) {
|
| 153 |
-
throw std::runtime_error("Expected None to be converted to empty std::function");
|
| 154 |
-
}
|
| 155 |
-
return f;
|
| 156 |
-
},
|
| 157 |
-
py::arg("f"),
|
| 158 |
-
py::arg("expect_none") = false);
|
| 159 |
-
m.def("test_dummy_function", [](const std::function<int(int)> &f) -> std::string {
|
| 160 |
-
using fn_type = int (*)(int);
|
| 161 |
-
const auto *result = f.target<fn_type>();
|
| 162 |
-
if (!result) {
|
| 163 |
-
auto r = f(1);
|
| 164 |
-
return "can't convert to function pointer: eval(1) = " + std::to_string(r);
|
| 165 |
-
}
|
| 166 |
-
if (*result == dummy_function) {
|
| 167 |
-
auto r = (*result)(1);
|
| 168 |
-
return "matches dummy_function: eval(1) = " + std::to_string(r);
|
| 169 |
-
}
|
| 170 |
-
return "argument does NOT match dummy_function. This should never happen!";
|
| 171 |
-
});
|
| 172 |
-
|
| 173 |
-
class AbstractBase {
|
| 174 |
-
public:
|
| 175 |
-
// [workaround(intel)] = default does not work here
|
| 176 |
-
// Defaulting this destructor results in linking errors with the Intel compiler
|
| 177 |
-
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
|
| 178 |
-
virtual ~AbstractBase() {} // NOLINT(modernize-use-equals-default)
|
| 179 |
-
virtual unsigned int func() = 0;
|
| 180 |
-
};
|
| 181 |
-
m.def("func_accepting_func_accepting_base",
|
| 182 |
-
[](const std::function<double(AbstractBase &)> &) {});
|
| 183 |
-
|
| 184 |
-
struct MovableObject {
|
| 185 |
-
bool valid = true;
|
| 186 |
-
|
| 187 |
-
MovableObject() = default;
|
| 188 |
-
MovableObject(const MovableObject &) = default;
|
| 189 |
-
MovableObject &operator=(const MovableObject &) = default;
|
| 190 |
-
MovableObject(MovableObject &&o) noexcept : valid(o.valid) { o.valid = false; }
|
| 191 |
-
MovableObject &operator=(MovableObject &&o) noexcept {
|
| 192 |
-
valid = o.valid;
|
| 193 |
-
o.valid = false;
|
| 194 |
-
return *this;
|
| 195 |
-
}
|
| 196 |
-
};
|
| 197 |
-
py::class_<MovableObject>(m, "MovableObject");
|
| 198 |
-
|
| 199 |
-
// test_movable_object
|
| 200 |
-
m.def("callback_with_movable", [](const std::function<void(MovableObject &)> &f) {
|
| 201 |
-
auto x = MovableObject();
|
| 202 |
-
f(x); // lvalue reference shouldn't move out object
|
| 203 |
-
return x.valid; // must still return `true`
|
| 204 |
-
});
|
| 205 |
-
|
| 206 |
-
// test_bound_method_callback
|
| 207 |
-
struct CppBoundMethodTest {};
|
| 208 |
-
py::class_<CppBoundMethodTest>(m, "CppBoundMethodTest")
|
| 209 |
-
.def(py::init<>())
|
| 210 |
-
.def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; });
|
| 211 |
-
|
| 212 |
-
// This checks that builtin functions can be passed as callbacks
|
| 213 |
-
// rather than throwing RuntimeError due to trying to extract as capsule
|
| 214 |
-
m.def("test_sum_builtin",
|
| 215 |
-
[](const std::function<double(py::iterable)> &sum_builtin, const py::iterable &i) {
|
| 216 |
-
return sum_builtin(i);
|
| 217 |
-
});
|
| 218 |
-
|
| 219 |
-
// test async Python callbacks
|
| 220 |
-
using callback_f = std::function<void(int)>;
|
| 221 |
-
m.def("test_async_callback", [](const callback_f &f, const py::list &work) {
|
| 222 |
-
// make detached thread that calls `f` with piece of work after a little delay
|
| 223 |
-
auto start_f = [f](int j) {
|
| 224 |
-
auto invoke_f = [f, j] {
|
| 225 |
-
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
| 226 |
-
f(j);
|
| 227 |
-
};
|
| 228 |
-
auto t = std::thread(std::move(invoke_f));
|
| 229 |
-
t.detach();
|
| 230 |
-
};
|
| 231 |
-
|
| 232 |
-
// spawn worker threads
|
| 233 |
-
for (auto i : work) {
|
| 234 |
-
start_f(py::cast<int>(i));
|
| 235 |
-
}
|
| 236 |
-
});
|
| 237 |
-
|
| 238 |
-
m.def("callback_num_times", [](const py::function &f, std::size_t num) {
|
| 239 |
-
for (std::size_t i = 0; i < num; i++) {
|
| 240 |
-
f();
|
| 241 |
-
}
|
| 242 |
-
});
|
| 243 |
-
|
| 244 |
-
auto *custom_def = []() {
|
| 245 |
-
static PyMethodDef def;
|
| 246 |
-
def.ml_name = "example_name";
|
| 247 |
-
def.ml_doc = "Example doc";
|
| 248 |
-
def.ml_meth = [](PyObject *, PyObject *args) -> PyObject * {
|
| 249 |
-
if (PyTuple_Size(args) != 1) {
|
| 250 |
-
throw std::runtime_error("Invalid number of arguments for example_name");
|
| 251 |
-
}
|
| 252 |
-
PyObject *first = PyTuple_GetItem(args, 0);
|
| 253 |
-
if (!PyLong_Check(first)) {
|
| 254 |
-
throw std::runtime_error("Invalid argument to example_name");
|
| 255 |
-
}
|
| 256 |
-
auto result = py::cast(PyLong_AsLong(first) * 9);
|
| 257 |
-
return result.release().ptr();
|
| 258 |
-
};
|
| 259 |
-
def.ml_flags = METH_VARARGS;
|
| 260 |
-
return &def;
|
| 261 |
-
}();
|
| 262 |
-
|
| 263 |
-
// rec_capsule with name that has the same value (but not pointer) as our internal one
|
| 264 |
-
// This capsule should be detected by our code as foreign and not inspected as the pointers
|
| 265 |
-
// shouldn't match
|
| 266 |
-
constexpr const char *rec_capsule_name
|
| 267 |
-
= pybind11::detail::internals_function_record_capsule_name;
|
| 268 |
-
py::capsule rec_capsule(std::malloc(1), [](void *data) { std::free(data); });
|
| 269 |
-
rec_capsule.set_name(rec_capsule_name);
|
| 270 |
-
m.add_object("custom_function", PyCFunction_New(custom_def, rec_capsule.ptr()));
|
| 271 |
-
|
| 272 |
-
// This test requires a new ABI version to pass
|
| 273 |
-
#if PYBIND11_INTERNALS_VERSION > 4
|
| 274 |
-
// rec_capsule with nullptr name
|
| 275 |
-
py::capsule rec_capsule2(std::malloc(1), [](void *data) { std::free(data); });
|
| 276 |
-
m.add_object("custom_function2", PyCFunction_New(custom_def, rec_capsule2.ptr()));
|
| 277 |
-
#else
|
| 278 |
-
m.add_object("custom_function2", py::none());
|
| 279 |
-
#endif
|
| 280 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_callbacks.cpp -- callbacks
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#include <pybind11/functional.h>
|
| 11 |
+
|
| 12 |
+
#include "constructor_stats.h"
|
| 13 |
+
#include "pybind11_tests.h"
|
| 14 |
+
|
| 15 |
+
#include <thread>
|
| 16 |
+
|
| 17 |
+
int dummy_function(int i) { return i + 1; }
|
| 18 |
+
|
| 19 |
+
TEST_SUBMODULE(callbacks, m) {
|
| 20 |
+
// test_callbacks, test_function_signatures
|
| 21 |
+
m.def("test_callback1", [](const py::object &func) { return func(); });
|
| 22 |
+
m.def("test_callback2", [](const py::object &func) { return func("Hello", 'x', true, 5); });
|
| 23 |
+
m.def("test_callback3", [](const std::function<int(int)> &func) {
|
| 24 |
+
return "func(43) = " + std::to_string(func(43));
|
| 25 |
+
});
|
| 26 |
+
m.def("test_callback4",
|
| 27 |
+
[]() -> std::function<int(int)> { return [](int i) { return i + 1; }; });
|
| 28 |
+
m.def("test_callback5",
|
| 29 |
+
[]() { return py::cpp_function([](int i) { return i + 1; }, py::arg("number")); });
|
| 30 |
+
|
| 31 |
+
// test_keyword_args_and_generalized_unpacking
|
| 32 |
+
m.def("test_tuple_unpacking", [](const py::function &f) {
|
| 33 |
+
auto t1 = py::make_tuple(2, 3);
|
| 34 |
+
auto t2 = py::make_tuple(5, 6);
|
| 35 |
+
return f("positional", 1, *t1, 4, *t2);
|
| 36 |
+
});
|
| 37 |
+
|
| 38 |
+
m.def("test_dict_unpacking", [](const py::function &f) {
|
| 39 |
+
auto d1 = py::dict("key"_a = "value", "a"_a = 1);
|
| 40 |
+
auto d2 = py::dict();
|
| 41 |
+
auto d3 = py::dict("b"_a = 2);
|
| 42 |
+
return f("positional", 1, **d1, **d2, **d3);
|
| 43 |
+
});
|
| 44 |
+
|
| 45 |
+
m.def("test_keyword_args", [](const py::function &f) { return f("x"_a = 10, "y"_a = 20); });
|
| 46 |
+
|
| 47 |
+
m.def("test_unpacking_and_keywords1", [](const py::function &f) {
|
| 48 |
+
auto args = py::make_tuple(2);
|
| 49 |
+
auto kwargs = py::dict("d"_a = 4);
|
| 50 |
+
return f(1, *args, "c"_a = 3, **kwargs);
|
| 51 |
+
});
|
| 52 |
+
|
| 53 |
+
m.def("test_unpacking_and_keywords2", [](const py::function &f) {
|
| 54 |
+
auto kwargs1 = py::dict("a"_a = 1);
|
| 55 |
+
auto kwargs2 = py::dict("c"_a = 3, "d"_a = 4);
|
| 56 |
+
return f("positional",
|
| 57 |
+
*py::make_tuple(1),
|
| 58 |
+
2,
|
| 59 |
+
*py::make_tuple(3, 4),
|
| 60 |
+
5,
|
| 61 |
+
"key"_a = "value",
|
| 62 |
+
**kwargs1,
|
| 63 |
+
"b"_a = 2,
|
| 64 |
+
**kwargs2,
|
| 65 |
+
"e"_a = 5);
|
| 66 |
+
});
|
| 67 |
+
|
| 68 |
+
m.def("test_unpacking_error1", [](const py::function &f) {
|
| 69 |
+
auto kwargs = py::dict("x"_a = 3);
|
| 70 |
+
return f("x"_a = 1, "y"_a = 2, **kwargs); // duplicate ** after keyword
|
| 71 |
+
});
|
| 72 |
+
|
| 73 |
+
m.def("test_unpacking_error2", [](const py::function &f) {
|
| 74 |
+
auto kwargs = py::dict("x"_a = 3);
|
| 75 |
+
return f(**kwargs, "x"_a = 1); // duplicate keyword after **
|
| 76 |
+
});
|
| 77 |
+
|
| 78 |
+
m.def("test_arg_conversion_error1",
|
| 79 |
+
[](const py::function &f) { f(234, UnregisteredType(), "kw"_a = 567); });
|
| 80 |
+
|
| 81 |
+
m.def("test_arg_conversion_error2", [](const py::function &f) {
|
| 82 |
+
f(234, "expected_name"_a = UnregisteredType(), "kw"_a = 567);
|
| 83 |
+
});
|
| 84 |
+
|
| 85 |
+
// test_lambda_closure_cleanup
|
| 86 |
+
struct Payload {
|
| 87 |
+
Payload() { print_default_created(this); }
|
| 88 |
+
~Payload() { print_destroyed(this); }
|
| 89 |
+
Payload(const Payload &) { print_copy_created(this); }
|
| 90 |
+
Payload(Payload &&) noexcept { print_move_created(this); }
|
| 91 |
+
};
|
| 92 |
+
// Export the payload constructor statistics for testing purposes:
|
| 93 |
+
m.def("payload_cstats", &ConstructorStats::get<Payload>);
|
| 94 |
+
m.def("test_lambda_closure_cleanup", []() -> std::function<void()> {
|
| 95 |
+
Payload p;
|
| 96 |
+
|
| 97 |
+
// In this situation, `Func` in the implementation of
|
| 98 |
+
// `cpp_function::initialize` is NOT trivially destructible.
|
| 99 |
+
return [p]() {
|
| 100 |
+
/* p should be cleaned up when the returned function is garbage collected */
|
| 101 |
+
(void) p;
|
| 102 |
+
};
|
| 103 |
+
});
|
| 104 |
+
|
| 105 |
+
class CppCallable {
|
| 106 |
+
public:
|
| 107 |
+
CppCallable() { track_default_created(this); }
|
| 108 |
+
~CppCallable() { track_destroyed(this); }
|
| 109 |
+
CppCallable(const CppCallable &) { track_copy_created(this); }
|
| 110 |
+
CppCallable(CppCallable &&) noexcept { track_move_created(this); }
|
| 111 |
+
void operator()() {}
|
| 112 |
+
};
|
| 113 |
+
|
| 114 |
+
m.def("test_cpp_callable_cleanup", []() {
|
| 115 |
+
// Related issue: https://github.com/pybind/pybind11/issues/3228
|
| 116 |
+
// Related PR: https://github.com/pybind/pybind11/pull/3229
|
| 117 |
+
py::list alive_counts;
|
| 118 |
+
ConstructorStats &stat = ConstructorStats::get<CppCallable>();
|
| 119 |
+
alive_counts.append(stat.alive());
|
| 120 |
+
{
|
| 121 |
+
CppCallable cpp_callable;
|
| 122 |
+
alive_counts.append(stat.alive());
|
| 123 |
+
{
|
| 124 |
+
// In this situation, `Func` in the implementation of
|
| 125 |
+
// `cpp_function::initialize` IS trivially destructible,
|
| 126 |
+
// only `capture` is not.
|
| 127 |
+
py::cpp_function py_func(cpp_callable);
|
| 128 |
+
py::detail::silence_unused_warnings(py_func);
|
| 129 |
+
alive_counts.append(stat.alive());
|
| 130 |
+
}
|
| 131 |
+
alive_counts.append(stat.alive());
|
| 132 |
+
{
|
| 133 |
+
py::cpp_function py_func(std::move(cpp_callable));
|
| 134 |
+
py::detail::silence_unused_warnings(py_func);
|
| 135 |
+
alive_counts.append(stat.alive());
|
| 136 |
+
}
|
| 137 |
+
alive_counts.append(stat.alive());
|
| 138 |
+
}
|
| 139 |
+
alive_counts.append(stat.alive());
|
| 140 |
+
return alive_counts;
|
| 141 |
+
});
|
| 142 |
+
|
| 143 |
+
// test_cpp_function_roundtrip
|
| 144 |
+
/* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
|
| 145 |
+
m.def("dummy_function", &dummy_function);
|
| 146 |
+
m.def("dummy_function_overloaded", [](int i, int j) { return i + j; });
|
| 147 |
+
m.def("dummy_function_overloaded", &dummy_function);
|
| 148 |
+
m.def("dummy_function2", [](int i, int j) { return i + j; });
|
| 149 |
+
m.def(
|
| 150 |
+
"roundtrip",
|
| 151 |
+
[](std::function<int(int)> f, bool expect_none = false) {
|
| 152 |
+
if (expect_none && f) {
|
| 153 |
+
throw std::runtime_error("Expected None to be converted to empty std::function");
|
| 154 |
+
}
|
| 155 |
+
return f;
|
| 156 |
+
},
|
| 157 |
+
py::arg("f"),
|
| 158 |
+
py::arg("expect_none") = false);
|
| 159 |
+
m.def("test_dummy_function", [](const std::function<int(int)> &f) -> std::string {
|
| 160 |
+
using fn_type = int (*)(int);
|
| 161 |
+
const auto *result = f.target<fn_type>();
|
| 162 |
+
if (!result) {
|
| 163 |
+
auto r = f(1);
|
| 164 |
+
return "can't convert to function pointer: eval(1) = " + std::to_string(r);
|
| 165 |
+
}
|
| 166 |
+
if (*result == dummy_function) {
|
| 167 |
+
auto r = (*result)(1);
|
| 168 |
+
return "matches dummy_function: eval(1) = " + std::to_string(r);
|
| 169 |
+
}
|
| 170 |
+
return "argument does NOT match dummy_function. This should never happen!";
|
| 171 |
+
});
|
| 172 |
+
|
| 173 |
+
class AbstractBase {
|
| 174 |
+
public:
|
| 175 |
+
// [workaround(intel)] = default does not work here
|
| 176 |
+
// Defaulting this destructor results in linking errors with the Intel compiler
|
| 177 |
+
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
|
| 178 |
+
virtual ~AbstractBase() {} // NOLINT(modernize-use-equals-default)
|
| 179 |
+
virtual unsigned int func() = 0;
|
| 180 |
+
};
|
| 181 |
+
m.def("func_accepting_func_accepting_base",
|
| 182 |
+
[](const std::function<double(AbstractBase &)> &) {});
|
| 183 |
+
|
| 184 |
+
struct MovableObject {
|
| 185 |
+
bool valid = true;
|
| 186 |
+
|
| 187 |
+
MovableObject() = default;
|
| 188 |
+
MovableObject(const MovableObject &) = default;
|
| 189 |
+
MovableObject &operator=(const MovableObject &) = default;
|
| 190 |
+
MovableObject(MovableObject &&o) noexcept : valid(o.valid) { o.valid = false; }
|
| 191 |
+
MovableObject &operator=(MovableObject &&o) noexcept {
|
| 192 |
+
valid = o.valid;
|
| 193 |
+
o.valid = false;
|
| 194 |
+
return *this;
|
| 195 |
+
}
|
| 196 |
+
};
|
| 197 |
+
py::class_<MovableObject>(m, "MovableObject");
|
| 198 |
+
|
| 199 |
+
// test_movable_object
|
| 200 |
+
m.def("callback_with_movable", [](const std::function<void(MovableObject &)> &f) {
|
| 201 |
+
auto x = MovableObject();
|
| 202 |
+
f(x); // lvalue reference shouldn't move out object
|
| 203 |
+
return x.valid; // must still return `true`
|
| 204 |
+
});
|
| 205 |
+
|
| 206 |
+
// test_bound_method_callback
|
| 207 |
+
struct CppBoundMethodTest {};
|
| 208 |
+
py::class_<CppBoundMethodTest>(m, "CppBoundMethodTest")
|
| 209 |
+
.def(py::init<>())
|
| 210 |
+
.def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; });
|
| 211 |
+
|
| 212 |
+
// This checks that builtin functions can be passed as callbacks
|
| 213 |
+
// rather than throwing RuntimeError due to trying to extract as capsule
|
| 214 |
+
m.def("test_sum_builtin",
|
| 215 |
+
[](const std::function<double(py::iterable)> &sum_builtin, const py::iterable &i) {
|
| 216 |
+
return sum_builtin(i);
|
| 217 |
+
});
|
| 218 |
+
|
| 219 |
+
// test async Python callbacks
|
| 220 |
+
using callback_f = std::function<void(int)>;
|
| 221 |
+
m.def("test_async_callback", [](const callback_f &f, const py::list &work) {
|
| 222 |
+
// make detached thread that calls `f` with piece of work after a little delay
|
| 223 |
+
auto start_f = [f](int j) {
|
| 224 |
+
auto invoke_f = [f, j] {
|
| 225 |
+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
| 226 |
+
f(j);
|
| 227 |
+
};
|
| 228 |
+
auto t = std::thread(std::move(invoke_f));
|
| 229 |
+
t.detach();
|
| 230 |
+
};
|
| 231 |
+
|
| 232 |
+
// spawn worker threads
|
| 233 |
+
for (auto i : work) {
|
| 234 |
+
start_f(py::cast<int>(i));
|
| 235 |
+
}
|
| 236 |
+
});
|
| 237 |
+
|
| 238 |
+
m.def("callback_num_times", [](const py::function &f, std::size_t num) {
|
| 239 |
+
for (std::size_t i = 0; i < num; i++) {
|
| 240 |
+
f();
|
| 241 |
+
}
|
| 242 |
+
});
|
| 243 |
+
|
| 244 |
+
auto *custom_def = []() {
|
| 245 |
+
static PyMethodDef def;
|
| 246 |
+
def.ml_name = "example_name";
|
| 247 |
+
def.ml_doc = "Example doc";
|
| 248 |
+
def.ml_meth = [](PyObject *, PyObject *args) -> PyObject * {
|
| 249 |
+
if (PyTuple_Size(args) != 1) {
|
| 250 |
+
throw std::runtime_error("Invalid number of arguments for example_name");
|
| 251 |
+
}
|
| 252 |
+
PyObject *first = PyTuple_GetItem(args, 0);
|
| 253 |
+
if (!PyLong_Check(first)) {
|
| 254 |
+
throw std::runtime_error("Invalid argument to example_name");
|
| 255 |
+
}
|
| 256 |
+
auto result = py::cast(PyLong_AsLong(first) * 9);
|
| 257 |
+
return result.release().ptr();
|
| 258 |
+
};
|
| 259 |
+
def.ml_flags = METH_VARARGS;
|
| 260 |
+
return &def;
|
| 261 |
+
}();
|
| 262 |
+
|
| 263 |
+
// rec_capsule with name that has the same value (but not pointer) as our internal one
|
| 264 |
+
// This capsule should be detected by our code as foreign and not inspected as the pointers
|
| 265 |
+
// shouldn't match
|
| 266 |
+
constexpr const char *rec_capsule_name
|
| 267 |
+
= pybind11::detail::internals_function_record_capsule_name;
|
| 268 |
+
py::capsule rec_capsule(std::malloc(1), [](void *data) { std::free(data); });
|
| 269 |
+
rec_capsule.set_name(rec_capsule_name);
|
| 270 |
+
m.add_object("custom_function", PyCFunction_New(custom_def, rec_capsule.ptr()));
|
| 271 |
+
|
| 272 |
+
// This test requires a new ABI version to pass
|
| 273 |
+
#if PYBIND11_INTERNALS_VERSION > 4
|
| 274 |
+
// rec_capsule with nullptr name
|
| 275 |
+
py::capsule rec_capsule2(std::malloc(1), [](void *data) { std::free(data); });
|
| 276 |
+
m.add_object("custom_function2", PyCFunction_New(custom_def, rec_capsule2.ptr()));
|
| 277 |
+
#else
|
| 278 |
+
m.add_object("custom_function2", py::none());
|
| 279 |
+
#endif
|
| 280 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_callbacks.py
CHANGED
|
@@ -1,225 +1,225 @@
|
|
| 1 |
-
import time
|
| 2 |
-
from threading import Thread
|
| 3 |
-
|
| 4 |
-
import pytest
|
| 5 |
-
|
| 6 |
-
import env # noqa: F401
|
| 7 |
-
from pybind11_tests import callbacks as m
|
| 8 |
-
from pybind11_tests import detailed_error_messages_enabled
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
def test_callbacks():
|
| 12 |
-
from functools import partial
|
| 13 |
-
|
| 14 |
-
def func1():
|
| 15 |
-
return "func1"
|
| 16 |
-
|
| 17 |
-
def func2(a, b, c, d):
|
| 18 |
-
return "func2", a, b, c, d
|
| 19 |
-
|
| 20 |
-
def func3(a):
|
| 21 |
-
return f"func3({a})"
|
| 22 |
-
|
| 23 |
-
assert m.test_callback1(func1) == "func1"
|
| 24 |
-
assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5)
|
| 25 |
-
assert m.test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4)
|
| 26 |
-
assert m.test_callback1(partial(func3, "partial")) == "func3(partial)"
|
| 27 |
-
assert m.test_callback3(lambda i: i + 1) == "func(43) = 44"
|
| 28 |
-
|
| 29 |
-
f = m.test_callback4()
|
| 30 |
-
assert f(43) == 44
|
| 31 |
-
f = m.test_callback5()
|
| 32 |
-
assert f(number=43) == 44
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
def test_bound_method_callback():
|
| 36 |
-
# Bound Python method:
|
| 37 |
-
class MyClass:
|
| 38 |
-
def double(self, val):
|
| 39 |
-
return 2 * val
|
| 40 |
-
|
| 41 |
-
z = MyClass()
|
| 42 |
-
assert m.test_callback3(z.double) == "func(43) = 86"
|
| 43 |
-
|
| 44 |
-
z = m.CppBoundMethodTest()
|
| 45 |
-
assert m.test_callback3(z.triple) == "func(43) = 129"
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
def test_keyword_args_and_generalized_unpacking():
|
| 49 |
-
def f(*args, **kwargs):
|
| 50 |
-
return args, kwargs
|
| 51 |
-
|
| 52 |
-
assert m.test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {})
|
| 53 |
-
assert m.test_dict_unpacking(f) == (
|
| 54 |
-
("positional", 1),
|
| 55 |
-
{"key": "value", "a": 1, "b": 2},
|
| 56 |
-
)
|
| 57 |
-
assert m.test_keyword_args(f) == ((), {"x": 10, "y": 20})
|
| 58 |
-
assert m.test_unpacking_and_keywords1(f) == ((1, 2), {"c": 3, "d": 4})
|
| 59 |
-
assert m.test_unpacking_and_keywords2(f) == (
|
| 60 |
-
("positional", 1, 2, 3, 4, 5),
|
| 61 |
-
{"key": "value", "a": 1, "b": 2, "c": 3, "d": 4, "e": 5},
|
| 62 |
-
)
|
| 63 |
-
|
| 64 |
-
with pytest.raises(TypeError) as excinfo:
|
| 65 |
-
m.test_unpacking_error1(f)
|
| 66 |
-
assert "Got multiple values for keyword argument" in str(excinfo.value)
|
| 67 |
-
|
| 68 |
-
with pytest.raises(TypeError) as excinfo:
|
| 69 |
-
m.test_unpacking_error2(f)
|
| 70 |
-
assert "Got multiple values for keyword argument" in str(excinfo.value)
|
| 71 |
-
|
| 72 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 73 |
-
m.test_arg_conversion_error1(f)
|
| 74 |
-
assert str(excinfo.value) == "Unable to convert call argument " + (
|
| 75 |
-
"'1' of type 'UnregisteredType' to Python object"
|
| 76 |
-
if detailed_error_messages_enabled
|
| 77 |
-
else "'1' to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"
|
| 78 |
-
)
|
| 79 |
-
|
| 80 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 81 |
-
m.test_arg_conversion_error2(f)
|
| 82 |
-
assert str(excinfo.value) == "Unable to convert call argument " + (
|
| 83 |
-
"'expected_name' of type 'UnregisteredType' to Python object"
|
| 84 |
-
if detailed_error_messages_enabled
|
| 85 |
-
else "'expected_name' to Python object "
|
| 86 |
-
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"
|
| 87 |
-
)
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
def test_lambda_closure_cleanup():
|
| 91 |
-
m.test_lambda_closure_cleanup()
|
| 92 |
-
cstats = m.payload_cstats()
|
| 93 |
-
assert cstats.alive() == 0
|
| 94 |
-
assert cstats.copy_constructions == 1
|
| 95 |
-
assert cstats.move_constructions >= 1
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
def test_cpp_callable_cleanup():
|
| 99 |
-
alive_counts = m.test_cpp_callable_cleanup()
|
| 100 |
-
assert alive_counts == [0, 1, 2, 1, 2, 1, 0]
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
def test_cpp_function_roundtrip():
|
| 104 |
-
"""Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
|
| 105 |
-
|
| 106 |
-
assert (
|
| 107 |
-
m.test_dummy_function(m.dummy_function) == "matches dummy_function: eval(1) = 2"
|
| 108 |
-
)
|
| 109 |
-
assert (
|
| 110 |
-
m.test_dummy_function(m.roundtrip(m.dummy_function))
|
| 111 |
-
== "matches dummy_function: eval(1) = 2"
|
| 112 |
-
)
|
| 113 |
-
assert (
|
| 114 |
-
m.test_dummy_function(m.dummy_function_overloaded)
|
| 115 |
-
== "matches dummy_function: eval(1) = 2"
|
| 116 |
-
)
|
| 117 |
-
assert m.roundtrip(None, expect_none=True) is None
|
| 118 |
-
assert (
|
| 119 |
-
m.test_dummy_function(lambda x: x + 2)
|
| 120 |
-
== "can't convert to function pointer: eval(1) = 3"
|
| 121 |
-
)
|
| 122 |
-
|
| 123 |
-
with pytest.raises(TypeError) as excinfo:
|
| 124 |
-
m.test_dummy_function(m.dummy_function2)
|
| 125 |
-
assert "incompatible function arguments" in str(excinfo.value)
|
| 126 |
-
|
| 127 |
-
with pytest.raises(TypeError) as excinfo:
|
| 128 |
-
m.test_dummy_function(lambda x, y: x + y)
|
| 129 |
-
assert any(
|
| 130 |
-
s in str(excinfo.value)
|
| 131 |
-
for s in ("missing 1 required positional argument", "takes exactly 2 arguments")
|
| 132 |
-
)
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
def test_function_signatures(doc):
|
| 136 |
-
assert doc(m.test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str"
|
| 137 |
-
assert doc(m.test_callback4) == "test_callback4() -> Callable[[int], int]"
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
def test_movable_object():
|
| 141 |
-
assert m.callback_with_movable(lambda _: None) is True
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
@pytest.mark.skipif(
|
| 145 |
-
"env.PYPY",
|
| 146 |
-
reason="PyPy segfaults on here. See discussion on #1413.",
|
| 147 |
-
)
|
| 148 |
-
def test_python_builtins():
|
| 149 |
-
"""Test if python builtins like sum() can be used as callbacks"""
|
| 150 |
-
assert m.test_sum_builtin(sum, [1, 2, 3]) == 6
|
| 151 |
-
assert m.test_sum_builtin(sum, []) == 0
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
def test_async_callbacks():
|
| 155 |
-
# serves as state for async callback
|
| 156 |
-
class Item:
|
| 157 |
-
def __init__(self, value):
|
| 158 |
-
self.value = value
|
| 159 |
-
|
| 160 |
-
res = []
|
| 161 |
-
|
| 162 |
-
# generate stateful lambda that will store result in `res`
|
| 163 |
-
def gen_f():
|
| 164 |
-
s = Item(3)
|
| 165 |
-
return lambda j: res.append(s.value + j)
|
| 166 |
-
|
| 167 |
-
# do some work async
|
| 168 |
-
work = [1, 2, 3, 4]
|
| 169 |
-
m.test_async_callback(gen_f(), work)
|
| 170 |
-
# wait until work is done
|
| 171 |
-
from time import sleep
|
| 172 |
-
|
| 173 |
-
sleep(0.5)
|
| 174 |
-
assert sum(res) == sum(x + 3 for x in work)
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
def test_async_async_callbacks():
|
| 178 |
-
t = Thread(target=test_async_callbacks)
|
| 179 |
-
t.start()
|
| 180 |
-
t.join()
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
def test_callback_num_times():
|
| 184 |
-
# Super-simple micro-benchmarking related to PR #2919.
|
| 185 |
-
# Example runtimes (Intel Xeon 2.2GHz, fully optimized):
|
| 186 |
-
# num_millions 1, repeats 2: 0.1 secs
|
| 187 |
-
# num_millions 20, repeats 10: 11.5 secs
|
| 188 |
-
one_million = 1000000
|
| 189 |
-
num_millions = 1 # Try 20 for actual micro-benchmarking.
|
| 190 |
-
repeats = 2 # Try 10.
|
| 191 |
-
rates = []
|
| 192 |
-
for rep in range(repeats):
|
| 193 |
-
t0 = time.time()
|
| 194 |
-
m.callback_num_times(lambda: None, num_millions * one_million)
|
| 195 |
-
td = time.time() - t0
|
| 196 |
-
rate = num_millions / td if td else 0
|
| 197 |
-
rates.append(rate)
|
| 198 |
-
if not rep:
|
| 199 |
-
print()
|
| 200 |
-
print(
|
| 201 |
-
f"callback_num_times: {num_millions:d} million / {td:.3f} seconds = {rate:.3f} million / second"
|
| 202 |
-
)
|
| 203 |
-
if len(rates) > 1:
|
| 204 |
-
print("Min Mean Max")
|
| 205 |
-
print(f"{min(rates):6.3f} {sum(rates) / len(rates):6.3f} {max(rates):6.3f}")
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
def test_custom_func():
|
| 209 |
-
assert m.custom_function(4) == 36
|
| 210 |
-
assert m.roundtrip(m.custom_function)(4) == 36
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
@pytest.mark.skipif(
|
| 214 |
-
m.custom_function2 is None, reason="Current PYBIND11_INTERNALS_VERSION too low"
|
| 215 |
-
)
|
| 216 |
-
def test_custom_func2():
|
| 217 |
-
assert m.custom_function2(3) == 27
|
| 218 |
-
assert m.roundtrip(m.custom_function2)(3) == 27
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
def test_callback_docstring():
|
| 222 |
-
assert (
|
| 223 |
-
m.test_tuple_unpacking.__doc__.strip()
|
| 224 |
-
== "test_tuple_unpacking(arg0: Callable) -> object"
|
| 225 |
-
)
|
|
|
|
| 1 |
+
import time
|
| 2 |
+
from threading import Thread
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
import env # noqa: F401
|
| 7 |
+
from pybind11_tests import callbacks as m
|
| 8 |
+
from pybind11_tests import detailed_error_messages_enabled
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def test_callbacks():
|
| 12 |
+
from functools import partial
|
| 13 |
+
|
| 14 |
+
def func1():
|
| 15 |
+
return "func1"
|
| 16 |
+
|
| 17 |
+
def func2(a, b, c, d):
|
| 18 |
+
return "func2", a, b, c, d
|
| 19 |
+
|
| 20 |
+
def func3(a):
|
| 21 |
+
return f"func3({a})"
|
| 22 |
+
|
| 23 |
+
assert m.test_callback1(func1) == "func1"
|
| 24 |
+
assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5)
|
| 25 |
+
assert m.test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4)
|
| 26 |
+
assert m.test_callback1(partial(func3, "partial")) == "func3(partial)"
|
| 27 |
+
assert m.test_callback3(lambda i: i + 1) == "func(43) = 44"
|
| 28 |
+
|
| 29 |
+
f = m.test_callback4()
|
| 30 |
+
assert f(43) == 44
|
| 31 |
+
f = m.test_callback5()
|
| 32 |
+
assert f(number=43) == 44
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def test_bound_method_callback():
|
| 36 |
+
# Bound Python method:
|
| 37 |
+
class MyClass:
|
| 38 |
+
def double(self, val):
|
| 39 |
+
return 2 * val
|
| 40 |
+
|
| 41 |
+
z = MyClass()
|
| 42 |
+
assert m.test_callback3(z.double) == "func(43) = 86"
|
| 43 |
+
|
| 44 |
+
z = m.CppBoundMethodTest()
|
| 45 |
+
assert m.test_callback3(z.triple) == "func(43) = 129"
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def test_keyword_args_and_generalized_unpacking():
|
| 49 |
+
def f(*args, **kwargs):
|
| 50 |
+
return args, kwargs
|
| 51 |
+
|
| 52 |
+
assert m.test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {})
|
| 53 |
+
assert m.test_dict_unpacking(f) == (
|
| 54 |
+
("positional", 1),
|
| 55 |
+
{"key": "value", "a": 1, "b": 2},
|
| 56 |
+
)
|
| 57 |
+
assert m.test_keyword_args(f) == ((), {"x": 10, "y": 20})
|
| 58 |
+
assert m.test_unpacking_and_keywords1(f) == ((1, 2), {"c": 3, "d": 4})
|
| 59 |
+
assert m.test_unpacking_and_keywords2(f) == (
|
| 60 |
+
("positional", 1, 2, 3, 4, 5),
|
| 61 |
+
{"key": "value", "a": 1, "b": 2, "c": 3, "d": 4, "e": 5},
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
with pytest.raises(TypeError) as excinfo:
|
| 65 |
+
m.test_unpacking_error1(f)
|
| 66 |
+
assert "Got multiple values for keyword argument" in str(excinfo.value)
|
| 67 |
+
|
| 68 |
+
with pytest.raises(TypeError) as excinfo:
|
| 69 |
+
m.test_unpacking_error2(f)
|
| 70 |
+
assert "Got multiple values for keyword argument" in str(excinfo.value)
|
| 71 |
+
|
| 72 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 73 |
+
m.test_arg_conversion_error1(f)
|
| 74 |
+
assert str(excinfo.value) == "Unable to convert call argument " + (
|
| 75 |
+
"'1' of type 'UnregisteredType' to Python object"
|
| 76 |
+
if detailed_error_messages_enabled
|
| 77 |
+
else "'1' to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"
|
| 78 |
+
)
|
| 79 |
+
|
| 80 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 81 |
+
m.test_arg_conversion_error2(f)
|
| 82 |
+
assert str(excinfo.value) == "Unable to convert call argument " + (
|
| 83 |
+
"'expected_name' of type 'UnregisteredType' to Python object"
|
| 84 |
+
if detailed_error_messages_enabled
|
| 85 |
+
else "'expected_name' to Python object "
|
| 86 |
+
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"
|
| 87 |
+
)
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def test_lambda_closure_cleanup():
|
| 91 |
+
m.test_lambda_closure_cleanup()
|
| 92 |
+
cstats = m.payload_cstats()
|
| 93 |
+
assert cstats.alive() == 0
|
| 94 |
+
assert cstats.copy_constructions == 1
|
| 95 |
+
assert cstats.move_constructions >= 1
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def test_cpp_callable_cleanup():
|
| 99 |
+
alive_counts = m.test_cpp_callable_cleanup()
|
| 100 |
+
assert alive_counts == [0, 1, 2, 1, 2, 1, 0]
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def test_cpp_function_roundtrip():
|
| 104 |
+
"""Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
|
| 105 |
+
|
| 106 |
+
assert (
|
| 107 |
+
m.test_dummy_function(m.dummy_function) == "matches dummy_function: eval(1) = 2"
|
| 108 |
+
)
|
| 109 |
+
assert (
|
| 110 |
+
m.test_dummy_function(m.roundtrip(m.dummy_function))
|
| 111 |
+
== "matches dummy_function: eval(1) = 2"
|
| 112 |
+
)
|
| 113 |
+
assert (
|
| 114 |
+
m.test_dummy_function(m.dummy_function_overloaded)
|
| 115 |
+
== "matches dummy_function: eval(1) = 2"
|
| 116 |
+
)
|
| 117 |
+
assert m.roundtrip(None, expect_none=True) is None
|
| 118 |
+
assert (
|
| 119 |
+
m.test_dummy_function(lambda x: x + 2)
|
| 120 |
+
== "can't convert to function pointer: eval(1) = 3"
|
| 121 |
+
)
|
| 122 |
+
|
| 123 |
+
with pytest.raises(TypeError) as excinfo:
|
| 124 |
+
m.test_dummy_function(m.dummy_function2)
|
| 125 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
| 126 |
+
|
| 127 |
+
with pytest.raises(TypeError) as excinfo:
|
| 128 |
+
m.test_dummy_function(lambda x, y: x + y)
|
| 129 |
+
assert any(
|
| 130 |
+
s in str(excinfo.value)
|
| 131 |
+
for s in ("missing 1 required positional argument", "takes exactly 2 arguments")
|
| 132 |
+
)
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def test_function_signatures(doc):
|
| 136 |
+
assert doc(m.test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str"
|
| 137 |
+
assert doc(m.test_callback4) == "test_callback4() -> Callable[[int], int]"
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
def test_movable_object():
|
| 141 |
+
assert m.callback_with_movable(lambda _: None) is True
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
@pytest.mark.skipif(
|
| 145 |
+
"env.PYPY",
|
| 146 |
+
reason="PyPy segfaults on here. See discussion on #1413.",
|
| 147 |
+
)
|
| 148 |
+
def test_python_builtins():
|
| 149 |
+
"""Test if python builtins like sum() can be used as callbacks"""
|
| 150 |
+
assert m.test_sum_builtin(sum, [1, 2, 3]) == 6
|
| 151 |
+
assert m.test_sum_builtin(sum, []) == 0
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
def test_async_callbacks():
|
| 155 |
+
# serves as state for async callback
|
| 156 |
+
class Item:
|
| 157 |
+
def __init__(self, value):
|
| 158 |
+
self.value = value
|
| 159 |
+
|
| 160 |
+
res = []
|
| 161 |
+
|
| 162 |
+
# generate stateful lambda that will store result in `res`
|
| 163 |
+
def gen_f():
|
| 164 |
+
s = Item(3)
|
| 165 |
+
return lambda j: res.append(s.value + j)
|
| 166 |
+
|
| 167 |
+
# do some work async
|
| 168 |
+
work = [1, 2, 3, 4]
|
| 169 |
+
m.test_async_callback(gen_f(), work)
|
| 170 |
+
# wait until work is done
|
| 171 |
+
from time import sleep
|
| 172 |
+
|
| 173 |
+
sleep(0.5)
|
| 174 |
+
assert sum(res) == sum(x + 3 for x in work)
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def test_async_async_callbacks():
|
| 178 |
+
t = Thread(target=test_async_callbacks)
|
| 179 |
+
t.start()
|
| 180 |
+
t.join()
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
def test_callback_num_times():
|
| 184 |
+
# Super-simple micro-benchmarking related to PR #2919.
|
| 185 |
+
# Example runtimes (Intel Xeon 2.2GHz, fully optimized):
|
| 186 |
+
# num_millions 1, repeats 2: 0.1 secs
|
| 187 |
+
# num_millions 20, repeats 10: 11.5 secs
|
| 188 |
+
one_million = 1000000
|
| 189 |
+
num_millions = 1 # Try 20 for actual micro-benchmarking.
|
| 190 |
+
repeats = 2 # Try 10.
|
| 191 |
+
rates = []
|
| 192 |
+
for rep in range(repeats):
|
| 193 |
+
t0 = time.time()
|
| 194 |
+
m.callback_num_times(lambda: None, num_millions * one_million)
|
| 195 |
+
td = time.time() - t0
|
| 196 |
+
rate = num_millions / td if td else 0
|
| 197 |
+
rates.append(rate)
|
| 198 |
+
if not rep:
|
| 199 |
+
print()
|
| 200 |
+
print(
|
| 201 |
+
f"callback_num_times: {num_millions:d} million / {td:.3f} seconds = {rate:.3f} million / second"
|
| 202 |
+
)
|
| 203 |
+
if len(rates) > 1:
|
| 204 |
+
print("Min Mean Max")
|
| 205 |
+
print(f"{min(rates):6.3f} {sum(rates) / len(rates):6.3f} {max(rates):6.3f}")
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
def test_custom_func():
|
| 209 |
+
assert m.custom_function(4) == 36
|
| 210 |
+
assert m.roundtrip(m.custom_function)(4) == 36
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
@pytest.mark.skipif(
|
| 214 |
+
m.custom_function2 is None, reason="Current PYBIND11_INTERNALS_VERSION too low"
|
| 215 |
+
)
|
| 216 |
+
def test_custom_func2():
|
| 217 |
+
assert m.custom_function2(3) == 27
|
| 218 |
+
assert m.roundtrip(m.custom_function2)(3) == 27
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
def test_callback_docstring():
|
| 222 |
+
assert (
|
| 223 |
+
m.test_tuple_unpacking.__doc__.strip()
|
| 224 |
+
== "test_tuple_unpacking(arg0: Callable) -> object"
|
| 225 |
+
)
|
third_party/CityFlow/extern/pybind11/tests/test_chrono.cpp
CHANGED
|
@@ -1,81 +1,81 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_chrono.cpp -- test conversions to/from std::chrono types
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2016 Trent Houliston <trent@houliston.me> and
|
| 5 |
-
Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 6 |
-
|
| 7 |
-
All rights reserved. Use of this source code is governed by a
|
| 8 |
-
BSD-style license that can be found in the LICENSE file.
|
| 9 |
-
*/
|
| 10 |
-
|
| 11 |
-
#include <pybind11/chrono.h>
|
| 12 |
-
|
| 13 |
-
#include "pybind11_tests.h"
|
| 14 |
-
|
| 15 |
-
#include <chrono>
|
| 16 |
-
|
| 17 |
-
struct different_resolutions {
|
| 18 |
-
using time_point_h = std::chrono::time_point<std::chrono::system_clock, std::chrono::hours>;
|
| 19 |
-
using time_point_m = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
|
| 20 |
-
using time_point_s = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
|
| 21 |
-
using time_point_ms
|
| 22 |
-
= std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>;
|
| 23 |
-
using time_point_us
|
| 24 |
-
= std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>;
|
| 25 |
-
time_point_h timestamp_h;
|
| 26 |
-
time_point_m timestamp_m;
|
| 27 |
-
time_point_s timestamp_s;
|
| 28 |
-
time_point_ms timestamp_ms;
|
| 29 |
-
time_point_us timestamp_us;
|
| 30 |
-
};
|
| 31 |
-
|
| 32 |
-
TEST_SUBMODULE(chrono, m) {
|
| 33 |
-
using system_time = std::chrono::system_clock::time_point;
|
| 34 |
-
using steady_time = std::chrono::steady_clock::time_point;
|
| 35 |
-
|
| 36 |
-
using timespan = std::chrono::duration<int64_t, std::nano>;
|
| 37 |
-
using timestamp = std::chrono::time_point<std::chrono::system_clock, timespan>;
|
| 38 |
-
|
| 39 |
-
// test_chrono_system_clock
|
| 40 |
-
// Return the current time off the wall clock
|
| 41 |
-
m.def("test_chrono1", []() { return std::chrono::system_clock::now(); });
|
| 42 |
-
|
| 43 |
-
// test_chrono_system_clock_roundtrip
|
| 44 |
-
// Round trip the passed in system clock time
|
| 45 |
-
m.def("test_chrono2", [](system_time t) { return t; });
|
| 46 |
-
|
| 47 |
-
// test_chrono_duration_roundtrip
|
| 48 |
-
// Round trip the passed in duration
|
| 49 |
-
m.def("test_chrono3", [](std::chrono::system_clock::duration d) { return d; });
|
| 50 |
-
|
| 51 |
-
// test_chrono_duration_subtraction_equivalence
|
| 52 |
-
// Difference between two passed in time_points
|
| 53 |
-
m.def("test_chrono4", [](system_time a, system_time b) { return a - b; });
|
| 54 |
-
|
| 55 |
-
// test_chrono_steady_clock
|
| 56 |
-
// Return the current time off the steady_clock
|
| 57 |
-
m.def("test_chrono5", []() { return std::chrono::steady_clock::now(); });
|
| 58 |
-
|
| 59 |
-
// test_chrono_steady_clock_roundtrip
|
| 60 |
-
// Round trip a steady clock timepoint
|
| 61 |
-
m.def("test_chrono6", [](steady_time t) { return t; });
|
| 62 |
-
|
| 63 |
-
// test_floating_point_duration
|
| 64 |
-
// Roundtrip a duration in microseconds from a float argument
|
| 65 |
-
m.def("test_chrono7", [](std::chrono::microseconds t) { return t; });
|
| 66 |
-
// Float durations (issue #719)
|
| 67 |
-
m.def("test_chrono_float_diff",
|
| 68 |
-
[](std::chrono::duration<float> a, std::chrono::duration<float> b) { return a - b; });
|
| 69 |
-
|
| 70 |
-
m.def("test_nano_timepoint",
|
| 71 |
-
[](timestamp start, timespan delta) -> timestamp { return start + delta; });
|
| 72 |
-
|
| 73 |
-
// Test different resolutions
|
| 74 |
-
py::class_<different_resolutions>(m, "different_resolutions")
|
| 75 |
-
.def(py::init<>())
|
| 76 |
-
.def_readwrite("timestamp_h", &different_resolutions::timestamp_h)
|
| 77 |
-
.def_readwrite("timestamp_m", &different_resolutions::timestamp_m)
|
| 78 |
-
.def_readwrite("timestamp_s", &different_resolutions::timestamp_s)
|
| 79 |
-
.def_readwrite("timestamp_ms", &different_resolutions::timestamp_ms)
|
| 80 |
-
.def_readwrite("timestamp_us", &different_resolutions::timestamp_us);
|
| 81 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_chrono.cpp -- test conversions to/from std::chrono types
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2016 Trent Houliston <trent@houliston.me> and
|
| 5 |
+
Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 6 |
+
|
| 7 |
+
All rights reserved. Use of this source code is governed by a
|
| 8 |
+
BSD-style license that can be found in the LICENSE file.
|
| 9 |
+
*/
|
| 10 |
+
|
| 11 |
+
#include <pybind11/chrono.h>
|
| 12 |
+
|
| 13 |
+
#include "pybind11_tests.h"
|
| 14 |
+
|
| 15 |
+
#include <chrono>
|
| 16 |
+
|
| 17 |
+
struct different_resolutions {
|
| 18 |
+
using time_point_h = std::chrono::time_point<std::chrono::system_clock, std::chrono::hours>;
|
| 19 |
+
using time_point_m = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
|
| 20 |
+
using time_point_s = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
|
| 21 |
+
using time_point_ms
|
| 22 |
+
= std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>;
|
| 23 |
+
using time_point_us
|
| 24 |
+
= std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>;
|
| 25 |
+
time_point_h timestamp_h;
|
| 26 |
+
time_point_m timestamp_m;
|
| 27 |
+
time_point_s timestamp_s;
|
| 28 |
+
time_point_ms timestamp_ms;
|
| 29 |
+
time_point_us timestamp_us;
|
| 30 |
+
};
|
| 31 |
+
|
| 32 |
+
TEST_SUBMODULE(chrono, m) {
|
| 33 |
+
using system_time = std::chrono::system_clock::time_point;
|
| 34 |
+
using steady_time = std::chrono::steady_clock::time_point;
|
| 35 |
+
|
| 36 |
+
using timespan = std::chrono::duration<int64_t, std::nano>;
|
| 37 |
+
using timestamp = std::chrono::time_point<std::chrono::system_clock, timespan>;
|
| 38 |
+
|
| 39 |
+
// test_chrono_system_clock
|
| 40 |
+
// Return the current time off the wall clock
|
| 41 |
+
m.def("test_chrono1", []() { return std::chrono::system_clock::now(); });
|
| 42 |
+
|
| 43 |
+
// test_chrono_system_clock_roundtrip
|
| 44 |
+
// Round trip the passed in system clock time
|
| 45 |
+
m.def("test_chrono2", [](system_time t) { return t; });
|
| 46 |
+
|
| 47 |
+
// test_chrono_duration_roundtrip
|
| 48 |
+
// Round trip the passed in duration
|
| 49 |
+
m.def("test_chrono3", [](std::chrono::system_clock::duration d) { return d; });
|
| 50 |
+
|
| 51 |
+
// test_chrono_duration_subtraction_equivalence
|
| 52 |
+
// Difference between two passed in time_points
|
| 53 |
+
m.def("test_chrono4", [](system_time a, system_time b) { return a - b; });
|
| 54 |
+
|
| 55 |
+
// test_chrono_steady_clock
|
| 56 |
+
// Return the current time off the steady_clock
|
| 57 |
+
m.def("test_chrono5", []() { return std::chrono::steady_clock::now(); });
|
| 58 |
+
|
| 59 |
+
// test_chrono_steady_clock_roundtrip
|
| 60 |
+
// Round trip a steady clock timepoint
|
| 61 |
+
m.def("test_chrono6", [](steady_time t) { return t; });
|
| 62 |
+
|
| 63 |
+
// test_floating_point_duration
|
| 64 |
+
// Roundtrip a duration in microseconds from a float argument
|
| 65 |
+
m.def("test_chrono7", [](std::chrono::microseconds t) { return t; });
|
| 66 |
+
// Float durations (issue #719)
|
| 67 |
+
m.def("test_chrono_float_diff",
|
| 68 |
+
[](std::chrono::duration<float> a, std::chrono::duration<float> b) { return a - b; });
|
| 69 |
+
|
| 70 |
+
m.def("test_nano_timepoint",
|
| 71 |
+
[](timestamp start, timespan delta) -> timestamp { return start + delta; });
|
| 72 |
+
|
| 73 |
+
// Test different resolutions
|
| 74 |
+
py::class_<different_resolutions>(m, "different_resolutions")
|
| 75 |
+
.def(py::init<>())
|
| 76 |
+
.def_readwrite("timestamp_h", &different_resolutions::timestamp_h)
|
| 77 |
+
.def_readwrite("timestamp_m", &different_resolutions::timestamp_m)
|
| 78 |
+
.def_readwrite("timestamp_s", &different_resolutions::timestamp_s)
|
| 79 |
+
.def_readwrite("timestamp_ms", &different_resolutions::timestamp_ms)
|
| 80 |
+
.def_readwrite("timestamp_us", &different_resolutions::timestamp_us);
|
| 81 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_chrono.py
CHANGED
|
@@ -1,205 +1,205 @@
|
|
| 1 |
-
import datetime
|
| 2 |
-
|
| 3 |
-
import pytest
|
| 4 |
-
|
| 5 |
-
import env # noqa: F401
|
| 6 |
-
from pybind11_tests import chrono as m
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
def test_chrono_system_clock():
|
| 10 |
-
# Get the time from both c++ and datetime
|
| 11 |
-
date0 = datetime.datetime.today()
|
| 12 |
-
date1 = m.test_chrono1()
|
| 13 |
-
date2 = datetime.datetime.today()
|
| 14 |
-
|
| 15 |
-
# The returned value should be a datetime
|
| 16 |
-
assert isinstance(date1, datetime.datetime)
|
| 17 |
-
|
| 18 |
-
# The numbers should vary by a very small amount (time it took to execute)
|
| 19 |
-
diff_python = abs(date2 - date0)
|
| 20 |
-
diff = abs(date1 - date2)
|
| 21 |
-
|
| 22 |
-
# There should never be a days difference
|
| 23 |
-
assert diff.days == 0
|
| 24 |
-
|
| 25 |
-
# Since datetime.datetime.today() calls time.time(), and on some platforms
|
| 26 |
-
# that has 1 second accuracy, we compare this way
|
| 27 |
-
assert diff.seconds <= diff_python.seconds
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
def test_chrono_system_clock_roundtrip():
|
| 31 |
-
date1 = datetime.datetime.today()
|
| 32 |
-
|
| 33 |
-
# Roundtrip the time
|
| 34 |
-
date2 = m.test_chrono2(date1)
|
| 35 |
-
|
| 36 |
-
# The returned value should be a datetime
|
| 37 |
-
assert isinstance(date2, datetime.datetime)
|
| 38 |
-
|
| 39 |
-
# They should be identical (no information lost on roundtrip)
|
| 40 |
-
diff = abs(date1 - date2)
|
| 41 |
-
assert diff == datetime.timedelta(0)
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
def test_chrono_system_clock_roundtrip_date():
|
| 45 |
-
date1 = datetime.date.today()
|
| 46 |
-
|
| 47 |
-
# Roundtrip the time
|
| 48 |
-
datetime2 = m.test_chrono2(date1)
|
| 49 |
-
date2 = datetime2.date()
|
| 50 |
-
time2 = datetime2.time()
|
| 51 |
-
|
| 52 |
-
# The returned value should be a datetime
|
| 53 |
-
assert isinstance(datetime2, datetime.datetime)
|
| 54 |
-
assert isinstance(date2, datetime.date)
|
| 55 |
-
assert isinstance(time2, datetime.time)
|
| 56 |
-
|
| 57 |
-
# They should be identical (no information lost on roundtrip)
|
| 58 |
-
diff = abs(date1 - date2)
|
| 59 |
-
assert diff.days == 0
|
| 60 |
-
assert diff.seconds == 0
|
| 61 |
-
assert diff.microseconds == 0
|
| 62 |
-
|
| 63 |
-
# Year, Month & Day should be the same after the round trip
|
| 64 |
-
assert date1 == date2
|
| 65 |
-
|
| 66 |
-
# There should be no time information
|
| 67 |
-
assert time2.hour == 0
|
| 68 |
-
assert time2.minute == 0
|
| 69 |
-
assert time2.second == 0
|
| 70 |
-
assert time2.microsecond == 0
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
SKIP_TZ_ENV_ON_WIN = pytest.mark.skipif(
|
| 74 |
-
"env.WIN", reason="TZ environment variable only supported on POSIX"
|
| 75 |
-
)
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
@pytest.mark.parametrize(
|
| 79 |
-
"time1",
|
| 80 |
-
[
|
| 81 |
-
datetime.datetime.today().time(),
|
| 82 |
-
datetime.time(0, 0, 0),
|
| 83 |
-
datetime.time(0, 0, 0, 1),
|
| 84 |
-
datetime.time(0, 28, 45, 109827),
|
| 85 |
-
datetime.time(0, 59, 59, 999999),
|
| 86 |
-
datetime.time(1, 0, 0),
|
| 87 |
-
datetime.time(5, 59, 59, 0),
|
| 88 |
-
datetime.time(5, 59, 59, 1),
|
| 89 |
-
],
|
| 90 |
-
)
|
| 91 |
-
@pytest.mark.parametrize(
|
| 92 |
-
"tz",
|
| 93 |
-
[
|
| 94 |
-
None,
|
| 95 |
-
pytest.param("Europe/Brussels", marks=SKIP_TZ_ENV_ON_WIN),
|
| 96 |
-
pytest.param("Asia/Pyongyang", marks=SKIP_TZ_ENV_ON_WIN),
|
| 97 |
-
pytest.param("America/New_York", marks=SKIP_TZ_ENV_ON_WIN),
|
| 98 |
-
],
|
| 99 |
-
)
|
| 100 |
-
def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch):
|
| 101 |
-
if tz is not None:
|
| 102 |
-
monkeypatch.setenv("TZ", f"/usr/share/zoneinfo/{tz}")
|
| 103 |
-
|
| 104 |
-
# Roundtrip the time
|
| 105 |
-
datetime2 = m.test_chrono2(time1)
|
| 106 |
-
date2 = datetime2.date()
|
| 107 |
-
time2 = datetime2.time()
|
| 108 |
-
|
| 109 |
-
# The returned value should be a datetime
|
| 110 |
-
assert isinstance(datetime2, datetime.datetime)
|
| 111 |
-
assert isinstance(date2, datetime.date)
|
| 112 |
-
assert isinstance(time2, datetime.time)
|
| 113 |
-
|
| 114 |
-
# Hour, Minute, Second & Microsecond should be the same after the round trip
|
| 115 |
-
assert time1 == time2
|
| 116 |
-
|
| 117 |
-
# There should be no date information (i.e. date = python base date)
|
| 118 |
-
assert date2.year == 1970
|
| 119 |
-
assert date2.month == 1
|
| 120 |
-
assert date2.day == 1
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
def test_chrono_duration_roundtrip():
|
| 124 |
-
# Get the difference between two times (a timedelta)
|
| 125 |
-
date1 = datetime.datetime.today()
|
| 126 |
-
date2 = datetime.datetime.today()
|
| 127 |
-
diff = date2 - date1
|
| 128 |
-
|
| 129 |
-
# Make sure this is a timedelta
|
| 130 |
-
assert isinstance(diff, datetime.timedelta)
|
| 131 |
-
|
| 132 |
-
cpp_diff = m.test_chrono3(diff)
|
| 133 |
-
|
| 134 |
-
assert cpp_diff == diff
|
| 135 |
-
|
| 136 |
-
# Negative timedelta roundtrip
|
| 137 |
-
diff = datetime.timedelta(microseconds=-1)
|
| 138 |
-
cpp_diff = m.test_chrono3(diff)
|
| 139 |
-
|
| 140 |
-
assert cpp_diff == diff
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
def test_chrono_duration_subtraction_equivalence():
|
| 144 |
-
date1 = datetime.datetime.today()
|
| 145 |
-
date2 = datetime.datetime.today()
|
| 146 |
-
|
| 147 |
-
diff = date2 - date1
|
| 148 |
-
cpp_diff = m.test_chrono4(date2, date1)
|
| 149 |
-
|
| 150 |
-
assert cpp_diff == diff
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
def test_chrono_duration_subtraction_equivalence_date():
|
| 154 |
-
date1 = datetime.date.today()
|
| 155 |
-
date2 = datetime.date.today()
|
| 156 |
-
|
| 157 |
-
diff = date2 - date1
|
| 158 |
-
cpp_diff = m.test_chrono4(date2, date1)
|
| 159 |
-
|
| 160 |
-
assert cpp_diff == diff
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
def test_chrono_steady_clock():
|
| 164 |
-
time1 = m.test_chrono5()
|
| 165 |
-
assert isinstance(time1, datetime.timedelta)
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
def test_chrono_steady_clock_roundtrip():
|
| 169 |
-
time1 = datetime.timedelta(days=10, seconds=10, microseconds=100)
|
| 170 |
-
time2 = m.test_chrono6(time1)
|
| 171 |
-
|
| 172 |
-
assert isinstance(time2, datetime.timedelta)
|
| 173 |
-
|
| 174 |
-
# They should be identical (no information lost on roundtrip)
|
| 175 |
-
assert time1 == time2
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
def test_floating_point_duration():
|
| 179 |
-
# Test using a floating point number in seconds
|
| 180 |
-
time = m.test_chrono7(35.525123)
|
| 181 |
-
|
| 182 |
-
assert isinstance(time, datetime.timedelta)
|
| 183 |
-
|
| 184 |
-
assert time.seconds == 35
|
| 185 |
-
assert 525122 <= time.microseconds <= 525123
|
| 186 |
-
|
| 187 |
-
diff = m.test_chrono_float_diff(43.789012, 1.123456)
|
| 188 |
-
assert diff.seconds == 42
|
| 189 |
-
assert 665556 <= diff.microseconds <= 665557
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
def test_nano_timepoint():
|
| 193 |
-
time = datetime.datetime.now()
|
| 194 |
-
time1 = m.test_nano_timepoint(time, datetime.timedelta(seconds=60))
|
| 195 |
-
assert time1 == time + datetime.timedelta(seconds=60)
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
def test_chrono_different_resolutions():
|
| 199 |
-
resolutions = m.different_resolutions()
|
| 200 |
-
time = datetime.datetime.now()
|
| 201 |
-
resolutions.timestamp_h = time
|
| 202 |
-
resolutions.timestamp_m = time
|
| 203 |
-
resolutions.timestamp_s = time
|
| 204 |
-
resolutions.timestamp_ms = time
|
| 205 |
-
resolutions.timestamp_us = time
|
|
|
|
| 1 |
+
import datetime
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
import env # noqa: F401
|
| 6 |
+
from pybind11_tests import chrono as m
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def test_chrono_system_clock():
|
| 10 |
+
# Get the time from both c++ and datetime
|
| 11 |
+
date0 = datetime.datetime.today()
|
| 12 |
+
date1 = m.test_chrono1()
|
| 13 |
+
date2 = datetime.datetime.today()
|
| 14 |
+
|
| 15 |
+
# The returned value should be a datetime
|
| 16 |
+
assert isinstance(date1, datetime.datetime)
|
| 17 |
+
|
| 18 |
+
# The numbers should vary by a very small amount (time it took to execute)
|
| 19 |
+
diff_python = abs(date2 - date0)
|
| 20 |
+
diff = abs(date1 - date2)
|
| 21 |
+
|
| 22 |
+
# There should never be a days difference
|
| 23 |
+
assert diff.days == 0
|
| 24 |
+
|
| 25 |
+
# Since datetime.datetime.today() calls time.time(), and on some platforms
|
| 26 |
+
# that has 1 second accuracy, we compare this way
|
| 27 |
+
assert diff.seconds <= diff_python.seconds
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def test_chrono_system_clock_roundtrip():
|
| 31 |
+
date1 = datetime.datetime.today()
|
| 32 |
+
|
| 33 |
+
# Roundtrip the time
|
| 34 |
+
date2 = m.test_chrono2(date1)
|
| 35 |
+
|
| 36 |
+
# The returned value should be a datetime
|
| 37 |
+
assert isinstance(date2, datetime.datetime)
|
| 38 |
+
|
| 39 |
+
# They should be identical (no information lost on roundtrip)
|
| 40 |
+
diff = abs(date1 - date2)
|
| 41 |
+
assert diff == datetime.timedelta(0)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def test_chrono_system_clock_roundtrip_date():
|
| 45 |
+
date1 = datetime.date.today()
|
| 46 |
+
|
| 47 |
+
# Roundtrip the time
|
| 48 |
+
datetime2 = m.test_chrono2(date1)
|
| 49 |
+
date2 = datetime2.date()
|
| 50 |
+
time2 = datetime2.time()
|
| 51 |
+
|
| 52 |
+
# The returned value should be a datetime
|
| 53 |
+
assert isinstance(datetime2, datetime.datetime)
|
| 54 |
+
assert isinstance(date2, datetime.date)
|
| 55 |
+
assert isinstance(time2, datetime.time)
|
| 56 |
+
|
| 57 |
+
# They should be identical (no information lost on roundtrip)
|
| 58 |
+
diff = abs(date1 - date2)
|
| 59 |
+
assert diff.days == 0
|
| 60 |
+
assert diff.seconds == 0
|
| 61 |
+
assert diff.microseconds == 0
|
| 62 |
+
|
| 63 |
+
# Year, Month & Day should be the same after the round trip
|
| 64 |
+
assert date1 == date2
|
| 65 |
+
|
| 66 |
+
# There should be no time information
|
| 67 |
+
assert time2.hour == 0
|
| 68 |
+
assert time2.minute == 0
|
| 69 |
+
assert time2.second == 0
|
| 70 |
+
assert time2.microsecond == 0
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
SKIP_TZ_ENV_ON_WIN = pytest.mark.skipif(
|
| 74 |
+
"env.WIN", reason="TZ environment variable only supported on POSIX"
|
| 75 |
+
)
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
@pytest.mark.parametrize(
|
| 79 |
+
"time1",
|
| 80 |
+
[
|
| 81 |
+
datetime.datetime.today().time(),
|
| 82 |
+
datetime.time(0, 0, 0),
|
| 83 |
+
datetime.time(0, 0, 0, 1),
|
| 84 |
+
datetime.time(0, 28, 45, 109827),
|
| 85 |
+
datetime.time(0, 59, 59, 999999),
|
| 86 |
+
datetime.time(1, 0, 0),
|
| 87 |
+
datetime.time(5, 59, 59, 0),
|
| 88 |
+
datetime.time(5, 59, 59, 1),
|
| 89 |
+
],
|
| 90 |
+
)
|
| 91 |
+
@pytest.mark.parametrize(
|
| 92 |
+
"tz",
|
| 93 |
+
[
|
| 94 |
+
None,
|
| 95 |
+
pytest.param("Europe/Brussels", marks=SKIP_TZ_ENV_ON_WIN),
|
| 96 |
+
pytest.param("Asia/Pyongyang", marks=SKIP_TZ_ENV_ON_WIN),
|
| 97 |
+
pytest.param("America/New_York", marks=SKIP_TZ_ENV_ON_WIN),
|
| 98 |
+
],
|
| 99 |
+
)
|
| 100 |
+
def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch):
|
| 101 |
+
if tz is not None:
|
| 102 |
+
monkeypatch.setenv("TZ", f"/usr/share/zoneinfo/{tz}")
|
| 103 |
+
|
| 104 |
+
# Roundtrip the time
|
| 105 |
+
datetime2 = m.test_chrono2(time1)
|
| 106 |
+
date2 = datetime2.date()
|
| 107 |
+
time2 = datetime2.time()
|
| 108 |
+
|
| 109 |
+
# The returned value should be a datetime
|
| 110 |
+
assert isinstance(datetime2, datetime.datetime)
|
| 111 |
+
assert isinstance(date2, datetime.date)
|
| 112 |
+
assert isinstance(time2, datetime.time)
|
| 113 |
+
|
| 114 |
+
# Hour, Minute, Second & Microsecond should be the same after the round trip
|
| 115 |
+
assert time1 == time2
|
| 116 |
+
|
| 117 |
+
# There should be no date information (i.e. date = python base date)
|
| 118 |
+
assert date2.year == 1970
|
| 119 |
+
assert date2.month == 1
|
| 120 |
+
assert date2.day == 1
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def test_chrono_duration_roundtrip():
|
| 124 |
+
# Get the difference between two times (a timedelta)
|
| 125 |
+
date1 = datetime.datetime.today()
|
| 126 |
+
date2 = datetime.datetime.today()
|
| 127 |
+
diff = date2 - date1
|
| 128 |
+
|
| 129 |
+
# Make sure this is a timedelta
|
| 130 |
+
assert isinstance(diff, datetime.timedelta)
|
| 131 |
+
|
| 132 |
+
cpp_diff = m.test_chrono3(diff)
|
| 133 |
+
|
| 134 |
+
assert cpp_diff == diff
|
| 135 |
+
|
| 136 |
+
# Negative timedelta roundtrip
|
| 137 |
+
diff = datetime.timedelta(microseconds=-1)
|
| 138 |
+
cpp_diff = m.test_chrono3(diff)
|
| 139 |
+
|
| 140 |
+
assert cpp_diff == diff
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def test_chrono_duration_subtraction_equivalence():
|
| 144 |
+
date1 = datetime.datetime.today()
|
| 145 |
+
date2 = datetime.datetime.today()
|
| 146 |
+
|
| 147 |
+
diff = date2 - date1
|
| 148 |
+
cpp_diff = m.test_chrono4(date2, date1)
|
| 149 |
+
|
| 150 |
+
assert cpp_diff == diff
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def test_chrono_duration_subtraction_equivalence_date():
|
| 154 |
+
date1 = datetime.date.today()
|
| 155 |
+
date2 = datetime.date.today()
|
| 156 |
+
|
| 157 |
+
diff = date2 - date1
|
| 158 |
+
cpp_diff = m.test_chrono4(date2, date1)
|
| 159 |
+
|
| 160 |
+
assert cpp_diff == diff
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
def test_chrono_steady_clock():
|
| 164 |
+
time1 = m.test_chrono5()
|
| 165 |
+
assert isinstance(time1, datetime.timedelta)
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
def test_chrono_steady_clock_roundtrip():
|
| 169 |
+
time1 = datetime.timedelta(days=10, seconds=10, microseconds=100)
|
| 170 |
+
time2 = m.test_chrono6(time1)
|
| 171 |
+
|
| 172 |
+
assert isinstance(time2, datetime.timedelta)
|
| 173 |
+
|
| 174 |
+
# They should be identical (no information lost on roundtrip)
|
| 175 |
+
assert time1 == time2
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def test_floating_point_duration():
|
| 179 |
+
# Test using a floating point number in seconds
|
| 180 |
+
time = m.test_chrono7(35.525123)
|
| 181 |
+
|
| 182 |
+
assert isinstance(time, datetime.timedelta)
|
| 183 |
+
|
| 184 |
+
assert time.seconds == 35
|
| 185 |
+
assert 525122 <= time.microseconds <= 525123
|
| 186 |
+
|
| 187 |
+
diff = m.test_chrono_float_diff(43.789012, 1.123456)
|
| 188 |
+
assert diff.seconds == 42
|
| 189 |
+
assert 665556 <= diff.microseconds <= 665557
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
def test_nano_timepoint():
|
| 193 |
+
time = datetime.datetime.now()
|
| 194 |
+
time1 = m.test_nano_timepoint(time, datetime.timedelta(seconds=60))
|
| 195 |
+
assert time1 == time + datetime.timedelta(seconds=60)
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
def test_chrono_different_resolutions():
|
| 199 |
+
resolutions = m.different_resolutions()
|
| 200 |
+
time = datetime.datetime.now()
|
| 201 |
+
resolutions.timestamp_h = time
|
| 202 |
+
resolutions.timestamp_m = time
|
| 203 |
+
resolutions.timestamp_s = time
|
| 204 |
+
resolutions.timestamp_ms = time
|
| 205 |
+
resolutions.timestamp_us = time
|
third_party/CityFlow/extern/pybind11/tests/test_class.cpp
CHANGED
|
@@ -1,657 +1,657 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_class.cpp -- test py::class_ definitions and basic functionality
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#if defined(__INTEL_COMPILER) && __cplusplus >= 201703L
|
| 11 |
-
// Intel compiler requires a separate header file to support aligned new operators
|
| 12 |
-
// and does not set the __cpp_aligned_new feature macro.
|
| 13 |
-
// This header needs to be included before pybind11.
|
| 14 |
-
# include <aligned_new>
|
| 15 |
-
#endif
|
| 16 |
-
|
| 17 |
-
#include <pybind11/stl.h>
|
| 18 |
-
|
| 19 |
-
#include "constructor_stats.h"
|
| 20 |
-
#include "local_bindings.h"
|
| 21 |
-
#include "pybind11_tests.h"
|
| 22 |
-
|
| 23 |
-
#include <utility>
|
| 24 |
-
|
| 25 |
-
PYBIND11_WARNING_DISABLE_MSVC(4324)
|
| 26 |
-
// warning C4324: structure was padded due to alignment specifier
|
| 27 |
-
|
| 28 |
-
// test_brace_initialization
|
| 29 |
-
struct NoBraceInitialization {
|
| 30 |
-
explicit NoBraceInitialization(std::vector<int> v) : vec{std::move(v)} {}
|
| 31 |
-
template <typename T>
|
| 32 |
-
NoBraceInitialization(std::initializer_list<T> l) : vec(l) {}
|
| 33 |
-
|
| 34 |
-
std::vector<int> vec;
|
| 35 |
-
};
|
| 36 |
-
|
| 37 |
-
namespace test_class {
|
| 38 |
-
namespace pr4220_tripped_over_this { // PR #4227
|
| 39 |
-
|
| 40 |
-
template <int>
|
| 41 |
-
struct SoEmpty {};
|
| 42 |
-
|
| 43 |
-
template <typename T>
|
| 44 |
-
std::string get_msg(const T &) {
|
| 45 |
-
return "This is really only meant to exercise successful compilation.";
|
| 46 |
-
}
|
| 47 |
-
|
| 48 |
-
using Empty0 = SoEmpty<0x0>;
|
| 49 |
-
|
| 50 |
-
void bind_empty0(py::module_ &m) {
|
| 51 |
-
py::class_<Empty0>(m, "Empty0").def(py::init<>()).def("get_msg", get_msg<Empty0>);
|
| 52 |
-
}
|
| 53 |
-
|
| 54 |
-
} // namespace pr4220_tripped_over_this
|
| 55 |
-
} // namespace test_class
|
| 56 |
-
|
| 57 |
-
TEST_SUBMODULE(class_, m) {
|
| 58 |
-
m.def("obj_class_name", [](py::handle obj) { return py::detail::obj_class_name(obj.ptr()); });
|
| 59 |
-
|
| 60 |
-
// test_instance
|
| 61 |
-
struct NoConstructor {
|
| 62 |
-
NoConstructor() = default;
|
| 63 |
-
NoConstructor(const NoConstructor &) = default;
|
| 64 |
-
NoConstructor(NoConstructor &&) = default;
|
| 65 |
-
static NoConstructor *new_instance() {
|
| 66 |
-
auto *ptr = new NoConstructor();
|
| 67 |
-
print_created(ptr, "via new_instance");
|
| 68 |
-
return ptr;
|
| 69 |
-
}
|
| 70 |
-
~NoConstructor() { print_destroyed(this); }
|
| 71 |
-
};
|
| 72 |
-
struct NoConstructorNew {
|
| 73 |
-
NoConstructorNew() = default;
|
| 74 |
-
NoConstructorNew(const NoConstructorNew &) = default;
|
| 75 |
-
NoConstructorNew(NoConstructorNew &&) = default;
|
| 76 |
-
static NoConstructorNew *new_instance() {
|
| 77 |
-
auto *ptr = new NoConstructorNew();
|
| 78 |
-
print_created(ptr, "via new_instance");
|
| 79 |
-
return ptr;
|
| 80 |
-
}
|
| 81 |
-
~NoConstructorNew() { print_destroyed(this); }
|
| 82 |
-
};
|
| 83 |
-
|
| 84 |
-
py::class_<NoConstructor>(m, "NoConstructor")
|
| 85 |
-
.def_static("new_instance", &NoConstructor::new_instance, "Return an instance");
|
| 86 |
-
|
| 87 |
-
py::class_<NoConstructorNew>(m, "NoConstructorNew")
|
| 88 |
-
.def(py::init([]() { return nullptr; })) // Need a NOOP __init__
|
| 89 |
-
.def_static("__new__",
|
| 90 |
-
[](const py::object &) { return NoConstructorNew::new_instance(); });
|
| 91 |
-
|
| 92 |
-
// test_inheritance
|
| 93 |
-
class Pet {
|
| 94 |
-
public:
|
| 95 |
-
Pet(const std::string &name, const std::string &species)
|
| 96 |
-
: m_name(name), m_species(species) {}
|
| 97 |
-
std::string name() const { return m_name; }
|
| 98 |
-
std::string species() const { return m_species; }
|
| 99 |
-
|
| 100 |
-
private:
|
| 101 |
-
std::string m_name;
|
| 102 |
-
std::string m_species;
|
| 103 |
-
};
|
| 104 |
-
|
| 105 |
-
class Dog : public Pet {
|
| 106 |
-
public:
|
| 107 |
-
explicit Dog(const std::string &name) : Pet(name, "dog") {}
|
| 108 |
-
std::string bark() const { return "Woof!"; }
|
| 109 |
-
};
|
| 110 |
-
|
| 111 |
-
class Rabbit : public Pet {
|
| 112 |
-
public:
|
| 113 |
-
explicit Rabbit(const std::string &name) : Pet(name, "parrot") {}
|
| 114 |
-
};
|
| 115 |
-
|
| 116 |
-
class Hamster : public Pet {
|
| 117 |
-
public:
|
| 118 |
-
explicit Hamster(const std::string &name) : Pet(name, "rodent") {}
|
| 119 |
-
};
|
| 120 |
-
|
| 121 |
-
class Chimera : public Pet {
|
| 122 |
-
Chimera() : Pet("Kimmy", "chimera") {}
|
| 123 |
-
};
|
| 124 |
-
|
| 125 |
-
py::class_<Pet> pet_class(m, "Pet");
|
| 126 |
-
pet_class.def(py::init<std::string, std::string>())
|
| 127 |
-
.def("name", &Pet::name)
|
| 128 |
-
.def("species", &Pet::species);
|
| 129 |
-
|
| 130 |
-
/* One way of declaring a subclass relationship: reference parent's class_ object */
|
| 131 |
-
py::class_<Dog>(m, "Dog", pet_class).def(py::init<std::string>());
|
| 132 |
-
|
| 133 |
-
/* Another way of declaring a subclass relationship: reference parent's C++ type */
|
| 134 |
-
py::class_<Rabbit, Pet>(m, "Rabbit").def(py::init<std::string>());
|
| 135 |
-
|
| 136 |
-
/* And another: list parent in class template arguments */
|
| 137 |
-
py::class_<Hamster, Pet>(m, "Hamster").def(py::init<std::string>());
|
| 138 |
-
|
| 139 |
-
/* Constructors are not inherited by default */
|
| 140 |
-
py::class_<Chimera, Pet>(m, "Chimera");
|
| 141 |
-
|
| 142 |
-
m.def("pet_name_species",
|
| 143 |
-
[](const Pet &pet) { return pet.name() + " is a " + pet.species(); });
|
| 144 |
-
m.def("dog_bark", [](const Dog &dog) { return dog.bark(); });
|
| 145 |
-
|
| 146 |
-
// test_automatic_upcasting
|
| 147 |
-
struct BaseClass {
|
| 148 |
-
BaseClass() = default;
|
| 149 |
-
BaseClass(const BaseClass &) = default;
|
| 150 |
-
BaseClass(BaseClass &&) = default;
|
| 151 |
-
virtual ~BaseClass() = default;
|
| 152 |
-
};
|
| 153 |
-
struct DerivedClass1 : BaseClass {};
|
| 154 |
-
struct DerivedClass2 : BaseClass {};
|
| 155 |
-
|
| 156 |
-
py::class_<BaseClass>(m, "BaseClass").def(py::init<>());
|
| 157 |
-
py::class_<DerivedClass1>(m, "DerivedClass1").def(py::init<>());
|
| 158 |
-
py::class_<DerivedClass2>(m, "DerivedClass2").def(py::init<>());
|
| 159 |
-
|
| 160 |
-
m.def("return_class_1", []() -> BaseClass * { return new DerivedClass1(); });
|
| 161 |
-
m.def("return_class_2", []() -> BaseClass * { return new DerivedClass2(); });
|
| 162 |
-
m.def("return_class_n", [](int n) -> BaseClass * {
|
| 163 |
-
if (n == 1) {
|
| 164 |
-
return new DerivedClass1();
|
| 165 |
-
}
|
| 166 |
-
if (n == 2) {
|
| 167 |
-
return new DerivedClass2();
|
| 168 |
-
}
|
| 169 |
-
return new BaseClass();
|
| 170 |
-
});
|
| 171 |
-
m.def("return_none", []() -> BaseClass * { return nullptr; });
|
| 172 |
-
|
| 173 |
-
// test_isinstance
|
| 174 |
-
m.def("check_instances", [](const py::list &l) {
|
| 175 |
-
return py::make_tuple(py::isinstance<py::tuple>(l[0]),
|
| 176 |
-
py::isinstance<py::dict>(l[1]),
|
| 177 |
-
py::isinstance<Pet>(l[2]),
|
| 178 |
-
py::isinstance<Pet>(l[3]),
|
| 179 |
-
py::isinstance<Dog>(l[4]),
|
| 180 |
-
py::isinstance<Rabbit>(l[5]),
|
| 181 |
-
py::isinstance<UnregisteredType>(l[6]));
|
| 182 |
-
});
|
| 183 |
-
|
| 184 |
-
struct Invalid {};
|
| 185 |
-
|
| 186 |
-
// test_type
|
| 187 |
-
m.def("check_type", [](int category) {
|
| 188 |
-
// Currently not supported (via a fail at compile time)
|
| 189 |
-
// See https://github.com/pybind/pybind11/issues/2486
|
| 190 |
-
// if (category == 2)
|
| 191 |
-
// return py::type::of<int>();
|
| 192 |
-
if (category == 1) {
|
| 193 |
-
return py::type::of<DerivedClass1>();
|
| 194 |
-
}
|
| 195 |
-
return py::type::of<Invalid>();
|
| 196 |
-
});
|
| 197 |
-
|
| 198 |
-
m.def("get_type_of", [](py::object ob) { return py::type::of(std::move(ob)); });
|
| 199 |
-
|
| 200 |
-
m.def("get_type_classic", [](py::handle h) { return h.get_type(); });
|
| 201 |
-
|
| 202 |
-
m.def("as_type", [](const py::object &ob) { return py::type(ob); });
|
| 203 |
-
|
| 204 |
-
// test_mismatched_holder
|
| 205 |
-
struct MismatchBase1 {};
|
| 206 |
-
struct MismatchDerived1 : MismatchBase1 {};
|
| 207 |
-
|
| 208 |
-
struct MismatchBase2 {};
|
| 209 |
-
struct MismatchDerived2 : MismatchBase2 {};
|
| 210 |
-
|
| 211 |
-
m.def("mismatched_holder_1", []() {
|
| 212 |
-
auto mod = py::module_::import("__main__");
|
| 213 |
-
py::class_<MismatchBase1, std::shared_ptr<MismatchBase1>>(mod, "MismatchBase1");
|
| 214 |
-
py::class_<MismatchDerived1, MismatchBase1>(mod, "MismatchDerived1");
|
| 215 |
-
});
|
| 216 |
-
m.def("mismatched_holder_2", []() {
|
| 217 |
-
auto mod = py::module_::import("__main__");
|
| 218 |
-
py::class_<MismatchBase2>(mod, "MismatchBase2");
|
| 219 |
-
py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>, MismatchBase2>(
|
| 220 |
-
mod, "MismatchDerived2");
|
| 221 |
-
});
|
| 222 |
-
|
| 223 |
-
// test_override_static
|
| 224 |
-
// #511: problem with inheritance + overwritten def_static
|
| 225 |
-
struct MyBase {
|
| 226 |
-
static std::unique_ptr<MyBase> make() { return std::unique_ptr<MyBase>(new MyBase()); }
|
| 227 |
-
};
|
| 228 |
-
|
| 229 |
-
struct MyDerived : MyBase {
|
| 230 |
-
static std::unique_ptr<MyDerived> make() {
|
| 231 |
-
return std::unique_ptr<MyDerived>(new MyDerived());
|
| 232 |
-
}
|
| 233 |
-
};
|
| 234 |
-
|
| 235 |
-
py::class_<MyBase>(m, "MyBase").def_static("make", &MyBase::make);
|
| 236 |
-
|
| 237 |
-
py::class_<MyDerived, MyBase>(m, "MyDerived")
|
| 238 |
-
.def_static("make", &MyDerived::make)
|
| 239 |
-
.def_static("make2", &MyDerived::make);
|
| 240 |
-
|
| 241 |
-
// test_implicit_conversion_life_support
|
| 242 |
-
struct ConvertibleFromUserType {
|
| 243 |
-
int i;
|
| 244 |
-
|
| 245 |
-
explicit ConvertibleFromUserType(UserType u) : i(u.value()) {}
|
| 246 |
-
};
|
| 247 |
-
|
| 248 |
-
py::class_<ConvertibleFromUserType>(m, "AcceptsUserType").def(py::init<UserType>());
|
| 249 |
-
py::implicitly_convertible<UserType, ConvertibleFromUserType>();
|
| 250 |
-
|
| 251 |
-
m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; });
|
| 252 |
-
m.def("implicitly_convert_variable", [](const py::object &o) {
|
| 253 |
-
// `o` is `UserType` and `r` is a reference to a temporary created by implicit
|
| 254 |
-
// conversion. This is valid when called inside a bound function because the temp
|
| 255 |
-
// object is attached to the same life support system as the arguments.
|
| 256 |
-
const auto &r = o.cast<const ConvertibleFromUserType &>();
|
| 257 |
-
return r.i;
|
| 258 |
-
});
|
| 259 |
-
m.add_object("implicitly_convert_variable_fail", [&] {
|
| 260 |
-
auto f = [](PyObject *, PyObject *args) -> PyObject * {
|
| 261 |
-
auto o = py::reinterpret_borrow<py::tuple>(args)[0];
|
| 262 |
-
try { // It should fail here because there is no life support.
|
| 263 |
-
o.cast<const ConvertibleFromUserType &>();
|
| 264 |
-
} catch (const py::cast_error &e) {
|
| 265 |
-
return py::str(e.what()).release().ptr();
|
| 266 |
-
}
|
| 267 |
-
return py::str().release().ptr();
|
| 268 |
-
};
|
| 269 |
-
|
| 270 |
-
auto *def = new PyMethodDef{"f", f, METH_VARARGS, nullptr};
|
| 271 |
-
py::capsule def_capsule(def,
|
| 272 |
-
[](void *ptr) { delete reinterpret_cast<PyMethodDef *>(ptr); });
|
| 273 |
-
return py::reinterpret_steal<py::object>(
|
| 274 |
-
PyCFunction_NewEx(def, def_capsule.ptr(), m.ptr()));
|
| 275 |
-
}());
|
| 276 |
-
|
| 277 |
-
// test_operator_new_delete
|
| 278 |
-
struct HasOpNewDel {
|
| 279 |
-
std::uint64_t i;
|
| 280 |
-
static void *operator new(size_t s) {
|
| 281 |
-
py::print("A new", s);
|
| 282 |
-
return ::operator new(s);
|
| 283 |
-
}
|
| 284 |
-
static void *operator new(size_t s, void *ptr) {
|
| 285 |
-
py::print("A placement-new", s);
|
| 286 |
-
return ptr;
|
| 287 |
-
}
|
| 288 |
-
static void operator delete(void *p) {
|
| 289 |
-
py::print("A delete");
|
| 290 |
-
return ::operator delete(p);
|
| 291 |
-
}
|
| 292 |
-
};
|
| 293 |
-
struct HasOpNewDelSize {
|
| 294 |
-
std::uint32_t i;
|
| 295 |
-
static void *operator new(size_t s) {
|
| 296 |
-
py::print("B new", s);
|
| 297 |
-
return ::operator new(s);
|
| 298 |
-
}
|
| 299 |
-
static void *operator new(size_t s, void *ptr) {
|
| 300 |
-
py::print("B placement-new", s);
|
| 301 |
-
return ptr;
|
| 302 |
-
}
|
| 303 |
-
static void operator delete(void *p, size_t s) {
|
| 304 |
-
py::print("B delete", s);
|
| 305 |
-
return ::operator delete(p);
|
| 306 |
-
}
|
| 307 |
-
};
|
| 308 |
-
struct AliasedHasOpNewDelSize {
|
| 309 |
-
std::uint64_t i;
|
| 310 |
-
static void *operator new(size_t s) {
|
| 311 |
-
py::print("C new", s);
|
| 312 |
-
return ::operator new(s);
|
| 313 |
-
}
|
| 314 |
-
static void *operator new(size_t s, void *ptr) {
|
| 315 |
-
py::print("C placement-new", s);
|
| 316 |
-
return ptr;
|
| 317 |
-
}
|
| 318 |
-
static void operator delete(void *p, size_t s) {
|
| 319 |
-
py::print("C delete", s);
|
| 320 |
-
return ::operator delete(p);
|
| 321 |
-
}
|
| 322 |
-
virtual ~AliasedHasOpNewDelSize() = default;
|
| 323 |
-
AliasedHasOpNewDelSize() = default;
|
| 324 |
-
AliasedHasOpNewDelSize(const AliasedHasOpNewDelSize &) = delete;
|
| 325 |
-
};
|
| 326 |
-
struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize {
|
| 327 |
-
PyAliasedHasOpNewDelSize() = default;
|
| 328 |
-
explicit PyAliasedHasOpNewDelSize(int) {}
|
| 329 |
-
std::uint64_t j;
|
| 330 |
-
};
|
| 331 |
-
struct HasOpNewDelBoth {
|
| 332 |
-
std::uint32_t i[8];
|
| 333 |
-
static void *operator new(size_t s) {
|
| 334 |
-
py::print("D new", s);
|
| 335 |
-
return ::operator new(s);
|
| 336 |
-
}
|
| 337 |
-
static void *operator new(size_t s, void *ptr) {
|
| 338 |
-
py::print("D placement-new", s);
|
| 339 |
-
return ptr;
|
| 340 |
-
}
|
| 341 |
-
static void operator delete(void *p) {
|
| 342 |
-
py::print("D delete");
|
| 343 |
-
return ::operator delete(p);
|
| 344 |
-
}
|
| 345 |
-
static void operator delete(void *p, size_t s) {
|
| 346 |
-
py::print("D wrong delete", s);
|
| 347 |
-
return ::operator delete(p);
|
| 348 |
-
}
|
| 349 |
-
};
|
| 350 |
-
py::class_<HasOpNewDel>(m, "HasOpNewDel").def(py::init<>());
|
| 351 |
-
py::class_<HasOpNewDelSize>(m, "HasOpNewDelSize").def(py::init<>());
|
| 352 |
-
py::class_<HasOpNewDelBoth>(m, "HasOpNewDelBoth").def(py::init<>());
|
| 353 |
-
py::class_<AliasedHasOpNewDelSize, PyAliasedHasOpNewDelSize> aliased(m,
|
| 354 |
-
"AliasedHasOpNewDelSize");
|
| 355 |
-
aliased.def(py::init<>());
|
| 356 |
-
aliased.attr("size_noalias") = py::int_(sizeof(AliasedHasOpNewDelSize));
|
| 357 |
-
aliased.attr("size_alias") = py::int_(sizeof(PyAliasedHasOpNewDelSize));
|
| 358 |
-
|
| 359 |
-
// This test is actually part of test_local_bindings (test_duplicate_local), but we need a
|
| 360 |
-
// definition in a different compilation unit within the same module:
|
| 361 |
-
bind_local<LocalExternal, 17>(m, "LocalExternal", py::module_local());
|
| 362 |
-
|
| 363 |
-
// test_bind_protected_functions
|
| 364 |
-
class ProtectedA {
|
| 365 |
-
protected:
|
| 366 |
-
int foo() const { return value; }
|
| 367 |
-
|
| 368 |
-
private:
|
| 369 |
-
int value = 42;
|
| 370 |
-
};
|
| 371 |
-
|
| 372 |
-
class PublicistA : public ProtectedA {
|
| 373 |
-
public:
|
| 374 |
-
using ProtectedA::foo;
|
| 375 |
-
};
|
| 376 |
-
|
| 377 |
-
py::class_<ProtectedA>(m, "ProtectedA").def(py::init<>()).def("foo", &PublicistA::foo);
|
| 378 |
-
|
| 379 |
-
class ProtectedB {
|
| 380 |
-
public:
|
| 381 |
-
virtual ~ProtectedB() = default;
|
| 382 |
-
ProtectedB() = default;
|
| 383 |
-
ProtectedB(const ProtectedB &) = delete;
|
| 384 |
-
|
| 385 |
-
protected:
|
| 386 |
-
virtual int foo() const { return value; }
|
| 387 |
-
virtual void *void_foo() { return static_cast<void *>(&value); }
|
| 388 |
-
virtual void *get_self() { return static_cast<void *>(this); }
|
| 389 |
-
|
| 390 |
-
private:
|
| 391 |
-
int value = 42;
|
| 392 |
-
};
|
| 393 |
-
|
| 394 |
-
class TrampolineB : public ProtectedB {
|
| 395 |
-
public:
|
| 396 |
-
int foo() const override { PYBIND11_OVERRIDE(int, ProtectedB, foo, ); }
|
| 397 |
-
void *void_foo() override { PYBIND11_OVERRIDE(void *, ProtectedB, void_foo, ); }
|
| 398 |
-
void *get_self() override { PYBIND11_OVERRIDE(void *, ProtectedB, get_self, ); }
|
| 399 |
-
};
|
| 400 |
-
|
| 401 |
-
class PublicistB : public ProtectedB {
|
| 402 |
-
public:
|
| 403 |
-
// [workaround(intel)] = default does not work here
|
| 404 |
-
// Removing or defaulting this destructor results in linking errors with the Intel compiler
|
| 405 |
-
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
|
| 406 |
-
~PublicistB() override{}; // NOLINT(modernize-use-equals-default)
|
| 407 |
-
using ProtectedB::foo;
|
| 408 |
-
using ProtectedB::get_self;
|
| 409 |
-
using ProtectedB::void_foo;
|
| 410 |
-
};
|
| 411 |
-
|
| 412 |
-
m.def("read_foo", [](const void *original) {
|
| 413 |
-
const int *ptr = reinterpret_cast<const int *>(original);
|
| 414 |
-
return *ptr;
|
| 415 |
-
});
|
| 416 |
-
|
| 417 |
-
m.def("pointers_equal",
|
| 418 |
-
[](const void *original, const void *comparison) { return original == comparison; });
|
| 419 |
-
|
| 420 |
-
py::class_<ProtectedB, TrampolineB>(m, "ProtectedB")
|
| 421 |
-
.def(py::init<>())
|
| 422 |
-
.def("foo", &PublicistB::foo)
|
| 423 |
-
.def("void_foo", &PublicistB::void_foo)
|
| 424 |
-
.def("get_self", &PublicistB::get_self);
|
| 425 |
-
|
| 426 |
-
// test_brace_initialization
|
| 427 |
-
struct BraceInitialization {
|
| 428 |
-
int field1;
|
| 429 |
-
std::string field2;
|
| 430 |
-
};
|
| 431 |
-
|
| 432 |
-
py::class_<BraceInitialization>(m, "BraceInitialization")
|
| 433 |
-
.def(py::init<int, const std::string &>())
|
| 434 |
-
.def_readwrite("field1", &BraceInitialization::field1)
|
| 435 |
-
.def_readwrite("field2", &BraceInitialization::field2);
|
| 436 |
-
// We *don't* want to construct using braces when the given constructor argument maps to a
|
| 437 |
-
// constructor, because brace initialization could go to the wrong place (in particular when
|
| 438 |
-
// there is also an `initializer_list<T>`-accept constructor):
|
| 439 |
-
py::class_<NoBraceInitialization>(m, "NoBraceInitialization")
|
| 440 |
-
.def(py::init<std::vector<int>>())
|
| 441 |
-
.def_readonly("vec", &NoBraceInitialization::vec);
|
| 442 |
-
|
| 443 |
-
// test_reentrant_implicit_conversion_failure
|
| 444 |
-
// #1035: issue with runaway reentrant implicit conversion
|
| 445 |
-
struct BogusImplicitConversion {
|
| 446 |
-
BogusImplicitConversion(const BogusImplicitConversion &) = default;
|
| 447 |
-
};
|
| 448 |
-
|
| 449 |
-
py::class_<BogusImplicitConversion>(m, "BogusImplicitConversion")
|
| 450 |
-
.def(py::init<const BogusImplicitConversion &>());
|
| 451 |
-
|
| 452 |
-
py::implicitly_convertible<int, BogusImplicitConversion>();
|
| 453 |
-
|
| 454 |
-
// test_qualname
|
| 455 |
-
// #1166: nested class docstring doesn't show nested name
|
| 456 |
-
// Also related: tests that __qualname__ is set properly
|
| 457 |
-
struct NestBase {};
|
| 458 |
-
struct Nested {};
|
| 459 |
-
py::class_<NestBase> base(m, "NestBase");
|
| 460 |
-
base.def(py::init<>());
|
| 461 |
-
py::class_<Nested>(base, "Nested")
|
| 462 |
-
.def(py::init<>())
|
| 463 |
-
.def("fn", [](Nested &, int, NestBase &, Nested &) {})
|
| 464 |
-
.def(
|
| 465 |
-
"fa", [](Nested &, int, NestBase &, Nested &) {}, "a"_a, "b"_a, "c"_a);
|
| 466 |
-
base.def("g", [](NestBase &, Nested &) {});
|
| 467 |
-
base.def("h", []() { return NestBase(); });
|
| 468 |
-
|
| 469 |
-
// test_error_after_conversion
|
| 470 |
-
// The second-pass path through dispatcher() previously didn't
|
| 471 |
-
// remember which overload was used, and would crash trying to
|
| 472 |
-
// generate a useful error message
|
| 473 |
-
|
| 474 |
-
struct NotRegistered {};
|
| 475 |
-
struct StringWrapper {
|
| 476 |
-
std::string str;
|
| 477 |
-
};
|
| 478 |
-
m.def("test_error_after_conversions", [](int) {});
|
| 479 |
-
m.def("test_error_after_conversions",
|
| 480 |
-
[](const StringWrapper &) -> NotRegistered { return {}; });
|
| 481 |
-
py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>());
|
| 482 |
-
py::implicitly_convertible<std::string, StringWrapper>();
|
| 483 |
-
|
| 484 |
-
#if defined(PYBIND11_CPP17)
|
| 485 |
-
struct alignas(1024) Aligned {
|
| 486 |
-
std::uintptr_t ptr() const { return (uintptr_t) this; }
|
| 487 |
-
};
|
| 488 |
-
py::class_<Aligned>(m, "Aligned").def(py::init<>()).def("ptr", &Aligned::ptr);
|
| 489 |
-
#endif
|
| 490 |
-
|
| 491 |
-
// test_final
|
| 492 |
-
struct IsFinal final {};
|
| 493 |
-
py::class_<IsFinal>(m, "IsFinal", py::is_final());
|
| 494 |
-
|
| 495 |
-
// test_non_final_final
|
| 496 |
-
struct IsNonFinalFinal {};
|
| 497 |
-
py::class_<IsNonFinalFinal>(m, "IsNonFinalFinal", py::is_final());
|
| 498 |
-
|
| 499 |
-
// test_exception_rvalue_abort
|
| 500 |
-
struct PyPrintDestructor {
|
| 501 |
-
PyPrintDestructor() = default;
|
| 502 |
-
~PyPrintDestructor() { py::print("Print from destructor"); }
|
| 503 |
-
void throw_something() { throw std::runtime_error("error"); }
|
| 504 |
-
};
|
| 505 |
-
py::class_<PyPrintDestructor>(m, "PyPrintDestructor")
|
| 506 |
-
.def(py::init<>())
|
| 507 |
-
.def("throw_something", &PyPrintDestructor::throw_something);
|
| 508 |
-
|
| 509 |
-
// test_multiple_instances_with_same_pointer
|
| 510 |
-
struct SamePointer {};
|
| 511 |
-
static SamePointer samePointer;
|
| 512 |
-
py::class_<SamePointer, std::unique_ptr<SamePointer, py::nodelete>>(m, "SamePointer")
|
| 513 |
-
.def(py::init([]() { return &samePointer; }));
|
| 514 |
-
|
| 515 |
-
struct Empty {};
|
| 516 |
-
py::class_<Empty>(m, "Empty").def(py::init<>());
|
| 517 |
-
|
| 518 |
-
// test_base_and_derived_nested_scope
|
| 519 |
-
struct BaseWithNested {
|
| 520 |
-
struct Nested {};
|
| 521 |
-
};
|
| 522 |
-
|
| 523 |
-
struct DerivedWithNested : BaseWithNested {
|
| 524 |
-
struct Nested {};
|
| 525 |
-
};
|
| 526 |
-
|
| 527 |
-
py::class_<BaseWithNested> baseWithNested_class(m, "BaseWithNested");
|
| 528 |
-
py::class_<DerivedWithNested, BaseWithNested> derivedWithNested_class(m, "DerivedWithNested");
|
| 529 |
-
py::class_<BaseWithNested::Nested>(baseWithNested_class, "Nested")
|
| 530 |
-
.def_static("get_name", []() { return "BaseWithNested::Nested"; });
|
| 531 |
-
py::class_<DerivedWithNested::Nested>(derivedWithNested_class, "Nested")
|
| 532 |
-
.def_static("get_name", []() { return "DerivedWithNested::Nested"; });
|
| 533 |
-
|
| 534 |
-
// test_register_duplicate_class
|
| 535 |
-
struct Duplicate {};
|
| 536 |
-
struct OtherDuplicate {};
|
| 537 |
-
struct DuplicateNested {};
|
| 538 |
-
struct OtherDuplicateNested {};
|
| 539 |
-
|
| 540 |
-
m.def("register_duplicate_class_name", [](const py::module_ &m) {
|
| 541 |
-
py::class_<Duplicate>(m, "Duplicate");
|
| 542 |
-
py::class_<OtherDuplicate>(m, "Duplicate");
|
| 543 |
-
});
|
| 544 |
-
m.def("register_duplicate_class_type", [](const py::module_ &m) {
|
| 545 |
-
py::class_<OtherDuplicate>(m, "OtherDuplicate");
|
| 546 |
-
py::class_<OtherDuplicate>(m, "YetAnotherDuplicate");
|
| 547 |
-
});
|
| 548 |
-
m.def("register_duplicate_nested_class_name", [](const py::object >) {
|
| 549 |
-
py::class_<DuplicateNested>(gt, "DuplicateNested");
|
| 550 |
-
py::class_<OtherDuplicateNested>(gt, "DuplicateNested");
|
| 551 |
-
});
|
| 552 |
-
m.def("register_duplicate_nested_class_type", [](const py::object >) {
|
| 553 |
-
py::class_<OtherDuplicateNested>(gt, "OtherDuplicateNested");
|
| 554 |
-
py::class_<OtherDuplicateNested>(gt, "YetAnotherDuplicateNested");
|
| 555 |
-
});
|
| 556 |
-
|
| 557 |
-
test_class::pr4220_tripped_over_this::bind_empty0(m);
|
| 558 |
-
}
|
| 559 |
-
|
| 560 |
-
template <int N>
|
| 561 |
-
class BreaksBase {
|
| 562 |
-
public:
|
| 563 |
-
virtual ~BreaksBase() = default;
|
| 564 |
-
BreaksBase() = default;
|
| 565 |
-
BreaksBase(const BreaksBase &) = delete;
|
| 566 |
-
};
|
| 567 |
-
template <int N>
|
| 568 |
-
class BreaksTramp : public BreaksBase<N> {};
|
| 569 |
-
// These should all compile just fine:
|
| 570 |
-
using DoesntBreak1 = py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>>;
|
| 571 |
-
using DoesntBreak2 = py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>>;
|
| 572 |
-
using DoesntBreak3 = py::class_<BreaksBase<3>, std::unique_ptr<BreaksBase<3>>>;
|
| 573 |
-
using DoesntBreak4 = py::class_<BreaksBase<4>, BreaksTramp<4>>;
|
| 574 |
-
using DoesntBreak5 = py::class_<BreaksBase<5>>;
|
| 575 |
-
using DoesntBreak6 = py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>>;
|
| 576 |
-
using DoesntBreak7 = py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>>;
|
| 577 |
-
using DoesntBreak8 = py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>>;
|
| 578 |
-
#define CHECK_BASE(N) \
|
| 579 |
-
static_assert(std::is_same<typename DoesntBreak##N::type, BreaksBase<(N)>>::value, \
|
| 580 |
-
"DoesntBreak" #N " has wrong type!")
|
| 581 |
-
CHECK_BASE(1);
|
| 582 |
-
CHECK_BASE(2);
|
| 583 |
-
CHECK_BASE(3);
|
| 584 |
-
CHECK_BASE(4);
|
| 585 |
-
CHECK_BASE(5);
|
| 586 |
-
CHECK_BASE(6);
|
| 587 |
-
CHECK_BASE(7);
|
| 588 |
-
CHECK_BASE(8);
|
| 589 |
-
#define CHECK_ALIAS(N) \
|
| 590 |
-
static_assert( \
|
| 591 |
-
DoesntBreak##N::has_alias \
|
| 592 |
-
&& std::is_same<typename DoesntBreak##N::type_alias, BreaksTramp<(N)>>::value, \
|
| 593 |
-
"DoesntBreak" #N " has wrong type_alias!")
|
| 594 |
-
#define CHECK_NOALIAS(N) \
|
| 595 |
-
static_assert(!DoesntBreak##N::has_alias \
|
| 596 |
-
&& std::is_void<typename DoesntBreak##N::type_alias>::value, \
|
| 597 |
-
"DoesntBreak" #N " has type alias, but shouldn't!")
|
| 598 |
-
CHECK_ALIAS(1);
|
| 599 |
-
CHECK_ALIAS(2);
|
| 600 |
-
CHECK_NOALIAS(3);
|
| 601 |
-
CHECK_ALIAS(4);
|
| 602 |
-
CHECK_NOALIAS(5);
|
| 603 |
-
CHECK_ALIAS(6);
|
| 604 |
-
CHECK_ALIAS(7);
|
| 605 |
-
CHECK_NOALIAS(8);
|
| 606 |
-
#define CHECK_HOLDER(N, TYPE) \
|
| 607 |
-
static_assert(std::is_same<typename DoesntBreak##N::holder_type, \
|
| 608 |
-
std::TYPE##_ptr<BreaksBase<(N)>>>::value, \
|
| 609 |
-
"DoesntBreak" #N " has wrong holder_type!")
|
| 610 |
-
CHECK_HOLDER(1, unique);
|
| 611 |
-
CHECK_HOLDER(2, unique);
|
| 612 |
-
CHECK_HOLDER(3, unique);
|
| 613 |
-
CHECK_HOLDER(4, unique);
|
| 614 |
-
CHECK_HOLDER(5, unique);
|
| 615 |
-
CHECK_HOLDER(6, shared);
|
| 616 |
-
CHECK_HOLDER(7, shared);
|
| 617 |
-
CHECK_HOLDER(8, shared);
|
| 618 |
-
|
| 619 |
-
// There's no nice way to test that these fail because they fail to compile; leave them here,
|
| 620 |
-
// though, so that they can be manually tested by uncommenting them (and seeing that compilation
|
| 621 |
-
// failures occurs).
|
| 622 |
-
|
| 623 |
-
// We have to actually look into the type: the typedef alone isn't enough to instantiate the type:
|
| 624 |
-
#define CHECK_BROKEN(N) \
|
| 625 |
-
static_assert(std::is_same<typename Breaks##N::type, BreaksBase<-(N)>>::value, \
|
| 626 |
-
"Breaks1 has wrong type!");
|
| 627 |
-
|
| 628 |
-
#ifdef PYBIND11_NEVER_DEFINED_EVER
|
| 629 |
-
// Two holder classes:
|
| 630 |
-
typedef py::
|
| 631 |
-
class_<BreaksBase<-1>, std::unique_ptr<BreaksBase<-1>>, std::unique_ptr<BreaksBase<-1>>>
|
| 632 |
-
Breaks1;
|
| 633 |
-
CHECK_BROKEN(1);
|
| 634 |
-
// Two aliases:
|
| 635 |
-
typedef py::class_<BreaksBase<-2>, BreaksTramp<-2>, BreaksTramp<-2>> Breaks2;
|
| 636 |
-
CHECK_BROKEN(2);
|
| 637 |
-
// Holder + 2 aliases
|
| 638 |
-
typedef py::
|
| 639 |
-
class_<BreaksBase<-3>, std::unique_ptr<BreaksBase<-3>>, BreaksTramp<-3>, BreaksTramp<-3>>
|
| 640 |
-
Breaks3;
|
| 641 |
-
CHECK_BROKEN(3);
|
| 642 |
-
// Alias + 2 holders
|
| 643 |
-
typedef py::class_<BreaksBase<-4>,
|
| 644 |
-
std::unique_ptr<BreaksBase<-4>>,
|
| 645 |
-
BreaksTramp<-4>,
|
| 646 |
-
std::shared_ptr<BreaksBase<-4>>>
|
| 647 |
-
Breaks4;
|
| 648 |
-
CHECK_BROKEN(4);
|
| 649 |
-
// Invalid option (not a subclass or holder)
|
| 650 |
-
typedef py::class_<BreaksBase<-5>, BreaksTramp<-4>> Breaks5;
|
| 651 |
-
CHECK_BROKEN(5);
|
| 652 |
-
// Invalid option: multiple inheritance not supported:
|
| 653 |
-
template <>
|
| 654 |
-
struct BreaksBase<-8> : BreaksBase<-6>, BreaksBase<-7> {};
|
| 655 |
-
typedef py::class_<BreaksBase<-8>, BreaksBase<-6>, BreaksBase<-7>> Breaks8;
|
| 656 |
-
CHECK_BROKEN(8);
|
| 657 |
-
#endif
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_class.cpp -- test py::class_ definitions and basic functionality
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#if defined(__INTEL_COMPILER) && __cplusplus >= 201703L
|
| 11 |
+
// Intel compiler requires a separate header file to support aligned new operators
|
| 12 |
+
// and does not set the __cpp_aligned_new feature macro.
|
| 13 |
+
// This header needs to be included before pybind11.
|
| 14 |
+
# include <aligned_new>
|
| 15 |
+
#endif
|
| 16 |
+
|
| 17 |
+
#include <pybind11/stl.h>
|
| 18 |
+
|
| 19 |
+
#include "constructor_stats.h"
|
| 20 |
+
#include "local_bindings.h"
|
| 21 |
+
#include "pybind11_tests.h"
|
| 22 |
+
|
| 23 |
+
#include <utility>
|
| 24 |
+
|
| 25 |
+
PYBIND11_WARNING_DISABLE_MSVC(4324)
|
| 26 |
+
// warning C4324: structure was padded due to alignment specifier
|
| 27 |
+
|
| 28 |
+
// test_brace_initialization
|
| 29 |
+
struct NoBraceInitialization {
|
| 30 |
+
explicit NoBraceInitialization(std::vector<int> v) : vec{std::move(v)} {}
|
| 31 |
+
template <typename T>
|
| 32 |
+
NoBraceInitialization(std::initializer_list<T> l) : vec(l) {}
|
| 33 |
+
|
| 34 |
+
std::vector<int> vec;
|
| 35 |
+
};
|
| 36 |
+
|
| 37 |
+
namespace test_class {
|
| 38 |
+
namespace pr4220_tripped_over_this { // PR #4227
|
| 39 |
+
|
| 40 |
+
template <int>
|
| 41 |
+
struct SoEmpty {};
|
| 42 |
+
|
| 43 |
+
template <typename T>
|
| 44 |
+
std::string get_msg(const T &) {
|
| 45 |
+
return "This is really only meant to exercise successful compilation.";
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
using Empty0 = SoEmpty<0x0>;
|
| 49 |
+
|
| 50 |
+
void bind_empty0(py::module_ &m) {
|
| 51 |
+
py::class_<Empty0>(m, "Empty0").def(py::init<>()).def("get_msg", get_msg<Empty0>);
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
} // namespace pr4220_tripped_over_this
|
| 55 |
+
} // namespace test_class
|
| 56 |
+
|
| 57 |
+
TEST_SUBMODULE(class_, m) {
|
| 58 |
+
m.def("obj_class_name", [](py::handle obj) { return py::detail::obj_class_name(obj.ptr()); });
|
| 59 |
+
|
| 60 |
+
// test_instance
|
| 61 |
+
struct NoConstructor {
|
| 62 |
+
NoConstructor() = default;
|
| 63 |
+
NoConstructor(const NoConstructor &) = default;
|
| 64 |
+
NoConstructor(NoConstructor &&) = default;
|
| 65 |
+
static NoConstructor *new_instance() {
|
| 66 |
+
auto *ptr = new NoConstructor();
|
| 67 |
+
print_created(ptr, "via new_instance");
|
| 68 |
+
return ptr;
|
| 69 |
+
}
|
| 70 |
+
~NoConstructor() { print_destroyed(this); }
|
| 71 |
+
};
|
| 72 |
+
struct NoConstructorNew {
|
| 73 |
+
NoConstructorNew() = default;
|
| 74 |
+
NoConstructorNew(const NoConstructorNew &) = default;
|
| 75 |
+
NoConstructorNew(NoConstructorNew &&) = default;
|
| 76 |
+
static NoConstructorNew *new_instance() {
|
| 77 |
+
auto *ptr = new NoConstructorNew();
|
| 78 |
+
print_created(ptr, "via new_instance");
|
| 79 |
+
return ptr;
|
| 80 |
+
}
|
| 81 |
+
~NoConstructorNew() { print_destroyed(this); }
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
py::class_<NoConstructor>(m, "NoConstructor")
|
| 85 |
+
.def_static("new_instance", &NoConstructor::new_instance, "Return an instance");
|
| 86 |
+
|
| 87 |
+
py::class_<NoConstructorNew>(m, "NoConstructorNew")
|
| 88 |
+
.def(py::init([]() { return nullptr; })) // Need a NOOP __init__
|
| 89 |
+
.def_static("__new__",
|
| 90 |
+
[](const py::object &) { return NoConstructorNew::new_instance(); });
|
| 91 |
+
|
| 92 |
+
// test_inheritance
|
| 93 |
+
class Pet {
|
| 94 |
+
public:
|
| 95 |
+
Pet(const std::string &name, const std::string &species)
|
| 96 |
+
: m_name(name), m_species(species) {}
|
| 97 |
+
std::string name() const { return m_name; }
|
| 98 |
+
std::string species() const { return m_species; }
|
| 99 |
+
|
| 100 |
+
private:
|
| 101 |
+
std::string m_name;
|
| 102 |
+
std::string m_species;
|
| 103 |
+
};
|
| 104 |
+
|
| 105 |
+
class Dog : public Pet {
|
| 106 |
+
public:
|
| 107 |
+
explicit Dog(const std::string &name) : Pet(name, "dog") {}
|
| 108 |
+
std::string bark() const { return "Woof!"; }
|
| 109 |
+
};
|
| 110 |
+
|
| 111 |
+
class Rabbit : public Pet {
|
| 112 |
+
public:
|
| 113 |
+
explicit Rabbit(const std::string &name) : Pet(name, "parrot") {}
|
| 114 |
+
};
|
| 115 |
+
|
| 116 |
+
class Hamster : public Pet {
|
| 117 |
+
public:
|
| 118 |
+
explicit Hamster(const std::string &name) : Pet(name, "rodent") {}
|
| 119 |
+
};
|
| 120 |
+
|
| 121 |
+
class Chimera : public Pet {
|
| 122 |
+
Chimera() : Pet("Kimmy", "chimera") {}
|
| 123 |
+
};
|
| 124 |
+
|
| 125 |
+
py::class_<Pet> pet_class(m, "Pet");
|
| 126 |
+
pet_class.def(py::init<std::string, std::string>())
|
| 127 |
+
.def("name", &Pet::name)
|
| 128 |
+
.def("species", &Pet::species);
|
| 129 |
+
|
| 130 |
+
/* One way of declaring a subclass relationship: reference parent's class_ object */
|
| 131 |
+
py::class_<Dog>(m, "Dog", pet_class).def(py::init<std::string>());
|
| 132 |
+
|
| 133 |
+
/* Another way of declaring a subclass relationship: reference parent's C++ type */
|
| 134 |
+
py::class_<Rabbit, Pet>(m, "Rabbit").def(py::init<std::string>());
|
| 135 |
+
|
| 136 |
+
/* And another: list parent in class template arguments */
|
| 137 |
+
py::class_<Hamster, Pet>(m, "Hamster").def(py::init<std::string>());
|
| 138 |
+
|
| 139 |
+
/* Constructors are not inherited by default */
|
| 140 |
+
py::class_<Chimera, Pet>(m, "Chimera");
|
| 141 |
+
|
| 142 |
+
m.def("pet_name_species",
|
| 143 |
+
[](const Pet &pet) { return pet.name() + " is a " + pet.species(); });
|
| 144 |
+
m.def("dog_bark", [](const Dog &dog) { return dog.bark(); });
|
| 145 |
+
|
| 146 |
+
// test_automatic_upcasting
|
| 147 |
+
struct BaseClass {
|
| 148 |
+
BaseClass() = default;
|
| 149 |
+
BaseClass(const BaseClass &) = default;
|
| 150 |
+
BaseClass(BaseClass &&) = default;
|
| 151 |
+
virtual ~BaseClass() = default;
|
| 152 |
+
};
|
| 153 |
+
struct DerivedClass1 : BaseClass {};
|
| 154 |
+
struct DerivedClass2 : BaseClass {};
|
| 155 |
+
|
| 156 |
+
py::class_<BaseClass>(m, "BaseClass").def(py::init<>());
|
| 157 |
+
py::class_<DerivedClass1>(m, "DerivedClass1").def(py::init<>());
|
| 158 |
+
py::class_<DerivedClass2>(m, "DerivedClass2").def(py::init<>());
|
| 159 |
+
|
| 160 |
+
m.def("return_class_1", []() -> BaseClass * { return new DerivedClass1(); });
|
| 161 |
+
m.def("return_class_2", []() -> BaseClass * { return new DerivedClass2(); });
|
| 162 |
+
m.def("return_class_n", [](int n) -> BaseClass * {
|
| 163 |
+
if (n == 1) {
|
| 164 |
+
return new DerivedClass1();
|
| 165 |
+
}
|
| 166 |
+
if (n == 2) {
|
| 167 |
+
return new DerivedClass2();
|
| 168 |
+
}
|
| 169 |
+
return new BaseClass();
|
| 170 |
+
});
|
| 171 |
+
m.def("return_none", []() -> BaseClass * { return nullptr; });
|
| 172 |
+
|
| 173 |
+
// test_isinstance
|
| 174 |
+
m.def("check_instances", [](const py::list &l) {
|
| 175 |
+
return py::make_tuple(py::isinstance<py::tuple>(l[0]),
|
| 176 |
+
py::isinstance<py::dict>(l[1]),
|
| 177 |
+
py::isinstance<Pet>(l[2]),
|
| 178 |
+
py::isinstance<Pet>(l[3]),
|
| 179 |
+
py::isinstance<Dog>(l[4]),
|
| 180 |
+
py::isinstance<Rabbit>(l[5]),
|
| 181 |
+
py::isinstance<UnregisteredType>(l[6]));
|
| 182 |
+
});
|
| 183 |
+
|
| 184 |
+
struct Invalid {};
|
| 185 |
+
|
| 186 |
+
// test_type
|
| 187 |
+
m.def("check_type", [](int category) {
|
| 188 |
+
// Currently not supported (via a fail at compile time)
|
| 189 |
+
// See https://github.com/pybind/pybind11/issues/2486
|
| 190 |
+
// if (category == 2)
|
| 191 |
+
// return py::type::of<int>();
|
| 192 |
+
if (category == 1) {
|
| 193 |
+
return py::type::of<DerivedClass1>();
|
| 194 |
+
}
|
| 195 |
+
return py::type::of<Invalid>();
|
| 196 |
+
});
|
| 197 |
+
|
| 198 |
+
m.def("get_type_of", [](py::object ob) { return py::type::of(std::move(ob)); });
|
| 199 |
+
|
| 200 |
+
m.def("get_type_classic", [](py::handle h) { return h.get_type(); });
|
| 201 |
+
|
| 202 |
+
m.def("as_type", [](const py::object &ob) { return py::type(ob); });
|
| 203 |
+
|
| 204 |
+
// test_mismatched_holder
|
| 205 |
+
struct MismatchBase1 {};
|
| 206 |
+
struct MismatchDerived1 : MismatchBase1 {};
|
| 207 |
+
|
| 208 |
+
struct MismatchBase2 {};
|
| 209 |
+
struct MismatchDerived2 : MismatchBase2 {};
|
| 210 |
+
|
| 211 |
+
m.def("mismatched_holder_1", []() {
|
| 212 |
+
auto mod = py::module_::import("__main__");
|
| 213 |
+
py::class_<MismatchBase1, std::shared_ptr<MismatchBase1>>(mod, "MismatchBase1");
|
| 214 |
+
py::class_<MismatchDerived1, MismatchBase1>(mod, "MismatchDerived1");
|
| 215 |
+
});
|
| 216 |
+
m.def("mismatched_holder_2", []() {
|
| 217 |
+
auto mod = py::module_::import("__main__");
|
| 218 |
+
py::class_<MismatchBase2>(mod, "MismatchBase2");
|
| 219 |
+
py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>, MismatchBase2>(
|
| 220 |
+
mod, "MismatchDerived2");
|
| 221 |
+
});
|
| 222 |
+
|
| 223 |
+
// test_override_static
|
| 224 |
+
// #511: problem with inheritance + overwritten def_static
|
| 225 |
+
struct MyBase {
|
| 226 |
+
static std::unique_ptr<MyBase> make() { return std::unique_ptr<MyBase>(new MyBase()); }
|
| 227 |
+
};
|
| 228 |
+
|
| 229 |
+
struct MyDerived : MyBase {
|
| 230 |
+
static std::unique_ptr<MyDerived> make() {
|
| 231 |
+
return std::unique_ptr<MyDerived>(new MyDerived());
|
| 232 |
+
}
|
| 233 |
+
};
|
| 234 |
+
|
| 235 |
+
py::class_<MyBase>(m, "MyBase").def_static("make", &MyBase::make);
|
| 236 |
+
|
| 237 |
+
py::class_<MyDerived, MyBase>(m, "MyDerived")
|
| 238 |
+
.def_static("make", &MyDerived::make)
|
| 239 |
+
.def_static("make2", &MyDerived::make);
|
| 240 |
+
|
| 241 |
+
// test_implicit_conversion_life_support
|
| 242 |
+
struct ConvertibleFromUserType {
|
| 243 |
+
int i;
|
| 244 |
+
|
| 245 |
+
explicit ConvertibleFromUserType(UserType u) : i(u.value()) {}
|
| 246 |
+
};
|
| 247 |
+
|
| 248 |
+
py::class_<ConvertibleFromUserType>(m, "AcceptsUserType").def(py::init<UserType>());
|
| 249 |
+
py::implicitly_convertible<UserType, ConvertibleFromUserType>();
|
| 250 |
+
|
| 251 |
+
m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; });
|
| 252 |
+
m.def("implicitly_convert_variable", [](const py::object &o) {
|
| 253 |
+
// `o` is `UserType` and `r` is a reference to a temporary created by implicit
|
| 254 |
+
// conversion. This is valid when called inside a bound function because the temp
|
| 255 |
+
// object is attached to the same life support system as the arguments.
|
| 256 |
+
const auto &r = o.cast<const ConvertibleFromUserType &>();
|
| 257 |
+
return r.i;
|
| 258 |
+
});
|
| 259 |
+
m.add_object("implicitly_convert_variable_fail", [&] {
|
| 260 |
+
auto f = [](PyObject *, PyObject *args) -> PyObject * {
|
| 261 |
+
auto o = py::reinterpret_borrow<py::tuple>(args)[0];
|
| 262 |
+
try { // It should fail here because there is no life support.
|
| 263 |
+
o.cast<const ConvertibleFromUserType &>();
|
| 264 |
+
} catch (const py::cast_error &e) {
|
| 265 |
+
return py::str(e.what()).release().ptr();
|
| 266 |
+
}
|
| 267 |
+
return py::str().release().ptr();
|
| 268 |
+
};
|
| 269 |
+
|
| 270 |
+
auto *def = new PyMethodDef{"f", f, METH_VARARGS, nullptr};
|
| 271 |
+
py::capsule def_capsule(def,
|
| 272 |
+
[](void *ptr) { delete reinterpret_cast<PyMethodDef *>(ptr); });
|
| 273 |
+
return py::reinterpret_steal<py::object>(
|
| 274 |
+
PyCFunction_NewEx(def, def_capsule.ptr(), m.ptr()));
|
| 275 |
+
}());
|
| 276 |
+
|
| 277 |
+
// test_operator_new_delete
|
| 278 |
+
struct HasOpNewDel {
|
| 279 |
+
std::uint64_t i;
|
| 280 |
+
static void *operator new(size_t s) {
|
| 281 |
+
py::print("A new", s);
|
| 282 |
+
return ::operator new(s);
|
| 283 |
+
}
|
| 284 |
+
static void *operator new(size_t s, void *ptr) {
|
| 285 |
+
py::print("A placement-new", s);
|
| 286 |
+
return ptr;
|
| 287 |
+
}
|
| 288 |
+
static void operator delete(void *p) {
|
| 289 |
+
py::print("A delete");
|
| 290 |
+
return ::operator delete(p);
|
| 291 |
+
}
|
| 292 |
+
};
|
| 293 |
+
struct HasOpNewDelSize {
|
| 294 |
+
std::uint32_t i;
|
| 295 |
+
static void *operator new(size_t s) {
|
| 296 |
+
py::print("B new", s);
|
| 297 |
+
return ::operator new(s);
|
| 298 |
+
}
|
| 299 |
+
static void *operator new(size_t s, void *ptr) {
|
| 300 |
+
py::print("B placement-new", s);
|
| 301 |
+
return ptr;
|
| 302 |
+
}
|
| 303 |
+
static void operator delete(void *p, size_t s) {
|
| 304 |
+
py::print("B delete", s);
|
| 305 |
+
return ::operator delete(p);
|
| 306 |
+
}
|
| 307 |
+
};
|
| 308 |
+
struct AliasedHasOpNewDelSize {
|
| 309 |
+
std::uint64_t i;
|
| 310 |
+
static void *operator new(size_t s) {
|
| 311 |
+
py::print("C new", s);
|
| 312 |
+
return ::operator new(s);
|
| 313 |
+
}
|
| 314 |
+
static void *operator new(size_t s, void *ptr) {
|
| 315 |
+
py::print("C placement-new", s);
|
| 316 |
+
return ptr;
|
| 317 |
+
}
|
| 318 |
+
static void operator delete(void *p, size_t s) {
|
| 319 |
+
py::print("C delete", s);
|
| 320 |
+
return ::operator delete(p);
|
| 321 |
+
}
|
| 322 |
+
virtual ~AliasedHasOpNewDelSize() = default;
|
| 323 |
+
AliasedHasOpNewDelSize() = default;
|
| 324 |
+
AliasedHasOpNewDelSize(const AliasedHasOpNewDelSize &) = delete;
|
| 325 |
+
};
|
| 326 |
+
struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize {
|
| 327 |
+
PyAliasedHasOpNewDelSize() = default;
|
| 328 |
+
explicit PyAliasedHasOpNewDelSize(int) {}
|
| 329 |
+
std::uint64_t j;
|
| 330 |
+
};
|
| 331 |
+
struct HasOpNewDelBoth {
|
| 332 |
+
std::uint32_t i[8];
|
| 333 |
+
static void *operator new(size_t s) {
|
| 334 |
+
py::print("D new", s);
|
| 335 |
+
return ::operator new(s);
|
| 336 |
+
}
|
| 337 |
+
static void *operator new(size_t s, void *ptr) {
|
| 338 |
+
py::print("D placement-new", s);
|
| 339 |
+
return ptr;
|
| 340 |
+
}
|
| 341 |
+
static void operator delete(void *p) {
|
| 342 |
+
py::print("D delete");
|
| 343 |
+
return ::operator delete(p);
|
| 344 |
+
}
|
| 345 |
+
static void operator delete(void *p, size_t s) {
|
| 346 |
+
py::print("D wrong delete", s);
|
| 347 |
+
return ::operator delete(p);
|
| 348 |
+
}
|
| 349 |
+
};
|
| 350 |
+
py::class_<HasOpNewDel>(m, "HasOpNewDel").def(py::init<>());
|
| 351 |
+
py::class_<HasOpNewDelSize>(m, "HasOpNewDelSize").def(py::init<>());
|
| 352 |
+
py::class_<HasOpNewDelBoth>(m, "HasOpNewDelBoth").def(py::init<>());
|
| 353 |
+
py::class_<AliasedHasOpNewDelSize, PyAliasedHasOpNewDelSize> aliased(m,
|
| 354 |
+
"AliasedHasOpNewDelSize");
|
| 355 |
+
aliased.def(py::init<>());
|
| 356 |
+
aliased.attr("size_noalias") = py::int_(sizeof(AliasedHasOpNewDelSize));
|
| 357 |
+
aliased.attr("size_alias") = py::int_(sizeof(PyAliasedHasOpNewDelSize));
|
| 358 |
+
|
| 359 |
+
// This test is actually part of test_local_bindings (test_duplicate_local), but we need a
|
| 360 |
+
// definition in a different compilation unit within the same module:
|
| 361 |
+
bind_local<LocalExternal, 17>(m, "LocalExternal", py::module_local());
|
| 362 |
+
|
| 363 |
+
// test_bind_protected_functions
|
| 364 |
+
class ProtectedA {
|
| 365 |
+
protected:
|
| 366 |
+
int foo() const { return value; }
|
| 367 |
+
|
| 368 |
+
private:
|
| 369 |
+
int value = 42;
|
| 370 |
+
};
|
| 371 |
+
|
| 372 |
+
class PublicistA : public ProtectedA {
|
| 373 |
+
public:
|
| 374 |
+
using ProtectedA::foo;
|
| 375 |
+
};
|
| 376 |
+
|
| 377 |
+
py::class_<ProtectedA>(m, "ProtectedA").def(py::init<>()).def("foo", &PublicistA::foo);
|
| 378 |
+
|
| 379 |
+
class ProtectedB {
|
| 380 |
+
public:
|
| 381 |
+
virtual ~ProtectedB() = default;
|
| 382 |
+
ProtectedB() = default;
|
| 383 |
+
ProtectedB(const ProtectedB &) = delete;
|
| 384 |
+
|
| 385 |
+
protected:
|
| 386 |
+
virtual int foo() const { return value; }
|
| 387 |
+
virtual void *void_foo() { return static_cast<void *>(&value); }
|
| 388 |
+
virtual void *get_self() { return static_cast<void *>(this); }
|
| 389 |
+
|
| 390 |
+
private:
|
| 391 |
+
int value = 42;
|
| 392 |
+
};
|
| 393 |
+
|
| 394 |
+
class TrampolineB : public ProtectedB {
|
| 395 |
+
public:
|
| 396 |
+
int foo() const override { PYBIND11_OVERRIDE(int, ProtectedB, foo, ); }
|
| 397 |
+
void *void_foo() override { PYBIND11_OVERRIDE(void *, ProtectedB, void_foo, ); }
|
| 398 |
+
void *get_self() override { PYBIND11_OVERRIDE(void *, ProtectedB, get_self, ); }
|
| 399 |
+
};
|
| 400 |
+
|
| 401 |
+
class PublicistB : public ProtectedB {
|
| 402 |
+
public:
|
| 403 |
+
// [workaround(intel)] = default does not work here
|
| 404 |
+
// Removing or defaulting this destructor results in linking errors with the Intel compiler
|
| 405 |
+
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
|
| 406 |
+
~PublicistB() override{}; // NOLINT(modernize-use-equals-default)
|
| 407 |
+
using ProtectedB::foo;
|
| 408 |
+
using ProtectedB::get_self;
|
| 409 |
+
using ProtectedB::void_foo;
|
| 410 |
+
};
|
| 411 |
+
|
| 412 |
+
m.def("read_foo", [](const void *original) {
|
| 413 |
+
const int *ptr = reinterpret_cast<const int *>(original);
|
| 414 |
+
return *ptr;
|
| 415 |
+
});
|
| 416 |
+
|
| 417 |
+
m.def("pointers_equal",
|
| 418 |
+
[](const void *original, const void *comparison) { return original == comparison; });
|
| 419 |
+
|
| 420 |
+
py::class_<ProtectedB, TrampolineB>(m, "ProtectedB")
|
| 421 |
+
.def(py::init<>())
|
| 422 |
+
.def("foo", &PublicistB::foo)
|
| 423 |
+
.def("void_foo", &PublicistB::void_foo)
|
| 424 |
+
.def("get_self", &PublicistB::get_self);
|
| 425 |
+
|
| 426 |
+
// test_brace_initialization
|
| 427 |
+
struct BraceInitialization {
|
| 428 |
+
int field1;
|
| 429 |
+
std::string field2;
|
| 430 |
+
};
|
| 431 |
+
|
| 432 |
+
py::class_<BraceInitialization>(m, "BraceInitialization")
|
| 433 |
+
.def(py::init<int, const std::string &>())
|
| 434 |
+
.def_readwrite("field1", &BraceInitialization::field1)
|
| 435 |
+
.def_readwrite("field2", &BraceInitialization::field2);
|
| 436 |
+
// We *don't* want to construct using braces when the given constructor argument maps to a
|
| 437 |
+
// constructor, because brace initialization could go to the wrong place (in particular when
|
| 438 |
+
// there is also an `initializer_list<T>`-accept constructor):
|
| 439 |
+
py::class_<NoBraceInitialization>(m, "NoBraceInitialization")
|
| 440 |
+
.def(py::init<std::vector<int>>())
|
| 441 |
+
.def_readonly("vec", &NoBraceInitialization::vec);
|
| 442 |
+
|
| 443 |
+
// test_reentrant_implicit_conversion_failure
|
| 444 |
+
// #1035: issue with runaway reentrant implicit conversion
|
| 445 |
+
struct BogusImplicitConversion {
|
| 446 |
+
BogusImplicitConversion(const BogusImplicitConversion &) = default;
|
| 447 |
+
};
|
| 448 |
+
|
| 449 |
+
py::class_<BogusImplicitConversion>(m, "BogusImplicitConversion")
|
| 450 |
+
.def(py::init<const BogusImplicitConversion &>());
|
| 451 |
+
|
| 452 |
+
py::implicitly_convertible<int, BogusImplicitConversion>();
|
| 453 |
+
|
| 454 |
+
// test_qualname
|
| 455 |
+
// #1166: nested class docstring doesn't show nested name
|
| 456 |
+
// Also related: tests that __qualname__ is set properly
|
| 457 |
+
struct NestBase {};
|
| 458 |
+
struct Nested {};
|
| 459 |
+
py::class_<NestBase> base(m, "NestBase");
|
| 460 |
+
base.def(py::init<>());
|
| 461 |
+
py::class_<Nested>(base, "Nested")
|
| 462 |
+
.def(py::init<>())
|
| 463 |
+
.def("fn", [](Nested &, int, NestBase &, Nested &) {})
|
| 464 |
+
.def(
|
| 465 |
+
"fa", [](Nested &, int, NestBase &, Nested &) {}, "a"_a, "b"_a, "c"_a);
|
| 466 |
+
base.def("g", [](NestBase &, Nested &) {});
|
| 467 |
+
base.def("h", []() { return NestBase(); });
|
| 468 |
+
|
| 469 |
+
// test_error_after_conversion
|
| 470 |
+
// The second-pass path through dispatcher() previously didn't
|
| 471 |
+
// remember which overload was used, and would crash trying to
|
| 472 |
+
// generate a useful error message
|
| 473 |
+
|
| 474 |
+
struct NotRegistered {};
|
| 475 |
+
struct StringWrapper {
|
| 476 |
+
std::string str;
|
| 477 |
+
};
|
| 478 |
+
m.def("test_error_after_conversions", [](int) {});
|
| 479 |
+
m.def("test_error_after_conversions",
|
| 480 |
+
[](const StringWrapper &) -> NotRegistered { return {}; });
|
| 481 |
+
py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>());
|
| 482 |
+
py::implicitly_convertible<std::string, StringWrapper>();
|
| 483 |
+
|
| 484 |
+
#if defined(PYBIND11_CPP17)
|
| 485 |
+
struct alignas(1024) Aligned {
|
| 486 |
+
std::uintptr_t ptr() const { return (uintptr_t) this; }
|
| 487 |
+
};
|
| 488 |
+
py::class_<Aligned>(m, "Aligned").def(py::init<>()).def("ptr", &Aligned::ptr);
|
| 489 |
+
#endif
|
| 490 |
+
|
| 491 |
+
// test_final
|
| 492 |
+
struct IsFinal final {};
|
| 493 |
+
py::class_<IsFinal>(m, "IsFinal", py::is_final());
|
| 494 |
+
|
| 495 |
+
// test_non_final_final
|
| 496 |
+
struct IsNonFinalFinal {};
|
| 497 |
+
py::class_<IsNonFinalFinal>(m, "IsNonFinalFinal", py::is_final());
|
| 498 |
+
|
| 499 |
+
// test_exception_rvalue_abort
|
| 500 |
+
struct PyPrintDestructor {
|
| 501 |
+
PyPrintDestructor() = default;
|
| 502 |
+
~PyPrintDestructor() { py::print("Print from destructor"); }
|
| 503 |
+
void throw_something() { throw std::runtime_error("error"); }
|
| 504 |
+
};
|
| 505 |
+
py::class_<PyPrintDestructor>(m, "PyPrintDestructor")
|
| 506 |
+
.def(py::init<>())
|
| 507 |
+
.def("throw_something", &PyPrintDestructor::throw_something);
|
| 508 |
+
|
| 509 |
+
// test_multiple_instances_with_same_pointer
|
| 510 |
+
struct SamePointer {};
|
| 511 |
+
static SamePointer samePointer;
|
| 512 |
+
py::class_<SamePointer, std::unique_ptr<SamePointer, py::nodelete>>(m, "SamePointer")
|
| 513 |
+
.def(py::init([]() { return &samePointer; }));
|
| 514 |
+
|
| 515 |
+
struct Empty {};
|
| 516 |
+
py::class_<Empty>(m, "Empty").def(py::init<>());
|
| 517 |
+
|
| 518 |
+
// test_base_and_derived_nested_scope
|
| 519 |
+
struct BaseWithNested {
|
| 520 |
+
struct Nested {};
|
| 521 |
+
};
|
| 522 |
+
|
| 523 |
+
struct DerivedWithNested : BaseWithNested {
|
| 524 |
+
struct Nested {};
|
| 525 |
+
};
|
| 526 |
+
|
| 527 |
+
py::class_<BaseWithNested> baseWithNested_class(m, "BaseWithNested");
|
| 528 |
+
py::class_<DerivedWithNested, BaseWithNested> derivedWithNested_class(m, "DerivedWithNested");
|
| 529 |
+
py::class_<BaseWithNested::Nested>(baseWithNested_class, "Nested")
|
| 530 |
+
.def_static("get_name", []() { return "BaseWithNested::Nested"; });
|
| 531 |
+
py::class_<DerivedWithNested::Nested>(derivedWithNested_class, "Nested")
|
| 532 |
+
.def_static("get_name", []() { return "DerivedWithNested::Nested"; });
|
| 533 |
+
|
| 534 |
+
// test_register_duplicate_class
|
| 535 |
+
struct Duplicate {};
|
| 536 |
+
struct OtherDuplicate {};
|
| 537 |
+
struct DuplicateNested {};
|
| 538 |
+
struct OtherDuplicateNested {};
|
| 539 |
+
|
| 540 |
+
m.def("register_duplicate_class_name", [](const py::module_ &m) {
|
| 541 |
+
py::class_<Duplicate>(m, "Duplicate");
|
| 542 |
+
py::class_<OtherDuplicate>(m, "Duplicate");
|
| 543 |
+
});
|
| 544 |
+
m.def("register_duplicate_class_type", [](const py::module_ &m) {
|
| 545 |
+
py::class_<OtherDuplicate>(m, "OtherDuplicate");
|
| 546 |
+
py::class_<OtherDuplicate>(m, "YetAnotherDuplicate");
|
| 547 |
+
});
|
| 548 |
+
m.def("register_duplicate_nested_class_name", [](const py::object >) {
|
| 549 |
+
py::class_<DuplicateNested>(gt, "DuplicateNested");
|
| 550 |
+
py::class_<OtherDuplicateNested>(gt, "DuplicateNested");
|
| 551 |
+
});
|
| 552 |
+
m.def("register_duplicate_nested_class_type", [](const py::object >) {
|
| 553 |
+
py::class_<OtherDuplicateNested>(gt, "OtherDuplicateNested");
|
| 554 |
+
py::class_<OtherDuplicateNested>(gt, "YetAnotherDuplicateNested");
|
| 555 |
+
});
|
| 556 |
+
|
| 557 |
+
test_class::pr4220_tripped_over_this::bind_empty0(m);
|
| 558 |
+
}
|
| 559 |
+
|
| 560 |
+
template <int N>
|
| 561 |
+
class BreaksBase {
|
| 562 |
+
public:
|
| 563 |
+
virtual ~BreaksBase() = default;
|
| 564 |
+
BreaksBase() = default;
|
| 565 |
+
BreaksBase(const BreaksBase &) = delete;
|
| 566 |
+
};
|
| 567 |
+
template <int N>
|
| 568 |
+
class BreaksTramp : public BreaksBase<N> {};
|
| 569 |
+
// These should all compile just fine:
|
| 570 |
+
using DoesntBreak1 = py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>>;
|
| 571 |
+
using DoesntBreak2 = py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>>;
|
| 572 |
+
using DoesntBreak3 = py::class_<BreaksBase<3>, std::unique_ptr<BreaksBase<3>>>;
|
| 573 |
+
using DoesntBreak4 = py::class_<BreaksBase<4>, BreaksTramp<4>>;
|
| 574 |
+
using DoesntBreak5 = py::class_<BreaksBase<5>>;
|
| 575 |
+
using DoesntBreak6 = py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>>;
|
| 576 |
+
using DoesntBreak7 = py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>>;
|
| 577 |
+
using DoesntBreak8 = py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>>;
|
| 578 |
+
#define CHECK_BASE(N) \
|
| 579 |
+
static_assert(std::is_same<typename DoesntBreak##N::type, BreaksBase<(N)>>::value, \
|
| 580 |
+
"DoesntBreak" #N " has wrong type!")
|
| 581 |
+
CHECK_BASE(1);
|
| 582 |
+
CHECK_BASE(2);
|
| 583 |
+
CHECK_BASE(3);
|
| 584 |
+
CHECK_BASE(4);
|
| 585 |
+
CHECK_BASE(5);
|
| 586 |
+
CHECK_BASE(6);
|
| 587 |
+
CHECK_BASE(7);
|
| 588 |
+
CHECK_BASE(8);
|
| 589 |
+
#define CHECK_ALIAS(N) \
|
| 590 |
+
static_assert( \
|
| 591 |
+
DoesntBreak##N::has_alias \
|
| 592 |
+
&& std::is_same<typename DoesntBreak##N::type_alias, BreaksTramp<(N)>>::value, \
|
| 593 |
+
"DoesntBreak" #N " has wrong type_alias!")
|
| 594 |
+
#define CHECK_NOALIAS(N) \
|
| 595 |
+
static_assert(!DoesntBreak##N::has_alias \
|
| 596 |
+
&& std::is_void<typename DoesntBreak##N::type_alias>::value, \
|
| 597 |
+
"DoesntBreak" #N " has type alias, but shouldn't!")
|
| 598 |
+
CHECK_ALIAS(1);
|
| 599 |
+
CHECK_ALIAS(2);
|
| 600 |
+
CHECK_NOALIAS(3);
|
| 601 |
+
CHECK_ALIAS(4);
|
| 602 |
+
CHECK_NOALIAS(5);
|
| 603 |
+
CHECK_ALIAS(6);
|
| 604 |
+
CHECK_ALIAS(7);
|
| 605 |
+
CHECK_NOALIAS(8);
|
| 606 |
+
#define CHECK_HOLDER(N, TYPE) \
|
| 607 |
+
static_assert(std::is_same<typename DoesntBreak##N::holder_type, \
|
| 608 |
+
std::TYPE##_ptr<BreaksBase<(N)>>>::value, \
|
| 609 |
+
"DoesntBreak" #N " has wrong holder_type!")
|
| 610 |
+
CHECK_HOLDER(1, unique);
|
| 611 |
+
CHECK_HOLDER(2, unique);
|
| 612 |
+
CHECK_HOLDER(3, unique);
|
| 613 |
+
CHECK_HOLDER(4, unique);
|
| 614 |
+
CHECK_HOLDER(5, unique);
|
| 615 |
+
CHECK_HOLDER(6, shared);
|
| 616 |
+
CHECK_HOLDER(7, shared);
|
| 617 |
+
CHECK_HOLDER(8, shared);
|
| 618 |
+
|
| 619 |
+
// There's no nice way to test that these fail because they fail to compile; leave them here,
|
| 620 |
+
// though, so that they can be manually tested by uncommenting them (and seeing that compilation
|
| 621 |
+
// failures occurs).
|
| 622 |
+
|
| 623 |
+
// We have to actually look into the type: the typedef alone isn't enough to instantiate the type:
|
| 624 |
+
#define CHECK_BROKEN(N) \
|
| 625 |
+
static_assert(std::is_same<typename Breaks##N::type, BreaksBase<-(N)>>::value, \
|
| 626 |
+
"Breaks1 has wrong type!");
|
| 627 |
+
|
| 628 |
+
#ifdef PYBIND11_NEVER_DEFINED_EVER
|
| 629 |
+
// Two holder classes:
|
| 630 |
+
typedef py::
|
| 631 |
+
class_<BreaksBase<-1>, std::unique_ptr<BreaksBase<-1>>, std::unique_ptr<BreaksBase<-1>>>
|
| 632 |
+
Breaks1;
|
| 633 |
+
CHECK_BROKEN(1);
|
| 634 |
+
// Two aliases:
|
| 635 |
+
typedef py::class_<BreaksBase<-2>, BreaksTramp<-2>, BreaksTramp<-2>> Breaks2;
|
| 636 |
+
CHECK_BROKEN(2);
|
| 637 |
+
// Holder + 2 aliases
|
| 638 |
+
typedef py::
|
| 639 |
+
class_<BreaksBase<-3>, std::unique_ptr<BreaksBase<-3>>, BreaksTramp<-3>, BreaksTramp<-3>>
|
| 640 |
+
Breaks3;
|
| 641 |
+
CHECK_BROKEN(3);
|
| 642 |
+
// Alias + 2 holders
|
| 643 |
+
typedef py::class_<BreaksBase<-4>,
|
| 644 |
+
std::unique_ptr<BreaksBase<-4>>,
|
| 645 |
+
BreaksTramp<-4>,
|
| 646 |
+
std::shared_ptr<BreaksBase<-4>>>
|
| 647 |
+
Breaks4;
|
| 648 |
+
CHECK_BROKEN(4);
|
| 649 |
+
// Invalid option (not a subclass or holder)
|
| 650 |
+
typedef py::class_<BreaksBase<-5>, BreaksTramp<-4>> Breaks5;
|
| 651 |
+
CHECK_BROKEN(5);
|
| 652 |
+
// Invalid option: multiple inheritance not supported:
|
| 653 |
+
template <>
|
| 654 |
+
struct BreaksBase<-8> : BreaksBase<-6>, BreaksBase<-7> {};
|
| 655 |
+
typedef py::class_<BreaksBase<-8>, BreaksBase<-6>, BreaksBase<-7>> Breaks8;
|
| 656 |
+
CHECK_BROKEN(8);
|
| 657 |
+
#endif
|
third_party/CityFlow/extern/pybind11/tests/test_class.py
CHANGED
|
@@ -1,499 +1,499 @@
|
|
| 1 |
-
from unittest import mock
|
| 2 |
-
|
| 3 |
-
import pytest
|
| 4 |
-
|
| 5 |
-
import env
|
| 6 |
-
from pybind11_tests import ConstructorStats, UserType
|
| 7 |
-
from pybind11_tests import class_ as m
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
def test_obj_class_name():
|
| 11 |
-
expected_name = "UserType" if env.PYPY else "pybind11_tests.UserType"
|
| 12 |
-
assert m.obj_class_name(UserType(1)) == expected_name
|
| 13 |
-
assert m.obj_class_name(UserType) == expected_name
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
def test_repr():
|
| 17 |
-
assert "pybind11_type" in repr(type(UserType))
|
| 18 |
-
assert "UserType" in repr(UserType)
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
def test_instance(msg):
|
| 22 |
-
with pytest.raises(TypeError) as excinfo:
|
| 23 |
-
m.NoConstructor()
|
| 24 |
-
assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!"
|
| 25 |
-
|
| 26 |
-
instance = m.NoConstructor.new_instance()
|
| 27 |
-
|
| 28 |
-
cstats = ConstructorStats.get(m.NoConstructor)
|
| 29 |
-
assert cstats.alive() == 1
|
| 30 |
-
del instance
|
| 31 |
-
assert cstats.alive() == 0
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
def test_instance_new():
|
| 35 |
-
instance = m.NoConstructorNew() # .__new__(m.NoConstructor.__class__)
|
| 36 |
-
cstats = ConstructorStats.get(m.NoConstructorNew)
|
| 37 |
-
assert cstats.alive() == 1
|
| 38 |
-
del instance
|
| 39 |
-
assert cstats.alive() == 0
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
def test_type():
|
| 43 |
-
assert m.check_type(1) == m.DerivedClass1
|
| 44 |
-
with pytest.raises(RuntimeError) as execinfo:
|
| 45 |
-
m.check_type(0)
|
| 46 |
-
|
| 47 |
-
assert "pybind11::detail::get_type_info: unable to find type info" in str(
|
| 48 |
-
execinfo.value
|
| 49 |
-
)
|
| 50 |
-
assert "Invalid" in str(execinfo.value)
|
| 51 |
-
|
| 52 |
-
# Currently not supported
|
| 53 |
-
# See https://github.com/pybind/pybind11/issues/2486
|
| 54 |
-
# assert m.check_type(2) == int
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
def test_type_of_py():
|
| 58 |
-
assert m.get_type_of(1) == int
|
| 59 |
-
assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
|
| 60 |
-
assert m.get_type_of(int) == type
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
def test_type_of_classic():
|
| 64 |
-
assert m.get_type_classic(1) == int
|
| 65 |
-
assert m.get_type_classic(m.DerivedClass1()) == m.DerivedClass1
|
| 66 |
-
assert m.get_type_classic(int) == type
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
def test_type_of_py_nodelete():
|
| 70 |
-
# If the above test deleted the class, this will segfault
|
| 71 |
-
assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
def test_as_type_py():
|
| 75 |
-
assert m.as_type(int) == int
|
| 76 |
-
|
| 77 |
-
with pytest.raises(TypeError):
|
| 78 |
-
assert m.as_type(1) == int
|
| 79 |
-
|
| 80 |
-
with pytest.raises(TypeError):
|
| 81 |
-
assert m.as_type(m.DerivedClass1()) == m.DerivedClass1
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
def test_docstrings(doc):
|
| 85 |
-
assert doc(UserType) == "A `py::class_` type for testing"
|
| 86 |
-
assert UserType.__name__ == "UserType"
|
| 87 |
-
assert UserType.__module__ == "pybind11_tests"
|
| 88 |
-
assert UserType.get_value.__name__ == "get_value"
|
| 89 |
-
assert UserType.get_value.__module__ == "pybind11_tests"
|
| 90 |
-
|
| 91 |
-
assert (
|
| 92 |
-
doc(UserType.get_value)
|
| 93 |
-
== """
|
| 94 |
-
get_value(self: m.UserType) -> int
|
| 95 |
-
|
| 96 |
-
Get value using a method
|
| 97 |
-
"""
|
| 98 |
-
)
|
| 99 |
-
assert doc(UserType.value) == "Get/set value using a property"
|
| 100 |
-
|
| 101 |
-
assert (
|
| 102 |
-
doc(m.NoConstructor.new_instance)
|
| 103 |
-
== """
|
| 104 |
-
new_instance() -> m.class_.NoConstructor
|
| 105 |
-
|
| 106 |
-
Return an instance
|
| 107 |
-
"""
|
| 108 |
-
)
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
def test_qualname(doc):
|
| 112 |
-
"""Tests that a properly qualified name is set in __qualname__ and that
|
| 113 |
-
generated docstrings properly use it and the module name"""
|
| 114 |
-
assert m.NestBase.__qualname__ == "NestBase"
|
| 115 |
-
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
|
| 116 |
-
|
| 117 |
-
assert (
|
| 118 |
-
doc(m.NestBase.__init__)
|
| 119 |
-
== """
|
| 120 |
-
__init__(self: m.class_.NestBase) -> None
|
| 121 |
-
"""
|
| 122 |
-
)
|
| 123 |
-
assert (
|
| 124 |
-
doc(m.NestBase.g)
|
| 125 |
-
== """
|
| 126 |
-
g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None
|
| 127 |
-
"""
|
| 128 |
-
)
|
| 129 |
-
assert (
|
| 130 |
-
doc(m.NestBase.Nested.__init__)
|
| 131 |
-
== """
|
| 132 |
-
__init__(self: m.class_.NestBase.Nested) -> None
|
| 133 |
-
"""
|
| 134 |
-
)
|
| 135 |
-
assert (
|
| 136 |
-
doc(m.NestBase.Nested.fn)
|
| 137 |
-
== """
|
| 138 |
-
fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
|
| 139 |
-
"""
|
| 140 |
-
)
|
| 141 |
-
assert (
|
| 142 |
-
doc(m.NestBase.Nested.fa)
|
| 143 |
-
== """
|
| 144 |
-
fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
|
| 145 |
-
"""
|
| 146 |
-
)
|
| 147 |
-
assert m.NestBase.__module__ == "pybind11_tests.class_"
|
| 148 |
-
assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
def test_inheritance(msg):
|
| 152 |
-
roger = m.Rabbit("Rabbit")
|
| 153 |
-
assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
|
| 154 |
-
assert m.pet_name_species(roger) == "Rabbit is a parrot"
|
| 155 |
-
|
| 156 |
-
polly = m.Pet("Polly", "parrot")
|
| 157 |
-
assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
|
| 158 |
-
assert m.pet_name_species(polly) == "Polly is a parrot"
|
| 159 |
-
|
| 160 |
-
molly = m.Dog("Molly")
|
| 161 |
-
assert molly.name() + " is a " + molly.species() == "Molly is a dog"
|
| 162 |
-
assert m.pet_name_species(molly) == "Molly is a dog"
|
| 163 |
-
|
| 164 |
-
fred = m.Hamster("Fred")
|
| 165 |
-
assert fred.name() + " is a " + fred.species() == "Fred is a rodent"
|
| 166 |
-
|
| 167 |
-
assert m.dog_bark(molly) == "Woof!"
|
| 168 |
-
|
| 169 |
-
with pytest.raises(TypeError) as excinfo:
|
| 170 |
-
m.dog_bark(polly)
|
| 171 |
-
assert (
|
| 172 |
-
msg(excinfo.value)
|
| 173 |
-
== """
|
| 174 |
-
dog_bark(): incompatible function arguments. The following argument types are supported:
|
| 175 |
-
1. (arg0: m.class_.Dog) -> str
|
| 176 |
-
|
| 177 |
-
Invoked with: <m.class_.Pet object at 0>
|
| 178 |
-
"""
|
| 179 |
-
)
|
| 180 |
-
|
| 181 |
-
with pytest.raises(TypeError) as excinfo:
|
| 182 |
-
m.Chimera("lion", "goat")
|
| 183 |
-
assert "No constructor defined!" in str(excinfo.value)
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
def test_inheritance_init(msg):
|
| 187 |
-
# Single base
|
| 188 |
-
class Python(m.Pet):
|
| 189 |
-
def __init__(self):
|
| 190 |
-
pass
|
| 191 |
-
|
| 192 |
-
with pytest.raises(TypeError) as exc_info:
|
| 193 |
-
Python()
|
| 194 |
-
expected = "m.class_.Pet.__init__() must be called when overriding __init__"
|
| 195 |
-
assert msg(exc_info.value) == expected
|
| 196 |
-
|
| 197 |
-
# Multiple bases
|
| 198 |
-
class RabbitHamster(m.Rabbit, m.Hamster):
|
| 199 |
-
def __init__(self):
|
| 200 |
-
m.Rabbit.__init__(self, "RabbitHamster")
|
| 201 |
-
|
| 202 |
-
with pytest.raises(TypeError) as exc_info:
|
| 203 |
-
RabbitHamster()
|
| 204 |
-
expected = "m.class_.Hamster.__init__() must be called when overriding __init__"
|
| 205 |
-
assert msg(exc_info.value) == expected
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
@pytest.mark.parametrize(
|
| 209 |
-
"mock_return_value", [None, (1, 2, 3), m.Pet("Polly", "parrot"), m.Dog("Molly")]
|
| 210 |
-
)
|
| 211 |
-
def test_mock_new(mock_return_value):
|
| 212 |
-
with mock.patch.object(
|
| 213 |
-
m.Pet, "__new__", return_value=mock_return_value
|
| 214 |
-
) as mock_new:
|
| 215 |
-
obj = m.Pet("Noname", "Nospecies")
|
| 216 |
-
assert obj is mock_return_value
|
| 217 |
-
mock_new.assert_called_once_with(m.Pet, "Noname", "Nospecies")
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
def test_automatic_upcasting():
|
| 221 |
-
assert type(m.return_class_1()).__name__ == "DerivedClass1"
|
| 222 |
-
assert type(m.return_class_2()).__name__ == "DerivedClass2"
|
| 223 |
-
assert type(m.return_none()).__name__ == "NoneType"
|
| 224 |
-
# Repeat these a few times in a random order to ensure no invalid caching is applied
|
| 225 |
-
assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
|
| 226 |
-
assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
|
| 227 |
-
assert type(m.return_class_n(0)).__name__ == "BaseClass"
|
| 228 |
-
assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
|
| 229 |
-
assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
|
| 230 |
-
assert type(m.return_class_n(0)).__name__ == "BaseClass"
|
| 231 |
-
assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
def test_isinstance():
|
| 235 |
-
objects = [(), {}, m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4
|
| 236 |
-
expected = (True, True, True, True, True, False, False)
|
| 237 |
-
assert m.check_instances(objects) == expected
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
def test_mismatched_holder():
|
| 241 |
-
import re
|
| 242 |
-
|
| 243 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 244 |
-
m.mismatched_holder_1()
|
| 245 |
-
assert re.match(
|
| 246 |
-
'generic_type: type ".*MismatchDerived1" does not have a non-default '
|
| 247 |
-
'holder type while its base ".*MismatchBase1" does',
|
| 248 |
-
str(excinfo.value),
|
| 249 |
-
)
|
| 250 |
-
|
| 251 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 252 |
-
m.mismatched_holder_2()
|
| 253 |
-
assert re.match(
|
| 254 |
-
'generic_type: type ".*MismatchDerived2" has a non-default holder type '
|
| 255 |
-
'while its base ".*MismatchBase2" does not',
|
| 256 |
-
str(excinfo.value),
|
| 257 |
-
)
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
def test_override_static():
|
| 261 |
-
"""#511: problem with inheritance + overwritten def_static"""
|
| 262 |
-
b = m.MyBase.make()
|
| 263 |
-
d1 = m.MyDerived.make2()
|
| 264 |
-
d2 = m.MyDerived.make()
|
| 265 |
-
|
| 266 |
-
assert isinstance(b, m.MyBase)
|
| 267 |
-
assert isinstance(d1, m.MyDerived)
|
| 268 |
-
assert isinstance(d2, m.MyDerived)
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
def test_implicit_conversion_life_support():
|
| 272 |
-
"""Ensure the lifetime of temporary objects created for implicit conversions"""
|
| 273 |
-
assert m.implicitly_convert_argument(UserType(5)) == 5
|
| 274 |
-
assert m.implicitly_convert_variable(UserType(5)) == 5
|
| 275 |
-
|
| 276 |
-
assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5))
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
def test_operator_new_delete(capture):
|
| 280 |
-
"""Tests that class-specific operator new/delete functions are invoked"""
|
| 281 |
-
|
| 282 |
-
class SubAliased(m.AliasedHasOpNewDelSize):
|
| 283 |
-
pass
|
| 284 |
-
|
| 285 |
-
with capture:
|
| 286 |
-
a = m.HasOpNewDel()
|
| 287 |
-
b = m.HasOpNewDelSize()
|
| 288 |
-
d = m.HasOpNewDelBoth()
|
| 289 |
-
assert (
|
| 290 |
-
capture
|
| 291 |
-
== """
|
| 292 |
-
A new 8
|
| 293 |
-
B new 4
|
| 294 |
-
D new 32
|
| 295 |
-
"""
|
| 296 |
-
)
|
| 297 |
-
sz_alias = str(m.AliasedHasOpNewDelSize.size_alias)
|
| 298 |
-
sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias)
|
| 299 |
-
with capture:
|
| 300 |
-
c = m.AliasedHasOpNewDelSize()
|
| 301 |
-
c2 = SubAliased()
|
| 302 |
-
assert capture == ("C new " + sz_noalias + "\n" + "C new " + sz_alias + "\n")
|
| 303 |
-
|
| 304 |
-
with capture:
|
| 305 |
-
del a
|
| 306 |
-
pytest.gc_collect()
|
| 307 |
-
del b
|
| 308 |
-
pytest.gc_collect()
|
| 309 |
-
del d
|
| 310 |
-
pytest.gc_collect()
|
| 311 |
-
assert (
|
| 312 |
-
capture
|
| 313 |
-
== """
|
| 314 |
-
A delete
|
| 315 |
-
B delete 4
|
| 316 |
-
D delete
|
| 317 |
-
"""
|
| 318 |
-
)
|
| 319 |
-
|
| 320 |
-
with capture:
|
| 321 |
-
del c
|
| 322 |
-
pytest.gc_collect()
|
| 323 |
-
del c2
|
| 324 |
-
pytest.gc_collect()
|
| 325 |
-
assert capture == ("C delete " + sz_noalias + "\n" + "C delete " + sz_alias + "\n")
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
def test_bind_protected_functions():
|
| 329 |
-
"""Expose protected member functions to Python using a helper class"""
|
| 330 |
-
a = m.ProtectedA()
|
| 331 |
-
assert a.foo() == 42
|
| 332 |
-
|
| 333 |
-
b = m.ProtectedB()
|
| 334 |
-
assert b.foo() == 42
|
| 335 |
-
assert m.read_foo(b.void_foo()) == 42
|
| 336 |
-
assert m.pointers_equal(b.get_self(), b)
|
| 337 |
-
|
| 338 |
-
class C(m.ProtectedB):
|
| 339 |
-
def __init__(self):
|
| 340 |
-
m.ProtectedB.__init__(self)
|
| 341 |
-
|
| 342 |
-
def foo(self):
|
| 343 |
-
return 0
|
| 344 |
-
|
| 345 |
-
c = C()
|
| 346 |
-
assert c.foo() == 0
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
def test_brace_initialization():
|
| 350 |
-
"""Tests that simple POD classes can be constructed using C++11 brace initialization"""
|
| 351 |
-
a = m.BraceInitialization(123, "test")
|
| 352 |
-
assert a.field1 == 123
|
| 353 |
-
assert a.field2 == "test"
|
| 354 |
-
|
| 355 |
-
# Tests that a non-simple class doesn't get brace initialization (if the
|
| 356 |
-
# class defines an initializer_list constructor, in particular, it would
|
| 357 |
-
# win over the expected constructor).
|
| 358 |
-
b = m.NoBraceInitialization([123, 456])
|
| 359 |
-
assert b.vec == [123, 456]
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
@pytest.mark.xfail("env.PYPY")
|
| 363 |
-
def test_class_refcount():
|
| 364 |
-
"""Instances must correctly increase/decrease the reference count of their types (#1029)"""
|
| 365 |
-
from sys import getrefcount
|
| 366 |
-
|
| 367 |
-
class PyDog(m.Dog):
|
| 368 |
-
pass
|
| 369 |
-
|
| 370 |
-
for cls in m.Dog, PyDog:
|
| 371 |
-
refcount_1 = getrefcount(cls)
|
| 372 |
-
molly = [cls("Molly") for _ in range(10)]
|
| 373 |
-
refcount_2 = getrefcount(cls)
|
| 374 |
-
|
| 375 |
-
del molly
|
| 376 |
-
pytest.gc_collect()
|
| 377 |
-
refcount_3 = getrefcount(cls)
|
| 378 |
-
|
| 379 |
-
assert refcount_1 == refcount_3
|
| 380 |
-
assert refcount_2 > refcount_1
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
def test_reentrant_implicit_conversion_failure(msg):
|
| 384 |
-
# ensure that there is no runaway reentrant implicit conversion (#1035)
|
| 385 |
-
with pytest.raises(TypeError) as excinfo:
|
| 386 |
-
m.BogusImplicitConversion(0)
|
| 387 |
-
assert (
|
| 388 |
-
msg(excinfo.value)
|
| 389 |
-
== """
|
| 390 |
-
__init__(): incompatible constructor arguments. The following argument types are supported:
|
| 391 |
-
1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
|
| 392 |
-
|
| 393 |
-
Invoked with: 0
|
| 394 |
-
"""
|
| 395 |
-
)
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
def test_error_after_conversions():
|
| 399 |
-
with pytest.raises(TypeError) as exc_info:
|
| 400 |
-
m.test_error_after_conversions("hello")
|
| 401 |
-
assert str(exc_info.value).startswith(
|
| 402 |
-
"Unable to convert function return value to a Python type!"
|
| 403 |
-
)
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
def test_aligned():
|
| 407 |
-
if hasattr(m, "Aligned"):
|
| 408 |
-
p = m.Aligned().ptr()
|
| 409 |
-
assert p % 1024 == 0
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
# https://foss.heptapod.net/pypy/pypy/-/issues/2742
|
| 413 |
-
@pytest.mark.xfail("env.PYPY")
|
| 414 |
-
def test_final():
|
| 415 |
-
with pytest.raises(TypeError) as exc_info:
|
| 416 |
-
|
| 417 |
-
class PyFinalChild(m.IsFinal):
|
| 418 |
-
pass
|
| 419 |
-
|
| 420 |
-
assert str(exc_info.value).endswith("is not an acceptable base type")
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
# https://foss.heptapod.net/pypy/pypy/-/issues/2742
|
| 424 |
-
@pytest.mark.xfail("env.PYPY")
|
| 425 |
-
def test_non_final_final():
|
| 426 |
-
with pytest.raises(TypeError) as exc_info:
|
| 427 |
-
|
| 428 |
-
class PyNonFinalFinalChild(m.IsNonFinalFinal):
|
| 429 |
-
pass
|
| 430 |
-
|
| 431 |
-
assert str(exc_info.value).endswith("is not an acceptable base type")
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
# https://github.com/pybind/pybind11/issues/1878
|
| 435 |
-
def test_exception_rvalue_abort():
|
| 436 |
-
with pytest.raises(RuntimeError):
|
| 437 |
-
m.PyPrintDestructor().throw_something()
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
# https://github.com/pybind/pybind11/issues/1568
|
| 441 |
-
def test_multiple_instances_with_same_pointer():
|
| 442 |
-
n = 100
|
| 443 |
-
instances = [m.SamePointer() for _ in range(n)]
|
| 444 |
-
for i in range(n):
|
| 445 |
-
# We need to reuse the same allocated memory for with a different type,
|
| 446 |
-
# to ensure the bug in `deregister_instance_impl` is detected. Otherwise
|
| 447 |
-
# `Py_TYPE(self) == Py_TYPE(it->second)` will still succeed, even though
|
| 448 |
-
# the `instance` is already deleted.
|
| 449 |
-
instances[i] = m.Empty()
|
| 450 |
-
# No assert: if this does not trigger the error
|
| 451 |
-
# pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
|
| 452 |
-
# and just completes without crashing, we're good.
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
# https://github.com/pybind/pybind11/issues/1624
|
| 456 |
-
def test_base_and_derived_nested_scope():
|
| 457 |
-
assert issubclass(m.DerivedWithNested, m.BaseWithNested)
|
| 458 |
-
assert m.BaseWithNested.Nested != m.DerivedWithNested.Nested
|
| 459 |
-
assert m.BaseWithNested.Nested.get_name() == "BaseWithNested::Nested"
|
| 460 |
-
assert m.DerivedWithNested.Nested.get_name() == "DerivedWithNested::Nested"
|
| 461 |
-
|
| 462 |
-
|
| 463 |
-
def test_register_duplicate_class():
|
| 464 |
-
import types
|
| 465 |
-
|
| 466 |
-
module_scope = types.ModuleType("module_scope")
|
| 467 |
-
with pytest.raises(RuntimeError) as exc_info:
|
| 468 |
-
m.register_duplicate_class_name(module_scope)
|
| 469 |
-
expected = (
|
| 470 |
-
'generic_type: cannot initialize type "Duplicate": '
|
| 471 |
-
"an object with that name is already defined"
|
| 472 |
-
)
|
| 473 |
-
assert str(exc_info.value) == expected
|
| 474 |
-
with pytest.raises(RuntimeError) as exc_info:
|
| 475 |
-
m.register_duplicate_class_type(module_scope)
|
| 476 |
-
expected = 'generic_type: type "YetAnotherDuplicate" is already registered!'
|
| 477 |
-
assert str(exc_info.value) == expected
|
| 478 |
-
|
| 479 |
-
class ClassScope:
|
| 480 |
-
pass
|
| 481 |
-
|
| 482 |
-
with pytest.raises(RuntimeError) as exc_info:
|
| 483 |
-
m.register_duplicate_nested_class_name(ClassScope)
|
| 484 |
-
expected = (
|
| 485 |
-
'generic_type: cannot initialize type "DuplicateNested": '
|
| 486 |
-
"an object with that name is already defined"
|
| 487 |
-
)
|
| 488 |
-
assert str(exc_info.value) == expected
|
| 489 |
-
with pytest.raises(RuntimeError) as exc_info:
|
| 490 |
-
m.register_duplicate_nested_class_type(ClassScope)
|
| 491 |
-
expected = 'generic_type: type "YetAnotherDuplicateNested" is already registered!'
|
| 492 |
-
assert str(exc_info.value) == expected
|
| 493 |
-
|
| 494 |
-
|
| 495 |
-
def test_pr4220_tripped_over_this():
|
| 496 |
-
assert (
|
| 497 |
-
m.Empty0().get_msg()
|
| 498 |
-
== "This is really only meant to exercise successful compilation."
|
| 499 |
-
)
|
|
|
|
| 1 |
+
from unittest import mock
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
import env
|
| 6 |
+
from pybind11_tests import ConstructorStats, UserType
|
| 7 |
+
from pybind11_tests import class_ as m
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def test_obj_class_name():
|
| 11 |
+
expected_name = "UserType" if env.PYPY else "pybind11_tests.UserType"
|
| 12 |
+
assert m.obj_class_name(UserType(1)) == expected_name
|
| 13 |
+
assert m.obj_class_name(UserType) == expected_name
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def test_repr():
|
| 17 |
+
assert "pybind11_type" in repr(type(UserType))
|
| 18 |
+
assert "UserType" in repr(UserType)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def test_instance(msg):
|
| 22 |
+
with pytest.raises(TypeError) as excinfo:
|
| 23 |
+
m.NoConstructor()
|
| 24 |
+
assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!"
|
| 25 |
+
|
| 26 |
+
instance = m.NoConstructor.new_instance()
|
| 27 |
+
|
| 28 |
+
cstats = ConstructorStats.get(m.NoConstructor)
|
| 29 |
+
assert cstats.alive() == 1
|
| 30 |
+
del instance
|
| 31 |
+
assert cstats.alive() == 0
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def test_instance_new():
|
| 35 |
+
instance = m.NoConstructorNew() # .__new__(m.NoConstructor.__class__)
|
| 36 |
+
cstats = ConstructorStats.get(m.NoConstructorNew)
|
| 37 |
+
assert cstats.alive() == 1
|
| 38 |
+
del instance
|
| 39 |
+
assert cstats.alive() == 0
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def test_type():
|
| 43 |
+
assert m.check_type(1) == m.DerivedClass1
|
| 44 |
+
with pytest.raises(RuntimeError) as execinfo:
|
| 45 |
+
m.check_type(0)
|
| 46 |
+
|
| 47 |
+
assert "pybind11::detail::get_type_info: unable to find type info" in str(
|
| 48 |
+
execinfo.value
|
| 49 |
+
)
|
| 50 |
+
assert "Invalid" in str(execinfo.value)
|
| 51 |
+
|
| 52 |
+
# Currently not supported
|
| 53 |
+
# See https://github.com/pybind/pybind11/issues/2486
|
| 54 |
+
# assert m.check_type(2) == int
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def test_type_of_py():
|
| 58 |
+
assert m.get_type_of(1) == int
|
| 59 |
+
assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
|
| 60 |
+
assert m.get_type_of(int) == type
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def test_type_of_classic():
|
| 64 |
+
assert m.get_type_classic(1) == int
|
| 65 |
+
assert m.get_type_classic(m.DerivedClass1()) == m.DerivedClass1
|
| 66 |
+
assert m.get_type_classic(int) == type
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def test_type_of_py_nodelete():
|
| 70 |
+
# If the above test deleted the class, this will segfault
|
| 71 |
+
assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def test_as_type_py():
|
| 75 |
+
assert m.as_type(int) == int
|
| 76 |
+
|
| 77 |
+
with pytest.raises(TypeError):
|
| 78 |
+
assert m.as_type(1) == int
|
| 79 |
+
|
| 80 |
+
with pytest.raises(TypeError):
|
| 81 |
+
assert m.as_type(m.DerivedClass1()) == m.DerivedClass1
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def test_docstrings(doc):
|
| 85 |
+
assert doc(UserType) == "A `py::class_` type for testing"
|
| 86 |
+
assert UserType.__name__ == "UserType"
|
| 87 |
+
assert UserType.__module__ == "pybind11_tests"
|
| 88 |
+
assert UserType.get_value.__name__ == "get_value"
|
| 89 |
+
assert UserType.get_value.__module__ == "pybind11_tests"
|
| 90 |
+
|
| 91 |
+
assert (
|
| 92 |
+
doc(UserType.get_value)
|
| 93 |
+
== """
|
| 94 |
+
get_value(self: m.UserType) -> int
|
| 95 |
+
|
| 96 |
+
Get value using a method
|
| 97 |
+
"""
|
| 98 |
+
)
|
| 99 |
+
assert doc(UserType.value) == "Get/set value using a property"
|
| 100 |
+
|
| 101 |
+
assert (
|
| 102 |
+
doc(m.NoConstructor.new_instance)
|
| 103 |
+
== """
|
| 104 |
+
new_instance() -> m.class_.NoConstructor
|
| 105 |
+
|
| 106 |
+
Return an instance
|
| 107 |
+
"""
|
| 108 |
+
)
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def test_qualname(doc):
|
| 112 |
+
"""Tests that a properly qualified name is set in __qualname__ and that
|
| 113 |
+
generated docstrings properly use it and the module name"""
|
| 114 |
+
assert m.NestBase.__qualname__ == "NestBase"
|
| 115 |
+
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
|
| 116 |
+
|
| 117 |
+
assert (
|
| 118 |
+
doc(m.NestBase.__init__)
|
| 119 |
+
== """
|
| 120 |
+
__init__(self: m.class_.NestBase) -> None
|
| 121 |
+
"""
|
| 122 |
+
)
|
| 123 |
+
assert (
|
| 124 |
+
doc(m.NestBase.g)
|
| 125 |
+
== """
|
| 126 |
+
g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None
|
| 127 |
+
"""
|
| 128 |
+
)
|
| 129 |
+
assert (
|
| 130 |
+
doc(m.NestBase.Nested.__init__)
|
| 131 |
+
== """
|
| 132 |
+
__init__(self: m.class_.NestBase.Nested) -> None
|
| 133 |
+
"""
|
| 134 |
+
)
|
| 135 |
+
assert (
|
| 136 |
+
doc(m.NestBase.Nested.fn)
|
| 137 |
+
== """
|
| 138 |
+
fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
|
| 139 |
+
"""
|
| 140 |
+
)
|
| 141 |
+
assert (
|
| 142 |
+
doc(m.NestBase.Nested.fa)
|
| 143 |
+
== """
|
| 144 |
+
fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
|
| 145 |
+
"""
|
| 146 |
+
)
|
| 147 |
+
assert m.NestBase.__module__ == "pybind11_tests.class_"
|
| 148 |
+
assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def test_inheritance(msg):
|
| 152 |
+
roger = m.Rabbit("Rabbit")
|
| 153 |
+
assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
|
| 154 |
+
assert m.pet_name_species(roger) == "Rabbit is a parrot"
|
| 155 |
+
|
| 156 |
+
polly = m.Pet("Polly", "parrot")
|
| 157 |
+
assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
|
| 158 |
+
assert m.pet_name_species(polly) == "Polly is a parrot"
|
| 159 |
+
|
| 160 |
+
molly = m.Dog("Molly")
|
| 161 |
+
assert molly.name() + " is a " + molly.species() == "Molly is a dog"
|
| 162 |
+
assert m.pet_name_species(molly) == "Molly is a dog"
|
| 163 |
+
|
| 164 |
+
fred = m.Hamster("Fred")
|
| 165 |
+
assert fred.name() + " is a " + fred.species() == "Fred is a rodent"
|
| 166 |
+
|
| 167 |
+
assert m.dog_bark(molly) == "Woof!"
|
| 168 |
+
|
| 169 |
+
with pytest.raises(TypeError) as excinfo:
|
| 170 |
+
m.dog_bark(polly)
|
| 171 |
+
assert (
|
| 172 |
+
msg(excinfo.value)
|
| 173 |
+
== """
|
| 174 |
+
dog_bark(): incompatible function arguments. The following argument types are supported:
|
| 175 |
+
1. (arg0: m.class_.Dog) -> str
|
| 176 |
+
|
| 177 |
+
Invoked with: <m.class_.Pet object at 0>
|
| 178 |
+
"""
|
| 179 |
+
)
|
| 180 |
+
|
| 181 |
+
with pytest.raises(TypeError) as excinfo:
|
| 182 |
+
m.Chimera("lion", "goat")
|
| 183 |
+
assert "No constructor defined!" in str(excinfo.value)
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
def test_inheritance_init(msg):
|
| 187 |
+
# Single base
|
| 188 |
+
class Python(m.Pet):
|
| 189 |
+
def __init__(self):
|
| 190 |
+
pass
|
| 191 |
+
|
| 192 |
+
with pytest.raises(TypeError) as exc_info:
|
| 193 |
+
Python()
|
| 194 |
+
expected = "m.class_.Pet.__init__() must be called when overriding __init__"
|
| 195 |
+
assert msg(exc_info.value) == expected
|
| 196 |
+
|
| 197 |
+
# Multiple bases
|
| 198 |
+
class RabbitHamster(m.Rabbit, m.Hamster):
|
| 199 |
+
def __init__(self):
|
| 200 |
+
m.Rabbit.__init__(self, "RabbitHamster")
|
| 201 |
+
|
| 202 |
+
with pytest.raises(TypeError) as exc_info:
|
| 203 |
+
RabbitHamster()
|
| 204 |
+
expected = "m.class_.Hamster.__init__() must be called when overriding __init__"
|
| 205 |
+
assert msg(exc_info.value) == expected
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
@pytest.mark.parametrize(
|
| 209 |
+
"mock_return_value", [None, (1, 2, 3), m.Pet("Polly", "parrot"), m.Dog("Molly")]
|
| 210 |
+
)
|
| 211 |
+
def test_mock_new(mock_return_value):
|
| 212 |
+
with mock.patch.object(
|
| 213 |
+
m.Pet, "__new__", return_value=mock_return_value
|
| 214 |
+
) as mock_new:
|
| 215 |
+
obj = m.Pet("Noname", "Nospecies")
|
| 216 |
+
assert obj is mock_return_value
|
| 217 |
+
mock_new.assert_called_once_with(m.Pet, "Noname", "Nospecies")
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
def test_automatic_upcasting():
|
| 221 |
+
assert type(m.return_class_1()).__name__ == "DerivedClass1"
|
| 222 |
+
assert type(m.return_class_2()).__name__ == "DerivedClass2"
|
| 223 |
+
assert type(m.return_none()).__name__ == "NoneType"
|
| 224 |
+
# Repeat these a few times in a random order to ensure no invalid caching is applied
|
| 225 |
+
assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
|
| 226 |
+
assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
|
| 227 |
+
assert type(m.return_class_n(0)).__name__ == "BaseClass"
|
| 228 |
+
assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
|
| 229 |
+
assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
|
| 230 |
+
assert type(m.return_class_n(0)).__name__ == "BaseClass"
|
| 231 |
+
assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
def test_isinstance():
|
| 235 |
+
objects = [(), {}, m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4
|
| 236 |
+
expected = (True, True, True, True, True, False, False)
|
| 237 |
+
assert m.check_instances(objects) == expected
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
def test_mismatched_holder():
|
| 241 |
+
import re
|
| 242 |
+
|
| 243 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 244 |
+
m.mismatched_holder_1()
|
| 245 |
+
assert re.match(
|
| 246 |
+
'generic_type: type ".*MismatchDerived1" does not have a non-default '
|
| 247 |
+
'holder type while its base ".*MismatchBase1" does',
|
| 248 |
+
str(excinfo.value),
|
| 249 |
+
)
|
| 250 |
+
|
| 251 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 252 |
+
m.mismatched_holder_2()
|
| 253 |
+
assert re.match(
|
| 254 |
+
'generic_type: type ".*MismatchDerived2" has a non-default holder type '
|
| 255 |
+
'while its base ".*MismatchBase2" does not',
|
| 256 |
+
str(excinfo.value),
|
| 257 |
+
)
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
def test_override_static():
|
| 261 |
+
"""#511: problem with inheritance + overwritten def_static"""
|
| 262 |
+
b = m.MyBase.make()
|
| 263 |
+
d1 = m.MyDerived.make2()
|
| 264 |
+
d2 = m.MyDerived.make()
|
| 265 |
+
|
| 266 |
+
assert isinstance(b, m.MyBase)
|
| 267 |
+
assert isinstance(d1, m.MyDerived)
|
| 268 |
+
assert isinstance(d2, m.MyDerived)
|
| 269 |
+
|
| 270 |
+
|
| 271 |
+
def test_implicit_conversion_life_support():
|
| 272 |
+
"""Ensure the lifetime of temporary objects created for implicit conversions"""
|
| 273 |
+
assert m.implicitly_convert_argument(UserType(5)) == 5
|
| 274 |
+
assert m.implicitly_convert_variable(UserType(5)) == 5
|
| 275 |
+
|
| 276 |
+
assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5))
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
def test_operator_new_delete(capture):
|
| 280 |
+
"""Tests that class-specific operator new/delete functions are invoked"""
|
| 281 |
+
|
| 282 |
+
class SubAliased(m.AliasedHasOpNewDelSize):
|
| 283 |
+
pass
|
| 284 |
+
|
| 285 |
+
with capture:
|
| 286 |
+
a = m.HasOpNewDel()
|
| 287 |
+
b = m.HasOpNewDelSize()
|
| 288 |
+
d = m.HasOpNewDelBoth()
|
| 289 |
+
assert (
|
| 290 |
+
capture
|
| 291 |
+
== """
|
| 292 |
+
A new 8
|
| 293 |
+
B new 4
|
| 294 |
+
D new 32
|
| 295 |
+
"""
|
| 296 |
+
)
|
| 297 |
+
sz_alias = str(m.AliasedHasOpNewDelSize.size_alias)
|
| 298 |
+
sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias)
|
| 299 |
+
with capture:
|
| 300 |
+
c = m.AliasedHasOpNewDelSize()
|
| 301 |
+
c2 = SubAliased()
|
| 302 |
+
assert capture == ("C new " + sz_noalias + "\n" + "C new " + sz_alias + "\n")
|
| 303 |
+
|
| 304 |
+
with capture:
|
| 305 |
+
del a
|
| 306 |
+
pytest.gc_collect()
|
| 307 |
+
del b
|
| 308 |
+
pytest.gc_collect()
|
| 309 |
+
del d
|
| 310 |
+
pytest.gc_collect()
|
| 311 |
+
assert (
|
| 312 |
+
capture
|
| 313 |
+
== """
|
| 314 |
+
A delete
|
| 315 |
+
B delete 4
|
| 316 |
+
D delete
|
| 317 |
+
"""
|
| 318 |
+
)
|
| 319 |
+
|
| 320 |
+
with capture:
|
| 321 |
+
del c
|
| 322 |
+
pytest.gc_collect()
|
| 323 |
+
del c2
|
| 324 |
+
pytest.gc_collect()
|
| 325 |
+
assert capture == ("C delete " + sz_noalias + "\n" + "C delete " + sz_alias + "\n")
|
| 326 |
+
|
| 327 |
+
|
| 328 |
+
def test_bind_protected_functions():
|
| 329 |
+
"""Expose protected member functions to Python using a helper class"""
|
| 330 |
+
a = m.ProtectedA()
|
| 331 |
+
assert a.foo() == 42
|
| 332 |
+
|
| 333 |
+
b = m.ProtectedB()
|
| 334 |
+
assert b.foo() == 42
|
| 335 |
+
assert m.read_foo(b.void_foo()) == 42
|
| 336 |
+
assert m.pointers_equal(b.get_self(), b)
|
| 337 |
+
|
| 338 |
+
class C(m.ProtectedB):
|
| 339 |
+
def __init__(self):
|
| 340 |
+
m.ProtectedB.__init__(self)
|
| 341 |
+
|
| 342 |
+
def foo(self):
|
| 343 |
+
return 0
|
| 344 |
+
|
| 345 |
+
c = C()
|
| 346 |
+
assert c.foo() == 0
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
def test_brace_initialization():
|
| 350 |
+
"""Tests that simple POD classes can be constructed using C++11 brace initialization"""
|
| 351 |
+
a = m.BraceInitialization(123, "test")
|
| 352 |
+
assert a.field1 == 123
|
| 353 |
+
assert a.field2 == "test"
|
| 354 |
+
|
| 355 |
+
# Tests that a non-simple class doesn't get brace initialization (if the
|
| 356 |
+
# class defines an initializer_list constructor, in particular, it would
|
| 357 |
+
# win over the expected constructor).
|
| 358 |
+
b = m.NoBraceInitialization([123, 456])
|
| 359 |
+
assert b.vec == [123, 456]
|
| 360 |
+
|
| 361 |
+
|
| 362 |
+
@pytest.mark.xfail("env.PYPY")
|
| 363 |
+
def test_class_refcount():
|
| 364 |
+
"""Instances must correctly increase/decrease the reference count of their types (#1029)"""
|
| 365 |
+
from sys import getrefcount
|
| 366 |
+
|
| 367 |
+
class PyDog(m.Dog):
|
| 368 |
+
pass
|
| 369 |
+
|
| 370 |
+
for cls in m.Dog, PyDog:
|
| 371 |
+
refcount_1 = getrefcount(cls)
|
| 372 |
+
molly = [cls("Molly") for _ in range(10)]
|
| 373 |
+
refcount_2 = getrefcount(cls)
|
| 374 |
+
|
| 375 |
+
del molly
|
| 376 |
+
pytest.gc_collect()
|
| 377 |
+
refcount_3 = getrefcount(cls)
|
| 378 |
+
|
| 379 |
+
assert refcount_1 == refcount_3
|
| 380 |
+
assert refcount_2 > refcount_1
|
| 381 |
+
|
| 382 |
+
|
| 383 |
+
def test_reentrant_implicit_conversion_failure(msg):
|
| 384 |
+
# ensure that there is no runaway reentrant implicit conversion (#1035)
|
| 385 |
+
with pytest.raises(TypeError) as excinfo:
|
| 386 |
+
m.BogusImplicitConversion(0)
|
| 387 |
+
assert (
|
| 388 |
+
msg(excinfo.value)
|
| 389 |
+
== """
|
| 390 |
+
__init__(): incompatible constructor arguments. The following argument types are supported:
|
| 391 |
+
1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
|
| 392 |
+
|
| 393 |
+
Invoked with: 0
|
| 394 |
+
"""
|
| 395 |
+
)
|
| 396 |
+
|
| 397 |
+
|
| 398 |
+
def test_error_after_conversions():
|
| 399 |
+
with pytest.raises(TypeError) as exc_info:
|
| 400 |
+
m.test_error_after_conversions("hello")
|
| 401 |
+
assert str(exc_info.value).startswith(
|
| 402 |
+
"Unable to convert function return value to a Python type!"
|
| 403 |
+
)
|
| 404 |
+
|
| 405 |
+
|
| 406 |
+
def test_aligned():
|
| 407 |
+
if hasattr(m, "Aligned"):
|
| 408 |
+
p = m.Aligned().ptr()
|
| 409 |
+
assert p % 1024 == 0
|
| 410 |
+
|
| 411 |
+
|
| 412 |
+
# https://foss.heptapod.net/pypy/pypy/-/issues/2742
|
| 413 |
+
@pytest.mark.xfail("env.PYPY")
|
| 414 |
+
def test_final():
|
| 415 |
+
with pytest.raises(TypeError) as exc_info:
|
| 416 |
+
|
| 417 |
+
class PyFinalChild(m.IsFinal):
|
| 418 |
+
pass
|
| 419 |
+
|
| 420 |
+
assert str(exc_info.value).endswith("is not an acceptable base type")
|
| 421 |
+
|
| 422 |
+
|
| 423 |
+
# https://foss.heptapod.net/pypy/pypy/-/issues/2742
|
| 424 |
+
@pytest.mark.xfail("env.PYPY")
|
| 425 |
+
def test_non_final_final():
|
| 426 |
+
with pytest.raises(TypeError) as exc_info:
|
| 427 |
+
|
| 428 |
+
class PyNonFinalFinalChild(m.IsNonFinalFinal):
|
| 429 |
+
pass
|
| 430 |
+
|
| 431 |
+
assert str(exc_info.value).endswith("is not an acceptable base type")
|
| 432 |
+
|
| 433 |
+
|
| 434 |
+
# https://github.com/pybind/pybind11/issues/1878
|
| 435 |
+
def test_exception_rvalue_abort():
|
| 436 |
+
with pytest.raises(RuntimeError):
|
| 437 |
+
m.PyPrintDestructor().throw_something()
|
| 438 |
+
|
| 439 |
+
|
| 440 |
+
# https://github.com/pybind/pybind11/issues/1568
|
| 441 |
+
def test_multiple_instances_with_same_pointer():
|
| 442 |
+
n = 100
|
| 443 |
+
instances = [m.SamePointer() for _ in range(n)]
|
| 444 |
+
for i in range(n):
|
| 445 |
+
# We need to reuse the same allocated memory for with a different type,
|
| 446 |
+
# to ensure the bug in `deregister_instance_impl` is detected. Otherwise
|
| 447 |
+
# `Py_TYPE(self) == Py_TYPE(it->second)` will still succeed, even though
|
| 448 |
+
# the `instance` is already deleted.
|
| 449 |
+
instances[i] = m.Empty()
|
| 450 |
+
# No assert: if this does not trigger the error
|
| 451 |
+
# pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
|
| 452 |
+
# and just completes without crashing, we're good.
|
| 453 |
+
|
| 454 |
+
|
| 455 |
+
# https://github.com/pybind/pybind11/issues/1624
|
| 456 |
+
def test_base_and_derived_nested_scope():
|
| 457 |
+
assert issubclass(m.DerivedWithNested, m.BaseWithNested)
|
| 458 |
+
assert m.BaseWithNested.Nested != m.DerivedWithNested.Nested
|
| 459 |
+
assert m.BaseWithNested.Nested.get_name() == "BaseWithNested::Nested"
|
| 460 |
+
assert m.DerivedWithNested.Nested.get_name() == "DerivedWithNested::Nested"
|
| 461 |
+
|
| 462 |
+
|
| 463 |
+
def test_register_duplicate_class():
|
| 464 |
+
import types
|
| 465 |
+
|
| 466 |
+
module_scope = types.ModuleType("module_scope")
|
| 467 |
+
with pytest.raises(RuntimeError) as exc_info:
|
| 468 |
+
m.register_duplicate_class_name(module_scope)
|
| 469 |
+
expected = (
|
| 470 |
+
'generic_type: cannot initialize type "Duplicate": '
|
| 471 |
+
"an object with that name is already defined"
|
| 472 |
+
)
|
| 473 |
+
assert str(exc_info.value) == expected
|
| 474 |
+
with pytest.raises(RuntimeError) as exc_info:
|
| 475 |
+
m.register_duplicate_class_type(module_scope)
|
| 476 |
+
expected = 'generic_type: type "YetAnotherDuplicate" is already registered!'
|
| 477 |
+
assert str(exc_info.value) == expected
|
| 478 |
+
|
| 479 |
+
class ClassScope:
|
| 480 |
+
pass
|
| 481 |
+
|
| 482 |
+
with pytest.raises(RuntimeError) as exc_info:
|
| 483 |
+
m.register_duplicate_nested_class_name(ClassScope)
|
| 484 |
+
expected = (
|
| 485 |
+
'generic_type: cannot initialize type "DuplicateNested": '
|
| 486 |
+
"an object with that name is already defined"
|
| 487 |
+
)
|
| 488 |
+
assert str(exc_info.value) == expected
|
| 489 |
+
with pytest.raises(RuntimeError) as exc_info:
|
| 490 |
+
m.register_duplicate_nested_class_type(ClassScope)
|
| 491 |
+
expected = 'generic_type: type "YetAnotherDuplicateNested" is already registered!'
|
| 492 |
+
assert str(exc_info.value) == expected
|
| 493 |
+
|
| 494 |
+
|
| 495 |
+
def test_pr4220_tripped_over_this():
|
| 496 |
+
assert (
|
| 497 |
+
m.Empty0().get_msg()
|
| 498 |
+
== "This is really only meant to exercise successful compilation."
|
| 499 |
+
)
|
third_party/CityFlow/extern/pybind11/tests/test_const_name.cpp
CHANGED
|
@@ -1,55 +1,55 @@
|
|
| 1 |
-
// Copyright (c) 2021 The Pybind Development Team.
|
| 2 |
-
// All rights reserved. Use of this source code is governed by a
|
| 3 |
-
// BSD-style license that can be found in the LICENSE file.
|
| 4 |
-
|
| 5 |
-
#include "pybind11_tests.h"
|
| 6 |
-
|
| 7 |
-
// IUT = Implementation Under Test
|
| 8 |
-
#define CONST_NAME_TESTS(TEST_FUNC, IUT) \
|
| 9 |
-
std::string TEST_FUNC(int selector) { \
|
| 10 |
-
switch (selector) { \
|
| 11 |
-
case 0: \
|
| 12 |
-
return IUT("").text; \
|
| 13 |
-
case 1: \
|
| 14 |
-
return IUT("A").text; \
|
| 15 |
-
case 2: \
|
| 16 |
-
return IUT("Bd").text; \
|
| 17 |
-
case 3: \
|
| 18 |
-
return IUT("Cef").text; \
|
| 19 |
-
case 4: \
|
| 20 |
-
return IUT<int>().text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
| 21 |
-
case 5: \
|
| 22 |
-
return IUT<std::string>().text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
| 23 |
-
case 6: \
|
| 24 |
-
return IUT<true>("T1", "T2").text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
| 25 |
-
case 7: \
|
| 26 |
-
return IUT<false>("U1", "U2").text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
| 27 |
-
case 8: \
|
| 28 |
-
/*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
|
| 29 |
-
return IUT<true>(IUT("D1"), IUT("D2")).text; \
|
| 30 |
-
case 9: \
|
| 31 |
-
/*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
|
| 32 |
-
return IUT<false>(IUT("E1"), IUT("E2")).text; \
|
| 33 |
-
case 10: \
|
| 34 |
-
return IUT("KeepAtEnd").text; \
|
| 35 |
-
default: \
|
| 36 |
-
break; \
|
| 37 |
-
} \
|
| 38 |
-
throw std::runtime_error("Invalid selector value."); \
|
| 39 |
-
}
|
| 40 |
-
|
| 41 |
-
CONST_NAME_TESTS(const_name_tests, py::detail::const_name)
|
| 42 |
-
|
| 43 |
-
#ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
|
| 44 |
-
CONST_NAME_TESTS(underscore_tests, py::detail::_)
|
| 45 |
-
#endif
|
| 46 |
-
|
| 47 |
-
TEST_SUBMODULE(const_name, m) {
|
| 48 |
-
m.def("const_name_tests", const_name_tests);
|
| 49 |
-
|
| 50 |
-
#if defined(PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY)
|
| 51 |
-
m.def("underscore_tests", underscore_tests);
|
| 52 |
-
#else
|
| 53 |
-
m.attr("underscore_tests") = "PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY not defined.";
|
| 54 |
-
#endif
|
| 55 |
-
}
|
|
|
|
| 1 |
+
// Copyright (c) 2021 The Pybind Development Team.
|
| 2 |
+
// All rights reserved. Use of this source code is governed by a
|
| 3 |
+
// BSD-style license that can be found in the LICENSE file.
|
| 4 |
+
|
| 5 |
+
#include "pybind11_tests.h"
|
| 6 |
+
|
| 7 |
+
// IUT = Implementation Under Test
|
| 8 |
+
#define CONST_NAME_TESTS(TEST_FUNC, IUT) \
|
| 9 |
+
std::string TEST_FUNC(int selector) { \
|
| 10 |
+
switch (selector) { \
|
| 11 |
+
case 0: \
|
| 12 |
+
return IUT("").text; \
|
| 13 |
+
case 1: \
|
| 14 |
+
return IUT("A").text; \
|
| 15 |
+
case 2: \
|
| 16 |
+
return IUT("Bd").text; \
|
| 17 |
+
case 3: \
|
| 18 |
+
return IUT("Cef").text; \
|
| 19 |
+
case 4: \
|
| 20 |
+
return IUT<int>().text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
| 21 |
+
case 5: \
|
| 22 |
+
return IUT<std::string>().text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
| 23 |
+
case 6: \
|
| 24 |
+
return IUT<true>("T1", "T2").text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
| 25 |
+
case 7: \
|
| 26 |
+
return IUT<false>("U1", "U2").text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
| 27 |
+
case 8: \
|
| 28 |
+
/*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
|
| 29 |
+
return IUT<true>(IUT("D1"), IUT("D2")).text; \
|
| 30 |
+
case 9: \
|
| 31 |
+
/*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
|
| 32 |
+
return IUT<false>(IUT("E1"), IUT("E2")).text; \
|
| 33 |
+
case 10: \
|
| 34 |
+
return IUT("KeepAtEnd").text; \
|
| 35 |
+
default: \
|
| 36 |
+
break; \
|
| 37 |
+
} \
|
| 38 |
+
throw std::runtime_error("Invalid selector value."); \
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
CONST_NAME_TESTS(const_name_tests, py::detail::const_name)
|
| 42 |
+
|
| 43 |
+
#ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
|
| 44 |
+
CONST_NAME_TESTS(underscore_tests, py::detail::_)
|
| 45 |
+
#endif
|
| 46 |
+
|
| 47 |
+
TEST_SUBMODULE(const_name, m) {
|
| 48 |
+
m.def("const_name_tests", const_name_tests);
|
| 49 |
+
|
| 50 |
+
#if defined(PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY)
|
| 51 |
+
m.def("underscore_tests", underscore_tests);
|
| 52 |
+
#else
|
| 53 |
+
m.attr("underscore_tests") = "PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY not defined.";
|
| 54 |
+
#endif
|
| 55 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_const_name.py
CHANGED
|
@@ -1,29 +1,29 @@
|
|
| 1 |
-
import pytest
|
| 2 |
-
|
| 3 |
-
from pybind11_tests import const_name as m
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
@pytest.mark.parametrize("func", [m.const_name_tests, m.underscore_tests])
|
| 7 |
-
@pytest.mark.parametrize(
|
| 8 |
-
("selector", "expected"),
|
| 9 |
-
enumerate(
|
| 10 |
-
(
|
| 11 |
-
"",
|
| 12 |
-
"A",
|
| 13 |
-
"Bd",
|
| 14 |
-
"Cef",
|
| 15 |
-
"%",
|
| 16 |
-
"%",
|
| 17 |
-
"T1",
|
| 18 |
-
"U2",
|
| 19 |
-
"D1",
|
| 20 |
-
"E2",
|
| 21 |
-
"KeepAtEnd",
|
| 22 |
-
)
|
| 23 |
-
),
|
| 24 |
-
)
|
| 25 |
-
def test_const_name(func, selector, expected):
|
| 26 |
-
if isinstance(func, str):
|
| 27 |
-
pytest.skip(func)
|
| 28 |
-
text = func(selector)
|
| 29 |
-
assert text == expected
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
from pybind11_tests import const_name as m
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
@pytest.mark.parametrize("func", [m.const_name_tests, m.underscore_tests])
|
| 7 |
+
@pytest.mark.parametrize(
|
| 8 |
+
("selector", "expected"),
|
| 9 |
+
enumerate(
|
| 10 |
+
(
|
| 11 |
+
"",
|
| 12 |
+
"A",
|
| 13 |
+
"Bd",
|
| 14 |
+
"Cef",
|
| 15 |
+
"%",
|
| 16 |
+
"%",
|
| 17 |
+
"T1",
|
| 18 |
+
"U2",
|
| 19 |
+
"D1",
|
| 20 |
+
"E2",
|
| 21 |
+
"KeepAtEnd",
|
| 22 |
+
)
|
| 23 |
+
),
|
| 24 |
+
)
|
| 25 |
+
def test_const_name(func, selector, expected):
|
| 26 |
+
if isinstance(func, str):
|
| 27 |
+
pytest.skip(func)
|
| 28 |
+
text = func(selector)
|
| 29 |
+
assert text == expected
|
third_party/CityFlow/extern/pybind11/tests/test_constants_and_functions.cpp
CHANGED
|
@@ -1,158 +1,158 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw
|
| 3 |
-
byte strings
|
| 4 |
-
|
| 5 |
-
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 6 |
-
|
| 7 |
-
All rights reserved. Use of this source code is governed by a
|
| 8 |
-
BSD-style license that can be found in the LICENSE file.
|
| 9 |
-
*/
|
| 10 |
-
|
| 11 |
-
#include "pybind11_tests.h"
|
| 12 |
-
|
| 13 |
-
enum MyEnum { EFirstEntry = 1, ESecondEntry };
|
| 14 |
-
|
| 15 |
-
std::string test_function1() { return "test_function()"; }
|
| 16 |
-
|
| 17 |
-
std::string test_function2(MyEnum k) { return "test_function(enum=" + std::to_string(k) + ")"; }
|
| 18 |
-
|
| 19 |
-
std::string test_function3(int i) { return "test_function(" + std::to_string(i) + ")"; }
|
| 20 |
-
|
| 21 |
-
py::str test_function4() { return "test_function()"; }
|
| 22 |
-
py::str test_function4(char *) { return "test_function(char *)"; }
|
| 23 |
-
py::str test_function4(int, float) { return "test_function(int, float)"; }
|
| 24 |
-
py::str test_function4(float, int) { return "test_function(float, int)"; }
|
| 25 |
-
|
| 26 |
-
py::bytes return_bytes() {
|
| 27 |
-
const char *data = "\x01\x00\x02\x00";
|
| 28 |
-
return std::string(data, 4);
|
| 29 |
-
}
|
| 30 |
-
|
| 31 |
-
std::string print_bytes(const py::bytes &bytes) {
|
| 32 |
-
std::string ret = "bytes[";
|
| 33 |
-
const auto value = static_cast<std::string>(bytes);
|
| 34 |
-
for (char c : value) {
|
| 35 |
-
ret += std::to_string(static_cast<int>(c)) + ' ';
|
| 36 |
-
}
|
| 37 |
-
ret.back() = ']';
|
| 38 |
-
return ret;
|
| 39 |
-
}
|
| 40 |
-
|
| 41 |
-
// Test that we properly handle C++17 exception specifiers (which are part of the function
|
| 42 |
-
// signature in C++17). These should all still work before C++17, but don't affect the function
|
| 43 |
-
// signature.
|
| 44 |
-
namespace test_exc_sp {
|
| 45 |
-
// [workaround(intel)] Unable to use noexcept instead of noexcept(true)
|
| 46 |
-
// Make the f1 test basically the same as the f2 test in C++17 mode for the Intel compiler as
|
| 47 |
-
// it fails to compile with a plain noexcept (tested with icc (ICC) 2021.1 Beta 20200827).
|
| 48 |
-
#if defined(__INTEL_COMPILER) && defined(PYBIND11_CPP17)
|
| 49 |
-
int f1(int x) noexcept(true) { return x + 1; }
|
| 50 |
-
#else
|
| 51 |
-
int f1(int x) noexcept { return x + 1; }
|
| 52 |
-
#endif
|
| 53 |
-
int f2(int x) noexcept(true) { return x + 2; }
|
| 54 |
-
int f3(int x) noexcept(false) { return x + 3; }
|
| 55 |
-
PYBIND11_WARNING_PUSH
|
| 56 |
-
PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated")
|
| 57 |
-
#if defined(__clang_major__) && __clang_major__ >= 5
|
| 58 |
-
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated-dynamic-exception-spec")
|
| 59 |
-
#else
|
| 60 |
-
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated")
|
| 61 |
-
#endif
|
| 62 |
-
// NOLINTNEXTLINE(modernize-use-noexcept)
|
| 63 |
-
int f4(int x) throw() { return x + 4; } // Deprecated equivalent to noexcept(true)
|
| 64 |
-
PYBIND11_WARNING_POP
|
| 65 |
-
struct C {
|
| 66 |
-
int m1(int x) noexcept { return x - 1; }
|
| 67 |
-
int m2(int x) const noexcept { return x - 2; }
|
| 68 |
-
int m3(int x) noexcept(true) { return x - 3; }
|
| 69 |
-
int m4(int x) const noexcept(true) { return x - 4; }
|
| 70 |
-
int m5(int x) noexcept(false) { return x - 5; }
|
| 71 |
-
int m6(int x) const noexcept(false) { return x - 6; }
|
| 72 |
-
PYBIND11_WARNING_PUSH
|
| 73 |
-
PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated")
|
| 74 |
-
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated")
|
| 75 |
-
// NOLINTNEXTLINE(modernize-use-noexcept)
|
| 76 |
-
int m7(int x) throw() { return x - 7; }
|
| 77 |
-
// NOLINTNEXTLINE(modernize-use-noexcept)
|
| 78 |
-
int m8(int x) const throw() { return x - 8; }
|
| 79 |
-
PYBIND11_WARNING_POP
|
| 80 |
-
};
|
| 81 |
-
} // namespace test_exc_sp
|
| 82 |
-
|
| 83 |
-
TEST_SUBMODULE(constants_and_functions, m) {
|
| 84 |
-
// test_constants
|
| 85 |
-
m.attr("some_constant") = py::int_(14);
|
| 86 |
-
|
| 87 |
-
// test_function_overloading
|
| 88 |
-
m.def("test_function", &test_function1);
|
| 89 |
-
m.def("test_function", &test_function2);
|
| 90 |
-
m.def("test_function", &test_function3);
|
| 91 |
-
|
| 92 |
-
#if defined(PYBIND11_OVERLOAD_CAST)
|
| 93 |
-
m.def("test_function", py::overload_cast<>(&test_function4));
|
| 94 |
-
m.def("test_function", py::overload_cast<char *>(&test_function4));
|
| 95 |
-
m.def("test_function", py::overload_cast<int, float>(&test_function4));
|
| 96 |
-
m.def("test_function", py::overload_cast<float, int>(&test_function4));
|
| 97 |
-
#else
|
| 98 |
-
m.def("test_function", static_cast<py::str (*)()>(&test_function4));
|
| 99 |
-
m.def("test_function", static_cast<py::str (*)(char *)>(&test_function4));
|
| 100 |
-
m.def("test_function", static_cast<py::str (*)(int, float)>(&test_function4));
|
| 101 |
-
m.def("test_function", static_cast<py::str (*)(float, int)>(&test_function4));
|
| 102 |
-
#endif
|
| 103 |
-
|
| 104 |
-
py::enum_<MyEnum>(m, "MyEnum")
|
| 105 |
-
.value("EFirstEntry", EFirstEntry)
|
| 106 |
-
.value("ESecondEntry", ESecondEntry)
|
| 107 |
-
.export_values();
|
| 108 |
-
|
| 109 |
-
// test_bytes
|
| 110 |
-
m.def("return_bytes", &return_bytes);
|
| 111 |
-
m.def("print_bytes", &print_bytes);
|
| 112 |
-
|
| 113 |
-
// test_exception_specifiers
|
| 114 |
-
using namespace test_exc_sp;
|
| 115 |
-
py::class_<C>(m, "C")
|
| 116 |
-
.def(py::init<>())
|
| 117 |
-
.def("m1", &C::m1)
|
| 118 |
-
.def("m2", &C::m2)
|
| 119 |
-
.def("m3", &C::m3)
|
| 120 |
-
.def("m4", &C::m4)
|
| 121 |
-
.def("m5", &C::m5)
|
| 122 |
-
.def("m6", &C::m6)
|
| 123 |
-
.def("m7", &C::m7)
|
| 124 |
-
.def("m8", &C::m8);
|
| 125 |
-
m.def("f1", f1);
|
| 126 |
-
m.def("f2", f2);
|
| 127 |
-
|
| 128 |
-
PYBIND11_WARNING_PUSH
|
| 129 |
-
PYBIND11_WARNING_DISABLE_INTEL(878) // incompatible exception specifications
|
| 130 |
-
m.def("f3", f3);
|
| 131 |
-
PYBIND11_WARNING_POP
|
| 132 |
-
|
| 133 |
-
m.def("f4", f4);
|
| 134 |
-
|
| 135 |
-
// test_function_record_leaks
|
| 136 |
-
m.def("register_large_capture_with_invalid_arguments", [](py::module_ m) {
|
| 137 |
-
// This should always be enough to trigger the alternative branch
|
| 138 |
-
// where `sizeof(capture) > sizeof(rec->data)`
|
| 139 |
-
uint64_t capture[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
| 140 |
-
#if defined(__GNUC__) && __GNUC__ == 4 // CentOS7
|
| 141 |
-
py::detail::silence_unused_warnings(capture);
|
| 142 |
-
#endif
|
| 143 |
-
m.def(
|
| 144 |
-
"should_raise", [capture](int) { return capture[9] + 33; }, py::kw_only(), py::arg());
|
| 145 |
-
});
|
| 146 |
-
m.def("register_with_raising_repr", [](py::module_ m, const py::object &default_value) {
|
| 147 |
-
m.def(
|
| 148 |
-
"should_raise",
|
| 149 |
-
[](int, int, const py::object &) { return 42; },
|
| 150 |
-
"some docstring",
|
| 151 |
-
py::arg_v("x", 42),
|
| 152 |
-
py::arg_v("y", 42, "<the answer>"),
|
| 153 |
-
py::arg_v("z", default_value));
|
| 154 |
-
});
|
| 155 |
-
|
| 156 |
-
// test noexcept(true) lambda (#4565)
|
| 157 |
-
m.def("l1", []() noexcept(true) { return 0; });
|
| 158 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw
|
| 3 |
+
byte strings
|
| 4 |
+
|
| 5 |
+
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 6 |
+
|
| 7 |
+
All rights reserved. Use of this source code is governed by a
|
| 8 |
+
BSD-style license that can be found in the LICENSE file.
|
| 9 |
+
*/
|
| 10 |
+
|
| 11 |
+
#include "pybind11_tests.h"
|
| 12 |
+
|
| 13 |
+
enum MyEnum { EFirstEntry = 1, ESecondEntry };
|
| 14 |
+
|
| 15 |
+
std::string test_function1() { return "test_function()"; }
|
| 16 |
+
|
| 17 |
+
std::string test_function2(MyEnum k) { return "test_function(enum=" + std::to_string(k) + ")"; }
|
| 18 |
+
|
| 19 |
+
std::string test_function3(int i) { return "test_function(" + std::to_string(i) + ")"; }
|
| 20 |
+
|
| 21 |
+
py::str test_function4() { return "test_function()"; }
|
| 22 |
+
py::str test_function4(char *) { return "test_function(char *)"; }
|
| 23 |
+
py::str test_function4(int, float) { return "test_function(int, float)"; }
|
| 24 |
+
py::str test_function4(float, int) { return "test_function(float, int)"; }
|
| 25 |
+
|
| 26 |
+
py::bytes return_bytes() {
|
| 27 |
+
const char *data = "\x01\x00\x02\x00";
|
| 28 |
+
return std::string(data, 4);
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
std::string print_bytes(const py::bytes &bytes) {
|
| 32 |
+
std::string ret = "bytes[";
|
| 33 |
+
const auto value = static_cast<std::string>(bytes);
|
| 34 |
+
for (char c : value) {
|
| 35 |
+
ret += std::to_string(static_cast<int>(c)) + ' ';
|
| 36 |
+
}
|
| 37 |
+
ret.back() = ']';
|
| 38 |
+
return ret;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
// Test that we properly handle C++17 exception specifiers (which are part of the function
|
| 42 |
+
// signature in C++17). These should all still work before C++17, but don't affect the function
|
| 43 |
+
// signature.
|
| 44 |
+
namespace test_exc_sp {
|
| 45 |
+
// [workaround(intel)] Unable to use noexcept instead of noexcept(true)
|
| 46 |
+
// Make the f1 test basically the same as the f2 test in C++17 mode for the Intel compiler as
|
| 47 |
+
// it fails to compile with a plain noexcept (tested with icc (ICC) 2021.1 Beta 20200827).
|
| 48 |
+
#if defined(__INTEL_COMPILER) && defined(PYBIND11_CPP17)
|
| 49 |
+
int f1(int x) noexcept(true) { return x + 1; }
|
| 50 |
+
#else
|
| 51 |
+
int f1(int x) noexcept { return x + 1; }
|
| 52 |
+
#endif
|
| 53 |
+
int f2(int x) noexcept(true) { return x + 2; }
|
| 54 |
+
int f3(int x) noexcept(false) { return x + 3; }
|
| 55 |
+
PYBIND11_WARNING_PUSH
|
| 56 |
+
PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated")
|
| 57 |
+
#if defined(__clang_major__) && __clang_major__ >= 5
|
| 58 |
+
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated-dynamic-exception-spec")
|
| 59 |
+
#else
|
| 60 |
+
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated")
|
| 61 |
+
#endif
|
| 62 |
+
// NOLINTNEXTLINE(modernize-use-noexcept)
|
| 63 |
+
int f4(int x) throw() { return x + 4; } // Deprecated equivalent to noexcept(true)
|
| 64 |
+
PYBIND11_WARNING_POP
|
| 65 |
+
struct C {
|
| 66 |
+
int m1(int x) noexcept { return x - 1; }
|
| 67 |
+
int m2(int x) const noexcept { return x - 2; }
|
| 68 |
+
int m3(int x) noexcept(true) { return x - 3; }
|
| 69 |
+
int m4(int x) const noexcept(true) { return x - 4; }
|
| 70 |
+
int m5(int x) noexcept(false) { return x - 5; }
|
| 71 |
+
int m6(int x) const noexcept(false) { return x - 6; }
|
| 72 |
+
PYBIND11_WARNING_PUSH
|
| 73 |
+
PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated")
|
| 74 |
+
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated")
|
| 75 |
+
// NOLINTNEXTLINE(modernize-use-noexcept)
|
| 76 |
+
int m7(int x) throw() { return x - 7; }
|
| 77 |
+
// NOLINTNEXTLINE(modernize-use-noexcept)
|
| 78 |
+
int m8(int x) const throw() { return x - 8; }
|
| 79 |
+
PYBIND11_WARNING_POP
|
| 80 |
+
};
|
| 81 |
+
} // namespace test_exc_sp
|
| 82 |
+
|
| 83 |
+
TEST_SUBMODULE(constants_and_functions, m) {
|
| 84 |
+
// test_constants
|
| 85 |
+
m.attr("some_constant") = py::int_(14);
|
| 86 |
+
|
| 87 |
+
// test_function_overloading
|
| 88 |
+
m.def("test_function", &test_function1);
|
| 89 |
+
m.def("test_function", &test_function2);
|
| 90 |
+
m.def("test_function", &test_function3);
|
| 91 |
+
|
| 92 |
+
#if defined(PYBIND11_OVERLOAD_CAST)
|
| 93 |
+
m.def("test_function", py::overload_cast<>(&test_function4));
|
| 94 |
+
m.def("test_function", py::overload_cast<char *>(&test_function4));
|
| 95 |
+
m.def("test_function", py::overload_cast<int, float>(&test_function4));
|
| 96 |
+
m.def("test_function", py::overload_cast<float, int>(&test_function4));
|
| 97 |
+
#else
|
| 98 |
+
m.def("test_function", static_cast<py::str (*)()>(&test_function4));
|
| 99 |
+
m.def("test_function", static_cast<py::str (*)(char *)>(&test_function4));
|
| 100 |
+
m.def("test_function", static_cast<py::str (*)(int, float)>(&test_function4));
|
| 101 |
+
m.def("test_function", static_cast<py::str (*)(float, int)>(&test_function4));
|
| 102 |
+
#endif
|
| 103 |
+
|
| 104 |
+
py::enum_<MyEnum>(m, "MyEnum")
|
| 105 |
+
.value("EFirstEntry", EFirstEntry)
|
| 106 |
+
.value("ESecondEntry", ESecondEntry)
|
| 107 |
+
.export_values();
|
| 108 |
+
|
| 109 |
+
// test_bytes
|
| 110 |
+
m.def("return_bytes", &return_bytes);
|
| 111 |
+
m.def("print_bytes", &print_bytes);
|
| 112 |
+
|
| 113 |
+
// test_exception_specifiers
|
| 114 |
+
using namespace test_exc_sp;
|
| 115 |
+
py::class_<C>(m, "C")
|
| 116 |
+
.def(py::init<>())
|
| 117 |
+
.def("m1", &C::m1)
|
| 118 |
+
.def("m2", &C::m2)
|
| 119 |
+
.def("m3", &C::m3)
|
| 120 |
+
.def("m4", &C::m4)
|
| 121 |
+
.def("m5", &C::m5)
|
| 122 |
+
.def("m6", &C::m6)
|
| 123 |
+
.def("m7", &C::m7)
|
| 124 |
+
.def("m8", &C::m8);
|
| 125 |
+
m.def("f1", f1);
|
| 126 |
+
m.def("f2", f2);
|
| 127 |
+
|
| 128 |
+
PYBIND11_WARNING_PUSH
|
| 129 |
+
PYBIND11_WARNING_DISABLE_INTEL(878) // incompatible exception specifications
|
| 130 |
+
m.def("f3", f3);
|
| 131 |
+
PYBIND11_WARNING_POP
|
| 132 |
+
|
| 133 |
+
m.def("f4", f4);
|
| 134 |
+
|
| 135 |
+
// test_function_record_leaks
|
| 136 |
+
m.def("register_large_capture_with_invalid_arguments", [](py::module_ m) {
|
| 137 |
+
// This should always be enough to trigger the alternative branch
|
| 138 |
+
// where `sizeof(capture) > sizeof(rec->data)`
|
| 139 |
+
uint64_t capture[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
| 140 |
+
#if defined(__GNUC__) && __GNUC__ == 4 // CentOS7
|
| 141 |
+
py::detail::silence_unused_warnings(capture);
|
| 142 |
+
#endif
|
| 143 |
+
m.def(
|
| 144 |
+
"should_raise", [capture](int) { return capture[9] + 33; }, py::kw_only(), py::arg());
|
| 145 |
+
});
|
| 146 |
+
m.def("register_with_raising_repr", [](py::module_ m, const py::object &default_value) {
|
| 147 |
+
m.def(
|
| 148 |
+
"should_raise",
|
| 149 |
+
[](int, int, const py::object &) { return 42; },
|
| 150 |
+
"some docstring",
|
| 151 |
+
py::arg_v("x", 42),
|
| 152 |
+
py::arg_v("y", 42, "<the answer>"),
|
| 153 |
+
py::arg_v("z", default_value));
|
| 154 |
+
});
|
| 155 |
+
|
| 156 |
+
// test noexcept(true) lambda (#4565)
|
| 157 |
+
m.def("l1", []() noexcept(true) { return 0; });
|
| 158 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_constants_and_functions.py
CHANGED
|
@@ -1,56 +1,56 @@
|
|
| 1 |
-
import pytest
|
| 2 |
-
|
| 3 |
-
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
def test_constants():
|
| 7 |
-
assert m.some_constant == 14
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
def test_function_overloading():
|
| 11 |
-
assert m.test_function() == "test_function()"
|
| 12 |
-
assert m.test_function(7) == "test_function(7)"
|
| 13 |
-
assert m.test_function(m.MyEnum.EFirstEntry) == "test_function(enum=1)"
|
| 14 |
-
assert m.test_function(m.MyEnum.ESecondEntry) == "test_function(enum=2)"
|
| 15 |
-
|
| 16 |
-
assert m.test_function() == "test_function()"
|
| 17 |
-
assert m.test_function("abcd") == "test_function(char *)"
|
| 18 |
-
assert m.test_function(1, 1.0) == "test_function(int, float)"
|
| 19 |
-
assert m.test_function(1, 1.0) == "test_function(int, float)"
|
| 20 |
-
assert m.test_function(2.0, 2) == "test_function(float, int)"
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
def test_bytes():
|
| 24 |
-
assert m.print_bytes(m.return_bytes()) == "bytes[1 0 2 0]"
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
def test_exception_specifiers():
|
| 28 |
-
c = m.C()
|
| 29 |
-
assert c.m1(2) == 1
|
| 30 |
-
assert c.m2(3) == 1
|
| 31 |
-
assert c.m3(5) == 2
|
| 32 |
-
assert c.m4(7) == 3
|
| 33 |
-
assert c.m5(10) == 5
|
| 34 |
-
assert c.m6(14) == 8
|
| 35 |
-
assert c.m7(20) == 13
|
| 36 |
-
assert c.m8(29) == 21
|
| 37 |
-
|
| 38 |
-
assert m.f1(33) == 34
|
| 39 |
-
assert m.f2(53) == 55
|
| 40 |
-
assert m.f3(86) == 89
|
| 41 |
-
assert m.f4(140) == 144
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
def test_function_record_leaks():
|
| 45 |
-
class RaisingRepr:
|
| 46 |
-
def __repr__(self):
|
| 47 |
-
raise RuntimeError("Surprise!")
|
| 48 |
-
|
| 49 |
-
with pytest.raises(RuntimeError):
|
| 50 |
-
m.register_large_capture_with_invalid_arguments(m)
|
| 51 |
-
with pytest.raises(RuntimeError):
|
| 52 |
-
m.register_with_raising_repr(m, RaisingRepr())
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
def test_noexcept_lambda():
|
| 56 |
-
assert m.l1() == 0
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def test_constants():
|
| 7 |
+
assert m.some_constant == 14
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def test_function_overloading():
|
| 11 |
+
assert m.test_function() == "test_function()"
|
| 12 |
+
assert m.test_function(7) == "test_function(7)"
|
| 13 |
+
assert m.test_function(m.MyEnum.EFirstEntry) == "test_function(enum=1)"
|
| 14 |
+
assert m.test_function(m.MyEnum.ESecondEntry) == "test_function(enum=2)"
|
| 15 |
+
|
| 16 |
+
assert m.test_function() == "test_function()"
|
| 17 |
+
assert m.test_function("abcd") == "test_function(char *)"
|
| 18 |
+
assert m.test_function(1, 1.0) == "test_function(int, float)"
|
| 19 |
+
assert m.test_function(1, 1.0) == "test_function(int, float)"
|
| 20 |
+
assert m.test_function(2.0, 2) == "test_function(float, int)"
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def test_bytes():
|
| 24 |
+
assert m.print_bytes(m.return_bytes()) == "bytes[1 0 2 0]"
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def test_exception_specifiers():
|
| 28 |
+
c = m.C()
|
| 29 |
+
assert c.m1(2) == 1
|
| 30 |
+
assert c.m2(3) == 1
|
| 31 |
+
assert c.m3(5) == 2
|
| 32 |
+
assert c.m4(7) == 3
|
| 33 |
+
assert c.m5(10) == 5
|
| 34 |
+
assert c.m6(14) == 8
|
| 35 |
+
assert c.m7(20) == 13
|
| 36 |
+
assert c.m8(29) == 21
|
| 37 |
+
|
| 38 |
+
assert m.f1(33) == 34
|
| 39 |
+
assert m.f2(53) == 55
|
| 40 |
+
assert m.f3(86) == 89
|
| 41 |
+
assert m.f4(140) == 144
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def test_function_record_leaks():
|
| 45 |
+
class RaisingRepr:
|
| 46 |
+
def __repr__(self):
|
| 47 |
+
raise RuntimeError("Surprise!")
|
| 48 |
+
|
| 49 |
+
with pytest.raises(RuntimeError):
|
| 50 |
+
m.register_large_capture_with_invalid_arguments(m)
|
| 51 |
+
with pytest.raises(RuntimeError):
|
| 52 |
+
m.register_with_raising_repr(m, RaisingRepr())
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def test_noexcept_lambda():
|
| 56 |
+
assert m.l1() == 0
|
third_party/CityFlow/extern/pybind11/tests/test_copy_move.cpp
CHANGED
|
@@ -1,533 +1,533 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_copy_move_policies.cpp -- 'copy' and 'move' return value policies
|
| 3 |
-
and related tests
|
| 4 |
-
|
| 5 |
-
Copyright (c) 2016 Ben North <ben@redfrontdoor.org>
|
| 6 |
-
|
| 7 |
-
All rights reserved. Use of this source code is governed by a
|
| 8 |
-
BSD-style license that can be found in the LICENSE file.
|
| 9 |
-
*/
|
| 10 |
-
|
| 11 |
-
#include <pybind11/stl.h>
|
| 12 |
-
|
| 13 |
-
#include "constructor_stats.h"
|
| 14 |
-
#include "pybind11_tests.h"
|
| 15 |
-
|
| 16 |
-
#include <type_traits>
|
| 17 |
-
|
| 18 |
-
template <typename derived>
|
| 19 |
-
struct empty {
|
| 20 |
-
static const derived &get_one() { return instance_; }
|
| 21 |
-
static derived instance_;
|
| 22 |
-
};
|
| 23 |
-
|
| 24 |
-
struct lacking_copy_ctor : public empty<lacking_copy_ctor> {
|
| 25 |
-
lacking_copy_ctor() = default;
|
| 26 |
-
lacking_copy_ctor(const lacking_copy_ctor &other) = delete;
|
| 27 |
-
};
|
| 28 |
-
|
| 29 |
-
template <>
|
| 30 |
-
lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {};
|
| 31 |
-
|
| 32 |
-
struct lacking_move_ctor : public empty<lacking_move_ctor> {
|
| 33 |
-
lacking_move_ctor() = default;
|
| 34 |
-
lacking_move_ctor(const lacking_move_ctor &other) = delete;
|
| 35 |
-
lacking_move_ctor(lacking_move_ctor &&other) = delete;
|
| 36 |
-
};
|
| 37 |
-
|
| 38 |
-
template <>
|
| 39 |
-
lacking_move_ctor empty<lacking_move_ctor>::instance_ = {};
|
| 40 |
-
|
| 41 |
-
/* Custom type caster move/copy test classes */
|
| 42 |
-
class MoveOnlyInt {
|
| 43 |
-
public:
|
| 44 |
-
MoveOnlyInt() { print_default_created(this); }
|
| 45 |
-
explicit MoveOnlyInt(int v) : value{v} { print_created(this, value); }
|
| 46 |
-
MoveOnlyInt(MoveOnlyInt &&m) noexcept {
|
| 47 |
-
print_move_created(this, m.value);
|
| 48 |
-
std::swap(value, m.value);
|
| 49 |
-
}
|
| 50 |
-
MoveOnlyInt &operator=(MoveOnlyInt &&m) noexcept {
|
| 51 |
-
print_move_assigned(this, m.value);
|
| 52 |
-
std::swap(value, m.value);
|
| 53 |
-
return *this;
|
| 54 |
-
}
|
| 55 |
-
MoveOnlyInt(const MoveOnlyInt &) = delete;
|
| 56 |
-
MoveOnlyInt &operator=(const MoveOnlyInt &) = delete;
|
| 57 |
-
~MoveOnlyInt() { print_destroyed(this); }
|
| 58 |
-
|
| 59 |
-
int value;
|
| 60 |
-
};
|
| 61 |
-
class MoveOrCopyInt {
|
| 62 |
-
public:
|
| 63 |
-
MoveOrCopyInt() { print_default_created(this); }
|
| 64 |
-
explicit MoveOrCopyInt(int v) : value{v} { print_created(this, value); }
|
| 65 |
-
MoveOrCopyInt(MoveOrCopyInt &&m) noexcept {
|
| 66 |
-
print_move_created(this, m.value);
|
| 67 |
-
std::swap(value, m.value);
|
| 68 |
-
}
|
| 69 |
-
MoveOrCopyInt &operator=(MoveOrCopyInt &&m) noexcept {
|
| 70 |
-
print_move_assigned(this, m.value);
|
| 71 |
-
std::swap(value, m.value);
|
| 72 |
-
return *this;
|
| 73 |
-
}
|
| 74 |
-
MoveOrCopyInt(const MoveOrCopyInt &c) {
|
| 75 |
-
print_copy_created(this, c.value);
|
| 76 |
-
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
| 77 |
-
value = c.value;
|
| 78 |
-
}
|
| 79 |
-
MoveOrCopyInt &operator=(const MoveOrCopyInt &c) {
|
| 80 |
-
print_copy_assigned(this, c.value);
|
| 81 |
-
value = c.value;
|
| 82 |
-
return *this;
|
| 83 |
-
}
|
| 84 |
-
~MoveOrCopyInt() { print_destroyed(this); }
|
| 85 |
-
|
| 86 |
-
int value;
|
| 87 |
-
};
|
| 88 |
-
class CopyOnlyInt {
|
| 89 |
-
public:
|
| 90 |
-
CopyOnlyInt() { print_default_created(this); }
|
| 91 |
-
explicit CopyOnlyInt(int v) : value{v} { print_created(this, value); }
|
| 92 |
-
CopyOnlyInt(const CopyOnlyInt &c) {
|
| 93 |
-
print_copy_created(this, c.value);
|
| 94 |
-
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
| 95 |
-
value = c.value;
|
| 96 |
-
}
|
| 97 |
-
CopyOnlyInt &operator=(const CopyOnlyInt &c) {
|
| 98 |
-
print_copy_assigned(this, c.value);
|
| 99 |
-
value = c.value;
|
| 100 |
-
return *this;
|
| 101 |
-
}
|
| 102 |
-
~CopyOnlyInt() { print_destroyed(this); }
|
| 103 |
-
|
| 104 |
-
int value;
|
| 105 |
-
};
|
| 106 |
-
PYBIND11_NAMESPACE_BEGIN(pybind11)
|
| 107 |
-
PYBIND11_NAMESPACE_BEGIN(detail)
|
| 108 |
-
template <>
|
| 109 |
-
struct type_caster<MoveOnlyInt> {
|
| 110 |
-
PYBIND11_TYPE_CASTER(MoveOnlyInt, const_name("MoveOnlyInt"));
|
| 111 |
-
bool load(handle src, bool) {
|
| 112 |
-
value = MoveOnlyInt(src.cast<int>());
|
| 113 |
-
return true;
|
| 114 |
-
}
|
| 115 |
-
static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) {
|
| 116 |
-
return pybind11::cast(m.value, r, p);
|
| 117 |
-
}
|
| 118 |
-
};
|
| 119 |
-
|
| 120 |
-
template <>
|
| 121 |
-
struct type_caster<MoveOrCopyInt> {
|
| 122 |
-
PYBIND11_TYPE_CASTER(MoveOrCopyInt, const_name("MoveOrCopyInt"));
|
| 123 |
-
bool load(handle src, bool) {
|
| 124 |
-
value = MoveOrCopyInt(src.cast<int>());
|
| 125 |
-
return true;
|
| 126 |
-
}
|
| 127 |
-
static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) {
|
| 128 |
-
return pybind11::cast(m.value, r, p);
|
| 129 |
-
}
|
| 130 |
-
};
|
| 131 |
-
|
| 132 |
-
template <>
|
| 133 |
-
struct type_caster<CopyOnlyInt> {
|
| 134 |
-
protected:
|
| 135 |
-
CopyOnlyInt value;
|
| 136 |
-
|
| 137 |
-
public:
|
| 138 |
-
static constexpr auto name = const_name("CopyOnlyInt");
|
| 139 |
-
bool load(handle src, bool) {
|
| 140 |
-
value = CopyOnlyInt(src.cast<int>());
|
| 141 |
-
return true;
|
| 142 |
-
}
|
| 143 |
-
static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) {
|
| 144 |
-
return pybind11::cast(m.value, r, p);
|
| 145 |
-
}
|
| 146 |
-
static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) {
|
| 147 |
-
if (!src) {
|
| 148 |
-
return none().release();
|
| 149 |
-
}
|
| 150 |
-
return cast(*src, policy, parent);
|
| 151 |
-
}
|
| 152 |
-
explicit operator CopyOnlyInt *() { return &value; }
|
| 153 |
-
explicit operator CopyOnlyInt &() { return value; }
|
| 154 |
-
template <typename T>
|
| 155 |
-
using cast_op_type = pybind11::detail::cast_op_type<T>;
|
| 156 |
-
};
|
| 157 |
-
PYBIND11_NAMESPACE_END(detail)
|
| 158 |
-
PYBIND11_NAMESPACE_END(pybind11)
|
| 159 |
-
|
| 160 |
-
TEST_SUBMODULE(copy_move_policies, m) {
|
| 161 |
-
// test_lacking_copy_ctor
|
| 162 |
-
py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
|
| 163 |
-
.def_static("get_one", &lacking_copy_ctor::get_one, py::return_value_policy::copy);
|
| 164 |
-
// test_lacking_move_ctor
|
| 165 |
-
py::class_<lacking_move_ctor>(m, "lacking_move_ctor")
|
| 166 |
-
.def_static("get_one", &lacking_move_ctor::get_one, py::return_value_policy::move);
|
| 167 |
-
|
| 168 |
-
// test_move_and_copy_casts
|
| 169 |
-
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 170 |
-
m.def("move_and_copy_casts", [](const py::object &o) {
|
| 171 |
-
int r = 0;
|
| 172 |
-
r += py::cast<MoveOrCopyInt>(o).value; /* moves */
|
| 173 |
-
r += py::cast<MoveOnlyInt>(o).value; /* moves */
|
| 174 |
-
r += py::cast<CopyOnlyInt>(o).value; /* copies */
|
| 175 |
-
auto m1(py::cast<MoveOrCopyInt>(o)); /* moves */
|
| 176 |
-
auto m2(py::cast<MoveOnlyInt>(o)); /* moves */
|
| 177 |
-
auto m3(py::cast<CopyOnlyInt>(o)); /* copies */
|
| 178 |
-
r += m1.value + m2.value + m3.value;
|
| 179 |
-
|
| 180 |
-
return r;
|
| 181 |
-
});
|
| 182 |
-
|
| 183 |
-
// test_move_and_copy_loads
|
| 184 |
-
m.def("move_only", [](MoveOnlyInt m) { return m.value; });
|
| 185 |
-
// Changing this breaks the existing test: needs careful review.
|
| 186 |
-
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 187 |
-
m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; });
|
| 188 |
-
// Changing this breaks the existing test: needs careful review.
|
| 189 |
-
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 190 |
-
m.def("copy_only", [](CopyOnlyInt m) { return m.value; });
|
| 191 |
-
m.def("move_pair",
|
| 192 |
-
[](std::pair<MoveOnlyInt, MoveOrCopyInt> p) { return p.first.value + p.second.value; });
|
| 193 |
-
m.def("move_tuple", [](std::tuple<MoveOnlyInt, MoveOrCopyInt, MoveOnlyInt> t) {
|
| 194 |
-
return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value;
|
| 195 |
-
});
|
| 196 |
-
m.def("copy_tuple", [](std::tuple<CopyOnlyInt, CopyOnlyInt> t) {
|
| 197 |
-
return std::get<0>(t).value + std::get<1>(t).value;
|
| 198 |
-
});
|
| 199 |
-
m.def("move_copy_nested",
|
| 200 |
-
[](std::pair<MoveOnlyInt,
|
| 201 |
-
std::pair<std::tuple<MoveOrCopyInt, CopyOnlyInt, std::tuple<MoveOnlyInt>>,
|
| 202 |
-
MoveOrCopyInt>> x) {
|
| 203 |
-
return x.first.value + std::get<0>(x.second.first).value
|
| 204 |
-
+ std::get<1>(x.second.first).value
|
| 205 |
-
+ std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value;
|
| 206 |
-
});
|
| 207 |
-
m.def("move_and_copy_cstats", []() {
|
| 208 |
-
ConstructorStats::gc();
|
| 209 |
-
// Reset counts to 0 so that previous tests don't affect later ones:
|
| 210 |
-
auto &mc = ConstructorStats::get<MoveOrCopyInt>();
|
| 211 |
-
mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions
|
| 212 |
-
= 0;
|
| 213 |
-
auto &mo = ConstructorStats::get<MoveOnlyInt>();
|
| 214 |
-
mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions
|
| 215 |
-
= 0;
|
| 216 |
-
auto &co = ConstructorStats::get<CopyOnlyInt>();
|
| 217 |
-
co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions
|
| 218 |
-
= 0;
|
| 219 |
-
py::dict d;
|
| 220 |
-
d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference);
|
| 221 |
-
d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference);
|
| 222 |
-
d["CopyOnlyInt"] = py::cast(co, py::return_value_policy::reference);
|
| 223 |
-
return d;
|
| 224 |
-
});
|
| 225 |
-
#ifdef PYBIND11_HAS_OPTIONAL
|
| 226 |
-
// test_move_and_copy_load_optional
|
| 227 |
-
m.attr("has_optional") = true;
|
| 228 |
-
m.def("move_optional", [](std::optional<MoveOnlyInt> o) { return o->value; });
|
| 229 |
-
m.def("move_or_copy_optional", [](std::optional<MoveOrCopyInt> o) { return o->value; });
|
| 230 |
-
m.def("copy_optional", [](std::optional<CopyOnlyInt> o) { return o->value; });
|
| 231 |
-
m.def("move_optional_tuple",
|
| 232 |
-
[](std::optional<std::tuple<MoveOrCopyInt, MoveOnlyInt, CopyOnlyInt>> x) {
|
| 233 |
-
return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value;
|
| 234 |
-
});
|
| 235 |
-
#else
|
| 236 |
-
m.attr("has_optional") = false;
|
| 237 |
-
#endif
|
| 238 |
-
|
| 239 |
-
// #70 compilation issue if operator new is not public - simple body added
|
| 240 |
-
// but not needed on most compilers; MSVC and nvcc don't like a local
|
| 241 |
-
// struct not having a method defined when declared, since it can not be
|
| 242 |
-
// added later.
|
| 243 |
-
struct PrivateOpNew {
|
| 244 |
-
int value = 1;
|
| 245 |
-
|
| 246 |
-
private:
|
| 247 |
-
void *operator new(size_t bytes) {
|
| 248 |
-
void *ptr = std::malloc(bytes);
|
| 249 |
-
if (ptr) {
|
| 250 |
-
return ptr;
|
| 251 |
-
}
|
| 252 |
-
throw std::bad_alloc{};
|
| 253 |
-
}
|
| 254 |
-
};
|
| 255 |
-
py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
|
| 256 |
-
m.def("private_op_new_value", []() { return PrivateOpNew(); });
|
| 257 |
-
m.def(
|
| 258 |
-
"private_op_new_reference",
|
| 259 |
-
[]() -> const PrivateOpNew & {
|
| 260 |
-
static PrivateOpNew x{};
|
| 261 |
-
return x;
|
| 262 |
-
},
|
| 263 |
-
py::return_value_policy::reference);
|
| 264 |
-
|
| 265 |
-
// test_move_fallback
|
| 266 |
-
// #389: rvp::move should fall-through to copy on non-movable objects
|
| 267 |
-
struct MoveIssue1 {
|
| 268 |
-
int v;
|
| 269 |
-
explicit MoveIssue1(int v) : v{v} {}
|
| 270 |
-
MoveIssue1(const MoveIssue1 &c) = default;
|
| 271 |
-
MoveIssue1(MoveIssue1 &&) = delete;
|
| 272 |
-
};
|
| 273 |
-
py::class_<MoveIssue1>(m, "MoveIssue1")
|
| 274 |
-
.def(py::init<int>())
|
| 275 |
-
.def_readwrite("value", &MoveIssue1::v);
|
| 276 |
-
|
| 277 |
-
struct MoveIssue2 {
|
| 278 |
-
int v;
|
| 279 |
-
explicit MoveIssue2(int v) : v{v} {}
|
| 280 |
-
MoveIssue2(MoveIssue2 &&) = default;
|
| 281 |
-
};
|
| 282 |
-
py::class_<MoveIssue2>(m, "MoveIssue2")
|
| 283 |
-
.def(py::init<int>())
|
| 284 |
-
.def_readwrite("value", &MoveIssue2::v);
|
| 285 |
-
|
| 286 |
-
// #2742: Don't expect ownership of raw pointer to `new`ed object to be transferred with
|
| 287 |
-
// `py::return_value_policy::move`
|
| 288 |
-
m.def(
|
| 289 |
-
"get_moveissue1",
|
| 290 |
-
[](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); },
|
| 291 |
-
py::return_value_policy::move);
|
| 292 |
-
m.def(
|
| 293 |
-
"get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
|
| 294 |
-
|
| 295 |
-
// Make sure that cast from pytype rvalue to other pytype works
|
| 296 |
-
m.def("get_pytype_rvalue_castissue", [](double i) { return py::float_(i).cast<py::int_>(); });
|
| 297 |
-
}
|
| 298 |
-
|
| 299 |
-
/*
|
| 300 |
-
* Rest of the file:
|
| 301 |
-
* static_assert based tests for pybind11 adaptations of
|
| 302 |
-
* std::is_move_constructible, std::is_copy_constructible and
|
| 303 |
-
* std::is_copy_assignable (no adaptation of std::is_move_assignable).
|
| 304 |
-
* Difference between pybind11 and std traits: pybind11 traits will also check
|
| 305 |
-
* the contained value_types.
|
| 306 |
-
*/
|
| 307 |
-
|
| 308 |
-
struct NotMovable {
|
| 309 |
-
NotMovable() = default;
|
| 310 |
-
NotMovable(NotMovable const &) = default;
|
| 311 |
-
NotMovable(NotMovable &&) = delete;
|
| 312 |
-
NotMovable &operator=(NotMovable const &) = default;
|
| 313 |
-
NotMovable &operator=(NotMovable &&) = delete;
|
| 314 |
-
};
|
| 315 |
-
static_assert(!std::is_move_constructible<NotMovable>::value,
|
| 316 |
-
"!std::is_move_constructible<NotMovable>::value");
|
| 317 |
-
static_assert(std::is_copy_constructible<NotMovable>::value,
|
| 318 |
-
"std::is_copy_constructible<NotMovable>::value");
|
| 319 |
-
static_assert(!pybind11::detail::is_move_constructible<NotMovable>::value,
|
| 320 |
-
"!pybind11::detail::is_move_constructible<NotMovable>::value");
|
| 321 |
-
static_assert(pybind11::detail::is_copy_constructible<NotMovable>::value,
|
| 322 |
-
"pybind11::detail::is_copy_constructible<NotMovable>::value");
|
| 323 |
-
static_assert(!std::is_move_assignable<NotMovable>::value,
|
| 324 |
-
"!std::is_move_assignable<NotMovable>::value");
|
| 325 |
-
static_assert(std::is_copy_assignable<NotMovable>::value,
|
| 326 |
-
"std::is_copy_assignable<NotMovable>::value");
|
| 327 |
-
// pybind11 does not have this
|
| 328 |
-
// static_assert(!pybind11::detail::is_move_assignable<NotMovable>::value,
|
| 329 |
-
// "!pybind11::detail::is_move_assignable<NotMovable>::value");
|
| 330 |
-
static_assert(pybind11::detail::is_copy_assignable<NotMovable>::value,
|
| 331 |
-
"pybind11::detail::is_copy_assignable<NotMovable>::value");
|
| 332 |
-
|
| 333 |
-
struct NotCopyable {
|
| 334 |
-
NotCopyable() = default;
|
| 335 |
-
NotCopyable(NotCopyable const &) = delete;
|
| 336 |
-
NotCopyable(NotCopyable &&) = default;
|
| 337 |
-
NotCopyable &operator=(NotCopyable const &) = delete;
|
| 338 |
-
NotCopyable &operator=(NotCopyable &&) = default;
|
| 339 |
-
};
|
| 340 |
-
static_assert(std::is_move_constructible<NotCopyable>::value,
|
| 341 |
-
"std::is_move_constructible<NotCopyable>::value");
|
| 342 |
-
static_assert(!std::is_copy_constructible<NotCopyable>::value,
|
| 343 |
-
"!std::is_copy_constructible<NotCopyable>::value");
|
| 344 |
-
static_assert(pybind11::detail::is_move_constructible<NotCopyable>::value,
|
| 345 |
-
"pybind11::detail::is_move_constructible<NotCopyable>::value");
|
| 346 |
-
static_assert(!pybind11::detail::is_copy_constructible<NotCopyable>::value,
|
| 347 |
-
"!pybind11::detail::is_copy_constructible<NotCopyable>::value");
|
| 348 |
-
static_assert(std::is_move_assignable<NotCopyable>::value,
|
| 349 |
-
"std::is_move_assignable<NotCopyable>::value");
|
| 350 |
-
static_assert(!std::is_copy_assignable<NotCopyable>::value,
|
| 351 |
-
"!std::is_copy_assignable<NotCopyable>::value");
|
| 352 |
-
// pybind11 does not have this
|
| 353 |
-
// static_assert(!pybind11::detail::is_move_assignable<NotCopyable>::value,
|
| 354 |
-
// "!pybind11::detail::is_move_assignable<NotCopyable>::value");
|
| 355 |
-
static_assert(!pybind11::detail::is_copy_assignable<NotCopyable>::value,
|
| 356 |
-
"!pybind11::detail::is_copy_assignable<NotCopyable>::value");
|
| 357 |
-
|
| 358 |
-
struct NotCopyableNotMovable {
|
| 359 |
-
NotCopyableNotMovable() = default;
|
| 360 |
-
NotCopyableNotMovable(NotCopyableNotMovable const &) = delete;
|
| 361 |
-
NotCopyableNotMovable(NotCopyableNotMovable &&) = delete;
|
| 362 |
-
NotCopyableNotMovable &operator=(NotCopyableNotMovable const &) = delete;
|
| 363 |
-
NotCopyableNotMovable &operator=(NotCopyableNotMovable &&) = delete;
|
| 364 |
-
};
|
| 365 |
-
static_assert(!std::is_move_constructible<NotCopyableNotMovable>::value,
|
| 366 |
-
"!std::is_move_constructible<NotCopyableNotMovable>::value");
|
| 367 |
-
static_assert(!std::is_copy_constructible<NotCopyableNotMovable>::value,
|
| 368 |
-
"!std::is_copy_constructible<NotCopyableNotMovable>::value");
|
| 369 |
-
static_assert(!pybind11::detail::is_move_constructible<NotCopyableNotMovable>::value,
|
| 370 |
-
"!pybind11::detail::is_move_constructible<NotCopyableNotMovable>::value");
|
| 371 |
-
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableNotMovable>::value,
|
| 372 |
-
"!pybind11::detail::is_copy_constructible<NotCopyableNotMovable>::value");
|
| 373 |
-
static_assert(!std::is_move_assignable<NotCopyableNotMovable>::value,
|
| 374 |
-
"!std::is_move_assignable<NotCopyableNotMovable>::value");
|
| 375 |
-
static_assert(!std::is_copy_assignable<NotCopyableNotMovable>::value,
|
| 376 |
-
"!std::is_copy_assignable<NotCopyableNotMovable>::value");
|
| 377 |
-
// pybind11 does not have this
|
| 378 |
-
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableNotMovable>::value,
|
| 379 |
-
// "!pybind11::detail::is_move_assignable<NotCopyableNotMovable>::value");
|
| 380 |
-
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableNotMovable>::value,
|
| 381 |
-
"!pybind11::detail::is_copy_assignable<NotCopyableNotMovable>::value");
|
| 382 |
-
|
| 383 |
-
struct NotMovableVector : std::vector<NotMovable> {};
|
| 384 |
-
static_assert(std::is_move_constructible<NotMovableVector>::value,
|
| 385 |
-
"std::is_move_constructible<NotMovableVector>::value");
|
| 386 |
-
static_assert(std::is_copy_constructible<NotMovableVector>::value,
|
| 387 |
-
"std::is_copy_constructible<NotMovableVector>::value");
|
| 388 |
-
static_assert(!pybind11::detail::is_move_constructible<NotMovableVector>::value,
|
| 389 |
-
"!pybind11::detail::is_move_constructible<NotMovableVector>::value");
|
| 390 |
-
static_assert(pybind11::detail::is_copy_constructible<NotMovableVector>::value,
|
| 391 |
-
"pybind11::detail::is_copy_constructible<NotMovableVector>::value");
|
| 392 |
-
static_assert(std::is_move_assignable<NotMovableVector>::value,
|
| 393 |
-
"std::is_move_assignable<NotMovableVector>::value");
|
| 394 |
-
static_assert(std::is_copy_assignable<NotMovableVector>::value,
|
| 395 |
-
"std::is_copy_assignable<NotMovableVector>::value");
|
| 396 |
-
// pybind11 does not have this
|
| 397 |
-
// static_assert(!pybind11::detail::is_move_assignable<NotMovableVector>::value,
|
| 398 |
-
// "!pybind11::detail::is_move_assignable<NotMovableVector>::value");
|
| 399 |
-
static_assert(pybind11::detail::is_copy_assignable<NotMovableVector>::value,
|
| 400 |
-
"pybind11::detail::is_copy_assignable<NotMovableVector>::value");
|
| 401 |
-
|
| 402 |
-
struct NotCopyableVector : std::vector<NotCopyable> {};
|
| 403 |
-
static_assert(std::is_move_constructible<NotCopyableVector>::value,
|
| 404 |
-
"std::is_move_constructible<NotCopyableVector>::value");
|
| 405 |
-
static_assert(std::is_copy_constructible<NotCopyableVector>::value,
|
| 406 |
-
"std::is_copy_constructible<NotCopyableVector>::value");
|
| 407 |
-
static_assert(pybind11::detail::is_move_constructible<NotCopyableVector>::value,
|
| 408 |
-
"pybind11::detail::is_move_constructible<NotCopyableVector>::value");
|
| 409 |
-
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableVector>::value,
|
| 410 |
-
"!pybind11::detail::is_copy_constructible<NotCopyableVector>::value");
|
| 411 |
-
static_assert(std::is_move_assignable<NotCopyableVector>::value,
|
| 412 |
-
"std::is_move_assignable<NotCopyableVector>::value");
|
| 413 |
-
static_assert(std::is_copy_assignable<NotCopyableVector>::value,
|
| 414 |
-
"std::is_copy_assignable<NotCopyableVector>::value");
|
| 415 |
-
// pybind11 does not have this
|
| 416 |
-
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableVector>::value,
|
| 417 |
-
// "!pybind11::detail::is_move_assignable<NotCopyableVector>::value");
|
| 418 |
-
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableVector>::value,
|
| 419 |
-
"!pybind11::detail::is_copy_assignable<NotCopyableVector>::value");
|
| 420 |
-
|
| 421 |
-
struct NotCopyableNotMovableVector : std::vector<NotCopyableNotMovable> {};
|
| 422 |
-
static_assert(std::is_move_constructible<NotCopyableNotMovableVector>::value,
|
| 423 |
-
"std::is_move_constructible<NotCopyableNotMovableVector>::value");
|
| 424 |
-
static_assert(std::is_copy_constructible<NotCopyableNotMovableVector>::value,
|
| 425 |
-
"std::is_copy_constructible<NotCopyableNotMovableVector>::value");
|
| 426 |
-
static_assert(!pybind11::detail::is_move_constructible<NotCopyableNotMovableVector>::value,
|
| 427 |
-
"!pybind11::detail::is_move_constructible<NotCopyableNotMovableVector>::value");
|
| 428 |
-
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableNotMovableVector>::value,
|
| 429 |
-
"!pybind11::detail::is_copy_constructible<NotCopyableNotMovableVector>::value");
|
| 430 |
-
static_assert(std::is_move_assignable<NotCopyableNotMovableVector>::value,
|
| 431 |
-
"std::is_move_assignable<NotCopyableNotMovableVector>::value");
|
| 432 |
-
static_assert(std::is_copy_assignable<NotCopyableNotMovableVector>::value,
|
| 433 |
-
"std::is_copy_assignable<NotCopyableNotMovableVector>::value");
|
| 434 |
-
// pybind11 does not have this
|
| 435 |
-
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableNotMovableVector>::value,
|
| 436 |
-
// "!pybind11::detail::is_move_assignable<NotCopyableNotMovableVector>::value");
|
| 437 |
-
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableNotMovableVector>::value,
|
| 438 |
-
"!pybind11::detail::is_copy_assignable<NotCopyableNotMovableVector>::value");
|
| 439 |
-
|
| 440 |
-
struct NotMovableMap : std::map<int, NotMovable> {};
|
| 441 |
-
static_assert(std::is_move_constructible<NotMovableMap>::value,
|
| 442 |
-
"std::is_move_constructible<NotMovableMap>::value");
|
| 443 |
-
static_assert(std::is_copy_constructible<NotMovableMap>::value,
|
| 444 |
-
"std::is_copy_constructible<NotMovableMap>::value");
|
| 445 |
-
static_assert(!pybind11::detail::is_move_constructible<NotMovableMap>::value,
|
| 446 |
-
"!pybind11::detail::is_move_constructible<NotMovableMap>::value");
|
| 447 |
-
static_assert(pybind11::detail::is_copy_constructible<NotMovableMap>::value,
|
| 448 |
-
"pybind11::detail::is_copy_constructible<NotMovableMap>::value");
|
| 449 |
-
static_assert(std::is_move_assignable<NotMovableMap>::value,
|
| 450 |
-
"std::is_move_assignable<NotMovableMap>::value");
|
| 451 |
-
static_assert(std::is_copy_assignable<NotMovableMap>::value,
|
| 452 |
-
"std::is_copy_assignable<NotMovableMap>::value");
|
| 453 |
-
// pybind11 does not have this
|
| 454 |
-
// static_assert(!pybind11::detail::is_move_assignable<NotMovableMap>::value,
|
| 455 |
-
// "!pybind11::detail::is_move_assignable<NotMovableMap>::value");
|
| 456 |
-
static_assert(pybind11::detail::is_copy_assignable<NotMovableMap>::value,
|
| 457 |
-
"pybind11::detail::is_copy_assignable<NotMovableMap>::value");
|
| 458 |
-
|
| 459 |
-
struct NotCopyableMap : std::map<int, NotCopyable> {};
|
| 460 |
-
static_assert(std::is_move_constructible<NotCopyableMap>::value,
|
| 461 |
-
"std::is_move_constructible<NotCopyableMap>::value");
|
| 462 |
-
static_assert(std::is_copy_constructible<NotCopyableMap>::value,
|
| 463 |
-
"std::is_copy_constructible<NotCopyableMap>::value");
|
| 464 |
-
static_assert(pybind11::detail::is_move_constructible<NotCopyableMap>::value,
|
| 465 |
-
"pybind11::detail::is_move_constructible<NotCopyableMap>::value");
|
| 466 |
-
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableMap>::value,
|
| 467 |
-
"!pybind11::detail::is_copy_constructible<NotCopyableMap>::value");
|
| 468 |
-
static_assert(std::is_move_assignable<NotCopyableMap>::value,
|
| 469 |
-
"std::is_move_assignable<NotCopyableMap>::value");
|
| 470 |
-
static_assert(std::is_copy_assignable<NotCopyableMap>::value,
|
| 471 |
-
"std::is_copy_assignable<NotCopyableMap>::value");
|
| 472 |
-
// pybind11 does not have this
|
| 473 |
-
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableMap>::value,
|
| 474 |
-
// "!pybind11::detail::is_move_assignable<NotCopyableMap>::value");
|
| 475 |
-
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableMap>::value,
|
| 476 |
-
"!pybind11::detail::is_copy_assignable<NotCopyableMap>::value");
|
| 477 |
-
|
| 478 |
-
struct NotCopyableNotMovableMap : std::map<int, NotCopyableNotMovable> {};
|
| 479 |
-
static_assert(std::is_move_constructible<NotCopyableNotMovableMap>::value,
|
| 480 |
-
"std::is_move_constructible<NotCopyableNotMovableMap>::value");
|
| 481 |
-
static_assert(std::is_copy_constructible<NotCopyableNotMovableMap>::value,
|
| 482 |
-
"std::is_copy_constructible<NotCopyableNotMovableMap>::value");
|
| 483 |
-
static_assert(!pybind11::detail::is_move_constructible<NotCopyableNotMovableMap>::value,
|
| 484 |
-
"!pybind11::detail::is_move_constructible<NotCopyableNotMovableMap>::value");
|
| 485 |
-
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableNotMovableMap>::value,
|
| 486 |
-
"!pybind11::detail::is_copy_constructible<NotCopyableNotMovableMap>::value");
|
| 487 |
-
static_assert(std::is_move_assignable<NotCopyableNotMovableMap>::value,
|
| 488 |
-
"std::is_move_assignable<NotCopyableNotMovableMap>::value");
|
| 489 |
-
static_assert(std::is_copy_assignable<NotCopyableNotMovableMap>::value,
|
| 490 |
-
"std::is_copy_assignable<NotCopyableNotMovableMap>::value");
|
| 491 |
-
// pybind11 does not have this
|
| 492 |
-
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableNotMovableMap>::value,
|
| 493 |
-
// "!pybind11::detail::is_move_assignable<NotCopyableNotMovableMap>::value");
|
| 494 |
-
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableNotMovableMap>::value,
|
| 495 |
-
"!pybind11::detail::is_copy_assignable<NotCopyableNotMovableMap>::value");
|
| 496 |
-
|
| 497 |
-
struct RecursiveVector : std::vector<RecursiveVector> {};
|
| 498 |
-
static_assert(std::is_move_constructible<RecursiveVector>::value,
|
| 499 |
-
"std::is_move_constructible<RecursiveVector>::value");
|
| 500 |
-
static_assert(std::is_copy_constructible<RecursiveVector>::value,
|
| 501 |
-
"std::is_copy_constructible<RecursiveVector>::value");
|
| 502 |
-
static_assert(pybind11::detail::is_move_constructible<RecursiveVector>::value,
|
| 503 |
-
"pybind11::detail::is_move_constructible<RecursiveVector>::value");
|
| 504 |
-
static_assert(pybind11::detail::is_copy_constructible<RecursiveVector>::value,
|
| 505 |
-
"pybind11::detail::is_copy_constructible<RecursiveVector>::value");
|
| 506 |
-
static_assert(std::is_move_assignable<RecursiveVector>::value,
|
| 507 |
-
"std::is_move_assignable<RecursiveVector>::value");
|
| 508 |
-
static_assert(std::is_copy_assignable<RecursiveVector>::value,
|
| 509 |
-
"std::is_copy_assignable<RecursiveVector>::value");
|
| 510 |
-
// pybind11 does not have this
|
| 511 |
-
// static_assert(!pybind11::detail::is_move_assignable<RecursiveVector>::value,
|
| 512 |
-
// "!pybind11::detail::is_move_assignable<RecursiveVector>::value");
|
| 513 |
-
static_assert(pybind11::detail::is_copy_assignable<RecursiveVector>::value,
|
| 514 |
-
"pybind11::detail::is_copy_assignable<RecursiveVector>::value");
|
| 515 |
-
|
| 516 |
-
struct RecursiveMap : std::map<int, RecursiveMap> {};
|
| 517 |
-
static_assert(std::is_move_constructible<RecursiveMap>::value,
|
| 518 |
-
"std::is_move_constructible<RecursiveMap>::value");
|
| 519 |
-
static_assert(std::is_copy_constructible<RecursiveMap>::value,
|
| 520 |
-
"std::is_copy_constructible<RecursiveMap>::value");
|
| 521 |
-
static_assert(pybind11::detail::is_move_constructible<RecursiveMap>::value,
|
| 522 |
-
"pybind11::detail::is_move_constructible<RecursiveMap>::value");
|
| 523 |
-
static_assert(pybind11::detail::is_copy_constructible<RecursiveMap>::value,
|
| 524 |
-
"pybind11::detail::is_copy_constructible<RecursiveMap>::value");
|
| 525 |
-
static_assert(std::is_move_assignable<RecursiveMap>::value,
|
| 526 |
-
"std::is_move_assignable<RecursiveMap>::value");
|
| 527 |
-
static_assert(std::is_copy_assignable<RecursiveMap>::value,
|
| 528 |
-
"std::is_copy_assignable<RecursiveMap>::value");
|
| 529 |
-
// pybind11 does not have this
|
| 530 |
-
// static_assert(!pybind11::detail::is_move_assignable<RecursiveMap>::value,
|
| 531 |
-
// "!pybind11::detail::is_move_assignable<RecursiveMap>::value");
|
| 532 |
-
static_assert(pybind11::detail::is_copy_assignable<RecursiveMap>::value,
|
| 533 |
-
"pybind11::detail::is_copy_assignable<RecursiveMap>::value");
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_copy_move_policies.cpp -- 'copy' and 'move' return value policies
|
| 3 |
+
and related tests
|
| 4 |
+
|
| 5 |
+
Copyright (c) 2016 Ben North <ben@redfrontdoor.org>
|
| 6 |
+
|
| 7 |
+
All rights reserved. Use of this source code is governed by a
|
| 8 |
+
BSD-style license that can be found in the LICENSE file.
|
| 9 |
+
*/
|
| 10 |
+
|
| 11 |
+
#include <pybind11/stl.h>
|
| 12 |
+
|
| 13 |
+
#include "constructor_stats.h"
|
| 14 |
+
#include "pybind11_tests.h"
|
| 15 |
+
|
| 16 |
+
#include <type_traits>
|
| 17 |
+
|
| 18 |
+
template <typename derived>
|
| 19 |
+
struct empty {
|
| 20 |
+
static const derived &get_one() { return instance_; }
|
| 21 |
+
static derived instance_;
|
| 22 |
+
};
|
| 23 |
+
|
| 24 |
+
struct lacking_copy_ctor : public empty<lacking_copy_ctor> {
|
| 25 |
+
lacking_copy_ctor() = default;
|
| 26 |
+
lacking_copy_ctor(const lacking_copy_ctor &other) = delete;
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
template <>
|
| 30 |
+
lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {};
|
| 31 |
+
|
| 32 |
+
struct lacking_move_ctor : public empty<lacking_move_ctor> {
|
| 33 |
+
lacking_move_ctor() = default;
|
| 34 |
+
lacking_move_ctor(const lacking_move_ctor &other) = delete;
|
| 35 |
+
lacking_move_ctor(lacking_move_ctor &&other) = delete;
|
| 36 |
+
};
|
| 37 |
+
|
| 38 |
+
template <>
|
| 39 |
+
lacking_move_ctor empty<lacking_move_ctor>::instance_ = {};
|
| 40 |
+
|
| 41 |
+
/* Custom type caster move/copy test classes */
|
| 42 |
+
class MoveOnlyInt {
|
| 43 |
+
public:
|
| 44 |
+
MoveOnlyInt() { print_default_created(this); }
|
| 45 |
+
explicit MoveOnlyInt(int v) : value{v} { print_created(this, value); }
|
| 46 |
+
MoveOnlyInt(MoveOnlyInt &&m) noexcept {
|
| 47 |
+
print_move_created(this, m.value);
|
| 48 |
+
std::swap(value, m.value);
|
| 49 |
+
}
|
| 50 |
+
MoveOnlyInt &operator=(MoveOnlyInt &&m) noexcept {
|
| 51 |
+
print_move_assigned(this, m.value);
|
| 52 |
+
std::swap(value, m.value);
|
| 53 |
+
return *this;
|
| 54 |
+
}
|
| 55 |
+
MoveOnlyInt(const MoveOnlyInt &) = delete;
|
| 56 |
+
MoveOnlyInt &operator=(const MoveOnlyInt &) = delete;
|
| 57 |
+
~MoveOnlyInt() { print_destroyed(this); }
|
| 58 |
+
|
| 59 |
+
int value;
|
| 60 |
+
};
|
| 61 |
+
class MoveOrCopyInt {
|
| 62 |
+
public:
|
| 63 |
+
MoveOrCopyInt() { print_default_created(this); }
|
| 64 |
+
explicit MoveOrCopyInt(int v) : value{v} { print_created(this, value); }
|
| 65 |
+
MoveOrCopyInt(MoveOrCopyInt &&m) noexcept {
|
| 66 |
+
print_move_created(this, m.value);
|
| 67 |
+
std::swap(value, m.value);
|
| 68 |
+
}
|
| 69 |
+
MoveOrCopyInt &operator=(MoveOrCopyInt &&m) noexcept {
|
| 70 |
+
print_move_assigned(this, m.value);
|
| 71 |
+
std::swap(value, m.value);
|
| 72 |
+
return *this;
|
| 73 |
+
}
|
| 74 |
+
MoveOrCopyInt(const MoveOrCopyInt &c) {
|
| 75 |
+
print_copy_created(this, c.value);
|
| 76 |
+
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
| 77 |
+
value = c.value;
|
| 78 |
+
}
|
| 79 |
+
MoveOrCopyInt &operator=(const MoveOrCopyInt &c) {
|
| 80 |
+
print_copy_assigned(this, c.value);
|
| 81 |
+
value = c.value;
|
| 82 |
+
return *this;
|
| 83 |
+
}
|
| 84 |
+
~MoveOrCopyInt() { print_destroyed(this); }
|
| 85 |
+
|
| 86 |
+
int value;
|
| 87 |
+
};
|
| 88 |
+
class CopyOnlyInt {
|
| 89 |
+
public:
|
| 90 |
+
CopyOnlyInt() { print_default_created(this); }
|
| 91 |
+
explicit CopyOnlyInt(int v) : value{v} { print_created(this, value); }
|
| 92 |
+
CopyOnlyInt(const CopyOnlyInt &c) {
|
| 93 |
+
print_copy_created(this, c.value);
|
| 94 |
+
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
| 95 |
+
value = c.value;
|
| 96 |
+
}
|
| 97 |
+
CopyOnlyInt &operator=(const CopyOnlyInt &c) {
|
| 98 |
+
print_copy_assigned(this, c.value);
|
| 99 |
+
value = c.value;
|
| 100 |
+
return *this;
|
| 101 |
+
}
|
| 102 |
+
~CopyOnlyInt() { print_destroyed(this); }
|
| 103 |
+
|
| 104 |
+
int value;
|
| 105 |
+
};
|
| 106 |
+
PYBIND11_NAMESPACE_BEGIN(pybind11)
|
| 107 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
| 108 |
+
template <>
|
| 109 |
+
struct type_caster<MoveOnlyInt> {
|
| 110 |
+
PYBIND11_TYPE_CASTER(MoveOnlyInt, const_name("MoveOnlyInt"));
|
| 111 |
+
bool load(handle src, bool) {
|
| 112 |
+
value = MoveOnlyInt(src.cast<int>());
|
| 113 |
+
return true;
|
| 114 |
+
}
|
| 115 |
+
static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) {
|
| 116 |
+
return pybind11::cast(m.value, r, p);
|
| 117 |
+
}
|
| 118 |
+
};
|
| 119 |
+
|
| 120 |
+
template <>
|
| 121 |
+
struct type_caster<MoveOrCopyInt> {
|
| 122 |
+
PYBIND11_TYPE_CASTER(MoveOrCopyInt, const_name("MoveOrCopyInt"));
|
| 123 |
+
bool load(handle src, bool) {
|
| 124 |
+
value = MoveOrCopyInt(src.cast<int>());
|
| 125 |
+
return true;
|
| 126 |
+
}
|
| 127 |
+
static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) {
|
| 128 |
+
return pybind11::cast(m.value, r, p);
|
| 129 |
+
}
|
| 130 |
+
};
|
| 131 |
+
|
| 132 |
+
template <>
|
| 133 |
+
struct type_caster<CopyOnlyInt> {
|
| 134 |
+
protected:
|
| 135 |
+
CopyOnlyInt value;
|
| 136 |
+
|
| 137 |
+
public:
|
| 138 |
+
static constexpr auto name = const_name("CopyOnlyInt");
|
| 139 |
+
bool load(handle src, bool) {
|
| 140 |
+
value = CopyOnlyInt(src.cast<int>());
|
| 141 |
+
return true;
|
| 142 |
+
}
|
| 143 |
+
static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) {
|
| 144 |
+
return pybind11::cast(m.value, r, p);
|
| 145 |
+
}
|
| 146 |
+
static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) {
|
| 147 |
+
if (!src) {
|
| 148 |
+
return none().release();
|
| 149 |
+
}
|
| 150 |
+
return cast(*src, policy, parent);
|
| 151 |
+
}
|
| 152 |
+
explicit operator CopyOnlyInt *() { return &value; }
|
| 153 |
+
explicit operator CopyOnlyInt &() { return value; }
|
| 154 |
+
template <typename T>
|
| 155 |
+
using cast_op_type = pybind11::detail::cast_op_type<T>;
|
| 156 |
+
};
|
| 157 |
+
PYBIND11_NAMESPACE_END(detail)
|
| 158 |
+
PYBIND11_NAMESPACE_END(pybind11)
|
| 159 |
+
|
| 160 |
+
TEST_SUBMODULE(copy_move_policies, m) {
|
| 161 |
+
// test_lacking_copy_ctor
|
| 162 |
+
py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
|
| 163 |
+
.def_static("get_one", &lacking_copy_ctor::get_one, py::return_value_policy::copy);
|
| 164 |
+
// test_lacking_move_ctor
|
| 165 |
+
py::class_<lacking_move_ctor>(m, "lacking_move_ctor")
|
| 166 |
+
.def_static("get_one", &lacking_move_ctor::get_one, py::return_value_policy::move);
|
| 167 |
+
|
| 168 |
+
// test_move_and_copy_casts
|
| 169 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 170 |
+
m.def("move_and_copy_casts", [](const py::object &o) {
|
| 171 |
+
int r = 0;
|
| 172 |
+
r += py::cast<MoveOrCopyInt>(o).value; /* moves */
|
| 173 |
+
r += py::cast<MoveOnlyInt>(o).value; /* moves */
|
| 174 |
+
r += py::cast<CopyOnlyInt>(o).value; /* copies */
|
| 175 |
+
auto m1(py::cast<MoveOrCopyInt>(o)); /* moves */
|
| 176 |
+
auto m2(py::cast<MoveOnlyInt>(o)); /* moves */
|
| 177 |
+
auto m3(py::cast<CopyOnlyInt>(o)); /* copies */
|
| 178 |
+
r += m1.value + m2.value + m3.value;
|
| 179 |
+
|
| 180 |
+
return r;
|
| 181 |
+
});
|
| 182 |
+
|
| 183 |
+
// test_move_and_copy_loads
|
| 184 |
+
m.def("move_only", [](MoveOnlyInt m) { return m.value; });
|
| 185 |
+
// Changing this breaks the existing test: needs careful review.
|
| 186 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 187 |
+
m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; });
|
| 188 |
+
// Changing this breaks the existing test: needs careful review.
|
| 189 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 190 |
+
m.def("copy_only", [](CopyOnlyInt m) { return m.value; });
|
| 191 |
+
m.def("move_pair",
|
| 192 |
+
[](std::pair<MoveOnlyInt, MoveOrCopyInt> p) { return p.first.value + p.second.value; });
|
| 193 |
+
m.def("move_tuple", [](std::tuple<MoveOnlyInt, MoveOrCopyInt, MoveOnlyInt> t) {
|
| 194 |
+
return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value;
|
| 195 |
+
});
|
| 196 |
+
m.def("copy_tuple", [](std::tuple<CopyOnlyInt, CopyOnlyInt> t) {
|
| 197 |
+
return std::get<0>(t).value + std::get<1>(t).value;
|
| 198 |
+
});
|
| 199 |
+
m.def("move_copy_nested",
|
| 200 |
+
[](std::pair<MoveOnlyInt,
|
| 201 |
+
std::pair<std::tuple<MoveOrCopyInt, CopyOnlyInt, std::tuple<MoveOnlyInt>>,
|
| 202 |
+
MoveOrCopyInt>> x) {
|
| 203 |
+
return x.first.value + std::get<0>(x.second.first).value
|
| 204 |
+
+ std::get<1>(x.second.first).value
|
| 205 |
+
+ std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value;
|
| 206 |
+
});
|
| 207 |
+
m.def("move_and_copy_cstats", []() {
|
| 208 |
+
ConstructorStats::gc();
|
| 209 |
+
// Reset counts to 0 so that previous tests don't affect later ones:
|
| 210 |
+
auto &mc = ConstructorStats::get<MoveOrCopyInt>();
|
| 211 |
+
mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions
|
| 212 |
+
= 0;
|
| 213 |
+
auto &mo = ConstructorStats::get<MoveOnlyInt>();
|
| 214 |
+
mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions
|
| 215 |
+
= 0;
|
| 216 |
+
auto &co = ConstructorStats::get<CopyOnlyInt>();
|
| 217 |
+
co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions
|
| 218 |
+
= 0;
|
| 219 |
+
py::dict d;
|
| 220 |
+
d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference);
|
| 221 |
+
d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference);
|
| 222 |
+
d["CopyOnlyInt"] = py::cast(co, py::return_value_policy::reference);
|
| 223 |
+
return d;
|
| 224 |
+
});
|
| 225 |
+
#ifdef PYBIND11_HAS_OPTIONAL
|
| 226 |
+
// test_move_and_copy_load_optional
|
| 227 |
+
m.attr("has_optional") = true;
|
| 228 |
+
m.def("move_optional", [](std::optional<MoveOnlyInt> o) { return o->value; });
|
| 229 |
+
m.def("move_or_copy_optional", [](std::optional<MoveOrCopyInt> o) { return o->value; });
|
| 230 |
+
m.def("copy_optional", [](std::optional<CopyOnlyInt> o) { return o->value; });
|
| 231 |
+
m.def("move_optional_tuple",
|
| 232 |
+
[](std::optional<std::tuple<MoveOrCopyInt, MoveOnlyInt, CopyOnlyInt>> x) {
|
| 233 |
+
return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value;
|
| 234 |
+
});
|
| 235 |
+
#else
|
| 236 |
+
m.attr("has_optional") = false;
|
| 237 |
+
#endif
|
| 238 |
+
|
| 239 |
+
// #70 compilation issue if operator new is not public - simple body added
|
| 240 |
+
// but not needed on most compilers; MSVC and nvcc don't like a local
|
| 241 |
+
// struct not having a method defined when declared, since it can not be
|
| 242 |
+
// added later.
|
| 243 |
+
struct PrivateOpNew {
|
| 244 |
+
int value = 1;
|
| 245 |
+
|
| 246 |
+
private:
|
| 247 |
+
void *operator new(size_t bytes) {
|
| 248 |
+
void *ptr = std::malloc(bytes);
|
| 249 |
+
if (ptr) {
|
| 250 |
+
return ptr;
|
| 251 |
+
}
|
| 252 |
+
throw std::bad_alloc{};
|
| 253 |
+
}
|
| 254 |
+
};
|
| 255 |
+
py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
|
| 256 |
+
m.def("private_op_new_value", []() { return PrivateOpNew(); });
|
| 257 |
+
m.def(
|
| 258 |
+
"private_op_new_reference",
|
| 259 |
+
[]() -> const PrivateOpNew & {
|
| 260 |
+
static PrivateOpNew x{};
|
| 261 |
+
return x;
|
| 262 |
+
},
|
| 263 |
+
py::return_value_policy::reference);
|
| 264 |
+
|
| 265 |
+
// test_move_fallback
|
| 266 |
+
// #389: rvp::move should fall-through to copy on non-movable objects
|
| 267 |
+
struct MoveIssue1 {
|
| 268 |
+
int v;
|
| 269 |
+
explicit MoveIssue1(int v) : v{v} {}
|
| 270 |
+
MoveIssue1(const MoveIssue1 &c) = default;
|
| 271 |
+
MoveIssue1(MoveIssue1 &&) = delete;
|
| 272 |
+
};
|
| 273 |
+
py::class_<MoveIssue1>(m, "MoveIssue1")
|
| 274 |
+
.def(py::init<int>())
|
| 275 |
+
.def_readwrite("value", &MoveIssue1::v);
|
| 276 |
+
|
| 277 |
+
struct MoveIssue2 {
|
| 278 |
+
int v;
|
| 279 |
+
explicit MoveIssue2(int v) : v{v} {}
|
| 280 |
+
MoveIssue2(MoveIssue2 &&) = default;
|
| 281 |
+
};
|
| 282 |
+
py::class_<MoveIssue2>(m, "MoveIssue2")
|
| 283 |
+
.def(py::init<int>())
|
| 284 |
+
.def_readwrite("value", &MoveIssue2::v);
|
| 285 |
+
|
| 286 |
+
// #2742: Don't expect ownership of raw pointer to `new`ed object to be transferred with
|
| 287 |
+
// `py::return_value_policy::move`
|
| 288 |
+
m.def(
|
| 289 |
+
"get_moveissue1",
|
| 290 |
+
[](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); },
|
| 291 |
+
py::return_value_policy::move);
|
| 292 |
+
m.def(
|
| 293 |
+
"get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
|
| 294 |
+
|
| 295 |
+
// Make sure that cast from pytype rvalue to other pytype works
|
| 296 |
+
m.def("get_pytype_rvalue_castissue", [](double i) { return py::float_(i).cast<py::int_>(); });
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
/*
|
| 300 |
+
* Rest of the file:
|
| 301 |
+
* static_assert based tests for pybind11 adaptations of
|
| 302 |
+
* std::is_move_constructible, std::is_copy_constructible and
|
| 303 |
+
* std::is_copy_assignable (no adaptation of std::is_move_assignable).
|
| 304 |
+
* Difference between pybind11 and std traits: pybind11 traits will also check
|
| 305 |
+
* the contained value_types.
|
| 306 |
+
*/
|
| 307 |
+
|
| 308 |
+
struct NotMovable {
|
| 309 |
+
NotMovable() = default;
|
| 310 |
+
NotMovable(NotMovable const &) = default;
|
| 311 |
+
NotMovable(NotMovable &&) = delete;
|
| 312 |
+
NotMovable &operator=(NotMovable const &) = default;
|
| 313 |
+
NotMovable &operator=(NotMovable &&) = delete;
|
| 314 |
+
};
|
| 315 |
+
static_assert(!std::is_move_constructible<NotMovable>::value,
|
| 316 |
+
"!std::is_move_constructible<NotMovable>::value");
|
| 317 |
+
static_assert(std::is_copy_constructible<NotMovable>::value,
|
| 318 |
+
"std::is_copy_constructible<NotMovable>::value");
|
| 319 |
+
static_assert(!pybind11::detail::is_move_constructible<NotMovable>::value,
|
| 320 |
+
"!pybind11::detail::is_move_constructible<NotMovable>::value");
|
| 321 |
+
static_assert(pybind11::detail::is_copy_constructible<NotMovable>::value,
|
| 322 |
+
"pybind11::detail::is_copy_constructible<NotMovable>::value");
|
| 323 |
+
static_assert(!std::is_move_assignable<NotMovable>::value,
|
| 324 |
+
"!std::is_move_assignable<NotMovable>::value");
|
| 325 |
+
static_assert(std::is_copy_assignable<NotMovable>::value,
|
| 326 |
+
"std::is_copy_assignable<NotMovable>::value");
|
| 327 |
+
// pybind11 does not have this
|
| 328 |
+
// static_assert(!pybind11::detail::is_move_assignable<NotMovable>::value,
|
| 329 |
+
// "!pybind11::detail::is_move_assignable<NotMovable>::value");
|
| 330 |
+
static_assert(pybind11::detail::is_copy_assignable<NotMovable>::value,
|
| 331 |
+
"pybind11::detail::is_copy_assignable<NotMovable>::value");
|
| 332 |
+
|
| 333 |
+
struct NotCopyable {
|
| 334 |
+
NotCopyable() = default;
|
| 335 |
+
NotCopyable(NotCopyable const &) = delete;
|
| 336 |
+
NotCopyable(NotCopyable &&) = default;
|
| 337 |
+
NotCopyable &operator=(NotCopyable const &) = delete;
|
| 338 |
+
NotCopyable &operator=(NotCopyable &&) = default;
|
| 339 |
+
};
|
| 340 |
+
static_assert(std::is_move_constructible<NotCopyable>::value,
|
| 341 |
+
"std::is_move_constructible<NotCopyable>::value");
|
| 342 |
+
static_assert(!std::is_copy_constructible<NotCopyable>::value,
|
| 343 |
+
"!std::is_copy_constructible<NotCopyable>::value");
|
| 344 |
+
static_assert(pybind11::detail::is_move_constructible<NotCopyable>::value,
|
| 345 |
+
"pybind11::detail::is_move_constructible<NotCopyable>::value");
|
| 346 |
+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyable>::value,
|
| 347 |
+
"!pybind11::detail::is_copy_constructible<NotCopyable>::value");
|
| 348 |
+
static_assert(std::is_move_assignable<NotCopyable>::value,
|
| 349 |
+
"std::is_move_assignable<NotCopyable>::value");
|
| 350 |
+
static_assert(!std::is_copy_assignable<NotCopyable>::value,
|
| 351 |
+
"!std::is_copy_assignable<NotCopyable>::value");
|
| 352 |
+
// pybind11 does not have this
|
| 353 |
+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyable>::value,
|
| 354 |
+
// "!pybind11::detail::is_move_assignable<NotCopyable>::value");
|
| 355 |
+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyable>::value,
|
| 356 |
+
"!pybind11::detail::is_copy_assignable<NotCopyable>::value");
|
| 357 |
+
|
| 358 |
+
struct NotCopyableNotMovable {
|
| 359 |
+
NotCopyableNotMovable() = default;
|
| 360 |
+
NotCopyableNotMovable(NotCopyableNotMovable const &) = delete;
|
| 361 |
+
NotCopyableNotMovable(NotCopyableNotMovable &&) = delete;
|
| 362 |
+
NotCopyableNotMovable &operator=(NotCopyableNotMovable const &) = delete;
|
| 363 |
+
NotCopyableNotMovable &operator=(NotCopyableNotMovable &&) = delete;
|
| 364 |
+
};
|
| 365 |
+
static_assert(!std::is_move_constructible<NotCopyableNotMovable>::value,
|
| 366 |
+
"!std::is_move_constructible<NotCopyableNotMovable>::value");
|
| 367 |
+
static_assert(!std::is_copy_constructible<NotCopyableNotMovable>::value,
|
| 368 |
+
"!std::is_copy_constructible<NotCopyableNotMovable>::value");
|
| 369 |
+
static_assert(!pybind11::detail::is_move_constructible<NotCopyableNotMovable>::value,
|
| 370 |
+
"!pybind11::detail::is_move_constructible<NotCopyableNotMovable>::value");
|
| 371 |
+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableNotMovable>::value,
|
| 372 |
+
"!pybind11::detail::is_copy_constructible<NotCopyableNotMovable>::value");
|
| 373 |
+
static_assert(!std::is_move_assignable<NotCopyableNotMovable>::value,
|
| 374 |
+
"!std::is_move_assignable<NotCopyableNotMovable>::value");
|
| 375 |
+
static_assert(!std::is_copy_assignable<NotCopyableNotMovable>::value,
|
| 376 |
+
"!std::is_copy_assignable<NotCopyableNotMovable>::value");
|
| 377 |
+
// pybind11 does not have this
|
| 378 |
+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableNotMovable>::value,
|
| 379 |
+
// "!pybind11::detail::is_move_assignable<NotCopyableNotMovable>::value");
|
| 380 |
+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableNotMovable>::value,
|
| 381 |
+
"!pybind11::detail::is_copy_assignable<NotCopyableNotMovable>::value");
|
| 382 |
+
|
| 383 |
+
struct NotMovableVector : std::vector<NotMovable> {};
|
| 384 |
+
static_assert(std::is_move_constructible<NotMovableVector>::value,
|
| 385 |
+
"std::is_move_constructible<NotMovableVector>::value");
|
| 386 |
+
static_assert(std::is_copy_constructible<NotMovableVector>::value,
|
| 387 |
+
"std::is_copy_constructible<NotMovableVector>::value");
|
| 388 |
+
static_assert(!pybind11::detail::is_move_constructible<NotMovableVector>::value,
|
| 389 |
+
"!pybind11::detail::is_move_constructible<NotMovableVector>::value");
|
| 390 |
+
static_assert(pybind11::detail::is_copy_constructible<NotMovableVector>::value,
|
| 391 |
+
"pybind11::detail::is_copy_constructible<NotMovableVector>::value");
|
| 392 |
+
static_assert(std::is_move_assignable<NotMovableVector>::value,
|
| 393 |
+
"std::is_move_assignable<NotMovableVector>::value");
|
| 394 |
+
static_assert(std::is_copy_assignable<NotMovableVector>::value,
|
| 395 |
+
"std::is_copy_assignable<NotMovableVector>::value");
|
| 396 |
+
// pybind11 does not have this
|
| 397 |
+
// static_assert(!pybind11::detail::is_move_assignable<NotMovableVector>::value,
|
| 398 |
+
// "!pybind11::detail::is_move_assignable<NotMovableVector>::value");
|
| 399 |
+
static_assert(pybind11::detail::is_copy_assignable<NotMovableVector>::value,
|
| 400 |
+
"pybind11::detail::is_copy_assignable<NotMovableVector>::value");
|
| 401 |
+
|
| 402 |
+
struct NotCopyableVector : std::vector<NotCopyable> {};
|
| 403 |
+
static_assert(std::is_move_constructible<NotCopyableVector>::value,
|
| 404 |
+
"std::is_move_constructible<NotCopyableVector>::value");
|
| 405 |
+
static_assert(std::is_copy_constructible<NotCopyableVector>::value,
|
| 406 |
+
"std::is_copy_constructible<NotCopyableVector>::value");
|
| 407 |
+
static_assert(pybind11::detail::is_move_constructible<NotCopyableVector>::value,
|
| 408 |
+
"pybind11::detail::is_move_constructible<NotCopyableVector>::value");
|
| 409 |
+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableVector>::value,
|
| 410 |
+
"!pybind11::detail::is_copy_constructible<NotCopyableVector>::value");
|
| 411 |
+
static_assert(std::is_move_assignable<NotCopyableVector>::value,
|
| 412 |
+
"std::is_move_assignable<NotCopyableVector>::value");
|
| 413 |
+
static_assert(std::is_copy_assignable<NotCopyableVector>::value,
|
| 414 |
+
"std::is_copy_assignable<NotCopyableVector>::value");
|
| 415 |
+
// pybind11 does not have this
|
| 416 |
+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableVector>::value,
|
| 417 |
+
// "!pybind11::detail::is_move_assignable<NotCopyableVector>::value");
|
| 418 |
+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableVector>::value,
|
| 419 |
+
"!pybind11::detail::is_copy_assignable<NotCopyableVector>::value");
|
| 420 |
+
|
| 421 |
+
struct NotCopyableNotMovableVector : std::vector<NotCopyableNotMovable> {};
|
| 422 |
+
static_assert(std::is_move_constructible<NotCopyableNotMovableVector>::value,
|
| 423 |
+
"std::is_move_constructible<NotCopyableNotMovableVector>::value");
|
| 424 |
+
static_assert(std::is_copy_constructible<NotCopyableNotMovableVector>::value,
|
| 425 |
+
"std::is_copy_constructible<NotCopyableNotMovableVector>::value");
|
| 426 |
+
static_assert(!pybind11::detail::is_move_constructible<NotCopyableNotMovableVector>::value,
|
| 427 |
+
"!pybind11::detail::is_move_constructible<NotCopyableNotMovableVector>::value");
|
| 428 |
+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableNotMovableVector>::value,
|
| 429 |
+
"!pybind11::detail::is_copy_constructible<NotCopyableNotMovableVector>::value");
|
| 430 |
+
static_assert(std::is_move_assignable<NotCopyableNotMovableVector>::value,
|
| 431 |
+
"std::is_move_assignable<NotCopyableNotMovableVector>::value");
|
| 432 |
+
static_assert(std::is_copy_assignable<NotCopyableNotMovableVector>::value,
|
| 433 |
+
"std::is_copy_assignable<NotCopyableNotMovableVector>::value");
|
| 434 |
+
// pybind11 does not have this
|
| 435 |
+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableNotMovableVector>::value,
|
| 436 |
+
// "!pybind11::detail::is_move_assignable<NotCopyableNotMovableVector>::value");
|
| 437 |
+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableNotMovableVector>::value,
|
| 438 |
+
"!pybind11::detail::is_copy_assignable<NotCopyableNotMovableVector>::value");
|
| 439 |
+
|
| 440 |
+
struct NotMovableMap : std::map<int, NotMovable> {};
|
| 441 |
+
static_assert(std::is_move_constructible<NotMovableMap>::value,
|
| 442 |
+
"std::is_move_constructible<NotMovableMap>::value");
|
| 443 |
+
static_assert(std::is_copy_constructible<NotMovableMap>::value,
|
| 444 |
+
"std::is_copy_constructible<NotMovableMap>::value");
|
| 445 |
+
static_assert(!pybind11::detail::is_move_constructible<NotMovableMap>::value,
|
| 446 |
+
"!pybind11::detail::is_move_constructible<NotMovableMap>::value");
|
| 447 |
+
static_assert(pybind11::detail::is_copy_constructible<NotMovableMap>::value,
|
| 448 |
+
"pybind11::detail::is_copy_constructible<NotMovableMap>::value");
|
| 449 |
+
static_assert(std::is_move_assignable<NotMovableMap>::value,
|
| 450 |
+
"std::is_move_assignable<NotMovableMap>::value");
|
| 451 |
+
static_assert(std::is_copy_assignable<NotMovableMap>::value,
|
| 452 |
+
"std::is_copy_assignable<NotMovableMap>::value");
|
| 453 |
+
// pybind11 does not have this
|
| 454 |
+
// static_assert(!pybind11::detail::is_move_assignable<NotMovableMap>::value,
|
| 455 |
+
// "!pybind11::detail::is_move_assignable<NotMovableMap>::value");
|
| 456 |
+
static_assert(pybind11::detail::is_copy_assignable<NotMovableMap>::value,
|
| 457 |
+
"pybind11::detail::is_copy_assignable<NotMovableMap>::value");
|
| 458 |
+
|
| 459 |
+
struct NotCopyableMap : std::map<int, NotCopyable> {};
|
| 460 |
+
static_assert(std::is_move_constructible<NotCopyableMap>::value,
|
| 461 |
+
"std::is_move_constructible<NotCopyableMap>::value");
|
| 462 |
+
static_assert(std::is_copy_constructible<NotCopyableMap>::value,
|
| 463 |
+
"std::is_copy_constructible<NotCopyableMap>::value");
|
| 464 |
+
static_assert(pybind11::detail::is_move_constructible<NotCopyableMap>::value,
|
| 465 |
+
"pybind11::detail::is_move_constructible<NotCopyableMap>::value");
|
| 466 |
+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableMap>::value,
|
| 467 |
+
"!pybind11::detail::is_copy_constructible<NotCopyableMap>::value");
|
| 468 |
+
static_assert(std::is_move_assignable<NotCopyableMap>::value,
|
| 469 |
+
"std::is_move_assignable<NotCopyableMap>::value");
|
| 470 |
+
static_assert(std::is_copy_assignable<NotCopyableMap>::value,
|
| 471 |
+
"std::is_copy_assignable<NotCopyableMap>::value");
|
| 472 |
+
// pybind11 does not have this
|
| 473 |
+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableMap>::value,
|
| 474 |
+
// "!pybind11::detail::is_move_assignable<NotCopyableMap>::value");
|
| 475 |
+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableMap>::value,
|
| 476 |
+
"!pybind11::detail::is_copy_assignable<NotCopyableMap>::value");
|
| 477 |
+
|
| 478 |
+
struct NotCopyableNotMovableMap : std::map<int, NotCopyableNotMovable> {};
|
| 479 |
+
static_assert(std::is_move_constructible<NotCopyableNotMovableMap>::value,
|
| 480 |
+
"std::is_move_constructible<NotCopyableNotMovableMap>::value");
|
| 481 |
+
static_assert(std::is_copy_constructible<NotCopyableNotMovableMap>::value,
|
| 482 |
+
"std::is_copy_constructible<NotCopyableNotMovableMap>::value");
|
| 483 |
+
static_assert(!pybind11::detail::is_move_constructible<NotCopyableNotMovableMap>::value,
|
| 484 |
+
"!pybind11::detail::is_move_constructible<NotCopyableNotMovableMap>::value");
|
| 485 |
+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableNotMovableMap>::value,
|
| 486 |
+
"!pybind11::detail::is_copy_constructible<NotCopyableNotMovableMap>::value");
|
| 487 |
+
static_assert(std::is_move_assignable<NotCopyableNotMovableMap>::value,
|
| 488 |
+
"std::is_move_assignable<NotCopyableNotMovableMap>::value");
|
| 489 |
+
static_assert(std::is_copy_assignable<NotCopyableNotMovableMap>::value,
|
| 490 |
+
"std::is_copy_assignable<NotCopyableNotMovableMap>::value");
|
| 491 |
+
// pybind11 does not have this
|
| 492 |
+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableNotMovableMap>::value,
|
| 493 |
+
// "!pybind11::detail::is_move_assignable<NotCopyableNotMovableMap>::value");
|
| 494 |
+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableNotMovableMap>::value,
|
| 495 |
+
"!pybind11::detail::is_copy_assignable<NotCopyableNotMovableMap>::value");
|
| 496 |
+
|
| 497 |
+
struct RecursiveVector : std::vector<RecursiveVector> {};
|
| 498 |
+
static_assert(std::is_move_constructible<RecursiveVector>::value,
|
| 499 |
+
"std::is_move_constructible<RecursiveVector>::value");
|
| 500 |
+
static_assert(std::is_copy_constructible<RecursiveVector>::value,
|
| 501 |
+
"std::is_copy_constructible<RecursiveVector>::value");
|
| 502 |
+
static_assert(pybind11::detail::is_move_constructible<RecursiveVector>::value,
|
| 503 |
+
"pybind11::detail::is_move_constructible<RecursiveVector>::value");
|
| 504 |
+
static_assert(pybind11::detail::is_copy_constructible<RecursiveVector>::value,
|
| 505 |
+
"pybind11::detail::is_copy_constructible<RecursiveVector>::value");
|
| 506 |
+
static_assert(std::is_move_assignable<RecursiveVector>::value,
|
| 507 |
+
"std::is_move_assignable<RecursiveVector>::value");
|
| 508 |
+
static_assert(std::is_copy_assignable<RecursiveVector>::value,
|
| 509 |
+
"std::is_copy_assignable<RecursiveVector>::value");
|
| 510 |
+
// pybind11 does not have this
|
| 511 |
+
// static_assert(!pybind11::detail::is_move_assignable<RecursiveVector>::value,
|
| 512 |
+
// "!pybind11::detail::is_move_assignable<RecursiveVector>::value");
|
| 513 |
+
static_assert(pybind11::detail::is_copy_assignable<RecursiveVector>::value,
|
| 514 |
+
"pybind11::detail::is_copy_assignable<RecursiveVector>::value");
|
| 515 |
+
|
| 516 |
+
struct RecursiveMap : std::map<int, RecursiveMap> {};
|
| 517 |
+
static_assert(std::is_move_constructible<RecursiveMap>::value,
|
| 518 |
+
"std::is_move_constructible<RecursiveMap>::value");
|
| 519 |
+
static_assert(std::is_copy_constructible<RecursiveMap>::value,
|
| 520 |
+
"std::is_copy_constructible<RecursiveMap>::value");
|
| 521 |
+
static_assert(pybind11::detail::is_move_constructible<RecursiveMap>::value,
|
| 522 |
+
"pybind11::detail::is_move_constructible<RecursiveMap>::value");
|
| 523 |
+
static_assert(pybind11::detail::is_copy_constructible<RecursiveMap>::value,
|
| 524 |
+
"pybind11::detail::is_copy_constructible<RecursiveMap>::value");
|
| 525 |
+
static_assert(std::is_move_assignable<RecursiveMap>::value,
|
| 526 |
+
"std::is_move_assignable<RecursiveMap>::value");
|
| 527 |
+
static_assert(std::is_copy_assignable<RecursiveMap>::value,
|
| 528 |
+
"std::is_copy_assignable<RecursiveMap>::value");
|
| 529 |
+
// pybind11 does not have this
|
| 530 |
+
// static_assert(!pybind11::detail::is_move_assignable<RecursiveMap>::value,
|
| 531 |
+
// "!pybind11::detail::is_move_assignable<RecursiveMap>::value");
|
| 532 |
+
static_assert(pybind11::detail::is_copy_assignable<RecursiveMap>::value,
|
| 533 |
+
"pybind11::detail::is_copy_assignable<RecursiveMap>::value");
|
third_party/CityFlow/extern/pybind11/tests/test_copy_move.py
CHANGED
|
@@ -1,132 +1,132 @@
|
|
| 1 |
-
import pytest
|
| 2 |
-
|
| 3 |
-
from pybind11_tests import copy_move_policies as m
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
def test_lacking_copy_ctor():
|
| 7 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 8 |
-
m.lacking_copy_ctor.get_one()
|
| 9 |
-
assert "is non-copyable!" in str(excinfo.value)
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
def test_lacking_move_ctor():
|
| 13 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 14 |
-
m.lacking_move_ctor.get_one()
|
| 15 |
-
assert "is neither movable nor copyable!" in str(excinfo.value)
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
def test_move_and_copy_casts():
|
| 19 |
-
"""Cast some values in C++ via custom type casters and count the number of moves/copies."""
|
| 20 |
-
|
| 21 |
-
cstats = m.move_and_copy_cstats()
|
| 22 |
-
c_m, c_mc, c_c = (
|
| 23 |
-
cstats["MoveOnlyInt"],
|
| 24 |
-
cstats["MoveOrCopyInt"],
|
| 25 |
-
cstats["CopyOnlyInt"],
|
| 26 |
-
)
|
| 27 |
-
|
| 28 |
-
# The type move constructions/assignments below each get incremented: the move assignment comes
|
| 29 |
-
# from the type_caster load; the move construction happens when extracting that via a cast or
|
| 30 |
-
# loading into an argument.
|
| 31 |
-
assert m.move_and_copy_casts(3) == 18
|
| 32 |
-
assert c_m.copy_assignments + c_m.copy_constructions == 0
|
| 33 |
-
assert c_m.move_assignments == 2
|
| 34 |
-
assert c_m.move_constructions >= 2
|
| 35 |
-
assert c_mc.alive() == 0
|
| 36 |
-
assert c_mc.copy_assignments + c_mc.copy_constructions == 0
|
| 37 |
-
assert c_mc.move_assignments == 2
|
| 38 |
-
assert c_mc.move_constructions >= 2
|
| 39 |
-
assert c_c.alive() == 0
|
| 40 |
-
assert c_c.copy_assignments == 2
|
| 41 |
-
assert c_c.copy_constructions >= 2
|
| 42 |
-
assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
def test_move_and_copy_loads():
|
| 46 |
-
"""Call some functions that load arguments via custom type casters and count the number of
|
| 47 |
-
moves/copies."""
|
| 48 |
-
|
| 49 |
-
cstats = m.move_and_copy_cstats()
|
| 50 |
-
c_m, c_mc, c_c = (
|
| 51 |
-
cstats["MoveOnlyInt"],
|
| 52 |
-
cstats["MoveOrCopyInt"],
|
| 53 |
-
cstats["CopyOnlyInt"],
|
| 54 |
-
)
|
| 55 |
-
|
| 56 |
-
assert m.move_only(10) == 10 # 1 move, c_m
|
| 57 |
-
assert m.move_or_copy(11) == 11 # 1 move, c_mc
|
| 58 |
-
assert m.copy_only(12) == 12 # 1 copy, c_c
|
| 59 |
-
assert m.move_pair((13, 14)) == 27 # 1 c_m move, 1 c_mc move
|
| 60 |
-
assert m.move_tuple((15, 16, 17)) == 48 # 2 c_m moves, 1 c_mc move
|
| 61 |
-
assert m.copy_tuple((18, 19)) == 37 # 2 c_c copies
|
| 62 |
-
# Direct constructions: 2 c_m moves, 2 c_mc moves, 1 c_c copy
|
| 63 |
-
# Extra moves/copies when moving pairs/tuples: 3 c_m, 3 c_mc, 2 c_c
|
| 64 |
-
assert m.move_copy_nested((1, ((2, 3, (4,)), 5))) == 15
|
| 65 |
-
|
| 66 |
-
assert c_m.copy_assignments + c_m.copy_constructions == 0
|
| 67 |
-
assert c_m.move_assignments == 6
|
| 68 |
-
assert c_m.move_constructions == 9
|
| 69 |
-
assert c_mc.copy_assignments + c_mc.copy_constructions == 0
|
| 70 |
-
assert c_mc.move_assignments == 5
|
| 71 |
-
assert c_mc.move_constructions == 8
|
| 72 |
-
assert c_c.copy_assignments == 4
|
| 73 |
-
assert c_c.copy_constructions == 6
|
| 74 |
-
assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
@pytest.mark.skipif(not m.has_optional, reason="no <optional>")
|
| 78 |
-
def test_move_and_copy_load_optional():
|
| 79 |
-
"""Tests move/copy loads of std::optional arguments"""
|
| 80 |
-
|
| 81 |
-
cstats = m.move_and_copy_cstats()
|
| 82 |
-
c_m, c_mc, c_c = (
|
| 83 |
-
cstats["MoveOnlyInt"],
|
| 84 |
-
cstats["MoveOrCopyInt"],
|
| 85 |
-
cstats["CopyOnlyInt"],
|
| 86 |
-
)
|
| 87 |
-
|
| 88 |
-
# The extra move/copy constructions below come from the std::optional move (which has to move
|
| 89 |
-
# its arguments):
|
| 90 |
-
assert m.move_optional(10) == 10 # c_m: 1 move assign, 2 move construct
|
| 91 |
-
assert m.move_or_copy_optional(11) == 11 # c_mc: 1 move assign, 2 move construct
|
| 92 |
-
assert m.copy_optional(12) == 12 # c_c: 1 copy assign, 2 copy construct
|
| 93 |
-
# 1 move assign + move construct moves each of c_m, c_mc, 1 c_c copy
|
| 94 |
-
# +1 move/copy construct each from moving the tuple
|
| 95 |
-
# +1 move/copy construct each from moving the optional (which moves the tuple again)
|
| 96 |
-
assert m.move_optional_tuple((3, 4, 5)) == 12
|
| 97 |
-
|
| 98 |
-
assert c_m.copy_assignments + c_m.copy_constructions == 0
|
| 99 |
-
assert c_m.move_assignments == 2
|
| 100 |
-
assert c_m.move_constructions == 5
|
| 101 |
-
assert c_mc.copy_assignments + c_mc.copy_constructions == 0
|
| 102 |
-
assert c_mc.move_assignments == 2
|
| 103 |
-
assert c_mc.move_constructions == 5
|
| 104 |
-
assert c_c.copy_assignments == 2
|
| 105 |
-
assert c_c.copy_constructions == 5
|
| 106 |
-
assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
def test_private_op_new():
|
| 110 |
-
"""An object with a private `operator new` cannot be returned by value"""
|
| 111 |
-
|
| 112 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 113 |
-
m.private_op_new_value()
|
| 114 |
-
assert "is neither movable nor copyable" in str(excinfo.value)
|
| 115 |
-
|
| 116 |
-
assert m.private_op_new_reference().value == 1
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
def test_move_fallback():
|
| 120 |
-
"""#389: rvp::move should fall-through to copy on non-movable objects"""
|
| 121 |
-
|
| 122 |
-
m1 = m.get_moveissue1(1)
|
| 123 |
-
assert m1.value == 1
|
| 124 |
-
m2 = m.get_moveissue2(2)
|
| 125 |
-
assert m2.value == 2
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
def test_pytype_rvalue_cast():
|
| 129 |
-
"""Make sure that cast from pytype rvalue to other pytype works"""
|
| 130 |
-
|
| 131 |
-
value = m.get_pytype_rvalue_castissue(1.0)
|
| 132 |
-
assert value == 1
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
from pybind11_tests import copy_move_policies as m
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def test_lacking_copy_ctor():
|
| 7 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 8 |
+
m.lacking_copy_ctor.get_one()
|
| 9 |
+
assert "is non-copyable!" in str(excinfo.value)
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def test_lacking_move_ctor():
|
| 13 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 14 |
+
m.lacking_move_ctor.get_one()
|
| 15 |
+
assert "is neither movable nor copyable!" in str(excinfo.value)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def test_move_and_copy_casts():
|
| 19 |
+
"""Cast some values in C++ via custom type casters and count the number of moves/copies."""
|
| 20 |
+
|
| 21 |
+
cstats = m.move_and_copy_cstats()
|
| 22 |
+
c_m, c_mc, c_c = (
|
| 23 |
+
cstats["MoveOnlyInt"],
|
| 24 |
+
cstats["MoveOrCopyInt"],
|
| 25 |
+
cstats["CopyOnlyInt"],
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
# The type move constructions/assignments below each get incremented: the move assignment comes
|
| 29 |
+
# from the type_caster load; the move construction happens when extracting that via a cast or
|
| 30 |
+
# loading into an argument.
|
| 31 |
+
assert m.move_and_copy_casts(3) == 18
|
| 32 |
+
assert c_m.copy_assignments + c_m.copy_constructions == 0
|
| 33 |
+
assert c_m.move_assignments == 2
|
| 34 |
+
assert c_m.move_constructions >= 2
|
| 35 |
+
assert c_mc.alive() == 0
|
| 36 |
+
assert c_mc.copy_assignments + c_mc.copy_constructions == 0
|
| 37 |
+
assert c_mc.move_assignments == 2
|
| 38 |
+
assert c_mc.move_constructions >= 2
|
| 39 |
+
assert c_c.alive() == 0
|
| 40 |
+
assert c_c.copy_assignments == 2
|
| 41 |
+
assert c_c.copy_constructions >= 2
|
| 42 |
+
assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def test_move_and_copy_loads():
|
| 46 |
+
"""Call some functions that load arguments via custom type casters and count the number of
|
| 47 |
+
moves/copies."""
|
| 48 |
+
|
| 49 |
+
cstats = m.move_and_copy_cstats()
|
| 50 |
+
c_m, c_mc, c_c = (
|
| 51 |
+
cstats["MoveOnlyInt"],
|
| 52 |
+
cstats["MoveOrCopyInt"],
|
| 53 |
+
cstats["CopyOnlyInt"],
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
assert m.move_only(10) == 10 # 1 move, c_m
|
| 57 |
+
assert m.move_or_copy(11) == 11 # 1 move, c_mc
|
| 58 |
+
assert m.copy_only(12) == 12 # 1 copy, c_c
|
| 59 |
+
assert m.move_pair((13, 14)) == 27 # 1 c_m move, 1 c_mc move
|
| 60 |
+
assert m.move_tuple((15, 16, 17)) == 48 # 2 c_m moves, 1 c_mc move
|
| 61 |
+
assert m.copy_tuple((18, 19)) == 37 # 2 c_c copies
|
| 62 |
+
# Direct constructions: 2 c_m moves, 2 c_mc moves, 1 c_c copy
|
| 63 |
+
# Extra moves/copies when moving pairs/tuples: 3 c_m, 3 c_mc, 2 c_c
|
| 64 |
+
assert m.move_copy_nested((1, ((2, 3, (4,)), 5))) == 15
|
| 65 |
+
|
| 66 |
+
assert c_m.copy_assignments + c_m.copy_constructions == 0
|
| 67 |
+
assert c_m.move_assignments == 6
|
| 68 |
+
assert c_m.move_constructions == 9
|
| 69 |
+
assert c_mc.copy_assignments + c_mc.copy_constructions == 0
|
| 70 |
+
assert c_mc.move_assignments == 5
|
| 71 |
+
assert c_mc.move_constructions == 8
|
| 72 |
+
assert c_c.copy_assignments == 4
|
| 73 |
+
assert c_c.copy_constructions == 6
|
| 74 |
+
assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
@pytest.mark.skipif(not m.has_optional, reason="no <optional>")
|
| 78 |
+
def test_move_and_copy_load_optional():
|
| 79 |
+
"""Tests move/copy loads of std::optional arguments"""
|
| 80 |
+
|
| 81 |
+
cstats = m.move_and_copy_cstats()
|
| 82 |
+
c_m, c_mc, c_c = (
|
| 83 |
+
cstats["MoveOnlyInt"],
|
| 84 |
+
cstats["MoveOrCopyInt"],
|
| 85 |
+
cstats["CopyOnlyInt"],
|
| 86 |
+
)
|
| 87 |
+
|
| 88 |
+
# The extra move/copy constructions below come from the std::optional move (which has to move
|
| 89 |
+
# its arguments):
|
| 90 |
+
assert m.move_optional(10) == 10 # c_m: 1 move assign, 2 move construct
|
| 91 |
+
assert m.move_or_copy_optional(11) == 11 # c_mc: 1 move assign, 2 move construct
|
| 92 |
+
assert m.copy_optional(12) == 12 # c_c: 1 copy assign, 2 copy construct
|
| 93 |
+
# 1 move assign + move construct moves each of c_m, c_mc, 1 c_c copy
|
| 94 |
+
# +1 move/copy construct each from moving the tuple
|
| 95 |
+
# +1 move/copy construct each from moving the optional (which moves the tuple again)
|
| 96 |
+
assert m.move_optional_tuple((3, 4, 5)) == 12
|
| 97 |
+
|
| 98 |
+
assert c_m.copy_assignments + c_m.copy_constructions == 0
|
| 99 |
+
assert c_m.move_assignments == 2
|
| 100 |
+
assert c_m.move_constructions == 5
|
| 101 |
+
assert c_mc.copy_assignments + c_mc.copy_constructions == 0
|
| 102 |
+
assert c_mc.move_assignments == 2
|
| 103 |
+
assert c_mc.move_constructions == 5
|
| 104 |
+
assert c_c.copy_assignments == 2
|
| 105 |
+
assert c_c.copy_constructions == 5
|
| 106 |
+
assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def test_private_op_new():
|
| 110 |
+
"""An object with a private `operator new` cannot be returned by value"""
|
| 111 |
+
|
| 112 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 113 |
+
m.private_op_new_value()
|
| 114 |
+
assert "is neither movable nor copyable" in str(excinfo.value)
|
| 115 |
+
|
| 116 |
+
assert m.private_op_new_reference().value == 1
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def test_move_fallback():
|
| 120 |
+
"""#389: rvp::move should fall-through to copy on non-movable objects"""
|
| 121 |
+
|
| 122 |
+
m1 = m.get_moveissue1(1)
|
| 123 |
+
assert m1.value == 1
|
| 124 |
+
m2 = m.get_moveissue2(2)
|
| 125 |
+
assert m2.value == 2
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
def test_pytype_rvalue_cast():
|
| 129 |
+
"""Make sure that cast from pytype rvalue to other pytype works"""
|
| 130 |
+
|
| 131 |
+
value = m.get_pytype_rvalue_castissue(1.0)
|
| 132 |
+
assert value == 1
|
third_party/CityFlow/extern/pybind11/tests/test_custom_type_casters.cpp
CHANGED
|
@@ -1,221 +1,221 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_custom_type_casters.cpp -- tests type_caster<T>
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#include "constructor_stats.h"
|
| 11 |
-
#include "pybind11_tests.h"
|
| 12 |
-
|
| 13 |
-
// py::arg/py::arg_v testing: these arguments just record their argument when invoked
|
| 14 |
-
class ArgInspector1 {
|
| 15 |
-
public:
|
| 16 |
-
std::string arg = "(default arg inspector 1)";
|
| 17 |
-
};
|
| 18 |
-
class ArgInspector2 {
|
| 19 |
-
public:
|
| 20 |
-
std::string arg = "(default arg inspector 2)";
|
| 21 |
-
};
|
| 22 |
-
class ArgAlwaysConverts {};
|
| 23 |
-
|
| 24 |
-
namespace PYBIND11_NAMESPACE {
|
| 25 |
-
namespace detail {
|
| 26 |
-
template <>
|
| 27 |
-
struct type_caster<ArgInspector1> {
|
| 28 |
-
public:
|
| 29 |
-
// Classic
|
| 30 |
-
#ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
|
| 31 |
-
PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1"));
|
| 32 |
-
#else
|
| 33 |
-
PYBIND11_TYPE_CASTER(ArgInspector1, const_name("ArgInspector1"));
|
| 34 |
-
#endif
|
| 35 |
-
|
| 36 |
-
bool load(handle src, bool convert) {
|
| 37 |
-
value.arg = "loading ArgInspector1 argument " + std::string(convert ? "WITH" : "WITHOUT")
|
| 38 |
-
+ " conversion allowed. "
|
| 39 |
-
"Argument value = "
|
| 40 |
-
+ (std::string) str(src);
|
| 41 |
-
return true;
|
| 42 |
-
}
|
| 43 |
-
|
| 44 |
-
static handle cast(const ArgInspector1 &src, return_value_policy, handle) {
|
| 45 |
-
return str(src.arg).release();
|
| 46 |
-
}
|
| 47 |
-
};
|
| 48 |
-
template <>
|
| 49 |
-
struct type_caster<ArgInspector2> {
|
| 50 |
-
public:
|
| 51 |
-
PYBIND11_TYPE_CASTER(ArgInspector2, const_name("ArgInspector2"));
|
| 52 |
-
|
| 53 |
-
bool load(handle src, bool convert) {
|
| 54 |
-
value.arg = "loading ArgInspector2 argument " + std::string(convert ? "WITH" : "WITHOUT")
|
| 55 |
-
+ " conversion allowed. "
|
| 56 |
-
"Argument value = "
|
| 57 |
-
+ (std::string) str(src);
|
| 58 |
-
return true;
|
| 59 |
-
}
|
| 60 |
-
|
| 61 |
-
static handle cast(const ArgInspector2 &src, return_value_policy, handle) {
|
| 62 |
-
return str(src.arg).release();
|
| 63 |
-
}
|
| 64 |
-
};
|
| 65 |
-
template <>
|
| 66 |
-
struct type_caster<ArgAlwaysConverts> {
|
| 67 |
-
public:
|
| 68 |
-
PYBIND11_TYPE_CASTER(ArgAlwaysConverts, const_name("ArgAlwaysConverts"));
|
| 69 |
-
|
| 70 |
-
bool load(handle, bool convert) { return convert; }
|
| 71 |
-
|
| 72 |
-
static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) {
|
| 73 |
-
return py::none().release();
|
| 74 |
-
}
|
| 75 |
-
};
|
| 76 |
-
} // namespace detail
|
| 77 |
-
} // namespace PYBIND11_NAMESPACE
|
| 78 |
-
|
| 79 |
-
// test_custom_caster_destruction
|
| 80 |
-
class DestructionTester {
|
| 81 |
-
public:
|
| 82 |
-
DestructionTester() { print_default_created(this); }
|
| 83 |
-
~DestructionTester() { print_destroyed(this); }
|
| 84 |
-
DestructionTester(const DestructionTester &) { print_copy_created(this); }
|
| 85 |
-
DestructionTester(DestructionTester &&) noexcept { print_move_created(this); }
|
| 86 |
-
DestructionTester &operator=(const DestructionTester &) {
|
| 87 |
-
print_copy_assigned(this);
|
| 88 |
-
return *this;
|
| 89 |
-
}
|
| 90 |
-
DestructionTester &operator=(DestructionTester &&) noexcept {
|
| 91 |
-
print_move_assigned(this);
|
| 92 |
-
return *this;
|
| 93 |
-
}
|
| 94 |
-
};
|
| 95 |
-
namespace PYBIND11_NAMESPACE {
|
| 96 |
-
namespace detail {
|
| 97 |
-
template <>
|
| 98 |
-
struct type_caster<DestructionTester> {
|
| 99 |
-
PYBIND11_TYPE_CASTER(DestructionTester, const_name("DestructionTester"));
|
| 100 |
-
bool load(handle, bool) { return true; }
|
| 101 |
-
|
| 102 |
-
static handle cast(const DestructionTester &, return_value_policy, handle) {
|
| 103 |
-
return py::bool_(true).release();
|
| 104 |
-
}
|
| 105 |
-
};
|
| 106 |
-
} // namespace detail
|
| 107 |
-
} // namespace PYBIND11_NAMESPACE
|
| 108 |
-
|
| 109 |
-
// Define type caster outside of `pybind11::detail` and then alias it.
|
| 110 |
-
namespace other_lib {
|
| 111 |
-
struct MyType {};
|
| 112 |
-
// Corrupt `py` shorthand alias for surrounding context.
|
| 113 |
-
namespace py {}
|
| 114 |
-
// Corrupt unqualified relative `pybind11` namespace.
|
| 115 |
-
namespace PYBIND11_NAMESPACE {}
|
| 116 |
-
// Correct alias.
|
| 117 |
-
namespace py_ = ::pybind11;
|
| 118 |
-
// Define caster. This is effectively no-op, we only ensure it compiles and we
|
| 119 |
-
// don't have any symbol collision when using macro mixin.
|
| 120 |
-
struct my_caster {
|
| 121 |
-
PYBIND11_TYPE_CASTER(MyType, py_::detail::const_name("MyType"));
|
| 122 |
-
bool load(py_::handle, bool) { return true; }
|
| 123 |
-
|
| 124 |
-
static py_::handle cast(const MyType &, py_::return_value_policy, py_::handle) {
|
| 125 |
-
return py_::bool_(true).release();
|
| 126 |
-
}
|
| 127 |
-
};
|
| 128 |
-
} // namespace other_lib
|
| 129 |
-
// Effectively "alias" it into correct namespace (via inheritance).
|
| 130 |
-
namespace PYBIND11_NAMESPACE {
|
| 131 |
-
namespace detail {
|
| 132 |
-
template <>
|
| 133 |
-
struct type_caster<other_lib::MyType> : public other_lib::my_caster {};
|
| 134 |
-
} // namespace detail
|
| 135 |
-
} // namespace PYBIND11_NAMESPACE
|
| 136 |
-
|
| 137 |
-
// This simply is required to compile
|
| 138 |
-
namespace ADL_issue {
|
| 139 |
-
template <typename OutStringType = std::string, typename... Args>
|
| 140 |
-
OutStringType concat(Args &&...) {
|
| 141 |
-
return OutStringType();
|
| 142 |
-
}
|
| 143 |
-
|
| 144 |
-
struct test {};
|
| 145 |
-
} // namespace ADL_issue
|
| 146 |
-
|
| 147 |
-
TEST_SUBMODULE(custom_type_casters, m) {
|
| 148 |
-
// test_custom_type_casters
|
| 149 |
-
|
| 150 |
-
// test_noconvert_args
|
| 151 |
-
//
|
| 152 |
-
// Test converting. The ArgAlwaysConverts is just there to make the first no-conversion pass
|
| 153 |
-
// fail so that our call always ends up happening via the second dispatch (the one that allows
|
| 154 |
-
// some conversion).
|
| 155 |
-
class ArgInspector {
|
| 156 |
-
public:
|
| 157 |
-
ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; }
|
| 158 |
-
std::string g(const ArgInspector1 &a,
|
| 159 |
-
const ArgInspector1 &b,
|
| 160 |
-
int c,
|
| 161 |
-
ArgInspector2 *d,
|
| 162 |
-
ArgAlwaysConverts) {
|
| 163 |
-
return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg;
|
| 164 |
-
}
|
| 165 |
-
static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; }
|
| 166 |
-
};
|
| 167 |
-
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
| 168 |
-
py::class_<ArgInspector>(m, "ArgInspector")
|
| 169 |
-
.def(py::init<>())
|
| 170 |
-
.def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts())
|
| 171 |
-
.def("g",
|
| 172 |
-
&ArgInspector::g,
|
| 173 |
-
"a"_a.noconvert(),
|
| 174 |
-
"b"_a,
|
| 175 |
-
"c"_a.noconvert() = 13,
|
| 176 |
-
"d"_a = ArgInspector2(),
|
| 177 |
-
py::arg() = ArgAlwaysConverts())
|
| 178 |
-
.def_static("h", &ArgInspector::h, py::arg{}.noconvert(), py::arg() = ArgAlwaysConverts());
|
| 179 |
-
m.def(
|
| 180 |
-
"arg_inspect_func",
|
| 181 |
-
[](const ArgInspector2 &a, const ArgInspector1 &b, ArgAlwaysConverts) {
|
| 182 |
-
return a.arg + "\n" + b.arg;
|
| 183 |
-
},
|
| 184 |
-
py::arg{}.noconvert(false),
|
| 185 |
-
py::arg_v(nullptr, ArgInspector1()).noconvert(true),
|
| 186 |
-
py::arg() = ArgAlwaysConverts());
|
| 187 |
-
|
| 188 |
-
m.def(
|
| 189 |
-
"floats_preferred", [](double f) { return 0.5 * f; }, "f"_a);
|
| 190 |
-
m.def(
|
| 191 |
-
"floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert());
|
| 192 |
-
m.def(
|
| 193 |
-
"ints_preferred", [](int i) { return i / 2; }, "i"_a);
|
| 194 |
-
m.def(
|
| 195 |
-
"ints_only", [](int i) { return i / 2; }, "i"_a.noconvert());
|
| 196 |
-
|
| 197 |
-
// test_custom_caster_destruction
|
| 198 |
-
// Test that `take_ownership` works on types with a custom type caster when given a pointer
|
| 199 |
-
|
| 200 |
-
// default policy: don't take ownership:
|
| 201 |
-
m.def("custom_caster_no_destroy", []() {
|
| 202 |
-
static auto *dt = new DestructionTester();
|
| 203 |
-
return dt;
|
| 204 |
-
});
|
| 205 |
-
|
| 206 |
-
m.def(
|
| 207 |
-
"custom_caster_destroy",
|
| 208 |
-
[]() { return new DestructionTester(); },
|
| 209 |
-
py::return_value_policy::take_ownership); // Takes ownership: destroy when finished
|
| 210 |
-
m.def(
|
| 211 |
-
"custom_caster_destroy_const",
|
| 212 |
-
[]() -> const DestructionTester * { return new DestructionTester(); },
|
| 213 |
-
py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction)
|
| 214 |
-
m.def("destruction_tester_cstats",
|
| 215 |
-
&ConstructorStats::get<DestructionTester>,
|
| 216 |
-
py::return_value_policy::reference);
|
| 217 |
-
|
| 218 |
-
m.def("other_lib_type", [](other_lib::MyType x) { return x; });
|
| 219 |
-
|
| 220 |
-
m.def("_adl_issue", [](const ADL_issue::test &) {});
|
| 221 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_custom_type_casters.cpp -- tests type_caster<T>
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#include "constructor_stats.h"
|
| 11 |
+
#include "pybind11_tests.h"
|
| 12 |
+
|
| 13 |
+
// py::arg/py::arg_v testing: these arguments just record their argument when invoked
|
| 14 |
+
class ArgInspector1 {
|
| 15 |
+
public:
|
| 16 |
+
std::string arg = "(default arg inspector 1)";
|
| 17 |
+
};
|
| 18 |
+
class ArgInspector2 {
|
| 19 |
+
public:
|
| 20 |
+
std::string arg = "(default arg inspector 2)";
|
| 21 |
+
};
|
| 22 |
+
class ArgAlwaysConverts {};
|
| 23 |
+
|
| 24 |
+
namespace PYBIND11_NAMESPACE {
|
| 25 |
+
namespace detail {
|
| 26 |
+
template <>
|
| 27 |
+
struct type_caster<ArgInspector1> {
|
| 28 |
+
public:
|
| 29 |
+
// Classic
|
| 30 |
+
#ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
|
| 31 |
+
PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1"));
|
| 32 |
+
#else
|
| 33 |
+
PYBIND11_TYPE_CASTER(ArgInspector1, const_name("ArgInspector1"));
|
| 34 |
+
#endif
|
| 35 |
+
|
| 36 |
+
bool load(handle src, bool convert) {
|
| 37 |
+
value.arg = "loading ArgInspector1 argument " + std::string(convert ? "WITH" : "WITHOUT")
|
| 38 |
+
+ " conversion allowed. "
|
| 39 |
+
"Argument value = "
|
| 40 |
+
+ (std::string) str(src);
|
| 41 |
+
return true;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
static handle cast(const ArgInspector1 &src, return_value_policy, handle) {
|
| 45 |
+
return str(src.arg).release();
|
| 46 |
+
}
|
| 47 |
+
};
|
| 48 |
+
template <>
|
| 49 |
+
struct type_caster<ArgInspector2> {
|
| 50 |
+
public:
|
| 51 |
+
PYBIND11_TYPE_CASTER(ArgInspector2, const_name("ArgInspector2"));
|
| 52 |
+
|
| 53 |
+
bool load(handle src, bool convert) {
|
| 54 |
+
value.arg = "loading ArgInspector2 argument " + std::string(convert ? "WITH" : "WITHOUT")
|
| 55 |
+
+ " conversion allowed. "
|
| 56 |
+
"Argument value = "
|
| 57 |
+
+ (std::string) str(src);
|
| 58 |
+
return true;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
static handle cast(const ArgInspector2 &src, return_value_policy, handle) {
|
| 62 |
+
return str(src.arg).release();
|
| 63 |
+
}
|
| 64 |
+
};
|
| 65 |
+
template <>
|
| 66 |
+
struct type_caster<ArgAlwaysConverts> {
|
| 67 |
+
public:
|
| 68 |
+
PYBIND11_TYPE_CASTER(ArgAlwaysConverts, const_name("ArgAlwaysConverts"));
|
| 69 |
+
|
| 70 |
+
bool load(handle, bool convert) { return convert; }
|
| 71 |
+
|
| 72 |
+
static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) {
|
| 73 |
+
return py::none().release();
|
| 74 |
+
}
|
| 75 |
+
};
|
| 76 |
+
} // namespace detail
|
| 77 |
+
} // namespace PYBIND11_NAMESPACE
|
| 78 |
+
|
| 79 |
+
// test_custom_caster_destruction
|
| 80 |
+
class DestructionTester {
|
| 81 |
+
public:
|
| 82 |
+
DestructionTester() { print_default_created(this); }
|
| 83 |
+
~DestructionTester() { print_destroyed(this); }
|
| 84 |
+
DestructionTester(const DestructionTester &) { print_copy_created(this); }
|
| 85 |
+
DestructionTester(DestructionTester &&) noexcept { print_move_created(this); }
|
| 86 |
+
DestructionTester &operator=(const DestructionTester &) {
|
| 87 |
+
print_copy_assigned(this);
|
| 88 |
+
return *this;
|
| 89 |
+
}
|
| 90 |
+
DestructionTester &operator=(DestructionTester &&) noexcept {
|
| 91 |
+
print_move_assigned(this);
|
| 92 |
+
return *this;
|
| 93 |
+
}
|
| 94 |
+
};
|
| 95 |
+
namespace PYBIND11_NAMESPACE {
|
| 96 |
+
namespace detail {
|
| 97 |
+
template <>
|
| 98 |
+
struct type_caster<DestructionTester> {
|
| 99 |
+
PYBIND11_TYPE_CASTER(DestructionTester, const_name("DestructionTester"));
|
| 100 |
+
bool load(handle, bool) { return true; }
|
| 101 |
+
|
| 102 |
+
static handle cast(const DestructionTester &, return_value_policy, handle) {
|
| 103 |
+
return py::bool_(true).release();
|
| 104 |
+
}
|
| 105 |
+
};
|
| 106 |
+
} // namespace detail
|
| 107 |
+
} // namespace PYBIND11_NAMESPACE
|
| 108 |
+
|
| 109 |
+
// Define type caster outside of `pybind11::detail` and then alias it.
|
| 110 |
+
namespace other_lib {
|
| 111 |
+
struct MyType {};
|
| 112 |
+
// Corrupt `py` shorthand alias for surrounding context.
|
| 113 |
+
namespace py {}
|
| 114 |
+
// Corrupt unqualified relative `pybind11` namespace.
|
| 115 |
+
namespace PYBIND11_NAMESPACE {}
|
| 116 |
+
// Correct alias.
|
| 117 |
+
namespace py_ = ::pybind11;
|
| 118 |
+
// Define caster. This is effectively no-op, we only ensure it compiles and we
|
| 119 |
+
// don't have any symbol collision when using macro mixin.
|
| 120 |
+
struct my_caster {
|
| 121 |
+
PYBIND11_TYPE_CASTER(MyType, py_::detail::const_name("MyType"));
|
| 122 |
+
bool load(py_::handle, bool) { return true; }
|
| 123 |
+
|
| 124 |
+
static py_::handle cast(const MyType &, py_::return_value_policy, py_::handle) {
|
| 125 |
+
return py_::bool_(true).release();
|
| 126 |
+
}
|
| 127 |
+
};
|
| 128 |
+
} // namespace other_lib
|
| 129 |
+
// Effectively "alias" it into correct namespace (via inheritance).
|
| 130 |
+
namespace PYBIND11_NAMESPACE {
|
| 131 |
+
namespace detail {
|
| 132 |
+
template <>
|
| 133 |
+
struct type_caster<other_lib::MyType> : public other_lib::my_caster {};
|
| 134 |
+
} // namespace detail
|
| 135 |
+
} // namespace PYBIND11_NAMESPACE
|
| 136 |
+
|
| 137 |
+
// This simply is required to compile
|
| 138 |
+
namespace ADL_issue {
|
| 139 |
+
template <typename OutStringType = std::string, typename... Args>
|
| 140 |
+
OutStringType concat(Args &&...) {
|
| 141 |
+
return OutStringType();
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
struct test {};
|
| 145 |
+
} // namespace ADL_issue
|
| 146 |
+
|
| 147 |
+
TEST_SUBMODULE(custom_type_casters, m) {
|
| 148 |
+
// test_custom_type_casters
|
| 149 |
+
|
| 150 |
+
// test_noconvert_args
|
| 151 |
+
//
|
| 152 |
+
// Test converting. The ArgAlwaysConverts is just there to make the first no-conversion pass
|
| 153 |
+
// fail so that our call always ends up happening via the second dispatch (the one that allows
|
| 154 |
+
// some conversion).
|
| 155 |
+
class ArgInspector {
|
| 156 |
+
public:
|
| 157 |
+
ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; }
|
| 158 |
+
std::string g(const ArgInspector1 &a,
|
| 159 |
+
const ArgInspector1 &b,
|
| 160 |
+
int c,
|
| 161 |
+
ArgInspector2 *d,
|
| 162 |
+
ArgAlwaysConverts) {
|
| 163 |
+
return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg;
|
| 164 |
+
}
|
| 165 |
+
static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; }
|
| 166 |
+
};
|
| 167 |
+
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
| 168 |
+
py::class_<ArgInspector>(m, "ArgInspector")
|
| 169 |
+
.def(py::init<>())
|
| 170 |
+
.def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts())
|
| 171 |
+
.def("g",
|
| 172 |
+
&ArgInspector::g,
|
| 173 |
+
"a"_a.noconvert(),
|
| 174 |
+
"b"_a,
|
| 175 |
+
"c"_a.noconvert() = 13,
|
| 176 |
+
"d"_a = ArgInspector2(),
|
| 177 |
+
py::arg() = ArgAlwaysConverts())
|
| 178 |
+
.def_static("h", &ArgInspector::h, py::arg{}.noconvert(), py::arg() = ArgAlwaysConverts());
|
| 179 |
+
m.def(
|
| 180 |
+
"arg_inspect_func",
|
| 181 |
+
[](const ArgInspector2 &a, const ArgInspector1 &b, ArgAlwaysConverts) {
|
| 182 |
+
return a.arg + "\n" + b.arg;
|
| 183 |
+
},
|
| 184 |
+
py::arg{}.noconvert(false),
|
| 185 |
+
py::arg_v(nullptr, ArgInspector1()).noconvert(true),
|
| 186 |
+
py::arg() = ArgAlwaysConverts());
|
| 187 |
+
|
| 188 |
+
m.def(
|
| 189 |
+
"floats_preferred", [](double f) { return 0.5 * f; }, "f"_a);
|
| 190 |
+
m.def(
|
| 191 |
+
"floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert());
|
| 192 |
+
m.def(
|
| 193 |
+
"ints_preferred", [](int i) { return i / 2; }, "i"_a);
|
| 194 |
+
m.def(
|
| 195 |
+
"ints_only", [](int i) { return i / 2; }, "i"_a.noconvert());
|
| 196 |
+
|
| 197 |
+
// test_custom_caster_destruction
|
| 198 |
+
// Test that `take_ownership` works on types with a custom type caster when given a pointer
|
| 199 |
+
|
| 200 |
+
// default policy: don't take ownership:
|
| 201 |
+
m.def("custom_caster_no_destroy", []() {
|
| 202 |
+
static auto *dt = new DestructionTester();
|
| 203 |
+
return dt;
|
| 204 |
+
});
|
| 205 |
+
|
| 206 |
+
m.def(
|
| 207 |
+
"custom_caster_destroy",
|
| 208 |
+
[]() { return new DestructionTester(); },
|
| 209 |
+
py::return_value_policy::take_ownership); // Takes ownership: destroy when finished
|
| 210 |
+
m.def(
|
| 211 |
+
"custom_caster_destroy_const",
|
| 212 |
+
[]() -> const DestructionTester * { return new DestructionTester(); },
|
| 213 |
+
py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction)
|
| 214 |
+
m.def("destruction_tester_cstats",
|
| 215 |
+
&ConstructorStats::get<DestructionTester>,
|
| 216 |
+
py::return_value_policy::reference);
|
| 217 |
+
|
| 218 |
+
m.def("other_lib_type", [](other_lib::MyType x) { return x; });
|
| 219 |
+
|
| 220 |
+
m.def("_adl_issue", [](const ADL_issue::test &) {});
|
| 221 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_custom_type_casters.py
CHANGED
|
@@ -1,122 +1,122 @@
|
|
| 1 |
-
import pytest
|
| 2 |
-
|
| 3 |
-
from pybind11_tests import custom_type_casters as m
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
def test_noconvert_args(msg):
|
| 7 |
-
a = m.ArgInspector()
|
| 8 |
-
assert (
|
| 9 |
-
msg(a.f("hi"))
|
| 10 |
-
== """
|
| 11 |
-
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
|
| 12 |
-
"""
|
| 13 |
-
)
|
| 14 |
-
assert (
|
| 15 |
-
msg(a.g("this is a", "this is b"))
|
| 16 |
-
== """
|
| 17 |
-
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
|
| 18 |
-
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
| 19 |
-
13
|
| 20 |
-
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
| 21 |
-
"""
|
| 22 |
-
)
|
| 23 |
-
assert (
|
| 24 |
-
msg(a.g("this is a", "this is b", 42))
|
| 25 |
-
== """
|
| 26 |
-
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
|
| 27 |
-
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
| 28 |
-
42
|
| 29 |
-
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
| 30 |
-
"""
|
| 31 |
-
)
|
| 32 |
-
assert (
|
| 33 |
-
msg(a.g("this is a", "this is b", 42, "this is d"))
|
| 34 |
-
== """
|
| 35 |
-
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
|
| 36 |
-
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
| 37 |
-
42
|
| 38 |
-
loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d
|
| 39 |
-
"""
|
| 40 |
-
)
|
| 41 |
-
assert (
|
| 42 |
-
a.h("arg 1")
|
| 43 |
-
== "loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1"
|
| 44 |
-
)
|
| 45 |
-
assert (
|
| 46 |
-
msg(m.arg_inspect_func("A1", "A2"))
|
| 47 |
-
== """
|
| 48 |
-
loading ArgInspector2 argument WITH conversion allowed. Argument value = A1
|
| 49 |
-
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
|
| 50 |
-
"""
|
| 51 |
-
)
|
| 52 |
-
|
| 53 |
-
assert m.floats_preferred(4) == 2.0
|
| 54 |
-
assert m.floats_only(4.0) == 2.0
|
| 55 |
-
with pytest.raises(TypeError) as excinfo:
|
| 56 |
-
m.floats_only(4)
|
| 57 |
-
assert (
|
| 58 |
-
msg(excinfo.value)
|
| 59 |
-
== """
|
| 60 |
-
floats_only(): incompatible function arguments. The following argument types are supported:
|
| 61 |
-
1. (f: float) -> float
|
| 62 |
-
|
| 63 |
-
Invoked with: 4
|
| 64 |
-
"""
|
| 65 |
-
)
|
| 66 |
-
|
| 67 |
-
assert m.ints_preferred(4) == 2
|
| 68 |
-
assert m.ints_preferred(True) == 0
|
| 69 |
-
with pytest.raises(TypeError) as excinfo:
|
| 70 |
-
m.ints_preferred(4.0)
|
| 71 |
-
assert (
|
| 72 |
-
msg(excinfo.value)
|
| 73 |
-
== """
|
| 74 |
-
ints_preferred(): incompatible function arguments. The following argument types are supported:
|
| 75 |
-
1. (i: int) -> int
|
| 76 |
-
|
| 77 |
-
Invoked with: 4.0
|
| 78 |
-
"""
|
| 79 |
-
)
|
| 80 |
-
|
| 81 |
-
assert m.ints_only(4) == 2
|
| 82 |
-
with pytest.raises(TypeError) as excinfo:
|
| 83 |
-
m.ints_only(4.0)
|
| 84 |
-
assert (
|
| 85 |
-
msg(excinfo.value)
|
| 86 |
-
== """
|
| 87 |
-
ints_only(): incompatible function arguments. The following argument types are supported:
|
| 88 |
-
1. (i: int) -> int
|
| 89 |
-
|
| 90 |
-
Invoked with: 4.0
|
| 91 |
-
"""
|
| 92 |
-
)
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
def test_custom_caster_destruction():
|
| 96 |
-
"""Tests that returning a pointer to a type that gets converted with a custom type caster gets
|
| 97 |
-
destroyed when the function has py::return_value_policy::take_ownership policy applied.
|
| 98 |
-
"""
|
| 99 |
-
|
| 100 |
-
cstats = m.destruction_tester_cstats()
|
| 101 |
-
# This one *doesn't* have take_ownership: the pointer should be used but not destroyed:
|
| 102 |
-
z = m.custom_caster_no_destroy()
|
| 103 |
-
assert cstats.alive() == 1
|
| 104 |
-
assert cstats.default_constructions == 1
|
| 105 |
-
assert z
|
| 106 |
-
|
| 107 |
-
# take_ownership applied: this constructs a new object, casts it, then destroys it:
|
| 108 |
-
z = m.custom_caster_destroy()
|
| 109 |
-
assert z
|
| 110 |
-
assert cstats.default_constructions == 2
|
| 111 |
-
|
| 112 |
-
# Same, but with a const pointer return (which should *not* inhibit destruction):
|
| 113 |
-
z = m.custom_caster_destroy_const()
|
| 114 |
-
assert z
|
| 115 |
-
assert cstats.default_constructions == 3
|
| 116 |
-
|
| 117 |
-
# Make sure we still only have the original object (from ..._no_destroy()) alive:
|
| 118 |
-
assert cstats.alive() == 1
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
def test_custom_caster_other_lib():
|
| 122 |
-
assert m.other_lib_type(True)
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
from pybind11_tests import custom_type_casters as m
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def test_noconvert_args(msg):
|
| 7 |
+
a = m.ArgInspector()
|
| 8 |
+
assert (
|
| 9 |
+
msg(a.f("hi"))
|
| 10 |
+
== """
|
| 11 |
+
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
|
| 12 |
+
"""
|
| 13 |
+
)
|
| 14 |
+
assert (
|
| 15 |
+
msg(a.g("this is a", "this is b"))
|
| 16 |
+
== """
|
| 17 |
+
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
|
| 18 |
+
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
| 19 |
+
13
|
| 20 |
+
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
| 21 |
+
"""
|
| 22 |
+
)
|
| 23 |
+
assert (
|
| 24 |
+
msg(a.g("this is a", "this is b", 42))
|
| 25 |
+
== """
|
| 26 |
+
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
|
| 27 |
+
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
| 28 |
+
42
|
| 29 |
+
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
| 30 |
+
"""
|
| 31 |
+
)
|
| 32 |
+
assert (
|
| 33 |
+
msg(a.g("this is a", "this is b", 42, "this is d"))
|
| 34 |
+
== """
|
| 35 |
+
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
|
| 36 |
+
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
| 37 |
+
42
|
| 38 |
+
loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d
|
| 39 |
+
"""
|
| 40 |
+
)
|
| 41 |
+
assert (
|
| 42 |
+
a.h("arg 1")
|
| 43 |
+
== "loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1"
|
| 44 |
+
)
|
| 45 |
+
assert (
|
| 46 |
+
msg(m.arg_inspect_func("A1", "A2"))
|
| 47 |
+
== """
|
| 48 |
+
loading ArgInspector2 argument WITH conversion allowed. Argument value = A1
|
| 49 |
+
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
|
| 50 |
+
"""
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
assert m.floats_preferred(4) == 2.0
|
| 54 |
+
assert m.floats_only(4.0) == 2.0
|
| 55 |
+
with pytest.raises(TypeError) as excinfo:
|
| 56 |
+
m.floats_only(4)
|
| 57 |
+
assert (
|
| 58 |
+
msg(excinfo.value)
|
| 59 |
+
== """
|
| 60 |
+
floats_only(): incompatible function arguments. The following argument types are supported:
|
| 61 |
+
1. (f: float) -> float
|
| 62 |
+
|
| 63 |
+
Invoked with: 4
|
| 64 |
+
"""
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
assert m.ints_preferred(4) == 2
|
| 68 |
+
assert m.ints_preferred(True) == 0
|
| 69 |
+
with pytest.raises(TypeError) as excinfo:
|
| 70 |
+
m.ints_preferred(4.0)
|
| 71 |
+
assert (
|
| 72 |
+
msg(excinfo.value)
|
| 73 |
+
== """
|
| 74 |
+
ints_preferred(): incompatible function arguments. The following argument types are supported:
|
| 75 |
+
1. (i: int) -> int
|
| 76 |
+
|
| 77 |
+
Invoked with: 4.0
|
| 78 |
+
"""
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
assert m.ints_only(4) == 2
|
| 82 |
+
with pytest.raises(TypeError) as excinfo:
|
| 83 |
+
m.ints_only(4.0)
|
| 84 |
+
assert (
|
| 85 |
+
msg(excinfo.value)
|
| 86 |
+
== """
|
| 87 |
+
ints_only(): incompatible function arguments. The following argument types are supported:
|
| 88 |
+
1. (i: int) -> int
|
| 89 |
+
|
| 90 |
+
Invoked with: 4.0
|
| 91 |
+
"""
|
| 92 |
+
)
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def test_custom_caster_destruction():
|
| 96 |
+
"""Tests that returning a pointer to a type that gets converted with a custom type caster gets
|
| 97 |
+
destroyed when the function has py::return_value_policy::take_ownership policy applied.
|
| 98 |
+
"""
|
| 99 |
+
|
| 100 |
+
cstats = m.destruction_tester_cstats()
|
| 101 |
+
# This one *doesn't* have take_ownership: the pointer should be used but not destroyed:
|
| 102 |
+
z = m.custom_caster_no_destroy()
|
| 103 |
+
assert cstats.alive() == 1
|
| 104 |
+
assert cstats.default_constructions == 1
|
| 105 |
+
assert z
|
| 106 |
+
|
| 107 |
+
# take_ownership applied: this constructs a new object, casts it, then destroys it:
|
| 108 |
+
z = m.custom_caster_destroy()
|
| 109 |
+
assert z
|
| 110 |
+
assert cstats.default_constructions == 2
|
| 111 |
+
|
| 112 |
+
# Same, but with a const pointer return (which should *not* inhibit destruction):
|
| 113 |
+
z = m.custom_caster_destroy_const()
|
| 114 |
+
assert z
|
| 115 |
+
assert cstats.default_constructions == 3
|
| 116 |
+
|
| 117 |
+
# Make sure we still only have the original object (from ..._no_destroy()) alive:
|
| 118 |
+
assert cstats.alive() == 1
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def test_custom_caster_other_lib():
|
| 122 |
+
assert m.other_lib_type(True)
|
third_party/CityFlow/extern/pybind11/tests/test_custom_type_setup.cpp
CHANGED
|
@@ -1,41 +1,41 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_custom_type_setup.cpp -- Tests `pybind11::custom_type_setup`
|
| 3 |
-
|
| 4 |
-
Copyright (c) Google LLC
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#include <pybind11/pybind11.h>
|
| 11 |
-
|
| 12 |
-
#include "pybind11_tests.h"
|
| 13 |
-
|
| 14 |
-
namespace py = pybind11;
|
| 15 |
-
|
| 16 |
-
namespace {
|
| 17 |
-
|
| 18 |
-
struct OwnsPythonObjects {
|
| 19 |
-
py::object value = py::none();
|
| 20 |
-
};
|
| 21 |
-
} // namespace
|
| 22 |
-
|
| 23 |
-
TEST_SUBMODULE(custom_type_setup, m) {
|
| 24 |
-
py::class_<OwnsPythonObjects> cls(
|
| 25 |
-
m, "OwnsPythonObjects", py::custom_type_setup([](PyHeapTypeObject *heap_type) {
|
| 26 |
-
auto *type = &heap_type->ht_type;
|
| 27 |
-
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
| 28 |
-
type->tp_traverse = [](PyObject *self_base, visitproc visit, void *arg) {
|
| 29 |
-
auto &self = py::cast<OwnsPythonObjects &>(py::handle(self_base));
|
| 30 |
-
Py_VISIT(self.value.ptr());
|
| 31 |
-
return 0;
|
| 32 |
-
};
|
| 33 |
-
type->tp_clear = [](PyObject *self_base) {
|
| 34 |
-
auto &self = py::cast<OwnsPythonObjects &>(py::handle(self_base));
|
| 35 |
-
self.value = py::none();
|
| 36 |
-
return 0;
|
| 37 |
-
};
|
| 38 |
-
}));
|
| 39 |
-
cls.def(py::init<>());
|
| 40 |
-
cls.def_readwrite("value", &OwnsPythonObjects::value);
|
| 41 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_custom_type_setup.cpp -- Tests `pybind11::custom_type_setup`
|
| 3 |
+
|
| 4 |
+
Copyright (c) Google LLC
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#include <pybind11/pybind11.h>
|
| 11 |
+
|
| 12 |
+
#include "pybind11_tests.h"
|
| 13 |
+
|
| 14 |
+
namespace py = pybind11;
|
| 15 |
+
|
| 16 |
+
namespace {
|
| 17 |
+
|
| 18 |
+
struct OwnsPythonObjects {
|
| 19 |
+
py::object value = py::none();
|
| 20 |
+
};
|
| 21 |
+
} // namespace
|
| 22 |
+
|
| 23 |
+
TEST_SUBMODULE(custom_type_setup, m) {
|
| 24 |
+
py::class_<OwnsPythonObjects> cls(
|
| 25 |
+
m, "OwnsPythonObjects", py::custom_type_setup([](PyHeapTypeObject *heap_type) {
|
| 26 |
+
auto *type = &heap_type->ht_type;
|
| 27 |
+
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
| 28 |
+
type->tp_traverse = [](PyObject *self_base, visitproc visit, void *arg) {
|
| 29 |
+
auto &self = py::cast<OwnsPythonObjects &>(py::handle(self_base));
|
| 30 |
+
Py_VISIT(self.value.ptr());
|
| 31 |
+
return 0;
|
| 32 |
+
};
|
| 33 |
+
type->tp_clear = [](PyObject *self_base) {
|
| 34 |
+
auto &self = py::cast<OwnsPythonObjects &>(py::handle(self_base));
|
| 35 |
+
self.value = py::none();
|
| 36 |
+
return 0;
|
| 37 |
+
};
|
| 38 |
+
}));
|
| 39 |
+
cls.def(py::init<>());
|
| 40 |
+
cls.def_readwrite("value", &OwnsPythonObjects::value);
|
| 41 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_custom_type_setup.py
CHANGED
|
@@ -1,48 +1,48 @@
|
|
| 1 |
-
import gc
|
| 2 |
-
import weakref
|
| 3 |
-
|
| 4 |
-
import pytest
|
| 5 |
-
|
| 6 |
-
import env # noqa: F401
|
| 7 |
-
from pybind11_tests import custom_type_setup as m
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
@pytest.fixture()
|
| 11 |
-
def gc_tester():
|
| 12 |
-
"""Tests that an object is garbage collected.
|
| 13 |
-
|
| 14 |
-
Assumes that any unreferenced objects are fully collected after calling
|
| 15 |
-
`gc.collect()`. That is true on CPython, but does not appear to reliably
|
| 16 |
-
hold on PyPy.
|
| 17 |
-
"""
|
| 18 |
-
|
| 19 |
-
weak_refs = []
|
| 20 |
-
|
| 21 |
-
def add_ref(obj):
|
| 22 |
-
# PyPy does not support `gc.is_tracked`.
|
| 23 |
-
if hasattr(gc, "is_tracked"):
|
| 24 |
-
assert gc.is_tracked(obj)
|
| 25 |
-
weak_refs.append(weakref.ref(obj))
|
| 26 |
-
|
| 27 |
-
yield add_ref
|
| 28 |
-
|
| 29 |
-
gc.collect()
|
| 30 |
-
for ref in weak_refs:
|
| 31 |
-
assert ref() is None
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
# PyPy does not seem to reliably garbage collect.
|
| 35 |
-
@pytest.mark.skipif("env.PYPY")
|
| 36 |
-
def test_self_cycle(gc_tester):
|
| 37 |
-
obj = m.OwnsPythonObjects()
|
| 38 |
-
obj.value = obj
|
| 39 |
-
gc_tester(obj)
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
# PyPy does not seem to reliably garbage collect.
|
| 43 |
-
@pytest.mark.skipif("env.PYPY")
|
| 44 |
-
def test_indirect_cycle(gc_tester):
|
| 45 |
-
obj = m.OwnsPythonObjects()
|
| 46 |
-
obj_list = [obj]
|
| 47 |
-
obj.value = obj_list
|
| 48 |
-
gc_tester(obj)
|
|
|
|
| 1 |
+
import gc
|
| 2 |
+
import weakref
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
import env # noqa: F401
|
| 7 |
+
from pybind11_tests import custom_type_setup as m
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@pytest.fixture()
|
| 11 |
+
def gc_tester():
|
| 12 |
+
"""Tests that an object is garbage collected.
|
| 13 |
+
|
| 14 |
+
Assumes that any unreferenced objects are fully collected after calling
|
| 15 |
+
`gc.collect()`. That is true on CPython, but does not appear to reliably
|
| 16 |
+
hold on PyPy.
|
| 17 |
+
"""
|
| 18 |
+
|
| 19 |
+
weak_refs = []
|
| 20 |
+
|
| 21 |
+
def add_ref(obj):
|
| 22 |
+
# PyPy does not support `gc.is_tracked`.
|
| 23 |
+
if hasattr(gc, "is_tracked"):
|
| 24 |
+
assert gc.is_tracked(obj)
|
| 25 |
+
weak_refs.append(weakref.ref(obj))
|
| 26 |
+
|
| 27 |
+
yield add_ref
|
| 28 |
+
|
| 29 |
+
gc.collect()
|
| 30 |
+
for ref in weak_refs:
|
| 31 |
+
assert ref() is None
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
# PyPy does not seem to reliably garbage collect.
|
| 35 |
+
@pytest.mark.skipif("env.PYPY")
|
| 36 |
+
def test_self_cycle(gc_tester):
|
| 37 |
+
obj = m.OwnsPythonObjects()
|
| 38 |
+
obj.value = obj
|
| 39 |
+
gc_tester(obj)
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
# PyPy does not seem to reliably garbage collect.
|
| 43 |
+
@pytest.mark.skipif("env.PYPY")
|
| 44 |
+
def test_indirect_cycle(gc_tester):
|
| 45 |
+
obj = m.OwnsPythonObjects()
|
| 46 |
+
obj_list = [obj]
|
| 47 |
+
obj.value = obj_list
|
| 48 |
+
gc_tester(obj)
|
third_party/CityFlow/extern/pybind11/tests/test_docstring_options.cpp
CHANGED
|
@@ -1,141 +1,141 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_docstring_options.cpp -- generation of docstrings and signatures
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#include "pybind11_tests.h"
|
| 11 |
-
|
| 12 |
-
TEST_SUBMODULE(docstring_options, m) {
|
| 13 |
-
// test_docstring_options
|
| 14 |
-
{
|
| 15 |
-
py::options options;
|
| 16 |
-
options.disable_function_signatures();
|
| 17 |
-
|
| 18 |
-
m.def(
|
| 19 |
-
"test_function1", [](int, int) {}, py::arg("a"), py::arg("b"));
|
| 20 |
-
m.def(
|
| 21 |
-
"test_function2", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
| 22 |
-
|
| 23 |
-
m.def(
|
| 24 |
-
"test_overloaded1", [](int) {}, py::arg("i"), "Overload docstring");
|
| 25 |
-
m.def(
|
| 26 |
-
"test_overloaded1", [](double) {}, py::arg("d"));
|
| 27 |
-
|
| 28 |
-
m.def(
|
| 29 |
-
"test_overloaded2", [](int) {}, py::arg("i"), "overload docstring 1");
|
| 30 |
-
m.def(
|
| 31 |
-
"test_overloaded2", [](double) {}, py::arg("d"), "overload docstring 2");
|
| 32 |
-
|
| 33 |
-
m.def(
|
| 34 |
-
"test_overloaded3", [](int) {}, py::arg("i"));
|
| 35 |
-
m.def(
|
| 36 |
-
"test_overloaded3", [](double) {}, py::arg("d"), "Overload docstr");
|
| 37 |
-
|
| 38 |
-
options.enable_function_signatures();
|
| 39 |
-
|
| 40 |
-
m.def(
|
| 41 |
-
"test_function3", [](int, int) {}, py::arg("a"), py::arg("b"));
|
| 42 |
-
m.def(
|
| 43 |
-
"test_function4", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
| 44 |
-
|
| 45 |
-
options.disable_function_signatures().disable_user_defined_docstrings();
|
| 46 |
-
|
| 47 |
-
m.def(
|
| 48 |
-
"test_function5", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
| 49 |
-
|
| 50 |
-
{
|
| 51 |
-
py::options nested_options;
|
| 52 |
-
nested_options.enable_user_defined_docstrings();
|
| 53 |
-
m.def(
|
| 54 |
-
"test_function6",
|
| 55 |
-
[](int, int) {},
|
| 56 |
-
py::arg("a"),
|
| 57 |
-
py::arg("b"),
|
| 58 |
-
"A custom docstring");
|
| 59 |
-
}
|
| 60 |
-
}
|
| 61 |
-
|
| 62 |
-
m.def(
|
| 63 |
-
"test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
| 64 |
-
|
| 65 |
-
{
|
| 66 |
-
py::options options;
|
| 67 |
-
options.disable_user_defined_docstrings();
|
| 68 |
-
options.disable_function_signatures();
|
| 69 |
-
|
| 70 |
-
m.def("test_function8", []() {});
|
| 71 |
-
}
|
| 72 |
-
|
| 73 |
-
{
|
| 74 |
-
py::options options;
|
| 75 |
-
options.disable_user_defined_docstrings();
|
| 76 |
-
|
| 77 |
-
struct DocstringTestFoo {
|
| 78 |
-
int value;
|
| 79 |
-
void setValue(int v) { value = v; }
|
| 80 |
-
int getValue() const { return value; }
|
| 81 |
-
};
|
| 82 |
-
py::class_<DocstringTestFoo>(m, "DocstringTestFoo", "This is a class docstring")
|
| 83 |
-
.def_property("value_prop",
|
| 84 |
-
&DocstringTestFoo::getValue,
|
| 85 |
-
&DocstringTestFoo::setValue,
|
| 86 |
-
"This is a property docstring");
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
{
|
| 90 |
-
enum class DocstringTestEnum1 { Member1, Member2 };
|
| 91 |
-
|
| 92 |
-
py::enum_<DocstringTestEnum1>(m, "DocstringTestEnum1", "Enum docstring")
|
| 93 |
-
.value("Member1", DocstringTestEnum1::Member1)
|
| 94 |
-
.value("Member2", DocstringTestEnum1::Member2);
|
| 95 |
-
}
|
| 96 |
-
|
| 97 |
-
{
|
| 98 |
-
py::options options;
|
| 99 |
-
options.enable_enum_members_docstring();
|
| 100 |
-
|
| 101 |
-
enum class DocstringTestEnum2 { Member1, Member2 };
|
| 102 |
-
|
| 103 |
-
py::enum_<DocstringTestEnum2>(m, "DocstringTestEnum2", "Enum docstring")
|
| 104 |
-
.value("Member1", DocstringTestEnum2::Member1)
|
| 105 |
-
.value("Member2", DocstringTestEnum2::Member2);
|
| 106 |
-
}
|
| 107 |
-
|
| 108 |
-
{
|
| 109 |
-
py::options options;
|
| 110 |
-
options.disable_enum_members_docstring();
|
| 111 |
-
|
| 112 |
-
enum class DocstringTestEnum3 { Member1, Member2 };
|
| 113 |
-
|
| 114 |
-
py::enum_<DocstringTestEnum3>(m, "DocstringTestEnum3", "Enum docstring")
|
| 115 |
-
.value("Member1", DocstringTestEnum3::Member1)
|
| 116 |
-
.value("Member2", DocstringTestEnum3::Member2);
|
| 117 |
-
}
|
| 118 |
-
|
| 119 |
-
{
|
| 120 |
-
py::options options;
|
| 121 |
-
options.disable_user_defined_docstrings();
|
| 122 |
-
|
| 123 |
-
enum class DocstringTestEnum4 { Member1, Member2 };
|
| 124 |
-
|
| 125 |
-
py::enum_<DocstringTestEnum4>(m, "DocstringTestEnum4", "Enum docstring")
|
| 126 |
-
.value("Member1", DocstringTestEnum4::Member1)
|
| 127 |
-
.value("Member2", DocstringTestEnum4::Member2);
|
| 128 |
-
}
|
| 129 |
-
|
| 130 |
-
{
|
| 131 |
-
py::options options;
|
| 132 |
-
options.disable_user_defined_docstrings();
|
| 133 |
-
options.disable_enum_members_docstring();
|
| 134 |
-
|
| 135 |
-
enum class DocstringTestEnum5 { Member1, Member2 };
|
| 136 |
-
|
| 137 |
-
py::enum_<DocstringTestEnum5>(m, "DocstringTestEnum5", "Enum docstring")
|
| 138 |
-
.value("Member1", DocstringTestEnum5::Member1)
|
| 139 |
-
.value("Member2", DocstringTestEnum5::Member2);
|
| 140 |
-
}
|
| 141 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_docstring_options.cpp -- generation of docstrings and signatures
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#include "pybind11_tests.h"
|
| 11 |
+
|
| 12 |
+
TEST_SUBMODULE(docstring_options, m) {
|
| 13 |
+
// test_docstring_options
|
| 14 |
+
{
|
| 15 |
+
py::options options;
|
| 16 |
+
options.disable_function_signatures();
|
| 17 |
+
|
| 18 |
+
m.def(
|
| 19 |
+
"test_function1", [](int, int) {}, py::arg("a"), py::arg("b"));
|
| 20 |
+
m.def(
|
| 21 |
+
"test_function2", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
| 22 |
+
|
| 23 |
+
m.def(
|
| 24 |
+
"test_overloaded1", [](int) {}, py::arg("i"), "Overload docstring");
|
| 25 |
+
m.def(
|
| 26 |
+
"test_overloaded1", [](double) {}, py::arg("d"));
|
| 27 |
+
|
| 28 |
+
m.def(
|
| 29 |
+
"test_overloaded2", [](int) {}, py::arg("i"), "overload docstring 1");
|
| 30 |
+
m.def(
|
| 31 |
+
"test_overloaded2", [](double) {}, py::arg("d"), "overload docstring 2");
|
| 32 |
+
|
| 33 |
+
m.def(
|
| 34 |
+
"test_overloaded3", [](int) {}, py::arg("i"));
|
| 35 |
+
m.def(
|
| 36 |
+
"test_overloaded3", [](double) {}, py::arg("d"), "Overload docstr");
|
| 37 |
+
|
| 38 |
+
options.enable_function_signatures();
|
| 39 |
+
|
| 40 |
+
m.def(
|
| 41 |
+
"test_function3", [](int, int) {}, py::arg("a"), py::arg("b"));
|
| 42 |
+
m.def(
|
| 43 |
+
"test_function4", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
| 44 |
+
|
| 45 |
+
options.disable_function_signatures().disable_user_defined_docstrings();
|
| 46 |
+
|
| 47 |
+
m.def(
|
| 48 |
+
"test_function5", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
| 49 |
+
|
| 50 |
+
{
|
| 51 |
+
py::options nested_options;
|
| 52 |
+
nested_options.enable_user_defined_docstrings();
|
| 53 |
+
m.def(
|
| 54 |
+
"test_function6",
|
| 55 |
+
[](int, int) {},
|
| 56 |
+
py::arg("a"),
|
| 57 |
+
py::arg("b"),
|
| 58 |
+
"A custom docstring");
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
m.def(
|
| 63 |
+
"test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
| 64 |
+
|
| 65 |
+
{
|
| 66 |
+
py::options options;
|
| 67 |
+
options.disable_user_defined_docstrings();
|
| 68 |
+
options.disable_function_signatures();
|
| 69 |
+
|
| 70 |
+
m.def("test_function8", []() {});
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
{
|
| 74 |
+
py::options options;
|
| 75 |
+
options.disable_user_defined_docstrings();
|
| 76 |
+
|
| 77 |
+
struct DocstringTestFoo {
|
| 78 |
+
int value;
|
| 79 |
+
void setValue(int v) { value = v; }
|
| 80 |
+
int getValue() const { return value; }
|
| 81 |
+
};
|
| 82 |
+
py::class_<DocstringTestFoo>(m, "DocstringTestFoo", "This is a class docstring")
|
| 83 |
+
.def_property("value_prop",
|
| 84 |
+
&DocstringTestFoo::getValue,
|
| 85 |
+
&DocstringTestFoo::setValue,
|
| 86 |
+
"This is a property docstring");
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
{
|
| 90 |
+
enum class DocstringTestEnum1 { Member1, Member2 };
|
| 91 |
+
|
| 92 |
+
py::enum_<DocstringTestEnum1>(m, "DocstringTestEnum1", "Enum docstring")
|
| 93 |
+
.value("Member1", DocstringTestEnum1::Member1)
|
| 94 |
+
.value("Member2", DocstringTestEnum1::Member2);
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
{
|
| 98 |
+
py::options options;
|
| 99 |
+
options.enable_enum_members_docstring();
|
| 100 |
+
|
| 101 |
+
enum class DocstringTestEnum2 { Member1, Member2 };
|
| 102 |
+
|
| 103 |
+
py::enum_<DocstringTestEnum2>(m, "DocstringTestEnum2", "Enum docstring")
|
| 104 |
+
.value("Member1", DocstringTestEnum2::Member1)
|
| 105 |
+
.value("Member2", DocstringTestEnum2::Member2);
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
{
|
| 109 |
+
py::options options;
|
| 110 |
+
options.disable_enum_members_docstring();
|
| 111 |
+
|
| 112 |
+
enum class DocstringTestEnum3 { Member1, Member2 };
|
| 113 |
+
|
| 114 |
+
py::enum_<DocstringTestEnum3>(m, "DocstringTestEnum3", "Enum docstring")
|
| 115 |
+
.value("Member1", DocstringTestEnum3::Member1)
|
| 116 |
+
.value("Member2", DocstringTestEnum3::Member2);
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
{
|
| 120 |
+
py::options options;
|
| 121 |
+
options.disable_user_defined_docstrings();
|
| 122 |
+
|
| 123 |
+
enum class DocstringTestEnum4 { Member1, Member2 };
|
| 124 |
+
|
| 125 |
+
py::enum_<DocstringTestEnum4>(m, "DocstringTestEnum4", "Enum docstring")
|
| 126 |
+
.value("Member1", DocstringTestEnum4::Member1)
|
| 127 |
+
.value("Member2", DocstringTestEnum4::Member2);
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
{
|
| 131 |
+
py::options options;
|
| 132 |
+
options.disable_user_defined_docstrings();
|
| 133 |
+
options.disable_enum_members_docstring();
|
| 134 |
+
|
| 135 |
+
enum class DocstringTestEnum5 { Member1, Member2 };
|
| 136 |
+
|
| 137 |
+
py::enum_<DocstringTestEnum5>(m, "DocstringTestEnum5", "Enum docstring")
|
| 138 |
+
.value("Member1", DocstringTestEnum5::Member1)
|
| 139 |
+
.value("Member2", DocstringTestEnum5::Member2);
|
| 140 |
+
}
|
| 141 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_docstring_options.py
CHANGED
|
@@ -1,64 +1,64 @@
|
|
| 1 |
-
from pybind11_tests import docstring_options as m
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
def test_docstring_options():
|
| 5 |
-
# options.disable_function_signatures()
|
| 6 |
-
assert not m.test_function1.__doc__
|
| 7 |
-
|
| 8 |
-
assert m.test_function2.__doc__ == "A custom docstring"
|
| 9 |
-
|
| 10 |
-
# docstring specified on just the first overload definition:
|
| 11 |
-
assert m.test_overloaded1.__doc__ == "Overload docstring"
|
| 12 |
-
|
| 13 |
-
# docstring on both overloads:
|
| 14 |
-
assert m.test_overloaded2.__doc__ == "overload docstring 1\noverload docstring 2"
|
| 15 |
-
|
| 16 |
-
# docstring on only second overload:
|
| 17 |
-
assert m.test_overloaded3.__doc__ == "Overload docstr"
|
| 18 |
-
|
| 19 |
-
# options.enable_function_signatures()
|
| 20 |
-
assert m.test_function3.__doc__.startswith("test_function3(a: int, b: int) -> None")
|
| 21 |
-
|
| 22 |
-
assert m.test_function4.__doc__.startswith("test_function4(a: int, b: int) -> None")
|
| 23 |
-
assert m.test_function4.__doc__.endswith("A custom docstring\n")
|
| 24 |
-
|
| 25 |
-
# options.disable_function_signatures()
|
| 26 |
-
# options.disable_user_defined_docstrings()
|
| 27 |
-
assert not m.test_function5.__doc__
|
| 28 |
-
|
| 29 |
-
# nested options.enable_user_defined_docstrings()
|
| 30 |
-
assert m.test_function6.__doc__ == "A custom docstring"
|
| 31 |
-
|
| 32 |
-
# RAII destructor
|
| 33 |
-
assert m.test_function7.__doc__.startswith("test_function7(a: int, b: int) -> None")
|
| 34 |
-
assert m.test_function7.__doc__.endswith("A custom docstring\n")
|
| 35 |
-
|
| 36 |
-
# when all options are disabled, no docstring (instead of an empty one) should be generated
|
| 37 |
-
assert m.test_function8.__doc__ is None
|
| 38 |
-
|
| 39 |
-
# Suppression of user-defined docstrings for non-function objects
|
| 40 |
-
assert not m.DocstringTestFoo.__doc__
|
| 41 |
-
assert not m.DocstringTestFoo.value_prop.__doc__
|
| 42 |
-
|
| 43 |
-
# Check existig behaviour of enum docstings
|
| 44 |
-
assert (
|
| 45 |
-
m.DocstringTestEnum1.__doc__
|
| 46 |
-
== "Enum docstring\n\nMembers:\n\n Member1\n\n Member2"
|
| 47 |
-
)
|
| 48 |
-
|
| 49 |
-
# options.enable_enum_members_docstring()
|
| 50 |
-
assert (
|
| 51 |
-
m.DocstringTestEnum2.__doc__
|
| 52 |
-
== "Enum docstring\n\nMembers:\n\n Member1\n\n Member2"
|
| 53 |
-
)
|
| 54 |
-
|
| 55 |
-
# options.disable_enum_members_docstring()
|
| 56 |
-
assert m.DocstringTestEnum3.__doc__ == "Enum docstring"
|
| 57 |
-
|
| 58 |
-
# options.disable_user_defined_docstrings()
|
| 59 |
-
assert m.DocstringTestEnum4.__doc__ == "Members:\n\n Member1\n\n Member2"
|
| 60 |
-
|
| 61 |
-
# options.disable_user_defined_docstrings()
|
| 62 |
-
# options.disable_enum_members_docstring()
|
| 63 |
-
# When all options are disabled, no docstring (instead of an empty one) should be generated
|
| 64 |
-
assert m.DocstringTestEnum5.__doc__ is None
|
|
|
|
| 1 |
+
from pybind11_tests import docstring_options as m
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def test_docstring_options():
|
| 5 |
+
# options.disable_function_signatures()
|
| 6 |
+
assert not m.test_function1.__doc__
|
| 7 |
+
|
| 8 |
+
assert m.test_function2.__doc__ == "A custom docstring"
|
| 9 |
+
|
| 10 |
+
# docstring specified on just the first overload definition:
|
| 11 |
+
assert m.test_overloaded1.__doc__ == "Overload docstring"
|
| 12 |
+
|
| 13 |
+
# docstring on both overloads:
|
| 14 |
+
assert m.test_overloaded2.__doc__ == "overload docstring 1\noverload docstring 2"
|
| 15 |
+
|
| 16 |
+
# docstring on only second overload:
|
| 17 |
+
assert m.test_overloaded3.__doc__ == "Overload docstr"
|
| 18 |
+
|
| 19 |
+
# options.enable_function_signatures()
|
| 20 |
+
assert m.test_function3.__doc__.startswith("test_function3(a: int, b: int) -> None")
|
| 21 |
+
|
| 22 |
+
assert m.test_function4.__doc__.startswith("test_function4(a: int, b: int) -> None")
|
| 23 |
+
assert m.test_function4.__doc__.endswith("A custom docstring\n")
|
| 24 |
+
|
| 25 |
+
# options.disable_function_signatures()
|
| 26 |
+
# options.disable_user_defined_docstrings()
|
| 27 |
+
assert not m.test_function5.__doc__
|
| 28 |
+
|
| 29 |
+
# nested options.enable_user_defined_docstrings()
|
| 30 |
+
assert m.test_function6.__doc__ == "A custom docstring"
|
| 31 |
+
|
| 32 |
+
# RAII destructor
|
| 33 |
+
assert m.test_function7.__doc__.startswith("test_function7(a: int, b: int) -> None")
|
| 34 |
+
assert m.test_function7.__doc__.endswith("A custom docstring\n")
|
| 35 |
+
|
| 36 |
+
# when all options are disabled, no docstring (instead of an empty one) should be generated
|
| 37 |
+
assert m.test_function8.__doc__ is None
|
| 38 |
+
|
| 39 |
+
# Suppression of user-defined docstrings for non-function objects
|
| 40 |
+
assert not m.DocstringTestFoo.__doc__
|
| 41 |
+
assert not m.DocstringTestFoo.value_prop.__doc__
|
| 42 |
+
|
| 43 |
+
# Check existig behaviour of enum docstings
|
| 44 |
+
assert (
|
| 45 |
+
m.DocstringTestEnum1.__doc__
|
| 46 |
+
== "Enum docstring\n\nMembers:\n\n Member1\n\n Member2"
|
| 47 |
+
)
|
| 48 |
+
|
| 49 |
+
# options.enable_enum_members_docstring()
|
| 50 |
+
assert (
|
| 51 |
+
m.DocstringTestEnum2.__doc__
|
| 52 |
+
== "Enum docstring\n\nMembers:\n\n Member1\n\n Member2"
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
# options.disable_enum_members_docstring()
|
| 56 |
+
assert m.DocstringTestEnum3.__doc__ == "Enum docstring"
|
| 57 |
+
|
| 58 |
+
# options.disable_user_defined_docstrings()
|
| 59 |
+
assert m.DocstringTestEnum4.__doc__ == "Members:\n\n Member1\n\n Member2"
|
| 60 |
+
|
| 61 |
+
# options.disable_user_defined_docstrings()
|
| 62 |
+
# options.disable_enum_members_docstring()
|
| 63 |
+
# When all options are disabled, no docstring (instead of an empty one) should be generated
|
| 64 |
+
assert m.DocstringTestEnum5.__doc__ is None
|
third_party/CityFlow/extern/pybind11/tests/test_eigen_matrix.cpp
CHANGED
|
@@ -1,445 +1,445 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/eigen.cpp -- automatic conversion of Eigen types
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#include <pybind11/eigen/matrix.h>
|
| 11 |
-
#include <pybind11/stl.h>
|
| 12 |
-
|
| 13 |
-
#include "constructor_stats.h"
|
| 14 |
-
#include "pybind11_tests.h"
|
| 15 |
-
|
| 16 |
-
PYBIND11_WARNING_DISABLE_MSVC(4996)
|
| 17 |
-
|
| 18 |
-
#include <Eigen/Cholesky>
|
| 19 |
-
|
| 20 |
-
using MatrixXdR = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
|
| 21 |
-
|
| 22 |
-
// Sets/resets a testing reference matrix to have values of 10*r + c, where r and c are the
|
| 23 |
-
// (1-based) row/column number.
|
| 24 |
-
template <typename M>
|
| 25 |
-
void reset_ref(M &x) {
|
| 26 |
-
for (int i = 0; i < x.rows(); i++) {
|
| 27 |
-
for (int j = 0; j < x.cols(); j++) {
|
| 28 |
-
x(i, j) = 11 + 10 * i + j;
|
| 29 |
-
}
|
| 30 |
-
}
|
| 31 |
-
}
|
| 32 |
-
|
| 33 |
-
// Returns a static, column-major matrix
|
| 34 |
-
Eigen::MatrixXd &get_cm() {
|
| 35 |
-
static Eigen::MatrixXd *x;
|
| 36 |
-
if (!x) {
|
| 37 |
-
x = new Eigen::MatrixXd(3, 3);
|
| 38 |
-
reset_ref(*x);
|
| 39 |
-
}
|
| 40 |
-
return *x;
|
| 41 |
-
}
|
| 42 |
-
// Likewise, but row-major
|
| 43 |
-
MatrixXdR &get_rm() {
|
| 44 |
-
static MatrixXdR *x;
|
| 45 |
-
if (!x) {
|
| 46 |
-
x = new MatrixXdR(3, 3);
|
| 47 |
-
reset_ref(*x);
|
| 48 |
-
}
|
| 49 |
-
return *x;
|
| 50 |
-
}
|
| 51 |
-
// Resets the values of the static matrices returned by get_cm()/get_rm()
|
| 52 |
-
void reset_refs() {
|
| 53 |
-
reset_ref(get_cm());
|
| 54 |
-
reset_ref(get_rm());
|
| 55 |
-
}
|
| 56 |
-
|
| 57 |
-
// Returns element 2,1 from a matrix (used to test copy/nocopy)
|
| 58 |
-
double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); };
|
| 59 |
-
|
| 60 |
-
// Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix
|
| 61 |
-
// reference is referencing rows/columns correctly).
|
| 62 |
-
template <typename MatrixArgType>
|
| 63 |
-
Eigen::MatrixXd adjust_matrix(MatrixArgType m) {
|
| 64 |
-
Eigen::MatrixXd ret(m);
|
| 65 |
-
for (int c = 0; c < m.cols(); c++) {
|
| 66 |
-
for (int r = 0; r < m.rows(); r++) {
|
| 67 |
-
ret(r, c) += 10 * r + 100 * c; // NOLINT(clang-analyzer-core.uninitialized.Assign)
|
| 68 |
-
}
|
| 69 |
-
}
|
| 70 |
-
return ret;
|
| 71 |
-
}
|
| 72 |
-
|
| 73 |
-
struct CustomOperatorNew {
|
| 74 |
-
CustomOperatorNew() = default;
|
| 75 |
-
|
| 76 |
-
Eigen::Matrix4d a = Eigen::Matrix4d::Zero();
|
| 77 |
-
Eigen::Matrix4d b = Eigen::Matrix4d::Identity();
|
| 78 |
-
|
| 79 |
-
EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
|
| 80 |
-
};
|
| 81 |
-
|
| 82 |
-
TEST_SUBMODULE(eigen_matrix, m) {
|
| 83 |
-
using FixedMatrixR = Eigen::Matrix<float, 5, 6, Eigen::RowMajor>;
|
| 84 |
-
using FixedMatrixC = Eigen::Matrix<float, 5, 6>;
|
| 85 |
-
using DenseMatrixR = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
|
| 86 |
-
using DenseMatrixC = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic>;
|
| 87 |
-
using FourRowMatrixC = Eigen::Matrix<float, 4, Eigen::Dynamic>;
|
| 88 |
-
using FourColMatrixC = Eigen::Matrix<float, Eigen::Dynamic, 4>;
|
| 89 |
-
using FourRowMatrixR = Eigen::Matrix<float, 4, Eigen::Dynamic>;
|
| 90 |
-
using FourColMatrixR = Eigen::Matrix<float, Eigen::Dynamic, 4>;
|
| 91 |
-
using SparseMatrixR = Eigen::SparseMatrix<float, Eigen::RowMajor>;
|
| 92 |
-
using SparseMatrixC = Eigen::SparseMatrix<float>;
|
| 93 |
-
|
| 94 |
-
// various tests
|
| 95 |
-
m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; });
|
| 96 |
-
m.def("double_row",
|
| 97 |
-
[](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; });
|
| 98 |
-
m.def("double_complex",
|
| 99 |
-
[](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; });
|
| 100 |
-
m.def("double_threec", [](py::EigenDRef<Eigen::Vector3f> x) { x *= 2; });
|
| 101 |
-
m.def("double_threer", [](py::EigenDRef<Eigen::RowVector3f> x) { x *= 2; });
|
| 102 |
-
m.def("double_mat_cm", [](const Eigen::MatrixXf &x) -> Eigen::MatrixXf { return 2.0f * x; });
|
| 103 |
-
m.def("double_mat_rm", [](const DenseMatrixR &x) -> DenseMatrixR { return 2.0f * x; });
|
| 104 |
-
|
| 105 |
-
// test_eigen_ref_to_python
|
| 106 |
-
// Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended
|
| 107 |
-
m.def("cholesky1",
|
| 108 |
-
[](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
| 109 |
-
m.def("cholesky2", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd {
|
| 110 |
-
return x.llt().matrixL();
|
| 111 |
-
});
|
| 112 |
-
m.def("cholesky3",
|
| 113 |
-
[](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
| 114 |
-
m.def("cholesky4", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd {
|
| 115 |
-
return x.llt().matrixL();
|
| 116 |
-
});
|
| 117 |
-
|
| 118 |
-
// test_eigen_ref_mutators
|
| 119 |
-
// Mutators: these add some value to the given element using Eigen, but Eigen should be mapping
|
| 120 |
-
// into the numpy array data and so the result should show up there. There are three versions:
|
| 121 |
-
// one that works on a contiguous-row matrix (numpy's default), one for a contiguous-column
|
| 122 |
-
// matrix, and one for any matrix.
|
| 123 |
-
auto add_rm = [](Eigen::Ref<MatrixXdR> x, int r, int c, double v) { x(r, c) += v; };
|
| 124 |
-
auto add_cm = [](Eigen::Ref<Eigen::MatrixXd> x, int r, int c, double v) { x(r, c) += v; };
|
| 125 |
-
|
| 126 |
-
// Mutators (Eigen maps into numpy variables):
|
| 127 |
-
m.def("add_rm", add_rm); // Only takes row-contiguous
|
| 128 |
-
m.def("add_cm", add_cm); // Only takes column-contiguous
|
| 129 |
-
// Overloaded versions that will accept either row or column contiguous:
|
| 130 |
-
m.def("add1", add_rm);
|
| 131 |
-
m.def("add1", add_cm);
|
| 132 |
-
m.def("add2", add_cm);
|
| 133 |
-
m.def("add2", add_rm);
|
| 134 |
-
// This one accepts a matrix of any stride:
|
| 135 |
-
m.def("add_any",
|
| 136 |
-
[](py::EigenDRef<Eigen::MatrixXd> x, int r, int c, double v) { x(r, c) += v; });
|
| 137 |
-
|
| 138 |
-
// Return mutable references (numpy maps into eigen variables)
|
| 139 |
-
m.def("get_cm_ref", []() { return Eigen::Ref<Eigen::MatrixXd>(get_cm()); });
|
| 140 |
-
m.def("get_rm_ref", []() { return Eigen::Ref<MatrixXdR>(get_rm()); });
|
| 141 |
-
// The same references, but non-mutable (numpy maps into eigen variables, but is !writeable)
|
| 142 |
-
m.def("get_cm_const_ref", []() { return Eigen::Ref<const Eigen::MatrixXd>(get_cm()); });
|
| 143 |
-
m.def("get_rm_const_ref", []() { return Eigen::Ref<const MatrixXdR>(get_rm()); });
|
| 144 |
-
|
| 145 |
-
m.def("reset_refs", reset_refs); // Restores get_{cm,rm}_ref to original values
|
| 146 |
-
|
| 147 |
-
// Increments and returns ref to (same) matrix
|
| 148 |
-
m.def(
|
| 149 |
-
"incr_matrix",
|
| 150 |
-
[](Eigen::Ref<Eigen::MatrixXd> m, double v) {
|
| 151 |
-
m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v);
|
| 152 |
-
return m;
|
| 153 |
-
},
|
| 154 |
-
py::return_value_policy::reference);
|
| 155 |
-
|
| 156 |
-
// Same, but accepts a matrix of any strides
|
| 157 |
-
m.def(
|
| 158 |
-
"incr_matrix_any",
|
| 159 |
-
[](py::EigenDRef<Eigen::MatrixXd> m, double v) {
|
| 160 |
-
m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v);
|
| 161 |
-
return m;
|
| 162 |
-
},
|
| 163 |
-
py::return_value_policy::reference);
|
| 164 |
-
|
| 165 |
-
// Returns an eigen slice of even rows
|
| 166 |
-
m.def(
|
| 167 |
-
"even_rows",
|
| 168 |
-
[](py::EigenDRef<Eigen::MatrixXd> m) {
|
| 169 |
-
return py::EigenDMap<Eigen::MatrixXd>(
|
| 170 |
-
m.data(),
|
| 171 |
-
(m.rows() + 1) / 2,
|
| 172 |
-
m.cols(),
|
| 173 |
-
py::EigenDStride(m.outerStride(), 2 * m.innerStride()));
|
| 174 |
-
},
|
| 175 |
-
py::return_value_policy::reference);
|
| 176 |
-
|
| 177 |
-
// Returns an eigen slice of even columns
|
| 178 |
-
m.def(
|
| 179 |
-
"even_cols",
|
| 180 |
-
[](py::EigenDRef<Eigen::MatrixXd> m) {
|
| 181 |
-
return py::EigenDMap<Eigen::MatrixXd>(
|
| 182 |
-
m.data(),
|
| 183 |
-
m.rows(),
|
| 184 |
-
(m.cols() + 1) / 2,
|
| 185 |
-
py::EigenDStride(2 * m.outerStride(), m.innerStride()));
|
| 186 |
-
},
|
| 187 |
-
py::return_value_policy::reference);
|
| 188 |
-
|
| 189 |
-
// Returns diagonals: a vector-like object with an inner stride != 1
|
| 190 |
-
m.def("diagonal", [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal(); });
|
| 191 |
-
m.def("diagonal_1",
|
| 192 |
-
[](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal<1>(); });
|
| 193 |
-
m.def("diagonal_n",
|
| 194 |
-
[](const Eigen::Ref<const Eigen::MatrixXd> &x, int index) { return x.diagonal(index); });
|
| 195 |
-
|
| 196 |
-
// Return a block of a matrix (gives non-standard strides)
|
| 197 |
-
m.def("block",
|
| 198 |
-
[m](const py::object &x_obj,
|
| 199 |
-
int start_row,
|
| 200 |
-
int start_col,
|
| 201 |
-
int block_rows,
|
| 202 |
-
int block_cols) {
|
| 203 |
-
return m.attr("_block")(x_obj, x_obj, start_row, start_col, block_rows, block_cols);
|
| 204 |
-
});
|
| 205 |
-
|
| 206 |
-
m.def(
|
| 207 |
-
"_block",
|
| 208 |
-
[](const py::object &x_obj,
|
| 209 |
-
const Eigen::Ref<const Eigen::MatrixXd> &x,
|
| 210 |
-
int start_row,
|
| 211 |
-
int start_col,
|
| 212 |
-
int block_rows,
|
| 213 |
-
int block_cols) {
|
| 214 |
-
// See PR #4217 for background. This test is a bit over the top, but might be useful
|
| 215 |
-
// as a concrete example to point to when explaining the dangling reference trap.
|
| 216 |
-
auto i0 = py::make_tuple(0, 0);
|
| 217 |
-
auto x0_orig = x_obj[*i0].cast<double>();
|
| 218 |
-
if (x(0, 0) != x0_orig) {
|
| 219 |
-
throw std::runtime_error(
|
| 220 |
-
"Something in the type_caster for Eigen::Ref is terribly wrong.");
|
| 221 |
-
}
|
| 222 |
-
double x0_mod = x0_orig + 1;
|
| 223 |
-
x_obj[*i0] = x0_mod;
|
| 224 |
-
auto copy_detected = (x(0, 0) != x0_mod);
|
| 225 |
-
x_obj[*i0] = x0_orig;
|
| 226 |
-
if (copy_detected) {
|
| 227 |
-
throw std::runtime_error("type_caster for Eigen::Ref made a copy.");
|
| 228 |
-
}
|
| 229 |
-
return x.block(start_row, start_col, block_rows, block_cols);
|
| 230 |
-
},
|
| 231 |
-
py::keep_alive<0, 1>());
|
| 232 |
-
|
| 233 |
-
// test_eigen_return_references, test_eigen_keepalive
|
| 234 |
-
// return value referencing/copying tests:
|
| 235 |
-
class ReturnTester {
|
| 236 |
-
Eigen::MatrixXd mat = create();
|
| 237 |
-
|
| 238 |
-
public:
|
| 239 |
-
ReturnTester() { print_created(this); }
|
| 240 |
-
~ReturnTester() { print_destroyed(this); }
|
| 241 |
-
static Eigen::MatrixXd create() { return Eigen::MatrixXd::Ones(10, 10); }
|
| 242 |
-
// NOLINTNEXTLINE(readability-const-return-type)
|
| 243 |
-
static const Eigen::MatrixXd createConst() { return Eigen::MatrixXd::Ones(10, 10); }
|
| 244 |
-
Eigen::MatrixXd &get() { return mat; }
|
| 245 |
-
Eigen::MatrixXd *getPtr() { return &mat; }
|
| 246 |
-
const Eigen::MatrixXd &view() { return mat; }
|
| 247 |
-
const Eigen::MatrixXd *viewPtr() { return &mat; }
|
| 248 |
-
Eigen::Ref<Eigen::MatrixXd> ref() { return mat; }
|
| 249 |
-
Eigen::Ref<const Eigen::MatrixXd> refConst() { return mat; }
|
| 250 |
-
Eigen::Block<Eigen::MatrixXd> block(int r, int c, int nrow, int ncol) {
|
| 251 |
-
return mat.block(r, c, nrow, ncol);
|
| 252 |
-
}
|
| 253 |
-
Eigen::Block<const Eigen::MatrixXd> blockConst(int r, int c, int nrow, int ncol) const {
|
| 254 |
-
return mat.block(r, c, nrow, ncol);
|
| 255 |
-
}
|
| 256 |
-
py::EigenDMap<Eigen::Matrix2d> corners() {
|
| 257 |
-
return py::EigenDMap<Eigen::Matrix2d>(
|
| 258 |
-
mat.data(),
|
| 259 |
-
py::EigenDStride(mat.outerStride() * (mat.outerSize() - 1),
|
| 260 |
-
mat.innerStride() * (mat.innerSize() - 1)));
|
| 261 |
-
}
|
| 262 |
-
py::EigenDMap<const Eigen::Matrix2d> cornersConst() const {
|
| 263 |
-
return py::EigenDMap<const Eigen::Matrix2d>(
|
| 264 |
-
mat.data(),
|
| 265 |
-
py::EigenDStride(mat.outerStride() * (mat.outerSize() - 1),
|
| 266 |
-
mat.innerStride() * (mat.innerSize() - 1)));
|
| 267 |
-
}
|
| 268 |
-
};
|
| 269 |
-
using rvp = py::return_value_policy;
|
| 270 |
-
py::class_<ReturnTester>(m, "ReturnTester")
|
| 271 |
-
.def(py::init<>())
|
| 272 |
-
.def_static("create", &ReturnTester::create)
|
| 273 |
-
.def_static("create_const", &ReturnTester::createConst)
|
| 274 |
-
.def("get", &ReturnTester::get, rvp::reference_internal)
|
| 275 |
-
.def("get_ptr", &ReturnTester::getPtr, rvp::reference_internal)
|
| 276 |
-
.def("view", &ReturnTester::view, rvp::reference_internal)
|
| 277 |
-
.def("view_ptr", &ReturnTester::view, rvp::reference_internal)
|
| 278 |
-
.def("copy_get", &ReturnTester::get) // Default rvp: copy
|
| 279 |
-
.def("copy_view", &ReturnTester::view) // "
|
| 280 |
-
.def("ref", &ReturnTester::ref) // Default for Ref is to reference
|
| 281 |
-
.def("ref_const", &ReturnTester::refConst) // Likewise, but const
|
| 282 |
-
.def("ref_safe", &ReturnTester::ref, rvp::reference_internal)
|
| 283 |
-
.def("ref_const_safe", &ReturnTester::refConst, rvp::reference_internal)
|
| 284 |
-
.def("copy_ref", &ReturnTester::ref, rvp::copy)
|
| 285 |
-
.def("copy_ref_const", &ReturnTester::refConst, rvp::copy)
|
| 286 |
-
.def("block", &ReturnTester::block)
|
| 287 |
-
.def("block_safe", &ReturnTester::block, rvp::reference_internal)
|
| 288 |
-
.def("block_const", &ReturnTester::blockConst, rvp::reference_internal)
|
| 289 |
-
.def("copy_block", &ReturnTester::block, rvp::copy)
|
| 290 |
-
.def("corners", &ReturnTester::corners, rvp::reference_internal)
|
| 291 |
-
.def("corners_const", &ReturnTester::cornersConst, rvp::reference_internal);
|
| 292 |
-
|
| 293 |
-
// test_special_matrix_objects
|
| 294 |
-
// Returns a DiagonalMatrix with diagonal (1,2,3,...)
|
| 295 |
-
m.def("incr_diag", [](int k) {
|
| 296 |
-
Eigen::DiagonalMatrix<int, Eigen::Dynamic> m(k);
|
| 297 |
-
for (int i = 0; i < k; i++) {
|
| 298 |
-
m.diagonal()[i] = i + 1;
|
| 299 |
-
}
|
| 300 |
-
return m;
|
| 301 |
-
});
|
| 302 |
-
|
| 303 |
-
// Returns a SelfAdjointView referencing the lower triangle of m
|
| 304 |
-
m.def("symmetric_lower",
|
| 305 |
-
[](const Eigen::MatrixXi &m) { return m.selfadjointView<Eigen::Lower>(); });
|
| 306 |
-
// Returns a SelfAdjointView referencing the lower triangle of m
|
| 307 |
-
m.def("symmetric_upper",
|
| 308 |
-
[](const Eigen::MatrixXi &m) { return m.selfadjointView<Eigen::Upper>(); });
|
| 309 |
-
|
| 310 |
-
// Test matrix for various functions below.
|
| 311 |
-
Eigen::MatrixXf mat(5, 6);
|
| 312 |
-
mat << 0, 3, 0, 0, 0, 11, 22, 0, 0, 0, 17, 11, 7, 5, 0, 1, 0, 11, 0, 0, 0, 0, 0, 11, 0, 0, 14,
|
| 313 |
-
0, 8, 11;
|
| 314 |
-
|
| 315 |
-
// test_fixed, and various other tests
|
| 316 |
-
m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); });
|
| 317 |
-
// Our Eigen does a hack which respects constness through the numpy writeable flag.
|
| 318 |
-
// Therefore, the const return actually affects this type despite being an rvalue.
|
| 319 |
-
// NOLINTNEXTLINE(readability-const-return-type)
|
| 320 |
-
m.def("fixed_r_const", [mat]() -> const FixedMatrixR { return FixedMatrixR(mat); });
|
| 321 |
-
m.def("fixed_c", [mat]() -> FixedMatrixC { return FixedMatrixC(mat); });
|
| 322 |
-
m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; });
|
| 323 |
-
m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; });
|
| 324 |
-
// test_mutator_descriptors
|
| 325 |
-
m.def("fixed_mutator_r", [](const Eigen::Ref<FixedMatrixR> &) {});
|
| 326 |
-
m.def("fixed_mutator_c", [](const Eigen::Ref<FixedMatrixC> &) {});
|
| 327 |
-
m.def("fixed_mutator_a", [](const py::EigenDRef<FixedMatrixC> &) {});
|
| 328 |
-
// test_dense
|
| 329 |
-
m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); });
|
| 330 |
-
m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); });
|
| 331 |
-
m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; });
|
| 332 |
-
m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; });
|
| 333 |
-
// test_defaults
|
| 334 |
-
bool have_numpy = true;
|
| 335 |
-
try {
|
| 336 |
-
py::module_::import("numpy");
|
| 337 |
-
} catch (const py::error_already_set &) {
|
| 338 |
-
have_numpy = false;
|
| 339 |
-
}
|
| 340 |
-
if (have_numpy) {
|
| 341 |
-
py::module_::import("numpy");
|
| 342 |
-
Eigen::Matrix<double, 3, 3> defaultMatrix = Eigen::Matrix3d::Identity();
|
| 343 |
-
m.def(
|
| 344 |
-
"defaults_mat", [](const Eigen::Matrix3d &) {}, py::arg("mat") = defaultMatrix);
|
| 345 |
-
|
| 346 |
-
Eigen::VectorXd defaultVector = Eigen::VectorXd::Ones(32);
|
| 347 |
-
m.def(
|
| 348 |
-
"defaults_vec", [](const Eigen::VectorXd &) {}, py::arg("vec") = defaultMatrix);
|
| 349 |
-
}
|
| 350 |
-
// test_sparse, test_sparse_signature
|
| 351 |
-
m.def("sparse_r", [mat]() -> SparseMatrixR {
|
| 352 |
-
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
| 353 |
-
return Eigen::SparseView<Eigen::MatrixXf>(mat);
|
| 354 |
-
});
|
| 355 |
-
m.def("sparse_c",
|
| 356 |
-
[mat]() -> SparseMatrixC { return Eigen::SparseView<Eigen::MatrixXf>(mat); });
|
| 357 |
-
m.def("sparse_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; });
|
| 358 |
-
m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; });
|
| 359 |
-
// test_partially_fixed
|
| 360 |
-
m.def("partial_copy_four_rm_r", [](const FourRowMatrixR &m) -> FourRowMatrixR { return m; });
|
| 361 |
-
m.def("partial_copy_four_rm_c", [](const FourColMatrixR &m) -> FourColMatrixR { return m; });
|
| 362 |
-
m.def("partial_copy_four_cm_r", [](const FourRowMatrixC &m) -> FourRowMatrixC { return m; });
|
| 363 |
-
m.def("partial_copy_four_cm_c", [](const FourColMatrixC &m) -> FourColMatrixC { return m; });
|
| 364 |
-
|
| 365 |
-
// test_cpp_casting
|
| 366 |
-
// Test that we can cast a numpy object to a Eigen::MatrixXd explicitly
|
| 367 |
-
m.def("cpp_copy", [](py::handle m) { return m.cast<Eigen::MatrixXd>()(1, 0); });
|
| 368 |
-
m.def("cpp_ref_c", [](py::handle m) { return m.cast<Eigen::Ref<Eigen::MatrixXd>>()(1, 0); });
|
| 369 |
-
m.def("cpp_ref_r", [](py::handle m) { return m.cast<Eigen::Ref<MatrixXdR>>()(1, 0); });
|
| 370 |
-
m.def("cpp_ref_any",
|
| 371 |
-
[](py::handle m) { return m.cast<py::EigenDRef<Eigen::MatrixXd>>()(1, 0); });
|
| 372 |
-
|
| 373 |
-
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
| 374 |
-
|
| 375 |
-
// test_nocopy_wrapper
|
| 376 |
-
// Test that we can prevent copying into an argument that would normally copy: First a version
|
| 377 |
-
// that would allow copying (if types or strides don't match) for comparison:
|
| 378 |
-
m.def("get_elem", &get_elem);
|
| 379 |
-
// Now this alternative that calls the tells pybind to fail rather than copy:
|
| 380 |
-
m.def(
|
| 381 |
-
"get_elem_nocopy",
|
| 382 |
-
[](const Eigen::Ref<const Eigen::MatrixXd> &m) -> double { return get_elem(m); },
|
| 383 |
-
py::arg{}.noconvert());
|
| 384 |
-
// Also test a row-major-only no-copy const ref:
|
| 385 |
-
m.def(
|
| 386 |
-
"get_elem_rm_nocopy",
|
| 387 |
-
[](Eigen::Ref<const Eigen::Matrix<long, -1, -1, Eigen::RowMajor>> &m) -> long {
|
| 388 |
-
return m(2, 1);
|
| 389 |
-
},
|
| 390 |
-
py::arg{}.noconvert());
|
| 391 |
-
|
| 392 |
-
// test_issue738, test_zero_length
|
| 393 |
-
// Issue #738: 1×N or N×1 2D matrices were neither accepted nor properly copied with an
|
| 394 |
-
// incompatible stride value on the length-1 dimension--but that should be allowed (without
|
| 395 |
-
// requiring a copy!) because the stride value can be safely ignored on a size-1 dimension.
|
| 396 |
-
// Similarly, 0×N or N×0 matrices were not accepted--again, these should be allowed since
|
| 397 |
-
// they contain no data. This particularly affects numpy ≥ 1.23, which sets the strides to
|
| 398 |
-
// 0 if any dimension size is 0.
|
| 399 |
-
m.def("iss738_f1",
|
| 400 |
-
&adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>,
|
| 401 |
-
py::arg{}.noconvert());
|
| 402 |
-
m.def("iss738_f2",
|
| 403 |
-
&adjust_matrix<const Eigen::Ref<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> &>,
|
| 404 |
-
py::arg{}.noconvert());
|
| 405 |
-
|
| 406 |
-
// test_issue1105
|
| 407 |
-
// Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense
|
| 408 |
-
// eigen Vector or RowVector, the argument would fail to load because the numpy copy would
|
| 409 |
-
// fail: numpy won't broadcast a Nx1 into a 1-dimensional vector.
|
| 410 |
-
m.def("iss1105_col", [](const Eigen::VectorXd &) { return true; });
|
| 411 |
-
m.def("iss1105_row", [](const Eigen::RowVectorXd &) { return true; });
|
| 412 |
-
|
| 413 |
-
// test_named_arguments
|
| 414 |
-
// Make sure named arguments are working properly:
|
| 415 |
-
m.def(
|
| 416 |
-
"matrix_multiply",
|
| 417 |
-
[](const py::EigenDRef<const Eigen::MatrixXd> &A,
|
| 418 |
-
const py::EigenDRef<const Eigen::MatrixXd> &B) -> Eigen::MatrixXd {
|
| 419 |
-
if (A.cols() != B.rows()) {
|
| 420 |
-
throw std::domain_error("Nonconformable matrices!");
|
| 421 |
-
}
|
| 422 |
-
return A * B;
|
| 423 |
-
},
|
| 424 |
-
py::arg("A"),
|
| 425 |
-
py::arg("B"));
|
| 426 |
-
|
| 427 |
-
// test_custom_operator_new
|
| 428 |
-
py::class_<CustomOperatorNew>(m, "CustomOperatorNew")
|
| 429 |
-
.def(py::init<>())
|
| 430 |
-
.def_readonly("a", &CustomOperatorNew::a)
|
| 431 |
-
.def_readonly("b", &CustomOperatorNew::b);
|
| 432 |
-
|
| 433 |
-
// test_eigen_ref_life_support
|
| 434 |
-
// In case of a failure (the caster's temp array does not live long enough), creating
|
| 435 |
-
// a new array (np.ones(10)) increases the chances that the temp array will be garbage
|
| 436 |
-
// collected and/or that its memory will be overridden with different values.
|
| 437 |
-
m.def("get_elem_direct", [](const Eigen::Ref<const Eigen::VectorXd> &v) {
|
| 438 |
-
py::module_::import("numpy").attr("ones")(10);
|
| 439 |
-
return v(5);
|
| 440 |
-
});
|
| 441 |
-
m.def("get_elem_indirect", [](std::vector<Eigen::Ref<const Eigen::VectorXd>> v) {
|
| 442 |
-
py::module_::import("numpy").attr("ones")(10);
|
| 443 |
-
return v[0](5);
|
| 444 |
-
});
|
| 445 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/eigen.cpp -- automatic conversion of Eigen types
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#include <pybind11/eigen/matrix.h>
|
| 11 |
+
#include <pybind11/stl.h>
|
| 12 |
+
|
| 13 |
+
#include "constructor_stats.h"
|
| 14 |
+
#include "pybind11_tests.h"
|
| 15 |
+
|
| 16 |
+
PYBIND11_WARNING_DISABLE_MSVC(4996)
|
| 17 |
+
|
| 18 |
+
#include <Eigen/Cholesky>
|
| 19 |
+
|
| 20 |
+
using MatrixXdR = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
|
| 21 |
+
|
| 22 |
+
// Sets/resets a testing reference matrix to have values of 10*r + c, where r and c are the
|
| 23 |
+
// (1-based) row/column number.
|
| 24 |
+
template <typename M>
|
| 25 |
+
void reset_ref(M &x) {
|
| 26 |
+
for (int i = 0; i < x.rows(); i++) {
|
| 27 |
+
for (int j = 0; j < x.cols(); j++) {
|
| 28 |
+
x(i, j) = 11 + 10 * i + j;
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
// Returns a static, column-major matrix
|
| 34 |
+
Eigen::MatrixXd &get_cm() {
|
| 35 |
+
static Eigen::MatrixXd *x;
|
| 36 |
+
if (!x) {
|
| 37 |
+
x = new Eigen::MatrixXd(3, 3);
|
| 38 |
+
reset_ref(*x);
|
| 39 |
+
}
|
| 40 |
+
return *x;
|
| 41 |
+
}
|
| 42 |
+
// Likewise, but row-major
|
| 43 |
+
MatrixXdR &get_rm() {
|
| 44 |
+
static MatrixXdR *x;
|
| 45 |
+
if (!x) {
|
| 46 |
+
x = new MatrixXdR(3, 3);
|
| 47 |
+
reset_ref(*x);
|
| 48 |
+
}
|
| 49 |
+
return *x;
|
| 50 |
+
}
|
| 51 |
+
// Resets the values of the static matrices returned by get_cm()/get_rm()
|
| 52 |
+
void reset_refs() {
|
| 53 |
+
reset_ref(get_cm());
|
| 54 |
+
reset_ref(get_rm());
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
// Returns element 2,1 from a matrix (used to test copy/nocopy)
|
| 58 |
+
double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); };
|
| 59 |
+
|
| 60 |
+
// Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix
|
| 61 |
+
// reference is referencing rows/columns correctly).
|
| 62 |
+
template <typename MatrixArgType>
|
| 63 |
+
Eigen::MatrixXd adjust_matrix(MatrixArgType m) {
|
| 64 |
+
Eigen::MatrixXd ret(m);
|
| 65 |
+
for (int c = 0; c < m.cols(); c++) {
|
| 66 |
+
for (int r = 0; r < m.rows(); r++) {
|
| 67 |
+
ret(r, c) += 10 * r + 100 * c; // NOLINT(clang-analyzer-core.uninitialized.Assign)
|
| 68 |
+
}
|
| 69 |
+
}
|
| 70 |
+
return ret;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
struct CustomOperatorNew {
|
| 74 |
+
CustomOperatorNew() = default;
|
| 75 |
+
|
| 76 |
+
Eigen::Matrix4d a = Eigen::Matrix4d::Zero();
|
| 77 |
+
Eigen::Matrix4d b = Eigen::Matrix4d::Identity();
|
| 78 |
+
|
| 79 |
+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
|
| 80 |
+
};
|
| 81 |
+
|
| 82 |
+
TEST_SUBMODULE(eigen_matrix, m) {
|
| 83 |
+
using FixedMatrixR = Eigen::Matrix<float, 5, 6, Eigen::RowMajor>;
|
| 84 |
+
using FixedMatrixC = Eigen::Matrix<float, 5, 6>;
|
| 85 |
+
using DenseMatrixR = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
|
| 86 |
+
using DenseMatrixC = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic>;
|
| 87 |
+
using FourRowMatrixC = Eigen::Matrix<float, 4, Eigen::Dynamic>;
|
| 88 |
+
using FourColMatrixC = Eigen::Matrix<float, Eigen::Dynamic, 4>;
|
| 89 |
+
using FourRowMatrixR = Eigen::Matrix<float, 4, Eigen::Dynamic>;
|
| 90 |
+
using FourColMatrixR = Eigen::Matrix<float, Eigen::Dynamic, 4>;
|
| 91 |
+
using SparseMatrixR = Eigen::SparseMatrix<float, Eigen::RowMajor>;
|
| 92 |
+
using SparseMatrixC = Eigen::SparseMatrix<float>;
|
| 93 |
+
|
| 94 |
+
// various tests
|
| 95 |
+
m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; });
|
| 96 |
+
m.def("double_row",
|
| 97 |
+
[](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; });
|
| 98 |
+
m.def("double_complex",
|
| 99 |
+
[](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; });
|
| 100 |
+
m.def("double_threec", [](py::EigenDRef<Eigen::Vector3f> x) { x *= 2; });
|
| 101 |
+
m.def("double_threer", [](py::EigenDRef<Eigen::RowVector3f> x) { x *= 2; });
|
| 102 |
+
m.def("double_mat_cm", [](const Eigen::MatrixXf &x) -> Eigen::MatrixXf { return 2.0f * x; });
|
| 103 |
+
m.def("double_mat_rm", [](const DenseMatrixR &x) -> DenseMatrixR { return 2.0f * x; });
|
| 104 |
+
|
| 105 |
+
// test_eigen_ref_to_python
|
| 106 |
+
// Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended
|
| 107 |
+
m.def("cholesky1",
|
| 108 |
+
[](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
| 109 |
+
m.def("cholesky2", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd {
|
| 110 |
+
return x.llt().matrixL();
|
| 111 |
+
});
|
| 112 |
+
m.def("cholesky3",
|
| 113 |
+
[](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
| 114 |
+
m.def("cholesky4", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd {
|
| 115 |
+
return x.llt().matrixL();
|
| 116 |
+
});
|
| 117 |
+
|
| 118 |
+
// test_eigen_ref_mutators
|
| 119 |
+
// Mutators: these add some value to the given element using Eigen, but Eigen should be mapping
|
| 120 |
+
// into the numpy array data and so the result should show up there. There are three versions:
|
| 121 |
+
// one that works on a contiguous-row matrix (numpy's default), one for a contiguous-column
|
| 122 |
+
// matrix, and one for any matrix.
|
| 123 |
+
auto add_rm = [](Eigen::Ref<MatrixXdR> x, int r, int c, double v) { x(r, c) += v; };
|
| 124 |
+
auto add_cm = [](Eigen::Ref<Eigen::MatrixXd> x, int r, int c, double v) { x(r, c) += v; };
|
| 125 |
+
|
| 126 |
+
// Mutators (Eigen maps into numpy variables):
|
| 127 |
+
m.def("add_rm", add_rm); // Only takes row-contiguous
|
| 128 |
+
m.def("add_cm", add_cm); // Only takes column-contiguous
|
| 129 |
+
// Overloaded versions that will accept either row or column contiguous:
|
| 130 |
+
m.def("add1", add_rm);
|
| 131 |
+
m.def("add1", add_cm);
|
| 132 |
+
m.def("add2", add_cm);
|
| 133 |
+
m.def("add2", add_rm);
|
| 134 |
+
// This one accepts a matrix of any stride:
|
| 135 |
+
m.def("add_any",
|
| 136 |
+
[](py::EigenDRef<Eigen::MatrixXd> x, int r, int c, double v) { x(r, c) += v; });
|
| 137 |
+
|
| 138 |
+
// Return mutable references (numpy maps into eigen variables)
|
| 139 |
+
m.def("get_cm_ref", []() { return Eigen::Ref<Eigen::MatrixXd>(get_cm()); });
|
| 140 |
+
m.def("get_rm_ref", []() { return Eigen::Ref<MatrixXdR>(get_rm()); });
|
| 141 |
+
// The same references, but non-mutable (numpy maps into eigen variables, but is !writeable)
|
| 142 |
+
m.def("get_cm_const_ref", []() { return Eigen::Ref<const Eigen::MatrixXd>(get_cm()); });
|
| 143 |
+
m.def("get_rm_const_ref", []() { return Eigen::Ref<const MatrixXdR>(get_rm()); });
|
| 144 |
+
|
| 145 |
+
m.def("reset_refs", reset_refs); // Restores get_{cm,rm}_ref to original values
|
| 146 |
+
|
| 147 |
+
// Increments and returns ref to (same) matrix
|
| 148 |
+
m.def(
|
| 149 |
+
"incr_matrix",
|
| 150 |
+
[](Eigen::Ref<Eigen::MatrixXd> m, double v) {
|
| 151 |
+
m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v);
|
| 152 |
+
return m;
|
| 153 |
+
},
|
| 154 |
+
py::return_value_policy::reference);
|
| 155 |
+
|
| 156 |
+
// Same, but accepts a matrix of any strides
|
| 157 |
+
m.def(
|
| 158 |
+
"incr_matrix_any",
|
| 159 |
+
[](py::EigenDRef<Eigen::MatrixXd> m, double v) {
|
| 160 |
+
m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v);
|
| 161 |
+
return m;
|
| 162 |
+
},
|
| 163 |
+
py::return_value_policy::reference);
|
| 164 |
+
|
| 165 |
+
// Returns an eigen slice of even rows
|
| 166 |
+
m.def(
|
| 167 |
+
"even_rows",
|
| 168 |
+
[](py::EigenDRef<Eigen::MatrixXd> m) {
|
| 169 |
+
return py::EigenDMap<Eigen::MatrixXd>(
|
| 170 |
+
m.data(),
|
| 171 |
+
(m.rows() + 1) / 2,
|
| 172 |
+
m.cols(),
|
| 173 |
+
py::EigenDStride(m.outerStride(), 2 * m.innerStride()));
|
| 174 |
+
},
|
| 175 |
+
py::return_value_policy::reference);
|
| 176 |
+
|
| 177 |
+
// Returns an eigen slice of even columns
|
| 178 |
+
m.def(
|
| 179 |
+
"even_cols",
|
| 180 |
+
[](py::EigenDRef<Eigen::MatrixXd> m) {
|
| 181 |
+
return py::EigenDMap<Eigen::MatrixXd>(
|
| 182 |
+
m.data(),
|
| 183 |
+
m.rows(),
|
| 184 |
+
(m.cols() + 1) / 2,
|
| 185 |
+
py::EigenDStride(2 * m.outerStride(), m.innerStride()));
|
| 186 |
+
},
|
| 187 |
+
py::return_value_policy::reference);
|
| 188 |
+
|
| 189 |
+
// Returns diagonals: a vector-like object with an inner stride != 1
|
| 190 |
+
m.def("diagonal", [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal(); });
|
| 191 |
+
m.def("diagonal_1",
|
| 192 |
+
[](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal<1>(); });
|
| 193 |
+
m.def("diagonal_n",
|
| 194 |
+
[](const Eigen::Ref<const Eigen::MatrixXd> &x, int index) { return x.diagonal(index); });
|
| 195 |
+
|
| 196 |
+
// Return a block of a matrix (gives non-standard strides)
|
| 197 |
+
m.def("block",
|
| 198 |
+
[m](const py::object &x_obj,
|
| 199 |
+
int start_row,
|
| 200 |
+
int start_col,
|
| 201 |
+
int block_rows,
|
| 202 |
+
int block_cols) {
|
| 203 |
+
return m.attr("_block")(x_obj, x_obj, start_row, start_col, block_rows, block_cols);
|
| 204 |
+
});
|
| 205 |
+
|
| 206 |
+
m.def(
|
| 207 |
+
"_block",
|
| 208 |
+
[](const py::object &x_obj,
|
| 209 |
+
const Eigen::Ref<const Eigen::MatrixXd> &x,
|
| 210 |
+
int start_row,
|
| 211 |
+
int start_col,
|
| 212 |
+
int block_rows,
|
| 213 |
+
int block_cols) {
|
| 214 |
+
// See PR #4217 for background. This test is a bit over the top, but might be useful
|
| 215 |
+
// as a concrete example to point to when explaining the dangling reference trap.
|
| 216 |
+
auto i0 = py::make_tuple(0, 0);
|
| 217 |
+
auto x0_orig = x_obj[*i0].cast<double>();
|
| 218 |
+
if (x(0, 0) != x0_orig) {
|
| 219 |
+
throw std::runtime_error(
|
| 220 |
+
"Something in the type_caster for Eigen::Ref is terribly wrong.");
|
| 221 |
+
}
|
| 222 |
+
double x0_mod = x0_orig + 1;
|
| 223 |
+
x_obj[*i0] = x0_mod;
|
| 224 |
+
auto copy_detected = (x(0, 0) != x0_mod);
|
| 225 |
+
x_obj[*i0] = x0_orig;
|
| 226 |
+
if (copy_detected) {
|
| 227 |
+
throw std::runtime_error("type_caster for Eigen::Ref made a copy.");
|
| 228 |
+
}
|
| 229 |
+
return x.block(start_row, start_col, block_rows, block_cols);
|
| 230 |
+
},
|
| 231 |
+
py::keep_alive<0, 1>());
|
| 232 |
+
|
| 233 |
+
// test_eigen_return_references, test_eigen_keepalive
|
| 234 |
+
// return value referencing/copying tests:
|
| 235 |
+
class ReturnTester {
|
| 236 |
+
Eigen::MatrixXd mat = create();
|
| 237 |
+
|
| 238 |
+
public:
|
| 239 |
+
ReturnTester() { print_created(this); }
|
| 240 |
+
~ReturnTester() { print_destroyed(this); }
|
| 241 |
+
static Eigen::MatrixXd create() { return Eigen::MatrixXd::Ones(10, 10); }
|
| 242 |
+
// NOLINTNEXTLINE(readability-const-return-type)
|
| 243 |
+
static const Eigen::MatrixXd createConst() { return Eigen::MatrixXd::Ones(10, 10); }
|
| 244 |
+
Eigen::MatrixXd &get() { return mat; }
|
| 245 |
+
Eigen::MatrixXd *getPtr() { return &mat; }
|
| 246 |
+
const Eigen::MatrixXd &view() { return mat; }
|
| 247 |
+
const Eigen::MatrixXd *viewPtr() { return &mat; }
|
| 248 |
+
Eigen::Ref<Eigen::MatrixXd> ref() { return mat; }
|
| 249 |
+
Eigen::Ref<const Eigen::MatrixXd> refConst() { return mat; }
|
| 250 |
+
Eigen::Block<Eigen::MatrixXd> block(int r, int c, int nrow, int ncol) {
|
| 251 |
+
return mat.block(r, c, nrow, ncol);
|
| 252 |
+
}
|
| 253 |
+
Eigen::Block<const Eigen::MatrixXd> blockConst(int r, int c, int nrow, int ncol) const {
|
| 254 |
+
return mat.block(r, c, nrow, ncol);
|
| 255 |
+
}
|
| 256 |
+
py::EigenDMap<Eigen::Matrix2d> corners() {
|
| 257 |
+
return py::EigenDMap<Eigen::Matrix2d>(
|
| 258 |
+
mat.data(),
|
| 259 |
+
py::EigenDStride(mat.outerStride() * (mat.outerSize() - 1),
|
| 260 |
+
mat.innerStride() * (mat.innerSize() - 1)));
|
| 261 |
+
}
|
| 262 |
+
py::EigenDMap<const Eigen::Matrix2d> cornersConst() const {
|
| 263 |
+
return py::EigenDMap<const Eigen::Matrix2d>(
|
| 264 |
+
mat.data(),
|
| 265 |
+
py::EigenDStride(mat.outerStride() * (mat.outerSize() - 1),
|
| 266 |
+
mat.innerStride() * (mat.innerSize() - 1)));
|
| 267 |
+
}
|
| 268 |
+
};
|
| 269 |
+
using rvp = py::return_value_policy;
|
| 270 |
+
py::class_<ReturnTester>(m, "ReturnTester")
|
| 271 |
+
.def(py::init<>())
|
| 272 |
+
.def_static("create", &ReturnTester::create)
|
| 273 |
+
.def_static("create_const", &ReturnTester::createConst)
|
| 274 |
+
.def("get", &ReturnTester::get, rvp::reference_internal)
|
| 275 |
+
.def("get_ptr", &ReturnTester::getPtr, rvp::reference_internal)
|
| 276 |
+
.def("view", &ReturnTester::view, rvp::reference_internal)
|
| 277 |
+
.def("view_ptr", &ReturnTester::view, rvp::reference_internal)
|
| 278 |
+
.def("copy_get", &ReturnTester::get) // Default rvp: copy
|
| 279 |
+
.def("copy_view", &ReturnTester::view) // "
|
| 280 |
+
.def("ref", &ReturnTester::ref) // Default for Ref is to reference
|
| 281 |
+
.def("ref_const", &ReturnTester::refConst) // Likewise, but const
|
| 282 |
+
.def("ref_safe", &ReturnTester::ref, rvp::reference_internal)
|
| 283 |
+
.def("ref_const_safe", &ReturnTester::refConst, rvp::reference_internal)
|
| 284 |
+
.def("copy_ref", &ReturnTester::ref, rvp::copy)
|
| 285 |
+
.def("copy_ref_const", &ReturnTester::refConst, rvp::copy)
|
| 286 |
+
.def("block", &ReturnTester::block)
|
| 287 |
+
.def("block_safe", &ReturnTester::block, rvp::reference_internal)
|
| 288 |
+
.def("block_const", &ReturnTester::blockConst, rvp::reference_internal)
|
| 289 |
+
.def("copy_block", &ReturnTester::block, rvp::copy)
|
| 290 |
+
.def("corners", &ReturnTester::corners, rvp::reference_internal)
|
| 291 |
+
.def("corners_const", &ReturnTester::cornersConst, rvp::reference_internal);
|
| 292 |
+
|
| 293 |
+
// test_special_matrix_objects
|
| 294 |
+
// Returns a DiagonalMatrix with diagonal (1,2,3,...)
|
| 295 |
+
m.def("incr_diag", [](int k) {
|
| 296 |
+
Eigen::DiagonalMatrix<int, Eigen::Dynamic> m(k);
|
| 297 |
+
for (int i = 0; i < k; i++) {
|
| 298 |
+
m.diagonal()[i] = i + 1;
|
| 299 |
+
}
|
| 300 |
+
return m;
|
| 301 |
+
});
|
| 302 |
+
|
| 303 |
+
// Returns a SelfAdjointView referencing the lower triangle of m
|
| 304 |
+
m.def("symmetric_lower",
|
| 305 |
+
[](const Eigen::MatrixXi &m) { return m.selfadjointView<Eigen::Lower>(); });
|
| 306 |
+
// Returns a SelfAdjointView referencing the lower triangle of m
|
| 307 |
+
m.def("symmetric_upper",
|
| 308 |
+
[](const Eigen::MatrixXi &m) { return m.selfadjointView<Eigen::Upper>(); });
|
| 309 |
+
|
| 310 |
+
// Test matrix for various functions below.
|
| 311 |
+
Eigen::MatrixXf mat(5, 6);
|
| 312 |
+
mat << 0, 3, 0, 0, 0, 11, 22, 0, 0, 0, 17, 11, 7, 5, 0, 1, 0, 11, 0, 0, 0, 0, 0, 11, 0, 0, 14,
|
| 313 |
+
0, 8, 11;
|
| 314 |
+
|
| 315 |
+
// test_fixed, and various other tests
|
| 316 |
+
m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); });
|
| 317 |
+
// Our Eigen does a hack which respects constness through the numpy writeable flag.
|
| 318 |
+
// Therefore, the const return actually affects this type despite being an rvalue.
|
| 319 |
+
// NOLINTNEXTLINE(readability-const-return-type)
|
| 320 |
+
m.def("fixed_r_const", [mat]() -> const FixedMatrixR { return FixedMatrixR(mat); });
|
| 321 |
+
m.def("fixed_c", [mat]() -> FixedMatrixC { return FixedMatrixC(mat); });
|
| 322 |
+
m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; });
|
| 323 |
+
m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; });
|
| 324 |
+
// test_mutator_descriptors
|
| 325 |
+
m.def("fixed_mutator_r", [](const Eigen::Ref<FixedMatrixR> &) {});
|
| 326 |
+
m.def("fixed_mutator_c", [](const Eigen::Ref<FixedMatrixC> &) {});
|
| 327 |
+
m.def("fixed_mutator_a", [](const py::EigenDRef<FixedMatrixC> &) {});
|
| 328 |
+
// test_dense
|
| 329 |
+
m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); });
|
| 330 |
+
m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); });
|
| 331 |
+
m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; });
|
| 332 |
+
m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; });
|
| 333 |
+
// test_defaults
|
| 334 |
+
bool have_numpy = true;
|
| 335 |
+
try {
|
| 336 |
+
py::module_::import("numpy");
|
| 337 |
+
} catch (const py::error_already_set &) {
|
| 338 |
+
have_numpy = false;
|
| 339 |
+
}
|
| 340 |
+
if (have_numpy) {
|
| 341 |
+
py::module_::import("numpy");
|
| 342 |
+
Eigen::Matrix<double, 3, 3> defaultMatrix = Eigen::Matrix3d::Identity();
|
| 343 |
+
m.def(
|
| 344 |
+
"defaults_mat", [](const Eigen::Matrix3d &) {}, py::arg("mat") = defaultMatrix);
|
| 345 |
+
|
| 346 |
+
Eigen::VectorXd defaultVector = Eigen::VectorXd::Ones(32);
|
| 347 |
+
m.def(
|
| 348 |
+
"defaults_vec", [](const Eigen::VectorXd &) {}, py::arg("vec") = defaultMatrix);
|
| 349 |
+
}
|
| 350 |
+
// test_sparse, test_sparse_signature
|
| 351 |
+
m.def("sparse_r", [mat]() -> SparseMatrixR {
|
| 352 |
+
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
| 353 |
+
return Eigen::SparseView<Eigen::MatrixXf>(mat);
|
| 354 |
+
});
|
| 355 |
+
m.def("sparse_c",
|
| 356 |
+
[mat]() -> SparseMatrixC { return Eigen::SparseView<Eigen::MatrixXf>(mat); });
|
| 357 |
+
m.def("sparse_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; });
|
| 358 |
+
m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; });
|
| 359 |
+
// test_partially_fixed
|
| 360 |
+
m.def("partial_copy_four_rm_r", [](const FourRowMatrixR &m) -> FourRowMatrixR { return m; });
|
| 361 |
+
m.def("partial_copy_four_rm_c", [](const FourColMatrixR &m) -> FourColMatrixR { return m; });
|
| 362 |
+
m.def("partial_copy_four_cm_r", [](const FourRowMatrixC &m) -> FourRowMatrixC { return m; });
|
| 363 |
+
m.def("partial_copy_four_cm_c", [](const FourColMatrixC &m) -> FourColMatrixC { return m; });
|
| 364 |
+
|
| 365 |
+
// test_cpp_casting
|
| 366 |
+
// Test that we can cast a numpy object to a Eigen::MatrixXd explicitly
|
| 367 |
+
m.def("cpp_copy", [](py::handle m) { return m.cast<Eigen::MatrixXd>()(1, 0); });
|
| 368 |
+
m.def("cpp_ref_c", [](py::handle m) { return m.cast<Eigen::Ref<Eigen::MatrixXd>>()(1, 0); });
|
| 369 |
+
m.def("cpp_ref_r", [](py::handle m) { return m.cast<Eigen::Ref<MatrixXdR>>()(1, 0); });
|
| 370 |
+
m.def("cpp_ref_any",
|
| 371 |
+
[](py::handle m) { return m.cast<py::EigenDRef<Eigen::MatrixXd>>()(1, 0); });
|
| 372 |
+
|
| 373 |
+
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
| 374 |
+
|
| 375 |
+
// test_nocopy_wrapper
|
| 376 |
+
// Test that we can prevent copying into an argument that would normally copy: First a version
|
| 377 |
+
// that would allow copying (if types or strides don't match) for comparison:
|
| 378 |
+
m.def("get_elem", &get_elem);
|
| 379 |
+
// Now this alternative that calls the tells pybind to fail rather than copy:
|
| 380 |
+
m.def(
|
| 381 |
+
"get_elem_nocopy",
|
| 382 |
+
[](const Eigen::Ref<const Eigen::MatrixXd> &m) -> double { return get_elem(m); },
|
| 383 |
+
py::arg{}.noconvert());
|
| 384 |
+
// Also test a row-major-only no-copy const ref:
|
| 385 |
+
m.def(
|
| 386 |
+
"get_elem_rm_nocopy",
|
| 387 |
+
[](Eigen::Ref<const Eigen::Matrix<long, -1, -1, Eigen::RowMajor>> &m) -> long {
|
| 388 |
+
return m(2, 1);
|
| 389 |
+
},
|
| 390 |
+
py::arg{}.noconvert());
|
| 391 |
+
|
| 392 |
+
// test_issue738, test_zero_length
|
| 393 |
+
// Issue #738: 1×N or N×1 2D matrices were neither accepted nor properly copied with an
|
| 394 |
+
// incompatible stride value on the length-1 dimension--but that should be allowed (without
|
| 395 |
+
// requiring a copy!) because the stride value can be safely ignored on a size-1 dimension.
|
| 396 |
+
// Similarly, 0×N or N×0 matrices were not accepted--again, these should be allowed since
|
| 397 |
+
// they contain no data. This particularly affects numpy ≥ 1.23, which sets the strides to
|
| 398 |
+
// 0 if any dimension size is 0.
|
| 399 |
+
m.def("iss738_f1",
|
| 400 |
+
&adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>,
|
| 401 |
+
py::arg{}.noconvert());
|
| 402 |
+
m.def("iss738_f2",
|
| 403 |
+
&adjust_matrix<const Eigen::Ref<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> &>,
|
| 404 |
+
py::arg{}.noconvert());
|
| 405 |
+
|
| 406 |
+
// test_issue1105
|
| 407 |
+
// Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense
|
| 408 |
+
// eigen Vector or RowVector, the argument would fail to load because the numpy copy would
|
| 409 |
+
// fail: numpy won't broadcast a Nx1 into a 1-dimensional vector.
|
| 410 |
+
m.def("iss1105_col", [](const Eigen::VectorXd &) { return true; });
|
| 411 |
+
m.def("iss1105_row", [](const Eigen::RowVectorXd &) { return true; });
|
| 412 |
+
|
| 413 |
+
// test_named_arguments
|
| 414 |
+
// Make sure named arguments are working properly:
|
| 415 |
+
m.def(
|
| 416 |
+
"matrix_multiply",
|
| 417 |
+
[](const py::EigenDRef<const Eigen::MatrixXd> &A,
|
| 418 |
+
const py::EigenDRef<const Eigen::MatrixXd> &B) -> Eigen::MatrixXd {
|
| 419 |
+
if (A.cols() != B.rows()) {
|
| 420 |
+
throw std::domain_error("Nonconformable matrices!");
|
| 421 |
+
}
|
| 422 |
+
return A * B;
|
| 423 |
+
},
|
| 424 |
+
py::arg("A"),
|
| 425 |
+
py::arg("B"));
|
| 426 |
+
|
| 427 |
+
// test_custom_operator_new
|
| 428 |
+
py::class_<CustomOperatorNew>(m, "CustomOperatorNew")
|
| 429 |
+
.def(py::init<>())
|
| 430 |
+
.def_readonly("a", &CustomOperatorNew::a)
|
| 431 |
+
.def_readonly("b", &CustomOperatorNew::b);
|
| 432 |
+
|
| 433 |
+
// test_eigen_ref_life_support
|
| 434 |
+
// In case of a failure (the caster's temp array does not live long enough), creating
|
| 435 |
+
// a new array (np.ones(10)) increases the chances that the temp array will be garbage
|
| 436 |
+
// collected and/or that its memory will be overridden with different values.
|
| 437 |
+
m.def("get_elem_direct", [](const Eigen::Ref<const Eigen::VectorXd> &v) {
|
| 438 |
+
py::module_::import("numpy").attr("ones")(10);
|
| 439 |
+
return v(5);
|
| 440 |
+
});
|
| 441 |
+
m.def("get_elem_indirect", [](std::vector<Eigen::Ref<const Eigen::VectorXd>> v) {
|
| 442 |
+
py::module_::import("numpy").attr("ones")(10);
|
| 443 |
+
return v[0](5);
|
| 444 |
+
});
|
| 445 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_eigen_matrix.py
CHANGED
|
@@ -1,814 +1,814 @@
|
|
| 1 |
-
import pytest
|
| 2 |
-
|
| 3 |
-
from pybind11_tests import ConstructorStats
|
| 4 |
-
|
| 5 |
-
np = pytest.importorskip("numpy")
|
| 6 |
-
m = pytest.importorskip("pybind11_tests.eigen_matrix")
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
ref = np.array(
|
| 10 |
-
[
|
| 11 |
-
[0.0, 3, 0, 0, 0, 11],
|
| 12 |
-
[22, 0, 0, 0, 17, 11],
|
| 13 |
-
[7, 5, 0, 1, 0, 11],
|
| 14 |
-
[0, 0, 0, 0, 0, 11],
|
| 15 |
-
[0, 0, 14, 0, 8, 11],
|
| 16 |
-
]
|
| 17 |
-
)
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
def assert_equal_ref(mat):
|
| 21 |
-
np.testing.assert_array_equal(mat, ref)
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
def assert_sparse_equal_ref(sparse_mat):
|
| 25 |
-
assert_equal_ref(sparse_mat.toarray())
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
def test_fixed():
|
| 29 |
-
assert_equal_ref(m.fixed_c())
|
| 30 |
-
assert_equal_ref(m.fixed_r())
|
| 31 |
-
assert_equal_ref(m.fixed_copy_r(m.fixed_r()))
|
| 32 |
-
assert_equal_ref(m.fixed_copy_c(m.fixed_c()))
|
| 33 |
-
assert_equal_ref(m.fixed_copy_r(m.fixed_c()))
|
| 34 |
-
assert_equal_ref(m.fixed_copy_c(m.fixed_r()))
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
def test_dense():
|
| 38 |
-
assert_equal_ref(m.dense_r())
|
| 39 |
-
assert_equal_ref(m.dense_c())
|
| 40 |
-
assert_equal_ref(m.dense_copy_r(m.dense_r()))
|
| 41 |
-
assert_equal_ref(m.dense_copy_c(m.dense_c()))
|
| 42 |
-
assert_equal_ref(m.dense_copy_r(m.dense_c()))
|
| 43 |
-
assert_equal_ref(m.dense_copy_c(m.dense_r()))
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
def test_partially_fixed():
|
| 47 |
-
ref2 = np.array([[0.0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]])
|
| 48 |
-
np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2), ref2)
|
| 49 |
-
np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2), ref2)
|
| 50 |
-
np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]])
|
| 51 |
-
np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :])
|
| 52 |
-
np.testing.assert_array_equal(
|
| 53 |
-
m.partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]
|
| 54 |
-
)
|
| 55 |
-
np.testing.assert_array_equal(
|
| 56 |
-
m.partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]
|
| 57 |
-
)
|
| 58 |
-
|
| 59 |
-
np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2), ref2)
|
| 60 |
-
np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2), ref2)
|
| 61 |
-
np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]])
|
| 62 |
-
np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :])
|
| 63 |
-
np.testing.assert_array_equal(
|
| 64 |
-
m.partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]
|
| 65 |
-
)
|
| 66 |
-
np.testing.assert_array_equal(
|
| 67 |
-
m.partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]
|
| 68 |
-
)
|
| 69 |
-
|
| 70 |
-
# TypeError should be raise for a shape mismatch
|
| 71 |
-
functions = [
|
| 72 |
-
m.partial_copy_four_rm_r,
|
| 73 |
-
m.partial_copy_four_rm_c,
|
| 74 |
-
m.partial_copy_four_cm_r,
|
| 75 |
-
m.partial_copy_four_cm_c,
|
| 76 |
-
]
|
| 77 |
-
matrix_with_wrong_shape = [[1, 2], [3, 4]]
|
| 78 |
-
for f in functions:
|
| 79 |
-
with pytest.raises(TypeError) as excinfo:
|
| 80 |
-
f(matrix_with_wrong_shape)
|
| 81 |
-
assert "incompatible function arguments" in str(excinfo.value)
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
def test_mutator_descriptors():
|
| 85 |
-
zr = np.arange(30, dtype="float32").reshape(5, 6) # row-major
|
| 86 |
-
zc = zr.reshape(6, 5).transpose() # column-major
|
| 87 |
-
|
| 88 |
-
m.fixed_mutator_r(zr)
|
| 89 |
-
m.fixed_mutator_c(zc)
|
| 90 |
-
m.fixed_mutator_a(zr)
|
| 91 |
-
m.fixed_mutator_a(zc)
|
| 92 |
-
with pytest.raises(TypeError) as excinfo:
|
| 93 |
-
m.fixed_mutator_r(zc)
|
| 94 |
-
assert (
|
| 95 |
-
"(arg0: numpy.ndarray[numpy.float32[5, 6],"
|
| 96 |
-
" flags.writeable, flags.c_contiguous]) -> None" in str(excinfo.value)
|
| 97 |
-
)
|
| 98 |
-
with pytest.raises(TypeError) as excinfo:
|
| 99 |
-
m.fixed_mutator_c(zr)
|
| 100 |
-
assert (
|
| 101 |
-
"(arg0: numpy.ndarray[numpy.float32[5, 6],"
|
| 102 |
-
" flags.writeable, flags.f_contiguous]) -> None" in str(excinfo.value)
|
| 103 |
-
)
|
| 104 |
-
with pytest.raises(TypeError) as excinfo:
|
| 105 |
-
m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype="float32"))
|
| 106 |
-
assert "(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None" in str(
|
| 107 |
-
excinfo.value
|
| 108 |
-
)
|
| 109 |
-
zr.flags.writeable = False
|
| 110 |
-
with pytest.raises(TypeError):
|
| 111 |
-
m.fixed_mutator_r(zr)
|
| 112 |
-
with pytest.raises(TypeError):
|
| 113 |
-
m.fixed_mutator_a(zr)
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
def test_cpp_casting():
|
| 117 |
-
assert m.cpp_copy(m.fixed_r()) == 22.0
|
| 118 |
-
assert m.cpp_copy(m.fixed_c()) == 22.0
|
| 119 |
-
z = np.array([[5.0, 6], [7, 8]])
|
| 120 |
-
assert m.cpp_copy(z) == 7.0
|
| 121 |
-
assert m.cpp_copy(m.get_cm_ref()) == 21.0
|
| 122 |
-
assert m.cpp_copy(m.get_rm_ref()) == 21.0
|
| 123 |
-
assert m.cpp_ref_c(m.get_cm_ref()) == 21.0
|
| 124 |
-
assert m.cpp_ref_r(m.get_rm_ref()) == 21.0
|
| 125 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 126 |
-
# Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles
|
| 127 |
-
m.cpp_ref_any(m.fixed_c())
|
| 128 |
-
assert "Unable to cast Python instance" in str(excinfo.value)
|
| 129 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 130 |
-
# Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles
|
| 131 |
-
m.cpp_ref_any(m.fixed_r())
|
| 132 |
-
assert "Unable to cast Python instance" in str(excinfo.value)
|
| 133 |
-
assert m.cpp_ref_any(m.ReturnTester.create()) == 1.0
|
| 134 |
-
|
| 135 |
-
assert m.cpp_ref_any(m.get_cm_ref()) == 21.0
|
| 136 |
-
assert m.cpp_ref_any(m.get_cm_ref()) == 21.0
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
def test_pass_readonly_array():
|
| 140 |
-
z = np.full((5, 6), 42.0)
|
| 141 |
-
z.flags.writeable = False
|
| 142 |
-
np.testing.assert_array_equal(z, m.fixed_copy_r(z))
|
| 143 |
-
np.testing.assert_array_equal(m.fixed_r_const(), m.fixed_r())
|
| 144 |
-
assert not m.fixed_r_const().flags.writeable
|
| 145 |
-
np.testing.assert_array_equal(m.fixed_copy_r(m.fixed_r_const()), m.fixed_r_const())
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
def test_nonunit_stride_from_python():
|
| 149 |
-
counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
|
| 150 |
-
second_row = counting_mat[1, :]
|
| 151 |
-
second_col = counting_mat[:, 1]
|
| 152 |
-
np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
|
| 153 |
-
np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
|
| 154 |
-
np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
|
| 155 |
-
np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
|
| 156 |
-
np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
|
| 157 |
-
np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
|
| 158 |
-
|
| 159 |
-
counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
|
| 160 |
-
slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
|
| 161 |
-
for ref_mat in slices:
|
| 162 |
-
np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
|
| 163 |
-
np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
|
| 164 |
-
|
| 165 |
-
# Mutator:
|
| 166 |
-
m.double_threer(second_row)
|
| 167 |
-
m.double_threec(second_col)
|
| 168 |
-
np.testing.assert_array_equal(counting_mat, [[0.0, 2, 2], [6, 16, 10], [6, 14, 8]])
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
def test_negative_stride_from_python(msg):
|
| 172 |
-
"""Eigen doesn't support (as of yet) negative strides. When a function takes an Eigen matrix by
|
| 173 |
-
copy or const reference, we can pass a numpy array that has negative strides. Otherwise, an
|
| 174 |
-
exception will be thrown as Eigen will not be able to map the numpy array."""
|
| 175 |
-
|
| 176 |
-
counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
|
| 177 |
-
counting_mat = counting_mat[::-1, ::-1]
|
| 178 |
-
second_row = counting_mat[1, :]
|
| 179 |
-
second_col = counting_mat[:, 1]
|
| 180 |
-
np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
|
| 181 |
-
np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
|
| 182 |
-
np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
|
| 183 |
-
np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
|
| 184 |
-
np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
|
| 185 |
-
np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
|
| 186 |
-
|
| 187 |
-
counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
|
| 188 |
-
counting_3d = counting_3d[::-1, ::-1, ::-1]
|
| 189 |
-
slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
|
| 190 |
-
for ref_mat in slices:
|
| 191 |
-
np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
|
| 192 |
-
np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
|
| 193 |
-
|
| 194 |
-
# Mutator:
|
| 195 |
-
with pytest.raises(TypeError) as excinfo:
|
| 196 |
-
m.double_threer(second_row)
|
| 197 |
-
assert (
|
| 198 |
-
msg(excinfo.value)
|
| 199 |
-
== """
|
| 200 |
-
double_threer(): incompatible function arguments. The following argument types are supported:
|
| 201 |
-
1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None
|
| 202 |
-
|
| 203 |
-
Invoked with: """
|
| 204 |
-
+ repr(np.array([5.0, 4.0, 3.0], dtype="float32"))
|
| 205 |
-
)
|
| 206 |
-
|
| 207 |
-
with pytest.raises(TypeError) as excinfo:
|
| 208 |
-
m.double_threec(second_col)
|
| 209 |
-
assert (
|
| 210 |
-
msg(excinfo.value)
|
| 211 |
-
== """
|
| 212 |
-
double_threec(): incompatible function arguments. The following argument types are supported:
|
| 213 |
-
1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None
|
| 214 |
-
|
| 215 |
-
Invoked with: """
|
| 216 |
-
+ repr(np.array([7.0, 4.0, 1.0], dtype="float32"))
|
| 217 |
-
)
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
def test_block_runtime_error_type_caster_eigen_ref_made_a_copy():
|
| 221 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 222 |
-
m.block(ref, 0, 0, 0, 0)
|
| 223 |
-
assert str(excinfo.value) == "type_caster for Eigen::Ref made a copy."
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
def test_nonunit_stride_to_python():
|
| 227 |
-
assert np.all(m.diagonal(ref) == ref.diagonal())
|
| 228 |
-
assert np.all(m.diagonal_1(ref) == ref.diagonal(1))
|
| 229 |
-
for i in range(-5, 7):
|
| 230 |
-
assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), f"m.diagonal_n({i})"
|
| 231 |
-
|
| 232 |
-
# Must be order="F", otherwise the type_caster will make a copy and
|
| 233 |
-
# m.block() will return a dangling reference (heap-use-after-free).
|
| 234 |
-
rof = np.asarray(ref, order="F")
|
| 235 |
-
assert np.all(m.block(rof, 2, 1, 3, 3) == rof[2:5, 1:4])
|
| 236 |
-
assert np.all(m.block(rof, 1, 4, 4, 2) == rof[1:, 4:])
|
| 237 |
-
assert np.all(m.block(rof, 1, 4, 3, 2) == rof[1:4, 4:])
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
def test_eigen_ref_to_python():
|
| 241 |
-
chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4]
|
| 242 |
-
for i, chol in enumerate(chols, start=1):
|
| 243 |
-
mymat = chol(np.array([[1.0, 2, 4], [2, 13, 23], [4, 23, 77]]))
|
| 244 |
-
assert np.all(
|
| 245 |
-
mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])
|
| 246 |
-
), f"cholesky{i}"
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
def assign_both(a1, a2, r, c, v):
|
| 250 |
-
a1[r, c] = v
|
| 251 |
-
a2[r, c] = v
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
def array_copy_but_one(a, r, c, v):
|
| 255 |
-
z = np.array(a, copy=True)
|
| 256 |
-
z[r, c] = v
|
| 257 |
-
return z
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
def test_eigen_return_references():
|
| 261 |
-
"""Tests various ways of returning references and non-referencing copies"""
|
| 262 |
-
|
| 263 |
-
primary = np.ones((10, 10))
|
| 264 |
-
a = m.ReturnTester()
|
| 265 |
-
a_get1 = a.get()
|
| 266 |
-
assert not a_get1.flags.owndata
|
| 267 |
-
assert a_get1.flags.writeable
|
| 268 |
-
assign_both(a_get1, primary, 3, 3, 5)
|
| 269 |
-
a_get2 = a.get_ptr()
|
| 270 |
-
assert not a_get2.flags.owndata
|
| 271 |
-
assert a_get2.flags.writeable
|
| 272 |
-
assign_both(a_get1, primary, 2, 3, 6)
|
| 273 |
-
|
| 274 |
-
a_view1 = a.view()
|
| 275 |
-
assert not a_view1.flags.owndata
|
| 276 |
-
assert not a_view1.flags.writeable
|
| 277 |
-
with pytest.raises(ValueError):
|
| 278 |
-
a_view1[2, 3] = 4
|
| 279 |
-
a_view2 = a.view_ptr()
|
| 280 |
-
assert not a_view2.flags.owndata
|
| 281 |
-
assert not a_view2.flags.writeable
|
| 282 |
-
with pytest.raises(ValueError):
|
| 283 |
-
a_view2[2, 3] = 4
|
| 284 |
-
|
| 285 |
-
a_copy1 = a.copy_get()
|
| 286 |
-
assert a_copy1.flags.owndata
|
| 287 |
-
assert a_copy1.flags.writeable
|
| 288 |
-
np.testing.assert_array_equal(a_copy1, primary)
|
| 289 |
-
a_copy1[7, 7] = -44 # Shouldn't affect anything else
|
| 290 |
-
c1want = array_copy_but_one(primary, 7, 7, -44)
|
| 291 |
-
a_copy2 = a.copy_view()
|
| 292 |
-
assert a_copy2.flags.owndata
|
| 293 |
-
assert a_copy2.flags.writeable
|
| 294 |
-
np.testing.assert_array_equal(a_copy2, primary)
|
| 295 |
-
a_copy2[4, 4] = -22 # Shouldn't affect anything else
|
| 296 |
-
c2want = array_copy_but_one(primary, 4, 4, -22)
|
| 297 |
-
|
| 298 |
-
a_ref1 = a.ref()
|
| 299 |
-
assert not a_ref1.flags.owndata
|
| 300 |
-
assert a_ref1.flags.writeable
|
| 301 |
-
assign_both(a_ref1, primary, 1, 1, 15)
|
| 302 |
-
a_ref2 = a.ref_const()
|
| 303 |
-
assert not a_ref2.flags.owndata
|
| 304 |
-
assert not a_ref2.flags.writeable
|
| 305 |
-
with pytest.raises(ValueError):
|
| 306 |
-
a_ref2[5, 5] = 33
|
| 307 |
-
a_ref3 = a.ref_safe()
|
| 308 |
-
assert not a_ref3.flags.owndata
|
| 309 |
-
assert a_ref3.flags.writeable
|
| 310 |
-
assign_both(a_ref3, primary, 0, 7, 99)
|
| 311 |
-
a_ref4 = a.ref_const_safe()
|
| 312 |
-
assert not a_ref4.flags.owndata
|
| 313 |
-
assert not a_ref4.flags.writeable
|
| 314 |
-
with pytest.raises(ValueError):
|
| 315 |
-
a_ref4[7, 0] = 987654321
|
| 316 |
-
|
| 317 |
-
a_copy3 = a.copy_ref()
|
| 318 |
-
assert a_copy3.flags.owndata
|
| 319 |
-
assert a_copy3.flags.writeable
|
| 320 |
-
np.testing.assert_array_equal(a_copy3, primary)
|
| 321 |
-
a_copy3[8, 1] = 11
|
| 322 |
-
c3want = array_copy_but_one(primary, 8, 1, 11)
|
| 323 |
-
a_copy4 = a.copy_ref_const()
|
| 324 |
-
assert a_copy4.flags.owndata
|
| 325 |
-
assert a_copy4.flags.writeable
|
| 326 |
-
np.testing.assert_array_equal(a_copy4, primary)
|
| 327 |
-
a_copy4[8, 4] = 88
|
| 328 |
-
c4want = array_copy_but_one(primary, 8, 4, 88)
|
| 329 |
-
|
| 330 |
-
a_block1 = a.block(3, 3, 2, 2)
|
| 331 |
-
assert not a_block1.flags.owndata
|
| 332 |
-
assert a_block1.flags.writeable
|
| 333 |
-
a_block1[0, 0] = 55
|
| 334 |
-
primary[3, 3] = 55
|
| 335 |
-
a_block2 = a.block_safe(2, 2, 3, 2)
|
| 336 |
-
assert not a_block2.flags.owndata
|
| 337 |
-
assert a_block2.flags.writeable
|
| 338 |
-
a_block2[2, 1] = -123
|
| 339 |
-
primary[4, 3] = -123
|
| 340 |
-
a_block3 = a.block_const(6, 7, 4, 3)
|
| 341 |
-
assert not a_block3.flags.owndata
|
| 342 |
-
assert not a_block3.flags.writeable
|
| 343 |
-
with pytest.raises(ValueError):
|
| 344 |
-
a_block3[2, 2] = -44444
|
| 345 |
-
|
| 346 |
-
a_copy5 = a.copy_block(2, 2, 2, 3)
|
| 347 |
-
assert a_copy5.flags.owndata
|
| 348 |
-
assert a_copy5.flags.writeable
|
| 349 |
-
np.testing.assert_array_equal(a_copy5, primary[2:4, 2:5])
|
| 350 |
-
a_copy5[1, 1] = 777
|
| 351 |
-
c5want = array_copy_but_one(primary[2:4, 2:5], 1, 1, 777)
|
| 352 |
-
|
| 353 |
-
a_corn1 = a.corners()
|
| 354 |
-
assert not a_corn1.flags.owndata
|
| 355 |
-
assert a_corn1.flags.writeable
|
| 356 |
-
a_corn1 *= 50
|
| 357 |
-
a_corn1[1, 1] = 999
|
| 358 |
-
primary[0, 0] = 50
|
| 359 |
-
primary[0, 9] = 50
|
| 360 |
-
primary[9, 0] = 50
|
| 361 |
-
primary[9, 9] = 999
|
| 362 |
-
a_corn2 = a.corners_const()
|
| 363 |
-
assert not a_corn2.flags.owndata
|
| 364 |
-
assert not a_corn2.flags.writeable
|
| 365 |
-
with pytest.raises(ValueError):
|
| 366 |
-
a_corn2[1, 0] = 51
|
| 367 |
-
|
| 368 |
-
# All of the changes made all the way along should be visible everywhere
|
| 369 |
-
# now (except for the copies, of course)
|
| 370 |
-
np.testing.assert_array_equal(a_get1, primary)
|
| 371 |
-
np.testing.assert_array_equal(a_get2, primary)
|
| 372 |
-
np.testing.assert_array_equal(a_view1, primary)
|
| 373 |
-
np.testing.assert_array_equal(a_view2, primary)
|
| 374 |
-
np.testing.assert_array_equal(a_ref1, primary)
|
| 375 |
-
np.testing.assert_array_equal(a_ref2, primary)
|
| 376 |
-
np.testing.assert_array_equal(a_ref3, primary)
|
| 377 |
-
np.testing.assert_array_equal(a_ref4, primary)
|
| 378 |
-
np.testing.assert_array_equal(a_block1, primary[3:5, 3:5])
|
| 379 |
-
np.testing.assert_array_equal(a_block2, primary[2:5, 2:4])
|
| 380 |
-
np.testing.assert_array_equal(a_block3, primary[6:10, 7:10])
|
| 381 |
-
np.testing.assert_array_equal(
|
| 382 |
-
a_corn1, primary[0 :: primary.shape[0] - 1, 0 :: primary.shape[1] - 1]
|
| 383 |
-
)
|
| 384 |
-
np.testing.assert_array_equal(
|
| 385 |
-
a_corn2, primary[0 :: primary.shape[0] - 1, 0 :: primary.shape[1] - 1]
|
| 386 |
-
)
|
| 387 |
-
|
| 388 |
-
np.testing.assert_array_equal(a_copy1, c1want)
|
| 389 |
-
np.testing.assert_array_equal(a_copy2, c2want)
|
| 390 |
-
np.testing.assert_array_equal(a_copy3, c3want)
|
| 391 |
-
np.testing.assert_array_equal(a_copy4, c4want)
|
| 392 |
-
np.testing.assert_array_equal(a_copy5, c5want)
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
def assert_keeps_alive(cl, method, *args):
|
| 396 |
-
cstats = ConstructorStats.get(cl)
|
| 397 |
-
start_with = cstats.alive()
|
| 398 |
-
a = cl()
|
| 399 |
-
assert cstats.alive() == start_with + 1
|
| 400 |
-
z = method(a, *args)
|
| 401 |
-
assert cstats.alive() == start_with + 1
|
| 402 |
-
del a
|
| 403 |
-
# Here's the keep alive in action:
|
| 404 |
-
assert cstats.alive() == start_with + 1
|
| 405 |
-
del z
|
| 406 |
-
# Keep alive should have expired:
|
| 407 |
-
assert cstats.alive() == start_with
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
def test_eigen_keepalive():
|
| 411 |
-
a = m.ReturnTester()
|
| 412 |
-
cstats = ConstructorStats.get(m.ReturnTester)
|
| 413 |
-
assert cstats.alive() == 1
|
| 414 |
-
unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)]
|
| 415 |
-
copies = [
|
| 416 |
-
a.copy_get(),
|
| 417 |
-
a.copy_view(),
|
| 418 |
-
a.copy_ref(),
|
| 419 |
-
a.copy_ref_const(),
|
| 420 |
-
a.copy_block(4, 3, 2, 1),
|
| 421 |
-
]
|
| 422 |
-
del a
|
| 423 |
-
assert cstats.alive() == 0
|
| 424 |
-
del unsafe
|
| 425 |
-
del copies
|
| 426 |
-
|
| 427 |
-
for meth in [
|
| 428 |
-
m.ReturnTester.get,
|
| 429 |
-
m.ReturnTester.get_ptr,
|
| 430 |
-
m.ReturnTester.view,
|
| 431 |
-
m.ReturnTester.view_ptr,
|
| 432 |
-
m.ReturnTester.ref_safe,
|
| 433 |
-
m.ReturnTester.ref_const_safe,
|
| 434 |
-
m.ReturnTester.corners,
|
| 435 |
-
m.ReturnTester.corners_const,
|
| 436 |
-
]:
|
| 437 |
-
assert_keeps_alive(m.ReturnTester, meth)
|
| 438 |
-
|
| 439 |
-
for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]:
|
| 440 |
-
assert_keeps_alive(m.ReturnTester, meth, 4, 3, 2, 1)
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
def test_eigen_ref_mutators():
|
| 444 |
-
"""Tests Eigen's ability to mutate numpy values"""
|
| 445 |
-
|
| 446 |
-
orig = np.array([[1.0, 2, 3], [4, 5, 6], [7, 8, 9]])
|
| 447 |
-
zr = np.array(orig)
|
| 448 |
-
zc = np.array(orig, order="F")
|
| 449 |
-
m.add_rm(zr, 1, 0, 100)
|
| 450 |
-
assert np.all(zr == np.array([[1.0, 2, 3], [104, 5, 6], [7, 8, 9]]))
|
| 451 |
-
m.add_cm(zc, 1, 0, 200)
|
| 452 |
-
assert np.all(zc == np.array([[1.0, 2, 3], [204, 5, 6], [7, 8, 9]]))
|
| 453 |
-
|
| 454 |
-
m.add_any(zr, 1, 0, 20)
|
| 455 |
-
assert np.all(zr == np.array([[1.0, 2, 3], [124, 5, 6], [7, 8, 9]]))
|
| 456 |
-
m.add_any(zc, 1, 0, 10)
|
| 457 |
-
assert np.all(zc == np.array([[1.0, 2, 3], [214, 5, 6], [7, 8, 9]]))
|
| 458 |
-
|
| 459 |
-
# Can't reference a col-major array with a row-major Ref, and vice versa:
|
| 460 |
-
with pytest.raises(TypeError):
|
| 461 |
-
m.add_rm(zc, 1, 0, 1)
|
| 462 |
-
with pytest.raises(TypeError):
|
| 463 |
-
m.add_cm(zr, 1, 0, 1)
|
| 464 |
-
|
| 465 |
-
# Overloads:
|
| 466 |
-
m.add1(zr, 1, 0, -100)
|
| 467 |
-
m.add2(zr, 1, 0, -20)
|
| 468 |
-
assert np.all(zr == orig)
|
| 469 |
-
m.add1(zc, 1, 0, -200)
|
| 470 |
-
m.add2(zc, 1, 0, -10)
|
| 471 |
-
assert np.all(zc == orig)
|
| 472 |
-
|
| 473 |
-
# a non-contiguous slice (this won't work on either the row- or
|
| 474 |
-
# column-contiguous refs, but should work for the any)
|
| 475 |
-
cornersr = zr[0::2, 0::2]
|
| 476 |
-
cornersc = zc[0::2, 0::2]
|
| 477 |
-
|
| 478 |
-
assert np.all(cornersr == np.array([[1.0, 3], [7, 9]]))
|
| 479 |
-
assert np.all(cornersc == np.array([[1.0, 3], [7, 9]]))
|
| 480 |
-
|
| 481 |
-
with pytest.raises(TypeError):
|
| 482 |
-
m.add_rm(cornersr, 0, 1, 25)
|
| 483 |
-
with pytest.raises(TypeError):
|
| 484 |
-
m.add_cm(cornersr, 0, 1, 25)
|
| 485 |
-
with pytest.raises(TypeError):
|
| 486 |
-
m.add_rm(cornersc, 0, 1, 25)
|
| 487 |
-
with pytest.raises(TypeError):
|
| 488 |
-
m.add_cm(cornersc, 0, 1, 25)
|
| 489 |
-
m.add_any(cornersr, 0, 1, 25)
|
| 490 |
-
m.add_any(cornersc, 0, 1, 44)
|
| 491 |
-
assert np.all(zr == np.array([[1.0, 2, 28], [4, 5, 6], [7, 8, 9]]))
|
| 492 |
-
assert np.all(zc == np.array([[1.0, 2, 47], [4, 5, 6], [7, 8, 9]]))
|
| 493 |
-
|
| 494 |
-
# You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method:
|
| 495 |
-
zro = zr[0:4, 0:4]
|
| 496 |
-
zro.flags.writeable = False
|
| 497 |
-
with pytest.raises(TypeError):
|
| 498 |
-
m.add_rm(zro, 0, 0, 0)
|
| 499 |
-
with pytest.raises(TypeError):
|
| 500 |
-
m.add_any(zro, 0, 0, 0)
|
| 501 |
-
with pytest.raises(TypeError):
|
| 502 |
-
m.add1(zro, 0, 0, 0)
|
| 503 |
-
with pytest.raises(TypeError):
|
| 504 |
-
m.add2(zro, 0, 0, 0)
|
| 505 |
-
|
| 506 |
-
# integer array shouldn't be passable to a double-matrix-accepting mutating func:
|
| 507 |
-
zi = np.array([[1, 2], [3, 4]])
|
| 508 |
-
with pytest.raises(TypeError):
|
| 509 |
-
m.add_rm(zi)
|
| 510 |
-
|
| 511 |
-
|
| 512 |
-
def test_numpy_ref_mutators():
|
| 513 |
-
"""Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)"""
|
| 514 |
-
|
| 515 |
-
m.reset_refs() # In case another test already changed it
|
| 516 |
-
|
| 517 |
-
zc = m.get_cm_ref()
|
| 518 |
-
zcro = m.get_cm_const_ref()
|
| 519 |
-
zr = m.get_rm_ref()
|
| 520 |
-
zrro = m.get_rm_const_ref()
|
| 521 |
-
|
| 522 |
-
assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4
|
| 523 |
-
|
| 524 |
-
assert not zc.flags.owndata
|
| 525 |
-
assert zc.flags.writeable
|
| 526 |
-
assert not zr.flags.owndata
|
| 527 |
-
assert zr.flags.writeable
|
| 528 |
-
assert not zcro.flags.owndata
|
| 529 |
-
assert not zcro.flags.writeable
|
| 530 |
-
assert not zrro.flags.owndata
|
| 531 |
-
assert not zrro.flags.writeable
|
| 532 |
-
|
| 533 |
-
zc[1, 2] = 99
|
| 534 |
-
expect = np.array([[11.0, 12, 13], [21, 22, 99], [31, 32, 33]])
|
| 535 |
-
# We should have just changed zc, of course, but also zcro and the original eigen matrix
|
| 536 |
-
assert np.all(zc == expect)
|
| 537 |
-
assert np.all(zcro == expect)
|
| 538 |
-
assert np.all(m.get_cm_ref() == expect)
|
| 539 |
-
|
| 540 |
-
zr[1, 2] = 99
|
| 541 |
-
assert np.all(zr == expect)
|
| 542 |
-
assert np.all(zrro == expect)
|
| 543 |
-
assert np.all(m.get_rm_ref() == expect)
|
| 544 |
-
|
| 545 |
-
# Make sure the readonly ones are numpy-readonly:
|
| 546 |
-
with pytest.raises(ValueError):
|
| 547 |
-
zcro[1, 2] = 6
|
| 548 |
-
with pytest.raises(ValueError):
|
| 549 |
-
zrro[1, 2] = 6
|
| 550 |
-
|
| 551 |
-
# We should be able to explicitly copy like this (and since we're copying,
|
| 552 |
-
# the const should drop away)
|
| 553 |
-
y1 = np.array(m.get_cm_const_ref())
|
| 554 |
-
|
| 555 |
-
assert y1.flags.owndata
|
| 556 |
-
assert y1.flags.writeable
|
| 557 |
-
# We should get copies of the eigen data, which was modified above:
|
| 558 |
-
assert y1[1, 2] == 99
|
| 559 |
-
y1[1, 2] += 12
|
| 560 |
-
assert y1[1, 2] == 111
|
| 561 |
-
assert zc[1, 2] == 99 # Make sure we aren't referencing the original
|
| 562 |
-
|
| 563 |
-
|
| 564 |
-
def test_both_ref_mutators():
|
| 565 |
-
"""Tests a complex chain of nested eigen/numpy references"""
|
| 566 |
-
|
| 567 |
-
m.reset_refs() # In case another test already changed it
|
| 568 |
-
|
| 569 |
-
z = m.get_cm_ref() # numpy -> eigen
|
| 570 |
-
z[0, 2] -= 3
|
| 571 |
-
z2 = m.incr_matrix(z, 1) # numpy -> eigen -> numpy -> eigen
|
| 572 |
-
z2[1, 1] += 6
|
| 573 |
-
z3 = m.incr_matrix(z, 2) # (numpy -> eigen)^3
|
| 574 |
-
z3[2, 2] += -5
|
| 575 |
-
z4 = m.incr_matrix(z, 3) # (numpy -> eigen)^4
|
| 576 |
-
z4[1, 1] -= 1
|
| 577 |
-
z5 = m.incr_matrix(z, 4) # (numpy -> eigen)^5
|
| 578 |
-
z5[0, 0] = 0
|
| 579 |
-
assert np.all(z == z2)
|
| 580 |
-
assert np.all(z == z3)
|
| 581 |
-
assert np.all(z == z4)
|
| 582 |
-
assert np.all(z == z5)
|
| 583 |
-
expect = np.array([[0.0, 22, 20], [31, 37, 33], [41, 42, 38]])
|
| 584 |
-
assert np.all(z == expect)
|
| 585 |
-
|
| 586 |
-
y = np.array(range(100), dtype="float64").reshape(10, 10)
|
| 587 |
-
y2 = m.incr_matrix_any(y, 10) # np -> eigen -> np
|
| 588 |
-
y3 = m.incr_matrix_any(
|
| 589 |
-
y2[0::2, 0::2], -33
|
| 590 |
-
) # np -> eigen -> np slice -> np -> eigen -> np
|
| 591 |
-
y4 = m.even_rows(y3) # numpy -> eigen slice -> (... y3)
|
| 592 |
-
y5 = m.even_cols(y4) # numpy -> eigen slice -> (... y4)
|
| 593 |
-
y6 = m.incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5)
|
| 594 |
-
|
| 595 |
-
# Apply same mutations using just numpy:
|
| 596 |
-
yexpect = np.array(range(100), dtype="float64").reshape(10, 10)
|
| 597 |
-
yexpect += 10
|
| 598 |
-
yexpect[0::2, 0::2] -= 33
|
| 599 |
-
yexpect[0::4, 0::4] += 1000
|
| 600 |
-
assert np.all(y6 == yexpect[0::4, 0::4])
|
| 601 |
-
assert np.all(y5 == yexpect[0::4, 0::4])
|
| 602 |
-
assert np.all(y4 == yexpect[0::4, 0::2])
|
| 603 |
-
assert np.all(y3 == yexpect[0::2, 0::2])
|
| 604 |
-
assert np.all(y2 == yexpect)
|
| 605 |
-
assert np.all(y == yexpect)
|
| 606 |
-
|
| 607 |
-
|
| 608 |
-
def test_nocopy_wrapper():
|
| 609 |
-
# get_elem requires a column-contiguous matrix reference, but should be
|
| 610 |
-
# callable with other types of matrix (via copying):
|
| 611 |
-
int_matrix_colmajor = np.array(
|
| 612 |
-
[[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype="l", order="F"
|
| 613 |
-
)
|
| 614 |
-
dbl_matrix_colmajor = np.array(
|
| 615 |
-
int_matrix_colmajor, dtype="double", order="F", copy=True
|
| 616 |
-
)
|
| 617 |
-
int_matrix_rowmajor = np.array(int_matrix_colmajor, order="C", copy=True)
|
| 618 |
-
dbl_matrix_rowmajor = np.array(
|
| 619 |
-
int_matrix_rowmajor, dtype="double", order="C", copy=True
|
| 620 |
-
)
|
| 621 |
-
|
| 622 |
-
# All should be callable via get_elem:
|
| 623 |
-
assert m.get_elem(int_matrix_colmajor) == 8
|
| 624 |
-
assert m.get_elem(dbl_matrix_colmajor) == 8
|
| 625 |
-
assert m.get_elem(int_matrix_rowmajor) == 8
|
| 626 |
-
assert m.get_elem(dbl_matrix_rowmajor) == 8
|
| 627 |
-
|
| 628 |
-
# All but the second should fail with m.get_elem_nocopy:
|
| 629 |
-
with pytest.raises(TypeError) as excinfo:
|
| 630 |
-
m.get_elem_nocopy(int_matrix_colmajor)
|
| 631 |
-
assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
|
| 632 |
-
assert ", flags.f_contiguous" in str(excinfo.value)
|
| 633 |
-
assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8
|
| 634 |
-
with pytest.raises(TypeError) as excinfo:
|
| 635 |
-
m.get_elem_nocopy(int_matrix_rowmajor)
|
| 636 |
-
assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
|
| 637 |
-
assert ", flags.f_contiguous" in str(excinfo.value)
|
| 638 |
-
with pytest.raises(TypeError) as excinfo:
|
| 639 |
-
m.get_elem_nocopy(dbl_matrix_rowmajor)
|
| 640 |
-
assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
|
| 641 |
-
assert ", flags.f_contiguous" in str(excinfo.value)
|
| 642 |
-
|
| 643 |
-
# For the row-major test, we take a long matrix in row-major, so only the third is allowed:
|
| 644 |
-
with pytest.raises(TypeError) as excinfo:
|
| 645 |
-
m.get_elem_rm_nocopy(int_matrix_colmajor)
|
| 646 |
-
assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
|
| 647 |
-
excinfo.value
|
| 648 |
-
)
|
| 649 |
-
assert ", flags.c_contiguous" in str(excinfo.value)
|
| 650 |
-
with pytest.raises(TypeError) as excinfo:
|
| 651 |
-
m.get_elem_rm_nocopy(dbl_matrix_colmajor)
|
| 652 |
-
assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
|
| 653 |
-
excinfo.value
|
| 654 |
-
)
|
| 655 |
-
assert ", flags.c_contiguous" in str(excinfo.value)
|
| 656 |
-
assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8
|
| 657 |
-
with pytest.raises(TypeError) as excinfo:
|
| 658 |
-
m.get_elem_rm_nocopy(dbl_matrix_rowmajor)
|
| 659 |
-
assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
|
| 660 |
-
excinfo.value
|
| 661 |
-
)
|
| 662 |
-
assert ", flags.c_contiguous" in str(excinfo.value)
|
| 663 |
-
|
| 664 |
-
|
| 665 |
-
def test_eigen_ref_life_support():
|
| 666 |
-
"""Ensure the lifetime of temporary arrays created by the `Ref` caster
|
| 667 |
-
|
| 668 |
-
The `Ref` caster sometimes creates a copy which needs to stay alive. This needs to
|
| 669 |
-
happen both for directs casts (just the array) or indirectly (e.g. list of arrays).
|
| 670 |
-
"""
|
| 671 |
-
|
| 672 |
-
a = np.full(shape=10, fill_value=8, dtype=np.int8)
|
| 673 |
-
assert m.get_elem_direct(a) == 8
|
| 674 |
-
|
| 675 |
-
list_of_a = [a]
|
| 676 |
-
assert m.get_elem_indirect(list_of_a) == 8
|
| 677 |
-
|
| 678 |
-
|
| 679 |
-
def test_special_matrix_objects():
|
| 680 |
-
assert np.all(m.incr_diag(7) == np.diag([1.0, 2, 3, 4, 5, 6, 7]))
|
| 681 |
-
|
| 682 |
-
asymm = np.array([[1.0, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
|
| 683 |
-
symm_lower = np.array(asymm)
|
| 684 |
-
symm_upper = np.array(asymm)
|
| 685 |
-
for i in range(4):
|
| 686 |
-
for j in range(i + 1, 4):
|
| 687 |
-
symm_lower[i, j] = symm_lower[j, i]
|
| 688 |
-
symm_upper[j, i] = symm_upper[i, j]
|
| 689 |
-
|
| 690 |
-
assert np.all(m.symmetric_lower(asymm) == symm_lower)
|
| 691 |
-
assert np.all(m.symmetric_upper(asymm) == symm_upper)
|
| 692 |
-
|
| 693 |
-
|
| 694 |
-
def test_dense_signature(doc):
|
| 695 |
-
assert (
|
| 696 |
-
doc(m.double_col)
|
| 697 |
-
== """
|
| 698 |
-
double_col(arg0: numpy.ndarray[numpy.float32[m, 1]]) -> numpy.ndarray[numpy.float32[m, 1]]
|
| 699 |
-
"""
|
| 700 |
-
)
|
| 701 |
-
assert (
|
| 702 |
-
doc(m.double_row)
|
| 703 |
-
== """
|
| 704 |
-
double_row(arg0: numpy.ndarray[numpy.float32[1, n]]) -> numpy.ndarray[numpy.float32[1, n]]
|
| 705 |
-
"""
|
| 706 |
-
)
|
| 707 |
-
assert doc(m.double_complex) == (
|
| 708 |
-
"""
|
| 709 |
-
double_complex(arg0: numpy.ndarray[numpy.complex64[m, 1]])"""
|
| 710 |
-
""" -> numpy.ndarray[numpy.complex64[m, 1]]
|
| 711 |
-
"""
|
| 712 |
-
)
|
| 713 |
-
assert doc(m.double_mat_rm) == (
|
| 714 |
-
"""
|
| 715 |
-
double_mat_rm(arg0: numpy.ndarray[numpy.float32[m, n]])"""
|
| 716 |
-
""" -> numpy.ndarray[numpy.float32[m, n]]
|
| 717 |
-
"""
|
| 718 |
-
)
|
| 719 |
-
|
| 720 |
-
|
| 721 |
-
def test_defaults(doc):
|
| 722 |
-
assert "\n" not in str(doc(m.defaults_mat))
|
| 723 |
-
assert "\n" not in str(doc(m.defaults_vec))
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
def test_named_arguments():
|
| 727 |
-
a = np.array([[1.0, 2], [3, 4], [5, 6]])
|
| 728 |
-
b = np.ones((2, 1))
|
| 729 |
-
|
| 730 |
-
assert np.all(m.matrix_multiply(a, b) == np.array([[3.0], [7], [11]]))
|
| 731 |
-
assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.0], [7], [11]]))
|
| 732 |
-
assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.0], [7], [11]]))
|
| 733 |
-
|
| 734 |
-
with pytest.raises(ValueError) as excinfo:
|
| 735 |
-
m.matrix_multiply(b, a)
|
| 736 |
-
assert str(excinfo.value) == "Nonconformable matrices!"
|
| 737 |
-
|
| 738 |
-
with pytest.raises(ValueError) as excinfo:
|
| 739 |
-
m.matrix_multiply(A=b, B=a)
|
| 740 |
-
assert str(excinfo.value) == "Nonconformable matrices!"
|
| 741 |
-
|
| 742 |
-
with pytest.raises(ValueError) as excinfo:
|
| 743 |
-
m.matrix_multiply(B=a, A=b)
|
| 744 |
-
assert str(excinfo.value) == "Nonconformable matrices!"
|
| 745 |
-
|
| 746 |
-
|
| 747 |
-
def test_sparse():
|
| 748 |
-
pytest.importorskip("scipy")
|
| 749 |
-
assert_sparse_equal_ref(m.sparse_r())
|
| 750 |
-
assert_sparse_equal_ref(m.sparse_c())
|
| 751 |
-
assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_r()))
|
| 752 |
-
assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_c()))
|
| 753 |
-
assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_c()))
|
| 754 |
-
assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_r()))
|
| 755 |
-
|
| 756 |
-
|
| 757 |
-
def test_sparse_signature(doc):
|
| 758 |
-
pytest.importorskip("scipy")
|
| 759 |
-
assert (
|
| 760 |
-
doc(m.sparse_copy_r)
|
| 761 |
-
== """
|
| 762 |
-
sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32]
|
| 763 |
-
"""
|
| 764 |
-
)
|
| 765 |
-
assert (
|
| 766 |
-
doc(m.sparse_copy_c)
|
| 767 |
-
== """
|
| 768 |
-
sparse_copy_c(arg0: scipy.sparse.csc_matrix[numpy.float32]) -> scipy.sparse.csc_matrix[numpy.float32]
|
| 769 |
-
"""
|
| 770 |
-
)
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
def test_issue738():
|
| 774 |
-
"""Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)"""
|
| 775 |
-
assert np.all(m.iss738_f1(np.array([[1.0, 2, 3]])) == np.array([[1.0, 102, 203]]))
|
| 776 |
-
assert np.all(
|
| 777 |
-
m.iss738_f1(np.array([[1.0], [2], [3]])) == np.array([[1.0], [12], [23]])
|
| 778 |
-
)
|
| 779 |
-
|
| 780 |
-
assert np.all(m.iss738_f2(np.array([[1.0, 2, 3]])) == np.array([[1.0, 102, 203]]))
|
| 781 |
-
assert np.all(
|
| 782 |
-
m.iss738_f2(np.array([[1.0], [2], [3]])) == np.array([[1.0], [12], [23]])
|
| 783 |
-
)
|
| 784 |
-
|
| 785 |
-
|
| 786 |
-
@pytest.mark.parametrize("func", [m.iss738_f1, m.iss738_f2])
|
| 787 |
-
@pytest.mark.parametrize("sizes", [(0, 2), (2, 0)])
|
| 788 |
-
def test_zero_length(func, sizes):
|
| 789 |
-
"""Ignore strides on a length-0 dimension (even if they would be incompatible length > 1)"""
|
| 790 |
-
assert np.all(func(np.zeros(sizes)) == np.zeros(sizes))
|
| 791 |
-
|
| 792 |
-
|
| 793 |
-
def test_issue1105():
|
| 794 |
-
"""Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen
|
| 795 |
-
compile-time row vectors or column vector"""
|
| 796 |
-
assert m.iss1105_row(np.ones((1, 7)))
|
| 797 |
-
assert m.iss1105_col(np.ones((7, 1)))
|
| 798 |
-
|
| 799 |
-
# These should still fail (incompatible dimensions):
|
| 800 |
-
with pytest.raises(TypeError) as excinfo:
|
| 801 |
-
m.iss1105_row(np.ones((7, 1)))
|
| 802 |
-
assert "incompatible function arguments" in str(excinfo.value)
|
| 803 |
-
with pytest.raises(TypeError) as excinfo:
|
| 804 |
-
m.iss1105_col(np.ones((1, 7)))
|
| 805 |
-
assert "incompatible function arguments" in str(excinfo.value)
|
| 806 |
-
|
| 807 |
-
|
| 808 |
-
def test_custom_operator_new():
|
| 809 |
-
"""Using Eigen types as member variables requires a class-specific
|
| 810 |
-
operator new with proper alignment"""
|
| 811 |
-
|
| 812 |
-
o = m.CustomOperatorNew()
|
| 813 |
-
np.testing.assert_allclose(o.a, 0.0)
|
| 814 |
-
np.testing.assert_allclose(o.b.diagonal(), 1.0)
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
from pybind11_tests import ConstructorStats
|
| 4 |
+
|
| 5 |
+
np = pytest.importorskip("numpy")
|
| 6 |
+
m = pytest.importorskip("pybind11_tests.eigen_matrix")
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
ref = np.array(
|
| 10 |
+
[
|
| 11 |
+
[0.0, 3, 0, 0, 0, 11],
|
| 12 |
+
[22, 0, 0, 0, 17, 11],
|
| 13 |
+
[7, 5, 0, 1, 0, 11],
|
| 14 |
+
[0, 0, 0, 0, 0, 11],
|
| 15 |
+
[0, 0, 14, 0, 8, 11],
|
| 16 |
+
]
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def assert_equal_ref(mat):
|
| 21 |
+
np.testing.assert_array_equal(mat, ref)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def assert_sparse_equal_ref(sparse_mat):
|
| 25 |
+
assert_equal_ref(sparse_mat.toarray())
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_fixed():
|
| 29 |
+
assert_equal_ref(m.fixed_c())
|
| 30 |
+
assert_equal_ref(m.fixed_r())
|
| 31 |
+
assert_equal_ref(m.fixed_copy_r(m.fixed_r()))
|
| 32 |
+
assert_equal_ref(m.fixed_copy_c(m.fixed_c()))
|
| 33 |
+
assert_equal_ref(m.fixed_copy_r(m.fixed_c()))
|
| 34 |
+
assert_equal_ref(m.fixed_copy_c(m.fixed_r()))
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def test_dense():
|
| 38 |
+
assert_equal_ref(m.dense_r())
|
| 39 |
+
assert_equal_ref(m.dense_c())
|
| 40 |
+
assert_equal_ref(m.dense_copy_r(m.dense_r()))
|
| 41 |
+
assert_equal_ref(m.dense_copy_c(m.dense_c()))
|
| 42 |
+
assert_equal_ref(m.dense_copy_r(m.dense_c()))
|
| 43 |
+
assert_equal_ref(m.dense_copy_c(m.dense_r()))
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def test_partially_fixed():
|
| 47 |
+
ref2 = np.array([[0.0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]])
|
| 48 |
+
np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2), ref2)
|
| 49 |
+
np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2), ref2)
|
| 50 |
+
np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]])
|
| 51 |
+
np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :])
|
| 52 |
+
np.testing.assert_array_equal(
|
| 53 |
+
m.partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]
|
| 54 |
+
)
|
| 55 |
+
np.testing.assert_array_equal(
|
| 56 |
+
m.partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2), ref2)
|
| 60 |
+
np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2), ref2)
|
| 61 |
+
np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]])
|
| 62 |
+
np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :])
|
| 63 |
+
np.testing.assert_array_equal(
|
| 64 |
+
m.partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]
|
| 65 |
+
)
|
| 66 |
+
np.testing.assert_array_equal(
|
| 67 |
+
m.partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
# TypeError should be raise for a shape mismatch
|
| 71 |
+
functions = [
|
| 72 |
+
m.partial_copy_four_rm_r,
|
| 73 |
+
m.partial_copy_four_rm_c,
|
| 74 |
+
m.partial_copy_four_cm_r,
|
| 75 |
+
m.partial_copy_four_cm_c,
|
| 76 |
+
]
|
| 77 |
+
matrix_with_wrong_shape = [[1, 2], [3, 4]]
|
| 78 |
+
for f in functions:
|
| 79 |
+
with pytest.raises(TypeError) as excinfo:
|
| 80 |
+
f(matrix_with_wrong_shape)
|
| 81 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def test_mutator_descriptors():
|
| 85 |
+
zr = np.arange(30, dtype="float32").reshape(5, 6) # row-major
|
| 86 |
+
zc = zr.reshape(6, 5).transpose() # column-major
|
| 87 |
+
|
| 88 |
+
m.fixed_mutator_r(zr)
|
| 89 |
+
m.fixed_mutator_c(zc)
|
| 90 |
+
m.fixed_mutator_a(zr)
|
| 91 |
+
m.fixed_mutator_a(zc)
|
| 92 |
+
with pytest.raises(TypeError) as excinfo:
|
| 93 |
+
m.fixed_mutator_r(zc)
|
| 94 |
+
assert (
|
| 95 |
+
"(arg0: numpy.ndarray[numpy.float32[5, 6],"
|
| 96 |
+
" flags.writeable, flags.c_contiguous]) -> None" in str(excinfo.value)
|
| 97 |
+
)
|
| 98 |
+
with pytest.raises(TypeError) as excinfo:
|
| 99 |
+
m.fixed_mutator_c(zr)
|
| 100 |
+
assert (
|
| 101 |
+
"(arg0: numpy.ndarray[numpy.float32[5, 6],"
|
| 102 |
+
" flags.writeable, flags.f_contiguous]) -> None" in str(excinfo.value)
|
| 103 |
+
)
|
| 104 |
+
with pytest.raises(TypeError) as excinfo:
|
| 105 |
+
m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype="float32"))
|
| 106 |
+
assert "(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None" in str(
|
| 107 |
+
excinfo.value
|
| 108 |
+
)
|
| 109 |
+
zr.flags.writeable = False
|
| 110 |
+
with pytest.raises(TypeError):
|
| 111 |
+
m.fixed_mutator_r(zr)
|
| 112 |
+
with pytest.raises(TypeError):
|
| 113 |
+
m.fixed_mutator_a(zr)
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def test_cpp_casting():
|
| 117 |
+
assert m.cpp_copy(m.fixed_r()) == 22.0
|
| 118 |
+
assert m.cpp_copy(m.fixed_c()) == 22.0
|
| 119 |
+
z = np.array([[5.0, 6], [7, 8]])
|
| 120 |
+
assert m.cpp_copy(z) == 7.0
|
| 121 |
+
assert m.cpp_copy(m.get_cm_ref()) == 21.0
|
| 122 |
+
assert m.cpp_copy(m.get_rm_ref()) == 21.0
|
| 123 |
+
assert m.cpp_ref_c(m.get_cm_ref()) == 21.0
|
| 124 |
+
assert m.cpp_ref_r(m.get_rm_ref()) == 21.0
|
| 125 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 126 |
+
# Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles
|
| 127 |
+
m.cpp_ref_any(m.fixed_c())
|
| 128 |
+
assert "Unable to cast Python instance" in str(excinfo.value)
|
| 129 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 130 |
+
# Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles
|
| 131 |
+
m.cpp_ref_any(m.fixed_r())
|
| 132 |
+
assert "Unable to cast Python instance" in str(excinfo.value)
|
| 133 |
+
assert m.cpp_ref_any(m.ReturnTester.create()) == 1.0
|
| 134 |
+
|
| 135 |
+
assert m.cpp_ref_any(m.get_cm_ref()) == 21.0
|
| 136 |
+
assert m.cpp_ref_any(m.get_cm_ref()) == 21.0
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def test_pass_readonly_array():
|
| 140 |
+
z = np.full((5, 6), 42.0)
|
| 141 |
+
z.flags.writeable = False
|
| 142 |
+
np.testing.assert_array_equal(z, m.fixed_copy_r(z))
|
| 143 |
+
np.testing.assert_array_equal(m.fixed_r_const(), m.fixed_r())
|
| 144 |
+
assert not m.fixed_r_const().flags.writeable
|
| 145 |
+
np.testing.assert_array_equal(m.fixed_copy_r(m.fixed_r_const()), m.fixed_r_const())
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
def test_nonunit_stride_from_python():
|
| 149 |
+
counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
|
| 150 |
+
second_row = counting_mat[1, :]
|
| 151 |
+
second_col = counting_mat[:, 1]
|
| 152 |
+
np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
|
| 153 |
+
np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
|
| 154 |
+
np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
|
| 155 |
+
np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
|
| 156 |
+
np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
|
| 157 |
+
np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
|
| 158 |
+
|
| 159 |
+
counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
|
| 160 |
+
slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
|
| 161 |
+
for ref_mat in slices:
|
| 162 |
+
np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
|
| 163 |
+
np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
|
| 164 |
+
|
| 165 |
+
# Mutator:
|
| 166 |
+
m.double_threer(second_row)
|
| 167 |
+
m.double_threec(second_col)
|
| 168 |
+
np.testing.assert_array_equal(counting_mat, [[0.0, 2, 2], [6, 16, 10], [6, 14, 8]])
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
def test_negative_stride_from_python(msg):
|
| 172 |
+
"""Eigen doesn't support (as of yet) negative strides. When a function takes an Eigen matrix by
|
| 173 |
+
copy or const reference, we can pass a numpy array that has negative strides. Otherwise, an
|
| 174 |
+
exception will be thrown as Eigen will not be able to map the numpy array."""
|
| 175 |
+
|
| 176 |
+
counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
|
| 177 |
+
counting_mat = counting_mat[::-1, ::-1]
|
| 178 |
+
second_row = counting_mat[1, :]
|
| 179 |
+
second_col = counting_mat[:, 1]
|
| 180 |
+
np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
|
| 181 |
+
np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
|
| 182 |
+
np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
|
| 183 |
+
np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
|
| 184 |
+
np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
|
| 185 |
+
np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
|
| 186 |
+
|
| 187 |
+
counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
|
| 188 |
+
counting_3d = counting_3d[::-1, ::-1, ::-1]
|
| 189 |
+
slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
|
| 190 |
+
for ref_mat in slices:
|
| 191 |
+
np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
|
| 192 |
+
np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
|
| 193 |
+
|
| 194 |
+
# Mutator:
|
| 195 |
+
with pytest.raises(TypeError) as excinfo:
|
| 196 |
+
m.double_threer(second_row)
|
| 197 |
+
assert (
|
| 198 |
+
msg(excinfo.value)
|
| 199 |
+
== """
|
| 200 |
+
double_threer(): incompatible function arguments. The following argument types are supported:
|
| 201 |
+
1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None
|
| 202 |
+
|
| 203 |
+
Invoked with: """
|
| 204 |
+
+ repr(np.array([5.0, 4.0, 3.0], dtype="float32"))
|
| 205 |
+
)
|
| 206 |
+
|
| 207 |
+
with pytest.raises(TypeError) as excinfo:
|
| 208 |
+
m.double_threec(second_col)
|
| 209 |
+
assert (
|
| 210 |
+
msg(excinfo.value)
|
| 211 |
+
== """
|
| 212 |
+
double_threec(): incompatible function arguments. The following argument types are supported:
|
| 213 |
+
1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None
|
| 214 |
+
|
| 215 |
+
Invoked with: """
|
| 216 |
+
+ repr(np.array([7.0, 4.0, 1.0], dtype="float32"))
|
| 217 |
+
)
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
def test_block_runtime_error_type_caster_eigen_ref_made_a_copy():
|
| 221 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 222 |
+
m.block(ref, 0, 0, 0, 0)
|
| 223 |
+
assert str(excinfo.value) == "type_caster for Eigen::Ref made a copy."
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
def test_nonunit_stride_to_python():
|
| 227 |
+
assert np.all(m.diagonal(ref) == ref.diagonal())
|
| 228 |
+
assert np.all(m.diagonal_1(ref) == ref.diagonal(1))
|
| 229 |
+
for i in range(-5, 7):
|
| 230 |
+
assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), f"m.diagonal_n({i})"
|
| 231 |
+
|
| 232 |
+
# Must be order="F", otherwise the type_caster will make a copy and
|
| 233 |
+
# m.block() will return a dangling reference (heap-use-after-free).
|
| 234 |
+
rof = np.asarray(ref, order="F")
|
| 235 |
+
assert np.all(m.block(rof, 2, 1, 3, 3) == rof[2:5, 1:4])
|
| 236 |
+
assert np.all(m.block(rof, 1, 4, 4, 2) == rof[1:, 4:])
|
| 237 |
+
assert np.all(m.block(rof, 1, 4, 3, 2) == rof[1:4, 4:])
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
def test_eigen_ref_to_python():
|
| 241 |
+
chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4]
|
| 242 |
+
for i, chol in enumerate(chols, start=1):
|
| 243 |
+
mymat = chol(np.array([[1.0, 2, 4], [2, 13, 23], [4, 23, 77]]))
|
| 244 |
+
assert np.all(
|
| 245 |
+
mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])
|
| 246 |
+
), f"cholesky{i}"
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
def assign_both(a1, a2, r, c, v):
|
| 250 |
+
a1[r, c] = v
|
| 251 |
+
a2[r, c] = v
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def array_copy_but_one(a, r, c, v):
|
| 255 |
+
z = np.array(a, copy=True)
|
| 256 |
+
z[r, c] = v
|
| 257 |
+
return z
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
def test_eigen_return_references():
|
| 261 |
+
"""Tests various ways of returning references and non-referencing copies"""
|
| 262 |
+
|
| 263 |
+
primary = np.ones((10, 10))
|
| 264 |
+
a = m.ReturnTester()
|
| 265 |
+
a_get1 = a.get()
|
| 266 |
+
assert not a_get1.flags.owndata
|
| 267 |
+
assert a_get1.flags.writeable
|
| 268 |
+
assign_both(a_get1, primary, 3, 3, 5)
|
| 269 |
+
a_get2 = a.get_ptr()
|
| 270 |
+
assert not a_get2.flags.owndata
|
| 271 |
+
assert a_get2.flags.writeable
|
| 272 |
+
assign_both(a_get1, primary, 2, 3, 6)
|
| 273 |
+
|
| 274 |
+
a_view1 = a.view()
|
| 275 |
+
assert not a_view1.flags.owndata
|
| 276 |
+
assert not a_view1.flags.writeable
|
| 277 |
+
with pytest.raises(ValueError):
|
| 278 |
+
a_view1[2, 3] = 4
|
| 279 |
+
a_view2 = a.view_ptr()
|
| 280 |
+
assert not a_view2.flags.owndata
|
| 281 |
+
assert not a_view2.flags.writeable
|
| 282 |
+
with pytest.raises(ValueError):
|
| 283 |
+
a_view2[2, 3] = 4
|
| 284 |
+
|
| 285 |
+
a_copy1 = a.copy_get()
|
| 286 |
+
assert a_copy1.flags.owndata
|
| 287 |
+
assert a_copy1.flags.writeable
|
| 288 |
+
np.testing.assert_array_equal(a_copy1, primary)
|
| 289 |
+
a_copy1[7, 7] = -44 # Shouldn't affect anything else
|
| 290 |
+
c1want = array_copy_but_one(primary, 7, 7, -44)
|
| 291 |
+
a_copy2 = a.copy_view()
|
| 292 |
+
assert a_copy2.flags.owndata
|
| 293 |
+
assert a_copy2.flags.writeable
|
| 294 |
+
np.testing.assert_array_equal(a_copy2, primary)
|
| 295 |
+
a_copy2[4, 4] = -22 # Shouldn't affect anything else
|
| 296 |
+
c2want = array_copy_but_one(primary, 4, 4, -22)
|
| 297 |
+
|
| 298 |
+
a_ref1 = a.ref()
|
| 299 |
+
assert not a_ref1.flags.owndata
|
| 300 |
+
assert a_ref1.flags.writeable
|
| 301 |
+
assign_both(a_ref1, primary, 1, 1, 15)
|
| 302 |
+
a_ref2 = a.ref_const()
|
| 303 |
+
assert not a_ref2.flags.owndata
|
| 304 |
+
assert not a_ref2.flags.writeable
|
| 305 |
+
with pytest.raises(ValueError):
|
| 306 |
+
a_ref2[5, 5] = 33
|
| 307 |
+
a_ref3 = a.ref_safe()
|
| 308 |
+
assert not a_ref3.flags.owndata
|
| 309 |
+
assert a_ref3.flags.writeable
|
| 310 |
+
assign_both(a_ref3, primary, 0, 7, 99)
|
| 311 |
+
a_ref4 = a.ref_const_safe()
|
| 312 |
+
assert not a_ref4.flags.owndata
|
| 313 |
+
assert not a_ref4.flags.writeable
|
| 314 |
+
with pytest.raises(ValueError):
|
| 315 |
+
a_ref4[7, 0] = 987654321
|
| 316 |
+
|
| 317 |
+
a_copy3 = a.copy_ref()
|
| 318 |
+
assert a_copy3.flags.owndata
|
| 319 |
+
assert a_copy3.flags.writeable
|
| 320 |
+
np.testing.assert_array_equal(a_copy3, primary)
|
| 321 |
+
a_copy3[8, 1] = 11
|
| 322 |
+
c3want = array_copy_but_one(primary, 8, 1, 11)
|
| 323 |
+
a_copy4 = a.copy_ref_const()
|
| 324 |
+
assert a_copy4.flags.owndata
|
| 325 |
+
assert a_copy4.flags.writeable
|
| 326 |
+
np.testing.assert_array_equal(a_copy4, primary)
|
| 327 |
+
a_copy4[8, 4] = 88
|
| 328 |
+
c4want = array_copy_but_one(primary, 8, 4, 88)
|
| 329 |
+
|
| 330 |
+
a_block1 = a.block(3, 3, 2, 2)
|
| 331 |
+
assert not a_block1.flags.owndata
|
| 332 |
+
assert a_block1.flags.writeable
|
| 333 |
+
a_block1[0, 0] = 55
|
| 334 |
+
primary[3, 3] = 55
|
| 335 |
+
a_block2 = a.block_safe(2, 2, 3, 2)
|
| 336 |
+
assert not a_block2.flags.owndata
|
| 337 |
+
assert a_block2.flags.writeable
|
| 338 |
+
a_block2[2, 1] = -123
|
| 339 |
+
primary[4, 3] = -123
|
| 340 |
+
a_block3 = a.block_const(6, 7, 4, 3)
|
| 341 |
+
assert not a_block3.flags.owndata
|
| 342 |
+
assert not a_block3.flags.writeable
|
| 343 |
+
with pytest.raises(ValueError):
|
| 344 |
+
a_block3[2, 2] = -44444
|
| 345 |
+
|
| 346 |
+
a_copy5 = a.copy_block(2, 2, 2, 3)
|
| 347 |
+
assert a_copy5.flags.owndata
|
| 348 |
+
assert a_copy5.flags.writeable
|
| 349 |
+
np.testing.assert_array_equal(a_copy5, primary[2:4, 2:5])
|
| 350 |
+
a_copy5[1, 1] = 777
|
| 351 |
+
c5want = array_copy_but_one(primary[2:4, 2:5], 1, 1, 777)
|
| 352 |
+
|
| 353 |
+
a_corn1 = a.corners()
|
| 354 |
+
assert not a_corn1.flags.owndata
|
| 355 |
+
assert a_corn1.flags.writeable
|
| 356 |
+
a_corn1 *= 50
|
| 357 |
+
a_corn1[1, 1] = 999
|
| 358 |
+
primary[0, 0] = 50
|
| 359 |
+
primary[0, 9] = 50
|
| 360 |
+
primary[9, 0] = 50
|
| 361 |
+
primary[9, 9] = 999
|
| 362 |
+
a_corn2 = a.corners_const()
|
| 363 |
+
assert not a_corn2.flags.owndata
|
| 364 |
+
assert not a_corn2.flags.writeable
|
| 365 |
+
with pytest.raises(ValueError):
|
| 366 |
+
a_corn2[1, 0] = 51
|
| 367 |
+
|
| 368 |
+
# All of the changes made all the way along should be visible everywhere
|
| 369 |
+
# now (except for the copies, of course)
|
| 370 |
+
np.testing.assert_array_equal(a_get1, primary)
|
| 371 |
+
np.testing.assert_array_equal(a_get2, primary)
|
| 372 |
+
np.testing.assert_array_equal(a_view1, primary)
|
| 373 |
+
np.testing.assert_array_equal(a_view2, primary)
|
| 374 |
+
np.testing.assert_array_equal(a_ref1, primary)
|
| 375 |
+
np.testing.assert_array_equal(a_ref2, primary)
|
| 376 |
+
np.testing.assert_array_equal(a_ref3, primary)
|
| 377 |
+
np.testing.assert_array_equal(a_ref4, primary)
|
| 378 |
+
np.testing.assert_array_equal(a_block1, primary[3:5, 3:5])
|
| 379 |
+
np.testing.assert_array_equal(a_block2, primary[2:5, 2:4])
|
| 380 |
+
np.testing.assert_array_equal(a_block3, primary[6:10, 7:10])
|
| 381 |
+
np.testing.assert_array_equal(
|
| 382 |
+
a_corn1, primary[0 :: primary.shape[0] - 1, 0 :: primary.shape[1] - 1]
|
| 383 |
+
)
|
| 384 |
+
np.testing.assert_array_equal(
|
| 385 |
+
a_corn2, primary[0 :: primary.shape[0] - 1, 0 :: primary.shape[1] - 1]
|
| 386 |
+
)
|
| 387 |
+
|
| 388 |
+
np.testing.assert_array_equal(a_copy1, c1want)
|
| 389 |
+
np.testing.assert_array_equal(a_copy2, c2want)
|
| 390 |
+
np.testing.assert_array_equal(a_copy3, c3want)
|
| 391 |
+
np.testing.assert_array_equal(a_copy4, c4want)
|
| 392 |
+
np.testing.assert_array_equal(a_copy5, c5want)
|
| 393 |
+
|
| 394 |
+
|
| 395 |
+
def assert_keeps_alive(cl, method, *args):
|
| 396 |
+
cstats = ConstructorStats.get(cl)
|
| 397 |
+
start_with = cstats.alive()
|
| 398 |
+
a = cl()
|
| 399 |
+
assert cstats.alive() == start_with + 1
|
| 400 |
+
z = method(a, *args)
|
| 401 |
+
assert cstats.alive() == start_with + 1
|
| 402 |
+
del a
|
| 403 |
+
# Here's the keep alive in action:
|
| 404 |
+
assert cstats.alive() == start_with + 1
|
| 405 |
+
del z
|
| 406 |
+
# Keep alive should have expired:
|
| 407 |
+
assert cstats.alive() == start_with
|
| 408 |
+
|
| 409 |
+
|
| 410 |
+
def test_eigen_keepalive():
|
| 411 |
+
a = m.ReturnTester()
|
| 412 |
+
cstats = ConstructorStats.get(m.ReturnTester)
|
| 413 |
+
assert cstats.alive() == 1
|
| 414 |
+
unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)]
|
| 415 |
+
copies = [
|
| 416 |
+
a.copy_get(),
|
| 417 |
+
a.copy_view(),
|
| 418 |
+
a.copy_ref(),
|
| 419 |
+
a.copy_ref_const(),
|
| 420 |
+
a.copy_block(4, 3, 2, 1),
|
| 421 |
+
]
|
| 422 |
+
del a
|
| 423 |
+
assert cstats.alive() == 0
|
| 424 |
+
del unsafe
|
| 425 |
+
del copies
|
| 426 |
+
|
| 427 |
+
for meth in [
|
| 428 |
+
m.ReturnTester.get,
|
| 429 |
+
m.ReturnTester.get_ptr,
|
| 430 |
+
m.ReturnTester.view,
|
| 431 |
+
m.ReturnTester.view_ptr,
|
| 432 |
+
m.ReturnTester.ref_safe,
|
| 433 |
+
m.ReturnTester.ref_const_safe,
|
| 434 |
+
m.ReturnTester.corners,
|
| 435 |
+
m.ReturnTester.corners_const,
|
| 436 |
+
]:
|
| 437 |
+
assert_keeps_alive(m.ReturnTester, meth)
|
| 438 |
+
|
| 439 |
+
for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]:
|
| 440 |
+
assert_keeps_alive(m.ReturnTester, meth, 4, 3, 2, 1)
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
def test_eigen_ref_mutators():
|
| 444 |
+
"""Tests Eigen's ability to mutate numpy values"""
|
| 445 |
+
|
| 446 |
+
orig = np.array([[1.0, 2, 3], [4, 5, 6], [7, 8, 9]])
|
| 447 |
+
zr = np.array(orig)
|
| 448 |
+
zc = np.array(orig, order="F")
|
| 449 |
+
m.add_rm(zr, 1, 0, 100)
|
| 450 |
+
assert np.all(zr == np.array([[1.0, 2, 3], [104, 5, 6], [7, 8, 9]]))
|
| 451 |
+
m.add_cm(zc, 1, 0, 200)
|
| 452 |
+
assert np.all(zc == np.array([[1.0, 2, 3], [204, 5, 6], [7, 8, 9]]))
|
| 453 |
+
|
| 454 |
+
m.add_any(zr, 1, 0, 20)
|
| 455 |
+
assert np.all(zr == np.array([[1.0, 2, 3], [124, 5, 6], [7, 8, 9]]))
|
| 456 |
+
m.add_any(zc, 1, 0, 10)
|
| 457 |
+
assert np.all(zc == np.array([[1.0, 2, 3], [214, 5, 6], [7, 8, 9]]))
|
| 458 |
+
|
| 459 |
+
# Can't reference a col-major array with a row-major Ref, and vice versa:
|
| 460 |
+
with pytest.raises(TypeError):
|
| 461 |
+
m.add_rm(zc, 1, 0, 1)
|
| 462 |
+
with pytest.raises(TypeError):
|
| 463 |
+
m.add_cm(zr, 1, 0, 1)
|
| 464 |
+
|
| 465 |
+
# Overloads:
|
| 466 |
+
m.add1(zr, 1, 0, -100)
|
| 467 |
+
m.add2(zr, 1, 0, -20)
|
| 468 |
+
assert np.all(zr == orig)
|
| 469 |
+
m.add1(zc, 1, 0, -200)
|
| 470 |
+
m.add2(zc, 1, 0, -10)
|
| 471 |
+
assert np.all(zc == orig)
|
| 472 |
+
|
| 473 |
+
# a non-contiguous slice (this won't work on either the row- or
|
| 474 |
+
# column-contiguous refs, but should work for the any)
|
| 475 |
+
cornersr = zr[0::2, 0::2]
|
| 476 |
+
cornersc = zc[0::2, 0::2]
|
| 477 |
+
|
| 478 |
+
assert np.all(cornersr == np.array([[1.0, 3], [7, 9]]))
|
| 479 |
+
assert np.all(cornersc == np.array([[1.0, 3], [7, 9]]))
|
| 480 |
+
|
| 481 |
+
with pytest.raises(TypeError):
|
| 482 |
+
m.add_rm(cornersr, 0, 1, 25)
|
| 483 |
+
with pytest.raises(TypeError):
|
| 484 |
+
m.add_cm(cornersr, 0, 1, 25)
|
| 485 |
+
with pytest.raises(TypeError):
|
| 486 |
+
m.add_rm(cornersc, 0, 1, 25)
|
| 487 |
+
with pytest.raises(TypeError):
|
| 488 |
+
m.add_cm(cornersc, 0, 1, 25)
|
| 489 |
+
m.add_any(cornersr, 0, 1, 25)
|
| 490 |
+
m.add_any(cornersc, 0, 1, 44)
|
| 491 |
+
assert np.all(zr == np.array([[1.0, 2, 28], [4, 5, 6], [7, 8, 9]]))
|
| 492 |
+
assert np.all(zc == np.array([[1.0, 2, 47], [4, 5, 6], [7, 8, 9]]))
|
| 493 |
+
|
| 494 |
+
# You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method:
|
| 495 |
+
zro = zr[0:4, 0:4]
|
| 496 |
+
zro.flags.writeable = False
|
| 497 |
+
with pytest.raises(TypeError):
|
| 498 |
+
m.add_rm(zro, 0, 0, 0)
|
| 499 |
+
with pytest.raises(TypeError):
|
| 500 |
+
m.add_any(zro, 0, 0, 0)
|
| 501 |
+
with pytest.raises(TypeError):
|
| 502 |
+
m.add1(zro, 0, 0, 0)
|
| 503 |
+
with pytest.raises(TypeError):
|
| 504 |
+
m.add2(zro, 0, 0, 0)
|
| 505 |
+
|
| 506 |
+
# integer array shouldn't be passable to a double-matrix-accepting mutating func:
|
| 507 |
+
zi = np.array([[1, 2], [3, 4]])
|
| 508 |
+
with pytest.raises(TypeError):
|
| 509 |
+
m.add_rm(zi)
|
| 510 |
+
|
| 511 |
+
|
| 512 |
+
def test_numpy_ref_mutators():
|
| 513 |
+
"""Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)"""
|
| 514 |
+
|
| 515 |
+
m.reset_refs() # In case another test already changed it
|
| 516 |
+
|
| 517 |
+
zc = m.get_cm_ref()
|
| 518 |
+
zcro = m.get_cm_const_ref()
|
| 519 |
+
zr = m.get_rm_ref()
|
| 520 |
+
zrro = m.get_rm_const_ref()
|
| 521 |
+
|
| 522 |
+
assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4
|
| 523 |
+
|
| 524 |
+
assert not zc.flags.owndata
|
| 525 |
+
assert zc.flags.writeable
|
| 526 |
+
assert not zr.flags.owndata
|
| 527 |
+
assert zr.flags.writeable
|
| 528 |
+
assert not zcro.flags.owndata
|
| 529 |
+
assert not zcro.flags.writeable
|
| 530 |
+
assert not zrro.flags.owndata
|
| 531 |
+
assert not zrro.flags.writeable
|
| 532 |
+
|
| 533 |
+
zc[1, 2] = 99
|
| 534 |
+
expect = np.array([[11.0, 12, 13], [21, 22, 99], [31, 32, 33]])
|
| 535 |
+
# We should have just changed zc, of course, but also zcro and the original eigen matrix
|
| 536 |
+
assert np.all(zc == expect)
|
| 537 |
+
assert np.all(zcro == expect)
|
| 538 |
+
assert np.all(m.get_cm_ref() == expect)
|
| 539 |
+
|
| 540 |
+
zr[1, 2] = 99
|
| 541 |
+
assert np.all(zr == expect)
|
| 542 |
+
assert np.all(zrro == expect)
|
| 543 |
+
assert np.all(m.get_rm_ref() == expect)
|
| 544 |
+
|
| 545 |
+
# Make sure the readonly ones are numpy-readonly:
|
| 546 |
+
with pytest.raises(ValueError):
|
| 547 |
+
zcro[1, 2] = 6
|
| 548 |
+
with pytest.raises(ValueError):
|
| 549 |
+
zrro[1, 2] = 6
|
| 550 |
+
|
| 551 |
+
# We should be able to explicitly copy like this (and since we're copying,
|
| 552 |
+
# the const should drop away)
|
| 553 |
+
y1 = np.array(m.get_cm_const_ref())
|
| 554 |
+
|
| 555 |
+
assert y1.flags.owndata
|
| 556 |
+
assert y1.flags.writeable
|
| 557 |
+
# We should get copies of the eigen data, which was modified above:
|
| 558 |
+
assert y1[1, 2] == 99
|
| 559 |
+
y1[1, 2] += 12
|
| 560 |
+
assert y1[1, 2] == 111
|
| 561 |
+
assert zc[1, 2] == 99 # Make sure we aren't referencing the original
|
| 562 |
+
|
| 563 |
+
|
| 564 |
+
def test_both_ref_mutators():
|
| 565 |
+
"""Tests a complex chain of nested eigen/numpy references"""
|
| 566 |
+
|
| 567 |
+
m.reset_refs() # In case another test already changed it
|
| 568 |
+
|
| 569 |
+
z = m.get_cm_ref() # numpy -> eigen
|
| 570 |
+
z[0, 2] -= 3
|
| 571 |
+
z2 = m.incr_matrix(z, 1) # numpy -> eigen -> numpy -> eigen
|
| 572 |
+
z2[1, 1] += 6
|
| 573 |
+
z3 = m.incr_matrix(z, 2) # (numpy -> eigen)^3
|
| 574 |
+
z3[2, 2] += -5
|
| 575 |
+
z4 = m.incr_matrix(z, 3) # (numpy -> eigen)^4
|
| 576 |
+
z4[1, 1] -= 1
|
| 577 |
+
z5 = m.incr_matrix(z, 4) # (numpy -> eigen)^5
|
| 578 |
+
z5[0, 0] = 0
|
| 579 |
+
assert np.all(z == z2)
|
| 580 |
+
assert np.all(z == z3)
|
| 581 |
+
assert np.all(z == z4)
|
| 582 |
+
assert np.all(z == z5)
|
| 583 |
+
expect = np.array([[0.0, 22, 20], [31, 37, 33], [41, 42, 38]])
|
| 584 |
+
assert np.all(z == expect)
|
| 585 |
+
|
| 586 |
+
y = np.array(range(100), dtype="float64").reshape(10, 10)
|
| 587 |
+
y2 = m.incr_matrix_any(y, 10) # np -> eigen -> np
|
| 588 |
+
y3 = m.incr_matrix_any(
|
| 589 |
+
y2[0::2, 0::2], -33
|
| 590 |
+
) # np -> eigen -> np slice -> np -> eigen -> np
|
| 591 |
+
y4 = m.even_rows(y3) # numpy -> eigen slice -> (... y3)
|
| 592 |
+
y5 = m.even_cols(y4) # numpy -> eigen slice -> (... y4)
|
| 593 |
+
y6 = m.incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5)
|
| 594 |
+
|
| 595 |
+
# Apply same mutations using just numpy:
|
| 596 |
+
yexpect = np.array(range(100), dtype="float64").reshape(10, 10)
|
| 597 |
+
yexpect += 10
|
| 598 |
+
yexpect[0::2, 0::2] -= 33
|
| 599 |
+
yexpect[0::4, 0::4] += 1000
|
| 600 |
+
assert np.all(y6 == yexpect[0::4, 0::4])
|
| 601 |
+
assert np.all(y5 == yexpect[0::4, 0::4])
|
| 602 |
+
assert np.all(y4 == yexpect[0::4, 0::2])
|
| 603 |
+
assert np.all(y3 == yexpect[0::2, 0::2])
|
| 604 |
+
assert np.all(y2 == yexpect)
|
| 605 |
+
assert np.all(y == yexpect)
|
| 606 |
+
|
| 607 |
+
|
| 608 |
+
def test_nocopy_wrapper():
|
| 609 |
+
# get_elem requires a column-contiguous matrix reference, but should be
|
| 610 |
+
# callable with other types of matrix (via copying):
|
| 611 |
+
int_matrix_colmajor = np.array(
|
| 612 |
+
[[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype="l", order="F"
|
| 613 |
+
)
|
| 614 |
+
dbl_matrix_colmajor = np.array(
|
| 615 |
+
int_matrix_colmajor, dtype="double", order="F", copy=True
|
| 616 |
+
)
|
| 617 |
+
int_matrix_rowmajor = np.array(int_matrix_colmajor, order="C", copy=True)
|
| 618 |
+
dbl_matrix_rowmajor = np.array(
|
| 619 |
+
int_matrix_rowmajor, dtype="double", order="C", copy=True
|
| 620 |
+
)
|
| 621 |
+
|
| 622 |
+
# All should be callable via get_elem:
|
| 623 |
+
assert m.get_elem(int_matrix_colmajor) == 8
|
| 624 |
+
assert m.get_elem(dbl_matrix_colmajor) == 8
|
| 625 |
+
assert m.get_elem(int_matrix_rowmajor) == 8
|
| 626 |
+
assert m.get_elem(dbl_matrix_rowmajor) == 8
|
| 627 |
+
|
| 628 |
+
# All but the second should fail with m.get_elem_nocopy:
|
| 629 |
+
with pytest.raises(TypeError) as excinfo:
|
| 630 |
+
m.get_elem_nocopy(int_matrix_colmajor)
|
| 631 |
+
assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
|
| 632 |
+
assert ", flags.f_contiguous" in str(excinfo.value)
|
| 633 |
+
assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8
|
| 634 |
+
with pytest.raises(TypeError) as excinfo:
|
| 635 |
+
m.get_elem_nocopy(int_matrix_rowmajor)
|
| 636 |
+
assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
|
| 637 |
+
assert ", flags.f_contiguous" in str(excinfo.value)
|
| 638 |
+
with pytest.raises(TypeError) as excinfo:
|
| 639 |
+
m.get_elem_nocopy(dbl_matrix_rowmajor)
|
| 640 |
+
assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
|
| 641 |
+
assert ", flags.f_contiguous" in str(excinfo.value)
|
| 642 |
+
|
| 643 |
+
# For the row-major test, we take a long matrix in row-major, so only the third is allowed:
|
| 644 |
+
with pytest.raises(TypeError) as excinfo:
|
| 645 |
+
m.get_elem_rm_nocopy(int_matrix_colmajor)
|
| 646 |
+
assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
|
| 647 |
+
excinfo.value
|
| 648 |
+
)
|
| 649 |
+
assert ", flags.c_contiguous" in str(excinfo.value)
|
| 650 |
+
with pytest.raises(TypeError) as excinfo:
|
| 651 |
+
m.get_elem_rm_nocopy(dbl_matrix_colmajor)
|
| 652 |
+
assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
|
| 653 |
+
excinfo.value
|
| 654 |
+
)
|
| 655 |
+
assert ", flags.c_contiguous" in str(excinfo.value)
|
| 656 |
+
assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8
|
| 657 |
+
with pytest.raises(TypeError) as excinfo:
|
| 658 |
+
m.get_elem_rm_nocopy(dbl_matrix_rowmajor)
|
| 659 |
+
assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
|
| 660 |
+
excinfo.value
|
| 661 |
+
)
|
| 662 |
+
assert ", flags.c_contiguous" in str(excinfo.value)
|
| 663 |
+
|
| 664 |
+
|
| 665 |
+
def test_eigen_ref_life_support():
|
| 666 |
+
"""Ensure the lifetime of temporary arrays created by the `Ref` caster
|
| 667 |
+
|
| 668 |
+
The `Ref` caster sometimes creates a copy which needs to stay alive. This needs to
|
| 669 |
+
happen both for directs casts (just the array) or indirectly (e.g. list of arrays).
|
| 670 |
+
"""
|
| 671 |
+
|
| 672 |
+
a = np.full(shape=10, fill_value=8, dtype=np.int8)
|
| 673 |
+
assert m.get_elem_direct(a) == 8
|
| 674 |
+
|
| 675 |
+
list_of_a = [a]
|
| 676 |
+
assert m.get_elem_indirect(list_of_a) == 8
|
| 677 |
+
|
| 678 |
+
|
| 679 |
+
def test_special_matrix_objects():
|
| 680 |
+
assert np.all(m.incr_diag(7) == np.diag([1.0, 2, 3, 4, 5, 6, 7]))
|
| 681 |
+
|
| 682 |
+
asymm = np.array([[1.0, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
|
| 683 |
+
symm_lower = np.array(asymm)
|
| 684 |
+
symm_upper = np.array(asymm)
|
| 685 |
+
for i in range(4):
|
| 686 |
+
for j in range(i + 1, 4):
|
| 687 |
+
symm_lower[i, j] = symm_lower[j, i]
|
| 688 |
+
symm_upper[j, i] = symm_upper[i, j]
|
| 689 |
+
|
| 690 |
+
assert np.all(m.symmetric_lower(asymm) == symm_lower)
|
| 691 |
+
assert np.all(m.symmetric_upper(asymm) == symm_upper)
|
| 692 |
+
|
| 693 |
+
|
| 694 |
+
def test_dense_signature(doc):
|
| 695 |
+
assert (
|
| 696 |
+
doc(m.double_col)
|
| 697 |
+
== """
|
| 698 |
+
double_col(arg0: numpy.ndarray[numpy.float32[m, 1]]) -> numpy.ndarray[numpy.float32[m, 1]]
|
| 699 |
+
"""
|
| 700 |
+
)
|
| 701 |
+
assert (
|
| 702 |
+
doc(m.double_row)
|
| 703 |
+
== """
|
| 704 |
+
double_row(arg0: numpy.ndarray[numpy.float32[1, n]]) -> numpy.ndarray[numpy.float32[1, n]]
|
| 705 |
+
"""
|
| 706 |
+
)
|
| 707 |
+
assert doc(m.double_complex) == (
|
| 708 |
+
"""
|
| 709 |
+
double_complex(arg0: numpy.ndarray[numpy.complex64[m, 1]])"""
|
| 710 |
+
""" -> numpy.ndarray[numpy.complex64[m, 1]]
|
| 711 |
+
"""
|
| 712 |
+
)
|
| 713 |
+
assert doc(m.double_mat_rm) == (
|
| 714 |
+
"""
|
| 715 |
+
double_mat_rm(arg0: numpy.ndarray[numpy.float32[m, n]])"""
|
| 716 |
+
""" -> numpy.ndarray[numpy.float32[m, n]]
|
| 717 |
+
"""
|
| 718 |
+
)
|
| 719 |
+
|
| 720 |
+
|
| 721 |
+
def test_defaults(doc):
|
| 722 |
+
assert "\n" not in str(doc(m.defaults_mat))
|
| 723 |
+
assert "\n" not in str(doc(m.defaults_vec))
|
| 724 |
+
|
| 725 |
+
|
| 726 |
+
def test_named_arguments():
|
| 727 |
+
a = np.array([[1.0, 2], [3, 4], [5, 6]])
|
| 728 |
+
b = np.ones((2, 1))
|
| 729 |
+
|
| 730 |
+
assert np.all(m.matrix_multiply(a, b) == np.array([[3.0], [7], [11]]))
|
| 731 |
+
assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.0], [7], [11]]))
|
| 732 |
+
assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.0], [7], [11]]))
|
| 733 |
+
|
| 734 |
+
with pytest.raises(ValueError) as excinfo:
|
| 735 |
+
m.matrix_multiply(b, a)
|
| 736 |
+
assert str(excinfo.value) == "Nonconformable matrices!"
|
| 737 |
+
|
| 738 |
+
with pytest.raises(ValueError) as excinfo:
|
| 739 |
+
m.matrix_multiply(A=b, B=a)
|
| 740 |
+
assert str(excinfo.value) == "Nonconformable matrices!"
|
| 741 |
+
|
| 742 |
+
with pytest.raises(ValueError) as excinfo:
|
| 743 |
+
m.matrix_multiply(B=a, A=b)
|
| 744 |
+
assert str(excinfo.value) == "Nonconformable matrices!"
|
| 745 |
+
|
| 746 |
+
|
| 747 |
+
def test_sparse():
|
| 748 |
+
pytest.importorskip("scipy")
|
| 749 |
+
assert_sparse_equal_ref(m.sparse_r())
|
| 750 |
+
assert_sparse_equal_ref(m.sparse_c())
|
| 751 |
+
assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_r()))
|
| 752 |
+
assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_c()))
|
| 753 |
+
assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_c()))
|
| 754 |
+
assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_r()))
|
| 755 |
+
|
| 756 |
+
|
| 757 |
+
def test_sparse_signature(doc):
|
| 758 |
+
pytest.importorskip("scipy")
|
| 759 |
+
assert (
|
| 760 |
+
doc(m.sparse_copy_r)
|
| 761 |
+
== """
|
| 762 |
+
sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32]
|
| 763 |
+
"""
|
| 764 |
+
)
|
| 765 |
+
assert (
|
| 766 |
+
doc(m.sparse_copy_c)
|
| 767 |
+
== """
|
| 768 |
+
sparse_copy_c(arg0: scipy.sparse.csc_matrix[numpy.float32]) -> scipy.sparse.csc_matrix[numpy.float32]
|
| 769 |
+
"""
|
| 770 |
+
)
|
| 771 |
+
|
| 772 |
+
|
| 773 |
+
def test_issue738():
|
| 774 |
+
"""Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)"""
|
| 775 |
+
assert np.all(m.iss738_f1(np.array([[1.0, 2, 3]])) == np.array([[1.0, 102, 203]]))
|
| 776 |
+
assert np.all(
|
| 777 |
+
m.iss738_f1(np.array([[1.0], [2], [3]])) == np.array([[1.0], [12], [23]])
|
| 778 |
+
)
|
| 779 |
+
|
| 780 |
+
assert np.all(m.iss738_f2(np.array([[1.0, 2, 3]])) == np.array([[1.0, 102, 203]]))
|
| 781 |
+
assert np.all(
|
| 782 |
+
m.iss738_f2(np.array([[1.0], [2], [3]])) == np.array([[1.0], [12], [23]])
|
| 783 |
+
)
|
| 784 |
+
|
| 785 |
+
|
| 786 |
+
@pytest.mark.parametrize("func", [m.iss738_f1, m.iss738_f2])
|
| 787 |
+
@pytest.mark.parametrize("sizes", [(0, 2), (2, 0)])
|
| 788 |
+
def test_zero_length(func, sizes):
|
| 789 |
+
"""Ignore strides on a length-0 dimension (even if they would be incompatible length > 1)"""
|
| 790 |
+
assert np.all(func(np.zeros(sizes)) == np.zeros(sizes))
|
| 791 |
+
|
| 792 |
+
|
| 793 |
+
def test_issue1105():
|
| 794 |
+
"""Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen
|
| 795 |
+
compile-time row vectors or column vector"""
|
| 796 |
+
assert m.iss1105_row(np.ones((1, 7)))
|
| 797 |
+
assert m.iss1105_col(np.ones((7, 1)))
|
| 798 |
+
|
| 799 |
+
# These should still fail (incompatible dimensions):
|
| 800 |
+
with pytest.raises(TypeError) as excinfo:
|
| 801 |
+
m.iss1105_row(np.ones((7, 1)))
|
| 802 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
| 803 |
+
with pytest.raises(TypeError) as excinfo:
|
| 804 |
+
m.iss1105_col(np.ones((1, 7)))
|
| 805 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
| 806 |
+
|
| 807 |
+
|
| 808 |
+
def test_custom_operator_new():
|
| 809 |
+
"""Using Eigen types as member variables requires a class-specific
|
| 810 |
+
operator new with proper alignment"""
|
| 811 |
+
|
| 812 |
+
o = m.CustomOperatorNew()
|
| 813 |
+
np.testing.assert_allclose(o.a, 0.0)
|
| 814 |
+
np.testing.assert_allclose(o.b.diagonal(), 1.0)
|
third_party/CityFlow/extern/pybind11/tests/test_eigen_tensor.cpp
CHANGED
|
@@ -1,18 +1,18 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/eigen_tensor.cpp -- automatic conversion of Eigen Tensor
|
| 3 |
-
|
| 4 |
-
All rights reserved. Use of this source code is governed by a
|
| 5 |
-
BSD-style license that can be found in the LICENSE file.
|
| 6 |
-
*/
|
| 7 |
-
|
| 8 |
-
#define PYBIND11_TEST_EIGEN_TENSOR_NAMESPACE eigen_tensor
|
| 9 |
-
|
| 10 |
-
#ifdef EIGEN_AVOID_STL_ARRAY
|
| 11 |
-
# undef EIGEN_AVOID_STL_ARRAY
|
| 12 |
-
#endif
|
| 13 |
-
|
| 14 |
-
#include "test_eigen_tensor.inl"
|
| 15 |
-
|
| 16 |
-
#include "pybind11_tests.h"
|
| 17 |
-
|
| 18 |
-
test_initializer egien_tensor("eigen_tensor", eigen_tensor_test::test_module);
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/eigen_tensor.cpp -- automatic conversion of Eigen Tensor
|
| 3 |
+
|
| 4 |
+
All rights reserved. Use of this source code is governed by a
|
| 5 |
+
BSD-style license that can be found in the LICENSE file.
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
#define PYBIND11_TEST_EIGEN_TENSOR_NAMESPACE eigen_tensor
|
| 9 |
+
|
| 10 |
+
#ifdef EIGEN_AVOID_STL_ARRAY
|
| 11 |
+
# undef EIGEN_AVOID_STL_ARRAY
|
| 12 |
+
#endif
|
| 13 |
+
|
| 14 |
+
#include "test_eigen_tensor.inl"
|
| 15 |
+
|
| 16 |
+
#include "pybind11_tests.h"
|
| 17 |
+
|
| 18 |
+
test_initializer egien_tensor("eigen_tensor", eigen_tensor_test::test_module);
|
third_party/CityFlow/extern/pybind11/tests/test_eigen_tensor.inl
CHANGED
|
@@ -1,333 +1,333 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/eigen_tensor.cpp -- automatic conversion of Eigen Tensor
|
| 3 |
-
|
| 4 |
-
All rights reserved. Use of this source code is governed by a
|
| 5 |
-
BSD-style license that can be found in the LICENSE file.
|
| 6 |
-
*/
|
| 7 |
-
|
| 8 |
-
#include <pybind11/eigen/tensor.h>
|
| 9 |
-
|
| 10 |
-
PYBIND11_NAMESPACE_BEGIN(eigen_tensor_test)
|
| 11 |
-
|
| 12 |
-
namespace py = pybind11;
|
| 13 |
-
|
| 14 |
-
PYBIND11_WARNING_DISABLE_MSVC(4127)
|
| 15 |
-
|
| 16 |
-
template <typename M>
|
| 17 |
-
void reset_tensor(M &x) {
|
| 18 |
-
for (int i = 0; i < x.dimension(0); i++) {
|
| 19 |
-
for (int j = 0; j < x.dimension(1); j++) {
|
| 20 |
-
for (int k = 0; k < x.dimension(2); k++) {
|
| 21 |
-
x(i, j, k) = i * (5 * 2) + j * 2 + k;
|
| 22 |
-
}
|
| 23 |
-
}
|
| 24 |
-
}
|
| 25 |
-
}
|
| 26 |
-
|
| 27 |
-
template <typename M>
|
| 28 |
-
bool check_tensor(M &x) {
|
| 29 |
-
for (int i = 0; i < x.dimension(0); i++) {
|
| 30 |
-
for (int j = 0; j < x.dimension(1); j++) {
|
| 31 |
-
for (int k = 0; k < x.dimension(2); k++) {
|
| 32 |
-
if (x(i, j, k) != (i * (5 * 2) + j * 2 + k)) {
|
| 33 |
-
return false;
|
| 34 |
-
}
|
| 35 |
-
}
|
| 36 |
-
}
|
| 37 |
-
}
|
| 38 |
-
return true;
|
| 39 |
-
}
|
| 40 |
-
|
| 41 |
-
template <int Options>
|
| 42 |
-
Eigen::Tensor<double, 3, Options> &get_tensor() {
|
| 43 |
-
static Eigen::Tensor<double, 3, Options> *x;
|
| 44 |
-
|
| 45 |
-
if (!x) {
|
| 46 |
-
x = new Eigen::Tensor<double, 3, Options>(3, 5, 2);
|
| 47 |
-
reset_tensor(*x);
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
return *x;
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
template <int Options>
|
| 54 |
-
Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> &get_tensor_map() {
|
| 55 |
-
static Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> *x;
|
| 56 |
-
|
| 57 |
-
if (!x) {
|
| 58 |
-
x = new Eigen::TensorMap<Eigen::Tensor<double, 3, Options>>(get_tensor<Options>());
|
| 59 |
-
}
|
| 60 |
-
|
| 61 |
-
return *x;
|
| 62 |
-
}
|
| 63 |
-
|
| 64 |
-
template <int Options>
|
| 65 |
-
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options> &get_fixed_tensor() {
|
| 66 |
-
static Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options> *x;
|
| 67 |
-
|
| 68 |
-
if (!x) {
|
| 69 |
-
Eigen::aligned_allocator<Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>>
|
| 70 |
-
allocator;
|
| 71 |
-
x = new (allocator.allocate(1))
|
| 72 |
-
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>();
|
| 73 |
-
reset_tensor(*x);
|
| 74 |
-
}
|
| 75 |
-
|
| 76 |
-
return *x;
|
| 77 |
-
}
|
| 78 |
-
|
| 79 |
-
template <int Options>
|
| 80 |
-
const Eigen::Tensor<double, 3, Options> &get_const_tensor() {
|
| 81 |
-
return get_tensor<Options>();
|
| 82 |
-
}
|
| 83 |
-
|
| 84 |
-
template <int Options>
|
| 85 |
-
struct CustomExample {
|
| 86 |
-
CustomExample() : member(get_tensor<Options>()), view_member(member) {}
|
| 87 |
-
|
| 88 |
-
Eigen::Tensor<double, 3, Options> member;
|
| 89 |
-
Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> view_member;
|
| 90 |
-
};
|
| 91 |
-
|
| 92 |
-
template <int Options>
|
| 93 |
-
void init_tensor_module(pybind11::module &m) {
|
| 94 |
-
const char *needed_options = "";
|
| 95 |
-
if (Options == Eigen::ColMajor) {
|
| 96 |
-
needed_options = "F";
|
| 97 |
-
} else {
|
| 98 |
-
needed_options = "C";
|
| 99 |
-
}
|
| 100 |
-
m.attr("needed_options") = needed_options;
|
| 101 |
-
|
| 102 |
-
m.def("setup", []() {
|
| 103 |
-
reset_tensor(get_tensor<Options>());
|
| 104 |
-
reset_tensor(get_fixed_tensor<Options>());
|
| 105 |
-
});
|
| 106 |
-
|
| 107 |
-
m.def("is_ok", []() {
|
| 108 |
-
return check_tensor(get_tensor<Options>()) && check_tensor(get_fixed_tensor<Options>());
|
| 109 |
-
});
|
| 110 |
-
|
| 111 |
-
py::class_<CustomExample<Options>>(m, "CustomExample", py::module_local())
|
| 112 |
-
.def(py::init<>())
|
| 113 |
-
.def_readonly(
|
| 114 |
-
"member", &CustomExample<Options>::member, py::return_value_policy::reference_internal)
|
| 115 |
-
.def_readonly("member_view",
|
| 116 |
-
&CustomExample<Options>::view_member,
|
| 117 |
-
py::return_value_policy::reference_internal);
|
| 118 |
-
|
| 119 |
-
m.def(
|
| 120 |
-
"copy_fixed_tensor",
|
| 121 |
-
[]() { return &get_fixed_tensor<Options>(); },
|
| 122 |
-
py::return_value_policy::copy);
|
| 123 |
-
|
| 124 |
-
m.def(
|
| 125 |
-
"copy_tensor", []() { return &get_tensor<Options>(); }, py::return_value_policy::copy);
|
| 126 |
-
|
| 127 |
-
m.def(
|
| 128 |
-
"copy_const_tensor",
|
| 129 |
-
[]() { return &get_const_tensor<Options>(); },
|
| 130 |
-
py::return_value_policy::copy);
|
| 131 |
-
|
| 132 |
-
m.def(
|
| 133 |
-
"move_fixed_tensor_copy",
|
| 134 |
-
[]() -> Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options> {
|
| 135 |
-
return get_fixed_tensor<Options>();
|
| 136 |
-
},
|
| 137 |
-
py::return_value_policy::move);
|
| 138 |
-
|
| 139 |
-
m.def(
|
| 140 |
-
"move_tensor_copy",
|
| 141 |
-
[]() -> Eigen::Tensor<double, 3, Options> { return get_tensor<Options>(); },
|
| 142 |
-
py::return_value_policy::move);
|
| 143 |
-
|
| 144 |
-
m.def(
|
| 145 |
-
"move_const_tensor",
|
| 146 |
-
[]() -> const Eigen::Tensor<double, 3, Options> & { return get_const_tensor<Options>(); },
|
| 147 |
-
py::return_value_policy::move);
|
| 148 |
-
|
| 149 |
-
m.def(
|
| 150 |
-
"take_fixed_tensor",
|
| 151 |
-
|
| 152 |
-
[]() {
|
| 153 |
-
Eigen::aligned_allocator<
|
| 154 |
-
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>>
|
| 155 |
-
allocator;
|
| 156 |
-
return new (allocator.allocate(1))
|
| 157 |
-
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>(
|
| 158 |
-
get_fixed_tensor<Options>());
|
| 159 |
-
},
|
| 160 |
-
py::return_value_policy::take_ownership);
|
| 161 |
-
|
| 162 |
-
m.def(
|
| 163 |
-
"take_tensor",
|
| 164 |
-
[]() { return new Eigen::Tensor<double, 3, Options>(get_tensor<Options>()); },
|
| 165 |
-
py::return_value_policy::take_ownership);
|
| 166 |
-
|
| 167 |
-
m.def(
|
| 168 |
-
"take_const_tensor",
|
| 169 |
-
[]() -> const Eigen::Tensor<double, 3, Options> * {
|
| 170 |
-
return new Eigen::Tensor<double, 3, Options>(get_tensor<Options>());
|
| 171 |
-
},
|
| 172 |
-
py::return_value_policy::take_ownership);
|
| 173 |
-
|
| 174 |
-
m.def(
|
| 175 |
-
"take_view_tensor",
|
| 176 |
-
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> * {
|
| 177 |
-
return new Eigen::TensorMap<Eigen::Tensor<double, 3, Options>>(get_tensor<Options>());
|
| 178 |
-
},
|
| 179 |
-
py::return_value_policy::take_ownership);
|
| 180 |
-
|
| 181 |
-
m.def(
|
| 182 |
-
"reference_tensor",
|
| 183 |
-
[]() { return &get_tensor<Options>(); },
|
| 184 |
-
py::return_value_policy::reference);
|
| 185 |
-
|
| 186 |
-
m.def(
|
| 187 |
-
"reference_tensor_v2",
|
| 188 |
-
[]() -> Eigen::Tensor<double, 3, Options> & { return get_tensor<Options>(); },
|
| 189 |
-
py::return_value_policy::reference);
|
| 190 |
-
|
| 191 |
-
m.def(
|
| 192 |
-
"reference_tensor_internal",
|
| 193 |
-
[]() { return &get_tensor<Options>(); },
|
| 194 |
-
py::return_value_policy::reference_internal);
|
| 195 |
-
|
| 196 |
-
m.def(
|
| 197 |
-
"reference_fixed_tensor",
|
| 198 |
-
[]() { return &get_tensor<Options>(); },
|
| 199 |
-
py::return_value_policy::reference);
|
| 200 |
-
|
| 201 |
-
m.def(
|
| 202 |
-
"reference_const_tensor",
|
| 203 |
-
[]() { return &get_const_tensor<Options>(); },
|
| 204 |
-
py::return_value_policy::reference);
|
| 205 |
-
|
| 206 |
-
m.def(
|
| 207 |
-
"reference_const_tensor_v2",
|
| 208 |
-
[]() -> const Eigen::Tensor<double, 3, Options> & { return get_const_tensor<Options>(); },
|
| 209 |
-
py::return_value_policy::reference);
|
| 210 |
-
|
| 211 |
-
m.def(
|
| 212 |
-
"reference_view_of_tensor",
|
| 213 |
-
[]() -> Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> {
|
| 214 |
-
return get_tensor_map<Options>();
|
| 215 |
-
},
|
| 216 |
-
py::return_value_policy::reference);
|
| 217 |
-
|
| 218 |
-
m.def(
|
| 219 |
-
"reference_view_of_tensor_v2",
|
| 220 |
-
// NOLINTNEXTLINE(readability-const-return-type)
|
| 221 |
-
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> {
|
| 222 |
-
return get_tensor_map<Options>(); // NOLINT(readability-const-return-type)
|
| 223 |
-
}, // NOLINT(readability-const-return-type)
|
| 224 |
-
py::return_value_policy::reference);
|
| 225 |
-
|
| 226 |
-
m.def(
|
| 227 |
-
"reference_view_of_tensor_v3",
|
| 228 |
-
[]() -> Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> * {
|
| 229 |
-
return &get_tensor_map<Options>();
|
| 230 |
-
},
|
| 231 |
-
py::return_value_policy::reference);
|
| 232 |
-
|
| 233 |
-
m.def(
|
| 234 |
-
"reference_view_of_tensor_v4",
|
| 235 |
-
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> * {
|
| 236 |
-
return &get_tensor_map<Options>();
|
| 237 |
-
},
|
| 238 |
-
py::return_value_policy::reference);
|
| 239 |
-
|
| 240 |
-
m.def(
|
| 241 |
-
"reference_view_of_tensor_v5",
|
| 242 |
-
[]() -> Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> & {
|
| 243 |
-
return get_tensor_map<Options>();
|
| 244 |
-
},
|
| 245 |
-
py::return_value_policy::reference);
|
| 246 |
-
|
| 247 |
-
m.def(
|
| 248 |
-
"reference_view_of_tensor_v6",
|
| 249 |
-
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> & {
|
| 250 |
-
return get_tensor_map<Options>();
|
| 251 |
-
},
|
| 252 |
-
py::return_value_policy::reference);
|
| 253 |
-
|
| 254 |
-
m.def(
|
| 255 |
-
"reference_view_of_fixed_tensor",
|
| 256 |
-
[]() {
|
| 257 |
-
return Eigen::TensorMap<
|
| 258 |
-
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>>(
|
| 259 |
-
get_fixed_tensor<Options>());
|
| 260 |
-
},
|
| 261 |
-
py::return_value_policy::reference);
|
| 262 |
-
|
| 263 |
-
m.def("round_trip_tensor",
|
| 264 |
-
[](const Eigen::Tensor<double, 3, Options> &tensor) { return tensor; });
|
| 265 |
-
|
| 266 |
-
m.def(
|
| 267 |
-
"round_trip_tensor_noconvert",
|
| 268 |
-
[](const Eigen::Tensor<double, 3, Options> &tensor) { return tensor; },
|
| 269 |
-
py::arg("tensor").noconvert());
|
| 270 |
-
|
| 271 |
-
m.def("round_trip_tensor2",
|
| 272 |
-
[](const Eigen::Tensor<int32_t, 3, Options> &tensor) { return tensor; });
|
| 273 |
-
|
| 274 |
-
m.def("round_trip_fixed_tensor",
|
| 275 |
-
[](const Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options> &tensor) {
|
| 276 |
-
return tensor;
|
| 277 |
-
});
|
| 278 |
-
|
| 279 |
-
m.def(
|
| 280 |
-
"round_trip_view_tensor",
|
| 281 |
-
[](Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> view) { return view; },
|
| 282 |
-
py::return_value_policy::reference);
|
| 283 |
-
|
| 284 |
-
m.def(
|
| 285 |
-
"round_trip_view_tensor_ref",
|
| 286 |
-
[](Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> &view) { return view; },
|
| 287 |
-
py::return_value_policy::reference);
|
| 288 |
-
|
| 289 |
-
m.def(
|
| 290 |
-
"round_trip_view_tensor_ptr",
|
| 291 |
-
[](Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> *view) { return view; },
|
| 292 |
-
py::return_value_policy::reference);
|
| 293 |
-
|
| 294 |
-
m.def(
|
| 295 |
-
"round_trip_aligned_view_tensor",
|
| 296 |
-
[](Eigen::TensorMap<Eigen::Tensor<double, 3, Options>, Eigen::Aligned> view) {
|
| 297 |
-
return view;
|
| 298 |
-
},
|
| 299 |
-
py::return_value_policy::reference);
|
| 300 |
-
|
| 301 |
-
m.def(
|
| 302 |
-
"round_trip_const_view_tensor",
|
| 303 |
-
[](Eigen::TensorMap<const Eigen::Tensor<double, 3, Options>> view) {
|
| 304 |
-
return Eigen::Tensor<double, 3, Options>(view);
|
| 305 |
-
},
|
| 306 |
-
py::return_value_policy::move);
|
| 307 |
-
|
| 308 |
-
m.def(
|
| 309 |
-
"round_trip_rank_0",
|
| 310 |
-
[](const Eigen::Tensor<double, 0, Options> &tensor) { return tensor; },
|
| 311 |
-
py::return_value_policy::move);
|
| 312 |
-
|
| 313 |
-
m.def(
|
| 314 |
-
"round_trip_rank_0_noconvert",
|
| 315 |
-
[](const Eigen::Tensor<double, 0, Options> &tensor) { return tensor; },
|
| 316 |
-
py::arg("tensor").noconvert(),
|
| 317 |
-
py::return_value_policy::move);
|
| 318 |
-
|
| 319 |
-
m.def(
|
| 320 |
-
"round_trip_rank_0_view",
|
| 321 |
-
[](Eigen::TensorMap<Eigen::Tensor<double, 0, Options>> &tensor) { return tensor; },
|
| 322 |
-
py::return_value_policy::reference);
|
| 323 |
-
}
|
| 324 |
-
|
| 325 |
-
void test_module(py::module_ &m) {
|
| 326 |
-
auto f_style = m.def_submodule("f_style");
|
| 327 |
-
auto c_style = m.def_submodule("c_style");
|
| 328 |
-
|
| 329 |
-
init_tensor_module<Eigen::ColMajor>(f_style);
|
| 330 |
-
init_tensor_module<Eigen::RowMajor>(c_style);
|
| 331 |
-
}
|
| 332 |
-
|
| 333 |
-
PYBIND11_NAMESPACE_END(eigen_tensor_test)
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/eigen_tensor.cpp -- automatic conversion of Eigen Tensor
|
| 3 |
+
|
| 4 |
+
All rights reserved. Use of this source code is governed by a
|
| 5 |
+
BSD-style license that can be found in the LICENSE file.
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
#include <pybind11/eigen/tensor.h>
|
| 9 |
+
|
| 10 |
+
PYBIND11_NAMESPACE_BEGIN(eigen_tensor_test)
|
| 11 |
+
|
| 12 |
+
namespace py = pybind11;
|
| 13 |
+
|
| 14 |
+
PYBIND11_WARNING_DISABLE_MSVC(4127)
|
| 15 |
+
|
| 16 |
+
template <typename M>
|
| 17 |
+
void reset_tensor(M &x) {
|
| 18 |
+
for (int i = 0; i < x.dimension(0); i++) {
|
| 19 |
+
for (int j = 0; j < x.dimension(1); j++) {
|
| 20 |
+
for (int k = 0; k < x.dimension(2); k++) {
|
| 21 |
+
x(i, j, k) = i * (5 * 2) + j * 2 + k;
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
}
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
template <typename M>
|
| 28 |
+
bool check_tensor(M &x) {
|
| 29 |
+
for (int i = 0; i < x.dimension(0); i++) {
|
| 30 |
+
for (int j = 0; j < x.dimension(1); j++) {
|
| 31 |
+
for (int k = 0; k < x.dimension(2); k++) {
|
| 32 |
+
if (x(i, j, k) != (i * (5 * 2) + j * 2 + k)) {
|
| 33 |
+
return false;
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
return true;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
template <int Options>
|
| 42 |
+
Eigen::Tensor<double, 3, Options> &get_tensor() {
|
| 43 |
+
static Eigen::Tensor<double, 3, Options> *x;
|
| 44 |
+
|
| 45 |
+
if (!x) {
|
| 46 |
+
x = new Eigen::Tensor<double, 3, Options>(3, 5, 2);
|
| 47 |
+
reset_tensor(*x);
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
return *x;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
template <int Options>
|
| 54 |
+
Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> &get_tensor_map() {
|
| 55 |
+
static Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> *x;
|
| 56 |
+
|
| 57 |
+
if (!x) {
|
| 58 |
+
x = new Eigen::TensorMap<Eigen::Tensor<double, 3, Options>>(get_tensor<Options>());
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
return *x;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
template <int Options>
|
| 65 |
+
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options> &get_fixed_tensor() {
|
| 66 |
+
static Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options> *x;
|
| 67 |
+
|
| 68 |
+
if (!x) {
|
| 69 |
+
Eigen::aligned_allocator<Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>>
|
| 70 |
+
allocator;
|
| 71 |
+
x = new (allocator.allocate(1))
|
| 72 |
+
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>();
|
| 73 |
+
reset_tensor(*x);
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
return *x;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
template <int Options>
|
| 80 |
+
const Eigen::Tensor<double, 3, Options> &get_const_tensor() {
|
| 81 |
+
return get_tensor<Options>();
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
template <int Options>
|
| 85 |
+
struct CustomExample {
|
| 86 |
+
CustomExample() : member(get_tensor<Options>()), view_member(member) {}
|
| 87 |
+
|
| 88 |
+
Eigen::Tensor<double, 3, Options> member;
|
| 89 |
+
Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> view_member;
|
| 90 |
+
};
|
| 91 |
+
|
| 92 |
+
template <int Options>
|
| 93 |
+
void init_tensor_module(pybind11::module &m) {
|
| 94 |
+
const char *needed_options = "";
|
| 95 |
+
if (Options == Eigen::ColMajor) {
|
| 96 |
+
needed_options = "F";
|
| 97 |
+
} else {
|
| 98 |
+
needed_options = "C";
|
| 99 |
+
}
|
| 100 |
+
m.attr("needed_options") = needed_options;
|
| 101 |
+
|
| 102 |
+
m.def("setup", []() {
|
| 103 |
+
reset_tensor(get_tensor<Options>());
|
| 104 |
+
reset_tensor(get_fixed_tensor<Options>());
|
| 105 |
+
});
|
| 106 |
+
|
| 107 |
+
m.def("is_ok", []() {
|
| 108 |
+
return check_tensor(get_tensor<Options>()) && check_tensor(get_fixed_tensor<Options>());
|
| 109 |
+
});
|
| 110 |
+
|
| 111 |
+
py::class_<CustomExample<Options>>(m, "CustomExample", py::module_local())
|
| 112 |
+
.def(py::init<>())
|
| 113 |
+
.def_readonly(
|
| 114 |
+
"member", &CustomExample<Options>::member, py::return_value_policy::reference_internal)
|
| 115 |
+
.def_readonly("member_view",
|
| 116 |
+
&CustomExample<Options>::view_member,
|
| 117 |
+
py::return_value_policy::reference_internal);
|
| 118 |
+
|
| 119 |
+
m.def(
|
| 120 |
+
"copy_fixed_tensor",
|
| 121 |
+
[]() { return &get_fixed_tensor<Options>(); },
|
| 122 |
+
py::return_value_policy::copy);
|
| 123 |
+
|
| 124 |
+
m.def(
|
| 125 |
+
"copy_tensor", []() { return &get_tensor<Options>(); }, py::return_value_policy::copy);
|
| 126 |
+
|
| 127 |
+
m.def(
|
| 128 |
+
"copy_const_tensor",
|
| 129 |
+
[]() { return &get_const_tensor<Options>(); },
|
| 130 |
+
py::return_value_policy::copy);
|
| 131 |
+
|
| 132 |
+
m.def(
|
| 133 |
+
"move_fixed_tensor_copy",
|
| 134 |
+
[]() -> Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options> {
|
| 135 |
+
return get_fixed_tensor<Options>();
|
| 136 |
+
},
|
| 137 |
+
py::return_value_policy::move);
|
| 138 |
+
|
| 139 |
+
m.def(
|
| 140 |
+
"move_tensor_copy",
|
| 141 |
+
[]() -> Eigen::Tensor<double, 3, Options> { return get_tensor<Options>(); },
|
| 142 |
+
py::return_value_policy::move);
|
| 143 |
+
|
| 144 |
+
m.def(
|
| 145 |
+
"move_const_tensor",
|
| 146 |
+
[]() -> const Eigen::Tensor<double, 3, Options> & { return get_const_tensor<Options>(); },
|
| 147 |
+
py::return_value_policy::move);
|
| 148 |
+
|
| 149 |
+
m.def(
|
| 150 |
+
"take_fixed_tensor",
|
| 151 |
+
|
| 152 |
+
[]() {
|
| 153 |
+
Eigen::aligned_allocator<
|
| 154 |
+
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>>
|
| 155 |
+
allocator;
|
| 156 |
+
return new (allocator.allocate(1))
|
| 157 |
+
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>(
|
| 158 |
+
get_fixed_tensor<Options>());
|
| 159 |
+
},
|
| 160 |
+
py::return_value_policy::take_ownership);
|
| 161 |
+
|
| 162 |
+
m.def(
|
| 163 |
+
"take_tensor",
|
| 164 |
+
[]() { return new Eigen::Tensor<double, 3, Options>(get_tensor<Options>()); },
|
| 165 |
+
py::return_value_policy::take_ownership);
|
| 166 |
+
|
| 167 |
+
m.def(
|
| 168 |
+
"take_const_tensor",
|
| 169 |
+
[]() -> const Eigen::Tensor<double, 3, Options> * {
|
| 170 |
+
return new Eigen::Tensor<double, 3, Options>(get_tensor<Options>());
|
| 171 |
+
},
|
| 172 |
+
py::return_value_policy::take_ownership);
|
| 173 |
+
|
| 174 |
+
m.def(
|
| 175 |
+
"take_view_tensor",
|
| 176 |
+
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> * {
|
| 177 |
+
return new Eigen::TensorMap<Eigen::Tensor<double, 3, Options>>(get_tensor<Options>());
|
| 178 |
+
},
|
| 179 |
+
py::return_value_policy::take_ownership);
|
| 180 |
+
|
| 181 |
+
m.def(
|
| 182 |
+
"reference_tensor",
|
| 183 |
+
[]() { return &get_tensor<Options>(); },
|
| 184 |
+
py::return_value_policy::reference);
|
| 185 |
+
|
| 186 |
+
m.def(
|
| 187 |
+
"reference_tensor_v2",
|
| 188 |
+
[]() -> Eigen::Tensor<double, 3, Options> & { return get_tensor<Options>(); },
|
| 189 |
+
py::return_value_policy::reference);
|
| 190 |
+
|
| 191 |
+
m.def(
|
| 192 |
+
"reference_tensor_internal",
|
| 193 |
+
[]() { return &get_tensor<Options>(); },
|
| 194 |
+
py::return_value_policy::reference_internal);
|
| 195 |
+
|
| 196 |
+
m.def(
|
| 197 |
+
"reference_fixed_tensor",
|
| 198 |
+
[]() { return &get_tensor<Options>(); },
|
| 199 |
+
py::return_value_policy::reference);
|
| 200 |
+
|
| 201 |
+
m.def(
|
| 202 |
+
"reference_const_tensor",
|
| 203 |
+
[]() { return &get_const_tensor<Options>(); },
|
| 204 |
+
py::return_value_policy::reference);
|
| 205 |
+
|
| 206 |
+
m.def(
|
| 207 |
+
"reference_const_tensor_v2",
|
| 208 |
+
[]() -> const Eigen::Tensor<double, 3, Options> & { return get_const_tensor<Options>(); },
|
| 209 |
+
py::return_value_policy::reference);
|
| 210 |
+
|
| 211 |
+
m.def(
|
| 212 |
+
"reference_view_of_tensor",
|
| 213 |
+
[]() -> Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> {
|
| 214 |
+
return get_tensor_map<Options>();
|
| 215 |
+
},
|
| 216 |
+
py::return_value_policy::reference);
|
| 217 |
+
|
| 218 |
+
m.def(
|
| 219 |
+
"reference_view_of_tensor_v2",
|
| 220 |
+
// NOLINTNEXTLINE(readability-const-return-type)
|
| 221 |
+
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> {
|
| 222 |
+
return get_tensor_map<Options>(); // NOLINT(readability-const-return-type)
|
| 223 |
+
}, // NOLINT(readability-const-return-type)
|
| 224 |
+
py::return_value_policy::reference);
|
| 225 |
+
|
| 226 |
+
m.def(
|
| 227 |
+
"reference_view_of_tensor_v3",
|
| 228 |
+
[]() -> Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> * {
|
| 229 |
+
return &get_tensor_map<Options>();
|
| 230 |
+
},
|
| 231 |
+
py::return_value_policy::reference);
|
| 232 |
+
|
| 233 |
+
m.def(
|
| 234 |
+
"reference_view_of_tensor_v4",
|
| 235 |
+
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> * {
|
| 236 |
+
return &get_tensor_map<Options>();
|
| 237 |
+
},
|
| 238 |
+
py::return_value_policy::reference);
|
| 239 |
+
|
| 240 |
+
m.def(
|
| 241 |
+
"reference_view_of_tensor_v5",
|
| 242 |
+
[]() -> Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> & {
|
| 243 |
+
return get_tensor_map<Options>();
|
| 244 |
+
},
|
| 245 |
+
py::return_value_policy::reference);
|
| 246 |
+
|
| 247 |
+
m.def(
|
| 248 |
+
"reference_view_of_tensor_v6",
|
| 249 |
+
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> & {
|
| 250 |
+
return get_tensor_map<Options>();
|
| 251 |
+
},
|
| 252 |
+
py::return_value_policy::reference);
|
| 253 |
+
|
| 254 |
+
m.def(
|
| 255 |
+
"reference_view_of_fixed_tensor",
|
| 256 |
+
[]() {
|
| 257 |
+
return Eigen::TensorMap<
|
| 258 |
+
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>>(
|
| 259 |
+
get_fixed_tensor<Options>());
|
| 260 |
+
},
|
| 261 |
+
py::return_value_policy::reference);
|
| 262 |
+
|
| 263 |
+
m.def("round_trip_tensor",
|
| 264 |
+
[](const Eigen::Tensor<double, 3, Options> &tensor) { return tensor; });
|
| 265 |
+
|
| 266 |
+
m.def(
|
| 267 |
+
"round_trip_tensor_noconvert",
|
| 268 |
+
[](const Eigen::Tensor<double, 3, Options> &tensor) { return tensor; },
|
| 269 |
+
py::arg("tensor").noconvert());
|
| 270 |
+
|
| 271 |
+
m.def("round_trip_tensor2",
|
| 272 |
+
[](const Eigen::Tensor<int32_t, 3, Options> &tensor) { return tensor; });
|
| 273 |
+
|
| 274 |
+
m.def("round_trip_fixed_tensor",
|
| 275 |
+
[](const Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options> &tensor) {
|
| 276 |
+
return tensor;
|
| 277 |
+
});
|
| 278 |
+
|
| 279 |
+
m.def(
|
| 280 |
+
"round_trip_view_tensor",
|
| 281 |
+
[](Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> view) { return view; },
|
| 282 |
+
py::return_value_policy::reference);
|
| 283 |
+
|
| 284 |
+
m.def(
|
| 285 |
+
"round_trip_view_tensor_ref",
|
| 286 |
+
[](Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> &view) { return view; },
|
| 287 |
+
py::return_value_policy::reference);
|
| 288 |
+
|
| 289 |
+
m.def(
|
| 290 |
+
"round_trip_view_tensor_ptr",
|
| 291 |
+
[](Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> *view) { return view; },
|
| 292 |
+
py::return_value_policy::reference);
|
| 293 |
+
|
| 294 |
+
m.def(
|
| 295 |
+
"round_trip_aligned_view_tensor",
|
| 296 |
+
[](Eigen::TensorMap<Eigen::Tensor<double, 3, Options>, Eigen::Aligned> view) {
|
| 297 |
+
return view;
|
| 298 |
+
},
|
| 299 |
+
py::return_value_policy::reference);
|
| 300 |
+
|
| 301 |
+
m.def(
|
| 302 |
+
"round_trip_const_view_tensor",
|
| 303 |
+
[](Eigen::TensorMap<const Eigen::Tensor<double, 3, Options>> view) {
|
| 304 |
+
return Eigen::Tensor<double, 3, Options>(view);
|
| 305 |
+
},
|
| 306 |
+
py::return_value_policy::move);
|
| 307 |
+
|
| 308 |
+
m.def(
|
| 309 |
+
"round_trip_rank_0",
|
| 310 |
+
[](const Eigen::Tensor<double, 0, Options> &tensor) { return tensor; },
|
| 311 |
+
py::return_value_policy::move);
|
| 312 |
+
|
| 313 |
+
m.def(
|
| 314 |
+
"round_trip_rank_0_noconvert",
|
| 315 |
+
[](const Eigen::Tensor<double, 0, Options> &tensor) { return tensor; },
|
| 316 |
+
py::arg("tensor").noconvert(),
|
| 317 |
+
py::return_value_policy::move);
|
| 318 |
+
|
| 319 |
+
m.def(
|
| 320 |
+
"round_trip_rank_0_view",
|
| 321 |
+
[](Eigen::TensorMap<Eigen::Tensor<double, 0, Options>> &tensor) { return tensor; },
|
| 322 |
+
py::return_value_policy::reference);
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
void test_module(py::module_ &m) {
|
| 326 |
+
auto f_style = m.def_submodule("f_style");
|
| 327 |
+
auto c_style = m.def_submodule("c_style");
|
| 328 |
+
|
| 329 |
+
init_tensor_module<Eigen::ColMajor>(f_style);
|
| 330 |
+
init_tensor_module<Eigen::RowMajor>(c_style);
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
PYBIND11_NAMESPACE_END(eigen_tensor_test)
|
third_party/CityFlow/extern/pybind11/tests/test_eigen_tensor.py
CHANGED
|
@@ -1,288 +1,288 @@
|
|
| 1 |
-
import sys
|
| 2 |
-
|
| 3 |
-
import pytest
|
| 4 |
-
|
| 5 |
-
np = pytest.importorskip("numpy")
|
| 6 |
-
eigen_tensor = pytest.importorskip("pybind11_tests.eigen_tensor")
|
| 7 |
-
submodules = [eigen_tensor.c_style, eigen_tensor.f_style]
|
| 8 |
-
try:
|
| 9 |
-
import eigen_tensor_avoid_stl_array as avoid
|
| 10 |
-
|
| 11 |
-
submodules += [avoid.c_style, avoid.f_style]
|
| 12 |
-
except ImportError as e:
|
| 13 |
-
# Ensure config, build, toolchain, etc. issues are not masked here:
|
| 14 |
-
msg = (
|
| 15 |
-
"import eigen_tensor_avoid_stl_array FAILED, while "
|
| 16 |
-
"import pybind11_tests.eigen_tensor succeeded. "
|
| 17 |
-
"Please ensure that "
|
| 18 |
-
"test_eigen_tensor.cpp & "
|
| 19 |
-
"eigen_tensor_avoid_stl_array.cpp "
|
| 20 |
-
"are built together (or both are not built if Eigen is not available)."
|
| 21 |
-
)
|
| 22 |
-
raise RuntimeError(msg) from e
|
| 23 |
-
|
| 24 |
-
tensor_ref = np.empty((3, 5, 2), dtype=np.int64)
|
| 25 |
-
|
| 26 |
-
for i in range(tensor_ref.shape[0]):
|
| 27 |
-
for j in range(tensor_ref.shape[1]):
|
| 28 |
-
for k in range(tensor_ref.shape[2]):
|
| 29 |
-
tensor_ref[i, j, k] = i * (5 * 2) + j * 2 + k
|
| 30 |
-
|
| 31 |
-
indices = (2, 3, 1)
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
@pytest.fixture(autouse=True)
|
| 35 |
-
def cleanup():
|
| 36 |
-
for module in submodules:
|
| 37 |
-
module.setup()
|
| 38 |
-
|
| 39 |
-
yield
|
| 40 |
-
|
| 41 |
-
for module in submodules:
|
| 42 |
-
assert module.is_ok()
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
def test_import_avoid_stl_array():
|
| 46 |
-
pytest.importorskip("eigen_tensor_avoid_stl_array")
|
| 47 |
-
assert len(submodules) == 4
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
def assert_equal_tensor_ref(mat, writeable=True, modified=None):
|
| 51 |
-
assert mat.flags.writeable == writeable
|
| 52 |
-
|
| 53 |
-
copy = np.array(tensor_ref)
|
| 54 |
-
if modified is not None:
|
| 55 |
-
copy[indices] = modified
|
| 56 |
-
|
| 57 |
-
np.testing.assert_array_equal(mat, copy)
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
@pytest.mark.parametrize("m", submodules)
|
| 61 |
-
@pytest.mark.parametrize("member_name", ["member", "member_view"])
|
| 62 |
-
def test_reference_internal(m, member_name):
|
| 63 |
-
if not hasattr(sys, "getrefcount"):
|
| 64 |
-
pytest.skip("No reference counting")
|
| 65 |
-
foo = m.CustomExample()
|
| 66 |
-
counts = sys.getrefcount(foo)
|
| 67 |
-
mem = getattr(foo, member_name)
|
| 68 |
-
assert_equal_tensor_ref(mem, writeable=False)
|
| 69 |
-
new_counts = sys.getrefcount(foo)
|
| 70 |
-
assert new_counts == counts + 1
|
| 71 |
-
assert_equal_tensor_ref(mem, writeable=False)
|
| 72 |
-
del mem
|
| 73 |
-
assert sys.getrefcount(foo) == counts
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
assert_equal_funcs = [
|
| 77 |
-
"copy_tensor",
|
| 78 |
-
"copy_fixed_tensor",
|
| 79 |
-
"copy_const_tensor",
|
| 80 |
-
"move_tensor_copy",
|
| 81 |
-
"move_fixed_tensor_copy",
|
| 82 |
-
"take_tensor",
|
| 83 |
-
"take_fixed_tensor",
|
| 84 |
-
"reference_tensor",
|
| 85 |
-
"reference_tensor_v2",
|
| 86 |
-
"reference_fixed_tensor",
|
| 87 |
-
"reference_view_of_tensor",
|
| 88 |
-
"reference_view_of_tensor_v3",
|
| 89 |
-
"reference_view_of_tensor_v5",
|
| 90 |
-
"reference_view_of_fixed_tensor",
|
| 91 |
-
]
|
| 92 |
-
|
| 93 |
-
assert_equal_const_funcs = [
|
| 94 |
-
"reference_view_of_tensor_v2",
|
| 95 |
-
"reference_view_of_tensor_v4",
|
| 96 |
-
"reference_view_of_tensor_v6",
|
| 97 |
-
"reference_const_tensor",
|
| 98 |
-
"reference_const_tensor_v2",
|
| 99 |
-
]
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
@pytest.mark.parametrize("m", submodules)
|
| 103 |
-
@pytest.mark.parametrize("func_name", assert_equal_funcs + assert_equal_const_funcs)
|
| 104 |
-
def test_convert_tensor_to_py(m, func_name):
|
| 105 |
-
writeable = func_name in assert_equal_funcs
|
| 106 |
-
assert_equal_tensor_ref(getattr(m, func_name)(), writeable=writeable)
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
@pytest.mark.parametrize("m", submodules)
|
| 110 |
-
def test_bad_cpp_to_python_casts(m):
|
| 111 |
-
with pytest.raises(
|
| 112 |
-
RuntimeError, match="Cannot use reference internal when there is no parent"
|
| 113 |
-
):
|
| 114 |
-
m.reference_tensor_internal()
|
| 115 |
-
|
| 116 |
-
with pytest.raises(RuntimeError, match="Cannot move from a constant reference"):
|
| 117 |
-
m.move_const_tensor()
|
| 118 |
-
|
| 119 |
-
with pytest.raises(
|
| 120 |
-
RuntimeError, match="Cannot take ownership of a const reference"
|
| 121 |
-
):
|
| 122 |
-
m.take_const_tensor()
|
| 123 |
-
|
| 124 |
-
with pytest.raises(
|
| 125 |
-
RuntimeError,
|
| 126 |
-
match="Invalid return_value_policy for Eigen Map type, must be either reference or reference_internal",
|
| 127 |
-
):
|
| 128 |
-
m.take_view_tensor()
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
@pytest.mark.parametrize("m", submodules)
|
| 132 |
-
def test_bad_python_to_cpp_casts(m):
|
| 133 |
-
with pytest.raises(
|
| 134 |
-
TypeError, match=r"^round_trip_tensor\(\): incompatible function arguments"
|
| 135 |
-
):
|
| 136 |
-
m.round_trip_tensor(np.zeros((2, 3)))
|
| 137 |
-
|
| 138 |
-
with pytest.raises(TypeError, match=r"^Cannot cast array data from dtype"):
|
| 139 |
-
m.round_trip_tensor(np.zeros(dtype=np.str_, shape=(2, 3, 1)))
|
| 140 |
-
|
| 141 |
-
with pytest.raises(
|
| 142 |
-
TypeError,
|
| 143 |
-
match=r"^round_trip_tensor_noconvert\(\): incompatible function arguments",
|
| 144 |
-
):
|
| 145 |
-
m.round_trip_tensor_noconvert(tensor_ref)
|
| 146 |
-
|
| 147 |
-
assert_equal_tensor_ref(
|
| 148 |
-
m.round_trip_tensor_noconvert(tensor_ref.astype(np.float64))
|
| 149 |
-
)
|
| 150 |
-
|
| 151 |
-
bad_options = "C" if m.needed_options == "F" else "F"
|
| 152 |
-
# Shape, dtype and the order need to be correct for a TensorMap cast
|
| 153 |
-
with pytest.raises(
|
| 154 |
-
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
|
| 155 |
-
):
|
| 156 |
-
m.round_trip_view_tensor(
|
| 157 |
-
np.zeros((3, 5, 2), dtype=np.float64, order=bad_options)
|
| 158 |
-
)
|
| 159 |
-
|
| 160 |
-
with pytest.raises(
|
| 161 |
-
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
|
| 162 |
-
):
|
| 163 |
-
m.round_trip_view_tensor(
|
| 164 |
-
np.zeros((3, 5, 2), dtype=np.float32, order=m.needed_options)
|
| 165 |
-
)
|
| 166 |
-
|
| 167 |
-
with pytest.raises(
|
| 168 |
-
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
|
| 169 |
-
):
|
| 170 |
-
m.round_trip_view_tensor(
|
| 171 |
-
np.zeros((3, 5), dtype=np.float64, order=m.needed_options)
|
| 172 |
-
)
|
| 173 |
-
|
| 174 |
-
temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options)
|
| 175 |
-
with pytest.raises(
|
| 176 |
-
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
|
| 177 |
-
):
|
| 178 |
-
m.round_trip_view_tensor(
|
| 179 |
-
temp[:, ::-1, :],
|
| 180 |
-
)
|
| 181 |
-
|
| 182 |
-
temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options)
|
| 183 |
-
temp.setflags(write=False)
|
| 184 |
-
with pytest.raises(
|
| 185 |
-
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
|
| 186 |
-
):
|
| 187 |
-
m.round_trip_view_tensor(temp)
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
@pytest.mark.parametrize("m", submodules)
|
| 191 |
-
def test_references_actually_refer(m):
|
| 192 |
-
a = m.reference_tensor()
|
| 193 |
-
temp = a[indices]
|
| 194 |
-
a[indices] = 100
|
| 195 |
-
assert_equal_tensor_ref(m.copy_const_tensor(), modified=100)
|
| 196 |
-
a[indices] = temp
|
| 197 |
-
assert_equal_tensor_ref(m.copy_const_tensor())
|
| 198 |
-
|
| 199 |
-
a = m.reference_view_of_tensor()
|
| 200 |
-
a[indices] = 100
|
| 201 |
-
assert_equal_tensor_ref(m.copy_const_tensor(), modified=100)
|
| 202 |
-
a[indices] = temp
|
| 203 |
-
assert_equal_tensor_ref(m.copy_const_tensor())
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
@pytest.mark.parametrize("m", submodules)
|
| 207 |
-
def test_round_trip(m):
|
| 208 |
-
assert_equal_tensor_ref(m.round_trip_tensor(tensor_ref))
|
| 209 |
-
|
| 210 |
-
with pytest.raises(TypeError, match="^Cannot cast array data from"):
|
| 211 |
-
assert_equal_tensor_ref(m.round_trip_tensor2(tensor_ref))
|
| 212 |
-
|
| 213 |
-
assert_equal_tensor_ref(m.round_trip_tensor2(np.array(tensor_ref, dtype=np.int32)))
|
| 214 |
-
assert_equal_tensor_ref(m.round_trip_fixed_tensor(tensor_ref))
|
| 215 |
-
assert_equal_tensor_ref(m.round_trip_aligned_view_tensor(m.reference_tensor()))
|
| 216 |
-
|
| 217 |
-
copy = np.array(tensor_ref, dtype=np.float64, order=m.needed_options)
|
| 218 |
-
assert_equal_tensor_ref(m.round_trip_view_tensor(copy))
|
| 219 |
-
assert_equal_tensor_ref(m.round_trip_view_tensor_ref(copy))
|
| 220 |
-
assert_equal_tensor_ref(m.round_trip_view_tensor_ptr(copy))
|
| 221 |
-
copy.setflags(write=False)
|
| 222 |
-
assert_equal_tensor_ref(m.round_trip_const_view_tensor(copy))
|
| 223 |
-
|
| 224 |
-
np.testing.assert_array_equal(
|
| 225 |
-
tensor_ref[:, ::-1, :], m.round_trip_tensor(tensor_ref[:, ::-1, :])
|
| 226 |
-
)
|
| 227 |
-
|
| 228 |
-
assert m.round_trip_rank_0(np.float64(3.5)) == 3.5
|
| 229 |
-
assert m.round_trip_rank_0(3.5) == 3.5
|
| 230 |
-
|
| 231 |
-
with pytest.raises(
|
| 232 |
-
TypeError,
|
| 233 |
-
match=r"^round_trip_rank_0_noconvert\(\): incompatible function arguments",
|
| 234 |
-
):
|
| 235 |
-
m.round_trip_rank_0_noconvert(np.float64(3.5))
|
| 236 |
-
|
| 237 |
-
with pytest.raises(
|
| 238 |
-
TypeError,
|
| 239 |
-
match=r"^round_trip_rank_0_noconvert\(\): incompatible function arguments",
|
| 240 |
-
):
|
| 241 |
-
m.round_trip_rank_0_noconvert(3.5)
|
| 242 |
-
|
| 243 |
-
with pytest.raises(
|
| 244 |
-
TypeError, match=r"^round_trip_rank_0_view\(\): incompatible function arguments"
|
| 245 |
-
):
|
| 246 |
-
m.round_trip_rank_0_view(np.float64(3.5))
|
| 247 |
-
|
| 248 |
-
with pytest.raises(
|
| 249 |
-
TypeError, match=r"^round_trip_rank_0_view\(\): incompatible function arguments"
|
| 250 |
-
):
|
| 251 |
-
m.round_trip_rank_0_view(3.5)
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
@pytest.mark.parametrize("m", submodules)
|
| 255 |
-
def test_round_trip_references_actually_refer(m):
|
| 256 |
-
# Need to create a copy that matches the type on the C side
|
| 257 |
-
copy = np.array(tensor_ref, dtype=np.float64, order=m.needed_options)
|
| 258 |
-
a = m.round_trip_view_tensor(copy)
|
| 259 |
-
temp = a[indices]
|
| 260 |
-
a[indices] = 100
|
| 261 |
-
assert_equal_tensor_ref(copy, modified=100)
|
| 262 |
-
a[indices] = temp
|
| 263 |
-
assert_equal_tensor_ref(copy)
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
@pytest.mark.parametrize("m", submodules)
|
| 267 |
-
def test_doc_string(m, doc):
|
| 268 |
-
assert (
|
| 269 |
-
doc(m.copy_tensor) == "copy_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]"
|
| 270 |
-
)
|
| 271 |
-
assert (
|
| 272 |
-
doc(m.copy_fixed_tensor)
|
| 273 |
-
== "copy_fixed_tensor() -> numpy.ndarray[numpy.float64[3, 5, 2]]"
|
| 274 |
-
)
|
| 275 |
-
assert (
|
| 276 |
-
doc(m.reference_const_tensor)
|
| 277 |
-
== "reference_const_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]"
|
| 278 |
-
)
|
| 279 |
-
|
| 280 |
-
order_flag = f"flags.{m.needed_options.lower()}_contiguous"
|
| 281 |
-
assert doc(m.round_trip_view_tensor) == (
|
| 282 |
-
f"round_trip_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}])"
|
| 283 |
-
f" -> numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}]"
|
| 284 |
-
)
|
| 285 |
-
assert doc(m.round_trip_const_view_tensor) == (
|
| 286 |
-
f"round_trip_const_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], {order_flag}])"
|
| 287 |
-
" -> numpy.ndarray[numpy.float64[?, ?, ?]]"
|
| 288 |
-
)
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
np = pytest.importorskip("numpy")
|
| 6 |
+
eigen_tensor = pytest.importorskip("pybind11_tests.eigen_tensor")
|
| 7 |
+
submodules = [eigen_tensor.c_style, eigen_tensor.f_style]
|
| 8 |
+
try:
|
| 9 |
+
import eigen_tensor_avoid_stl_array as avoid
|
| 10 |
+
|
| 11 |
+
submodules += [avoid.c_style, avoid.f_style]
|
| 12 |
+
except ImportError as e:
|
| 13 |
+
# Ensure config, build, toolchain, etc. issues are not masked here:
|
| 14 |
+
msg = (
|
| 15 |
+
"import eigen_tensor_avoid_stl_array FAILED, while "
|
| 16 |
+
"import pybind11_tests.eigen_tensor succeeded. "
|
| 17 |
+
"Please ensure that "
|
| 18 |
+
"test_eigen_tensor.cpp & "
|
| 19 |
+
"eigen_tensor_avoid_stl_array.cpp "
|
| 20 |
+
"are built together (or both are not built if Eigen is not available)."
|
| 21 |
+
)
|
| 22 |
+
raise RuntimeError(msg) from e
|
| 23 |
+
|
| 24 |
+
tensor_ref = np.empty((3, 5, 2), dtype=np.int64)
|
| 25 |
+
|
| 26 |
+
for i in range(tensor_ref.shape[0]):
|
| 27 |
+
for j in range(tensor_ref.shape[1]):
|
| 28 |
+
for k in range(tensor_ref.shape[2]):
|
| 29 |
+
tensor_ref[i, j, k] = i * (5 * 2) + j * 2 + k
|
| 30 |
+
|
| 31 |
+
indices = (2, 3, 1)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
@pytest.fixture(autouse=True)
|
| 35 |
+
def cleanup():
|
| 36 |
+
for module in submodules:
|
| 37 |
+
module.setup()
|
| 38 |
+
|
| 39 |
+
yield
|
| 40 |
+
|
| 41 |
+
for module in submodules:
|
| 42 |
+
assert module.is_ok()
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def test_import_avoid_stl_array():
|
| 46 |
+
pytest.importorskip("eigen_tensor_avoid_stl_array")
|
| 47 |
+
assert len(submodules) == 4
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def assert_equal_tensor_ref(mat, writeable=True, modified=None):
|
| 51 |
+
assert mat.flags.writeable == writeable
|
| 52 |
+
|
| 53 |
+
copy = np.array(tensor_ref)
|
| 54 |
+
if modified is not None:
|
| 55 |
+
copy[indices] = modified
|
| 56 |
+
|
| 57 |
+
np.testing.assert_array_equal(mat, copy)
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
@pytest.mark.parametrize("m", submodules)
|
| 61 |
+
@pytest.mark.parametrize("member_name", ["member", "member_view"])
|
| 62 |
+
def test_reference_internal(m, member_name):
|
| 63 |
+
if not hasattr(sys, "getrefcount"):
|
| 64 |
+
pytest.skip("No reference counting")
|
| 65 |
+
foo = m.CustomExample()
|
| 66 |
+
counts = sys.getrefcount(foo)
|
| 67 |
+
mem = getattr(foo, member_name)
|
| 68 |
+
assert_equal_tensor_ref(mem, writeable=False)
|
| 69 |
+
new_counts = sys.getrefcount(foo)
|
| 70 |
+
assert new_counts == counts + 1
|
| 71 |
+
assert_equal_tensor_ref(mem, writeable=False)
|
| 72 |
+
del mem
|
| 73 |
+
assert sys.getrefcount(foo) == counts
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
assert_equal_funcs = [
|
| 77 |
+
"copy_tensor",
|
| 78 |
+
"copy_fixed_tensor",
|
| 79 |
+
"copy_const_tensor",
|
| 80 |
+
"move_tensor_copy",
|
| 81 |
+
"move_fixed_tensor_copy",
|
| 82 |
+
"take_tensor",
|
| 83 |
+
"take_fixed_tensor",
|
| 84 |
+
"reference_tensor",
|
| 85 |
+
"reference_tensor_v2",
|
| 86 |
+
"reference_fixed_tensor",
|
| 87 |
+
"reference_view_of_tensor",
|
| 88 |
+
"reference_view_of_tensor_v3",
|
| 89 |
+
"reference_view_of_tensor_v5",
|
| 90 |
+
"reference_view_of_fixed_tensor",
|
| 91 |
+
]
|
| 92 |
+
|
| 93 |
+
assert_equal_const_funcs = [
|
| 94 |
+
"reference_view_of_tensor_v2",
|
| 95 |
+
"reference_view_of_tensor_v4",
|
| 96 |
+
"reference_view_of_tensor_v6",
|
| 97 |
+
"reference_const_tensor",
|
| 98 |
+
"reference_const_tensor_v2",
|
| 99 |
+
]
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
@pytest.mark.parametrize("m", submodules)
|
| 103 |
+
@pytest.mark.parametrize("func_name", assert_equal_funcs + assert_equal_const_funcs)
|
| 104 |
+
def test_convert_tensor_to_py(m, func_name):
|
| 105 |
+
writeable = func_name in assert_equal_funcs
|
| 106 |
+
assert_equal_tensor_ref(getattr(m, func_name)(), writeable=writeable)
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
@pytest.mark.parametrize("m", submodules)
|
| 110 |
+
def test_bad_cpp_to_python_casts(m):
|
| 111 |
+
with pytest.raises(
|
| 112 |
+
RuntimeError, match="Cannot use reference internal when there is no parent"
|
| 113 |
+
):
|
| 114 |
+
m.reference_tensor_internal()
|
| 115 |
+
|
| 116 |
+
with pytest.raises(RuntimeError, match="Cannot move from a constant reference"):
|
| 117 |
+
m.move_const_tensor()
|
| 118 |
+
|
| 119 |
+
with pytest.raises(
|
| 120 |
+
RuntimeError, match="Cannot take ownership of a const reference"
|
| 121 |
+
):
|
| 122 |
+
m.take_const_tensor()
|
| 123 |
+
|
| 124 |
+
with pytest.raises(
|
| 125 |
+
RuntimeError,
|
| 126 |
+
match="Invalid return_value_policy for Eigen Map type, must be either reference or reference_internal",
|
| 127 |
+
):
|
| 128 |
+
m.take_view_tensor()
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
@pytest.mark.parametrize("m", submodules)
|
| 132 |
+
def test_bad_python_to_cpp_casts(m):
|
| 133 |
+
with pytest.raises(
|
| 134 |
+
TypeError, match=r"^round_trip_tensor\(\): incompatible function arguments"
|
| 135 |
+
):
|
| 136 |
+
m.round_trip_tensor(np.zeros((2, 3)))
|
| 137 |
+
|
| 138 |
+
with pytest.raises(TypeError, match=r"^Cannot cast array data from dtype"):
|
| 139 |
+
m.round_trip_tensor(np.zeros(dtype=np.str_, shape=(2, 3, 1)))
|
| 140 |
+
|
| 141 |
+
with pytest.raises(
|
| 142 |
+
TypeError,
|
| 143 |
+
match=r"^round_trip_tensor_noconvert\(\): incompatible function arguments",
|
| 144 |
+
):
|
| 145 |
+
m.round_trip_tensor_noconvert(tensor_ref)
|
| 146 |
+
|
| 147 |
+
assert_equal_tensor_ref(
|
| 148 |
+
m.round_trip_tensor_noconvert(tensor_ref.astype(np.float64))
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
bad_options = "C" if m.needed_options == "F" else "F"
|
| 152 |
+
# Shape, dtype and the order need to be correct for a TensorMap cast
|
| 153 |
+
with pytest.raises(
|
| 154 |
+
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
|
| 155 |
+
):
|
| 156 |
+
m.round_trip_view_tensor(
|
| 157 |
+
np.zeros((3, 5, 2), dtype=np.float64, order=bad_options)
|
| 158 |
+
)
|
| 159 |
+
|
| 160 |
+
with pytest.raises(
|
| 161 |
+
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
|
| 162 |
+
):
|
| 163 |
+
m.round_trip_view_tensor(
|
| 164 |
+
np.zeros((3, 5, 2), dtype=np.float32, order=m.needed_options)
|
| 165 |
+
)
|
| 166 |
+
|
| 167 |
+
with pytest.raises(
|
| 168 |
+
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
|
| 169 |
+
):
|
| 170 |
+
m.round_trip_view_tensor(
|
| 171 |
+
np.zeros((3, 5), dtype=np.float64, order=m.needed_options)
|
| 172 |
+
)
|
| 173 |
+
|
| 174 |
+
temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options)
|
| 175 |
+
with pytest.raises(
|
| 176 |
+
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
|
| 177 |
+
):
|
| 178 |
+
m.round_trip_view_tensor(
|
| 179 |
+
temp[:, ::-1, :],
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options)
|
| 183 |
+
temp.setflags(write=False)
|
| 184 |
+
with pytest.raises(
|
| 185 |
+
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
|
| 186 |
+
):
|
| 187 |
+
m.round_trip_view_tensor(temp)
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
@pytest.mark.parametrize("m", submodules)
|
| 191 |
+
def test_references_actually_refer(m):
|
| 192 |
+
a = m.reference_tensor()
|
| 193 |
+
temp = a[indices]
|
| 194 |
+
a[indices] = 100
|
| 195 |
+
assert_equal_tensor_ref(m.copy_const_tensor(), modified=100)
|
| 196 |
+
a[indices] = temp
|
| 197 |
+
assert_equal_tensor_ref(m.copy_const_tensor())
|
| 198 |
+
|
| 199 |
+
a = m.reference_view_of_tensor()
|
| 200 |
+
a[indices] = 100
|
| 201 |
+
assert_equal_tensor_ref(m.copy_const_tensor(), modified=100)
|
| 202 |
+
a[indices] = temp
|
| 203 |
+
assert_equal_tensor_ref(m.copy_const_tensor())
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
@pytest.mark.parametrize("m", submodules)
|
| 207 |
+
def test_round_trip(m):
|
| 208 |
+
assert_equal_tensor_ref(m.round_trip_tensor(tensor_ref))
|
| 209 |
+
|
| 210 |
+
with pytest.raises(TypeError, match="^Cannot cast array data from"):
|
| 211 |
+
assert_equal_tensor_ref(m.round_trip_tensor2(tensor_ref))
|
| 212 |
+
|
| 213 |
+
assert_equal_tensor_ref(m.round_trip_tensor2(np.array(tensor_ref, dtype=np.int32)))
|
| 214 |
+
assert_equal_tensor_ref(m.round_trip_fixed_tensor(tensor_ref))
|
| 215 |
+
assert_equal_tensor_ref(m.round_trip_aligned_view_tensor(m.reference_tensor()))
|
| 216 |
+
|
| 217 |
+
copy = np.array(tensor_ref, dtype=np.float64, order=m.needed_options)
|
| 218 |
+
assert_equal_tensor_ref(m.round_trip_view_tensor(copy))
|
| 219 |
+
assert_equal_tensor_ref(m.round_trip_view_tensor_ref(copy))
|
| 220 |
+
assert_equal_tensor_ref(m.round_trip_view_tensor_ptr(copy))
|
| 221 |
+
copy.setflags(write=False)
|
| 222 |
+
assert_equal_tensor_ref(m.round_trip_const_view_tensor(copy))
|
| 223 |
+
|
| 224 |
+
np.testing.assert_array_equal(
|
| 225 |
+
tensor_ref[:, ::-1, :], m.round_trip_tensor(tensor_ref[:, ::-1, :])
|
| 226 |
+
)
|
| 227 |
+
|
| 228 |
+
assert m.round_trip_rank_0(np.float64(3.5)) == 3.5
|
| 229 |
+
assert m.round_trip_rank_0(3.5) == 3.5
|
| 230 |
+
|
| 231 |
+
with pytest.raises(
|
| 232 |
+
TypeError,
|
| 233 |
+
match=r"^round_trip_rank_0_noconvert\(\): incompatible function arguments",
|
| 234 |
+
):
|
| 235 |
+
m.round_trip_rank_0_noconvert(np.float64(3.5))
|
| 236 |
+
|
| 237 |
+
with pytest.raises(
|
| 238 |
+
TypeError,
|
| 239 |
+
match=r"^round_trip_rank_0_noconvert\(\): incompatible function arguments",
|
| 240 |
+
):
|
| 241 |
+
m.round_trip_rank_0_noconvert(3.5)
|
| 242 |
+
|
| 243 |
+
with pytest.raises(
|
| 244 |
+
TypeError, match=r"^round_trip_rank_0_view\(\): incompatible function arguments"
|
| 245 |
+
):
|
| 246 |
+
m.round_trip_rank_0_view(np.float64(3.5))
|
| 247 |
+
|
| 248 |
+
with pytest.raises(
|
| 249 |
+
TypeError, match=r"^round_trip_rank_0_view\(\): incompatible function arguments"
|
| 250 |
+
):
|
| 251 |
+
m.round_trip_rank_0_view(3.5)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
@pytest.mark.parametrize("m", submodules)
|
| 255 |
+
def test_round_trip_references_actually_refer(m):
|
| 256 |
+
# Need to create a copy that matches the type on the C side
|
| 257 |
+
copy = np.array(tensor_ref, dtype=np.float64, order=m.needed_options)
|
| 258 |
+
a = m.round_trip_view_tensor(copy)
|
| 259 |
+
temp = a[indices]
|
| 260 |
+
a[indices] = 100
|
| 261 |
+
assert_equal_tensor_ref(copy, modified=100)
|
| 262 |
+
a[indices] = temp
|
| 263 |
+
assert_equal_tensor_ref(copy)
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
@pytest.mark.parametrize("m", submodules)
|
| 267 |
+
def test_doc_string(m, doc):
|
| 268 |
+
assert (
|
| 269 |
+
doc(m.copy_tensor) == "copy_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]"
|
| 270 |
+
)
|
| 271 |
+
assert (
|
| 272 |
+
doc(m.copy_fixed_tensor)
|
| 273 |
+
== "copy_fixed_tensor() -> numpy.ndarray[numpy.float64[3, 5, 2]]"
|
| 274 |
+
)
|
| 275 |
+
assert (
|
| 276 |
+
doc(m.reference_const_tensor)
|
| 277 |
+
== "reference_const_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]"
|
| 278 |
+
)
|
| 279 |
+
|
| 280 |
+
order_flag = f"flags.{m.needed_options.lower()}_contiguous"
|
| 281 |
+
assert doc(m.round_trip_view_tensor) == (
|
| 282 |
+
f"round_trip_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}])"
|
| 283 |
+
f" -> numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}]"
|
| 284 |
+
)
|
| 285 |
+
assert doc(m.round_trip_const_view_tensor) == (
|
| 286 |
+
f"round_trip_const_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], {order_flag}])"
|
| 287 |
+
" -> numpy.ndarray[numpy.float64[?, ?, ?]]"
|
| 288 |
+
)
|
third_party/CityFlow/extern/pybind11/tests/test_enum.cpp
CHANGED
|
@@ -1,133 +1,133 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_enums.cpp -- enumerations
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#include "pybind11_tests.h"
|
| 11 |
-
|
| 12 |
-
TEST_SUBMODULE(enums, m) {
|
| 13 |
-
// test_unscoped_enum
|
| 14 |
-
enum UnscopedEnum { EOne = 1, ETwo, EThree };
|
| 15 |
-
py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration")
|
| 16 |
-
.value("EOne", EOne, "Docstring for EOne")
|
| 17 |
-
.value("ETwo", ETwo, "Docstring for ETwo")
|
| 18 |
-
.value("EThree", EThree, "Docstring for EThree")
|
| 19 |
-
.export_values();
|
| 20 |
-
|
| 21 |
-
// test_scoped_enum
|
| 22 |
-
enum class ScopedEnum { Two = 2, Three };
|
| 23 |
-
py::enum_<ScopedEnum>(m, "ScopedEnum", py::arithmetic())
|
| 24 |
-
.value("Two", ScopedEnum::Two)
|
| 25 |
-
.value("Three", ScopedEnum::Three);
|
| 26 |
-
|
| 27 |
-
m.def("test_scoped_enum", [](ScopedEnum z) {
|
| 28 |
-
return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three");
|
| 29 |
-
});
|
| 30 |
-
|
| 31 |
-
// test_binary_operators
|
| 32 |
-
enum Flags { Read = 4, Write = 2, Execute = 1 };
|
| 33 |
-
py::enum_<Flags>(m, "Flags", py::arithmetic())
|
| 34 |
-
.value("Read", Flags::Read)
|
| 35 |
-
.value("Write", Flags::Write)
|
| 36 |
-
.value("Execute", Flags::Execute)
|
| 37 |
-
.export_values();
|
| 38 |
-
|
| 39 |
-
// test_implicit_conversion
|
| 40 |
-
class ClassWithUnscopedEnum {
|
| 41 |
-
public:
|
| 42 |
-
enum EMode { EFirstMode = 1, ESecondMode };
|
| 43 |
-
|
| 44 |
-
static EMode test_function(EMode mode) { return mode; }
|
| 45 |
-
};
|
| 46 |
-
py::class_<ClassWithUnscopedEnum> exenum_class(m, "ClassWithUnscopedEnum");
|
| 47 |
-
exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function);
|
| 48 |
-
py::enum_<ClassWithUnscopedEnum::EMode>(exenum_class, "EMode")
|
| 49 |
-
.value("EFirstMode", ClassWithUnscopedEnum::EFirstMode)
|
| 50 |
-
.value("ESecondMode", ClassWithUnscopedEnum::ESecondMode)
|
| 51 |
-
.export_values();
|
| 52 |
-
|
| 53 |
-
// test_enum_to_int
|
| 54 |
-
m.def("test_enum_to_int", [](int) {});
|
| 55 |
-
m.def("test_enum_to_uint", [](uint32_t) {});
|
| 56 |
-
m.def("test_enum_to_long_long", [](long long) {});
|
| 57 |
-
|
| 58 |
-
// test_duplicate_enum_name
|
| 59 |
-
enum SimpleEnum { ONE, TWO, THREE };
|
| 60 |
-
|
| 61 |
-
m.def("register_bad_enum", [m]() {
|
| 62 |
-
py::enum_<SimpleEnum>(m, "SimpleEnum")
|
| 63 |
-
.value("ONE", SimpleEnum::ONE) // NOTE: all value function calls are called with the
|
| 64 |
-
// same first parameter value
|
| 65 |
-
.value("ONE", SimpleEnum::TWO)
|
| 66 |
-
.value("ONE", SimpleEnum::THREE)
|
| 67 |
-
.export_values();
|
| 68 |
-
});
|
| 69 |
-
|
| 70 |
-
// test_enum_scalar
|
| 71 |
-
enum UnscopedUCharEnum : unsigned char {};
|
| 72 |
-
enum class ScopedShortEnum : short {};
|
| 73 |
-
enum class ScopedLongEnum : long {};
|
| 74 |
-
enum UnscopedUInt64Enum : std::uint64_t {};
|
| 75 |
-
static_assert(
|
| 76 |
-
py::detail::all_of<
|
| 77 |
-
std::is_same<py::enum_<UnscopedUCharEnum>::Scalar, unsigned char>,
|
| 78 |
-
std::is_same<py::enum_<ScopedShortEnum>::Scalar, short>,
|
| 79 |
-
std::is_same<py::enum_<ScopedLongEnum>::Scalar, long>,
|
| 80 |
-
std::is_same<py::enum_<UnscopedUInt64Enum>::Scalar, std::uint64_t>>::value,
|
| 81 |
-
"Error during the deduction of enum's scalar type with normal integer underlying");
|
| 82 |
-
|
| 83 |
-
// test_enum_scalar_with_char_underlying
|
| 84 |
-
enum class ScopedCharEnum : char { Zero, Positive };
|
| 85 |
-
enum class ScopedWCharEnum : wchar_t { Zero, Positive };
|
| 86 |
-
enum class ScopedChar32Enum : char32_t { Zero, Positive };
|
| 87 |
-
enum class ScopedChar16Enum : char16_t { Zero, Positive };
|
| 88 |
-
|
| 89 |
-
// test the scalar of char type enums according to chapter 'Character types'
|
| 90 |
-
// from https://en.cppreference.com/w/cpp/language/types
|
| 91 |
-
static_assert(
|
| 92 |
-
py::detail::any_of<
|
| 93 |
-
std::is_same<py::enum_<ScopedCharEnum>::Scalar, signed char>, // e.g. gcc on x86
|
| 94 |
-
std::is_same<py::enum_<ScopedCharEnum>::Scalar, unsigned char> // e.g. arm linux
|
| 95 |
-
>::value,
|
| 96 |
-
"char should be cast to either signed char or unsigned char");
|
| 97 |
-
static_assert(sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 2
|
| 98 |
-
|| sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 4,
|
| 99 |
-
"wchar_t should be either 16 bits (Windows) or 32 (everywhere else)");
|
| 100 |
-
static_assert(
|
| 101 |
-
py::detail::all_of<
|
| 102 |
-
std::is_same<py::enum_<ScopedChar32Enum>::Scalar, std::uint_least32_t>,
|
| 103 |
-
std::is_same<py::enum_<ScopedChar16Enum>::Scalar, std::uint_least16_t>>::value,
|
| 104 |
-
"char32_t, char16_t (and char8_t)'s size, signedness, and alignment is determined");
|
| 105 |
-
#if defined(PYBIND11_HAS_U8STRING)
|
| 106 |
-
enum class ScopedChar8Enum : char8_t { Zero, Positive };
|
| 107 |
-
static_assert(std::is_same<py::enum_<ScopedChar8Enum>::Scalar, unsigned char>::value);
|
| 108 |
-
#endif
|
| 109 |
-
|
| 110 |
-
// test_char_underlying_enum
|
| 111 |
-
py::enum_<ScopedCharEnum>(m, "ScopedCharEnum")
|
| 112 |
-
.value("Zero", ScopedCharEnum::Zero)
|
| 113 |
-
.value("Positive", ScopedCharEnum::Positive);
|
| 114 |
-
py::enum_<ScopedWCharEnum>(m, "ScopedWCharEnum")
|
| 115 |
-
.value("Zero", ScopedWCharEnum::Zero)
|
| 116 |
-
.value("Positive", ScopedWCharEnum::Positive);
|
| 117 |
-
py::enum_<ScopedChar32Enum>(m, "ScopedChar32Enum")
|
| 118 |
-
.value("Zero", ScopedChar32Enum::Zero)
|
| 119 |
-
.value("Positive", ScopedChar32Enum::Positive);
|
| 120 |
-
py::enum_<ScopedChar16Enum>(m, "ScopedChar16Enum")
|
| 121 |
-
.value("Zero", ScopedChar16Enum::Zero)
|
| 122 |
-
.value("Positive", ScopedChar16Enum::Positive);
|
| 123 |
-
|
| 124 |
-
// test_bool_underlying_enum
|
| 125 |
-
enum class ScopedBoolEnum : bool { FALSE, TRUE };
|
| 126 |
-
|
| 127 |
-
// bool is unsigned (std::is_signed returns false) and 1-byte long, so represented with u8
|
| 128 |
-
static_assert(std::is_same<py::enum_<ScopedBoolEnum>::Scalar, std::uint8_t>::value, "");
|
| 129 |
-
|
| 130 |
-
py::enum_<ScopedBoolEnum>(m, "ScopedBoolEnum")
|
| 131 |
-
.value("FALSE", ScopedBoolEnum::FALSE)
|
| 132 |
-
.value("TRUE", ScopedBoolEnum::TRUE);
|
| 133 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_enums.cpp -- enumerations
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#include "pybind11_tests.h"
|
| 11 |
+
|
| 12 |
+
TEST_SUBMODULE(enums, m) {
|
| 13 |
+
// test_unscoped_enum
|
| 14 |
+
enum UnscopedEnum { EOne = 1, ETwo, EThree };
|
| 15 |
+
py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration")
|
| 16 |
+
.value("EOne", EOne, "Docstring for EOne")
|
| 17 |
+
.value("ETwo", ETwo, "Docstring for ETwo")
|
| 18 |
+
.value("EThree", EThree, "Docstring for EThree")
|
| 19 |
+
.export_values();
|
| 20 |
+
|
| 21 |
+
// test_scoped_enum
|
| 22 |
+
enum class ScopedEnum { Two = 2, Three };
|
| 23 |
+
py::enum_<ScopedEnum>(m, "ScopedEnum", py::arithmetic())
|
| 24 |
+
.value("Two", ScopedEnum::Two)
|
| 25 |
+
.value("Three", ScopedEnum::Three);
|
| 26 |
+
|
| 27 |
+
m.def("test_scoped_enum", [](ScopedEnum z) {
|
| 28 |
+
return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three");
|
| 29 |
+
});
|
| 30 |
+
|
| 31 |
+
// test_binary_operators
|
| 32 |
+
enum Flags { Read = 4, Write = 2, Execute = 1 };
|
| 33 |
+
py::enum_<Flags>(m, "Flags", py::arithmetic())
|
| 34 |
+
.value("Read", Flags::Read)
|
| 35 |
+
.value("Write", Flags::Write)
|
| 36 |
+
.value("Execute", Flags::Execute)
|
| 37 |
+
.export_values();
|
| 38 |
+
|
| 39 |
+
// test_implicit_conversion
|
| 40 |
+
class ClassWithUnscopedEnum {
|
| 41 |
+
public:
|
| 42 |
+
enum EMode { EFirstMode = 1, ESecondMode };
|
| 43 |
+
|
| 44 |
+
static EMode test_function(EMode mode) { return mode; }
|
| 45 |
+
};
|
| 46 |
+
py::class_<ClassWithUnscopedEnum> exenum_class(m, "ClassWithUnscopedEnum");
|
| 47 |
+
exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function);
|
| 48 |
+
py::enum_<ClassWithUnscopedEnum::EMode>(exenum_class, "EMode")
|
| 49 |
+
.value("EFirstMode", ClassWithUnscopedEnum::EFirstMode)
|
| 50 |
+
.value("ESecondMode", ClassWithUnscopedEnum::ESecondMode)
|
| 51 |
+
.export_values();
|
| 52 |
+
|
| 53 |
+
// test_enum_to_int
|
| 54 |
+
m.def("test_enum_to_int", [](int) {});
|
| 55 |
+
m.def("test_enum_to_uint", [](uint32_t) {});
|
| 56 |
+
m.def("test_enum_to_long_long", [](long long) {});
|
| 57 |
+
|
| 58 |
+
// test_duplicate_enum_name
|
| 59 |
+
enum SimpleEnum { ONE, TWO, THREE };
|
| 60 |
+
|
| 61 |
+
m.def("register_bad_enum", [m]() {
|
| 62 |
+
py::enum_<SimpleEnum>(m, "SimpleEnum")
|
| 63 |
+
.value("ONE", SimpleEnum::ONE) // NOTE: all value function calls are called with the
|
| 64 |
+
// same first parameter value
|
| 65 |
+
.value("ONE", SimpleEnum::TWO)
|
| 66 |
+
.value("ONE", SimpleEnum::THREE)
|
| 67 |
+
.export_values();
|
| 68 |
+
});
|
| 69 |
+
|
| 70 |
+
// test_enum_scalar
|
| 71 |
+
enum UnscopedUCharEnum : unsigned char {};
|
| 72 |
+
enum class ScopedShortEnum : short {};
|
| 73 |
+
enum class ScopedLongEnum : long {};
|
| 74 |
+
enum UnscopedUInt64Enum : std::uint64_t {};
|
| 75 |
+
static_assert(
|
| 76 |
+
py::detail::all_of<
|
| 77 |
+
std::is_same<py::enum_<UnscopedUCharEnum>::Scalar, unsigned char>,
|
| 78 |
+
std::is_same<py::enum_<ScopedShortEnum>::Scalar, short>,
|
| 79 |
+
std::is_same<py::enum_<ScopedLongEnum>::Scalar, long>,
|
| 80 |
+
std::is_same<py::enum_<UnscopedUInt64Enum>::Scalar, std::uint64_t>>::value,
|
| 81 |
+
"Error during the deduction of enum's scalar type with normal integer underlying");
|
| 82 |
+
|
| 83 |
+
// test_enum_scalar_with_char_underlying
|
| 84 |
+
enum class ScopedCharEnum : char { Zero, Positive };
|
| 85 |
+
enum class ScopedWCharEnum : wchar_t { Zero, Positive };
|
| 86 |
+
enum class ScopedChar32Enum : char32_t { Zero, Positive };
|
| 87 |
+
enum class ScopedChar16Enum : char16_t { Zero, Positive };
|
| 88 |
+
|
| 89 |
+
// test the scalar of char type enums according to chapter 'Character types'
|
| 90 |
+
// from https://en.cppreference.com/w/cpp/language/types
|
| 91 |
+
static_assert(
|
| 92 |
+
py::detail::any_of<
|
| 93 |
+
std::is_same<py::enum_<ScopedCharEnum>::Scalar, signed char>, // e.g. gcc on x86
|
| 94 |
+
std::is_same<py::enum_<ScopedCharEnum>::Scalar, unsigned char> // e.g. arm linux
|
| 95 |
+
>::value,
|
| 96 |
+
"char should be cast to either signed char or unsigned char");
|
| 97 |
+
static_assert(sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 2
|
| 98 |
+
|| sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 4,
|
| 99 |
+
"wchar_t should be either 16 bits (Windows) or 32 (everywhere else)");
|
| 100 |
+
static_assert(
|
| 101 |
+
py::detail::all_of<
|
| 102 |
+
std::is_same<py::enum_<ScopedChar32Enum>::Scalar, std::uint_least32_t>,
|
| 103 |
+
std::is_same<py::enum_<ScopedChar16Enum>::Scalar, std::uint_least16_t>>::value,
|
| 104 |
+
"char32_t, char16_t (and char8_t)'s size, signedness, and alignment is determined");
|
| 105 |
+
#if defined(PYBIND11_HAS_U8STRING)
|
| 106 |
+
enum class ScopedChar8Enum : char8_t { Zero, Positive };
|
| 107 |
+
static_assert(std::is_same<py::enum_<ScopedChar8Enum>::Scalar, unsigned char>::value);
|
| 108 |
+
#endif
|
| 109 |
+
|
| 110 |
+
// test_char_underlying_enum
|
| 111 |
+
py::enum_<ScopedCharEnum>(m, "ScopedCharEnum")
|
| 112 |
+
.value("Zero", ScopedCharEnum::Zero)
|
| 113 |
+
.value("Positive", ScopedCharEnum::Positive);
|
| 114 |
+
py::enum_<ScopedWCharEnum>(m, "ScopedWCharEnum")
|
| 115 |
+
.value("Zero", ScopedWCharEnum::Zero)
|
| 116 |
+
.value("Positive", ScopedWCharEnum::Positive);
|
| 117 |
+
py::enum_<ScopedChar32Enum>(m, "ScopedChar32Enum")
|
| 118 |
+
.value("Zero", ScopedChar32Enum::Zero)
|
| 119 |
+
.value("Positive", ScopedChar32Enum::Positive);
|
| 120 |
+
py::enum_<ScopedChar16Enum>(m, "ScopedChar16Enum")
|
| 121 |
+
.value("Zero", ScopedChar16Enum::Zero)
|
| 122 |
+
.value("Positive", ScopedChar16Enum::Positive);
|
| 123 |
+
|
| 124 |
+
// test_bool_underlying_enum
|
| 125 |
+
enum class ScopedBoolEnum : bool { FALSE, TRUE };
|
| 126 |
+
|
| 127 |
+
// bool is unsigned (std::is_signed returns false) and 1-byte long, so represented with u8
|
| 128 |
+
static_assert(std::is_same<py::enum_<ScopedBoolEnum>::Scalar, std::uint8_t>::value, "");
|
| 129 |
+
|
| 130 |
+
py::enum_<ScopedBoolEnum>(m, "ScopedBoolEnum")
|
| 131 |
+
.value("FALSE", ScopedBoolEnum::FALSE)
|
| 132 |
+
.value("TRUE", ScopedBoolEnum::TRUE);
|
| 133 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_enum.py
CHANGED
|
@@ -1,269 +1,269 @@
|
|
| 1 |
-
# ruff: noqa: SIM201 SIM300 SIM202
|
| 2 |
-
|
| 3 |
-
import pytest
|
| 4 |
-
|
| 5 |
-
from pybind11_tests import enums as m
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
def test_unscoped_enum():
|
| 9 |
-
assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne"
|
| 10 |
-
assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
|
| 11 |
-
assert str(m.EOne) == "UnscopedEnum.EOne"
|
| 12 |
-
assert repr(m.UnscopedEnum.EOne) == "<UnscopedEnum.EOne: 1>"
|
| 13 |
-
assert repr(m.UnscopedEnum.ETwo) == "<UnscopedEnum.ETwo: 2>"
|
| 14 |
-
assert repr(m.EOne) == "<UnscopedEnum.EOne: 1>"
|
| 15 |
-
|
| 16 |
-
# name property
|
| 17 |
-
assert m.UnscopedEnum.EOne.name == "EOne"
|
| 18 |
-
assert m.UnscopedEnum.EOne.value == 1
|
| 19 |
-
assert m.UnscopedEnum.ETwo.name == "ETwo"
|
| 20 |
-
assert m.UnscopedEnum.ETwo.value == 2
|
| 21 |
-
assert m.EOne is m.UnscopedEnum.EOne
|
| 22 |
-
# name, value readonly
|
| 23 |
-
with pytest.raises(AttributeError):
|
| 24 |
-
m.UnscopedEnum.EOne.name = ""
|
| 25 |
-
with pytest.raises(AttributeError):
|
| 26 |
-
m.UnscopedEnum.EOne.value = 10
|
| 27 |
-
# name, value returns a copy
|
| 28 |
-
# TODO: Neither the name nor value tests actually check against aliasing.
|
| 29 |
-
# Use a mutable type that has reference semantics.
|
| 30 |
-
nonaliased_name = m.UnscopedEnum.EOne.name
|
| 31 |
-
nonaliased_name = "bar" # noqa: F841
|
| 32 |
-
assert m.UnscopedEnum.EOne.name == "EOne"
|
| 33 |
-
nonaliased_value = m.UnscopedEnum.EOne.value
|
| 34 |
-
nonaliased_value = 10 # noqa: F841
|
| 35 |
-
assert m.UnscopedEnum.EOne.value == 1
|
| 36 |
-
|
| 37 |
-
# __members__ property
|
| 38 |
-
assert m.UnscopedEnum.__members__ == {
|
| 39 |
-
"EOne": m.UnscopedEnum.EOne,
|
| 40 |
-
"ETwo": m.UnscopedEnum.ETwo,
|
| 41 |
-
"EThree": m.UnscopedEnum.EThree,
|
| 42 |
-
}
|
| 43 |
-
# __members__ readonly
|
| 44 |
-
with pytest.raises(AttributeError):
|
| 45 |
-
m.UnscopedEnum.__members__ = {}
|
| 46 |
-
# __members__ returns a copy
|
| 47 |
-
nonaliased_members = m.UnscopedEnum.__members__
|
| 48 |
-
nonaliased_members["bar"] = "baz"
|
| 49 |
-
assert m.UnscopedEnum.__members__ == {
|
| 50 |
-
"EOne": m.UnscopedEnum.EOne,
|
| 51 |
-
"ETwo": m.UnscopedEnum.ETwo,
|
| 52 |
-
"EThree": m.UnscopedEnum.EThree,
|
| 53 |
-
}
|
| 54 |
-
|
| 55 |
-
for docstring_line in """An unscoped enumeration
|
| 56 |
-
|
| 57 |
-
Members:
|
| 58 |
-
|
| 59 |
-
EOne : Docstring for EOne
|
| 60 |
-
|
| 61 |
-
ETwo : Docstring for ETwo
|
| 62 |
-
|
| 63 |
-
EThree : Docstring for EThree""".split("\n"):
|
| 64 |
-
assert docstring_line in m.UnscopedEnum.__doc__
|
| 65 |
-
|
| 66 |
-
# Unscoped enums will accept ==/!= int comparisons
|
| 67 |
-
y = m.UnscopedEnum.ETwo
|
| 68 |
-
assert y == 2
|
| 69 |
-
assert 2 == y
|
| 70 |
-
assert y != 3
|
| 71 |
-
assert 3 != y
|
| 72 |
-
# Compare with None
|
| 73 |
-
assert y != None # noqa: E711
|
| 74 |
-
assert not (y == None) # noqa: E711
|
| 75 |
-
# Compare with an object
|
| 76 |
-
assert y != object()
|
| 77 |
-
assert not (y == object())
|
| 78 |
-
# Compare with string
|
| 79 |
-
assert y != "2"
|
| 80 |
-
assert "2" != y
|
| 81 |
-
assert not ("2" == y)
|
| 82 |
-
assert not (y == "2")
|
| 83 |
-
|
| 84 |
-
with pytest.raises(TypeError):
|
| 85 |
-
y < object() # noqa: B015
|
| 86 |
-
|
| 87 |
-
with pytest.raises(TypeError):
|
| 88 |
-
y <= object() # noqa: B015
|
| 89 |
-
|
| 90 |
-
with pytest.raises(TypeError):
|
| 91 |
-
y > object() # noqa: B015
|
| 92 |
-
|
| 93 |
-
with pytest.raises(TypeError):
|
| 94 |
-
y >= object() # noqa: B015
|
| 95 |
-
|
| 96 |
-
with pytest.raises(TypeError):
|
| 97 |
-
y | object()
|
| 98 |
-
|
| 99 |
-
with pytest.raises(TypeError):
|
| 100 |
-
y & object()
|
| 101 |
-
|
| 102 |
-
with pytest.raises(TypeError):
|
| 103 |
-
y ^ object()
|
| 104 |
-
|
| 105 |
-
assert int(m.UnscopedEnum.ETwo) == 2
|
| 106 |
-
assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo"
|
| 107 |
-
|
| 108 |
-
# order
|
| 109 |
-
assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo
|
| 110 |
-
assert m.UnscopedEnum.EOne < 2
|
| 111 |
-
assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne
|
| 112 |
-
assert m.UnscopedEnum.ETwo > 1
|
| 113 |
-
assert m.UnscopedEnum.ETwo <= 2
|
| 114 |
-
assert m.UnscopedEnum.ETwo >= 2
|
| 115 |
-
assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo
|
| 116 |
-
assert m.UnscopedEnum.EOne <= 2
|
| 117 |
-
assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne
|
| 118 |
-
assert m.UnscopedEnum.ETwo >= 1
|
| 119 |
-
assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne)
|
| 120 |
-
assert not (2 < m.UnscopedEnum.EOne)
|
| 121 |
-
|
| 122 |
-
# arithmetic
|
| 123 |
-
assert m.UnscopedEnum.EOne & m.UnscopedEnum.EThree == m.UnscopedEnum.EOne
|
| 124 |
-
assert m.UnscopedEnum.EOne | m.UnscopedEnum.ETwo == m.UnscopedEnum.EThree
|
| 125 |
-
assert m.UnscopedEnum.EOne ^ m.UnscopedEnum.EThree == m.UnscopedEnum.ETwo
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
def test_scoped_enum():
|
| 129 |
-
assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three"
|
| 130 |
-
z = m.ScopedEnum.Two
|
| 131 |
-
assert m.test_scoped_enum(z) == "ScopedEnum::Two"
|
| 132 |
-
|
| 133 |
-
# Scoped enums will *NOT* accept ==/!= int comparisons (Will always return False)
|
| 134 |
-
assert not z == 3
|
| 135 |
-
assert not 3 == z
|
| 136 |
-
assert z != 3
|
| 137 |
-
assert 3 != z
|
| 138 |
-
# Compare with None
|
| 139 |
-
assert z != None # noqa: E711
|
| 140 |
-
assert not (z == None) # noqa: E711
|
| 141 |
-
# Compare with an object
|
| 142 |
-
assert z != object()
|
| 143 |
-
assert not (z == object())
|
| 144 |
-
# Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions)
|
| 145 |
-
with pytest.raises(TypeError):
|
| 146 |
-
z > 3 # noqa: B015
|
| 147 |
-
with pytest.raises(TypeError):
|
| 148 |
-
z < 3 # noqa: B015
|
| 149 |
-
with pytest.raises(TypeError):
|
| 150 |
-
z >= 3 # noqa: B015
|
| 151 |
-
with pytest.raises(TypeError):
|
| 152 |
-
z <= 3 # noqa: B015
|
| 153 |
-
|
| 154 |
-
# order
|
| 155 |
-
assert m.ScopedEnum.Two < m.ScopedEnum.Three
|
| 156 |
-
assert m.ScopedEnum.Three > m.ScopedEnum.Two
|
| 157 |
-
assert m.ScopedEnum.Two <= m.ScopedEnum.Three
|
| 158 |
-
assert m.ScopedEnum.Two <= m.ScopedEnum.Two
|
| 159 |
-
assert m.ScopedEnum.Two >= m.ScopedEnum.Two
|
| 160 |
-
assert m.ScopedEnum.Three >= m.ScopedEnum.Two
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
def test_implicit_conversion():
|
| 164 |
-
assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
|
| 165 |
-
assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
|
| 166 |
-
assert repr(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "<EMode.EFirstMode: 1>"
|
| 167 |
-
assert repr(m.ClassWithUnscopedEnum.EFirstMode) == "<EMode.EFirstMode: 1>"
|
| 168 |
-
|
| 169 |
-
f = m.ClassWithUnscopedEnum.test_function
|
| 170 |
-
first = m.ClassWithUnscopedEnum.EFirstMode
|
| 171 |
-
second = m.ClassWithUnscopedEnum.ESecondMode
|
| 172 |
-
|
| 173 |
-
assert f(first) == 1
|
| 174 |
-
|
| 175 |
-
assert f(first) == f(first)
|
| 176 |
-
assert not f(first) != f(first)
|
| 177 |
-
|
| 178 |
-
assert f(first) != f(second)
|
| 179 |
-
assert not f(first) == f(second)
|
| 180 |
-
|
| 181 |
-
assert f(first) == int(f(first))
|
| 182 |
-
assert not f(first) != int(f(first))
|
| 183 |
-
|
| 184 |
-
assert f(first) != int(f(second))
|
| 185 |
-
assert not f(first) == int(f(second))
|
| 186 |
-
|
| 187 |
-
# noinspection PyDictCreation
|
| 188 |
-
x = {f(first): 1, f(second): 2}
|
| 189 |
-
x[f(first)] = 3
|
| 190 |
-
x[f(second)] = 4
|
| 191 |
-
# Hashing test
|
| 192 |
-
assert repr(x) == "{<EMode.EFirstMode: 1>: 3, <EMode.ESecondMode: 2>: 4}"
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
def test_binary_operators():
|
| 196 |
-
assert int(m.Flags.Read) == 4
|
| 197 |
-
assert int(m.Flags.Write) == 2
|
| 198 |
-
assert int(m.Flags.Execute) == 1
|
| 199 |
-
assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7
|
| 200 |
-
assert int(m.Flags.Read | m.Flags.Write) == 6
|
| 201 |
-
assert int(m.Flags.Read | m.Flags.Execute) == 5
|
| 202 |
-
assert int(m.Flags.Write | m.Flags.Execute) == 3
|
| 203 |
-
assert int(m.Flags.Write | 1) == 3
|
| 204 |
-
assert ~m.Flags.Write == -3
|
| 205 |
-
|
| 206 |
-
state = m.Flags.Read | m.Flags.Write
|
| 207 |
-
assert (state & m.Flags.Read) != 0
|
| 208 |
-
assert (state & m.Flags.Write) != 0
|
| 209 |
-
assert (state & m.Flags.Execute) == 0
|
| 210 |
-
assert (state & 1) == 0
|
| 211 |
-
|
| 212 |
-
state2 = ~state
|
| 213 |
-
assert state2 == -7
|
| 214 |
-
assert int(state ^ state2) == -1
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
def test_enum_to_int():
|
| 218 |
-
m.test_enum_to_int(m.Flags.Read)
|
| 219 |
-
m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode)
|
| 220 |
-
m.test_enum_to_int(m.ScopedCharEnum.Positive)
|
| 221 |
-
m.test_enum_to_int(m.ScopedBoolEnum.TRUE)
|
| 222 |
-
m.test_enum_to_uint(m.Flags.Read)
|
| 223 |
-
m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode)
|
| 224 |
-
m.test_enum_to_uint(m.ScopedCharEnum.Positive)
|
| 225 |
-
m.test_enum_to_uint(m.ScopedBoolEnum.TRUE)
|
| 226 |
-
m.test_enum_to_long_long(m.Flags.Read)
|
| 227 |
-
m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode)
|
| 228 |
-
m.test_enum_to_long_long(m.ScopedCharEnum.Positive)
|
| 229 |
-
m.test_enum_to_long_long(m.ScopedBoolEnum.TRUE)
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
def test_duplicate_enum_name():
|
| 233 |
-
with pytest.raises(ValueError) as excinfo:
|
| 234 |
-
m.register_bad_enum()
|
| 235 |
-
assert str(excinfo.value) == 'SimpleEnum: element "ONE" already exists!'
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
def test_char_underlying_enum(): # Issue #1331/PR #1334:
|
| 239 |
-
assert type(m.ScopedCharEnum.Positive.__int__()) is int
|
| 240 |
-
assert int(m.ScopedChar16Enum.Zero) == 0
|
| 241 |
-
assert hash(m.ScopedChar32Enum.Positive) == 1
|
| 242 |
-
assert type(m.ScopedCharEnum.Positive.__getstate__()) is int
|
| 243 |
-
assert m.ScopedWCharEnum(1) == m.ScopedWCharEnum.Positive
|
| 244 |
-
with pytest.raises(TypeError):
|
| 245 |
-
# Even if the underlying type is char, only an int can be used to construct the enum:
|
| 246 |
-
m.ScopedCharEnum("0")
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
def test_bool_underlying_enum():
|
| 250 |
-
assert type(m.ScopedBoolEnum.TRUE.__int__()) is int
|
| 251 |
-
assert int(m.ScopedBoolEnum.FALSE) == 0
|
| 252 |
-
assert hash(m.ScopedBoolEnum.TRUE) == 1
|
| 253 |
-
assert type(m.ScopedBoolEnum.TRUE.__getstate__()) is int
|
| 254 |
-
assert m.ScopedBoolEnum(1) == m.ScopedBoolEnum.TRUE
|
| 255 |
-
# Enum could construct with a bool
|
| 256 |
-
# (bool is a strict subclass of int, and False will be converted to 0)
|
| 257 |
-
assert m.ScopedBoolEnum(False) == m.ScopedBoolEnum.FALSE
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
def test_docstring_signatures():
|
| 261 |
-
for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
|
| 262 |
-
for attr in enum_type.__dict__.values():
|
| 263 |
-
# Issue #2623/PR #2637: Add argument names to enum_ methods
|
| 264 |
-
assert "arg0" not in (attr.__doc__ or "")
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
def test_str_signature():
|
| 268 |
-
for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
|
| 269 |
-
assert enum_type.__str__.__doc__.startswith("__str__")
|
|
|
|
| 1 |
+
# ruff: noqa: SIM201 SIM300 SIM202
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from pybind11_tests import enums as m
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def test_unscoped_enum():
|
| 9 |
+
assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne"
|
| 10 |
+
assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
|
| 11 |
+
assert str(m.EOne) == "UnscopedEnum.EOne"
|
| 12 |
+
assert repr(m.UnscopedEnum.EOne) == "<UnscopedEnum.EOne: 1>"
|
| 13 |
+
assert repr(m.UnscopedEnum.ETwo) == "<UnscopedEnum.ETwo: 2>"
|
| 14 |
+
assert repr(m.EOne) == "<UnscopedEnum.EOne: 1>"
|
| 15 |
+
|
| 16 |
+
# name property
|
| 17 |
+
assert m.UnscopedEnum.EOne.name == "EOne"
|
| 18 |
+
assert m.UnscopedEnum.EOne.value == 1
|
| 19 |
+
assert m.UnscopedEnum.ETwo.name == "ETwo"
|
| 20 |
+
assert m.UnscopedEnum.ETwo.value == 2
|
| 21 |
+
assert m.EOne is m.UnscopedEnum.EOne
|
| 22 |
+
# name, value readonly
|
| 23 |
+
with pytest.raises(AttributeError):
|
| 24 |
+
m.UnscopedEnum.EOne.name = ""
|
| 25 |
+
with pytest.raises(AttributeError):
|
| 26 |
+
m.UnscopedEnum.EOne.value = 10
|
| 27 |
+
# name, value returns a copy
|
| 28 |
+
# TODO: Neither the name nor value tests actually check against aliasing.
|
| 29 |
+
# Use a mutable type that has reference semantics.
|
| 30 |
+
nonaliased_name = m.UnscopedEnum.EOne.name
|
| 31 |
+
nonaliased_name = "bar" # noqa: F841
|
| 32 |
+
assert m.UnscopedEnum.EOne.name == "EOne"
|
| 33 |
+
nonaliased_value = m.UnscopedEnum.EOne.value
|
| 34 |
+
nonaliased_value = 10 # noqa: F841
|
| 35 |
+
assert m.UnscopedEnum.EOne.value == 1
|
| 36 |
+
|
| 37 |
+
# __members__ property
|
| 38 |
+
assert m.UnscopedEnum.__members__ == {
|
| 39 |
+
"EOne": m.UnscopedEnum.EOne,
|
| 40 |
+
"ETwo": m.UnscopedEnum.ETwo,
|
| 41 |
+
"EThree": m.UnscopedEnum.EThree,
|
| 42 |
+
}
|
| 43 |
+
# __members__ readonly
|
| 44 |
+
with pytest.raises(AttributeError):
|
| 45 |
+
m.UnscopedEnum.__members__ = {}
|
| 46 |
+
# __members__ returns a copy
|
| 47 |
+
nonaliased_members = m.UnscopedEnum.__members__
|
| 48 |
+
nonaliased_members["bar"] = "baz"
|
| 49 |
+
assert m.UnscopedEnum.__members__ == {
|
| 50 |
+
"EOne": m.UnscopedEnum.EOne,
|
| 51 |
+
"ETwo": m.UnscopedEnum.ETwo,
|
| 52 |
+
"EThree": m.UnscopedEnum.EThree,
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
for docstring_line in """An unscoped enumeration
|
| 56 |
+
|
| 57 |
+
Members:
|
| 58 |
+
|
| 59 |
+
EOne : Docstring for EOne
|
| 60 |
+
|
| 61 |
+
ETwo : Docstring for ETwo
|
| 62 |
+
|
| 63 |
+
EThree : Docstring for EThree""".split("\n"):
|
| 64 |
+
assert docstring_line in m.UnscopedEnum.__doc__
|
| 65 |
+
|
| 66 |
+
# Unscoped enums will accept ==/!= int comparisons
|
| 67 |
+
y = m.UnscopedEnum.ETwo
|
| 68 |
+
assert y == 2
|
| 69 |
+
assert 2 == y
|
| 70 |
+
assert y != 3
|
| 71 |
+
assert 3 != y
|
| 72 |
+
# Compare with None
|
| 73 |
+
assert y != None # noqa: E711
|
| 74 |
+
assert not (y == None) # noqa: E711
|
| 75 |
+
# Compare with an object
|
| 76 |
+
assert y != object()
|
| 77 |
+
assert not (y == object())
|
| 78 |
+
# Compare with string
|
| 79 |
+
assert y != "2"
|
| 80 |
+
assert "2" != y
|
| 81 |
+
assert not ("2" == y)
|
| 82 |
+
assert not (y == "2")
|
| 83 |
+
|
| 84 |
+
with pytest.raises(TypeError):
|
| 85 |
+
y < object() # noqa: B015
|
| 86 |
+
|
| 87 |
+
with pytest.raises(TypeError):
|
| 88 |
+
y <= object() # noqa: B015
|
| 89 |
+
|
| 90 |
+
with pytest.raises(TypeError):
|
| 91 |
+
y > object() # noqa: B015
|
| 92 |
+
|
| 93 |
+
with pytest.raises(TypeError):
|
| 94 |
+
y >= object() # noqa: B015
|
| 95 |
+
|
| 96 |
+
with pytest.raises(TypeError):
|
| 97 |
+
y | object()
|
| 98 |
+
|
| 99 |
+
with pytest.raises(TypeError):
|
| 100 |
+
y & object()
|
| 101 |
+
|
| 102 |
+
with pytest.raises(TypeError):
|
| 103 |
+
y ^ object()
|
| 104 |
+
|
| 105 |
+
assert int(m.UnscopedEnum.ETwo) == 2
|
| 106 |
+
assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo"
|
| 107 |
+
|
| 108 |
+
# order
|
| 109 |
+
assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo
|
| 110 |
+
assert m.UnscopedEnum.EOne < 2
|
| 111 |
+
assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne
|
| 112 |
+
assert m.UnscopedEnum.ETwo > 1
|
| 113 |
+
assert m.UnscopedEnum.ETwo <= 2
|
| 114 |
+
assert m.UnscopedEnum.ETwo >= 2
|
| 115 |
+
assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo
|
| 116 |
+
assert m.UnscopedEnum.EOne <= 2
|
| 117 |
+
assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne
|
| 118 |
+
assert m.UnscopedEnum.ETwo >= 1
|
| 119 |
+
assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne)
|
| 120 |
+
assert not (2 < m.UnscopedEnum.EOne)
|
| 121 |
+
|
| 122 |
+
# arithmetic
|
| 123 |
+
assert m.UnscopedEnum.EOne & m.UnscopedEnum.EThree == m.UnscopedEnum.EOne
|
| 124 |
+
assert m.UnscopedEnum.EOne | m.UnscopedEnum.ETwo == m.UnscopedEnum.EThree
|
| 125 |
+
assert m.UnscopedEnum.EOne ^ m.UnscopedEnum.EThree == m.UnscopedEnum.ETwo
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
def test_scoped_enum():
|
| 129 |
+
assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three"
|
| 130 |
+
z = m.ScopedEnum.Two
|
| 131 |
+
assert m.test_scoped_enum(z) == "ScopedEnum::Two"
|
| 132 |
+
|
| 133 |
+
# Scoped enums will *NOT* accept ==/!= int comparisons (Will always return False)
|
| 134 |
+
assert not z == 3
|
| 135 |
+
assert not 3 == z
|
| 136 |
+
assert z != 3
|
| 137 |
+
assert 3 != z
|
| 138 |
+
# Compare with None
|
| 139 |
+
assert z != None # noqa: E711
|
| 140 |
+
assert not (z == None) # noqa: E711
|
| 141 |
+
# Compare with an object
|
| 142 |
+
assert z != object()
|
| 143 |
+
assert not (z == object())
|
| 144 |
+
# Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions)
|
| 145 |
+
with pytest.raises(TypeError):
|
| 146 |
+
z > 3 # noqa: B015
|
| 147 |
+
with pytest.raises(TypeError):
|
| 148 |
+
z < 3 # noqa: B015
|
| 149 |
+
with pytest.raises(TypeError):
|
| 150 |
+
z >= 3 # noqa: B015
|
| 151 |
+
with pytest.raises(TypeError):
|
| 152 |
+
z <= 3 # noqa: B015
|
| 153 |
+
|
| 154 |
+
# order
|
| 155 |
+
assert m.ScopedEnum.Two < m.ScopedEnum.Three
|
| 156 |
+
assert m.ScopedEnum.Three > m.ScopedEnum.Two
|
| 157 |
+
assert m.ScopedEnum.Two <= m.ScopedEnum.Three
|
| 158 |
+
assert m.ScopedEnum.Two <= m.ScopedEnum.Two
|
| 159 |
+
assert m.ScopedEnum.Two >= m.ScopedEnum.Two
|
| 160 |
+
assert m.ScopedEnum.Three >= m.ScopedEnum.Two
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
def test_implicit_conversion():
|
| 164 |
+
assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
|
| 165 |
+
assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
|
| 166 |
+
assert repr(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "<EMode.EFirstMode: 1>"
|
| 167 |
+
assert repr(m.ClassWithUnscopedEnum.EFirstMode) == "<EMode.EFirstMode: 1>"
|
| 168 |
+
|
| 169 |
+
f = m.ClassWithUnscopedEnum.test_function
|
| 170 |
+
first = m.ClassWithUnscopedEnum.EFirstMode
|
| 171 |
+
second = m.ClassWithUnscopedEnum.ESecondMode
|
| 172 |
+
|
| 173 |
+
assert f(first) == 1
|
| 174 |
+
|
| 175 |
+
assert f(first) == f(first)
|
| 176 |
+
assert not f(first) != f(first)
|
| 177 |
+
|
| 178 |
+
assert f(first) != f(second)
|
| 179 |
+
assert not f(first) == f(second)
|
| 180 |
+
|
| 181 |
+
assert f(first) == int(f(first))
|
| 182 |
+
assert not f(first) != int(f(first))
|
| 183 |
+
|
| 184 |
+
assert f(first) != int(f(second))
|
| 185 |
+
assert not f(first) == int(f(second))
|
| 186 |
+
|
| 187 |
+
# noinspection PyDictCreation
|
| 188 |
+
x = {f(first): 1, f(second): 2}
|
| 189 |
+
x[f(first)] = 3
|
| 190 |
+
x[f(second)] = 4
|
| 191 |
+
# Hashing test
|
| 192 |
+
assert repr(x) == "{<EMode.EFirstMode: 1>: 3, <EMode.ESecondMode: 2>: 4}"
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
def test_binary_operators():
|
| 196 |
+
assert int(m.Flags.Read) == 4
|
| 197 |
+
assert int(m.Flags.Write) == 2
|
| 198 |
+
assert int(m.Flags.Execute) == 1
|
| 199 |
+
assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7
|
| 200 |
+
assert int(m.Flags.Read | m.Flags.Write) == 6
|
| 201 |
+
assert int(m.Flags.Read | m.Flags.Execute) == 5
|
| 202 |
+
assert int(m.Flags.Write | m.Flags.Execute) == 3
|
| 203 |
+
assert int(m.Flags.Write | 1) == 3
|
| 204 |
+
assert ~m.Flags.Write == -3
|
| 205 |
+
|
| 206 |
+
state = m.Flags.Read | m.Flags.Write
|
| 207 |
+
assert (state & m.Flags.Read) != 0
|
| 208 |
+
assert (state & m.Flags.Write) != 0
|
| 209 |
+
assert (state & m.Flags.Execute) == 0
|
| 210 |
+
assert (state & 1) == 0
|
| 211 |
+
|
| 212 |
+
state2 = ~state
|
| 213 |
+
assert state2 == -7
|
| 214 |
+
assert int(state ^ state2) == -1
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
def test_enum_to_int():
|
| 218 |
+
m.test_enum_to_int(m.Flags.Read)
|
| 219 |
+
m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode)
|
| 220 |
+
m.test_enum_to_int(m.ScopedCharEnum.Positive)
|
| 221 |
+
m.test_enum_to_int(m.ScopedBoolEnum.TRUE)
|
| 222 |
+
m.test_enum_to_uint(m.Flags.Read)
|
| 223 |
+
m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode)
|
| 224 |
+
m.test_enum_to_uint(m.ScopedCharEnum.Positive)
|
| 225 |
+
m.test_enum_to_uint(m.ScopedBoolEnum.TRUE)
|
| 226 |
+
m.test_enum_to_long_long(m.Flags.Read)
|
| 227 |
+
m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode)
|
| 228 |
+
m.test_enum_to_long_long(m.ScopedCharEnum.Positive)
|
| 229 |
+
m.test_enum_to_long_long(m.ScopedBoolEnum.TRUE)
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
def test_duplicate_enum_name():
|
| 233 |
+
with pytest.raises(ValueError) as excinfo:
|
| 234 |
+
m.register_bad_enum()
|
| 235 |
+
assert str(excinfo.value) == 'SimpleEnum: element "ONE" already exists!'
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
def test_char_underlying_enum(): # Issue #1331/PR #1334:
|
| 239 |
+
assert type(m.ScopedCharEnum.Positive.__int__()) is int
|
| 240 |
+
assert int(m.ScopedChar16Enum.Zero) == 0
|
| 241 |
+
assert hash(m.ScopedChar32Enum.Positive) == 1
|
| 242 |
+
assert type(m.ScopedCharEnum.Positive.__getstate__()) is int
|
| 243 |
+
assert m.ScopedWCharEnum(1) == m.ScopedWCharEnum.Positive
|
| 244 |
+
with pytest.raises(TypeError):
|
| 245 |
+
# Even if the underlying type is char, only an int can be used to construct the enum:
|
| 246 |
+
m.ScopedCharEnum("0")
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
def test_bool_underlying_enum():
|
| 250 |
+
assert type(m.ScopedBoolEnum.TRUE.__int__()) is int
|
| 251 |
+
assert int(m.ScopedBoolEnum.FALSE) == 0
|
| 252 |
+
assert hash(m.ScopedBoolEnum.TRUE) == 1
|
| 253 |
+
assert type(m.ScopedBoolEnum.TRUE.__getstate__()) is int
|
| 254 |
+
assert m.ScopedBoolEnum(1) == m.ScopedBoolEnum.TRUE
|
| 255 |
+
# Enum could construct with a bool
|
| 256 |
+
# (bool is a strict subclass of int, and False will be converted to 0)
|
| 257 |
+
assert m.ScopedBoolEnum(False) == m.ScopedBoolEnum.FALSE
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
def test_docstring_signatures():
|
| 261 |
+
for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
|
| 262 |
+
for attr in enum_type.__dict__.values():
|
| 263 |
+
# Issue #2623/PR #2637: Add argument names to enum_ methods
|
| 264 |
+
assert "arg0" not in (attr.__doc__ or "")
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
def test_str_signature():
|
| 268 |
+
for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
|
| 269 |
+
assert enum_type.__str__.__doc__.startswith("__str__")
|
third_party/CityFlow/extern/pybind11/tests/test_eval.cpp
CHANGED
|
@@ -1,118 +1,118 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_eval.cpp -- Usage of eval() and eval_file()
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2016 Klemens D. Morgenstern
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#include <pybind11/eval.h>
|
| 11 |
-
|
| 12 |
-
#include "pybind11_tests.h"
|
| 13 |
-
|
| 14 |
-
#include <utility>
|
| 15 |
-
|
| 16 |
-
TEST_SUBMODULE(eval_, m) {
|
| 17 |
-
// test_evals
|
| 18 |
-
|
| 19 |
-
auto global = py::dict(py::module_::import("__main__").attr("__dict__"));
|
| 20 |
-
|
| 21 |
-
m.def("test_eval_statements", [global]() {
|
| 22 |
-
auto local = py::dict();
|
| 23 |
-
local["call_test"] = py::cpp_function([&]() -> int { return 42; });
|
| 24 |
-
|
| 25 |
-
// Regular string literal
|
| 26 |
-
py::exec("message = 'Hello World!'\n"
|
| 27 |
-
"x = call_test()",
|
| 28 |
-
global,
|
| 29 |
-
local);
|
| 30 |
-
|
| 31 |
-
// Multi-line raw string literal
|
| 32 |
-
py::exec(R"(
|
| 33 |
-
if x == 42:
|
| 34 |
-
print(message)
|
| 35 |
-
else:
|
| 36 |
-
raise RuntimeError
|
| 37 |
-
)",
|
| 38 |
-
global,
|
| 39 |
-
local);
|
| 40 |
-
auto x = local["x"].cast<int>();
|
| 41 |
-
|
| 42 |
-
return x == 42;
|
| 43 |
-
});
|
| 44 |
-
|
| 45 |
-
m.def("test_eval", [global]() {
|
| 46 |
-
auto local = py::dict();
|
| 47 |
-
local["x"] = py::int_(42);
|
| 48 |
-
auto x = py::eval("x", global, local);
|
| 49 |
-
return x.cast<int>() == 42;
|
| 50 |
-
});
|
| 51 |
-
|
| 52 |
-
m.def("test_eval_single_statement", []() {
|
| 53 |
-
auto local = py::dict();
|
| 54 |
-
local["call_test"] = py::cpp_function([&]() -> int { return 42; });
|
| 55 |
-
|
| 56 |
-
auto result = py::eval<py::eval_single_statement>("x = call_test()", py::dict(), local);
|
| 57 |
-
auto x = local["x"].cast<int>();
|
| 58 |
-
return result.is_none() && x == 42;
|
| 59 |
-
});
|
| 60 |
-
|
| 61 |
-
m.def("test_eval_file", [global](py::str filename) {
|
| 62 |
-
auto local = py::dict();
|
| 63 |
-
local["y"] = py::int_(43);
|
| 64 |
-
|
| 65 |
-
int val_out = 0;
|
| 66 |
-
local["call_test2"] = py::cpp_function([&](int value) { val_out = value; });
|
| 67 |
-
|
| 68 |
-
auto result = py::eval_file(std::move(filename), global, local);
|
| 69 |
-
return val_out == 43 && result.is_none();
|
| 70 |
-
});
|
| 71 |
-
|
| 72 |
-
m.def("test_eval_failure", []() {
|
| 73 |
-
try {
|
| 74 |
-
py::eval("nonsense code ...");
|
| 75 |
-
} catch (py::error_already_set &) {
|
| 76 |
-
return true;
|
| 77 |
-
}
|
| 78 |
-
return false;
|
| 79 |
-
});
|
| 80 |
-
|
| 81 |
-
m.def("test_eval_file_failure", []() {
|
| 82 |
-
try {
|
| 83 |
-
py::eval_file("non-existing file");
|
| 84 |
-
} catch (std::exception &) {
|
| 85 |
-
return true;
|
| 86 |
-
}
|
| 87 |
-
return false;
|
| 88 |
-
});
|
| 89 |
-
|
| 90 |
-
// test_eval_empty_globals
|
| 91 |
-
m.def("eval_empty_globals", [](py::object global) {
|
| 92 |
-
if (global.is_none()) {
|
| 93 |
-
global = py::dict();
|
| 94 |
-
}
|
| 95 |
-
auto int_class = py::eval("isinstance(42, int)", global);
|
| 96 |
-
return global;
|
| 97 |
-
});
|
| 98 |
-
|
| 99 |
-
// test_eval_closure
|
| 100 |
-
m.def("test_eval_closure", []() {
|
| 101 |
-
py::dict global;
|
| 102 |
-
global["closure_value"] = 42;
|
| 103 |
-
py::dict local;
|
| 104 |
-
local["closure_value"] = 0;
|
| 105 |
-
py::exec(R"(
|
| 106 |
-
local_value = closure_value
|
| 107 |
-
|
| 108 |
-
def func_global():
|
| 109 |
-
return closure_value
|
| 110 |
-
|
| 111 |
-
def func_local():
|
| 112 |
-
return local_value
|
| 113 |
-
)",
|
| 114 |
-
global,
|
| 115 |
-
local);
|
| 116 |
-
return std::make_pair(global, local);
|
| 117 |
-
});
|
| 118 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_eval.cpp -- Usage of eval() and eval_file()
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2016 Klemens D. Morgenstern
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#include <pybind11/eval.h>
|
| 11 |
+
|
| 12 |
+
#include "pybind11_tests.h"
|
| 13 |
+
|
| 14 |
+
#include <utility>
|
| 15 |
+
|
| 16 |
+
TEST_SUBMODULE(eval_, m) {
|
| 17 |
+
// test_evals
|
| 18 |
+
|
| 19 |
+
auto global = py::dict(py::module_::import("__main__").attr("__dict__"));
|
| 20 |
+
|
| 21 |
+
m.def("test_eval_statements", [global]() {
|
| 22 |
+
auto local = py::dict();
|
| 23 |
+
local["call_test"] = py::cpp_function([&]() -> int { return 42; });
|
| 24 |
+
|
| 25 |
+
// Regular string literal
|
| 26 |
+
py::exec("message = 'Hello World!'\n"
|
| 27 |
+
"x = call_test()",
|
| 28 |
+
global,
|
| 29 |
+
local);
|
| 30 |
+
|
| 31 |
+
// Multi-line raw string literal
|
| 32 |
+
py::exec(R"(
|
| 33 |
+
if x == 42:
|
| 34 |
+
print(message)
|
| 35 |
+
else:
|
| 36 |
+
raise RuntimeError
|
| 37 |
+
)",
|
| 38 |
+
global,
|
| 39 |
+
local);
|
| 40 |
+
auto x = local["x"].cast<int>();
|
| 41 |
+
|
| 42 |
+
return x == 42;
|
| 43 |
+
});
|
| 44 |
+
|
| 45 |
+
m.def("test_eval", [global]() {
|
| 46 |
+
auto local = py::dict();
|
| 47 |
+
local["x"] = py::int_(42);
|
| 48 |
+
auto x = py::eval("x", global, local);
|
| 49 |
+
return x.cast<int>() == 42;
|
| 50 |
+
});
|
| 51 |
+
|
| 52 |
+
m.def("test_eval_single_statement", []() {
|
| 53 |
+
auto local = py::dict();
|
| 54 |
+
local["call_test"] = py::cpp_function([&]() -> int { return 42; });
|
| 55 |
+
|
| 56 |
+
auto result = py::eval<py::eval_single_statement>("x = call_test()", py::dict(), local);
|
| 57 |
+
auto x = local["x"].cast<int>();
|
| 58 |
+
return result.is_none() && x == 42;
|
| 59 |
+
});
|
| 60 |
+
|
| 61 |
+
m.def("test_eval_file", [global](py::str filename) {
|
| 62 |
+
auto local = py::dict();
|
| 63 |
+
local["y"] = py::int_(43);
|
| 64 |
+
|
| 65 |
+
int val_out = 0;
|
| 66 |
+
local["call_test2"] = py::cpp_function([&](int value) { val_out = value; });
|
| 67 |
+
|
| 68 |
+
auto result = py::eval_file(std::move(filename), global, local);
|
| 69 |
+
return val_out == 43 && result.is_none();
|
| 70 |
+
});
|
| 71 |
+
|
| 72 |
+
m.def("test_eval_failure", []() {
|
| 73 |
+
try {
|
| 74 |
+
py::eval("nonsense code ...");
|
| 75 |
+
} catch (py::error_already_set &) {
|
| 76 |
+
return true;
|
| 77 |
+
}
|
| 78 |
+
return false;
|
| 79 |
+
});
|
| 80 |
+
|
| 81 |
+
m.def("test_eval_file_failure", []() {
|
| 82 |
+
try {
|
| 83 |
+
py::eval_file("non-existing file");
|
| 84 |
+
} catch (std::exception &) {
|
| 85 |
+
return true;
|
| 86 |
+
}
|
| 87 |
+
return false;
|
| 88 |
+
});
|
| 89 |
+
|
| 90 |
+
// test_eval_empty_globals
|
| 91 |
+
m.def("eval_empty_globals", [](py::object global) {
|
| 92 |
+
if (global.is_none()) {
|
| 93 |
+
global = py::dict();
|
| 94 |
+
}
|
| 95 |
+
auto int_class = py::eval("isinstance(42, int)", global);
|
| 96 |
+
return global;
|
| 97 |
+
});
|
| 98 |
+
|
| 99 |
+
// test_eval_closure
|
| 100 |
+
m.def("test_eval_closure", []() {
|
| 101 |
+
py::dict global;
|
| 102 |
+
global["closure_value"] = 42;
|
| 103 |
+
py::dict local;
|
| 104 |
+
local["closure_value"] = 0;
|
| 105 |
+
py::exec(R"(
|
| 106 |
+
local_value = closure_value
|
| 107 |
+
|
| 108 |
+
def func_global():
|
| 109 |
+
return closure_value
|
| 110 |
+
|
| 111 |
+
def func_local():
|
| 112 |
+
return local_value
|
| 113 |
+
)",
|
| 114 |
+
global,
|
| 115 |
+
local);
|
| 116 |
+
return std::make_pair(global, local);
|
| 117 |
+
});
|
| 118 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_eval.py
CHANGED
|
@@ -1,50 +1,50 @@
|
|
| 1 |
-
import os
|
| 2 |
-
|
| 3 |
-
import pytest
|
| 4 |
-
|
| 5 |
-
import env # noqa: F401
|
| 6 |
-
from pybind11_tests import eval_ as m
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
def test_evals(capture):
|
| 10 |
-
with capture:
|
| 11 |
-
assert m.test_eval_statements()
|
| 12 |
-
assert capture == "Hello World!"
|
| 13 |
-
|
| 14 |
-
assert m.test_eval()
|
| 15 |
-
assert m.test_eval_single_statement()
|
| 16 |
-
|
| 17 |
-
assert m.test_eval_failure()
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
@pytest.mark.xfail("env.PYPY", raises=RuntimeError)
|
| 21 |
-
def test_eval_file():
|
| 22 |
-
filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
|
| 23 |
-
assert m.test_eval_file(filename)
|
| 24 |
-
|
| 25 |
-
assert m.test_eval_file_failure()
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
def test_eval_empty_globals():
|
| 29 |
-
assert "__builtins__" in m.eval_empty_globals(None)
|
| 30 |
-
|
| 31 |
-
g = {}
|
| 32 |
-
assert "__builtins__" in m.eval_empty_globals(g)
|
| 33 |
-
assert "__builtins__" in g
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
def test_eval_closure():
|
| 37 |
-
global_, local = m.test_eval_closure()
|
| 38 |
-
|
| 39 |
-
assert global_["closure_value"] == 42
|
| 40 |
-
assert local["closure_value"] == 0
|
| 41 |
-
|
| 42 |
-
assert "local_value" not in global_
|
| 43 |
-
assert local["local_value"] == 0
|
| 44 |
-
|
| 45 |
-
assert "func_global" not in global_
|
| 46 |
-
assert local["func_global"]() == 42
|
| 47 |
-
|
| 48 |
-
assert "func_local" not in global_
|
| 49 |
-
with pytest.raises(NameError):
|
| 50 |
-
local["func_local"]()
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
import env # noqa: F401
|
| 6 |
+
from pybind11_tests import eval_ as m
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def test_evals(capture):
|
| 10 |
+
with capture:
|
| 11 |
+
assert m.test_eval_statements()
|
| 12 |
+
assert capture == "Hello World!"
|
| 13 |
+
|
| 14 |
+
assert m.test_eval()
|
| 15 |
+
assert m.test_eval_single_statement()
|
| 16 |
+
|
| 17 |
+
assert m.test_eval_failure()
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
@pytest.mark.xfail("env.PYPY", raises=RuntimeError)
|
| 21 |
+
def test_eval_file():
|
| 22 |
+
filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
|
| 23 |
+
assert m.test_eval_file(filename)
|
| 24 |
+
|
| 25 |
+
assert m.test_eval_file_failure()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_eval_empty_globals():
|
| 29 |
+
assert "__builtins__" in m.eval_empty_globals(None)
|
| 30 |
+
|
| 31 |
+
g = {}
|
| 32 |
+
assert "__builtins__" in m.eval_empty_globals(g)
|
| 33 |
+
assert "__builtins__" in g
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def test_eval_closure():
|
| 37 |
+
global_, local = m.test_eval_closure()
|
| 38 |
+
|
| 39 |
+
assert global_["closure_value"] == 42
|
| 40 |
+
assert local["closure_value"] == 0
|
| 41 |
+
|
| 42 |
+
assert "local_value" not in global_
|
| 43 |
+
assert local["local_value"] == 0
|
| 44 |
+
|
| 45 |
+
assert "func_global" not in global_
|
| 46 |
+
assert local["func_global"]() == 42
|
| 47 |
+
|
| 48 |
+
assert "func_local" not in global_
|
| 49 |
+
with pytest.raises(NameError):
|
| 50 |
+
local["func_local"]()
|
third_party/CityFlow/extern/pybind11/tests/test_eval_call.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# This file is called from 'test_eval.py'
|
| 2 |
-
|
| 3 |
-
if "call_test2" in locals():
|
| 4 |
-
call_test2(y) # noqa: F821 undefined name
|
|
|
|
| 1 |
+
# This file is called from 'test_eval.py'
|
| 2 |
+
|
| 3 |
+
if "call_test2" in locals():
|
| 4 |
+
call_test2(y) # noqa: F821 undefined name
|
third_party/CityFlow/extern/pybind11/tests/test_exceptions.cpp
CHANGED
|
@@ -1,388 +1,388 @@
|
|
| 1 |
-
/*
|
| 2 |
-
tests/test_custom-exceptions.cpp -- exception translation
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2016 Pim Schellart <P.Schellart@princeton.edu>
|
| 5 |
-
|
| 6 |
-
All rights reserved. Use of this source code is governed by a
|
| 7 |
-
BSD-style license that can be found in the LICENSE file.
|
| 8 |
-
*/
|
| 9 |
-
#include <pybind11/gil_safe_call_once.h>
|
| 10 |
-
|
| 11 |
-
#include "test_exceptions.h"
|
| 12 |
-
|
| 13 |
-
#include "local_bindings.h"
|
| 14 |
-
#include "pybind11_tests.h"
|
| 15 |
-
|
| 16 |
-
#include <exception>
|
| 17 |
-
#include <stdexcept>
|
| 18 |
-
#include <utility>
|
| 19 |
-
|
| 20 |
-
// A type that should be raised as an exception in Python
|
| 21 |
-
class MyException : public std::exception {
|
| 22 |
-
public:
|
| 23 |
-
explicit MyException(const char *m) : message{m} {}
|
| 24 |
-
const char *what() const noexcept override { return message.c_str(); }
|
| 25 |
-
|
| 26 |
-
private:
|
| 27 |
-
std::string message = "";
|
| 28 |
-
};
|
| 29 |
-
|
| 30 |
-
class MyExceptionUseDeprecatedOperatorCall : public MyException {
|
| 31 |
-
using MyException::MyException;
|
| 32 |
-
};
|
| 33 |
-
|
| 34 |
-
// A type that should be translated to a standard Python exception
|
| 35 |
-
class MyException2 : public std::exception {
|
| 36 |
-
public:
|
| 37 |
-
explicit MyException2(const char *m) : message{m} {}
|
| 38 |
-
const char *what() const noexcept override { return message.c_str(); }
|
| 39 |
-
|
| 40 |
-
private:
|
| 41 |
-
std::string message = "";
|
| 42 |
-
};
|
| 43 |
-
|
| 44 |
-
// A type that is not derived from std::exception (and is thus unknown)
|
| 45 |
-
class MyException3 {
|
| 46 |
-
public:
|
| 47 |
-
explicit MyException3(const char *m) : message{m} {}
|
| 48 |
-
virtual const char *what() const noexcept { return message.c_str(); }
|
| 49 |
-
// Rule of 5 BEGIN: to preempt compiler warnings.
|
| 50 |
-
MyException3(const MyException3 &) = default;
|
| 51 |
-
MyException3(MyException3 &&) = default;
|
| 52 |
-
MyException3 &operator=(const MyException3 &) = default;
|
| 53 |
-
MyException3 &operator=(MyException3 &&) = default;
|
| 54 |
-
virtual ~MyException3() = default;
|
| 55 |
-
// Rule of 5 END.
|
| 56 |
-
private:
|
| 57 |
-
std::string message = "";
|
| 58 |
-
};
|
| 59 |
-
|
| 60 |
-
// A type that should be translated to MyException
|
| 61 |
-
// and delegated to its exception translator
|
| 62 |
-
class MyException4 : public std::exception {
|
| 63 |
-
public:
|
| 64 |
-
explicit MyException4(const char *m) : message{m} {}
|
| 65 |
-
const char *what() const noexcept override { return message.c_str(); }
|
| 66 |
-
|
| 67 |
-
private:
|
| 68 |
-
std::string message = "";
|
| 69 |
-
};
|
| 70 |
-
|
| 71 |
-
// Like the above, but declared via the helper function
|
| 72 |
-
class MyException5 : public std::logic_error {
|
| 73 |
-
public:
|
| 74 |
-
explicit MyException5(const std::string &what) : std::logic_error(what) {}
|
| 75 |
-
};
|
| 76 |
-
|
| 77 |
-
// Inherits from MyException5
|
| 78 |
-
class MyException5_1 : public MyException5 {
|
| 79 |
-
using MyException5::MyException5;
|
| 80 |
-
};
|
| 81 |
-
|
| 82 |
-
// Exception that will be caught via the module local translator.
|
| 83 |
-
class MyException6 : public std::exception {
|
| 84 |
-
public:
|
| 85 |
-
explicit MyException6(const char *m) : message{m} {}
|
| 86 |
-
const char *what() const noexcept override { return message.c_str(); }
|
| 87 |
-
|
| 88 |
-
private:
|
| 89 |
-
std::string message = "";
|
| 90 |
-
};
|
| 91 |
-
|
| 92 |
-
struct PythonCallInDestructor {
|
| 93 |
-
explicit PythonCallInDestructor(const py::dict &d) : d(d) {}
|
| 94 |
-
~PythonCallInDestructor() { d["good"] = true; }
|
| 95 |
-
|
| 96 |
-
py::dict d;
|
| 97 |
-
};
|
| 98 |
-
|
| 99 |
-
struct PythonAlreadySetInDestructor {
|
| 100 |
-
explicit PythonAlreadySetInDestructor(const py::str &s) : s(s) {}
|
| 101 |
-
~PythonAlreadySetInDestructor() {
|
| 102 |
-
py::dict foo;
|
| 103 |
-
try {
|
| 104 |
-
// Assign to a py::object to force read access of nonexistent dict entry
|
| 105 |
-
py::object o = foo["bar"];
|
| 106 |
-
} catch (py::error_already_set &ex) {
|
| 107 |
-
ex.discard_as_unraisable(s);
|
| 108 |
-
}
|
| 109 |
-
}
|
| 110 |
-
|
| 111 |
-
py::str s;
|
| 112 |
-
};
|
| 113 |
-
|
| 114 |
-
TEST_SUBMODULE(exceptions, m) {
|
| 115 |
-
m.def("throw_std_exception",
|
| 116 |
-
[]() { throw std::runtime_error("This exception was intentionally thrown."); });
|
| 117 |
-
|
| 118 |
-
// PLEASE KEEP IN SYNC with docs/advanced/exceptions.rst
|
| 119 |
-
PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> ex_storage;
|
| 120 |
-
ex_storage.call_once_and_store_result(
|
| 121 |
-
[&]() { return py::exception<MyException>(m, "MyException"); });
|
| 122 |
-
py::register_exception_translator([](std::exception_ptr p) {
|
| 123 |
-
try {
|
| 124 |
-
if (p) {
|
| 125 |
-
std::rethrow_exception(p);
|
| 126 |
-
}
|
| 127 |
-
} catch (const MyException &e) {
|
| 128 |
-
// Set MyException as the active python error
|
| 129 |
-
py::set_error(ex_storage.get_stored(), e.what());
|
| 130 |
-
}
|
| 131 |
-
});
|
| 132 |
-
|
| 133 |
-
// Same as above, but using the deprecated `py::exception<>::operator()`
|
| 134 |
-
// We want to be sure it still works, until it's removed.
|
| 135 |
-
static const auto *const exd = new py::exception<MyExceptionUseDeprecatedOperatorCall>(
|
| 136 |
-
m, "MyExceptionUseDeprecatedOperatorCall");
|
| 137 |
-
py::register_exception_translator([](std::exception_ptr p) {
|
| 138 |
-
try {
|
| 139 |
-
if (p) {
|
| 140 |
-
std::rethrow_exception(p);
|
| 141 |
-
}
|
| 142 |
-
} catch (const MyExceptionUseDeprecatedOperatorCall &e) {
|
| 143 |
-
#if defined(__INTEL_COMPILER) || defined(__NVCOMPILER)
|
| 144 |
-
// It is not worth the trouble dealing with warning suppressions for these compilers.
|
| 145 |
-
// Falling back to the recommended approach to keep the test code simple.
|
| 146 |
-
py::set_error(*exd, e.what());
|
| 147 |
-
#else
|
| 148 |
-
PYBIND11_WARNING_PUSH
|
| 149 |
-
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
|
| 150 |
-
PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
|
| 151 |
-
PYBIND11_WARNING_DISABLE_MSVC(4996)
|
| 152 |
-
(*exd)(e.what());
|
| 153 |
-
PYBIND11_WARNING_POP
|
| 154 |
-
#endif
|
| 155 |
-
}
|
| 156 |
-
});
|
| 157 |
-
|
| 158 |
-
// register new translator for MyException2
|
| 159 |
-
// no need to store anything here because this type will
|
| 160 |
-
// never by visible from Python
|
| 161 |
-
py::register_exception_translator([](std::exception_ptr p) {
|
| 162 |
-
try {
|
| 163 |
-
if (p) {
|
| 164 |
-
std::rethrow_exception(p);
|
| 165 |
-
}
|
| 166 |
-
} catch (const MyException2 &e) {
|
| 167 |
-
// Translate this exception to a standard RuntimeError
|
| 168 |
-
py::set_error(PyExc_RuntimeError, e.what());
|
| 169 |
-
}
|
| 170 |
-
});
|
| 171 |
-
|
| 172 |
-
// register new translator for MyException4
|
| 173 |
-
// which will catch it and delegate to the previously registered
|
| 174 |
-
// translator for MyException by throwing a new exception
|
| 175 |
-
py::register_exception_translator([](std::exception_ptr p) {
|
| 176 |
-
try {
|
| 177 |
-
if (p) {
|
| 178 |
-
std::rethrow_exception(p);
|
| 179 |
-
}
|
| 180 |
-
} catch (const MyException4 &e) {
|
| 181 |
-
throw MyException(e.what());
|
| 182 |
-
}
|
| 183 |
-
});
|
| 184 |
-
|
| 185 |
-
// A simple exception translation:
|
| 186 |
-
auto ex5 = py::register_exception<MyException5>(m, "MyException5");
|
| 187 |
-
// A slightly more complicated one that declares MyException5_1 as a subclass of MyException5
|
| 188 |
-
py::register_exception<MyException5_1>(m, "MyException5_1", ex5.ptr());
|
| 189 |
-
|
| 190 |
-
// py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException")
|
| 191 |
-
|
| 192 |
-
py::register_local_exception_translator([](std::exception_ptr p) {
|
| 193 |
-
try {
|
| 194 |
-
if (p) {
|
| 195 |
-
std::rethrow_exception(p);
|
| 196 |
-
}
|
| 197 |
-
} catch (const MyException6 &e) {
|
| 198 |
-
py::set_error(PyExc_RuntimeError, e.what());
|
| 199 |
-
}
|
| 200 |
-
});
|
| 201 |
-
|
| 202 |
-
m.def("throws1",
|
| 203 |
-
[]() { throw MyException("this error should go to py::exception<MyException>"); });
|
| 204 |
-
m.def("throws1d", []() {
|
| 205 |
-
throw MyExceptionUseDeprecatedOperatorCall(
|
| 206 |
-
"this error should go to py::exception<MyExceptionUseDeprecatedOperatorCall>");
|
| 207 |
-
});
|
| 208 |
-
m.def("throws2",
|
| 209 |
-
[]() { throw MyException2("this error should go to a standard Python exception"); });
|
| 210 |
-
m.def("throws3", []() { throw MyException3("this error cannot be translated"); });
|
| 211 |
-
m.def("throws4", []() { throw MyException4("this error is rethrown"); });
|
| 212 |
-
m.def("throws5",
|
| 213 |
-
[]() { throw MyException5("this is a helper-defined translated exception"); });
|
| 214 |
-
m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); });
|
| 215 |
-
m.def("throws6", []() { throw MyException6("MyException6 only handled in this module"); });
|
| 216 |
-
m.def("throws_logic_error", []() {
|
| 217 |
-
throw std::logic_error("this error should fall through to the standard handler");
|
| 218 |
-
});
|
| 219 |
-
m.def("throws_overflow_error", []() { throw std::overflow_error(""); });
|
| 220 |
-
m.def("throws_local_error", []() { throw LocalException("never caught"); });
|
| 221 |
-
m.def("throws_local_simple_error", []() { throw LocalSimpleException("this mod"); });
|
| 222 |
-
m.def("exception_matches", []() {
|
| 223 |
-
py::dict foo;
|
| 224 |
-
try {
|
| 225 |
-
// Assign to a py::object to force read access of nonexistent dict entry
|
| 226 |
-
py::object o = foo["bar"];
|
| 227 |
-
} catch (py::error_already_set &ex) {
|
| 228 |
-
if (!ex.matches(PyExc_KeyError)) {
|
| 229 |
-
throw;
|
| 230 |
-
}
|
| 231 |
-
return true;
|
| 232 |
-
}
|
| 233 |
-
return false;
|
| 234 |
-
});
|
| 235 |
-
m.def("exception_matches_base", []() {
|
| 236 |
-
py::dict foo;
|
| 237 |
-
try {
|
| 238 |
-
// Assign to a py::object to force read access of nonexistent dict entry
|
| 239 |
-
py::object o = foo["bar"];
|
| 240 |
-
} catch (py::error_already_set &ex) {
|
| 241 |
-
if (!ex.matches(PyExc_Exception)) {
|
| 242 |
-
throw;
|
| 243 |
-
}
|
| 244 |
-
return true;
|
| 245 |
-
}
|
| 246 |
-
return false;
|
| 247 |
-
});
|
| 248 |
-
m.def("modulenotfound_exception_matches_base", []() {
|
| 249 |
-
try {
|
| 250 |
-
// On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError
|
| 251 |
-
py::module_::import("nonexistent");
|
| 252 |
-
} catch (py::error_already_set &ex) {
|
| 253 |
-
if (!ex.matches(PyExc_ImportError)) {
|
| 254 |
-
throw;
|
| 255 |
-
}
|
| 256 |
-
return true;
|
| 257 |
-
}
|
| 258 |
-
return false;
|
| 259 |
-
});
|
| 260 |
-
|
| 261 |
-
m.def("throw_already_set", [](bool err) {
|
| 262 |
-
if (err) {
|
| 263 |
-
py::set_error(PyExc_ValueError, "foo");
|
| 264 |
-
}
|
| 265 |
-
try {
|
| 266 |
-
throw py::error_already_set();
|
| 267 |
-
} catch (const std::runtime_error &e) {
|
| 268 |
-
if ((err && e.what() != std::string("ValueError: foo"))
|
| 269 |
-
|| (!err
|
| 270 |
-
&& e.what()
|
| 271 |
-
!= std::string("Internal error: pybind11::error_already_set called "
|
| 272 |
-
"while Python error indicator not set."))) {
|
| 273 |
-
PyErr_Clear();
|
| 274 |
-
throw std::runtime_error("error message mismatch");
|
| 275 |
-
}
|
| 276 |
-
}
|
| 277 |
-
PyErr_Clear();
|
| 278 |
-
if (err) {
|
| 279 |
-
py::set_error(PyExc_ValueError, "foo");
|
| 280 |
-
}
|
| 281 |
-
throw py::error_already_set();
|
| 282 |
-
});
|
| 283 |
-
|
| 284 |
-
m.def("python_call_in_destructor", [](const py::dict &d) {
|
| 285 |
-
bool retval = false;
|
| 286 |
-
try {
|
| 287 |
-
PythonCallInDestructor set_dict_in_destructor(d);
|
| 288 |
-
py::set_error(PyExc_ValueError, "foo");
|
| 289 |
-
throw py::error_already_set();
|
| 290 |
-
} catch (const py::error_already_set &) {
|
| 291 |
-
retval = true;
|
| 292 |
-
}
|
| 293 |
-
return retval;
|
| 294 |
-
});
|
| 295 |
-
|
| 296 |
-
m.def("python_alreadyset_in_destructor", [](const py::str &s) {
|
| 297 |
-
PythonAlreadySetInDestructor alreadyset_in_destructor(s);
|
| 298 |
-
return true;
|
| 299 |
-
});
|
| 300 |
-
|
| 301 |
-
// test_nested_throws
|
| 302 |
-
m.def("try_catch",
|
| 303 |
-
[m](const py::object &exc_type, const py::function &f, const py::args &args) {
|
| 304 |
-
try {
|
| 305 |
-
f(*args);
|
| 306 |
-
} catch (py::error_already_set &ex) {
|
| 307 |
-
if (ex.matches(exc_type)) {
|
| 308 |
-
py::print(ex.what());
|
| 309 |
-
} else {
|
| 310 |
-
// Simply `throw;` also works and is better, but using `throw ex;`
|
| 311 |
-
// here to cover that situation (as observed in the wild).
|
| 312 |
-
throw ex; // Invokes the copy ctor.
|
| 313 |
-
}
|
| 314 |
-
}
|
| 315 |
-
});
|
| 316 |
-
|
| 317 |
-
// Test repr that cannot be displayed
|
| 318 |
-
m.def("simple_bool_passthrough", [](bool x) { return x; });
|
| 319 |
-
|
| 320 |
-
m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); });
|
| 321 |
-
|
| 322 |
-
m.def("raise_from", []() {
|
| 323 |
-
py::set_error(PyExc_ValueError, "inner");
|
| 324 |
-
py::raise_from(PyExc_ValueError, "outer");
|
| 325 |
-
throw py::error_already_set();
|
| 326 |
-
});
|
| 327 |
-
|
| 328 |
-
m.def("raise_from_already_set", []() {
|
| 329 |
-
try {
|
| 330 |
-
py::set_error(PyExc_ValueError, "inner");
|
| 331 |
-
throw py::error_already_set();
|
| 332 |
-
} catch (py::error_already_set &e) {
|
| 333 |
-
py::raise_from(e, PyExc_ValueError, "outer");
|
| 334 |
-
throw py::error_already_set();
|
| 335 |
-
}
|
| 336 |
-
});
|
| 337 |
-
|
| 338 |
-
m.def("throw_nested_exception", []() {
|
| 339 |
-
try {
|
| 340 |
-
throw std::runtime_error("Inner Exception");
|
| 341 |
-
} catch (const std::runtime_error &) {
|
| 342 |
-
std::throw_with_nested(std::runtime_error("Outer Exception"));
|
| 343 |
-
}
|
| 344 |
-
});
|
| 345 |
-
|
| 346 |
-
m.def("error_already_set_what", [](const py::object &exc_type, const py::object &exc_value) {
|
| 347 |
-
py::set_error(exc_type, exc_value);
|
| 348 |
-
std::string what = py::error_already_set().what();
|
| 349 |
-
bool py_err_set_after_what = (PyErr_Occurred() != nullptr);
|
| 350 |
-
PyErr_Clear();
|
| 351 |
-
return py::make_tuple(std::move(what), py_err_set_after_what);
|
| 352 |
-
});
|
| 353 |
-
|
| 354 |
-
m.def("test_cross_module_interleaved_error_already_set", []() {
|
| 355 |
-
auto cm = py::module_::import("cross_module_interleaved_error_already_set");
|
| 356 |
-
auto interleaved_error_already_set
|
| 357 |
-
= reinterpret_cast<void (*)()>(PyLong_AsVoidPtr(cm.attr("funcaddr").ptr()));
|
| 358 |
-
interleaved_error_already_set();
|
| 359 |
-
});
|
| 360 |
-
|
| 361 |
-
m.def("test_error_already_set_double_restore", [](bool dry_run) {
|
| 362 |
-
py::set_error(PyExc_ValueError, "Random error.");
|
| 363 |
-
py::error_already_set e;
|
| 364 |
-
e.restore();
|
| 365 |
-
PyErr_Clear();
|
| 366 |
-
if (!dry_run) {
|
| 367 |
-
e.restore();
|
| 368 |
-
}
|
| 369 |
-
});
|
| 370 |
-
|
| 371 |
-
// https://github.com/pybind/pybind11/issues/4075
|
| 372 |
-
m.def("test_pypy_oserror_normalization", []() {
|
| 373 |
-
try {
|
| 374 |
-
py::module_::import("io").attr("open")("this_filename_must_not_exist", "r");
|
| 375 |
-
} catch (const py::error_already_set &e) {
|
| 376 |
-
return py::str(e.what()); // str must be built before e goes out of scope.
|
| 377 |
-
}
|
| 378 |
-
return py::str("UNEXPECTED");
|
| 379 |
-
});
|
| 380 |
-
|
| 381 |
-
m.def("test_fn_cast_int", [](const py::function &fn) {
|
| 382 |
-
// function returns None instead of int, should give a useful error message
|
| 383 |
-
fn().cast<int>();
|
| 384 |
-
});
|
| 385 |
-
|
| 386 |
-
// m.def("pass_exception_void", [](const py::exception<void>&) {}); // Does not compile.
|
| 387 |
-
m.def("return_exception_void", []() { return py::exception<void>(); });
|
| 388 |
-
}
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
tests/test_custom-exceptions.cpp -- exception translation
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2016 Pim Schellart <P.Schellart@princeton.edu>
|
| 5 |
+
|
| 6 |
+
All rights reserved. Use of this source code is governed by a
|
| 7 |
+
BSD-style license that can be found in the LICENSE file.
|
| 8 |
+
*/
|
| 9 |
+
#include <pybind11/gil_safe_call_once.h>
|
| 10 |
+
|
| 11 |
+
#include "test_exceptions.h"
|
| 12 |
+
|
| 13 |
+
#include "local_bindings.h"
|
| 14 |
+
#include "pybind11_tests.h"
|
| 15 |
+
|
| 16 |
+
#include <exception>
|
| 17 |
+
#include <stdexcept>
|
| 18 |
+
#include <utility>
|
| 19 |
+
|
| 20 |
+
// A type that should be raised as an exception in Python
|
| 21 |
+
class MyException : public std::exception {
|
| 22 |
+
public:
|
| 23 |
+
explicit MyException(const char *m) : message{m} {}
|
| 24 |
+
const char *what() const noexcept override { return message.c_str(); }
|
| 25 |
+
|
| 26 |
+
private:
|
| 27 |
+
std::string message = "";
|
| 28 |
+
};
|
| 29 |
+
|
| 30 |
+
class MyExceptionUseDeprecatedOperatorCall : public MyException {
|
| 31 |
+
using MyException::MyException;
|
| 32 |
+
};
|
| 33 |
+
|
| 34 |
+
// A type that should be translated to a standard Python exception
|
| 35 |
+
class MyException2 : public std::exception {
|
| 36 |
+
public:
|
| 37 |
+
explicit MyException2(const char *m) : message{m} {}
|
| 38 |
+
const char *what() const noexcept override { return message.c_str(); }
|
| 39 |
+
|
| 40 |
+
private:
|
| 41 |
+
std::string message = "";
|
| 42 |
+
};
|
| 43 |
+
|
| 44 |
+
// A type that is not derived from std::exception (and is thus unknown)
|
| 45 |
+
class MyException3 {
|
| 46 |
+
public:
|
| 47 |
+
explicit MyException3(const char *m) : message{m} {}
|
| 48 |
+
virtual const char *what() const noexcept { return message.c_str(); }
|
| 49 |
+
// Rule of 5 BEGIN: to preempt compiler warnings.
|
| 50 |
+
MyException3(const MyException3 &) = default;
|
| 51 |
+
MyException3(MyException3 &&) = default;
|
| 52 |
+
MyException3 &operator=(const MyException3 &) = default;
|
| 53 |
+
MyException3 &operator=(MyException3 &&) = default;
|
| 54 |
+
virtual ~MyException3() = default;
|
| 55 |
+
// Rule of 5 END.
|
| 56 |
+
private:
|
| 57 |
+
std::string message = "";
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
// A type that should be translated to MyException
|
| 61 |
+
// and delegated to its exception translator
|
| 62 |
+
class MyException4 : public std::exception {
|
| 63 |
+
public:
|
| 64 |
+
explicit MyException4(const char *m) : message{m} {}
|
| 65 |
+
const char *what() const noexcept override { return message.c_str(); }
|
| 66 |
+
|
| 67 |
+
private:
|
| 68 |
+
std::string message = "";
|
| 69 |
+
};
|
| 70 |
+
|
| 71 |
+
// Like the above, but declared via the helper function
|
| 72 |
+
class MyException5 : public std::logic_error {
|
| 73 |
+
public:
|
| 74 |
+
explicit MyException5(const std::string &what) : std::logic_error(what) {}
|
| 75 |
+
};
|
| 76 |
+
|
| 77 |
+
// Inherits from MyException5
|
| 78 |
+
class MyException5_1 : public MyException5 {
|
| 79 |
+
using MyException5::MyException5;
|
| 80 |
+
};
|
| 81 |
+
|
| 82 |
+
// Exception that will be caught via the module local translator.
|
| 83 |
+
class MyException6 : public std::exception {
|
| 84 |
+
public:
|
| 85 |
+
explicit MyException6(const char *m) : message{m} {}
|
| 86 |
+
const char *what() const noexcept override { return message.c_str(); }
|
| 87 |
+
|
| 88 |
+
private:
|
| 89 |
+
std::string message = "";
|
| 90 |
+
};
|
| 91 |
+
|
| 92 |
+
struct PythonCallInDestructor {
|
| 93 |
+
explicit PythonCallInDestructor(const py::dict &d) : d(d) {}
|
| 94 |
+
~PythonCallInDestructor() { d["good"] = true; }
|
| 95 |
+
|
| 96 |
+
py::dict d;
|
| 97 |
+
};
|
| 98 |
+
|
| 99 |
+
struct PythonAlreadySetInDestructor {
|
| 100 |
+
explicit PythonAlreadySetInDestructor(const py::str &s) : s(s) {}
|
| 101 |
+
~PythonAlreadySetInDestructor() {
|
| 102 |
+
py::dict foo;
|
| 103 |
+
try {
|
| 104 |
+
// Assign to a py::object to force read access of nonexistent dict entry
|
| 105 |
+
py::object o = foo["bar"];
|
| 106 |
+
} catch (py::error_already_set &ex) {
|
| 107 |
+
ex.discard_as_unraisable(s);
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
py::str s;
|
| 112 |
+
};
|
| 113 |
+
|
| 114 |
+
TEST_SUBMODULE(exceptions, m) {
|
| 115 |
+
m.def("throw_std_exception",
|
| 116 |
+
[]() { throw std::runtime_error("This exception was intentionally thrown."); });
|
| 117 |
+
|
| 118 |
+
// PLEASE KEEP IN SYNC with docs/advanced/exceptions.rst
|
| 119 |
+
PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> ex_storage;
|
| 120 |
+
ex_storage.call_once_and_store_result(
|
| 121 |
+
[&]() { return py::exception<MyException>(m, "MyException"); });
|
| 122 |
+
py::register_exception_translator([](std::exception_ptr p) {
|
| 123 |
+
try {
|
| 124 |
+
if (p) {
|
| 125 |
+
std::rethrow_exception(p);
|
| 126 |
+
}
|
| 127 |
+
} catch (const MyException &e) {
|
| 128 |
+
// Set MyException as the active python error
|
| 129 |
+
py::set_error(ex_storage.get_stored(), e.what());
|
| 130 |
+
}
|
| 131 |
+
});
|
| 132 |
+
|
| 133 |
+
// Same as above, but using the deprecated `py::exception<>::operator()`
|
| 134 |
+
// We want to be sure it still works, until it's removed.
|
| 135 |
+
static const auto *const exd = new py::exception<MyExceptionUseDeprecatedOperatorCall>(
|
| 136 |
+
m, "MyExceptionUseDeprecatedOperatorCall");
|
| 137 |
+
py::register_exception_translator([](std::exception_ptr p) {
|
| 138 |
+
try {
|
| 139 |
+
if (p) {
|
| 140 |
+
std::rethrow_exception(p);
|
| 141 |
+
}
|
| 142 |
+
} catch (const MyExceptionUseDeprecatedOperatorCall &e) {
|
| 143 |
+
#if defined(__INTEL_COMPILER) || defined(__NVCOMPILER)
|
| 144 |
+
// It is not worth the trouble dealing with warning suppressions for these compilers.
|
| 145 |
+
// Falling back to the recommended approach to keep the test code simple.
|
| 146 |
+
py::set_error(*exd, e.what());
|
| 147 |
+
#else
|
| 148 |
+
PYBIND11_WARNING_PUSH
|
| 149 |
+
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
|
| 150 |
+
PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
|
| 151 |
+
PYBIND11_WARNING_DISABLE_MSVC(4996)
|
| 152 |
+
(*exd)(e.what());
|
| 153 |
+
PYBIND11_WARNING_POP
|
| 154 |
+
#endif
|
| 155 |
+
}
|
| 156 |
+
});
|
| 157 |
+
|
| 158 |
+
// register new translator for MyException2
|
| 159 |
+
// no need to store anything here because this type will
|
| 160 |
+
// never by visible from Python
|
| 161 |
+
py::register_exception_translator([](std::exception_ptr p) {
|
| 162 |
+
try {
|
| 163 |
+
if (p) {
|
| 164 |
+
std::rethrow_exception(p);
|
| 165 |
+
}
|
| 166 |
+
} catch (const MyException2 &e) {
|
| 167 |
+
// Translate this exception to a standard RuntimeError
|
| 168 |
+
py::set_error(PyExc_RuntimeError, e.what());
|
| 169 |
+
}
|
| 170 |
+
});
|
| 171 |
+
|
| 172 |
+
// register new translator for MyException4
|
| 173 |
+
// which will catch it and delegate to the previously registered
|
| 174 |
+
// translator for MyException by throwing a new exception
|
| 175 |
+
py::register_exception_translator([](std::exception_ptr p) {
|
| 176 |
+
try {
|
| 177 |
+
if (p) {
|
| 178 |
+
std::rethrow_exception(p);
|
| 179 |
+
}
|
| 180 |
+
} catch (const MyException4 &e) {
|
| 181 |
+
throw MyException(e.what());
|
| 182 |
+
}
|
| 183 |
+
});
|
| 184 |
+
|
| 185 |
+
// A simple exception translation:
|
| 186 |
+
auto ex5 = py::register_exception<MyException5>(m, "MyException5");
|
| 187 |
+
// A slightly more complicated one that declares MyException5_1 as a subclass of MyException5
|
| 188 |
+
py::register_exception<MyException5_1>(m, "MyException5_1", ex5.ptr());
|
| 189 |
+
|
| 190 |
+
// py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException")
|
| 191 |
+
|
| 192 |
+
py::register_local_exception_translator([](std::exception_ptr p) {
|
| 193 |
+
try {
|
| 194 |
+
if (p) {
|
| 195 |
+
std::rethrow_exception(p);
|
| 196 |
+
}
|
| 197 |
+
} catch (const MyException6 &e) {
|
| 198 |
+
py::set_error(PyExc_RuntimeError, e.what());
|
| 199 |
+
}
|
| 200 |
+
});
|
| 201 |
+
|
| 202 |
+
m.def("throws1",
|
| 203 |
+
[]() { throw MyException("this error should go to py::exception<MyException>"); });
|
| 204 |
+
m.def("throws1d", []() {
|
| 205 |
+
throw MyExceptionUseDeprecatedOperatorCall(
|
| 206 |
+
"this error should go to py::exception<MyExceptionUseDeprecatedOperatorCall>");
|
| 207 |
+
});
|
| 208 |
+
m.def("throws2",
|
| 209 |
+
[]() { throw MyException2("this error should go to a standard Python exception"); });
|
| 210 |
+
m.def("throws3", []() { throw MyException3("this error cannot be translated"); });
|
| 211 |
+
m.def("throws4", []() { throw MyException4("this error is rethrown"); });
|
| 212 |
+
m.def("throws5",
|
| 213 |
+
[]() { throw MyException5("this is a helper-defined translated exception"); });
|
| 214 |
+
m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); });
|
| 215 |
+
m.def("throws6", []() { throw MyException6("MyException6 only handled in this module"); });
|
| 216 |
+
m.def("throws_logic_error", []() {
|
| 217 |
+
throw std::logic_error("this error should fall through to the standard handler");
|
| 218 |
+
});
|
| 219 |
+
m.def("throws_overflow_error", []() { throw std::overflow_error(""); });
|
| 220 |
+
m.def("throws_local_error", []() { throw LocalException("never caught"); });
|
| 221 |
+
m.def("throws_local_simple_error", []() { throw LocalSimpleException("this mod"); });
|
| 222 |
+
m.def("exception_matches", []() {
|
| 223 |
+
py::dict foo;
|
| 224 |
+
try {
|
| 225 |
+
// Assign to a py::object to force read access of nonexistent dict entry
|
| 226 |
+
py::object o = foo["bar"];
|
| 227 |
+
} catch (py::error_already_set &ex) {
|
| 228 |
+
if (!ex.matches(PyExc_KeyError)) {
|
| 229 |
+
throw;
|
| 230 |
+
}
|
| 231 |
+
return true;
|
| 232 |
+
}
|
| 233 |
+
return false;
|
| 234 |
+
});
|
| 235 |
+
m.def("exception_matches_base", []() {
|
| 236 |
+
py::dict foo;
|
| 237 |
+
try {
|
| 238 |
+
// Assign to a py::object to force read access of nonexistent dict entry
|
| 239 |
+
py::object o = foo["bar"];
|
| 240 |
+
} catch (py::error_already_set &ex) {
|
| 241 |
+
if (!ex.matches(PyExc_Exception)) {
|
| 242 |
+
throw;
|
| 243 |
+
}
|
| 244 |
+
return true;
|
| 245 |
+
}
|
| 246 |
+
return false;
|
| 247 |
+
});
|
| 248 |
+
m.def("modulenotfound_exception_matches_base", []() {
|
| 249 |
+
try {
|
| 250 |
+
// On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError
|
| 251 |
+
py::module_::import("nonexistent");
|
| 252 |
+
} catch (py::error_already_set &ex) {
|
| 253 |
+
if (!ex.matches(PyExc_ImportError)) {
|
| 254 |
+
throw;
|
| 255 |
+
}
|
| 256 |
+
return true;
|
| 257 |
+
}
|
| 258 |
+
return false;
|
| 259 |
+
});
|
| 260 |
+
|
| 261 |
+
m.def("throw_already_set", [](bool err) {
|
| 262 |
+
if (err) {
|
| 263 |
+
py::set_error(PyExc_ValueError, "foo");
|
| 264 |
+
}
|
| 265 |
+
try {
|
| 266 |
+
throw py::error_already_set();
|
| 267 |
+
} catch (const std::runtime_error &e) {
|
| 268 |
+
if ((err && e.what() != std::string("ValueError: foo"))
|
| 269 |
+
|| (!err
|
| 270 |
+
&& e.what()
|
| 271 |
+
!= std::string("Internal error: pybind11::error_already_set called "
|
| 272 |
+
"while Python error indicator not set."))) {
|
| 273 |
+
PyErr_Clear();
|
| 274 |
+
throw std::runtime_error("error message mismatch");
|
| 275 |
+
}
|
| 276 |
+
}
|
| 277 |
+
PyErr_Clear();
|
| 278 |
+
if (err) {
|
| 279 |
+
py::set_error(PyExc_ValueError, "foo");
|
| 280 |
+
}
|
| 281 |
+
throw py::error_already_set();
|
| 282 |
+
});
|
| 283 |
+
|
| 284 |
+
m.def("python_call_in_destructor", [](const py::dict &d) {
|
| 285 |
+
bool retval = false;
|
| 286 |
+
try {
|
| 287 |
+
PythonCallInDestructor set_dict_in_destructor(d);
|
| 288 |
+
py::set_error(PyExc_ValueError, "foo");
|
| 289 |
+
throw py::error_already_set();
|
| 290 |
+
} catch (const py::error_already_set &) {
|
| 291 |
+
retval = true;
|
| 292 |
+
}
|
| 293 |
+
return retval;
|
| 294 |
+
});
|
| 295 |
+
|
| 296 |
+
m.def("python_alreadyset_in_destructor", [](const py::str &s) {
|
| 297 |
+
PythonAlreadySetInDestructor alreadyset_in_destructor(s);
|
| 298 |
+
return true;
|
| 299 |
+
});
|
| 300 |
+
|
| 301 |
+
// test_nested_throws
|
| 302 |
+
m.def("try_catch",
|
| 303 |
+
[m](const py::object &exc_type, const py::function &f, const py::args &args) {
|
| 304 |
+
try {
|
| 305 |
+
f(*args);
|
| 306 |
+
} catch (py::error_already_set &ex) {
|
| 307 |
+
if (ex.matches(exc_type)) {
|
| 308 |
+
py::print(ex.what());
|
| 309 |
+
} else {
|
| 310 |
+
// Simply `throw;` also works and is better, but using `throw ex;`
|
| 311 |
+
// here to cover that situation (as observed in the wild).
|
| 312 |
+
throw ex; // Invokes the copy ctor.
|
| 313 |
+
}
|
| 314 |
+
}
|
| 315 |
+
});
|
| 316 |
+
|
| 317 |
+
// Test repr that cannot be displayed
|
| 318 |
+
m.def("simple_bool_passthrough", [](bool x) { return x; });
|
| 319 |
+
|
| 320 |
+
m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); });
|
| 321 |
+
|
| 322 |
+
m.def("raise_from", []() {
|
| 323 |
+
py::set_error(PyExc_ValueError, "inner");
|
| 324 |
+
py::raise_from(PyExc_ValueError, "outer");
|
| 325 |
+
throw py::error_already_set();
|
| 326 |
+
});
|
| 327 |
+
|
| 328 |
+
m.def("raise_from_already_set", []() {
|
| 329 |
+
try {
|
| 330 |
+
py::set_error(PyExc_ValueError, "inner");
|
| 331 |
+
throw py::error_already_set();
|
| 332 |
+
} catch (py::error_already_set &e) {
|
| 333 |
+
py::raise_from(e, PyExc_ValueError, "outer");
|
| 334 |
+
throw py::error_already_set();
|
| 335 |
+
}
|
| 336 |
+
});
|
| 337 |
+
|
| 338 |
+
m.def("throw_nested_exception", []() {
|
| 339 |
+
try {
|
| 340 |
+
throw std::runtime_error("Inner Exception");
|
| 341 |
+
} catch (const std::runtime_error &) {
|
| 342 |
+
std::throw_with_nested(std::runtime_error("Outer Exception"));
|
| 343 |
+
}
|
| 344 |
+
});
|
| 345 |
+
|
| 346 |
+
m.def("error_already_set_what", [](const py::object &exc_type, const py::object &exc_value) {
|
| 347 |
+
py::set_error(exc_type, exc_value);
|
| 348 |
+
std::string what = py::error_already_set().what();
|
| 349 |
+
bool py_err_set_after_what = (PyErr_Occurred() != nullptr);
|
| 350 |
+
PyErr_Clear();
|
| 351 |
+
return py::make_tuple(std::move(what), py_err_set_after_what);
|
| 352 |
+
});
|
| 353 |
+
|
| 354 |
+
m.def("test_cross_module_interleaved_error_already_set", []() {
|
| 355 |
+
auto cm = py::module_::import("cross_module_interleaved_error_already_set");
|
| 356 |
+
auto interleaved_error_already_set
|
| 357 |
+
= reinterpret_cast<void (*)()>(PyLong_AsVoidPtr(cm.attr("funcaddr").ptr()));
|
| 358 |
+
interleaved_error_already_set();
|
| 359 |
+
});
|
| 360 |
+
|
| 361 |
+
m.def("test_error_already_set_double_restore", [](bool dry_run) {
|
| 362 |
+
py::set_error(PyExc_ValueError, "Random error.");
|
| 363 |
+
py::error_already_set e;
|
| 364 |
+
e.restore();
|
| 365 |
+
PyErr_Clear();
|
| 366 |
+
if (!dry_run) {
|
| 367 |
+
e.restore();
|
| 368 |
+
}
|
| 369 |
+
});
|
| 370 |
+
|
| 371 |
+
// https://github.com/pybind/pybind11/issues/4075
|
| 372 |
+
m.def("test_pypy_oserror_normalization", []() {
|
| 373 |
+
try {
|
| 374 |
+
py::module_::import("io").attr("open")("this_filename_must_not_exist", "r");
|
| 375 |
+
} catch (const py::error_already_set &e) {
|
| 376 |
+
return py::str(e.what()); // str must be built before e goes out of scope.
|
| 377 |
+
}
|
| 378 |
+
return py::str("UNEXPECTED");
|
| 379 |
+
});
|
| 380 |
+
|
| 381 |
+
m.def("test_fn_cast_int", [](const py::function &fn) {
|
| 382 |
+
// function returns None instead of int, should give a useful error message
|
| 383 |
+
fn().cast<int>();
|
| 384 |
+
});
|
| 385 |
+
|
| 386 |
+
// m.def("pass_exception_void", [](const py::exception<void>&) {}); // Does not compile.
|
| 387 |
+
m.def("return_exception_void", []() { return py::exception<void>(); });
|
| 388 |
+
}
|
third_party/CityFlow/extern/pybind11/tests/test_exceptions.h
CHANGED
|
@@ -1,13 +1,13 @@
|
|
| 1 |
-
#pragma once
|
| 2 |
-
#include "pybind11_tests.h"
|
| 3 |
-
|
| 4 |
-
#include <stdexcept>
|
| 5 |
-
|
| 6 |
-
// shared exceptions for cross_module_tests
|
| 7 |
-
|
| 8 |
-
class PYBIND11_EXPORT_EXCEPTION shared_exception : public pybind11::builtin_exception {
|
| 9 |
-
public:
|
| 10 |
-
using builtin_exception::builtin_exception;
|
| 11 |
-
explicit shared_exception() : shared_exception("") {}
|
| 12 |
-
void set_error() const override { py::set_error(PyExc_RuntimeError, what()); }
|
| 13 |
-
};
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
#include "pybind11_tests.h"
|
| 3 |
+
|
| 4 |
+
#include <stdexcept>
|
| 5 |
+
|
| 6 |
+
// shared exceptions for cross_module_tests
|
| 7 |
+
|
| 8 |
+
class PYBIND11_EXPORT_EXCEPTION shared_exception : public pybind11::builtin_exception {
|
| 9 |
+
public:
|
| 10 |
+
using builtin_exception::builtin_exception;
|
| 11 |
+
explicit shared_exception() : shared_exception("") {}
|
| 12 |
+
void set_error() const override { py::set_error(PyExc_RuntimeError, what()); }
|
| 13 |
+
};
|
third_party/CityFlow/extern/pybind11/tests/test_exceptions.py
CHANGED
|
@@ -1,432 +1,432 @@
|
|
| 1 |
-
import sys
|
| 2 |
-
|
| 3 |
-
import pytest
|
| 4 |
-
|
| 5 |
-
import env
|
| 6 |
-
import pybind11_cross_module_tests as cm
|
| 7 |
-
import pybind11_tests
|
| 8 |
-
from pybind11_tests import exceptions as m
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
def test_std_exception(msg):
|
| 12 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 13 |
-
m.throw_std_exception()
|
| 14 |
-
assert msg(excinfo.value) == "This exception was intentionally thrown."
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
def test_error_already_set(msg):
|
| 18 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 19 |
-
m.throw_already_set(False)
|
| 20 |
-
assert (
|
| 21 |
-
msg(excinfo.value)
|
| 22 |
-
== "Internal error: pybind11::error_already_set called while Python error indicator not set."
|
| 23 |
-
)
|
| 24 |
-
|
| 25 |
-
with pytest.raises(ValueError) as excinfo:
|
| 26 |
-
m.throw_already_set(True)
|
| 27 |
-
assert msg(excinfo.value) == "foo"
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
def test_raise_from(msg):
|
| 31 |
-
with pytest.raises(ValueError) as excinfo:
|
| 32 |
-
m.raise_from()
|
| 33 |
-
assert msg(excinfo.value) == "outer"
|
| 34 |
-
assert msg(excinfo.value.__cause__) == "inner"
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
def test_raise_from_already_set(msg):
|
| 38 |
-
with pytest.raises(ValueError) as excinfo:
|
| 39 |
-
m.raise_from_already_set()
|
| 40 |
-
assert msg(excinfo.value) == "outer"
|
| 41 |
-
assert msg(excinfo.value.__cause__) == "inner"
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
def test_cross_module_exceptions(msg):
|
| 45 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 46 |
-
cm.raise_runtime_error()
|
| 47 |
-
assert str(excinfo.value) == "My runtime error"
|
| 48 |
-
|
| 49 |
-
with pytest.raises(ValueError) as excinfo:
|
| 50 |
-
cm.raise_value_error()
|
| 51 |
-
assert str(excinfo.value) == "My value error"
|
| 52 |
-
|
| 53 |
-
with pytest.raises(ValueError) as excinfo:
|
| 54 |
-
cm.throw_pybind_value_error()
|
| 55 |
-
assert str(excinfo.value) == "pybind11 value error"
|
| 56 |
-
|
| 57 |
-
with pytest.raises(TypeError) as excinfo:
|
| 58 |
-
cm.throw_pybind_type_error()
|
| 59 |
-
assert str(excinfo.value) == "pybind11 type error"
|
| 60 |
-
|
| 61 |
-
with pytest.raises(StopIteration) as excinfo:
|
| 62 |
-
cm.throw_stop_iteration()
|
| 63 |
-
|
| 64 |
-
with pytest.raises(cm.LocalSimpleException) as excinfo:
|
| 65 |
-
cm.throw_local_simple_error()
|
| 66 |
-
assert msg(excinfo.value) == "external mod"
|
| 67 |
-
|
| 68 |
-
with pytest.raises(KeyError) as excinfo:
|
| 69 |
-
cm.throw_local_error()
|
| 70 |
-
# KeyError is a repr of the key, so it has an extra set of quotes
|
| 71 |
-
assert str(excinfo.value) == "'just local'"
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
# TODO: FIXME
|
| 75 |
-
@pytest.mark.xfail(
|
| 76 |
-
"env.MACOS and (env.PYPY or pybind11_tests.compiler_info.startswith('Homebrew Clang'))",
|
| 77 |
-
raises=RuntimeError,
|
| 78 |
-
reason="See Issue #2847, PR #2999, PR #4324",
|
| 79 |
-
)
|
| 80 |
-
def test_cross_module_exception_translator():
|
| 81 |
-
with pytest.raises(KeyError):
|
| 82 |
-
# translator registered in cross_module_tests
|
| 83 |
-
m.throw_should_be_translated_to_key_error()
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
def test_python_call_in_catch():
|
| 87 |
-
d = {}
|
| 88 |
-
assert m.python_call_in_destructor(d) is True
|
| 89 |
-
assert d["good"] is True
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
def ignore_pytest_unraisable_warning(f):
|
| 93 |
-
unraisable = "PytestUnraisableExceptionWarning"
|
| 94 |
-
if hasattr(pytest, unraisable): # Python >= 3.8 and pytest >= 6
|
| 95 |
-
dec = pytest.mark.filterwarnings(f"ignore::pytest.{unraisable}")
|
| 96 |
-
return dec(f)
|
| 97 |
-
return f
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
# TODO: find out why this fails on PyPy, https://foss.heptapod.net/pypy/pypy/-/issues/3583
|
| 101 |
-
@pytest.mark.xfail(env.PYPY, reason="Failure on PyPy 3.8 (7.3.7)", strict=False)
|
| 102 |
-
@ignore_pytest_unraisable_warning
|
| 103 |
-
def test_python_alreadyset_in_destructor(monkeypatch, capsys):
|
| 104 |
-
hooked = False
|
| 105 |
-
triggered = False
|
| 106 |
-
|
| 107 |
-
if hasattr(sys, "unraisablehook"): # Python 3.8+
|
| 108 |
-
hooked = True
|
| 109 |
-
# Don't take `sys.unraisablehook`, as that's overwritten by pytest
|
| 110 |
-
default_hook = sys.__unraisablehook__
|
| 111 |
-
|
| 112 |
-
def hook(unraisable_hook_args):
|
| 113 |
-
exc_type, exc_value, exc_tb, err_msg, obj = unraisable_hook_args
|
| 114 |
-
if obj == "already_set demo":
|
| 115 |
-
nonlocal triggered
|
| 116 |
-
triggered = True
|
| 117 |
-
default_hook(unraisable_hook_args)
|
| 118 |
-
return
|
| 119 |
-
|
| 120 |
-
# Use monkeypatch so pytest can apply and remove the patch as appropriate
|
| 121 |
-
monkeypatch.setattr(sys, "unraisablehook", hook)
|
| 122 |
-
|
| 123 |
-
assert m.python_alreadyset_in_destructor("already_set demo") is True
|
| 124 |
-
if hooked:
|
| 125 |
-
assert triggered is True
|
| 126 |
-
|
| 127 |
-
_, captured_stderr = capsys.readouterr()
|
| 128 |
-
assert captured_stderr.startswith("Exception ignored in: 'already_set demo'")
|
| 129 |
-
assert captured_stderr.rstrip().endswith("KeyError: 'bar'")
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
def test_exception_matches():
|
| 133 |
-
assert m.exception_matches()
|
| 134 |
-
assert m.exception_matches_base()
|
| 135 |
-
assert m.modulenotfound_exception_matches_base()
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
def test_custom(msg):
|
| 139 |
-
# Can we catch a MyException?
|
| 140 |
-
with pytest.raises(m.MyException) as excinfo:
|
| 141 |
-
m.throws1()
|
| 142 |
-
assert msg(excinfo.value) == "this error should go to py::exception<MyException>"
|
| 143 |
-
|
| 144 |
-
# Can we catch a MyExceptionUseDeprecatedOperatorCall?
|
| 145 |
-
with pytest.raises(m.MyExceptionUseDeprecatedOperatorCall) as excinfo:
|
| 146 |
-
m.throws1d()
|
| 147 |
-
assert (
|
| 148 |
-
msg(excinfo.value)
|
| 149 |
-
== "this error should go to py::exception<MyExceptionUseDeprecatedOperatorCall>"
|
| 150 |
-
)
|
| 151 |
-
|
| 152 |
-
# Can we translate to standard Python exceptions?
|
| 153 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 154 |
-
m.throws2()
|
| 155 |
-
assert msg(excinfo.value) == "this error should go to a standard Python exception"
|
| 156 |
-
|
| 157 |
-
# Can we handle unknown exceptions?
|
| 158 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 159 |
-
m.throws3()
|
| 160 |
-
assert msg(excinfo.value) == "Caught an unknown exception!"
|
| 161 |
-
|
| 162 |
-
# Can we delegate to another handler by rethrowing?
|
| 163 |
-
with pytest.raises(m.MyException) as excinfo:
|
| 164 |
-
m.throws4()
|
| 165 |
-
assert msg(excinfo.value) == "this error is rethrown"
|
| 166 |
-
|
| 167 |
-
# Can we fall-through to the default handler?
|
| 168 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 169 |
-
m.throws_logic_error()
|
| 170 |
-
assert (
|
| 171 |
-
msg(excinfo.value) == "this error should fall through to the standard handler"
|
| 172 |
-
)
|
| 173 |
-
|
| 174 |
-
# OverFlow error translation.
|
| 175 |
-
with pytest.raises(OverflowError) as excinfo:
|
| 176 |
-
m.throws_overflow_error()
|
| 177 |
-
|
| 178 |
-
# Can we handle a helper-declared exception?
|
| 179 |
-
with pytest.raises(m.MyException5) as excinfo:
|
| 180 |
-
m.throws5()
|
| 181 |
-
assert msg(excinfo.value) == "this is a helper-defined translated exception"
|
| 182 |
-
|
| 183 |
-
# Exception subclassing:
|
| 184 |
-
with pytest.raises(m.MyException5) as excinfo:
|
| 185 |
-
m.throws5_1()
|
| 186 |
-
assert msg(excinfo.value) == "MyException5 subclass"
|
| 187 |
-
assert isinstance(excinfo.value, m.MyException5_1)
|
| 188 |
-
|
| 189 |
-
with pytest.raises(m.MyException5_1) as excinfo:
|
| 190 |
-
m.throws5_1()
|
| 191 |
-
assert msg(excinfo.value) == "MyException5 subclass"
|
| 192 |
-
|
| 193 |
-
with pytest.raises(m.MyException5) as excinfo: # noqa: PT012
|
| 194 |
-
try:
|
| 195 |
-
m.throws5()
|
| 196 |
-
except m.MyException5_1 as err:
|
| 197 |
-
raise RuntimeError("Exception error: caught child from parent") from err
|
| 198 |
-
assert msg(excinfo.value) == "this is a helper-defined translated exception"
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
def test_nested_throws(capture):
|
| 202 |
-
"""Tests nested (e.g. C++ -> Python -> C++) exception handling"""
|
| 203 |
-
|
| 204 |
-
def throw_myex():
|
| 205 |
-
raise m.MyException("nested error")
|
| 206 |
-
|
| 207 |
-
def throw_myex5():
|
| 208 |
-
raise m.MyException5("nested error 5")
|
| 209 |
-
|
| 210 |
-
# In the comments below, the exception is caught in the first step, thrown in the last step
|
| 211 |
-
|
| 212 |
-
# C++ -> Python
|
| 213 |
-
with capture:
|
| 214 |
-
m.try_catch(m.MyException5, throw_myex5)
|
| 215 |
-
assert str(capture).startswith("MyException5: nested error 5")
|
| 216 |
-
|
| 217 |
-
# Python -> C++ -> Python
|
| 218 |
-
with pytest.raises(m.MyException) as excinfo:
|
| 219 |
-
m.try_catch(m.MyException5, throw_myex)
|
| 220 |
-
assert str(excinfo.value) == "nested error"
|
| 221 |
-
|
| 222 |
-
def pycatch(exctype, f, *args): # noqa: ARG001
|
| 223 |
-
try:
|
| 224 |
-
f(*args)
|
| 225 |
-
except m.MyException as e:
|
| 226 |
-
print(e)
|
| 227 |
-
|
| 228 |
-
# C++ -> Python -> C++ -> Python
|
| 229 |
-
with capture:
|
| 230 |
-
m.try_catch(
|
| 231 |
-
m.MyException5,
|
| 232 |
-
pycatch,
|
| 233 |
-
m.MyException,
|
| 234 |
-
m.try_catch,
|
| 235 |
-
m.MyException,
|
| 236 |
-
throw_myex5,
|
| 237 |
-
)
|
| 238 |
-
assert str(capture).startswith("MyException5: nested error 5")
|
| 239 |
-
|
| 240 |
-
# C++ -> Python -> C++
|
| 241 |
-
with capture:
|
| 242 |
-
m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4)
|
| 243 |
-
assert capture == "this error is rethrown"
|
| 244 |
-
|
| 245 |
-
# Python -> C++ -> Python -> C++
|
| 246 |
-
with pytest.raises(m.MyException5) as excinfo:
|
| 247 |
-
m.try_catch(m.MyException, pycatch, m.MyException, m.throws5)
|
| 248 |
-
assert str(excinfo.value) == "this is a helper-defined translated exception"
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
# TODO: Investigate this crash, see pybind/pybind11#5062 for background
|
| 252 |
-
@pytest.mark.skipif(
|
| 253 |
-
sys.platform.startswith("win32") and "Clang" in pybind11_tests.compiler_info,
|
| 254 |
-
reason="Started segfaulting February 2024",
|
| 255 |
-
)
|
| 256 |
-
def test_throw_nested_exception():
|
| 257 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 258 |
-
m.throw_nested_exception()
|
| 259 |
-
assert str(excinfo.value) == "Outer Exception"
|
| 260 |
-
assert str(excinfo.value.__cause__) == "Inner Exception"
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
# This can often happen if you wrap a pybind11 class in a Python wrapper
|
| 264 |
-
def test_invalid_repr():
|
| 265 |
-
class MyRepr:
|
| 266 |
-
def __repr__(self):
|
| 267 |
-
raise AttributeError("Example error")
|
| 268 |
-
|
| 269 |
-
with pytest.raises(TypeError):
|
| 270 |
-
m.simple_bool_passthrough(MyRepr())
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
def test_local_translator(msg):
|
| 274 |
-
"""Tests that a local translator works and that the local translator from
|
| 275 |
-
the cross module is not applied"""
|
| 276 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 277 |
-
m.throws6()
|
| 278 |
-
assert msg(excinfo.value) == "MyException6 only handled in this module"
|
| 279 |
-
|
| 280 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 281 |
-
m.throws_local_error()
|
| 282 |
-
assert not isinstance(excinfo.value, KeyError)
|
| 283 |
-
assert msg(excinfo.value) == "never caught"
|
| 284 |
-
|
| 285 |
-
with pytest.raises(Exception) as excinfo:
|
| 286 |
-
m.throws_local_simple_error()
|
| 287 |
-
assert not isinstance(excinfo.value, cm.LocalSimpleException)
|
| 288 |
-
assert msg(excinfo.value) == "this mod"
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
def test_error_already_set_message_with_unicode_surrogate(): # Issue #4288
|
| 292 |
-
assert m.error_already_set_what(RuntimeError, "\ud927") == (
|
| 293 |
-
"RuntimeError: \\ud927",
|
| 294 |
-
False,
|
| 295 |
-
)
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
def test_error_already_set_message_with_malformed_utf8():
|
| 299 |
-
assert m.error_already_set_what(RuntimeError, b"\x80") == (
|
| 300 |
-
"RuntimeError: b'\\x80'",
|
| 301 |
-
False,
|
| 302 |
-
)
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
class FlakyException(Exception):
|
| 306 |
-
def __init__(self, failure_point):
|
| 307 |
-
if failure_point == "failure_point_init":
|
| 308 |
-
raise ValueError("triggered_failure_point_init")
|
| 309 |
-
self.failure_point = failure_point
|
| 310 |
-
|
| 311 |
-
def __str__(self):
|
| 312 |
-
if self.failure_point == "failure_point_str":
|
| 313 |
-
raise ValueError("triggered_failure_point_str")
|
| 314 |
-
return "FlakyException.__str__"
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
@pytest.mark.parametrize(
|
| 318 |
-
("exc_type", "exc_value", "expected_what"),
|
| 319 |
-
[
|
| 320 |
-
(ValueError, "plain_str", "ValueError: plain_str"),
|
| 321 |
-
(ValueError, ("tuple_elem",), "ValueError: tuple_elem"),
|
| 322 |
-
(FlakyException, ("happy",), "FlakyException: FlakyException.__str__"),
|
| 323 |
-
],
|
| 324 |
-
)
|
| 325 |
-
def test_error_already_set_what_with_happy_exceptions(
|
| 326 |
-
exc_type, exc_value, expected_what
|
| 327 |
-
):
|
| 328 |
-
what, py_err_set_after_what = m.error_already_set_what(exc_type, exc_value)
|
| 329 |
-
assert not py_err_set_after_what
|
| 330 |
-
assert what == expected_what
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
def _test_flaky_exception_failure_point_init_before_py_3_12():
|
| 334 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 335 |
-
m.error_already_set_what(FlakyException, ("failure_point_init",))
|
| 336 |
-
lines = str(excinfo.value).splitlines()
|
| 337 |
-
# PyErr_NormalizeException replaces the original FlakyException with ValueError:
|
| 338 |
-
assert lines[:3] == [
|
| 339 |
-
"pybind11::error_already_set: MISMATCH of original and normalized active exception types:"
|
| 340 |
-
" ORIGINAL FlakyException REPLACED BY ValueError: triggered_failure_point_init",
|
| 341 |
-
"",
|
| 342 |
-
"At:",
|
| 343 |
-
]
|
| 344 |
-
# Checking the first two lines of the traceback as formatted in error_string():
|
| 345 |
-
assert "test_exceptions.py(" in lines[3]
|
| 346 |
-
assert lines[3].endswith("): __init__")
|
| 347 |
-
assert lines[4].endswith(
|
| 348 |
-
"): _test_flaky_exception_failure_point_init_before_py_3_12"
|
| 349 |
-
)
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
def _test_flaky_exception_failure_point_init_py_3_12():
|
| 353 |
-
# Behavior change in Python 3.12: https://github.com/python/cpython/issues/102594
|
| 354 |
-
what, py_err_set_after_what = m.error_already_set_what(
|
| 355 |
-
FlakyException, ("failure_point_init",)
|
| 356 |
-
)
|
| 357 |
-
assert not py_err_set_after_what
|
| 358 |
-
lines = what.splitlines()
|
| 359 |
-
assert lines[0].endswith("ValueError[WITH __notes__]: triggered_failure_point_init")
|
| 360 |
-
assert lines[1] == "__notes__ (len=1):"
|
| 361 |
-
assert "Normalization failed:" in lines[2]
|
| 362 |
-
assert "FlakyException" in lines[2]
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
@pytest.mark.skipif(
|
| 366 |
-
"env.PYPY and sys.version_info[:2] < (3, 12)",
|
| 367 |
-
reason="PyErr_NormalizeException Segmentation fault",
|
| 368 |
-
)
|
| 369 |
-
def test_flaky_exception_failure_point_init():
|
| 370 |
-
if sys.version_info[:2] < (3, 12):
|
| 371 |
-
_test_flaky_exception_failure_point_init_before_py_3_12()
|
| 372 |
-
else:
|
| 373 |
-
_test_flaky_exception_failure_point_init_py_3_12()
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
def test_flaky_exception_failure_point_str():
|
| 377 |
-
what, py_err_set_after_what = m.error_already_set_what(
|
| 378 |
-
FlakyException, ("failure_point_str",)
|
| 379 |
-
)
|
| 380 |
-
assert not py_err_set_after_what
|
| 381 |
-
lines = what.splitlines()
|
| 382 |
-
n = 3 if env.PYPY and len(lines) == 3 else 5
|
| 383 |
-
assert (
|
| 384 |
-
lines[:n]
|
| 385 |
-
== [
|
| 386 |
-
"FlakyException: <MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>",
|
| 387 |
-
"",
|
| 388 |
-
"MESSAGE UNAVAILABLE DUE TO EXCEPTION: ValueError: triggered_failure_point_str",
|
| 389 |
-
"",
|
| 390 |
-
"At:",
|
| 391 |
-
][:n]
|
| 392 |
-
)
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
def test_cross_module_interleaved_error_already_set():
|
| 396 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 397 |
-
m.test_cross_module_interleaved_error_already_set()
|
| 398 |
-
assert str(excinfo.value) in (
|
| 399 |
-
"2nd error.", # Almost all platforms.
|
| 400 |
-
"RuntimeError: 2nd error.", # Some PyPy builds (seen under macOS).
|
| 401 |
-
)
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
def test_error_already_set_double_restore():
|
| 405 |
-
m.test_error_already_set_double_restore(True) # dry_run
|
| 406 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 407 |
-
m.test_error_already_set_double_restore(False)
|
| 408 |
-
assert str(excinfo.value) == (
|
| 409 |
-
"Internal error: pybind11::detail::error_fetch_and_normalize::restore()"
|
| 410 |
-
" called a second time. ORIGINAL ERROR: ValueError: Random error."
|
| 411 |
-
)
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
def test_pypy_oserror_normalization():
|
| 415 |
-
# https://github.com/pybind/pybind11/issues/4075
|
| 416 |
-
what = m.test_pypy_oserror_normalization()
|
| 417 |
-
assert "this_filename_must_not_exist" in what
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
def test_fn_cast_int_exception():
|
| 421 |
-
with pytest.raises(RuntimeError) as excinfo:
|
| 422 |
-
m.test_fn_cast_int(lambda: None)
|
| 423 |
-
|
| 424 |
-
assert str(excinfo.value).startswith(
|
| 425 |
-
"Unable to cast Python instance of type <class 'NoneType'> to C++ type"
|
| 426 |
-
)
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
def test_return_exception_void():
|
| 430 |
-
with pytest.raises(TypeError) as excinfo:
|
| 431 |
-
m.return_exception_void()
|
| 432 |
-
assert "Exception" in str(excinfo.value)
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
import env
|
| 6 |
+
import pybind11_cross_module_tests as cm
|
| 7 |
+
import pybind11_tests
|
| 8 |
+
from pybind11_tests import exceptions as m
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def test_std_exception(msg):
|
| 12 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 13 |
+
m.throw_std_exception()
|
| 14 |
+
assert msg(excinfo.value) == "This exception was intentionally thrown."
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def test_error_already_set(msg):
|
| 18 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 19 |
+
m.throw_already_set(False)
|
| 20 |
+
assert (
|
| 21 |
+
msg(excinfo.value)
|
| 22 |
+
== "Internal error: pybind11::error_already_set called while Python error indicator not set."
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
with pytest.raises(ValueError) as excinfo:
|
| 26 |
+
m.throw_already_set(True)
|
| 27 |
+
assert msg(excinfo.value) == "foo"
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def test_raise_from(msg):
|
| 31 |
+
with pytest.raises(ValueError) as excinfo:
|
| 32 |
+
m.raise_from()
|
| 33 |
+
assert msg(excinfo.value) == "outer"
|
| 34 |
+
assert msg(excinfo.value.__cause__) == "inner"
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def test_raise_from_already_set(msg):
|
| 38 |
+
with pytest.raises(ValueError) as excinfo:
|
| 39 |
+
m.raise_from_already_set()
|
| 40 |
+
assert msg(excinfo.value) == "outer"
|
| 41 |
+
assert msg(excinfo.value.__cause__) == "inner"
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def test_cross_module_exceptions(msg):
|
| 45 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 46 |
+
cm.raise_runtime_error()
|
| 47 |
+
assert str(excinfo.value) == "My runtime error"
|
| 48 |
+
|
| 49 |
+
with pytest.raises(ValueError) as excinfo:
|
| 50 |
+
cm.raise_value_error()
|
| 51 |
+
assert str(excinfo.value) == "My value error"
|
| 52 |
+
|
| 53 |
+
with pytest.raises(ValueError) as excinfo:
|
| 54 |
+
cm.throw_pybind_value_error()
|
| 55 |
+
assert str(excinfo.value) == "pybind11 value error"
|
| 56 |
+
|
| 57 |
+
with pytest.raises(TypeError) as excinfo:
|
| 58 |
+
cm.throw_pybind_type_error()
|
| 59 |
+
assert str(excinfo.value) == "pybind11 type error"
|
| 60 |
+
|
| 61 |
+
with pytest.raises(StopIteration) as excinfo:
|
| 62 |
+
cm.throw_stop_iteration()
|
| 63 |
+
|
| 64 |
+
with pytest.raises(cm.LocalSimpleException) as excinfo:
|
| 65 |
+
cm.throw_local_simple_error()
|
| 66 |
+
assert msg(excinfo.value) == "external mod"
|
| 67 |
+
|
| 68 |
+
with pytest.raises(KeyError) as excinfo:
|
| 69 |
+
cm.throw_local_error()
|
| 70 |
+
# KeyError is a repr of the key, so it has an extra set of quotes
|
| 71 |
+
assert str(excinfo.value) == "'just local'"
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
# TODO: FIXME
|
| 75 |
+
@pytest.mark.xfail(
|
| 76 |
+
"env.MACOS and (env.PYPY or pybind11_tests.compiler_info.startswith('Homebrew Clang'))",
|
| 77 |
+
raises=RuntimeError,
|
| 78 |
+
reason="See Issue #2847, PR #2999, PR #4324",
|
| 79 |
+
)
|
| 80 |
+
def test_cross_module_exception_translator():
|
| 81 |
+
with pytest.raises(KeyError):
|
| 82 |
+
# translator registered in cross_module_tests
|
| 83 |
+
m.throw_should_be_translated_to_key_error()
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def test_python_call_in_catch():
|
| 87 |
+
d = {}
|
| 88 |
+
assert m.python_call_in_destructor(d) is True
|
| 89 |
+
assert d["good"] is True
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def ignore_pytest_unraisable_warning(f):
|
| 93 |
+
unraisable = "PytestUnraisableExceptionWarning"
|
| 94 |
+
if hasattr(pytest, unraisable): # Python >= 3.8 and pytest >= 6
|
| 95 |
+
dec = pytest.mark.filterwarnings(f"ignore::pytest.{unraisable}")
|
| 96 |
+
return dec(f)
|
| 97 |
+
return f
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
# TODO: find out why this fails on PyPy, https://foss.heptapod.net/pypy/pypy/-/issues/3583
|
| 101 |
+
@pytest.mark.xfail(env.PYPY, reason="Failure on PyPy 3.8 (7.3.7)", strict=False)
|
| 102 |
+
@ignore_pytest_unraisable_warning
|
| 103 |
+
def test_python_alreadyset_in_destructor(monkeypatch, capsys):
|
| 104 |
+
hooked = False
|
| 105 |
+
triggered = False
|
| 106 |
+
|
| 107 |
+
if hasattr(sys, "unraisablehook"): # Python 3.8+
|
| 108 |
+
hooked = True
|
| 109 |
+
# Don't take `sys.unraisablehook`, as that's overwritten by pytest
|
| 110 |
+
default_hook = sys.__unraisablehook__
|
| 111 |
+
|
| 112 |
+
def hook(unraisable_hook_args):
|
| 113 |
+
exc_type, exc_value, exc_tb, err_msg, obj = unraisable_hook_args
|
| 114 |
+
if obj == "already_set demo":
|
| 115 |
+
nonlocal triggered
|
| 116 |
+
triggered = True
|
| 117 |
+
default_hook(unraisable_hook_args)
|
| 118 |
+
return
|
| 119 |
+
|
| 120 |
+
# Use monkeypatch so pytest can apply and remove the patch as appropriate
|
| 121 |
+
monkeypatch.setattr(sys, "unraisablehook", hook)
|
| 122 |
+
|
| 123 |
+
assert m.python_alreadyset_in_destructor("already_set demo") is True
|
| 124 |
+
if hooked:
|
| 125 |
+
assert triggered is True
|
| 126 |
+
|
| 127 |
+
_, captured_stderr = capsys.readouterr()
|
| 128 |
+
assert captured_stderr.startswith("Exception ignored in: 'already_set demo'")
|
| 129 |
+
assert captured_stderr.rstrip().endswith("KeyError: 'bar'")
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def test_exception_matches():
|
| 133 |
+
assert m.exception_matches()
|
| 134 |
+
assert m.exception_matches_base()
|
| 135 |
+
assert m.modulenotfound_exception_matches_base()
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def test_custom(msg):
|
| 139 |
+
# Can we catch a MyException?
|
| 140 |
+
with pytest.raises(m.MyException) as excinfo:
|
| 141 |
+
m.throws1()
|
| 142 |
+
assert msg(excinfo.value) == "this error should go to py::exception<MyException>"
|
| 143 |
+
|
| 144 |
+
# Can we catch a MyExceptionUseDeprecatedOperatorCall?
|
| 145 |
+
with pytest.raises(m.MyExceptionUseDeprecatedOperatorCall) as excinfo:
|
| 146 |
+
m.throws1d()
|
| 147 |
+
assert (
|
| 148 |
+
msg(excinfo.value)
|
| 149 |
+
== "this error should go to py::exception<MyExceptionUseDeprecatedOperatorCall>"
|
| 150 |
+
)
|
| 151 |
+
|
| 152 |
+
# Can we translate to standard Python exceptions?
|
| 153 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 154 |
+
m.throws2()
|
| 155 |
+
assert msg(excinfo.value) == "this error should go to a standard Python exception"
|
| 156 |
+
|
| 157 |
+
# Can we handle unknown exceptions?
|
| 158 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 159 |
+
m.throws3()
|
| 160 |
+
assert msg(excinfo.value) == "Caught an unknown exception!"
|
| 161 |
+
|
| 162 |
+
# Can we delegate to another handler by rethrowing?
|
| 163 |
+
with pytest.raises(m.MyException) as excinfo:
|
| 164 |
+
m.throws4()
|
| 165 |
+
assert msg(excinfo.value) == "this error is rethrown"
|
| 166 |
+
|
| 167 |
+
# Can we fall-through to the default handler?
|
| 168 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 169 |
+
m.throws_logic_error()
|
| 170 |
+
assert (
|
| 171 |
+
msg(excinfo.value) == "this error should fall through to the standard handler"
|
| 172 |
+
)
|
| 173 |
+
|
| 174 |
+
# OverFlow error translation.
|
| 175 |
+
with pytest.raises(OverflowError) as excinfo:
|
| 176 |
+
m.throws_overflow_error()
|
| 177 |
+
|
| 178 |
+
# Can we handle a helper-declared exception?
|
| 179 |
+
with pytest.raises(m.MyException5) as excinfo:
|
| 180 |
+
m.throws5()
|
| 181 |
+
assert msg(excinfo.value) == "this is a helper-defined translated exception"
|
| 182 |
+
|
| 183 |
+
# Exception subclassing:
|
| 184 |
+
with pytest.raises(m.MyException5) as excinfo:
|
| 185 |
+
m.throws5_1()
|
| 186 |
+
assert msg(excinfo.value) == "MyException5 subclass"
|
| 187 |
+
assert isinstance(excinfo.value, m.MyException5_1)
|
| 188 |
+
|
| 189 |
+
with pytest.raises(m.MyException5_1) as excinfo:
|
| 190 |
+
m.throws5_1()
|
| 191 |
+
assert msg(excinfo.value) == "MyException5 subclass"
|
| 192 |
+
|
| 193 |
+
with pytest.raises(m.MyException5) as excinfo: # noqa: PT012
|
| 194 |
+
try:
|
| 195 |
+
m.throws5()
|
| 196 |
+
except m.MyException5_1 as err:
|
| 197 |
+
raise RuntimeError("Exception error: caught child from parent") from err
|
| 198 |
+
assert msg(excinfo.value) == "this is a helper-defined translated exception"
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
def test_nested_throws(capture):
|
| 202 |
+
"""Tests nested (e.g. C++ -> Python -> C++) exception handling"""
|
| 203 |
+
|
| 204 |
+
def throw_myex():
|
| 205 |
+
raise m.MyException("nested error")
|
| 206 |
+
|
| 207 |
+
def throw_myex5():
|
| 208 |
+
raise m.MyException5("nested error 5")
|
| 209 |
+
|
| 210 |
+
# In the comments below, the exception is caught in the first step, thrown in the last step
|
| 211 |
+
|
| 212 |
+
# C++ -> Python
|
| 213 |
+
with capture:
|
| 214 |
+
m.try_catch(m.MyException5, throw_myex5)
|
| 215 |
+
assert str(capture).startswith("MyException5: nested error 5")
|
| 216 |
+
|
| 217 |
+
# Python -> C++ -> Python
|
| 218 |
+
with pytest.raises(m.MyException) as excinfo:
|
| 219 |
+
m.try_catch(m.MyException5, throw_myex)
|
| 220 |
+
assert str(excinfo.value) == "nested error"
|
| 221 |
+
|
| 222 |
+
def pycatch(exctype, f, *args): # noqa: ARG001
|
| 223 |
+
try:
|
| 224 |
+
f(*args)
|
| 225 |
+
except m.MyException as e:
|
| 226 |
+
print(e)
|
| 227 |
+
|
| 228 |
+
# C++ -> Python -> C++ -> Python
|
| 229 |
+
with capture:
|
| 230 |
+
m.try_catch(
|
| 231 |
+
m.MyException5,
|
| 232 |
+
pycatch,
|
| 233 |
+
m.MyException,
|
| 234 |
+
m.try_catch,
|
| 235 |
+
m.MyException,
|
| 236 |
+
throw_myex5,
|
| 237 |
+
)
|
| 238 |
+
assert str(capture).startswith("MyException5: nested error 5")
|
| 239 |
+
|
| 240 |
+
# C++ -> Python -> C++
|
| 241 |
+
with capture:
|
| 242 |
+
m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4)
|
| 243 |
+
assert capture == "this error is rethrown"
|
| 244 |
+
|
| 245 |
+
# Python -> C++ -> Python -> C++
|
| 246 |
+
with pytest.raises(m.MyException5) as excinfo:
|
| 247 |
+
m.try_catch(m.MyException, pycatch, m.MyException, m.throws5)
|
| 248 |
+
assert str(excinfo.value) == "this is a helper-defined translated exception"
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
# TODO: Investigate this crash, see pybind/pybind11#5062 for background
|
| 252 |
+
@pytest.mark.skipif(
|
| 253 |
+
sys.platform.startswith("win32") and "Clang" in pybind11_tests.compiler_info,
|
| 254 |
+
reason="Started segfaulting February 2024",
|
| 255 |
+
)
|
| 256 |
+
def test_throw_nested_exception():
|
| 257 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 258 |
+
m.throw_nested_exception()
|
| 259 |
+
assert str(excinfo.value) == "Outer Exception"
|
| 260 |
+
assert str(excinfo.value.__cause__) == "Inner Exception"
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
# This can often happen if you wrap a pybind11 class in a Python wrapper
|
| 264 |
+
def test_invalid_repr():
|
| 265 |
+
class MyRepr:
|
| 266 |
+
def __repr__(self):
|
| 267 |
+
raise AttributeError("Example error")
|
| 268 |
+
|
| 269 |
+
with pytest.raises(TypeError):
|
| 270 |
+
m.simple_bool_passthrough(MyRepr())
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
def test_local_translator(msg):
|
| 274 |
+
"""Tests that a local translator works and that the local translator from
|
| 275 |
+
the cross module is not applied"""
|
| 276 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 277 |
+
m.throws6()
|
| 278 |
+
assert msg(excinfo.value) == "MyException6 only handled in this module"
|
| 279 |
+
|
| 280 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 281 |
+
m.throws_local_error()
|
| 282 |
+
assert not isinstance(excinfo.value, KeyError)
|
| 283 |
+
assert msg(excinfo.value) == "never caught"
|
| 284 |
+
|
| 285 |
+
with pytest.raises(Exception) as excinfo:
|
| 286 |
+
m.throws_local_simple_error()
|
| 287 |
+
assert not isinstance(excinfo.value, cm.LocalSimpleException)
|
| 288 |
+
assert msg(excinfo.value) == "this mod"
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
def test_error_already_set_message_with_unicode_surrogate(): # Issue #4288
|
| 292 |
+
assert m.error_already_set_what(RuntimeError, "\ud927") == (
|
| 293 |
+
"RuntimeError: \\ud927",
|
| 294 |
+
False,
|
| 295 |
+
)
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
def test_error_already_set_message_with_malformed_utf8():
|
| 299 |
+
assert m.error_already_set_what(RuntimeError, b"\x80") == (
|
| 300 |
+
"RuntimeError: b'\\x80'",
|
| 301 |
+
False,
|
| 302 |
+
)
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
class FlakyException(Exception):
|
| 306 |
+
def __init__(self, failure_point):
|
| 307 |
+
if failure_point == "failure_point_init":
|
| 308 |
+
raise ValueError("triggered_failure_point_init")
|
| 309 |
+
self.failure_point = failure_point
|
| 310 |
+
|
| 311 |
+
def __str__(self):
|
| 312 |
+
if self.failure_point == "failure_point_str":
|
| 313 |
+
raise ValueError("triggered_failure_point_str")
|
| 314 |
+
return "FlakyException.__str__"
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
@pytest.mark.parametrize(
|
| 318 |
+
("exc_type", "exc_value", "expected_what"),
|
| 319 |
+
[
|
| 320 |
+
(ValueError, "plain_str", "ValueError: plain_str"),
|
| 321 |
+
(ValueError, ("tuple_elem",), "ValueError: tuple_elem"),
|
| 322 |
+
(FlakyException, ("happy",), "FlakyException: FlakyException.__str__"),
|
| 323 |
+
],
|
| 324 |
+
)
|
| 325 |
+
def test_error_already_set_what_with_happy_exceptions(
|
| 326 |
+
exc_type, exc_value, expected_what
|
| 327 |
+
):
|
| 328 |
+
what, py_err_set_after_what = m.error_already_set_what(exc_type, exc_value)
|
| 329 |
+
assert not py_err_set_after_what
|
| 330 |
+
assert what == expected_what
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
def _test_flaky_exception_failure_point_init_before_py_3_12():
|
| 334 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 335 |
+
m.error_already_set_what(FlakyException, ("failure_point_init",))
|
| 336 |
+
lines = str(excinfo.value).splitlines()
|
| 337 |
+
# PyErr_NormalizeException replaces the original FlakyException with ValueError:
|
| 338 |
+
assert lines[:3] == [
|
| 339 |
+
"pybind11::error_already_set: MISMATCH of original and normalized active exception types:"
|
| 340 |
+
" ORIGINAL FlakyException REPLACED BY ValueError: triggered_failure_point_init",
|
| 341 |
+
"",
|
| 342 |
+
"At:",
|
| 343 |
+
]
|
| 344 |
+
# Checking the first two lines of the traceback as formatted in error_string():
|
| 345 |
+
assert "test_exceptions.py(" in lines[3]
|
| 346 |
+
assert lines[3].endswith("): __init__")
|
| 347 |
+
assert lines[4].endswith(
|
| 348 |
+
"): _test_flaky_exception_failure_point_init_before_py_3_12"
|
| 349 |
+
)
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
def _test_flaky_exception_failure_point_init_py_3_12():
|
| 353 |
+
# Behavior change in Python 3.12: https://github.com/python/cpython/issues/102594
|
| 354 |
+
what, py_err_set_after_what = m.error_already_set_what(
|
| 355 |
+
FlakyException, ("failure_point_init",)
|
| 356 |
+
)
|
| 357 |
+
assert not py_err_set_after_what
|
| 358 |
+
lines = what.splitlines()
|
| 359 |
+
assert lines[0].endswith("ValueError[WITH __notes__]: triggered_failure_point_init")
|
| 360 |
+
assert lines[1] == "__notes__ (len=1):"
|
| 361 |
+
assert "Normalization failed:" in lines[2]
|
| 362 |
+
assert "FlakyException" in lines[2]
|
| 363 |
+
|
| 364 |
+
|
| 365 |
+
@pytest.mark.skipif(
|
| 366 |
+
"env.PYPY and sys.version_info[:2] < (3, 12)",
|
| 367 |
+
reason="PyErr_NormalizeException Segmentation fault",
|
| 368 |
+
)
|
| 369 |
+
def test_flaky_exception_failure_point_init():
|
| 370 |
+
if sys.version_info[:2] < (3, 12):
|
| 371 |
+
_test_flaky_exception_failure_point_init_before_py_3_12()
|
| 372 |
+
else:
|
| 373 |
+
_test_flaky_exception_failure_point_init_py_3_12()
|
| 374 |
+
|
| 375 |
+
|
| 376 |
+
def test_flaky_exception_failure_point_str():
|
| 377 |
+
what, py_err_set_after_what = m.error_already_set_what(
|
| 378 |
+
FlakyException, ("failure_point_str",)
|
| 379 |
+
)
|
| 380 |
+
assert not py_err_set_after_what
|
| 381 |
+
lines = what.splitlines()
|
| 382 |
+
n = 3 if env.PYPY and len(lines) == 3 else 5
|
| 383 |
+
assert (
|
| 384 |
+
lines[:n]
|
| 385 |
+
== [
|
| 386 |
+
"FlakyException: <MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>",
|
| 387 |
+
"",
|
| 388 |
+
"MESSAGE UNAVAILABLE DUE TO EXCEPTION: ValueError: triggered_failure_point_str",
|
| 389 |
+
"",
|
| 390 |
+
"At:",
|
| 391 |
+
][:n]
|
| 392 |
+
)
|
| 393 |
+
|
| 394 |
+
|
| 395 |
+
def test_cross_module_interleaved_error_already_set():
|
| 396 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 397 |
+
m.test_cross_module_interleaved_error_already_set()
|
| 398 |
+
assert str(excinfo.value) in (
|
| 399 |
+
"2nd error.", # Almost all platforms.
|
| 400 |
+
"RuntimeError: 2nd error.", # Some PyPy builds (seen under macOS).
|
| 401 |
+
)
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
def test_error_already_set_double_restore():
|
| 405 |
+
m.test_error_already_set_double_restore(True) # dry_run
|
| 406 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 407 |
+
m.test_error_already_set_double_restore(False)
|
| 408 |
+
assert str(excinfo.value) == (
|
| 409 |
+
"Internal error: pybind11::detail::error_fetch_and_normalize::restore()"
|
| 410 |
+
" called a second time. ORIGINAL ERROR: ValueError: Random error."
|
| 411 |
+
)
|
| 412 |
+
|
| 413 |
+
|
| 414 |
+
def test_pypy_oserror_normalization():
|
| 415 |
+
# https://github.com/pybind/pybind11/issues/4075
|
| 416 |
+
what = m.test_pypy_oserror_normalization()
|
| 417 |
+
assert "this_filename_must_not_exist" in what
|
| 418 |
+
|
| 419 |
+
|
| 420 |
+
def test_fn_cast_int_exception():
|
| 421 |
+
with pytest.raises(RuntimeError) as excinfo:
|
| 422 |
+
m.test_fn_cast_int(lambda: None)
|
| 423 |
+
|
| 424 |
+
assert str(excinfo.value).startswith(
|
| 425 |
+
"Unable to cast Python instance of type <class 'NoneType'> to C++ type"
|
| 426 |
+
)
|
| 427 |
+
|
| 428 |
+
|
| 429 |
+
def test_return_exception_void():
|
| 430 |
+
with pytest.raises(TypeError) as excinfo:
|
| 431 |
+
m.return_exception_void()
|
| 432 |
+
assert "Exception" in str(excinfo.value)
|