Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
gaoqiong
pybind11
Commits
c50f90ec
Unverified
Commit
c50f90ec
authored
Oct 16, 2020
by
Henry Schreiner
Committed by
GitHub
Oct 16, 2020
Browse files
style: use Black everywhere (#2594)
* style: use Black everywhere * style: minor touchup from review
parent
2e31e466
Changes
38
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
768 additions
and
464 deletions
+768
-464
.pre-commit-config.yaml
.pre-commit-config.yaml
+1
-2
docs/benchmark.py
docs/benchmark.py
+20
-17
docs/conf.py
docs/conf.py
+94
-94
tests/conftest.py
tests/conftest.py
+17
-9
tests/test_buffers.py
tests/test_buffers.py
+9
-9
tests/test_builtin_casters.py
tests/test_builtin_casters.py
+85
-54
tests/test_call_policies.py
tests/test_call_policies.py
+39
-12
tests/test_callbacks.py
tests/test_callbacks.py
+21
-10
tests/test_chrono.py
tests/test_chrono.py
+23
-17
tests/test_class.py
tests/test_class.py
+82
-35
tests/test_copy_move.py
tests/test_copy_move.py
+16
-4
tests/test_custom_type_casters.py
tests/test_custom_type_casters.py
+36
-10
tests/test_docstring_options.py
tests/test_docstring_options.py
+5
-5
tests/test_eigen.py
tests/test_eigen.py
+182
-109
tests/test_enum.py
tests/test_enum.py
+18
-10
tests/test_eval_call.py
tests/test_eval_call.py
+1
-1
tests/test_exceptions.py
tests/test_exceptions.py
+15
-8
tests/test_factory_constructors.py
tests/test_factory_constructors.py
+75
-35
tests/test_gil_scoped.py
tests/test_gil_scoped.py
+4
-1
tests/test_iostream.py
tests/test_iostream.py
+25
-22
No files found.
.pre-commit-config.yaml
View file @
c50f90ec
...
...
@@ -36,8 +36,7 @@ repos:
-
id
:
black
# By default, this ignores pyi files, though black supports them
types
:
[
text
]
# Not all Python files are Blacked, yet
files
:
^(setup.py|pybind11|tests/extra|tools).*\.pyi?$
files
:
\.pyi?$
# Changes tabs to spaces
-
repo
:
https://github.com/Lucas-C/pre-commit-hooks
...
...
docs/benchmark.py
View file @
c50f90ec
...
...
@@ -14,7 +14,7 @@ def generate_dummy_code_pybind11(nclasses=10):
for
cl
in
range
(
nclasses
):
decl
+=
"class cl%03i;
\n
"
%
cl
decl
+=
'
\n
'
decl
+=
"
\n
"
for
cl
in
range
(
nclasses
):
decl
+=
"class cl%03i {
\n
"
%
cl
...
...
@@ -22,18 +22,17 @@ def generate_dummy_code_pybind11(nclasses=10):
bindings
+=
' py::class_<cl%03i>(m, "cl%03i")
\n
'
%
(
cl
,
cl
)
for
fn
in
range
(
nfns
):
ret
=
random
.
randint
(
0
,
nclasses
-
1
)
params
=
[
random
.
randint
(
0
,
nclasses
-
1
)
for
i
in
range
(
nargs
)]
params
=
[
random
.
randint
(
0
,
nclasses
-
1
)
for
i
in
range
(
nargs
)]
decl
+=
" cl%03i *fn_%03i("
%
(
ret
,
fn
)
decl
+=
", "
.
join
(
"cl%03i *"
%
p
for
p
in
params
)
decl
+=
");
\n
"
bindings
+=
' .def("fn_%03i", &cl%03i::fn_%03i)
\n
'
%
\
(
fn
,
cl
,
fn
)
bindings
+=
' .def("fn_%03i", &cl%03i::fn_%03i)
\n
'
%
(
fn
,
cl
,
fn
)
decl
+=
"};
\n\n
"
bindings
+=
'
;
\n
'
bindings
+=
"
;
\n
"
result
=
"#include <pybind11/pybind11.h>
\n\n
"
result
+=
"namespace py = pybind11;
\n\n
"
result
+=
decl
+
'
\n
'
result
+=
decl
+
"
\n
"
result
+=
"PYBIND11_MODULE(example, m) {
\n
"
result
+=
bindings
result
+=
"}"
...
...
@@ -46,7 +45,7 @@ def generate_dummy_code_boost(nclasses=10):
for
cl
in
range
(
nclasses
):
decl
+=
"class cl%03i;
\n
"
%
cl
decl
+=
'
\n
'
decl
+=
"
\n
"
for
cl
in
range
(
nclasses
):
decl
+=
"class cl%03i {
\n
"
%
cl
...
...
@@ -54,18 +53,20 @@ def generate_dummy_code_boost(nclasses=10):
bindings
+=
' py::class_<cl%03i>("cl%03i")
\n
'
%
(
cl
,
cl
)
for
fn
in
range
(
nfns
):
ret
=
random
.
randint
(
0
,
nclasses
-
1
)
params
=
[
random
.
randint
(
0
,
nclasses
-
1
)
for
i
in
range
(
nargs
)]
params
=
[
random
.
randint
(
0
,
nclasses
-
1
)
for
i
in
range
(
nargs
)]
decl
+=
" cl%03i *fn_%03i("
%
(
ret
,
fn
)
decl
+=
", "
.
join
(
"cl%03i *"
%
p
for
p
in
params
)
decl
+=
");
\n
"
bindings
+=
' .def("fn_%03i", &cl%03i::fn_%03i, py::return_value_policy<py::manage_new_object>())
\n
'
%
\
(
fn
,
cl
,
fn
)
bindings
+=
(
' .def("fn_%03i", &cl%03i::fn_%03i, py::return_value_policy<py::manage_new_object>())
\n
'
%
(
fn
,
cl
,
fn
)
)
decl
+=
"};
\n\n
"
bindings
+=
'
;
\n
'
bindings
+=
"
;
\n
"
result
=
"#include <boost/python.hpp>
\n\n
"
result
+=
"namespace py = boost::python;
\n\n
"
result
+=
decl
+
'
\n
'
result
+=
decl
+
"
\n
"
result
+=
"BOOST_PYTHON_MODULE(example) {
\n
"
result
+=
bindings
result
+=
"}"
...
...
@@ -73,17 +74,19 @@ def generate_dummy_code_boost(nclasses=10):
for
codegen
in
[
generate_dummy_code_pybind11
,
generate_dummy_code_boost
]:
print
(
"{"
)
print
(
"{"
)
for
i
in
range
(
0
,
10
):
nclasses
=
2
**
i
with
open
(
"test.cpp"
,
"w"
)
as
f
:
f
.
write
(
codegen
(
nclasses
))
n1
=
dt
.
datetime
.
now
()
os
.
system
(
"g++ -Os -shared -rdynamic -undefined dynamic_lookup "
os
.
system
(
"g++ -Os -shared -rdynamic -undefined dynamic_lookup "
"-fvisibility=hidden -std=c++14 test.cpp -I include "
"-I /System/Library/Frameworks/Python.framework/Headers -o test.so"
)
"-I /System/Library/Frameworks/Python.framework/Headers -o test.so"
)
n2
=
dt
.
datetime
.
now
()
elapsed
=
(
n2
-
n1
).
total_seconds
()
size
=
os
.
stat
(
'
test.so
'
).
st_size
size
=
os
.
stat
(
"
test.so
"
).
st_size
print
(
" {%i, %f, %i},"
%
(
nclasses
*
nfns
,
elapsed
,
size
))
print
(
"}"
)
print
(
"}"
)
docs/conf.py
View file @
c50f90ec
...
...
@@ -21,40 +21,44 @@ import subprocess
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
#
sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
#
needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions
=
[
'breathe'
,
'sphinxcontrib.rsvgconverter'
,
'sphinxcontrib.moderncmakedomain'
]
extensions
=
[
"breathe"
,
"sphinxcontrib.rsvgconverter"
,
"sphinxcontrib.moderncmakedomain"
,
]
breathe_projects
=
{
'
pybind11
'
:
'
.build/doxygenxml/
'
}
breathe_default_project
=
'
pybind11
'
breathe_domain_by_extension
=
{
'h'
:
'
cpp
'
}
breathe_projects
=
{
"
pybind11
"
:
"
.build/doxygenxml/
"
}
breathe_default_project
=
"
pybind11
"
breathe_domain_by_extension
=
{
"h"
:
"
cpp
"
}
# Add any paths that contain templates here, relative to this directory.
templates_path
=
[
'
.templates
'
]
templates_path
=
[
"
.templates
"
]
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix
=
'
.rst
'
source_suffix
=
"
.rst
"
# The encoding of source files.
#source_encoding = 'utf-8-sig'
#
source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc
=
'
index
'
master_doc
=
"
index
"
# General information about the project.
project
=
'
pybind11
'
copyright
=
'
2017, Wenzel Jakob
'
author
=
'
Wenzel Jakob
'
project
=
"
pybind11
"
copyright
=
"
2017, Wenzel Jakob
"
author
=
"
Wenzel Jakob
"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
...
...
@@ -78,37 +82,37 @@ language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
#
today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
#
today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns
=
[
'
.build
'
,
'
release.rst
'
]
exclude_patterns
=
[
"
.build
"
,
"
release.rst
"
]
# The reST default role (used for this markup: `text`) to use for all
# documents.
default_role
=
'
any
'
default_role
=
"
any
"
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
#
add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
#
add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
#
show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
#pygments_style = 'monokai'
#
pygments_style = 'monokai'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
#
modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
#
keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos
=
False
...
...
@@ -119,144 +123,137 @@ todo_include_todos = False
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
on_rtd
=
os
.
environ
.
get
(
'
READTHEDOCS
'
,
None
)
==
'
True
'
on_rtd
=
os
.
environ
.
get
(
"
READTHEDOCS
"
,
None
)
==
"
True
"
if
not
on_rtd
:
# only import and set the theme if we're building docs locally
import
sphinx_rtd_theme
html_theme
=
'sphinx_rtd_theme'
html_theme
=
"sphinx_rtd_theme"
html_theme_path
=
[
sphinx_rtd_theme
.
get_html_theme_path
()]
html_context
=
{
'css_files'
:
[
'_static/theme_overrides.css'
]
}
html_context
=
{
"css_files"
:
[
"_static/theme_overrides.css"
]}
else
:
html_context
=
{
'
css_files
'
:
[
'
//media.readthedocs.org/css/sphinx_rtd_theme.css
'
,
'
//media.readthedocs.org/css/readthedocs-doc-embed.css
'
,
'
_static/theme_overrides.css
'
"
css_files
"
:
[
"
//media.readthedocs.org/css/sphinx_rtd_theme.css
"
,
"
//media.readthedocs.org/css/readthedocs-doc-embed.css
"
,
"
_static/theme_overrides.css
"
,
]
}
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
#
html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
#
html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<version> documentation".
#html_title = None
#
html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
#
html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
#
html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
#
html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path
=
[
'
_static
'
]
html_static_path
=
[
"
_static
"
]
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
#
html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
#
html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
#
html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
#
html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
#
html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
#
html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
#
html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
#
html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
#
html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
#
html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
#
html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
#
html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
#
html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr'
#html_search_language = 'en'
#
html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
#
html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
#
html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename
=
'
pybind11doc
'
htmlhelp_basename
=
"
pybind11doc
"
# -- Options for LaTeX output ---------------------------------------------
latex_elements
=
{
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
'preamble'
:
r
'''
# The paper size ('letterpaper' or 'a4paper').
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
"preamble"
:
r
"""
\DeclareUnicodeCharacter{00A0}{}
\DeclareUnicodeCharacter{2194}{<->}
'''
,
# Latex figure (float) alignment
#'figure_align': 'htbp',
"""
,
# Latex figure (float) alignment
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents
=
[
(
master_doc
,
'pybind11.tex'
,
'pybind11 Documentation'
,
'Wenzel Jakob'
,
'manual'
),
(
master_doc
,
"pybind11.tex"
,
"pybind11 Documentation"
,
"Wenzel Jakob"
,
"manual"
),
]
# The name of an image file (relative to this directory) to place at the top of
...
...
@@ -265,32 +262,29 @@ latex_documents = [
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
#
latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
#
latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
#
latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
#
latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
#
latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages
=
[
(
master_doc
,
'pybind11'
,
'pybind11 Documentation'
,
[
author
],
1
)
]
man_pages
=
[(
master_doc
,
"pybind11"
,
"pybind11 Documentation"
,
[
author
],
1
)]
# If true, show URL addresses after external links.
#man_show_urls = False
#
man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
...
...
@@ -299,35 +293,41 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents
=
[
(
master_doc
,
'pybind11'
,
'pybind11 Documentation'
,
author
,
'pybind11'
,
'One line description of project.'
,
'Miscellaneous'
),
(
master_doc
,
"pybind11"
,
"pybind11 Documentation"
,
author
,
"pybind11"
,
"One line description of project."
,
"Miscellaneous"
,
),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
#
texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
#
texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
#
texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
#
texinfo_no_detailmenu = False
primary_domain
=
'
cpp
'
highlight_language
=
'
cpp
'
primary_domain
=
"
cpp
"
highlight_language
=
"
cpp
"
def
generate_doxygen_xml
(
app
):
build_dir
=
os
.
path
.
join
(
app
.
confdir
,
'
.build
'
)
build_dir
=
os
.
path
.
join
(
app
.
confdir
,
"
.build
"
)
if
not
os
.
path
.
exists
(
build_dir
):
os
.
mkdir
(
build_dir
)
try
:
subprocess
.
call
([
'
doxygen
'
,
'
--version
'
])
retcode
=
subprocess
.
call
([
'
doxygen
'
],
cwd
=
app
.
confdir
)
subprocess
.
call
([
"
doxygen
"
,
"
--version
"
])
retcode
=
subprocess
.
call
([
"
doxygen
"
],
cwd
=
app
.
confdir
)
if
retcode
<
0
:
sys
.
stderr
.
write
(
"doxygen error code: {}
\n
"
.
format
(
-
retcode
))
except
OSError
as
e
:
...
...
tests/conftest.py
View file @
c50f90ec
...
...
@@ -18,9 +18,9 @@ import env
# Early diagnostic for failed imports
import
pybind11_tests
# noqa: F401
_unicode_marker
=
re
.
compile
(
r
'
u(\'[^\']*\')
'
)
_long_marker
=
re
.
compile
(
r
'
([0-9])L
'
)
_hexadecimal
=
re
.
compile
(
r
'
0x[0-9a-fA-F]+
'
)
_unicode_marker
=
re
.
compile
(
r
"
u(\'[^\']*\')
"
)
_long_marker
=
re
.
compile
(
r
"
([0-9])L
"
)
_hexadecimal
=
re
.
compile
(
r
"
0x[0-9a-fA-F]+
"
)
# Avoid collecting Python3 only files
collect_ignore
=
[]
...
...
@@ -30,7 +30,7 @@ if env.PY2:
def
_strip_and_dedent
(
s
):
"""For triple-quote strings"""
return
textwrap
.
dedent
(
s
.
lstrip
(
'
\n
'
).
rstrip
())
return
textwrap
.
dedent
(
s
.
lstrip
(
"
\n
"
).
rstrip
())
def
_split_and_sort
(
s
):
...
...
@@ -40,11 +40,14 @@ def _split_and_sort(s):
def
_make_explanation
(
a
,
b
):
"""Explanation for a failed assert -- the a and b arguments are List[str]"""
return
[
"--- actual / +++ expected"
]
+
[
line
.
strip
(
'
\n
'
)
for
line
in
difflib
.
ndiff
(
a
,
b
)]
return
[
"--- actual / +++ expected"
]
+
[
line
.
strip
(
"
\n
"
)
for
line
in
difflib
.
ndiff
(
a
,
b
)
]
class
Output
(
object
):
"""Basic output post-processing and comparison"""
def
__init__
(
self
,
string
):
self
.
string
=
string
self
.
explanation
=
[]
...
...
@@ -54,7 +57,11 @@ class Output(object):
def
__eq__
(
self
,
other
):
# Ignore constructor/destructor output which is prefixed with "###"
a
=
[
line
for
line
in
self
.
string
.
strip
().
splitlines
()
if
not
line
.
startswith
(
"###"
)]
a
=
[
line
for
line
in
self
.
string
.
strip
().
splitlines
()
if
not
line
.
startswith
(
"###"
)
]
b
=
_strip_and_dedent
(
other
).
splitlines
()
if
a
==
b
:
return
True
...
...
@@ -65,6 +72,7 @@ class Output(object):
class
Unordered
(
Output
):
"""Custom comparison for output without strict line ordering"""
def
__eq__
(
self
,
other
):
a
=
_split_and_sort
(
self
.
string
)
b
=
_split_and_sort
(
other
)
...
...
@@ -175,7 +183,7 @@ def msg():
# noinspection PyUnusedLocal
def
pytest_assertrepr_compare
(
op
,
left
,
right
):
"""Hook to insert custom failure explanation"""
if
hasattr
(
left
,
'
explanation
'
):
if
hasattr
(
left
,
"
explanation
"
):
return
left
.
explanation
...
...
@@ -189,8 +197,8 @@ def suppress(exception):
def
gc_collect
():
'''
Run the garbage collector twice (needed when running
reference counting tests with PyPy)
'''
"""
Run the garbage collector twice (needed when running
reference counting tests with PyPy)
"""
gc
.
collect
()
gc
.
collect
()
...
...
tests/test_buffers.py
View file @
c50f90ec
...
...
@@ -46,8 +46,8 @@ def test_to_python():
mat
[
3
,
2
]
=
7.0
assert
mat
[
2
,
3
]
==
4
assert
mat
[
3
,
2
]
==
7
assert
struct
.
unpack_from
(
'f'
,
mat
,
(
3
*
4
+
2
)
*
4
)
==
(
7
,
)
assert
struct
.
unpack_from
(
'f'
,
mat
,
(
2
*
4
+
3
)
*
4
)
==
(
4
,
)
assert
struct
.
unpack_from
(
"f"
,
mat
,
(
3
*
4
+
2
)
*
4
)
==
(
7
,)
assert
struct
.
unpack_from
(
"f"
,
mat
,
(
2
*
4
+
3
)
*
4
)
==
(
4
,)
mat2
=
np
.
array
(
mat
,
copy
=
False
)
assert
mat2
.
shape
==
(
5
,
4
)
...
...
@@ -83,31 +83,31 @@ def test_pointer_to_member_fn():
for
cls
in
[
m
.
Buffer
,
m
.
ConstBuffer
,
m
.
DerivedBuffer
]:
buf
=
cls
()
buf
.
value
=
0x12345678
value
=
struct
.
unpack
(
'i'
,
bytearray
(
buf
))[
0
]
value
=
struct
.
unpack
(
"i"
,
bytearray
(
buf
))[
0
]
assert
value
==
0x12345678
def
test_readonly_buffer
():
buf
=
m
.
BufferReadOnly
(
0x64
)
view
=
memoryview
(
buf
)
assert
view
[
0
]
==
b
'd'
if
env
.
PY2
else
0x64
assert
view
[
0
]
==
b
"d"
if
env
.
PY2
else
0x64
assert
view
.
readonly
def
test_selective_readonly_buffer
():
buf
=
m
.
BufferReadOnlySelect
()
memoryview
(
buf
)[
0
]
=
b
'd'
if
env
.
PY2
else
0x64
memoryview
(
buf
)[
0
]
=
b
"d"
if
env
.
PY2
else
0x64
assert
buf
.
value
==
0x64
io
.
BytesIO
(
b
'A'
).
readinto
(
buf
)
assert
buf
.
value
==
ord
(
b
'A'
)
io
.
BytesIO
(
b
"A"
).
readinto
(
buf
)
assert
buf
.
value
==
ord
(
b
"A"
)
buf
.
readonly
=
True
with
pytest
.
raises
(
TypeError
):
memoryview
(
buf
)[
0
]
=
b
'
\0
'
if
env
.
PY2
else
0
memoryview
(
buf
)[
0
]
=
b
"
\0
"
if
env
.
PY2
else
0
with
pytest
.
raises
(
TypeError
):
io
.
BytesIO
(
b
'1'
).
readinto
(
buf
)
io
.
BytesIO
(
b
"1"
).
readinto
(
buf
)
def
test_ctypes_array_1d
():
...
...
tests/test_builtin_casters.py
View file @
c50f90ec
...
...
@@ -37,79 +37,85 @@ def test_unicode_conversion():
with
pytest
.
raises
(
UnicodeDecodeError
):
m
.
bad_utf8_u8string
()
assert
m
.
u8_Z
()
==
'Z'
assert
m
.
u8_eacute
()
==
u
'é'
assert
m
.
u16_ibang
()
==
u
'‽'
assert
m
.
u32_mathbfA
()
==
u
'𝐀'
assert
m
.
wchar_heart
()
==
u
'♥'
assert
m
.
u8_Z
()
==
"Z"
assert
m
.
u8_eacute
()
==
u
"é"
assert
m
.
u16_ibang
()
==
u
"‽"
assert
m
.
u32_mathbfA
()
==
u
"𝐀"
assert
m
.
wchar_heart
()
==
u
"♥"
if
hasattr
(
m
,
"has_u8string"
):
assert
m
.
u8_char8_Z
()
==
'Z'
assert
m
.
u8_char8_Z
()
==
"Z"
def
test_single_char_arguments
():
"""Tests failures for passing invalid inputs to char-accepting functions"""
def
toobig_message
(
r
):
return
"Character code point not in range({0:#x})"
.
format
(
r
)
toolong_message
=
"Expected a character, but multi-character string found"
assert
m
.
ord_char
(
u
'a'
)
==
0x61
# simple ASCII
assert
m
.
ord_char_lv
(
u
'b'
)
==
0x62
assert
m
.
ord_char
(
u
'é'
)
==
0xE9
# requires 2 bytes in utf-8, but can be stuffed in a char
assert
m
.
ord_char
(
u
"a"
)
==
0x61
# simple ASCII
assert
m
.
ord_char_lv
(
u
"b"
)
==
0x62
assert
(
m
.
ord_char
(
u
"é"
)
==
0xE9
)
# requires 2 bytes in utf-8, but can be stuffed in a char
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
assert
m
.
ord_char
(
u
'Ā'
)
==
0x100
# requires 2 bytes, doesn't fit in a char
assert
m
.
ord_char
(
u
"Ā"
)
==
0x100
# requires 2 bytes, doesn't fit in a char
assert
str
(
excinfo
.
value
)
==
toobig_message
(
0x100
)
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
assert
m
.
ord_char
(
u
'
ab
'
)
assert
m
.
ord_char
(
u
"
ab
"
)
assert
str
(
excinfo
.
value
)
==
toolong_message
assert
m
.
ord_char16
(
u
'a'
)
==
0x61
assert
m
.
ord_char16
(
u
'é'
)
==
0xE9
assert
m
.
ord_char16_lv
(
u
'ê'
)
==
0xEA
assert
m
.
ord_char16
(
u
'Ā'
)
==
0x100
assert
m
.
ord_char16
(
u
'‽'
)
==
0x203
d
assert
m
.
ord_char16
(
u
'♥'
)
==
0x2665
assert
m
.
ord_char16_lv
(
u
'♡'
)
==
0x2661
assert
m
.
ord_char16
(
u
"a"
)
==
0x61
assert
m
.
ord_char16
(
u
"é"
)
==
0xE9
assert
m
.
ord_char16_lv
(
u
"ê"
)
==
0xEA
assert
m
.
ord_char16
(
u
"Ā"
)
==
0x100
assert
m
.
ord_char16
(
u
"‽"
)
==
0x203
D
assert
m
.
ord_char16
(
u
"♥"
)
==
0x2665
assert
m
.
ord_char16_lv
(
u
"♡"
)
==
0x2661
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
assert
m
.
ord_char16
(
u
'🎂'
)
==
0x1F382
# requires surrogate pair
assert
m
.
ord_char16
(
u
"🎂"
)
==
0x1F382
# requires surrogate pair
assert
str
(
excinfo
.
value
)
==
toobig_message
(
0x10000
)
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
assert
m
.
ord_char16
(
u
'
aa
'
)
assert
m
.
ord_char16
(
u
"
aa
"
)
assert
str
(
excinfo
.
value
)
==
toolong_message
assert
m
.
ord_char32
(
u
'a'
)
==
0x61
assert
m
.
ord_char32
(
u
'é'
)
==
0xE9
assert
m
.
ord_char32
(
u
'Ā'
)
==
0x100
assert
m
.
ord_char32
(
u
'‽'
)
==
0x203
d
assert
m
.
ord_char32
(
u
'♥'
)
==
0x2665
assert
m
.
ord_char32
(
u
'🎂'
)
==
0x1F382
assert
m
.
ord_char32
(
u
"a"
)
==
0x61
assert
m
.
ord_char32
(
u
"é"
)
==
0xE9
assert
m
.
ord_char32
(
u
"Ā"
)
==
0x100
assert
m
.
ord_char32
(
u
"‽"
)
==
0x203
D
assert
m
.
ord_char32
(
u
"♥"
)
==
0x2665
assert
m
.
ord_char32
(
u
"🎂"
)
==
0x1F382
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
assert
m
.
ord_char32
(
u
'
aa
'
)
assert
m
.
ord_char32
(
u
"
aa
"
)
assert
str
(
excinfo
.
value
)
==
toolong_message
assert
m
.
ord_wchar
(
u
'a'
)
==
0x61
assert
m
.
ord_wchar
(
u
'é'
)
==
0xE9
assert
m
.
ord_wchar
(
u
'Ā'
)
==
0x100
assert
m
.
ord_wchar
(
u
'‽'
)
==
0x203
d
assert
m
.
ord_wchar
(
u
'♥'
)
==
0x2665
assert
m
.
ord_wchar
(
u
"a"
)
==
0x61
assert
m
.
ord_wchar
(
u
"é"
)
==
0xE9
assert
m
.
ord_wchar
(
u
"Ā"
)
==
0x100
assert
m
.
ord_wchar
(
u
"‽"
)
==
0x203
D
assert
m
.
ord_wchar
(
u
"♥"
)
==
0x2665
if
m
.
wchar_size
==
2
:
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
assert
m
.
ord_wchar
(
u
'🎂'
)
==
0x1F382
# requires surrogate pair
assert
m
.
ord_wchar
(
u
"🎂"
)
==
0x1F382
# requires surrogate pair
assert
str
(
excinfo
.
value
)
==
toobig_message
(
0x10000
)
else
:
assert
m
.
ord_wchar
(
u
'🎂'
)
==
0x1F382
assert
m
.
ord_wchar
(
u
"🎂"
)
==
0x1F382
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
assert
m
.
ord_wchar
(
u
'
aa
'
)
assert
m
.
ord_wchar
(
u
"
aa
"
)
assert
str
(
excinfo
.
value
)
==
toolong_message
if
hasattr
(
m
,
"has_u8string"
):
assert
m
.
ord_char8
(
u
'a'
)
==
0x61
# simple ASCII
assert
m
.
ord_char8_lv
(
u
'b'
)
==
0x62
assert
m
.
ord_char8
(
u
'é'
)
==
0xE9
# requires 2 bytes in utf-8, but can be stuffed in a char
assert
m
.
ord_char8
(
u
"a"
)
==
0x61
# simple ASCII
assert
m
.
ord_char8_lv
(
u
"b"
)
==
0x62
assert
(
m
.
ord_char8
(
u
"é"
)
==
0xE9
)
# requires 2 bytes in utf-8, but can be stuffed in a char
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
assert
m
.
ord_char8
(
u
'Ā'
)
==
0x100
# requires 2 bytes, doesn't fit in a char
assert
m
.
ord_char8
(
u
"Ā"
)
==
0x100
# requires 2 bytes, doesn't fit in a char
assert
str
(
excinfo
.
value
)
==
toobig_message
(
0x100
)
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
assert
m
.
ord_char8
(
u
'
ab
'
)
assert
m
.
ord_char8
(
u
"
ab
"
)
assert
str
(
excinfo
.
value
)
==
toolong_message
...
...
@@ -129,19 +135,19 @@ def test_bytes_to_string():
assert
m
.
strlen
(
to_bytes
(
"a
\x00
b"
))
==
1
# C-string limitation
# passing in a utf8 encoded string should work
assert
m
.
string_length
(
u
'💩'
.
encode
(
"utf8"
))
==
4
assert
m
.
string_length
(
u
"💩"
.
encode
(
"utf8"
))
==
4
@
pytest
.
mark
.
skipif
(
not
hasattr
(
m
,
"has_string_view"
),
reason
=
"no <string_view>"
)
def
test_string_view
(
capture
):
"""Tests support for C++17 string_view arguments and return values"""
assert
m
.
string_view_chars
(
"Hi"
)
==
[
72
,
105
]
assert
m
.
string_view_chars
(
"Hi 🎂"
)
==
[
72
,
105
,
32
,
0x
f
0
,
0x9
f
,
0x8
e
,
0x82
]
assert
m
.
string_view16_chars
(
u
"Hi 🎂"
)
==
[
72
,
105
,
32
,
0x
d
83
c
,
0x
df
82
]
assert
m
.
string_view_chars
(
"Hi 🎂"
)
==
[
72
,
105
,
32
,
0x
F
0
,
0x9
F
,
0x8
E
,
0x82
]
assert
m
.
string_view16_chars
(
u
"Hi 🎂"
)
==
[
72
,
105
,
32
,
0x
D
83
C
,
0x
DF
82
]
assert
m
.
string_view32_chars
(
u
"Hi 🎂"
)
==
[
72
,
105
,
32
,
127874
]
if
hasattr
(
m
,
"has_u8string"
):
assert
m
.
string_view8_chars
(
"Hi"
)
==
[
72
,
105
]
assert
m
.
string_view8_chars
(
u
"Hi 🎂"
)
==
[
72
,
105
,
32
,
0x
f
0
,
0x9
f
,
0x8
e
,
0x82
]
assert
m
.
string_view8_chars
(
u
"Hi 🎂"
)
==
[
72
,
105
,
32
,
0x
F
0
,
0x9
F
,
0x8
E
,
0x82
]
assert
m
.
string_view_return
()
==
u
"utf8 secret 🎂"
assert
m
.
string_view16_return
()
==
u
"utf16 secret 🎂"
...
...
@@ -154,40 +160,52 @@ def test_string_view(capture):
m
.
string_view_print
(
"utf8 🎂"
)
m
.
string_view16_print
(
u
"utf16 🎂"
)
m
.
string_view32_print
(
u
"utf32 🎂"
)
assert
capture
==
u
"""
assert
(
capture
==
u
"""
Hi 2
utf8 🎂 9
utf16 🎂 8
utf32 🎂 7
"""
)
if
hasattr
(
m
,
"has_u8string"
):
with
capture
:
m
.
string_view8_print
(
"Hi"
)
m
.
string_view8_print
(
u
"utf8 🎂"
)
assert
capture
==
u
"""
assert
(
capture
==
u
"""
Hi 2
utf8 🎂 9
"""
)
with
capture
:
m
.
string_view_print
(
"Hi, ascii"
)
m
.
string_view_print
(
"Hi, utf8 🎂"
)
m
.
string_view16_print
(
u
"Hi, utf16 🎂"
)
m
.
string_view32_print
(
u
"Hi, utf32 🎂"
)
assert
capture
==
u
"""
assert
(
capture
==
u
"""
Hi, ascii 9
Hi, utf8 🎂 13
Hi, utf16 🎂 12
Hi, utf32 🎂 11
"""
)
if
hasattr
(
m
,
"has_u8string"
):
with
capture
:
m
.
string_view8_print
(
"Hi, ascii"
)
m
.
string_view8_print
(
u
"Hi, utf8 🎂"
)
assert
capture
==
u
"""
assert
(
capture
==
u
"""
Hi, ascii 9
Hi, utf8 🎂 13
"""
)
def
test_integer_casting
():
...
...
@@ -199,8 +217,14 @@ def test_integer_casting():
if
env
.
PY2
:
assert
m
.
i32_str
(
long
(
-
1
))
==
"-1"
# noqa: F821 undefined name 'long'
assert
m
.
i64_str
(
long
(
-
1
))
==
"-1"
# noqa: F821 undefined name 'long'
assert
m
.
i64_str
(
long
(
-
999999999999
))
==
"-999999999999"
# noqa: F821 undefined name
assert
m
.
u64_str
(
long
(
999999999999
))
==
"999999999999"
# noqa: F821 undefined name 'long'
assert
(
m
.
i64_str
(
long
(
-
999999999999
))
# noqa: F821 undefined name 'long'
==
"-999999999999"
)
assert
(
m
.
u64_str
(
long
(
999999999999
))
# noqa: F821 undefined name 'long'
==
"999999999999"
)
else
:
assert
m
.
i64_str
(
-
999999999999
)
==
"-999999999999"
assert
m
.
u64_str
(
999999999999
)
==
"999999999999"
...
...
@@ -236,16 +260,22 @@ def test_tuple(doc):
assert
m
.
tuple_passthrough
([
True
,
"test"
,
5
])
==
(
5
,
"test"
,
True
)
assert
m
.
empty_tuple
()
==
()
assert
doc
(
m
.
pair_passthrough
)
==
"""
assert
(
doc
(
m
.
pair_passthrough
)
==
"""
pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool]
Return a pair in reversed order
"""
assert
doc
(
m
.
tuple_passthrough
)
==
"""
)
assert
(
doc
(
m
.
tuple_passthrough
)
==
"""
tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool]
Return a triple in reversed order
"""
)
assert
m
.
rvalue_pair
()
==
(
"rvalue"
,
"rvalue"
)
assert
m
.
lvalue_pair
()
==
(
"lvalue"
,
"lvalue"
)
...
...
@@ -372,7 +402,7 @@ def test_numpy_bool():
assert
convert
(
np
.
bool_
(
False
))
is
False
assert
noconvert
(
np
.
bool_
(
True
))
is
True
assert
noconvert
(
np
.
bool_
(
False
))
is
False
cant_convert
(
np
.
zeros
(
2
,
dtype
=
'
int
'
))
cant_convert
(
np
.
zeros
(
2
,
dtype
=
"
int
"
))
def
test_int_long
():
...
...
@@ -382,7 +412,8 @@ def test_int_long():
long."""
import
sys
must_be_long
=
type
(
getattr
(
sys
,
'maxint'
,
1
)
+
1
)
must_be_long
=
type
(
getattr
(
sys
,
"maxint"
,
1
)
+
1
)
assert
isinstance
(
m
.
int_cast
(),
int
)
assert
isinstance
(
m
.
long_cast
(),
int
)
assert
isinstance
(
m
.
longlong_cast
(),
must_be_long
)
...
...
tests/test_call_policies.py
View file @
c50f90ec
...
...
@@ -16,10 +16,13 @@ def test_keep_alive_argument(capture):
with
capture
:
p
.
addChild
(
m
.
Child
())
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
+
1
assert
capture
==
"""
assert
(
capture
==
"""
Allocating child.
Releasing child.
"""
)
with
capture
:
del
p
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
...
...
@@ -35,10 +38,13 @@ def test_keep_alive_argument(capture):
with
capture
:
del
p
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
assert
capture
==
"""
assert
(
capture
==
"""
Releasing parent.
Releasing child.
"""
)
def
test_keep_alive_return_value
(
capture
):
...
...
@@ -49,10 +55,13 @@ def test_keep_alive_return_value(capture):
with
capture
:
p
.
returnChild
()
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
+
1
assert
capture
==
"""
assert
(
capture
==
"""
Allocating child.
Releasing child.
"""
)
with
capture
:
del
p
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
...
...
@@ -68,10 +77,13 @@ def test_keep_alive_return_value(capture):
with
capture
:
del
p
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
assert
capture
==
"""
assert
(
capture
==
"""
Releasing parent.
Releasing child.
"""
)
# https://foss.heptapod.net/pypy/pypy/-/issues/2447
...
...
@@ -82,14 +94,17 @@ def test_alive_gc(capture):
p
.
addChildKeepAlive
(
m
.
Child
())
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
+
2
lst
=
[
p
]
lst
.
append
(
lst
)
# creates a circular reference
lst
.
append
(
lst
)
# creates a circular reference
with
capture
:
del
p
,
lst
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
assert
capture
==
"""
assert
(
capture
==
"""
Releasing parent.
Releasing child.
"""
)
def
test_alive_gc_derived
(
capture
):
...
...
@@ -101,14 +116,17 @@ def test_alive_gc_derived(capture):
p
.
addChildKeepAlive
(
m
.
Child
())
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
+
2
lst
=
[
p
]
lst
.
append
(
lst
)
# creates a circular reference
lst
.
append
(
lst
)
# creates a circular reference
with
capture
:
del
p
,
lst
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
assert
capture
==
"""
assert
(
capture
==
"""
Releasing parent.
Releasing child.
"""
)
def
test_alive_gc_multi_derived
(
capture
):
...
...
@@ -123,15 +141,18 @@ def test_alive_gc_multi_derived(capture):
# +3 rather than +2 because Derived corresponds to two registered instances
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
+
3
lst
=
[
p
]
lst
.
append
(
lst
)
# creates a circular reference
lst
.
append
(
lst
)
# creates a circular reference
with
capture
:
del
p
,
lst
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
assert
capture
==
"""
assert
(
capture
==
"""
Releasing parent.
Releasing child.
Releasing child.
"""
)
def
test_return_none
(
capture
):
...
...
@@ -167,17 +188,23 @@ def test_keep_alive_constructor(capture):
with
capture
:
p
=
m
.
Parent
(
m
.
Child
())
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
+
2
assert
capture
==
"""
assert
(
capture
==
"""
Allocating child.
Allocating parent.
"""
)
with
capture
:
del
p
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
assert
capture
==
"""
assert
(
capture
==
"""
Releasing parent.
Releasing child.
"""
)
def
test_call_guard
():
...
...
tests/test_callbacks.py
View file @
c50f90ec
...
...
@@ -42,17 +42,19 @@ def test_bound_method_callback():
def
test_keyword_args_and_generalized_unpacking
():
def
f
(
*
args
,
**
kwargs
):
return
args
,
kwargs
assert
m
.
test_tuple_unpacking
(
f
)
==
((
"positional"
,
1
,
2
,
3
,
4
,
5
,
6
),
{})
assert
m
.
test_dict_unpacking
(
f
)
==
((
"positional"
,
1
),
{
"key"
:
"value"
,
"a"
:
1
,
"b"
:
2
})
assert
m
.
test_dict_unpacking
(
f
)
==
(
(
"positional"
,
1
),
{
"key"
:
"value"
,
"a"
:
1
,
"b"
:
2
},
)
assert
m
.
test_keyword_args
(
f
)
==
((),
{
"x"
:
10
,
"y"
:
20
})
assert
m
.
test_unpacking_and_keywords1
(
f
)
==
((
1
,
2
),
{
"c"
:
3
,
"d"
:
4
})
assert
m
.
test_unpacking_and_keywords2
(
f
)
==
(
(
"positional"
,
1
,
2
,
3
,
4
,
5
),
{
"key"
:
"value"
,
"a"
:
1
,
"b"
:
2
,
"c"
:
3
,
"d"
:
4
,
"e"
:
5
}
{
"key"
:
"value"
,
"a"
:
1
,
"b"
:
2
,
"c"
:
3
,
"d"
:
4
,
"e"
:
5
}
,
)
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
...
...
@@ -83,12 +85,18 @@ def test_lambda_closure_cleanup():
def
test_cpp_function_roundtrip
():
"""Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
assert
m
.
test_dummy_function
(
m
.
dummy_function
)
==
"matches dummy_function: eval(1) = 2"
assert
(
m
.
test_dummy_function
(
m
.
roundtrip
(
m
.
dummy_function
))
==
"matches dummy_function: eval(1) = 2"
)
assert
(
m
.
test_dummy_function
(
m
.
dummy_function
)
==
"matches dummy_function: eval(1) = 2"
)
assert
(
m
.
test_dummy_function
(
m
.
roundtrip
(
m
.
dummy_function
))
==
"matches dummy_function: eval(1) = 2"
)
assert
m
.
roundtrip
(
None
,
expect_none
=
True
)
is
None
assert
(
m
.
test_dummy_function
(
lambda
x
:
x
+
2
)
==
"can't convert to function pointer: eval(1) = 3"
)
assert
(
m
.
test_dummy_function
(
lambda
x
:
x
+
2
)
==
"can't convert to function pointer: eval(1) = 3"
)
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
test_dummy_function
(
m
.
dummy_function2
)
...
...
@@ -96,8 +104,10 @@ def test_cpp_function_roundtrip():
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
test_dummy_function
(
lambda
x
,
y
:
x
+
y
)
assert
any
(
s
in
str
(
excinfo
.
value
)
for
s
in
(
"missing 1 required positional argument"
,
"takes exactly 2 arguments"
))
assert
any
(
s
in
str
(
excinfo
.
value
)
for
s
in
(
"missing 1 required positional argument"
,
"takes exactly 2 arguments"
)
)
def
test_function_signatures
(
doc
):
...
...
@@ -127,6 +137,7 @@ def test_async_callbacks():
m
.
test_async_callback
(
gen_f
(),
work
)
# wait until work is done
from
time
import
sleep
sleep
(
0.5
)
assert
sum
(
res
)
==
sum
([
x
+
3
for
x
in
work
])
...
...
tests/test_chrono.py
View file @
c50f90ec
...
...
@@ -80,22 +80,28 @@ SKIP_TZ_ENV_ON_WIN = pytest.mark.skipif(
)
@
pytest
.
mark
.
parametrize
(
"time1"
,
[
datetime
.
datetime
.
today
().
time
(),
datetime
.
time
(
0
,
0
,
0
),
datetime
.
time
(
0
,
0
,
0
,
1
),
datetime
.
time
(
0
,
28
,
45
,
109827
),
datetime
.
time
(
0
,
59
,
59
,
999999
),
datetime
.
time
(
1
,
0
,
0
),
datetime
.
time
(
5
,
59
,
59
,
0
),
datetime
.
time
(
5
,
59
,
59
,
1
),
])
@
pytest
.
mark
.
parametrize
(
"tz"
,
[
None
,
pytest
.
param
(
"Europe/Brussels"
,
marks
=
SKIP_TZ_ENV_ON_WIN
),
pytest
.
param
(
"Asia/Pyongyang"
,
marks
=
SKIP_TZ_ENV_ON_WIN
),
pytest
.
param
(
"America/New_York"
,
marks
=
SKIP_TZ_ENV_ON_WIN
),
])
@
pytest
.
mark
.
parametrize
(
"time1"
,
[
datetime
.
datetime
.
today
().
time
(),
datetime
.
time
(
0
,
0
,
0
),
datetime
.
time
(
0
,
0
,
0
,
1
),
datetime
.
time
(
0
,
28
,
45
,
109827
),
datetime
.
time
(
0
,
59
,
59
,
999999
),
datetime
.
time
(
1
,
0
,
0
),
datetime
.
time
(
5
,
59
,
59
,
0
),
datetime
.
time
(
5
,
59
,
59
,
1
),
],
)
@
pytest
.
mark
.
parametrize
(
"tz"
,
[
None
,
pytest
.
param
(
"Europe/Brussels"
,
marks
=
SKIP_TZ_ENV_ON_WIN
),
pytest
.
param
(
"Asia/Pyongyang"
,
marks
=
SKIP_TZ_ENV_ON_WIN
),
pytest
.
param
(
"America/New_York"
,
marks
=
SKIP_TZ_ENV_ON_WIN
),
],
)
def
test_chrono_system_clock_roundtrip_time
(
time1
,
tz
,
monkeypatch
):
if
tz
is
not
None
:
monkeypatch
.
setenv
(
"TZ"
,
"/usr/share/zoneinfo/{}"
.
format
(
tz
))
...
...
@@ -199,7 +205,7 @@ def test_floating_point_duration():
def
test_nano_timepoint
():
time
=
datetime
.
datetime
.
now
()
time1
=
m
.
test_nano_timepoint
(
time
,
datetime
.
timedelta
(
seconds
=
60
))
assert
(
time1
==
time
+
datetime
.
timedelta
(
seconds
=
60
)
)
assert
time1
==
time
+
datetime
.
timedelta
(
seconds
=
60
)
def
test_chrono_different_resolutions
():
...
...
tests/test_class.py
View file @
c50f90ec
...
...
@@ -31,8 +31,10 @@ def test_type():
with
pytest
.
raises
(
RuntimeError
)
as
execinfo
:
m
.
check_type
(
0
)
assert
'pybind11::detail::get_type_info: unable to find type info'
in
str
(
execinfo
.
value
)
assert
'Invalid'
in
str
(
execinfo
.
value
)
assert
"pybind11::detail::get_type_info: unable to find type info"
in
str
(
execinfo
.
value
)
assert
"Invalid"
in
str
(
execinfo
.
value
)
# Currently not supported
# See https://github.com/pybind/pybind11/issues/2486
...
...
@@ -73,18 +75,24 @@ def test_docstrings(doc):
assert
UserType
.
get_value
.
__name__
==
"get_value"
assert
UserType
.
get_value
.
__module__
==
"pybind11_tests"
assert
doc
(
UserType
.
get_value
)
==
"""
assert
(
doc
(
UserType
.
get_value
)
==
"""
get_value(self: m.UserType) -> int
Get value using a method
"""
)
assert
doc
(
UserType
.
value
)
==
"Get/set value using a property"
assert
doc
(
m
.
NoConstructor
.
new_instance
)
==
"""
assert
(
doc
(
m
.
NoConstructor
.
new_instance
)
==
"""
new_instance() -> m.class_.NoConstructor
Return an instance
"""
)
def
test_qualname
(
doc
):
...
...
@@ -93,51 +101,69 @@ def test_qualname(doc):
assert
m
.
NestBase
.
__qualname__
==
"NestBase"
assert
m
.
NestBase
.
Nested
.
__qualname__
==
"NestBase.Nested"
assert
doc
(
m
.
NestBase
.
__init__
)
==
"""
assert
(
doc
(
m
.
NestBase
.
__init__
)
==
"""
__init__(self: m.class_.NestBase) -> None
"""
assert
doc
(
m
.
NestBase
.
g
)
==
"""
)
assert
(
doc
(
m
.
NestBase
.
g
)
==
"""
g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None
"""
assert
doc
(
m
.
NestBase
.
Nested
.
__init__
)
==
"""
)
assert
(
doc
(
m
.
NestBase
.
Nested
.
__init__
)
==
"""
__init__(self: m.class_.NestBase.Nested) -> None
"""
assert
doc
(
m
.
NestBase
.
Nested
.
fn
)
==
"""
)
assert
(
doc
(
m
.
NestBase
.
Nested
.
fn
)
==
"""
fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
"""
# noqa: E501 line too long
assert
doc
(
m
.
NestBase
.
Nested
.
fa
)
==
"""
)
assert
(
doc
(
m
.
NestBase
.
Nested
.
fa
)
==
"""
fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
"""
# noqa: E501 line too long
)
assert
m
.
NestBase
.
__module__
==
"pybind11_tests.class_"
assert
m
.
NestBase
.
Nested
.
__module__
==
"pybind11_tests.class_"
def
test_inheritance
(
msg
):
roger
=
m
.
Rabbit
(
'
Rabbit
'
)
roger
=
m
.
Rabbit
(
"
Rabbit
"
)
assert
roger
.
name
()
+
" is a "
+
roger
.
species
()
==
"Rabbit is a parrot"
assert
m
.
pet_name_species
(
roger
)
==
"Rabbit is a parrot"
polly
=
m
.
Pet
(
'
Polly
'
,
'
parrot
'
)
polly
=
m
.
Pet
(
"
Polly
"
,
"
parrot
"
)
assert
polly
.
name
()
+
" is a "
+
polly
.
species
()
==
"Polly is a parrot"
assert
m
.
pet_name_species
(
polly
)
==
"Polly is a parrot"
molly
=
m
.
Dog
(
'
Molly
'
)
molly
=
m
.
Dog
(
"
Molly
"
)
assert
molly
.
name
()
+
" is a "
+
molly
.
species
()
==
"Molly is a dog"
assert
m
.
pet_name_species
(
molly
)
==
"Molly is a dog"
fred
=
m
.
Hamster
(
'
Fred
'
)
fred
=
m
.
Hamster
(
"
Fred
"
)
assert
fred
.
name
()
+
" is a "
+
fred
.
species
()
==
"Fred is a rodent"
assert
m
.
dog_bark
(
molly
)
==
"Woof!"
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
dog_bark
(
polly
)
assert
msg
(
excinfo
.
value
)
==
"""
assert
(
msg
(
excinfo
.
value
)
==
"""
dog_bark(): incompatible function arguments. The following argument types are supported:
1. (arg0: m.class_.Dog) -> str
Invoked with: <m.class_.Pet object at 0>
"""
)
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
Chimera
(
"lion"
,
"goat"
)
...
...
@@ -150,6 +176,7 @@ def test_inheritance_init(msg):
class
Python
(
m
.
Pet
):
def
__init__
(
self
):
pass
with
pytest
.
raises
(
TypeError
)
as
exc_info
:
Python
()
expected
=
"m.class_.Pet.__init__() must be called when overriding __init__"
...
...
@@ -191,13 +218,19 @@ def test_mismatched_holder():
with
pytest
.
raises
(
RuntimeError
)
as
excinfo
:
m
.
mismatched_holder_1
()
assert
re
.
match
(
'generic_type: type ".*MismatchDerived1" does not have a non-default '
'holder type while its base ".*MismatchBase1" does'
,
str
(
excinfo
.
value
))
assert
re
.
match
(
'generic_type: type ".*MismatchDerived1" does not have a non-default '
'holder type while its base ".*MismatchBase1" does'
,
str
(
excinfo
.
value
),
)
with
pytest
.
raises
(
RuntimeError
)
as
excinfo
:
m
.
mismatched_holder_2
()
assert
re
.
match
(
'generic_type: type ".*MismatchDerived2" has a non-default holder type '
'while its base ".*MismatchBase2" does not'
,
str
(
excinfo
.
value
))
assert
re
.
match
(
'generic_type: type ".*MismatchDerived2" has a non-default holder type '
'while its base ".*MismatchBase2" does not'
,
str
(
excinfo
.
value
),
)
def
test_override_static
():
...
...
@@ -229,20 +262,20 @@ def test_operator_new_delete(capture):
a
=
m
.
HasOpNewDel
()
b
=
m
.
HasOpNewDelSize
()
d
=
m
.
HasOpNewDelBoth
()
assert
capture
==
"""
assert
(
capture
==
"""
A new 8
B new 4
D new 32
"""
)
sz_alias
=
str
(
m
.
AliasedHasOpNewDelSize
.
size_alias
)
sz_noalias
=
str
(
m
.
AliasedHasOpNewDelSize
.
size_noalias
)
with
capture
:
c
=
m
.
AliasedHasOpNewDelSize
()
c2
=
SubAliased
()
assert
capture
==
(
"C new "
+
sz_noalias
+
"
\n
"
+
"C new "
+
sz_alias
+
"
\n
"
)
assert
capture
==
(
"C new "
+
sz_noalias
+
"
\n
"
+
"C new "
+
sz_alias
+
"
\n
"
)
with
capture
:
del
a
...
...
@@ -251,21 +284,21 @@ def test_operator_new_delete(capture):
pytest
.
gc_collect
()
del
d
pytest
.
gc_collect
()
assert
capture
==
"""
assert
(
capture
==
"""
A delete
B delete 4
D delete
"""
)
with
capture
:
del
c
pytest
.
gc_collect
()
del
c2
pytest
.
gc_collect
()
assert
capture
==
(
"C delete "
+
sz_noalias
+
"
\n
"
+
"C delete "
+
sz_alias
+
"
\n
"
)
assert
capture
==
(
"C delete "
+
sz_noalias
+
"
\n
"
+
"C delete "
+
sz_alias
+
"
\n
"
)
def
test_bind_protected_functions
():
...
...
@@ -325,19 +358,23 @@ def test_reentrant_implicit_conversion_failure(msg):
# ensure that there is no runaway reentrant implicit conversion (#1035)
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
BogusImplicitConversion
(
0
)
assert
msg
(
excinfo
.
value
)
==
'''
assert
(
msg
(
excinfo
.
value
)
==
"""
__init__(): incompatible constructor arguments. The following argument types are supported:
1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
Invoked with: 0
'''
"""
)
def
test_error_after_conversions
():
with
pytest
.
raises
(
TypeError
)
as
exc_info
:
m
.
test_error_after_conversions
(
"hello"
)
assert
str
(
exc_info
.
value
).
startswith
(
"Unable to convert function return value to a Python type!"
)
"Unable to convert function return value to a Python type!"
)
def
test_aligned
():
...
...
@@ -350,8 +387,10 @@ def test_aligned():
@
pytest
.
mark
.
xfail
(
"env.PYPY"
)
def
test_final
():
with
pytest
.
raises
(
TypeError
)
as
exc_info
:
class
PyFinalChild
(
m
.
IsFinal
):
pass
assert
str
(
exc_info
.
value
).
endswith
(
"is not an acceptable base type"
)
...
...
@@ -359,8 +398,10 @@ def test_final():
@
pytest
.
mark
.
xfail
(
"env.PYPY"
)
def
test_non_final_final
():
with
pytest
.
raises
(
TypeError
)
as
exc_info
:
class
PyNonFinalFinalChild
(
m
.
IsNonFinalFinal
):
pass
assert
str
(
exc_info
.
value
).
endswith
(
"is not an acceptable base type"
)
...
...
@@ -396,11 +437,14 @@ def test_base_and_derived_nested_scope():
@
pytest
.
mark
.
skip
(
"See https://github.com/pybind/pybind11/pull/2564"
)
def
test_register_duplicate_class
():
import
types
module_scope
=
types
.
ModuleType
(
"module_scope"
)
with
pytest
.
raises
(
RuntimeError
)
as
exc_info
:
m
.
register_duplicate_class_name
(
module_scope
)
expected
=
(
'generic_type: cannot initialize type "Duplicate": '
'an object with that name is already defined'
)
expected
=
(
'generic_type: cannot initialize type "Duplicate": '
"an object with that name is already defined"
)
assert
str
(
exc_info
.
value
)
==
expected
with
pytest
.
raises
(
RuntimeError
)
as
exc_info
:
m
.
register_duplicate_class_type
(
module_scope
)
...
...
@@ -409,10 +453,13 @@ def test_register_duplicate_class():
class
ClassScope
:
pass
with
pytest
.
raises
(
RuntimeError
)
as
exc_info
:
m
.
register_duplicate_nested_class_name
(
ClassScope
)
expected
=
(
'generic_type: cannot initialize type "DuplicateNested": '
'an object with that name is already defined'
)
expected
=
(
'generic_type: cannot initialize type "DuplicateNested": '
"an object with that name is already defined"
)
assert
str
(
exc_info
.
value
)
==
expected
with
pytest
.
raises
(
RuntimeError
)
as
exc_info
:
m
.
register_duplicate_nested_class_type
(
ClassScope
)
...
...
tests/test_copy_move.py
View file @
c50f90ec
...
...
@@ -19,7 +19,11 @@ def test_move_and_copy_casts():
"""Cast some values in C++ via custom type casters and count the number of moves/copies."""
cstats
=
m
.
move_and_copy_cstats
()
c_m
,
c_mc
,
c_c
=
cstats
[
"MoveOnlyInt"
],
cstats
[
"MoveOrCopyInt"
],
cstats
[
"CopyOnlyInt"
]
c_m
,
c_mc
,
c_c
=
(
cstats
[
"MoveOnlyInt"
],
cstats
[
"MoveOrCopyInt"
],
cstats
[
"CopyOnlyInt"
],
)
# The type move constructions/assignments below each get incremented: the move assignment comes
# from the type_caster load; the move construction happens when extracting that via a cast or
...
...
@@ -43,7 +47,11 @@ def test_move_and_copy_loads():
moves/copies."""
cstats
=
m
.
move_and_copy_cstats
()
c_m
,
c_mc
,
c_c
=
cstats
[
"MoveOnlyInt"
],
cstats
[
"MoveOrCopyInt"
],
cstats
[
"CopyOnlyInt"
]
c_m
,
c_mc
,
c_c
=
(
cstats
[
"MoveOnlyInt"
],
cstats
[
"MoveOrCopyInt"
],
cstats
[
"CopyOnlyInt"
],
)
assert
m
.
move_only
(
10
)
==
10
# 1 move, c_m
assert
m
.
move_or_copy
(
11
)
==
11
# 1 move, c_mc
...
...
@@ -66,12 +74,16 @@ def test_move_and_copy_loads():
assert
c_m
.
alive
()
+
c_mc
.
alive
()
+
c_c
.
alive
()
==
0
@
pytest
.
mark
.
skipif
(
not
m
.
has_optional
,
reason
=
'
no <optional>
'
)
@
pytest
.
mark
.
skipif
(
not
m
.
has_optional
,
reason
=
"
no <optional>
"
)
def
test_move_and_copy_load_optional
():
"""Tests move/copy loads of std::optional arguments"""
cstats
=
m
.
move_and_copy_cstats
()
c_m
,
c_mc
,
c_c
=
cstats
[
"MoveOnlyInt"
],
cstats
[
"MoveOrCopyInt"
],
cstats
[
"CopyOnlyInt"
]
c_m
,
c_mc
,
c_c
=
(
cstats
[
"MoveOnlyInt"
],
cstats
[
"MoveOrCopyInt"
],
cstats
[
"CopyOnlyInt"
],
)
# The extra move/copy constructions below come from the std::optional move (which has to move
# its arguments):
...
...
tests/test_custom_type_casters.py
View file @
c50f90ec
...
...
@@ -5,65 +5,91 @@ from pybind11_tests import custom_type_casters as m
def
test_noconvert_args
(
msg
):
a
=
m
.
ArgInspector
()
assert
msg
(
a
.
f
(
"hi"
))
==
"""
assert
(
msg
(
a
.
f
(
"hi"
))
==
"""
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
"""
assert
msg
(
a
.
g
(
"this is a"
,
"this is b"
))
==
"""
)
assert
(
msg
(
a
.
g
(
"this is a"
,
"this is b"
))
==
"""
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
13
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
"""
# noqa: E501 line too long
assert
msg
(
a
.
g
(
"this is a"
,
"this is b"
,
42
))
==
"""
)
assert
(
msg
(
a
.
g
(
"this is a"
,
"this is b"
,
42
))
==
"""
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
42
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
"""
# noqa: E501 line too long
assert
msg
(
a
.
g
(
"this is a"
,
"this is b"
,
42
,
"this is d"
))
==
"""
)
assert
(
msg
(
a
.
g
(
"this is a"
,
"this is b"
,
42
,
"this is d"
))
==
"""
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
42
loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d
"""
assert
(
a
.
h
(
"arg 1"
)
==
"loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1"
)
assert
msg
(
m
.
arg_inspect_func
(
"A1"
,
"A2"
))
==
"""
)
assert
(
a
.
h
(
"arg 1"
)
==
"loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1"
)
assert
(
msg
(
m
.
arg_inspect_func
(
"A1"
,
"A2"
))
==
"""
loading ArgInspector2 argument WITH conversion allowed. Argument value = A1
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
"""
)
assert
m
.
floats_preferred
(
4
)
==
2.0
assert
m
.
floats_only
(
4.0
)
==
2.0
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
floats_only
(
4
)
assert
msg
(
excinfo
.
value
)
==
"""
assert
(
msg
(
excinfo
.
value
)
==
"""
floats_only(): incompatible function arguments. The following argument types are supported:
1. (f: float) -> float
Invoked with: 4
"""
)
assert
m
.
ints_preferred
(
4
)
==
2
assert
m
.
ints_preferred
(
True
)
==
0
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
ints_preferred
(
4.0
)
assert
msg
(
excinfo
.
value
)
==
"""
assert
(
msg
(
excinfo
.
value
)
==
"""
ints_preferred(): incompatible function arguments. The following argument types are supported:
1. (i: int) -> int
Invoked with: 4.0
"""
# noqa: E501 line too long
)
assert
m
.
ints_only
(
4
)
==
2
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
ints_only
(
4.0
)
assert
msg
(
excinfo
.
value
)
==
"""
assert
(
msg
(
excinfo
.
value
)
==
"""
ints_only(): incompatible function arguments. The following argument types are supported:
1. (i: int) -> int
Invoked with: 4.0
"""
)
def
test_custom_caster_destruction
():
...
...
tests/test_docstring_options.py
View file @
c50f90ec
...
...
@@ -18,10 +18,10 @@ def test_docstring_options():
assert
m
.
test_overloaded3
.
__doc__
==
"Overload docstr"
# options.enable_function_signatures()
assert
m
.
test_function3
.
__doc__
.
startswith
(
"test_function3(a: int, b: int) -> None"
)
assert
m
.
test_function3
.
__doc__
.
startswith
(
"test_function3(a: int, b: int) -> None"
)
assert
m
.
test_function4
.
__doc__
.
startswith
(
"test_function4(a: int, b: int) -> None"
)
assert
m
.
test_function4
.
__doc__
.
endswith
(
"A custom docstring
\n
"
)
assert
m
.
test_function4
.
__doc__
.
startswith
(
"test_function4(a: int, b: int) -> None"
)
assert
m
.
test_function4
.
__doc__
.
endswith
(
"A custom docstring
\n
"
)
# options.disable_function_signatures()
# options.disable_user_defined_docstrings()
...
...
@@ -31,8 +31,8 @@ def test_docstring_options():
assert
m
.
test_function6
.
__doc__
==
"A custom docstring"
# RAII destructor
assert
m
.
test_function7
.
__doc__
.
startswith
(
"test_function7(a: int, b: int) -> None"
)
assert
m
.
test_function7
.
__doc__
.
endswith
(
"A custom docstring
\n
"
)
assert
m
.
test_function7
.
__doc__
.
startswith
(
"test_function7(a: int, b: int) -> None"
)
assert
m
.
test_function7
.
__doc__
.
endswith
(
"A custom docstring
\n
"
)
# Suppression of user-defined docstrings for non-function objects
assert
not
m
.
DocstringTestFoo
.
__doc__
...
...
tests/test_eigen.py
View file @
c50f90ec
...
...
@@ -6,11 +6,15 @@ np = pytest.importorskip("numpy")
m
=
pytest
.
importorskip
(
"pybind11_tests.eigen"
)
ref
=
np
.
array
([[
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
,
0
,
8
,
11
]])
ref
=
np
.
array
(
[
[
0.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
,
0
,
8
,
11
],
]
)
def
assert_equal_ref
(
mat
):
...
...
@@ -40,28 +44,37 @@ def test_dense():
def
test_partially_fixed
():
ref2
=
np
.
array
([[
0.
,
1
,
2
,
3
],
[
4
,
5
,
6
,
7
],
[
8
,
9
,
10
,
11
],
[
12
,
13
,
14
,
15
]])
ref2
=
np
.
array
([[
0.
0
,
1
,
2
,
3
],
[
4
,
5
,
6
,
7
],
[
8
,
9
,
10
,
11
],
[
12
,
13
,
14
,
15
]])
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_rm_r
(
ref2
),
ref2
)
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_rm_c
(
ref2
),
ref2
)
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_rm_r
(
ref2
[:,
1
]),
ref2
[:,
[
1
]])
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_rm_c
(
ref2
[
0
,
:]),
ref2
[[
0
],
:])
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_rm_r
(
ref2
[:,
(
0
,
2
)]),
ref2
[:,
(
0
,
2
)])
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_rm_c
(
ref2
[(
3
,
1
,
2
),
:]),
ref2
[(
3
,
1
,
2
),
:])
m
.
partial_copy_four_rm_r
(
ref2
[:,
(
0
,
2
)]),
ref2
[:,
(
0
,
2
)]
)
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_rm_c
(
ref2
[(
3
,
1
,
2
),
:]),
ref2
[(
3
,
1
,
2
),
:]
)
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_cm_r
(
ref2
),
ref2
)
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_cm_c
(
ref2
),
ref2
)
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_cm_r
(
ref2
[:,
1
]),
ref2
[:,
[
1
]])
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_cm_c
(
ref2
[
0
,
:]),
ref2
[[
0
],
:])
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_cm_r
(
ref2
[:,
(
0
,
2
)]),
ref2
[:,
(
0
,
2
)])
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_cm_c
(
ref2
[(
3
,
1
,
2
),
:]),
ref2
[(
3
,
1
,
2
),
:])
m
.
partial_copy_four_cm_r
(
ref2
[:,
(
0
,
2
)]),
ref2
[:,
(
0
,
2
)]
)
np
.
testing
.
assert_array_equal
(
m
.
partial_copy_four_cm_c
(
ref2
[(
3
,
1
,
2
),
:]),
ref2
[(
3
,
1
,
2
),
:]
)
# TypeError should be raise for a shape mismatch
functions
=
[
m
.
partial_copy_four_rm_r
,
m
.
partial_copy_four_rm_c
,
m
.
partial_copy_four_cm_r
,
m
.
partial_copy_four_cm_c
]
matrix_with_wrong_shape
=
[[
1
,
2
],
[
3
,
4
]]
functions
=
[
m
.
partial_copy_four_rm_r
,
m
.
partial_copy_four_rm_c
,
m
.
partial_copy_four_cm_r
,
m
.
partial_copy_four_cm_c
,
]
matrix_with_wrong_shape
=
[[
1
,
2
],
[
3
,
4
]]
for
f
in
functions
:
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
f
(
matrix_with_wrong_shape
)
...
...
@@ -69,7 +82,7 @@ def test_partially_fixed():
def
test_mutator_descriptors
():
zr
=
np
.
arange
(
30
,
dtype
=
'
float32
'
).
reshape
(
5
,
6
)
# row-major
zr
=
np
.
arange
(
30
,
dtype
=
"
float32
"
).
reshape
(
5
,
6
)
# row-major
zc
=
zr
.
reshape
(
6
,
5
).
transpose
()
# column-major
m
.
fixed_mutator_r
(
zr
)
...
...
@@ -78,18 +91,21 @@ def test_mutator_descriptors():
m
.
fixed_mutator_a
(
zc
)
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
fixed_mutator_r
(
zc
)
assert
(
'(arg0: numpy.ndarray[numpy.float32[5, 6],'
' flags.writeable, flags.c_contiguous]) -> None'
in
str
(
excinfo
.
value
))
assert
(
"(arg0: numpy.ndarray[numpy.float32[5, 6],"
" flags.writeable, flags.c_contiguous]) -> None"
in
str
(
excinfo
.
value
)
)
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
fixed_mutator_c
(
zr
)
assert
(
'(arg0: numpy.ndarray[numpy.float32[5, 6],'
' flags.writeable, flags.f_contiguous]) -> None'
in
str
(
excinfo
.
value
))
assert
(
"(arg0: numpy.ndarray[numpy.float32[5, 6],"
" flags.writeable, flags.f_contiguous]) -> None"
in
str
(
excinfo
.
value
)
)
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
fixed_mutator_a
(
np
.
array
([[
1
,
2
],
[
3
,
4
]],
dtype
=
'float32'
))
assert
(
'(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None'
in
str
(
excinfo
.
value
))
m
.
fixed_mutator_a
(
np
.
array
([[
1
,
2
],
[
3
,
4
]],
dtype
=
"float32"
))
assert
"(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None"
in
str
(
excinfo
.
value
)
zr
.
flags
.
writeable
=
False
with
pytest
.
raises
(
TypeError
):
m
.
fixed_mutator_r
(
zr
)
...
...
@@ -98,26 +114,26 @@ def test_mutator_descriptors():
def
test_cpp_casting
():
assert
m
.
cpp_copy
(
m
.
fixed_r
())
==
22.
assert
m
.
cpp_copy
(
m
.
fixed_c
())
==
22.
z
=
np
.
array
([[
5.
,
6
],
[
7
,
8
]])
assert
m
.
cpp_copy
(
z
)
==
7.
assert
m
.
cpp_copy
(
m
.
get_cm_ref
())
==
21.
assert
m
.
cpp_copy
(
m
.
get_rm_ref
())
==
21.
assert
m
.
cpp_ref_c
(
m
.
get_cm_ref
())
==
21.
assert
m
.
cpp_ref_r
(
m
.
get_rm_ref
())
==
21.
assert
m
.
cpp_copy
(
m
.
fixed_r
())
==
22.
0
assert
m
.
cpp_copy
(
m
.
fixed_c
())
==
22.
0
z
=
np
.
array
([[
5.
0
,
6
],
[
7
,
8
]])
assert
m
.
cpp_copy
(
z
)
==
7.
0
assert
m
.
cpp_copy
(
m
.
get_cm_ref
())
==
21.
0
assert
m
.
cpp_copy
(
m
.
get_rm_ref
())
==
21.
0
assert
m
.
cpp_ref_c
(
m
.
get_cm_ref
())
==
21.
0
assert
m
.
cpp_ref_r
(
m
.
get_rm_ref
())
==
21.
0
with
pytest
.
raises
(
RuntimeError
)
as
excinfo
:
# Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles
m
.
cpp_ref_any
(
m
.
fixed_c
())
assert
'
Unable to cast Python instance
'
in
str
(
excinfo
.
value
)
assert
"
Unable to cast Python instance
"
in
str
(
excinfo
.
value
)
with
pytest
.
raises
(
RuntimeError
)
as
excinfo
:
# Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles
m
.
cpp_ref_any
(
m
.
fixed_r
())
assert
'
Unable to cast Python instance
'
in
str
(
excinfo
.
value
)
assert
m
.
cpp_ref_any
(
m
.
ReturnTester
.
create
())
==
1.
assert
"
Unable to cast Python instance
"
in
str
(
excinfo
.
value
)
assert
m
.
cpp_ref_any
(
m
.
ReturnTester
.
create
())
==
1.
0
assert
m
.
cpp_ref_any
(
m
.
get_cm_ref
())
==
21.
assert
m
.
cpp_ref_any
(
m
.
get_cm_ref
())
==
21.
assert
m
.
cpp_ref_any
(
m
.
get_cm_ref
())
==
21.
0
assert
m
.
cpp_ref_any
(
m
.
get_cm_ref
())
==
21.
0
def
test_pass_readonly_array
():
...
...
@@ -149,7 +165,7 @@ def test_nonunit_stride_from_python():
# Mutator:
m
.
double_threer
(
second_row
)
m
.
double_threec
(
second_col
)
np
.
testing
.
assert_array_equal
(
counting_mat
,
[[
0.
,
2
,
2
],
[
6
,
16
,
10
],
[
6
,
14
,
8
]])
np
.
testing
.
assert_array_equal
(
counting_mat
,
[[
0.
0
,
2
,
2
],
[
6
,
16
,
10
],
[
6
,
14
,
8
]])
def
test_negative_stride_from_python
(
msg
):
...
...
@@ -178,26 +194,36 @@ def test_negative_stride_from_python(msg):
# Mutator:
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
double_threer
(
second_row
)
assert
msg
(
excinfo
.
value
)
==
"""
assert
(
msg
(
excinfo
.
value
)
==
"""
double_threer(): incompatible function arguments. The following argument types are supported:
1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None
Invoked with: """
+
repr
(
np
.
array
([
5.
,
4.
,
3.
],
dtype
=
'float32'
))
# noqa: E501 line too long
Invoked with: """
# noqa: E501 line too long
+
repr
(
np
.
array
([
5.0
,
4.0
,
3.0
],
dtype
=
"float32"
))
)
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
double_threec
(
second_col
)
assert
msg
(
excinfo
.
value
)
==
"""
assert
(
msg
(
excinfo
.
value
)
==
"""
double_threec(): incompatible function arguments. The following argument types are supported:
1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None
Invoked with: """
+
repr
(
np
.
array
([
7.
,
4.
,
1.
],
dtype
=
'float32'
))
# noqa: E501 line too long
Invoked with: """
# noqa: E501 line too long
+
repr
(
np
.
array
([
7.0
,
4.0
,
1.0
],
dtype
=
"float32"
))
)
def
test_nonunit_stride_to_python
():
assert
np
.
all
(
m
.
diagonal
(
ref
)
==
ref
.
diagonal
())
assert
np
.
all
(
m
.
diagonal_1
(
ref
)
==
ref
.
diagonal
(
1
))
for
i
in
range
(
-
5
,
7
):
assert
np
.
all
(
m
.
diagonal_n
(
ref
,
i
)
==
ref
.
diagonal
(
i
)),
"m.diagonal_n({})"
.
format
(
i
)
assert
np
.
all
(
m
.
diagonal_n
(
ref
,
i
)
==
ref
.
diagonal
(
i
)
),
"m.diagonal_n({})"
.
format
(
i
)
assert
np
.
all
(
m
.
block
(
ref
,
2
,
1
,
3
,
3
)
==
ref
[
2
:
5
,
1
:
4
])
assert
np
.
all
(
m
.
block
(
ref
,
1
,
4
,
4
,
2
)
==
ref
[
1
:,
4
:])
...
...
@@ -207,8 +233,10 @@ def test_nonunit_stride_to_python():
def
test_eigen_ref_to_python
():
chols
=
[
m
.
cholesky1
,
m
.
cholesky2
,
m
.
cholesky3
,
m
.
cholesky4
]
for
i
,
chol
in
enumerate
(
chols
,
start
=
1
):
mymat
=
chol
(
np
.
array
([[
1.
,
2
,
4
],
[
2
,
13
,
23
],
[
4
,
23
,
77
]]))
assert
np
.
all
(
mymat
==
np
.
array
([[
1
,
0
,
0
],
[
2
,
3
,
0
],
[
4
,
5
,
6
]])),
"cholesky{}"
.
format
(
i
)
mymat
=
chol
(
np
.
array
([[
1.0
,
2
,
4
],
[
2
,
13
,
23
],
[
4
,
23
,
77
]]))
assert
np
.
all
(
mymat
==
np
.
array
([[
1
,
0
,
0
],
[
2
,
3
,
0
],
[
4
,
5
,
6
]])
),
"cholesky{}"
.
format
(
i
)
def
assign_both
(
a1
,
a2
,
r
,
c
,
v
):
...
...
@@ -325,8 +353,12 @@ def test_eigen_return_references():
np
.
testing
.
assert_array_equal
(
a_block1
,
master
[
3
:
5
,
3
:
5
])
np
.
testing
.
assert_array_equal
(
a_block2
,
master
[
2
:
5
,
2
:
4
])
np
.
testing
.
assert_array_equal
(
a_block3
,
master
[
6
:
10
,
7
:
10
])
np
.
testing
.
assert_array_equal
(
a_corn1
,
master
[
0
::
master
.
shape
[
0
]
-
1
,
0
::
master
.
shape
[
1
]
-
1
])
np
.
testing
.
assert_array_equal
(
a_corn2
,
master
[
0
::
master
.
shape
[
0
]
-
1
,
0
::
master
.
shape
[
1
]
-
1
])
np
.
testing
.
assert_array_equal
(
a_corn1
,
master
[
0
::
master
.
shape
[
0
]
-
1
,
0
::
master
.
shape
[
1
]
-
1
]
)
np
.
testing
.
assert_array_equal
(
a_corn2
,
master
[
0
::
master
.
shape
[
0
]
-
1
,
0
::
master
.
shape
[
1
]
-
1
]
)
np
.
testing
.
assert_array_equal
(
a_copy1
,
c1want
)
np
.
testing
.
assert_array_equal
(
a_copy2
,
c2want
)
...
...
@@ -355,16 +387,28 @@ def test_eigen_keepalive():
cstats
=
ConstructorStats
.
get
(
m
.
ReturnTester
)
assert
cstats
.
alive
()
==
1
unsafe
=
[
a
.
ref
(),
a
.
ref_const
(),
a
.
block
(
1
,
2
,
3
,
4
)]
copies
=
[
a
.
copy_get
(),
a
.
copy_view
(),
a
.
copy_ref
(),
a
.
copy_ref_const
(),
a
.
copy_block
(
4
,
3
,
2
,
1
)]
copies
=
[
a
.
copy_get
(),
a
.
copy_view
(),
a
.
copy_ref
(),
a
.
copy_ref_const
(),
a
.
copy_block
(
4
,
3
,
2
,
1
),
]
del
a
assert
cstats
.
alive
()
==
0
del
unsafe
del
copies
for
meth
in
[
m
.
ReturnTester
.
get
,
m
.
ReturnTester
.
get_ptr
,
m
.
ReturnTester
.
view
,
m
.
ReturnTester
.
view_ptr
,
m
.
ReturnTester
.
ref_safe
,
m
.
ReturnTester
.
ref_const_safe
,
m
.
ReturnTester
.
corners
,
m
.
ReturnTester
.
corners_const
]:
for
meth
in
[
m
.
ReturnTester
.
get
,
m
.
ReturnTester
.
get_ptr
,
m
.
ReturnTester
.
view
,
m
.
ReturnTester
.
view_ptr
,
m
.
ReturnTester
.
ref_safe
,
m
.
ReturnTester
.
ref_const_safe
,
m
.
ReturnTester
.
corners
,
m
.
ReturnTester
.
corners_const
,
]:
assert_keeps_alive
(
m
.
ReturnTester
,
meth
)
for
meth
in
[
m
.
ReturnTester
.
block_safe
,
m
.
ReturnTester
.
block_const
]:
...
...
@@ -374,18 +418,18 @@ def test_eigen_keepalive():
def
test_eigen_ref_mutators
():
"""Tests Eigen's ability to mutate numpy values"""
orig
=
np
.
array
([[
1.
,
2
,
3
],
[
4
,
5
,
6
],
[
7
,
8
,
9
]])
orig
=
np
.
array
([[
1.
0
,
2
,
3
],
[
4
,
5
,
6
],
[
7
,
8
,
9
]])
zr
=
np
.
array
(
orig
)
zc
=
np
.
array
(
orig
,
order
=
'F'
)
zc
=
np
.
array
(
orig
,
order
=
"F"
)
m
.
add_rm
(
zr
,
1
,
0
,
100
)
assert
np
.
all
(
zr
==
np
.
array
([[
1.
,
2
,
3
],
[
104
,
5
,
6
],
[
7
,
8
,
9
]]))
assert
np
.
all
(
zr
==
np
.
array
([[
1.
0
,
2
,
3
],
[
104
,
5
,
6
],
[
7
,
8
,
9
]]))
m
.
add_cm
(
zc
,
1
,
0
,
200
)
assert
np
.
all
(
zc
==
np
.
array
([[
1.
,
2
,
3
],
[
204
,
5
,
6
],
[
7
,
8
,
9
]]))
assert
np
.
all
(
zc
==
np
.
array
([[
1.
0
,
2
,
3
],
[
204
,
5
,
6
],
[
7
,
8
,
9
]]))
m
.
add_any
(
zr
,
1
,
0
,
20
)
assert
np
.
all
(
zr
==
np
.
array
([[
1.
,
2
,
3
],
[
124
,
5
,
6
],
[
7
,
8
,
9
]]))
assert
np
.
all
(
zr
==
np
.
array
([[
1.
0
,
2
,
3
],
[
124
,
5
,
6
],
[
7
,
8
,
9
]]))
m
.
add_any
(
zc
,
1
,
0
,
10
)
assert
np
.
all
(
zc
==
np
.
array
([[
1.
,
2
,
3
],
[
214
,
5
,
6
],
[
7
,
8
,
9
]]))
assert
np
.
all
(
zc
==
np
.
array
([[
1.
0
,
2
,
3
],
[
214
,
5
,
6
],
[
7
,
8
,
9
]]))
# Can't reference a col-major array with a row-major Ref, and vice versa:
with
pytest
.
raises
(
TypeError
):
...
...
@@ -406,8 +450,8 @@ def test_eigen_ref_mutators():
cornersr
=
zr
[
0
::
2
,
0
::
2
]
cornersc
=
zc
[
0
::
2
,
0
::
2
]
assert
np
.
all
(
cornersr
==
np
.
array
([[
1.
,
3
],
[
7
,
9
]]))
assert
np
.
all
(
cornersc
==
np
.
array
([[
1.
,
3
],
[
7
,
9
]]))
assert
np
.
all
(
cornersr
==
np
.
array
([[
1.
0
,
3
],
[
7
,
9
]]))
assert
np
.
all
(
cornersc
==
np
.
array
([[
1.
0
,
3
],
[
7
,
9
]]))
with
pytest
.
raises
(
TypeError
):
m
.
add_rm
(
cornersr
,
0
,
1
,
25
)
...
...
@@ -419,8 +463,8 @@ def test_eigen_ref_mutators():
m
.
add_cm
(
cornersc
,
0
,
1
,
25
)
m
.
add_any
(
cornersr
,
0
,
1
,
25
)
m
.
add_any
(
cornersc
,
0
,
1
,
44
)
assert
np
.
all
(
zr
==
np
.
array
([[
1.
,
2
,
28
],
[
4
,
5
,
6
],
[
7
,
8
,
9
]]))
assert
np
.
all
(
zc
==
np
.
array
([[
1.
,
2
,
47
],
[
4
,
5
,
6
],
[
7
,
8
,
9
]]))
assert
np
.
all
(
zr
==
np
.
array
([[
1.
0
,
2
,
28
],
[
4
,
5
,
6
],
[
7
,
8
,
9
]]))
assert
np
.
all
(
zc
==
np
.
array
([[
1.
0
,
2
,
47
],
[
4
,
5
,
6
],
[
7
,
8
,
9
]]))
# You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method:
zro
=
zr
[
0
:
4
,
0
:
4
]
...
...
@@ -458,7 +502,7 @@ def test_numpy_ref_mutators():
assert
not
zrro
.
flags
.
owndata
and
not
zrro
.
flags
.
writeable
zc
[
1
,
2
]
=
99
expect
=
np
.
array
([[
11.
,
12
,
13
],
[
21
,
22
,
99
],
[
31
,
32
,
33
]])
expect
=
np
.
array
([[
11.
0
,
12
,
13
],
[
21
,
22
,
99
],
[
31
,
32
,
33
]])
# We should have just changed zc, of course, but also zcro and the original eigen matrix
assert
np
.
all
(
zc
==
expect
)
assert
np
.
all
(
zcro
==
expect
)
...
...
@@ -506,18 +550,20 @@ def test_both_ref_mutators():
assert
np
.
all
(
z
==
z3
)
assert
np
.
all
(
z
==
z4
)
assert
np
.
all
(
z
==
z5
)
expect
=
np
.
array
([[
0.
,
22
,
20
],
[
31
,
37
,
33
],
[
41
,
42
,
38
]])
expect
=
np
.
array
([[
0.
0
,
22
,
20
],
[
31
,
37
,
33
],
[
41
,
42
,
38
]])
assert
np
.
all
(
z
==
expect
)
y
=
np
.
array
(
range
(
100
),
dtype
=
'
float64
'
).
reshape
(
10
,
10
)
y
=
np
.
array
(
range
(
100
),
dtype
=
"
float64
"
).
reshape
(
10
,
10
)
y2
=
m
.
incr_matrix_any
(
y
,
10
)
# np -> eigen -> np
y3
=
m
.
incr_matrix_any
(
y2
[
0
::
2
,
0
::
2
],
-
33
)
# np -> eigen -> np slice -> np -> eigen -> np
y3
=
m
.
incr_matrix_any
(
y2
[
0
::
2
,
0
::
2
],
-
33
)
# np -> eigen -> np slice -> np -> eigen -> np
y4
=
m
.
even_rows
(
y3
)
# numpy -> eigen slice -> (... y3)
y5
=
m
.
even_cols
(
y4
)
# numpy -> eigen slice -> (... y4)
y6
=
m
.
incr_matrix_any
(
y5
,
1000
)
# numpy -> eigen -> (... y5)
# Apply same mutations using just numpy:
yexpect
=
np
.
array
(
range
(
100
),
dtype
=
'
float64
'
).
reshape
(
10
,
10
)
yexpect
=
np
.
array
(
range
(
100
),
dtype
=
"
float64
"
).
reshape
(
10
,
10
)
yexpect
+=
10
yexpect
[
0
::
2
,
0
::
2
]
-=
33
yexpect
[
0
::
4
,
0
::
4
]
+=
1000
...
...
@@ -532,10 +578,14 @@ def test_both_ref_mutators():
def
test_nocopy_wrapper
():
# get_elem requires a column-contiguous matrix reference, but should be
# callable with other types of matrix (via copying):
int_matrix_colmajor
=
np
.
array
([[
1
,
2
,
3
],
[
4
,
5
,
6
],
[
7
,
8
,
9
]],
order
=
'F'
)
dbl_matrix_colmajor
=
np
.
array
(
int_matrix_colmajor
,
dtype
=
'double'
,
order
=
'F'
,
copy
=
True
)
int_matrix_rowmajor
=
np
.
array
(
int_matrix_colmajor
,
order
=
'C'
,
copy
=
True
)
dbl_matrix_rowmajor
=
np
.
array
(
int_matrix_rowmajor
,
dtype
=
'double'
,
order
=
'C'
,
copy
=
True
)
int_matrix_colmajor
=
np
.
array
([[
1
,
2
,
3
],
[
4
,
5
,
6
],
[
7
,
8
,
9
]],
order
=
"F"
)
dbl_matrix_colmajor
=
np
.
array
(
int_matrix_colmajor
,
dtype
=
"double"
,
order
=
"F"
,
copy
=
True
)
int_matrix_rowmajor
=
np
.
array
(
int_matrix_colmajor
,
order
=
"C"
,
copy
=
True
)
dbl_matrix_rowmajor
=
np
.
array
(
int_matrix_rowmajor
,
dtype
=
"double"
,
order
=
"C"
,
copy
=
True
)
# All should be callable via get_elem:
assert
m
.
get_elem
(
int_matrix_colmajor
)
==
8
...
...
@@ -546,32 +596,38 @@ def test_nocopy_wrapper():
# All but the second should fail with m.get_elem_nocopy:
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
get_elem_nocopy
(
int_matrix_colmajor
)
assert
(
'get_elem_nocopy(): incompatible function arguments.'
in
str
(
excinfo
.
value
)
and
', flags.f_contiguous'
in
str
(
excinfo
.
value
))
assert
"get_elem_nocopy(): incompatible function arguments."
in
str
(
excinfo
.
value
)
and
", flags.f_contiguous"
in
str
(
excinfo
.
value
)
assert
m
.
get_elem_nocopy
(
dbl_matrix_colmajor
)
==
8
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
get_elem_nocopy
(
int_matrix_rowmajor
)
assert
(
'get_elem_nocopy(): incompatible function arguments.'
in
str
(
excinfo
.
value
)
and
', flags.f_contiguous'
in
str
(
excinfo
.
value
))
assert
"get_elem_nocopy(): incompatible function arguments."
in
str
(
excinfo
.
value
)
and
", flags.f_contiguous"
in
str
(
excinfo
.
value
)
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
get_elem_nocopy
(
dbl_matrix_rowmajor
)
assert
(
'get_elem_nocopy(): incompatible function arguments.'
in
str
(
excinfo
.
value
)
and
', flags.f_contiguous'
in
str
(
excinfo
.
value
))
assert
"get_elem_nocopy(): incompatible function arguments."
in
str
(
excinfo
.
value
)
and
", flags.f_contiguous"
in
str
(
excinfo
.
value
)
# For the row-major test, we take a long matrix in row-major, so only the third is allowed:
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
get_elem_rm_nocopy
(
int_matrix_colmajor
)
assert
(
'get_elem_rm_nocopy(): incompatible function arguments.'
in
str
(
excinfo
.
value
)
and
', flags.c_contiguous'
in
str
(
excinfo
.
value
))
assert
"get_elem_rm_nocopy(): incompatible function arguments."
in
str
(
excinfo
.
value
)
and
", flags.c_contiguous"
in
str
(
excinfo
.
value
)
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
get_elem_rm_nocopy
(
dbl_matrix_colmajor
)
assert
(
'get_elem_rm_nocopy(): incompatible function arguments.'
in
str
(
excinfo
.
value
)
and
', flags.c_contiguous'
in
str
(
excinfo
.
value
))
assert
"get_elem_rm_nocopy(): incompatible function arguments."
in
str
(
excinfo
.
value
)
and
", flags.c_contiguous"
in
str
(
excinfo
.
value
)
assert
m
.
get_elem_rm_nocopy
(
int_matrix_rowmajor
)
==
8
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
get_elem_rm_nocopy
(
dbl_matrix_rowmajor
)
assert
(
'get_elem_rm_nocopy(): incompatible function arguments.'
in
str
(
excinfo
.
value
)
and
', flags.c_contiguous'
in
str
(
excinfo
.
value
))
assert
"get_elem_rm_nocopy(): incompatible function arguments."
in
str
(
excinfo
.
value
)
and
", flags.c_contiguous"
in
str
(
excinfo
.
value
)
def
test_eigen_ref_life_support
():
...
...
@@ -589,12 +645,9 @@ def test_eigen_ref_life_support():
def
test_special_matrix_objects
():
assert
np
.
all
(
m
.
incr_diag
(
7
)
==
np
.
diag
([
1.
,
2
,
3
,
4
,
5
,
6
,
7
]))
assert
np
.
all
(
m
.
incr_diag
(
7
)
==
np
.
diag
([
1.
0
,
2
,
3
,
4
,
5
,
6
,
7
]))
asymm
=
np
.
array
([[
1.
,
2
,
3
,
4
],
[
5
,
6
,
7
,
8
],
[
9
,
10
,
11
,
12
],
[
13
,
14
,
15
,
16
]])
asymm
=
np
.
array
([[
1.0
,
2
,
3
,
4
],
[
5
,
6
,
7
,
8
],
[
9
,
10
,
11
,
12
],
[
13
,
14
,
15
,
16
]])
symm_lower
=
np
.
array
(
asymm
)
symm_upper
=
np
.
array
(
asymm
)
for
i
in
range
(
4
):
...
...
@@ -607,41 +660,51 @@ def test_special_matrix_objects():
def
test_dense_signature
(
doc
):
assert
doc
(
m
.
double_col
)
==
"""
assert
(
doc
(
m
.
double_col
)
==
"""
double_col(arg0: numpy.ndarray[numpy.float32[m, 1]]) -> numpy.ndarray[numpy.float32[m, 1]]
"""
assert
doc
(
m
.
double_row
)
==
"""
)
assert
(
doc
(
m
.
double_row
)
==
"""
double_row(arg0: numpy.ndarray[numpy.float32[1, n]]) -> numpy.ndarray[numpy.float32[1, n]]
"""
assert
doc
(
m
.
double_complex
)
==
(
"""
)
assert
doc
(
m
.
double_complex
)
==
(
"""
double_complex(arg0: numpy.ndarray[numpy.complex64[m, 1]])"""
""" -> numpy.ndarray[numpy.complex64[m, 1]]
"""
)
assert
doc
(
m
.
double_mat_rm
)
==
(
"""
""" -> numpy.ndarray[numpy.complex64[m, 1]]
"""
)
assert
doc
(
m
.
double_mat_rm
)
==
(
"""
double_mat_rm(arg0: numpy.ndarray[numpy.float32[m, n]])"""
""" -> numpy.ndarray[numpy.float32[m, n]]
"""
)
""" -> numpy.ndarray[numpy.float32[m, n]]
"""
)
def
test_named_arguments
():
a
=
np
.
array
([[
1.0
,
2
],
[
3
,
4
],
[
5
,
6
]])
b
=
np
.
ones
((
2
,
1
))
assert
np
.
all
(
m
.
matrix_multiply
(
a
,
b
)
==
np
.
array
([[
3.
],
[
7
],
[
11
]]))
assert
np
.
all
(
m
.
matrix_multiply
(
A
=
a
,
B
=
b
)
==
np
.
array
([[
3.
],
[
7
],
[
11
]]))
assert
np
.
all
(
m
.
matrix_multiply
(
B
=
b
,
A
=
a
)
==
np
.
array
([[
3.
],
[
7
],
[
11
]]))
assert
np
.
all
(
m
.
matrix_multiply
(
a
,
b
)
==
np
.
array
([[
3.
0
],
[
7
],
[
11
]]))
assert
np
.
all
(
m
.
matrix_multiply
(
A
=
a
,
B
=
b
)
==
np
.
array
([[
3.
0
],
[
7
],
[
11
]]))
assert
np
.
all
(
m
.
matrix_multiply
(
B
=
b
,
A
=
a
)
==
np
.
array
([[
3.
0
],
[
7
],
[
11
]]))
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
m
.
matrix_multiply
(
b
,
a
)
assert
str
(
excinfo
.
value
)
==
'
Nonconformable matrices!
'
assert
str
(
excinfo
.
value
)
==
"
Nonconformable matrices!
"
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
m
.
matrix_multiply
(
A
=
b
,
B
=
a
)
assert
str
(
excinfo
.
value
)
==
'
Nonconformable matrices!
'
assert
str
(
excinfo
.
value
)
==
"
Nonconformable matrices!
"
with
pytest
.
raises
(
ValueError
)
as
excinfo
:
m
.
matrix_multiply
(
B
=
a
,
A
=
b
)
assert
str
(
excinfo
.
value
)
==
'
Nonconformable matrices!
'
assert
str
(
excinfo
.
value
)
==
"
Nonconformable matrices!
"
def
test_sparse
():
...
...
@@ -656,21 +719,31 @@ def test_sparse():
def
test_sparse_signature
(
doc
):
pytest
.
importorskip
(
"scipy"
)
assert
doc
(
m
.
sparse_copy_r
)
==
"""
assert
(
doc
(
m
.
sparse_copy_r
)
==
"""
sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32]
"""
# noqa: E501 line too long
assert
doc
(
m
.
sparse_copy_c
)
==
"""
)
assert
(
doc
(
m
.
sparse_copy_c
)
==
"""
sparse_copy_c(arg0: scipy.sparse.csc_matrix[numpy.float32]) -> scipy.sparse.csc_matrix[numpy.float32]
"""
# noqa: E501 line too long
)
def
test_issue738
():
"""Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)"""
assert
np
.
all
(
m
.
iss738_f1
(
np
.
array
([[
1.
,
2
,
3
]]))
==
np
.
array
([[
1.
,
102
,
203
]]))
assert
np
.
all
(
m
.
iss738_f1
(
np
.
array
([[
1.
],
[
2
],
[
3
]]))
==
np
.
array
([[
1.
],
[
12
],
[
23
]]))
assert
np
.
all
(
m
.
iss738_f2
(
np
.
array
([[
1.
,
2
,
3
]]))
==
np
.
array
([[
1.
,
102
,
203
]]))
assert
np
.
all
(
m
.
iss738_f2
(
np
.
array
([[
1.
],
[
2
],
[
3
]]))
==
np
.
array
([[
1.
],
[
12
],
[
23
]]))
assert
np
.
all
(
m
.
iss738_f1
(
np
.
array
([[
1.0
,
2
,
3
]]))
==
np
.
array
([[
1.0
,
102
,
203
]]))
assert
np
.
all
(
m
.
iss738_f1
(
np
.
array
([[
1.0
],
[
2
],
[
3
]]))
==
np
.
array
([[
1.0
],
[
12
],
[
23
]])
)
assert
np
.
all
(
m
.
iss738_f2
(
np
.
array
([[
1.0
,
2
,
3
]]))
==
np
.
array
([[
1.0
,
102
,
203
]]))
assert
np
.
all
(
m
.
iss738_f2
(
np
.
array
([[
1.0
],
[
2
],
[
3
]]))
==
np
.
array
([[
1.0
],
[
12
],
[
23
]])
)
def
test_issue1105
():
...
...
tests/test_enum.py
View file @
c50f90ec
...
...
@@ -24,18 +24,24 @@ def test_unscoped_enum():
assert
m
.
UnscopedEnum
.
EOne
.
name
==
"EOne"
# __members__ property
assert
m
.
UnscopedEnum
.
__members__
==
\
{
"EOne"
:
m
.
UnscopedEnum
.
EOne
,
"ETwo"
:
m
.
UnscopedEnum
.
ETwo
,
"EThree"
:
m
.
UnscopedEnum
.
EThree
}
assert
m
.
UnscopedEnum
.
__members__
==
{
"EOne"
:
m
.
UnscopedEnum
.
EOne
,
"ETwo"
:
m
.
UnscopedEnum
.
ETwo
,
"EThree"
:
m
.
UnscopedEnum
.
EThree
,
}
# __members__ readonly
with
pytest
.
raises
(
AttributeError
):
m
.
UnscopedEnum
.
__members__
=
{}
# __members__ returns a copy
foo
=
m
.
UnscopedEnum
.
__members__
foo
[
"bar"
]
=
"baz"
assert
m
.
UnscopedEnum
.
__members__
==
\
{
"EOne"
:
m
.
UnscopedEnum
.
EOne
,
"ETwo"
:
m
.
UnscopedEnum
.
ETwo
,
"EThree"
:
m
.
UnscopedEnum
.
EThree
}
assert
m
.
UnscopedEnum
.
__members__
==
{
"EOne"
:
m
.
UnscopedEnum
.
EOne
,
"ETwo"
:
m
.
UnscopedEnum
.
ETwo
,
"EThree"
:
m
.
UnscopedEnum
.
EThree
,
}
for
docstring_line
in
'''
An unscoped enumeration
for
docstring_line
in
"""
An unscoped enumeration
Members:
...
...
@@ -43,7 +49,9 @@ Members:
ETwo : Docstring for ETwo
EThree : Docstring for EThree'''
.
split
(
'
\n
'
):
EThree : Docstring for EThree"""
.
split
(
"
\n
"
):
assert
docstring_line
in
m
.
UnscopedEnum
.
__doc__
# Unscoped enums will accept ==/!= int comparisons
...
...
@@ -53,10 +61,10 @@ Members:
assert
y
!=
3
assert
3
!=
y
# Compare with None
assert
(
y
!=
None
)
# noqa: E711
assert
y
!=
None
# noqa: E711
assert
not
(
y
==
None
)
# noqa: E711
# Compare with an object
assert
(
y
!=
object
()
)
assert
y
!=
object
()
assert
not
(
y
==
object
())
# Compare with string
assert
y
!=
"2"
...
...
@@ -119,10 +127,10 @@ def test_scoped_enum():
assert
z
!=
3
assert
3
!=
z
# Compare with None
assert
(
z
!=
None
)
# noqa: E711
assert
z
!=
None
# noqa: E711
assert
not
(
z
==
None
)
# noqa: E711
# Compare with an object
assert
(
z
!=
object
()
)
assert
z
!=
object
()
assert
not
(
z
==
object
())
# Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions)
with
pytest
.
raises
(
TypeError
):
...
...
tests/test_eval_call.py
View file @
c50f90ec
# -*- coding: utf-8 -*-
# This file is called from 'test_eval.py'
if
'
call_test2
'
in
locals
():
if
"
call_test2
"
in
locals
():
call_test2
(
y
)
# noqa: F821 undefined name
tests/test_exceptions.py
View file @
c50f90ec
...
...
@@ -54,27 +54,27 @@ def test_python_alreadyset_in_destructor(monkeypatch, capsys):
hooked
=
False
triggered
=
[
False
]
# mutable, so Python 2.7 closure can modify it
if
hasattr
(
sys
,
'
unraisablehook
'
):
# Python 3.8+
if
hasattr
(
sys
,
"
unraisablehook
"
):
# Python 3.8+
hooked
=
True
default_hook
=
sys
.
unraisablehook
def
hook
(
unraisable_hook_args
):
exc_type
,
exc_value
,
exc_tb
,
err_msg
,
obj
=
unraisable_hook_args
if
obj
==
'
already_set demo
'
:
if
obj
==
"
already_set demo
"
:
triggered
[
0
]
=
True
default_hook
(
unraisable_hook_args
)
return
# Use monkeypatch so pytest can apply and remove the patch as appropriate
monkeypatch
.
setattr
(
sys
,
'
unraisablehook
'
,
hook
)
monkeypatch
.
setattr
(
sys
,
"
unraisablehook
"
,
hook
)
assert
m
.
python_alreadyset_in_destructor
(
'
already_set demo
'
)
is
True
assert
m
.
python_alreadyset_in_destructor
(
"
already_set demo
"
)
is
True
if
hooked
:
assert
triggered
[
0
]
is
True
_
,
captured_stderr
=
capsys
.
readouterr
()
# Error message is different in Python 2 and 3, check for words that appear in both
assert
'
ignored
'
in
captured_stderr
and
'
already_set demo
'
in
captured_stderr
assert
"
ignored
"
in
captured_stderr
and
"
already_set demo
"
in
captured_stderr
def
test_exception_matches
():
...
...
@@ -107,7 +107,9 @@ def test_custom(msg):
# Can we fall-through to the default handler?
with
pytest
.
raises
(
RuntimeError
)
as
excinfo
:
m
.
throws_logic_error
()
assert
msg
(
excinfo
.
value
)
==
"this error should fall through to the standard handler"
assert
(
msg
(
excinfo
.
value
)
==
"this error should fall through to the standard handler"
)
# OverFlow error translation.
with
pytest
.
raises
(
OverflowError
)
as
excinfo
:
...
...
@@ -166,7 +168,13 @@ def test_nested_throws(capture):
# C++ -> Python -> C++ -> Python
with
capture
:
m
.
try_catch
(
m
.
MyException5
,
pycatch
,
m
.
MyException
,
m
.
try_catch
,
m
.
MyException
,
throw_myex5
)
m
.
MyException5
,
pycatch
,
m
.
MyException
,
m
.
try_catch
,
m
.
MyException
,
throw_myex5
,
)
assert
str
(
capture
).
startswith
(
"MyException5: nested error 5"
)
# C++ -> Python -> C++
...
...
@@ -182,7 +190,6 @@ def test_nested_throws(capture):
# This can often happen if you wrap a pybind11 class in a Python wrapper
def
test_invalid_repr
():
class
MyRepr
(
object
):
def
__repr__
(
self
):
raise
AttributeError
(
"Example error"
)
...
...
tests/test_factory_constructors.py
View file @
c50f90ec
...
...
@@ -12,7 +12,10 @@ from pybind11_tests import ConstructorStats
def
test_init_factory_basic
():
"""Tests py::init_factory() wrapper around various ways of returning the object"""
cstats
=
[
ConstructorStats
.
get
(
c
)
for
c
in
[
m
.
TestFactory1
,
m
.
TestFactory2
,
m
.
TestFactory3
]]
cstats
=
[
ConstructorStats
.
get
(
c
)
for
c
in
[
m
.
TestFactory1
,
m
.
TestFactory2
,
m
.
TestFactory3
]
]
cstats
[
0
].
alive
()
# force gc
n_inst
=
ConstructorStats
.
detail_reg_inst
()
...
...
@@ -41,12 +44,12 @@ def test_init_factory_basic():
z3
=
m
.
TestFactory3
(
"bye"
)
assert
z3
.
value
==
"bye"
for
null_ptr_kind
in
[
tag
.
null_ptr
,
tag
.
null_unique_ptr
,
tag
.
null_shared_ptr
]:
for
null_ptr_kind
in
[
tag
.
null_ptr
,
tag
.
null_unique_ptr
,
tag
.
null_shared_ptr
]:
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
TestFactory3
(
null_ptr_kind
)
assert
str
(
excinfo
.
value
)
==
"pybind11::init(): factory function returned nullptr"
assert
(
str
(
excinfo
.
value
)
==
"pybind11::init(): factory function returned nullptr"
)
assert
[
i
.
alive
()
for
i
in
cstats
]
==
[
3
,
3
,
3
]
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
+
9
...
...
@@ -61,7 +64,7 @@ def test_init_factory_basic():
assert
[
i
.
values
()
for
i
in
cstats
]
==
[
[
"3"
,
"hi!"
],
[
"7"
,
"hi again"
],
[
"42"
,
"bye"
]
[
"42"
,
"bye"
]
,
]
assert
[
i
.
default_constructions
for
i
in
cstats
]
==
[
1
,
1
,
1
]
...
...
@@ -69,7 +72,9 @@ def test_init_factory_basic():
def
test_init_factory_signature
(
msg
):
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
m
.
TestFactory1
(
"invalid"
,
"constructor"
,
"arguments"
)
assert
msg
(
excinfo
.
value
)
==
"""
assert
(
msg
(
excinfo
.
value
)
==
"""
__init__(): incompatible constructor arguments. The following argument types are supported:
1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int)
2. m.factory_constructors.TestFactory1(arg0: str)
...
...
@@ -78,8 +83,11 @@ def test_init_factory_signature(msg):
Invoked with: 'invalid', 'constructor', 'arguments'
"""
# noqa: E501 line too long
)
assert
msg
(
m
.
TestFactory1
.
__init__
.
__doc__
)
==
"""
assert
(
msg
(
m
.
TestFactory1
.
__init__
.
__doc__
)
==
"""
__init__(*args, **kwargs)
Overloaded function.
...
...
@@ -91,12 +99,16 @@ def test_init_factory_signature(msg):
4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None
"""
# noqa: E501 line too long
)
def
test_init_factory_casting
():
"""Tests py::init_factory() wrapper with various upcasting and downcasting returns"""
cstats
=
[
ConstructorStats
.
get
(
c
)
for
c
in
[
m
.
TestFactory3
,
m
.
TestFactory4
,
m
.
TestFactory5
]]
cstats
=
[
ConstructorStats
.
get
(
c
)
for
c
in
[
m
.
TestFactory3
,
m
.
TestFactory4
,
m
.
TestFactory5
]
]
cstats
[
0
].
alive
()
# force gc
n_inst
=
ConstructorStats
.
detail_reg_inst
()
...
...
@@ -134,7 +146,7 @@ def test_init_factory_casting():
assert
[
i
.
values
()
for
i
in
cstats
]
==
[
[
"4"
,
"5"
,
"6"
,
"7"
,
"8"
],
[
"4"
,
"5"
,
"8"
],
[
"6"
,
"7"
]
[
"6"
,
"7"
]
,
]
...
...
@@ -204,7 +216,7 @@ def test_init_factory_alias():
assert
[
i
.
values
()
for
i
in
cstats
]
==
[
[
"1"
,
"8"
,
"3"
,
"4"
,
"5"
,
"6"
,
"123"
,
"10"
,
"47"
],
[
"hi there"
,
"3"
,
"4"
,
"6"
,
"move"
,
"123"
,
"why hello!"
,
"move"
,
"47"
]
[
"hi there"
,
"3"
,
"4"
,
"6"
,
"move"
,
"123"
,
"why hello!"
,
"move"
,
"47"
]
,
]
...
...
@@ -268,9 +280,11 @@ def test_init_factory_dual():
assert
not
g1
.
has_alias
()
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
PythFactory7
(
tag
.
shared_ptr
,
tag
.
invalid_base
,
14
)
assert
(
str
(
excinfo
.
value
)
==
"pybind11::init(): construction failed: returned holder-wrapped instance is not an "
"alias instance"
)
assert
(
str
(
excinfo
.
value
)
==
"pybind11::init(): construction failed: returned holder-wrapped instance is not an "
"alias instance"
)
assert
[
i
.
alive
()
for
i
in
cstats
]
==
[
13
,
7
]
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
+
13
...
...
@@ -284,7 +298,7 @@ def test_init_factory_dual():
assert
[
i
.
values
()
for
i
in
cstats
]
==
[
[
"1"
,
"2"
,
"3"
,
"4"
,
"5"
,
"6"
,
"7"
,
"8"
,
"9"
,
"100"
,
"11"
,
"12"
,
"13"
,
"14"
],
[
"2"
,
"4"
,
"6"
,
"8"
,
"9"
,
"100"
,
"12"
]
[
"2"
,
"4"
,
"6"
,
"8"
,
"9"
,
"100"
,
"12"
]
,
]
...
...
@@ -294,7 +308,7 @@ def test_no_placement_new(capture):
with
capture
:
a
=
m
.
NoPlacementNew
(
123
)
found
=
re
.
search
(
r
'
^operator new called, returning (\d+)\n$
'
,
str
(
capture
))
found
=
re
.
search
(
r
"
^operator new called, returning (\d+)\n$
"
,
str
(
capture
))
assert
found
assert
a
.
i
==
123
with
capture
:
...
...
@@ -305,7 +319,7 @@ def test_no_placement_new(capture):
with
capture
:
b
=
m
.
NoPlacementNew
()
found
=
re
.
search
(
r
'
^operator new called, returning (\d+)\n$
'
,
str
(
capture
))
found
=
re
.
search
(
r
"
^operator new called, returning (\d+)\n$
"
,
str
(
capture
))
assert
found
assert
b
.
i
==
100
with
capture
:
...
...
@@ -333,7 +347,7 @@ def create_and_destroy(*args):
def
strip_comments
(
s
):
return
re
.
sub
(
r
'
\s+#.*
'
,
''
,
s
)
return
re
.
sub
(
r
"
\s+#.*
"
,
""
,
s
)
def
test_reallocation_a
(
capture
,
msg
):
...
...
@@ -345,7 +359,9 @@ def test_reallocation_a(capture, msg):
with
capture
:
create_and_destroy
(
1
)
assert
msg
(
capture
)
==
"""
assert
(
msg
(
capture
)
==
"""
noisy new
noisy placement new
NoisyAlloc(int 1)
...
...
@@ -353,12 +369,14 @@ def test_reallocation_a(capture, msg):
~NoisyAlloc()
noisy delete
"""
)
def
test_reallocation_b
(
capture
,
msg
):
with
capture
:
create_and_destroy
(
1.5
)
assert
msg
(
capture
)
==
strip_comments
(
"""
assert
msg
(
capture
)
==
strip_comments
(
"""
noisy new # allocation required to attempt first overload
noisy delete # have to dealloc before considering factory init overload
noisy new # pointer factory calling "new", part 1: allocation
...
...
@@ -366,51 +384,59 @@ def test_reallocation_b(capture, msg):
---
~NoisyAlloc() # Destructor
noisy delete # operator delete
"""
)
"""
)
def
test_reallocation_c
(
capture
,
msg
):
with
capture
:
create_and_destroy
(
2
,
3
)
assert
msg
(
capture
)
==
strip_comments
(
"""
assert
msg
(
capture
)
==
strip_comments
(
"""
noisy new # pointer factory calling "new", allocation
NoisyAlloc(int 2) # constructor
---
~NoisyAlloc() # Destructor
noisy delete # operator delete
"""
)
"""
)
def
test_reallocation_d
(
capture
,
msg
):
with
capture
:
create_and_destroy
(
2.5
,
3
)
assert
msg
(
capture
)
==
strip_comments
(
"""
assert
msg
(
capture
)
==
strip_comments
(
"""
NoisyAlloc(double 2.5) # construction (local func variable: operator_new not called)
noisy new # return-by-value "new" part 1: allocation
~NoisyAlloc() # moved-away local func variable destruction
---
~NoisyAlloc() # Destructor
noisy delete # operator delete
"""
)
"""
)
def
test_reallocation_e
(
capture
,
msg
):
with
capture
:
create_and_destroy
(
3.5
,
4.5
)
assert
msg
(
capture
)
==
strip_comments
(
"""
assert
msg
(
capture
)
==
strip_comments
(
"""
noisy new # preallocation needed before invoking placement-new overload
noisy placement new # Placement new
NoisyAlloc(double 3.5) # construction
---
~NoisyAlloc() # Destructor
noisy delete # operator delete
"""
)
"""
)
def
test_reallocation_f
(
capture
,
msg
):
with
capture
:
create_and_destroy
(
4
,
0.5
)
assert
msg
(
capture
)
==
strip_comments
(
"""
assert
msg
(
capture
)
==
strip_comments
(
"""
noisy new # preallocation needed before invoking placement-new overload
noisy delete # deallocation of preallocated storage
noisy new # Factory pointer allocation
...
...
@@ -418,13 +444,15 @@ def test_reallocation_f(capture, msg):
---
~NoisyAlloc() # Destructor
noisy delete # operator delete
"""
)
"""
)
def
test_reallocation_g
(
capture
,
msg
):
with
capture
:
create_and_destroy
(
5
,
"hi"
)
assert
msg
(
capture
)
==
strip_comments
(
"""
assert
msg
(
capture
)
==
strip_comments
(
"""
noisy new # preallocation needed before invoking first placement new
noisy delete # delete before considering new-style constructor
noisy new # preallocation for second placement new
...
...
@@ -433,13 +461,15 @@ def test_reallocation_g(capture, msg):
---
~NoisyAlloc() # Destructor
noisy delete # operator delete
"""
)
"""
)
@
pytest
.
mark
.
skipif
(
"env.PY2"
)
def
test_invalid_self
():
"""Tests invocation of the pybind-registered base class with an invalid `self` argument. You
can only actually do this on Python 3: Python 2 raises an exception itself if you try."""
class
NotPybindDerived
(
object
):
pass
...
...
@@ -463,16 +493,26 @@ def test_invalid_self():
a
=
m
.
TestFactory2
(
tag
.
pointer
,
1
)
m
.
TestFactory6
.
__init__
(
a
,
tag
.
alias
,
1
)
elif
bad
==
3
:
m
.
TestFactory6
.
__init__
(
NotPybindDerived
.
__new__
(
NotPybindDerived
),
tag
.
base
,
1
)
m
.
TestFactory6
.
__init__
(
NotPybindDerived
.
__new__
(
NotPybindDerived
),
tag
.
base
,
1
)
elif
bad
==
4
:
m
.
TestFactory6
.
__init__
(
NotPybindDerived
.
__new__
(
NotPybindDerived
),
tag
.
alias
,
1
)
m
.
TestFactory6
.
__init__
(
NotPybindDerived
.
__new__
(
NotPybindDerived
),
tag
.
alias
,
1
)
for
arg
in
(
1
,
2
):
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
BrokenTF1
(
arg
)
assert
str
(
excinfo
.
value
)
==
"__init__(self, ...) called with invalid `self` argument"
assert
(
str
(
excinfo
.
value
)
==
"__init__(self, ...) called with invalid `self` argument"
)
for
arg
in
(
1
,
2
,
3
,
4
):
with
pytest
.
raises
(
TypeError
)
as
excinfo
:
BrokenTF6
(
arg
)
assert
str
(
excinfo
.
value
)
==
"__init__(self, ...) called with invalid `self` argument"
assert
(
str
(
excinfo
.
value
)
==
"__init__(self, ...) called with invalid `self` argument"
)
tests/test_gil_scoped.py
View file @
c50f90ec
...
...
@@ -21,6 +21,7 @@ def _run_in_process(target, *args, **kwargs):
def
_python_to_cpp_to_python
():
"""Calls different C++ functions that come back to Python."""
class
ExtendedVirtClass
(
m
.
VirtClass
):
def
virtual_func
(
self
):
pass
...
...
@@ -74,7 +75,9 @@ def test_python_to_cpp_to_python_from_thread_multiple_sequential():
It runs in a separate process to be able to stop and assert if it deadlocks.
"""
assert
_run_in_process
(
_python_to_cpp_to_python_from_threads
,
8
,
parallel
=
False
)
==
0
assert
(
_run_in_process
(
_python_to_cpp_to_python_from_threads
,
8
,
parallel
=
False
)
==
0
)
# TODO: FIXME on macOS Python 3.9
...
...
tests/test_iostream.py
View file @
c50f90ec
...
...
@@ -18,6 +18,7 @@ try:
# Python 3.4
from
contextlib
import
redirect_stdout
except
ImportError
:
@
contextmanager
def
redirect_stdout
(
target
):
original
=
sys
.
stdout
...
...
@@ -25,10 +26,12 @@ except ImportError:
yield
sys
.
stdout
=
original
try
:
# Python 3.5
from
contextlib
import
redirect_stderr
except
ImportError
:
@
contextmanager
def
redirect_stderr
(
target
):
original
=
sys
.
stderr
...
...
@@ -42,16 +45,16 @@ def test_captured(capsys):
m
.
captured_output
(
msg
)
stdout
,
stderr
=
capsys
.
readouterr
()
assert
stdout
==
msg
assert
stderr
==
''
assert
stderr
==
""
m
.
captured_output_default
(
msg
)
stdout
,
stderr
=
capsys
.
readouterr
()
assert
stdout
==
msg
assert
stderr
==
''
assert
stderr
==
""
m
.
captured_err
(
msg
)
stdout
,
stderr
=
capsys
.
readouterr
()
assert
stdout
==
''
assert
stdout
==
""
assert
stderr
==
msg
...
...
@@ -63,7 +66,7 @@ def test_captured_large_string(capsys):
m
.
captured_output_default
(
msg
)
stdout
,
stderr
=
capsys
.
readouterr
()
assert
stdout
==
msg
assert
stderr
==
''
assert
stderr
==
""
def
test_guard_capture
(
capsys
):
...
...
@@ -71,7 +74,7 @@ def test_guard_capture(capsys):
m
.
guard_output
(
msg
)
stdout
,
stderr
=
capsys
.
readouterr
()
assert
stdout
==
msg
assert
stderr
==
''
assert
stderr
==
""
def
test_series_captured
(
capture
):
...
...
@@ -88,7 +91,7 @@ def test_flush(capfd):
with
m
.
ostream_redirect
():
m
.
noisy_function
(
msg
,
flush
=
False
)
stdout
,
stderr
=
capfd
.
readouterr
()
assert
stdout
==
''
assert
stdout
==
""
m
.
noisy_function
(
msg2
,
flush
=
True
)
stdout
,
stderr
=
capfd
.
readouterr
()
...
...
@@ -107,15 +110,15 @@ def test_not_captured(capfd):
m
.
raw_output
(
msg
)
stdout
,
stderr
=
capfd
.
readouterr
()
assert
stdout
==
msg
assert
stderr
==
''
assert
stream
.
getvalue
()
==
''
assert
stderr
==
""
assert
stream
.
getvalue
()
==
""
stream
=
StringIO
()
with
redirect_stdout
(
stream
):
m
.
captured_output
(
msg
)
stdout
,
stderr
=
capfd
.
readouterr
()
assert
stdout
==
''
assert
stderr
==
''
assert
stdout
==
""
assert
stderr
==
""
assert
stream
.
getvalue
()
==
msg
...
...
@@ -125,16 +128,16 @@ def test_err(capfd):
with
redirect_stderr
(
stream
):
m
.
raw_err
(
msg
)
stdout
,
stderr
=
capfd
.
readouterr
()
assert
stdout
==
''
assert
stdout
==
""
assert
stderr
==
msg
assert
stream
.
getvalue
()
==
''
assert
stream
.
getvalue
()
==
""
stream
=
StringIO
()
with
redirect_stderr
(
stream
):
m
.
captured_err
(
msg
)
stdout
,
stderr
=
capfd
.
readouterr
()
assert
stdout
==
''
assert
stderr
==
''
assert
stdout
==
""
assert
stderr
==
""
assert
stream
.
getvalue
()
==
msg
...
...
@@ -146,8 +149,8 @@ def test_multi_captured(capfd):
m
.
captured_output
(
"c"
)
m
.
raw_output
(
"d"
)
stdout
,
stderr
=
capfd
.
readouterr
()
assert
stdout
==
'
bd
'
assert
stream
.
getvalue
()
==
'
ac
'
assert
stdout
==
"
bd
"
assert
stream
.
getvalue
()
==
"
ac
"
def
test_dual
(
capsys
):
...
...
@@ -164,14 +167,14 @@ def test_redirect(capfd):
m
.
raw_output
(
msg
)
stdout
,
stderr
=
capfd
.
readouterr
()
assert
stdout
==
msg
assert
stream
.
getvalue
()
==
''
assert
stream
.
getvalue
()
==
""
stream
=
StringIO
()
with
redirect_stdout
(
stream
):
with
m
.
ostream_redirect
():
m
.
raw_output
(
msg
)
stdout
,
stderr
=
capfd
.
readouterr
()
assert
stdout
==
''
assert
stdout
==
""
assert
stream
.
getvalue
()
==
msg
stream
=
StringIO
()
...
...
@@ -179,7 +182,7 @@ def test_redirect(capfd):
m
.
raw_output
(
msg
)
stdout
,
stderr
=
capfd
.
readouterr
()
assert
stdout
==
msg
assert
stream
.
getvalue
()
==
''
assert
stream
.
getvalue
()
==
""
def
test_redirect_err
(
capfd
):
...
...
@@ -193,7 +196,7 @@ def test_redirect_err(capfd):
m
.
raw_err
(
msg2
)
stdout
,
stderr
=
capfd
.
readouterr
()
assert
stdout
==
msg
assert
stderr
==
''
assert
stderr
==
""
assert
stream
.
getvalue
()
==
msg2
...
...
@@ -209,7 +212,7 @@ def test_redirect_both(capfd):
m
.
raw_output
(
msg
)
m
.
raw_err
(
msg2
)
stdout
,
stderr
=
capfd
.
readouterr
()
assert
stdout
==
''
assert
stderr
==
''
assert
stdout
==
""
assert
stderr
==
""
assert
stream
.
getvalue
()
==
msg
assert
stream2
.
getvalue
()
==
msg2
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment