mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
style: use Black everywhere (#2594)
* style: use Black everywhere * style: minor touchup from review
This commit is contained in:
parent
2e31e466dc
commit
c50f90eca6
@ -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
|
||||
|
@ -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("}")
|
||||
|
188
docs/conf.py
188
docs/conf.py
@ -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:
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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():
|
||||
|
@ -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'‽') == 0x203d
|
||||
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"‽") == 0x203D
|
||||
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'‽') == 0x203d
|
||||
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"‽") == 0x203D
|
||||
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'‽') == 0x203d
|
||||
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"‽") == 0x203D
|
||||
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\x00b")) == 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, 0xf0, 0x9f, 0x8e, 0x82]
|
||||
assert m.string_view16_chars(u"Hi 🎂") == [72, 105, 32, 0xd83c, 0xdf82]
|
||||
assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
||||
assert m.string_view16_chars(u"Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
|
||||
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, 0xf0, 0x9f, 0x8e, 0x82]
|
||||
assert m.string_view8_chars(u"Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 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)
|
||||
|
@ -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():
|
||||
|
@ -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])
|
||||
|
||||
|
@ -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():
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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():
|
||||
|
@ -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__
|
||||
|
@ -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_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., 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_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():
|
||||
|
@ -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):
|
||||
|
@ -1,5 +1,5 @@
|
||||
# -*- 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
|
||||
|
@ -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")
|
||||
|
@ -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"
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -15,11 +15,17 @@ def test_function_signatures(doc):
|
||||
assert doc(m.kw_func_udl) == "kw_func_udl(x: int, y: int = 300) -> str"
|
||||
assert doc(m.kw_func_udl_z) == "kw_func_udl_z(x: int, y: int = 0) -> str"
|
||||
assert doc(m.args_function) == "args_function(*args) -> tuple"
|
||||
assert doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple"
|
||||
assert doc(m.KWClass.foo0) == \
|
||||
"foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None"
|
||||
assert doc(m.KWClass.foo1) == \
|
||||
"foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None"
|
||||
assert (
|
||||
doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple"
|
||||
)
|
||||
assert (
|
||||
doc(m.KWClass.foo0)
|
||||
== "foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None"
|
||||
)
|
||||
assert (
|
||||
doc(m.KWClass.foo1)
|
||||
== "foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None"
|
||||
)
|
||||
|
||||
|
||||
def test_named_arguments(msg):
|
||||
@ -40,7 +46,9 @@ def test_named_arguments(msg):
|
||||
# noinspection PyArgumentList
|
||||
m.kw_func2(x=5, y=10, z=12)
|
||||
assert excinfo.match(
|
||||
r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))' + '{3}$')
|
||||
r"(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))"
|
||||
+ "{3}$"
|
||||
)
|
||||
|
||||
assert m.kw_func4() == "{13 17}"
|
||||
assert m.kw_func4(myList=[1, 2, 3]) == "{1 2 3}"
|
||||
@ -50,11 +58,11 @@ def test_named_arguments(msg):
|
||||
|
||||
|
||||
def test_arg_and_kwargs():
|
||||
args = 'arg1_value', 'arg2_value', 3
|
||||
args = "arg1_value", "arg2_value", 3
|
||||
assert m.args_function(*args) == args
|
||||
|
||||
args = 'a1', 'a2'
|
||||
kwargs = dict(arg3='a3', arg4=4)
|
||||
args = "a1", "a2"
|
||||
kwargs = dict(arg3="a3", arg4=4)
|
||||
assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs)
|
||||
|
||||
|
||||
@ -68,47 +76,71 @@ def test_mixed_args_and_kwargs(msg):
|
||||
assert mpa(1, 2.5) == (1, 2.5, ())
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
assert mpa(1)
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
mixed_plus_args(): incompatible function arguments. The following argument types are supported:
|
||||
1. (arg0: int, arg1: float, *args) -> tuple
|
||||
|
||||
Invoked with: 1
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
assert mpa()
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
mixed_plus_args(): incompatible function arguments. The following argument types are supported:
|
||||
1. (arg0: int, arg1: float, *args) -> tuple
|
||||
|
||||
Invoked with:
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
|
||||
assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (-2, 3.5, {'e': 2.71828, 'pi': 3.14159})
|
||||
assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (
|
||||
-2,
|
||||
3.5,
|
||||
{"e": 2.71828, "pi": 3.14159},
|
||||
)
|
||||
assert mpak(7, 7.7, 7.77, 7.777, 7.7777, minusseven=-7) == (
|
||||
7, 7.7, (7.77, 7.777, 7.7777), {'minusseven': -7})
|
||||
7,
|
||||
7.7,
|
||||
(7.77, 7.777, 7.7777),
|
||||
{"minusseven": -7},
|
||||
)
|
||||
assert mpakd() == (1, 3.14159, (), {})
|
||||
assert mpakd(3) == (3, 3.14159, (), {})
|
||||
assert mpakd(j=2.71828) == (1, 2.71828, (), {})
|
||||
assert mpakd(k=42) == (1, 3.14159, (), {'k': 42})
|
||||
assert mpakd(k=42) == (1, 3.14159, (), {"k": 42})
|
||||
assert mpakd(1, 1, 2, 3, 5, 8, then=13, followedby=21) == (
|
||||
1, 1, (2, 3, 5, 8), {'then': 13, 'followedby': 21})
|
||||
1,
|
||||
1,
|
||||
(2, 3, 5, 8),
|
||||
{"then": 13, "followedby": 21},
|
||||
)
|
||||
# Arguments specified both positionally and via kwargs should fail:
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
assert mpakd(1, i=1)
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
|
||||
1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
|
||||
|
||||
Invoked with: 1; kwargs: i=1
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
assert mpakd(1, 2, j=1)
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
|
||||
1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
|
||||
|
||||
Invoked with: 1, 2; kwargs: j=1
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
|
||||
|
||||
def test_keyword_only_args(msg):
|
||||
@ -134,9 +166,9 @@ def test_keyword_only_args(msg):
|
||||
assert m.kw_only_mixed(j=2, i=3) == (3, 2)
|
||||
assert m.kw_only_mixed(i=2, j=3) == (2, 3)
|
||||
|
||||
assert m.kw_only_plus_more(4, 5, k=6, extra=7) == (4, 5, 6, {'extra': 7})
|
||||
assert m.kw_only_plus_more(3, k=5, j=4, extra=6) == (3, 4, 5, {'extra': 6})
|
||||
assert m.kw_only_plus_more(2, k=3, extra=4) == (2, -1, 3, {'extra': 4})
|
||||
assert m.kw_only_plus_more(4, 5, k=6, extra=7) == (4, 5, 6, {"extra": 7})
|
||||
assert m.kw_only_plus_more(3, k=5, j=4, extra=6) == (3, 4, 5, {"extra": 6})
|
||||
assert m.kw_only_plus_more(2, k=3, extra=4) == (2, -1, 3, {"extra": 4})
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
assert m.kw_only_mixed(i=1) == (1,)
|
||||
@ -144,9 +176,12 @@ def test_keyword_only_args(msg):
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.register_invalid_kw_only(m)
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
arg(): cannot specify an unnamed argument after an kw_only() annotation
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def test_positional_only_args(msg):
|
||||
@ -194,7 +229,10 @@ def test_signatures():
|
||||
assert "kw_only_mixed(i: int, *, j: int) -> tuple\n" == m.kw_only_mixed.__doc__
|
||||
assert "pos_only_all(i: int, j: int, /) -> tuple\n" == m.pos_only_all.__doc__
|
||||
assert "pos_only_mix(i: int, /, j: int) -> tuple\n" == m.pos_only_mix.__doc__
|
||||
assert "pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple\n" == m.pos_kw_only_mix.__doc__
|
||||
assert (
|
||||
"pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple\n"
|
||||
== m.pos_kw_only_mix.__doc__
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.xfail("env.PYPY and env.PY2", reason="PyPy2 doesn't double count")
|
||||
@ -219,11 +257,18 @@ def test_args_refcount():
|
||||
assert m.args_function(-1, myval) == (-1, myval)
|
||||
assert refcount(myval) == expected
|
||||
|
||||
assert m.mixed_plus_args_kwargs(5, 6.0, myval, a=myval) == (5, 6.0, (myval,), {"a": myval})
|
||||
assert m.mixed_plus_args_kwargs(5, 6.0, myval, a=myval) == (
|
||||
5,
|
||||
6.0,
|
||||
(myval,),
|
||||
{"a": myval},
|
||||
)
|
||||
assert refcount(myval) == expected
|
||||
|
||||
assert m.args_kwargs_function(7, 8, myval, a=1, b=myval) == \
|
||||
((7, 8, myval), {"a": 1, "b": myval})
|
||||
assert m.args_kwargs_function(7, 8, myval, a=1, b=myval) == (
|
||||
(7, 8, myval),
|
||||
{"a": 1, "b": myval},
|
||||
)
|
||||
assert refcount(myval) == expected
|
||||
|
||||
exp3 = refcount(myval, myval, myval)
|
||||
|
@ -36,8 +36,8 @@ def test_local_bindings():
|
||||
assert i2.get() == 11
|
||||
assert i2.get2() == 12
|
||||
|
||||
assert not hasattr(i1, 'get2')
|
||||
assert not hasattr(i2, 'get3')
|
||||
assert not hasattr(i1, "get2")
|
||||
assert not hasattr(i2, "get3")
|
||||
|
||||
# Loading within the local module
|
||||
assert m.local_value(i1) == 5
|
||||
@ -55,7 +55,9 @@ def test_nonlocal_failure():
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
cm.register_nonlocal()
|
||||
assert str(excinfo.value) == 'generic_type: type "NonLocalType" is already registered!'
|
||||
assert (
|
||||
str(excinfo.value) == 'generic_type: type "NonLocalType" is already registered!'
|
||||
)
|
||||
|
||||
|
||||
def test_duplicate_local():
|
||||
@ -63,9 +65,12 @@ def test_duplicate_local():
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.register_local_external()
|
||||
import pybind11_tests
|
||||
|
||||
assert str(excinfo.value) == (
|
||||
'generic_type: type "LocalExternal" is already registered!'
|
||||
if hasattr(pybind11_tests, 'class_') else 'test_class not enabled')
|
||||
if hasattr(pybind11_tests, "class_")
|
||||
else "test_class not enabled"
|
||||
)
|
||||
|
||||
|
||||
def test_stl_bind_local():
|
||||
@ -98,8 +103,8 @@ def test_stl_bind_local():
|
||||
d1["b"] = v1[1]
|
||||
d2["c"] = v2[0]
|
||||
d2["d"] = v2[1]
|
||||
assert {i: d1[i].get() for i in d1} == {'a': 0, 'b': 1}
|
||||
assert {i: d2[i].get() for i in d2} == {'c': 2, 'd': 3}
|
||||
assert {i: d1[i].get() for i in d1} == {"a": 0, "b": 1}
|
||||
assert {i: d2[i].get() for i in d2} == {"c": 2, "d": 3}
|
||||
|
||||
|
||||
def test_stl_bind_global():
|
||||
@ -107,15 +112,21 @@ def test_stl_bind_global():
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
cm.register_nonlocal_map()
|
||||
assert str(excinfo.value) == 'generic_type: type "NonLocalMap" is already registered!'
|
||||
assert (
|
||||
str(excinfo.value) == 'generic_type: type "NonLocalMap" is already registered!'
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
cm.register_nonlocal_vec()
|
||||
assert str(excinfo.value) == 'generic_type: type "NonLocalVec" is already registered!'
|
||||
assert (
|
||||
str(excinfo.value) == 'generic_type: type "NonLocalVec" is already registered!'
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
cm.register_nonlocal_map2()
|
||||
assert str(excinfo.value) == 'generic_type: type "NonLocalMap2" is already registered!'
|
||||
assert (
|
||||
str(excinfo.value) == 'generic_type: type "NonLocalMap2" is already registered!'
|
||||
)
|
||||
|
||||
|
||||
def test_mixed_local_global():
|
||||
@ -123,6 +134,7 @@ def test_mixed_local_global():
|
||||
type can be registered even if the type is already registered globally. With the module,
|
||||
casting will go to the local type; outside the module casting goes to the global type."""
|
||||
import pybind11_cross_module_tests as cm
|
||||
|
||||
m.register_mixed_global()
|
||||
m.register_mixed_local()
|
||||
|
||||
@ -145,13 +157,26 @@ def test_mixed_local_global():
|
||||
a.append(cm.get_mixed_gl(11))
|
||||
a.append(cm.get_mixed_lg(12))
|
||||
|
||||
assert [x.get() for x in a] == \
|
||||
[101, 1002, 103, 1004, 105, 1006, 207, 2008, 109, 1010, 211, 2012]
|
||||
assert [x.get() for x in a] == [
|
||||
101,
|
||||
1002,
|
||||
103,
|
||||
1004,
|
||||
105,
|
||||
1006,
|
||||
207,
|
||||
2008,
|
||||
109,
|
||||
1010,
|
||||
211,
|
||||
2012,
|
||||
]
|
||||
|
||||
|
||||
def test_internal_locals_differ():
|
||||
"""Makes sure the internal local type map differs across the two modules"""
|
||||
import pybind11_cross_module_tests as cm
|
||||
|
||||
assert m.local_cpp_types_addr() != cm.local_cpp_types_addr()
|
||||
|
||||
|
||||
@ -169,12 +194,15 @@ def test_stl_caster_vs_stl_bind(msg):
|
||||
assert m.load_vector_via_caster(v2) == 6
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
cm.load_vector_via_binding(v2) == 6
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
load_vector_via_binding(): incompatible function arguments. The following argument types are supported:
|
||||
1. (arg0: pybind11_cross_module_tests.VectorInt) -> int
|
||||
|
||||
Invoked with: [1, 2, 3]
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
|
||||
|
||||
def test_cross_module_calls():
|
||||
|
@ -40,17 +40,17 @@ def test_methods_and_attributes():
|
||||
assert instance1.overloaded(0) == "(int)"
|
||||
assert instance1.overloaded(1, 1.0) == "(int, float)"
|
||||
assert instance1.overloaded(2.0, 2) == "(float, int)"
|
||||
assert instance1.overloaded(3, 3) == "(int, int)"
|
||||
assert instance1.overloaded(4., 4.) == "(float, float)"
|
||||
assert instance1.overloaded(3, 3) == "(int, int)"
|
||||
assert instance1.overloaded(4.0, 4.0) == "(float, float)"
|
||||
assert instance1.overloaded_const(-3) == "(int) const"
|
||||
assert instance1.overloaded_const(5, 5.0) == "(int, float) const"
|
||||
assert instance1.overloaded_const(6.0, 6) == "(float, int) const"
|
||||
assert instance1.overloaded_const(7, 7) == "(int, int) const"
|
||||
assert instance1.overloaded_const(8., 8.) == "(float, float) const"
|
||||
assert instance1.overloaded_const(7, 7) == "(int, int) const"
|
||||
assert instance1.overloaded_const(8.0, 8.0) == "(float, float) const"
|
||||
assert instance1.overloaded_float(1, 1) == "(float, float)"
|
||||
assert instance1.overloaded_float(1, 1.) == "(float, float)"
|
||||
assert instance1.overloaded_float(1., 1) == "(float, float)"
|
||||
assert instance1.overloaded_float(1., 1.) == "(float, float)"
|
||||
assert instance1.overloaded_float(1, 1.0) == "(float, float)"
|
||||
assert instance1.overloaded_float(1.0, 1) == "(float, float)"
|
||||
assert instance1.overloaded_float(1.0, 1.0) == "(float, float)"
|
||||
|
||||
assert instance1.value == 320
|
||||
instance1.value = 100
|
||||
@ -193,7 +193,10 @@ def test_metaclass_override():
|
||||
assert type(m.MetaclassOverride).__name__ == "type"
|
||||
|
||||
assert m.MetaclassOverride.readonly == 1
|
||||
assert type(m.MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property"
|
||||
assert (
|
||||
type(m.MetaclassOverride.__dict__["readonly"]).__name__
|
||||
== "pybind11_static_property"
|
||||
)
|
||||
|
||||
# Regular `type` replaces the property instead of calling `__set__()`
|
||||
m.MetaclassOverride.readonly = 2
|
||||
@ -206,22 +209,26 @@ def test_no_mixed_overloads():
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.ExampleMandA.add_mixed_overloads1()
|
||||
assert (str(excinfo.value) ==
|
||||
"overloading a method with both static and instance methods is not supported; " +
|
||||
("compile in debug mode for more details" if not debug_enabled else
|
||||
"error while attempting to bind static method ExampleMandA.overload_mixed1"
|
||||
"(arg0: float) -> str")
|
||||
)
|
||||
assert str(
|
||||
excinfo.value
|
||||
) == "overloading a method with both static and instance methods is not supported; " + (
|
||||
"compile in debug mode for more details"
|
||||
if not debug_enabled
|
||||
else "error while attempting to bind static method ExampleMandA.overload_mixed1"
|
||||
"(arg0: float) -> str"
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.ExampleMandA.add_mixed_overloads2()
|
||||
assert (str(excinfo.value) ==
|
||||
"overloading a method with both static and instance methods is not supported; " +
|
||||
("compile in debug mode for more details" if not debug_enabled else
|
||||
"error while attempting to bind instance method ExampleMandA.overload_mixed2"
|
||||
"(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)"
|
||||
" -> str")
|
||||
)
|
||||
assert str(
|
||||
excinfo.value
|
||||
) == "overloading a method with both static and instance methods is not supported; " + (
|
||||
"compile in debug mode for more details"
|
||||
if not debug_enabled
|
||||
else "error while attempting to bind instance method ExampleMandA.overload_mixed2"
|
||||
"(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)"
|
||||
" -> str"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
|
||||
@ -333,8 +340,8 @@ def test_bad_arg_default(msg):
|
||||
assert msg(excinfo.value) == (
|
||||
"arg(): could not convert default argument 'a: UnregisteredType' in function "
|
||||
"'should_fail' into a Python object (type not registered yet?)"
|
||||
if debug_enabled else
|
||||
"arg(): could not convert default argument into a Python object (type not registered "
|
||||
if debug_enabled
|
||||
else "arg(): could not convert default argument into a Python object (type not registered "
|
||||
"yet?). Compile in debug mode for more information."
|
||||
)
|
||||
|
||||
@ -343,8 +350,8 @@ def test_bad_arg_default(msg):
|
||||
assert msg(excinfo.value) == (
|
||||
"arg(): could not convert default argument 'UnregisteredType' in function "
|
||||
"'should_fail' into a Python object (type not registered yet?)"
|
||||
if debug_enabled else
|
||||
"arg(): could not convert default argument into a Python object (type not registered "
|
||||
if debug_enabled
|
||||
else "arg(): could not convert default argument into a Python object (type not registered "
|
||||
"yet?). Compile in debug mode for more information."
|
||||
)
|
||||
|
||||
@ -381,12 +388,15 @@ def test_accepts_none(msg):
|
||||
# The first one still raises because you can't pass None as a lvalue reference arg:
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
assert m.ok_none1(None) == -1
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
ok_none1(): incompatible function arguments. The following argument types are supported:
|
||||
1. (arg0: m.methods_and_attributes.NoneTester) -> int
|
||||
|
||||
Invoked with: None
|
||||
"""
|
||||
)
|
||||
|
||||
# The rest take the argument as pointer or holder, and accept None:
|
||||
assert m.ok_none2(None) == -1
|
||||
@ -402,13 +412,16 @@ def test_str_issue(msg):
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
str(m.StrIssue("no", "such", "constructor"))
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
__init__(): incompatible constructor arguments. The following argument types are supported:
|
||||
1. m.methods_and_attributes.StrIssue(arg0: int)
|
||||
2. m.methods_and_attributes.StrIssue()
|
||||
|
||||
Invoked with: 'no', 'such', 'constructor'
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def test_unregistered_base_implementations():
|
||||
@ -441,7 +454,7 @@ def test_ref_qualified():
|
||||
|
||||
|
||||
def test_overload_ordering():
|
||||
'Check to see if the normal overload order (first defined) and prepend overload order works'
|
||||
"Check to see if the normal overload order (first defined) and prepend overload order works"
|
||||
assert m.overload_order("string") == 1
|
||||
assert m.overload_order(0) == 4
|
||||
|
||||
@ -449,8 +462,14 @@ def test_overload_ordering():
|
||||
uni_name = type(u"").__name__
|
||||
|
||||
assert "1. overload_order(arg0: int) -> int" in m.overload_order.__doc__
|
||||
assert "2. overload_order(arg0: {}) -> int".format(uni_name) in m.overload_order.__doc__
|
||||
assert "3. overload_order(arg0: {}) -> int".format(uni_name) in m.overload_order.__doc__
|
||||
assert (
|
||||
"2. overload_order(arg0: {}) -> int".format(uni_name)
|
||||
in m.overload_order.__doc__
|
||||
)
|
||||
assert (
|
||||
"3. overload_order(arg0: {}) -> int".format(uni_name)
|
||||
in m.overload_order.__doc__
|
||||
)
|
||||
assert "4. overload_order(arg0: int) -> int" in m.overload_order.__doc__
|
||||
|
||||
with pytest.raises(TypeError) as err:
|
||||
|
@ -6,9 +6,13 @@ from pybind11_tests import ConstructorStats
|
||||
|
||||
def test_nested_modules():
|
||||
import pybind11_tests
|
||||
|
||||
assert pybind11_tests.__name__ == "pybind11_tests"
|
||||
assert pybind11_tests.modules.__name__ == "pybind11_tests.modules"
|
||||
assert pybind11_tests.modules.subsubmodule.__name__ == "pybind11_tests.modules.subsubmodule"
|
||||
assert (
|
||||
pybind11_tests.modules.subsubmodule.__name__
|
||||
== "pybind11_tests.modules.subsubmodule"
|
||||
)
|
||||
assert m.__name__ == "pybind11_tests.modules"
|
||||
assert ms.__name__ == "pybind11_tests.modules.subsubmodule"
|
||||
|
||||
@ -35,7 +39,7 @@ def test_reference_internal():
|
||||
del b
|
||||
assert astats.alive() == 0
|
||||
assert bstats.alive() == 0
|
||||
assert astats.values() == ['1', '2', '42', '43']
|
||||
assert astats.values() == ["1", "2", "42", "43"]
|
||||
assert bstats.values() == []
|
||||
assert astats.default_constructions == 0
|
||||
assert bstats.default_constructions == 1
|
||||
@ -54,7 +58,7 @@ def test_importing():
|
||||
from collections import OrderedDict
|
||||
|
||||
assert OD is OrderedDict
|
||||
assert str(OD([(1, 'a'), (2, 'b')])) == "OrderedDict([(1, 'a'), (2, 'b')])"
|
||||
assert str(OD([(1, "a"), (2, "b")])) == "OrderedDict([(1, 'a'), (2, 'b')])"
|
||||
|
||||
|
||||
def test_pydoc():
|
||||
|
@ -57,7 +57,6 @@ def test_multiple_inheritance_mix2():
|
||||
@pytest.mark.skipif("env.PYPY and env.PY2")
|
||||
@pytest.mark.xfail("env.PYPY and not env.PY2")
|
||||
def test_multiple_inheritance_python():
|
||||
|
||||
class MI1(m.Base1, m.Base2):
|
||||
def __init__(self, i, j):
|
||||
m.Base1.__init__(self, i)
|
||||
@ -163,7 +162,6 @@ def test_multiple_inheritance_python():
|
||||
|
||||
|
||||
def test_multiple_inheritance_python_many_bases():
|
||||
|
||||
class MIMany14(m.BaseN1, m.BaseN2, m.BaseN3, m.BaseN4):
|
||||
def __init__(self):
|
||||
m.BaseN1.__init__(self, 1)
|
||||
@ -178,8 +176,16 @@ def test_multiple_inheritance_python_many_bases():
|
||||
m.BaseN7.__init__(self, 7)
|
||||
m.BaseN8.__init__(self, 8)
|
||||
|
||||
class MIMany916(m.BaseN9, m.BaseN10, m.BaseN11, m.BaseN12, m.BaseN13, m.BaseN14, m.BaseN15,
|
||||
m.BaseN16):
|
||||
class MIMany916(
|
||||
m.BaseN9,
|
||||
m.BaseN10,
|
||||
m.BaseN11,
|
||||
m.BaseN12,
|
||||
m.BaseN13,
|
||||
m.BaseN14,
|
||||
m.BaseN15,
|
||||
m.BaseN16,
|
||||
):
|
||||
def __init__(self):
|
||||
m.BaseN9.__init__(self, 9)
|
||||
m.BaseN10.__init__(self, 10)
|
||||
@ -225,7 +231,6 @@ def test_multiple_inheritance_python_many_bases():
|
||||
|
||||
|
||||
def test_multiple_inheritance_virtbase():
|
||||
|
||||
class MITypePy(m.Base12a):
|
||||
def __init__(self, i, j):
|
||||
m.Base12a.__init__(self, i, j)
|
||||
@ -238,7 +243,7 @@ def test_multiple_inheritance_virtbase():
|
||||
|
||||
def test_mi_static_properties():
|
||||
"""Mixing bases with and without static properties should be possible
|
||||
and the result should be independent of base definition order"""
|
||||
and the result should be independent of base definition order"""
|
||||
|
||||
for d in (m.VanillaStaticMix1(), m.VanillaStaticMix2()):
|
||||
assert d.vanilla() == "Vanilla"
|
||||
|
@ -19,33 +19,36 @@ def test_dtypes():
|
||||
print(check)
|
||||
assert check.numpy == check.pybind11, check
|
||||
if check.numpy.num != check.pybind11.num:
|
||||
print("NOTE: typenum mismatch for {}: {} != {}".format(
|
||||
check, check.numpy.num, check.pybind11.num))
|
||||
print(
|
||||
"NOTE: typenum mismatch for {}: {} != {}".format(
|
||||
check, check.numpy.num, check.pybind11.num
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
@pytest.fixture(scope="function")
|
||||
def arr():
|
||||
return np.array([[1, 2, 3], [4, 5, 6]], '=u2')
|
||||
return np.array([[1, 2, 3], [4, 5, 6]], "=u2")
|
||||
|
||||
|
||||
def test_array_attributes():
|
||||
a = np.array(0, 'f8')
|
||||
a = np.array(0, "f8")
|
||||
assert m.ndim(a) == 0
|
||||
assert all(m.shape(a) == [])
|
||||
assert all(m.strides(a) == [])
|
||||
with pytest.raises(IndexError) as excinfo:
|
||||
m.shape(a, 0)
|
||||
assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
|
||||
assert str(excinfo.value) == "invalid axis: 0 (ndim = 0)"
|
||||
with pytest.raises(IndexError) as excinfo:
|
||||
m.strides(a, 0)
|
||||
assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
|
||||
assert str(excinfo.value) == "invalid axis: 0 (ndim = 0)"
|
||||
assert m.writeable(a)
|
||||
assert m.size(a) == 1
|
||||
assert m.itemsize(a) == 8
|
||||
assert m.nbytes(a) == 8
|
||||
assert m.owndata(a)
|
||||
|
||||
a = np.array([[1, 2, 3], [4, 5, 6]], 'u2').view()
|
||||
a = np.array([[1, 2, 3], [4, 5, 6]], "u2").view()
|
||||
a.flags.writeable = False
|
||||
assert m.ndim(a) == 2
|
||||
assert all(m.shape(a) == [2, 3])
|
||||
@ -56,10 +59,10 @@ def test_array_attributes():
|
||||
assert m.strides(a, 1) == 2
|
||||
with pytest.raises(IndexError) as excinfo:
|
||||
m.shape(a, 2)
|
||||
assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
|
||||
assert str(excinfo.value) == "invalid axis: 2 (ndim = 2)"
|
||||
with pytest.raises(IndexError) as excinfo:
|
||||
m.strides(a, 2)
|
||||
assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
|
||||
assert str(excinfo.value) == "invalid axis: 2 (ndim = 2)"
|
||||
assert not m.writeable(a)
|
||||
assert m.size(a) == 6
|
||||
assert m.itemsize(a) == 2
|
||||
@ -67,7 +70,9 @@ def test_array_attributes():
|
||||
assert not m.owndata(a)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)])
|
||||
@pytest.mark.parametrize(
|
||||
"args, ret", [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)]
|
||||
)
|
||||
def test_index_offset(arr, args, ret):
|
||||
assert m.index_at(arr, *args) == ret
|
||||
assert m.index_at_t(arr, *args) == ret
|
||||
@ -76,31 +81,46 @@ def test_index_offset(arr, args, ret):
|
||||
|
||||
|
||||
def test_dim_check_fail(arr):
|
||||
for func in (m.index_at, m.index_at_t, m.offset_at, m.offset_at_t, m.data, m.data_t,
|
||||
m.mutate_data, m.mutate_data_t):
|
||||
for func in (
|
||||
m.index_at,
|
||||
m.index_at_t,
|
||||
m.offset_at,
|
||||
m.offset_at_t,
|
||||
m.data,
|
||||
m.data_t,
|
||||
m.mutate_data,
|
||||
m.mutate_data_t,
|
||||
):
|
||||
with pytest.raises(IndexError) as excinfo:
|
||||
func(arr, 1, 2, 3)
|
||||
assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)'
|
||||
assert str(excinfo.value) == "too many indices for an array: 3 (ndim = 2)"
|
||||
|
||||
|
||||
@pytest.mark.parametrize('args, ret',
|
||||
[([], [1, 2, 3, 4, 5, 6]),
|
||||
([1], [4, 5, 6]),
|
||||
([0, 1], [2, 3, 4, 5, 6]),
|
||||
([1, 2], [6])])
|
||||
@pytest.mark.parametrize(
|
||||
"args, ret",
|
||||
[
|
||||
([], [1, 2, 3, 4, 5, 6]),
|
||||
([1], [4, 5, 6]),
|
||||
([0, 1], [2, 3, 4, 5, 6]),
|
||||
([1, 2], [6]),
|
||||
],
|
||||
)
|
||||
def test_data(arr, args, ret):
|
||||
from sys import byteorder
|
||||
|
||||
assert all(m.data_t(arr, *args) == ret)
|
||||
assert all(m.data(arr, *args)[(0 if byteorder == 'little' else 1)::2] == ret)
|
||||
assert all(m.data(arr, *args)[(1 if byteorder == 'little' else 0)::2] == 0)
|
||||
assert all(m.data(arr, *args)[(0 if byteorder == "little" else 1) :: 2] == ret)
|
||||
assert all(m.data(arr, *args)[(1 if byteorder == "little" else 0) :: 2] == 0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dim', [0, 1, 3])
|
||||
@pytest.mark.parametrize("dim", [0, 1, 3])
|
||||
def test_at_fail(arr, dim):
|
||||
for func in m.at_t, m.mutate_at_t:
|
||||
with pytest.raises(IndexError) as excinfo:
|
||||
func(arr, *([0] * dim))
|
||||
assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim)
|
||||
assert str(excinfo.value) == "index dimension mismatch: {} (ndim = 2)".format(
|
||||
dim
|
||||
)
|
||||
|
||||
|
||||
def test_at(arr):
|
||||
@ -113,10 +133,14 @@ def test_at(arr):
|
||||
|
||||
def test_mutate_readonly(arr):
|
||||
arr.flags.writeable = False
|
||||
for func, args in (m.mutate_data, ()), (m.mutate_data_t, ()), (m.mutate_at_t, (0, 0)):
|
||||
for func, args in (
|
||||
(m.mutate_data, ()),
|
||||
(m.mutate_data_t, ()),
|
||||
(m.mutate_at_t, (0, 0)),
|
||||
):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
func(arr, *args)
|
||||
assert str(excinfo.value) == 'array is not writeable'
|
||||
assert str(excinfo.value) == "array is not writeable"
|
||||
|
||||
|
||||
def test_mutate_data(arr):
|
||||
@ -134,14 +158,22 @@ def test_mutate_data(arr):
|
||||
|
||||
|
||||
def test_bounds_check(arr):
|
||||
for func in (m.index_at, m.index_at_t, m.data, m.data_t,
|
||||
m.mutate_data, m.mutate_data_t, m.at_t, m.mutate_at_t):
|
||||
for func in (
|
||||
m.index_at,
|
||||
m.index_at_t,
|
||||
m.data,
|
||||
m.data_t,
|
||||
m.mutate_data,
|
||||
m.mutate_data_t,
|
||||
m.at_t,
|
||||
m.mutate_at_t,
|
||||
):
|
||||
with pytest.raises(IndexError) as excinfo:
|
||||
func(arr, 2, 0)
|
||||
assert str(excinfo.value) == 'index 2 is out of bounds for axis 0 with size 2'
|
||||
assert str(excinfo.value) == "index 2 is out of bounds for axis 0 with size 2"
|
||||
with pytest.raises(IndexError) as excinfo:
|
||||
func(arr, 0, 4)
|
||||
assert str(excinfo.value) == 'index 4 is out of bounds for axis 1 with size 3'
|
||||
assert str(excinfo.value) == "index 4 is out of bounds for axis 1 with size 3"
|
||||
|
||||
|
||||
def test_make_c_f_array():
|
||||
@ -163,10 +195,11 @@ def test_make_empty_shaped_array():
|
||||
def test_wrap():
|
||||
def assert_references(a, b, base=None):
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
if base is None:
|
||||
base = a
|
||||
assert a is not b
|
||||
assert a.__array_interface__['data'][0] == b.__array_interface__['data'][0]
|
||||
assert a.__array_interface__["data"][0] == b.__array_interface__["data"][0]
|
||||
assert a.shape == b.shape
|
||||
assert a.strides == b.strides
|
||||
assert a.flags.c_contiguous == b.flags.c_contiguous
|
||||
@ -189,12 +222,12 @@ def test_wrap():
|
||||
a2 = m.wrap(a1)
|
||||
assert_references(a1, a2)
|
||||
|
||||
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='F')
|
||||
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="F")
|
||||
assert a1.flags.owndata and a1.base is None
|
||||
a2 = m.wrap(a1)
|
||||
assert_references(a1, a2)
|
||||
|
||||
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='C')
|
||||
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="C")
|
||||
a1.flags.writeable = False
|
||||
a2 = m.wrap(a1)
|
||||
assert_references(a1, a2)
|
||||
@ -224,11 +257,14 @@ def test_numpy_view(capture):
|
||||
assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32))
|
||||
del ac
|
||||
pytest.gc_collect()
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
ArrayClass()
|
||||
ArrayClass::numpy_view()
|
||||
ArrayClass::numpy_view()
|
||||
"""
|
||||
)
|
||||
ac_view_1[0] = 4
|
||||
ac_view_1[1] = 3
|
||||
assert ac_view_2[0] == 4
|
||||
@ -238,9 +274,12 @@ def test_numpy_view(capture):
|
||||
del ac_view_2
|
||||
pytest.gc_collect()
|
||||
pytest.gc_collect()
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
~ArrayClass()
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def test_cast_numpy_int64_to_uint64():
|
||||
@ -271,20 +310,22 @@ def test_constructors():
|
||||
|
||||
def test_overload_resolution(msg):
|
||||
# Exact overload matches:
|
||||
assert m.overloaded(np.array([1], dtype='float64')) == 'double'
|
||||
assert m.overloaded(np.array([1], dtype='float32')) == 'float'
|
||||
assert m.overloaded(np.array([1], dtype='ushort')) == 'unsigned short'
|
||||
assert m.overloaded(np.array([1], dtype='intc')) == 'int'
|
||||
assert m.overloaded(np.array([1], dtype='longlong')) == 'long long'
|
||||
assert m.overloaded(np.array([1], dtype='complex')) == 'double complex'
|
||||
assert m.overloaded(np.array([1], dtype='csingle')) == 'float complex'
|
||||
assert m.overloaded(np.array([1], dtype="float64")) == "double"
|
||||
assert m.overloaded(np.array([1], dtype="float32")) == "float"
|
||||
assert m.overloaded(np.array([1], dtype="ushort")) == "unsigned short"
|
||||
assert m.overloaded(np.array([1], dtype="intc")) == "int"
|
||||
assert m.overloaded(np.array([1], dtype="longlong")) == "long long"
|
||||
assert m.overloaded(np.array([1], dtype="complex")) == "double complex"
|
||||
assert m.overloaded(np.array([1], dtype="csingle")) == "float complex"
|
||||
|
||||
# No exact match, should call first convertible version:
|
||||
assert m.overloaded(np.array([1], dtype='uint8')) == 'double'
|
||||
assert m.overloaded(np.array([1], dtype="uint8")) == "double"
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.overloaded("not an array")
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
overloaded(): incompatible function arguments. The following argument types are supported:
|
||||
1. (arg0: numpy.ndarray[numpy.float64]) -> str
|
||||
2. (arg0: numpy.ndarray[numpy.float32]) -> str
|
||||
@ -296,15 +337,16 @@ def test_overload_resolution(msg):
|
||||
|
||||
Invoked with: 'not an array'
|
||||
"""
|
||||
)
|
||||
|
||||
assert m.overloaded2(np.array([1], dtype='float64')) == 'double'
|
||||
assert m.overloaded2(np.array([1], dtype='float32')) == 'float'
|
||||
assert m.overloaded2(np.array([1], dtype='complex64')) == 'float complex'
|
||||
assert m.overloaded2(np.array([1], dtype='complex128')) == 'double complex'
|
||||
assert m.overloaded2(np.array([1], dtype='float32')) == 'float'
|
||||
assert m.overloaded2(np.array([1], dtype="float64")) == "double"
|
||||
assert m.overloaded2(np.array([1], dtype="float32")) == "float"
|
||||
assert m.overloaded2(np.array([1], dtype="complex64")) == "float complex"
|
||||
assert m.overloaded2(np.array([1], dtype="complex128")) == "double complex"
|
||||
assert m.overloaded2(np.array([1], dtype="float32")) == "float"
|
||||
|
||||
assert m.overloaded3(np.array([1], dtype='float64')) == 'double'
|
||||
assert m.overloaded3(np.array([1], dtype='intc')) == 'int'
|
||||
assert m.overloaded3(np.array([1], dtype="float64")) == "double"
|
||||
assert m.overloaded3(np.array([1], dtype="intc")) == "int"
|
||||
expected_exc = """
|
||||
overloaded3(): incompatible function arguments. The following argument types are supported:
|
||||
1. (arg0: numpy.ndarray[numpy.int32]) -> str
|
||||
@ -313,47 +355,49 @@ def test_overload_resolution(msg):
|
||||
Invoked with: """
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.overloaded3(np.array([1], dtype='uintc'))
|
||||
assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype='uint32'))
|
||||
m.overloaded3(np.array([1], dtype="uintc"))
|
||||
assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype="uint32"))
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.overloaded3(np.array([1], dtype='float32'))
|
||||
assert msg(excinfo.value) == expected_exc + repr(np.array([1.], dtype='float32'))
|
||||
m.overloaded3(np.array([1], dtype="float32"))
|
||||
assert msg(excinfo.value) == expected_exc + repr(np.array([1.0], dtype="float32"))
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.overloaded3(np.array([1], dtype='complex'))
|
||||
assert msg(excinfo.value) == expected_exc + repr(np.array([1. + 0.j]))
|
||||
m.overloaded3(np.array([1], dtype="complex"))
|
||||
assert msg(excinfo.value) == expected_exc + repr(np.array([1.0 + 0.0j]))
|
||||
|
||||
# Exact matches:
|
||||
assert m.overloaded4(np.array([1], dtype='double')) == 'double'
|
||||
assert m.overloaded4(np.array([1], dtype='longlong')) == 'long long'
|
||||
assert m.overloaded4(np.array([1], dtype="double")) == "double"
|
||||
assert m.overloaded4(np.array([1], dtype="longlong")) == "long long"
|
||||
# Non-exact matches requiring conversion. Since float to integer isn't a
|
||||
# save conversion, it should go to the double overload, but short can go to
|
||||
# either (and so should end up on the first-registered, the long long).
|
||||
assert m.overloaded4(np.array([1], dtype='float32')) == 'double'
|
||||
assert m.overloaded4(np.array([1], dtype='short')) == 'long long'
|
||||
assert m.overloaded4(np.array([1], dtype="float32")) == "double"
|
||||
assert m.overloaded4(np.array([1], dtype="short")) == "long long"
|
||||
|
||||
assert m.overloaded5(np.array([1], dtype='double')) == 'double'
|
||||
assert m.overloaded5(np.array([1], dtype='uintc')) == 'unsigned int'
|
||||
assert m.overloaded5(np.array([1], dtype='float32')) == 'unsigned int'
|
||||
assert m.overloaded5(np.array([1], dtype="double")) == "double"
|
||||
assert m.overloaded5(np.array([1], dtype="uintc")) == "unsigned int"
|
||||
assert m.overloaded5(np.array([1], dtype="float32")) == "unsigned int"
|
||||
|
||||
|
||||
def test_greedy_string_overload():
|
||||
"""Tests fix for #685 - ndarray shouldn't go to std::string overload"""
|
||||
|
||||
assert m.issue685("abc") == "string"
|
||||
assert m.issue685(np.array([97, 98, 99], dtype='b')) == "array"
|
||||
assert m.issue685(np.array([97, 98, 99], dtype="b")) == "array"
|
||||
assert m.issue685(123) == "other"
|
||||
|
||||
|
||||
def test_array_unchecked_fixed_dims(msg):
|
||||
z1 = np.array([[1, 2], [3, 4]], dtype='float64')
|
||||
z1 = np.array([[1, 2], [3, 4]], dtype="float64")
|
||||
m.proxy_add2(z1, 10)
|
||||
assert np.all(z1 == [[11, 12], [13, 14]])
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
m.proxy_add2(np.array([1., 2, 3]), 5.0)
|
||||
assert msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2"
|
||||
m.proxy_add2(np.array([1.0, 2, 3]), 5.0)
|
||||
assert (
|
||||
msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2"
|
||||
)
|
||||
|
||||
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int')
|
||||
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype="int")
|
||||
assert np.all(m.proxy_init3(3.0) == expect_c)
|
||||
expect_f = np.transpose(expect_c)
|
||||
assert np.all(m.proxy_init3F(3.0) == expect_f)
|
||||
@ -369,11 +413,11 @@ def test_array_unchecked_fixed_dims(msg):
|
||||
|
||||
|
||||
def test_array_unchecked_dyn_dims(msg):
|
||||
z1 = np.array([[1, 2], [3, 4]], dtype='float64')
|
||||
z1 = np.array([[1, 2], [3, 4]], dtype="float64")
|
||||
m.proxy_add2_dyn(z1, 10)
|
||||
assert np.all(z1 == [[11, 12], [13, 14]])
|
||||
|
||||
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int')
|
||||
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype="int")
|
||||
assert np.all(m.proxy_init3_dyn(3.0) == expect_c)
|
||||
|
||||
assert m.proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
|
||||
@ -383,15 +427,15 @@ def test_array_unchecked_dyn_dims(msg):
|
||||
def test_array_failure():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
m.array_fail_test()
|
||||
assert str(excinfo.value) == 'cannot create a pybind11::array from a nullptr'
|
||||
assert str(excinfo.value) == "cannot create a pybind11::array from a nullptr"
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
m.array_t_fail_test()
|
||||
assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr'
|
||||
assert str(excinfo.value) == "cannot create a pybind11::array_t from a nullptr"
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
m.array_fail_test_negative_size()
|
||||
assert str(excinfo.value) == 'negative dimensions are not allowed'
|
||||
assert str(excinfo.value) == "negative dimensions are not allowed"
|
||||
|
||||
|
||||
def test_initializer_list():
|
||||
@ -402,35 +446,35 @@ def test_initializer_list():
|
||||
|
||||
|
||||
def test_array_resize(msg):
|
||||
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='float64')
|
||||
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype="float64")
|
||||
m.array_reshape2(a)
|
||||
assert(a.size == 9)
|
||||
assert(np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
|
||||
assert a.size == 9
|
||||
assert np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
||||
|
||||
# total size change should succced with refcheck off
|
||||
m.array_resize3(a, 4, False)
|
||||
assert(a.size == 64)
|
||||
assert a.size == 64
|
||||
# ... and fail with refcheck on
|
||||
try:
|
||||
m.array_resize3(a, 3, True)
|
||||
except ValueError as e:
|
||||
assert(str(e).startswith("cannot resize an array"))
|
||||
assert str(e).startswith("cannot resize an array")
|
||||
# transposed array doesn't own data
|
||||
b = a.transpose()
|
||||
try:
|
||||
m.array_resize3(b, 3, False)
|
||||
except ValueError as e:
|
||||
assert(str(e).startswith("cannot resize this array: it does not own its data"))
|
||||
assert str(e).startswith("cannot resize this array: it does not own its data")
|
||||
# ... but reshape should be fine
|
||||
m.array_reshape2(b)
|
||||
assert(b.shape == (8, 8))
|
||||
assert b.shape == (8, 8)
|
||||
|
||||
|
||||
@pytest.mark.xfail("env.PYPY")
|
||||
def test_array_create_and_resize(msg):
|
||||
a = m.create_and_resize(2)
|
||||
assert(a.size == 4)
|
||||
assert(np.all(a == 42.))
|
||||
assert a.size == 4
|
||||
assert np.all(a == 42.0)
|
||||
|
||||
|
||||
def test_index_using_ellipsis():
|
||||
@ -439,16 +483,16 @@ def test_index_using_ellipsis():
|
||||
|
||||
|
||||
@pytest.mark.parametrize("forcecast", [False, True])
|
||||
@pytest.mark.parametrize("contiguity", [None, 'C', 'F'])
|
||||
@pytest.mark.parametrize("contiguity", [None, "C", "F"])
|
||||
@pytest.mark.parametrize("noconvert", [False, True])
|
||||
@pytest.mark.filterwarnings(
|
||||
"ignore:Casting complex values to real discards the imaginary part:numpy.ComplexWarning"
|
||||
)
|
||||
def test_argument_conversions(forcecast, contiguity, noconvert):
|
||||
function_name = "accept_double"
|
||||
if contiguity == 'C':
|
||||
if contiguity == "C":
|
||||
function_name += "_c_style"
|
||||
elif contiguity == 'F':
|
||||
elif contiguity == "F":
|
||||
function_name += "_f_style"
|
||||
if forcecast:
|
||||
function_name += "_forcecast"
|
||||
@ -456,37 +500,39 @@ def test_argument_conversions(forcecast, contiguity, noconvert):
|
||||
function_name += "_noconvert"
|
||||
function = getattr(m, function_name)
|
||||
|
||||
for dtype in [np.dtype('float32'), np.dtype('float64'), np.dtype('complex128')]:
|
||||
for order in ['C', 'F']:
|
||||
for dtype in [np.dtype("float32"), np.dtype("float64"), np.dtype("complex128")]:
|
||||
for order in ["C", "F"]:
|
||||
for shape in [(2, 2), (1, 3, 1, 1), (1, 1, 1), (0,)]:
|
||||
if not noconvert:
|
||||
# If noconvert is not passed, only complex128 needs to be truncated and
|
||||
# "cannot be safely obtained". So without `forcecast`, the argument shouldn't
|
||||
# be accepted.
|
||||
should_raise = dtype.name == 'complex128' and not forcecast
|
||||
should_raise = dtype.name == "complex128" and not forcecast
|
||||
else:
|
||||
# If noconvert is passed, only float64 and the matching order is accepted.
|
||||
# If at most one dimension has a size greater than 1, the array is also
|
||||
# trivially contiguous.
|
||||
trivially_contiguous = sum(1 for d in shape if d > 1) <= 1
|
||||
should_raise = (
|
||||
dtype.name != 'float64' or
|
||||
(contiguity is not None and
|
||||
contiguity != order and
|
||||
not trivially_contiguous)
|
||||
should_raise = dtype.name != "float64" or (
|
||||
contiguity is not None
|
||||
and contiguity != order
|
||||
and not trivially_contiguous
|
||||
)
|
||||
|
||||
array = np.zeros(shape, dtype=dtype, order=order)
|
||||
if not should_raise:
|
||||
function(array)
|
||||
else:
|
||||
with pytest.raises(TypeError, match="incompatible function arguments"):
|
||||
with pytest.raises(
|
||||
TypeError, match="incompatible function arguments"
|
||||
):
|
||||
function(array)
|
||||
|
||||
|
||||
@pytest.mark.xfail("env.PYPY")
|
||||
def test_dtype_refcount_leak():
|
||||
from sys import getrefcount
|
||||
|
||||
dtype = np.dtype(np.float_)
|
||||
a = np.array([1], dtype=dtype)
|
||||
before = getrefcount(dtype)
|
||||
|
@ -10,57 +10,71 @@ from pybind11_tests import numpy_dtypes as m
|
||||
np = pytest.importorskip("numpy")
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
@pytest.fixture(scope="module")
|
||||
def simple_dtype():
|
||||
ld = np.dtype('longdouble')
|
||||
return np.dtype({'names': ['bool_', 'uint_', 'float_', 'ldbl_'],
|
||||
'formats': ['?', 'u4', 'f4', 'f{}'.format(ld.itemsize)],
|
||||
'offsets': [0, 4, 8, (16 if ld.alignment > 4 else 12)]})
|
||||
ld = np.dtype("longdouble")
|
||||
return np.dtype(
|
||||
{
|
||||
"names": ["bool_", "uint_", "float_", "ldbl_"],
|
||||
"formats": ["?", "u4", "f4", "f{}".format(ld.itemsize)],
|
||||
"offsets": [0, 4, 8, (16 if ld.alignment > 4 else 12)],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
@pytest.fixture(scope="module")
|
||||
def packed_dtype():
|
||||
return np.dtype([('bool_', '?'), ('uint_', 'u4'), ('float_', 'f4'), ('ldbl_', 'g')])
|
||||
return np.dtype([("bool_", "?"), ("uint_", "u4"), ("float_", "f4"), ("ldbl_", "g")])
|
||||
|
||||
|
||||
def dt_fmt():
|
||||
from sys import byteorder
|
||||
e = '<' if byteorder == 'little' else '>'
|
||||
return ("{{'names':['bool_','uint_','float_','ldbl_'],"
|
||||
" 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}'],"
|
||||
" 'offsets':[0,4,8,{}], 'itemsize':{}}}")
|
||||
|
||||
e = "<" if byteorder == "little" else ">"
|
||||
return (
|
||||
"{{'names':['bool_','uint_','float_','ldbl_'],"
|
||||
" 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}'],"
|
||||
" 'offsets':[0,4,8,{}], 'itemsize':{}}}"
|
||||
)
|
||||
|
||||
|
||||
def simple_dtype_fmt():
|
||||
ld = np.dtype('longdouble')
|
||||
ld = np.dtype("longdouble")
|
||||
simple_ld_off = 12 + 4 * (ld.alignment > 4)
|
||||
return dt_fmt().format(ld.itemsize, simple_ld_off, simple_ld_off + ld.itemsize)
|
||||
|
||||
|
||||
def packed_dtype_fmt():
|
||||
from sys import byteorder
|
||||
|
||||
return "[('bool_', '?'), ('uint_', '{e}u4'), ('float_', '{e}f4'), ('ldbl_', '{e}f{}')]".format(
|
||||
np.dtype('longdouble').itemsize, e='<' if byteorder == 'little' else '>')
|
||||
np.dtype("longdouble").itemsize, e="<" if byteorder == "little" else ">"
|
||||
)
|
||||
|
||||
|
||||
def partial_ld_offset():
|
||||
return 12 + 4 * (np.dtype('uint64').alignment > 4) + 8 + 8 * (
|
||||
np.dtype('longdouble').alignment > 8)
|
||||
return (
|
||||
12
|
||||
+ 4 * (np.dtype("uint64").alignment > 4)
|
||||
+ 8
|
||||
+ 8 * (np.dtype("longdouble").alignment > 8)
|
||||
)
|
||||
|
||||
|
||||
def partial_dtype_fmt():
|
||||
ld = np.dtype('longdouble')
|
||||
ld = np.dtype("longdouble")
|
||||
partial_ld_off = partial_ld_offset()
|
||||
return dt_fmt().format(ld.itemsize, partial_ld_off, partial_ld_off + ld.itemsize)
|
||||
|
||||
|
||||
def partial_nested_fmt():
|
||||
ld = np.dtype('longdouble')
|
||||
ld = np.dtype("longdouble")
|
||||
partial_nested_off = 8 + 8 * (ld.alignment > 8)
|
||||
partial_ld_off = partial_ld_offset()
|
||||
partial_nested_size = partial_nested_off * 2 + partial_ld_off + ld.itemsize
|
||||
return "{{'names':['a'], 'formats':[{}], 'offsets':[{}], 'itemsize':{}}}".format(
|
||||
partial_dtype_fmt(), partial_nested_off, partial_nested_size)
|
||||
partial_dtype_fmt(), partial_nested_off, partial_nested_size
|
||||
)
|
||||
|
||||
|
||||
def assert_equal(actual, expected_data, expected_dtype):
|
||||
@ -70,15 +84,19 @@ def assert_equal(actual, expected_data, expected_dtype):
|
||||
def test_format_descriptors():
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.get_format_unbound()
|
||||
assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value))
|
||||
assert re.match(
|
||||
"^NumPy type info missing for .*UnboundStruct.*$", str(excinfo.value)
|
||||
)
|
||||
|
||||
ld = np.dtype('longdouble')
|
||||
ldbl_fmt = ('4x' if ld.alignment > 4 else '') + ld.char
|
||||
ld = np.dtype("longdouble")
|
||||
ldbl_fmt = ("4x" if ld.alignment > 4 else "") + ld.char
|
||||
ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}"
|
||||
dbl = np.dtype('double')
|
||||
partial_fmt = ("^T{?:bool_:3xI:uint_:f:float_:" +
|
||||
str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) +
|
||||
"xg:ldbl_:}")
|
||||
dbl = np.dtype("double")
|
||||
partial_fmt = (
|
||||
"^T{?:bool_:3xI:uint_:f:float_:"
|
||||
+ str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8))
|
||||
+ "xg:ldbl_:}"
|
||||
)
|
||||
nested_extra = str(max(8, ld.alignment))
|
||||
assert m.print_format_descriptors() == [
|
||||
ss_fmt,
|
||||
@ -88,14 +106,15 @@ def test_format_descriptors():
|
||||
"^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}",
|
||||
"^T{3s:a:3s:b:}",
|
||||
"^T{(3)4s:a:(2)i:b:(3)B:c:1x(4, 2)f:d:}",
|
||||
'^T{q:e1:B:e2:}',
|
||||
'^T{Zf:cflt:Zd:cdbl:}'
|
||||
"^T{q:e1:B:e2:}",
|
||||
"^T{Zf:cflt:Zd:cdbl:}",
|
||||
]
|
||||
|
||||
|
||||
def test_dtype(simple_dtype):
|
||||
from sys import byteorder
|
||||
e = '<' if byteorder == 'little' else '>'
|
||||
|
||||
e = "<" if byteorder == "little" else ">"
|
||||
|
||||
assert m.print_dtypes() == [
|
||||
simple_dtype_fmt(),
|
||||
@ -104,30 +123,60 @@ def test_dtype(simple_dtype):
|
||||
partial_dtype_fmt(),
|
||||
partial_nested_fmt(),
|
||||
"[('a', 'S3'), ('b', 'S3')]",
|
||||
("{{'names':['a','b','c','d'], " +
|
||||
"'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('" + e + "f4', (4, 2))], " +
|
||||
"'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e),
|
||||
(
|
||||
"{{'names':['a','b','c','d'], "
|
||||
+ "'formats':[('S4', (3,)),('"
|
||||
+ e
|
||||
+ "i4', (2,)),('u1', (3,)),('"
|
||||
+ e
|
||||
+ "f4', (4, 2))], "
|
||||
+ "'offsets':[0,12,20,24], 'itemsize':56}}"
|
||||
).format(e=e),
|
||||
"[('e1', '" + e + "i8'), ('e2', 'u1')]",
|
||||
"[('x', 'i1'), ('y', '" + e + "u8')]",
|
||||
"[('cflt', '" + e + "c8'), ('cdbl', '" + e + "c16')]"
|
||||
"[('cflt', '" + e + "c8'), ('cdbl', '" + e + "c16')]",
|
||||
]
|
||||
|
||||
d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'],
|
||||
'offsets': [1, 10], 'itemsize': 20})
|
||||
d2 = np.dtype([('a', 'i4'), ('b', 'f4')])
|
||||
assert m.test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'),
|
||||
np.dtype('bool'), d1, d1, np.dtype('uint32'), d2]
|
||||
d1 = np.dtype(
|
||||
{
|
||||
"names": ["a", "b"],
|
||||
"formats": ["int32", "float64"],
|
||||
"offsets": [1, 10],
|
||||
"itemsize": 20,
|
||||
}
|
||||
)
|
||||
d2 = np.dtype([("a", "i4"), ("b", "f4")])
|
||||
assert m.test_dtype_ctors() == [
|
||||
np.dtype("int32"),
|
||||
np.dtype("float64"),
|
||||
np.dtype("bool"),
|
||||
d1,
|
||||
d1,
|
||||
np.dtype("uint32"),
|
||||
d2,
|
||||
]
|
||||
|
||||
assert m.test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True,
|
||||
np.dtype('int32').itemsize, simple_dtype.itemsize]
|
||||
assert m.test_dtype_methods() == [
|
||||
np.dtype("int32"),
|
||||
simple_dtype,
|
||||
False,
|
||||
True,
|
||||
np.dtype("int32").itemsize,
|
||||
simple_dtype.itemsize,
|
||||
]
|
||||
|
||||
assert m.trailing_padding_dtype() == m.buffer_to_dtype(np.zeros(1, m.trailing_padding_dtype()))
|
||||
assert m.trailing_padding_dtype() == m.buffer_to_dtype(
|
||||
np.zeros(1, m.trailing_padding_dtype())
|
||||
)
|
||||
|
||||
|
||||
def test_recarray(simple_dtype, packed_dtype):
|
||||
elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]
|
||||
|
||||
for func, dtype in [(m.create_rec_simple, simple_dtype), (m.create_rec_packed, packed_dtype)]:
|
||||
for func, dtype in [
|
||||
(m.create_rec_simple, simple_dtype),
|
||||
(m.create_rec_packed, packed_dtype),
|
||||
]:
|
||||
arr = func(0)
|
||||
assert arr.dtype == dtype
|
||||
assert_equal(arr, [], simple_dtype)
|
||||
@ -146,16 +195,16 @@ def test_recarray(simple_dtype, packed_dtype):
|
||||
assert m.print_rec_simple(arr) == [
|
||||
"s:0,0,0,-0",
|
||||
"s:1,1,1.5,-2.5",
|
||||
"s:0,2,3,-5"
|
||||
"s:0,2,3,-5",
|
||||
]
|
||||
else:
|
||||
assert m.print_rec_packed(arr) == [
|
||||
"p:0,0,0,-0",
|
||||
"p:1,1,1.5,-2.5",
|
||||
"p:0,2,3,-5"
|
||||
"p:0,2,3,-5",
|
||||
]
|
||||
|
||||
nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)])
|
||||
nested_dtype = np.dtype([("a", simple_dtype), ("b", packed_dtype)])
|
||||
|
||||
arr = m.create_rec_nested(0)
|
||||
assert arr.dtype == nested_dtype
|
||||
@ -163,33 +212,39 @@ def test_recarray(simple_dtype, packed_dtype):
|
||||
|
||||
arr = m.create_rec_nested(3)
|
||||
assert arr.dtype == nested_dtype
|
||||
assert_equal(arr, [((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)),
|
||||
((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)),
|
||||
((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5))], nested_dtype)
|
||||
assert_equal(
|
||||
arr,
|
||||
[
|
||||
((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)),
|
||||
((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)),
|
||||
((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5)),
|
||||
],
|
||||
nested_dtype,
|
||||
)
|
||||
assert m.print_rec_nested(arr) == [
|
||||
"n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5",
|
||||
"n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5",
|
||||
"n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5"
|
||||
"n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5",
|
||||
]
|
||||
|
||||
arr = m.create_rec_partial(3)
|
||||
assert str(arr.dtype) == partial_dtype_fmt()
|
||||
partial_dtype = arr.dtype
|
||||
assert '' not in arr.dtype.fields
|
||||
assert "" not in arr.dtype.fields
|
||||
assert partial_dtype.itemsize > simple_dtype.itemsize
|
||||
assert_equal(arr, elements, simple_dtype)
|
||||
assert_equal(arr, elements, packed_dtype)
|
||||
|
||||
arr = m.create_rec_partial_nested(3)
|
||||
assert str(arr.dtype) == partial_nested_fmt()
|
||||
assert '' not in arr.dtype.fields
|
||||
assert '' not in arr.dtype.fields['a'][0].fields
|
||||
assert "" not in arr.dtype.fields
|
||||
assert "" not in arr.dtype.fields["a"][0].fields
|
||||
assert arr.dtype.itemsize > partial_dtype.itemsize
|
||||
np.testing.assert_equal(arr['a'], m.create_rec_partial(3))
|
||||
np.testing.assert_equal(arr["a"], m.create_rec_partial(3))
|
||||
|
||||
|
||||
def test_array_constructors():
|
||||
data = np.arange(1, 7, dtype='int32')
|
||||
data = np.arange(1, 7, dtype="int32")
|
||||
for i in range(8):
|
||||
np.testing.assert_array_equal(m.test_array_ctors(10 + i), data.reshape((3, 2)))
|
||||
np.testing.assert_array_equal(m.test_array_ctors(20 + i), data.reshape((3, 2)))
|
||||
@ -205,82 +260,92 @@ def test_string_array():
|
||||
"a='',b=''",
|
||||
"a='a',b='a'",
|
||||
"a='ab',b='ab'",
|
||||
"a='abc',b='abc'"
|
||||
"a='abc',b='abc'",
|
||||
]
|
||||
dtype = arr.dtype
|
||||
assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc']
|
||||
assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc']
|
||||
assert arr["a"].tolist() == [b"", b"a", b"ab", b"abc"]
|
||||
assert arr["b"].tolist() == [b"", b"a", b"ab", b"abc"]
|
||||
arr = m.create_string_array(False)
|
||||
assert dtype == arr.dtype
|
||||
|
||||
|
||||
def test_array_array():
|
||||
from sys import byteorder
|
||||
e = '<' if byteorder == 'little' else '>'
|
||||
|
||||
e = "<" if byteorder == "little" else ">"
|
||||
|
||||
arr = m.create_array_array(3)
|
||||
assert str(arr.dtype) == (
|
||||
"{{'names':['a','b','c','d'], " +
|
||||
"'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " +
|
||||
"'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e)
|
||||
"{{'names':['a','b','c','d'], "
|
||||
+ "'formats':[('S4', (3,)),('"
|
||||
+ e
|
||||
+ "i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], "
|
||||
+ "'offsets':[0,12,20,24], 'itemsize':56}}"
|
||||
).format(e=e)
|
||||
assert m.print_array_array(arr) == [
|
||||
"a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," +
|
||||
"c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}",
|
||||
"a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," +
|
||||
"c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}",
|
||||
"a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001}," +
|
||||
"c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}",
|
||||
"a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1},"
|
||||
+ "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}",
|
||||
"a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001},"
|
||||
+ "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}",
|
||||
"a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001},"
|
||||
+ "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}",
|
||||
]
|
||||
assert arr['a'].tolist() == [[b'ABCD', b'KLMN', b'UVWX'],
|
||||
[b'WXYZ', b'GHIJ', b'QRST'],
|
||||
[b'STUV', b'CDEF', b'MNOP']]
|
||||
assert arr['b'].tolist() == [[0, 1], [1000, 1001], [2000, 2001]]
|
||||
assert arr["a"].tolist() == [
|
||||
[b"ABCD", b"KLMN", b"UVWX"],
|
||||
[b"WXYZ", b"GHIJ", b"QRST"],
|
||||
[b"STUV", b"CDEF", b"MNOP"],
|
||||
]
|
||||
assert arr["b"].tolist() == [[0, 1], [1000, 1001], [2000, 2001]]
|
||||
assert m.create_array_array(0).dtype == arr.dtype
|
||||
|
||||
|
||||
def test_enum_array():
|
||||
from sys import byteorder
|
||||
e = '<' if byteorder == 'little' else '>'
|
||||
|
||||
e = "<" if byteorder == "little" else ">"
|
||||
|
||||
arr = m.create_enum_array(3)
|
||||
dtype = arr.dtype
|
||||
assert dtype == np.dtype([('e1', e + 'i8'), ('e2', 'u1')])
|
||||
assert m.print_enum_array(arr) == [
|
||||
"e1=A,e2=X",
|
||||
"e1=B,e2=Y",
|
||||
"e1=A,e2=X"
|
||||
]
|
||||
assert arr['e1'].tolist() == [-1, 1, -1]
|
||||
assert arr['e2'].tolist() == [1, 2, 1]
|
||||
assert dtype == np.dtype([("e1", e + "i8"), ("e2", "u1")])
|
||||
assert m.print_enum_array(arr) == ["e1=A,e2=X", "e1=B,e2=Y", "e1=A,e2=X"]
|
||||
assert arr["e1"].tolist() == [-1, 1, -1]
|
||||
assert arr["e2"].tolist() == [1, 2, 1]
|
||||
assert m.create_enum_array(0).dtype == dtype
|
||||
|
||||
|
||||
def test_complex_array():
|
||||
from sys import byteorder
|
||||
e = '<' if byteorder == 'little' else '>'
|
||||
|
||||
e = "<" if byteorder == "little" else ">"
|
||||
|
||||
arr = m.create_complex_array(3)
|
||||
dtype = arr.dtype
|
||||
assert dtype == np.dtype([('cflt', e + 'c8'), ('cdbl', e + 'c16')])
|
||||
assert dtype == np.dtype([("cflt", e + "c8"), ("cdbl", e + "c16")])
|
||||
assert m.print_complex_array(arr) == [
|
||||
"c:(0,0.25),(0.5,0.75)",
|
||||
"c:(1,1.25),(1.5,1.75)",
|
||||
"c:(2,2.25),(2.5,2.75)"
|
||||
"c:(2,2.25),(2.5,2.75)",
|
||||
]
|
||||
assert arr['cflt'].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j]
|
||||
assert arr['cdbl'].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j]
|
||||
assert arr["cflt"].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j]
|
||||
assert arr["cdbl"].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j]
|
||||
assert m.create_complex_array(0).dtype == dtype
|
||||
|
||||
|
||||
def test_signature(doc):
|
||||
assert doc(m.create_rec_nested) == \
|
||||
"create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
|
||||
assert (
|
||||
doc(m.create_rec_nested)
|
||||
== "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
|
||||
)
|
||||
|
||||
|
||||
def test_scalar_conversion():
|
||||
n = 3
|
||||
arrays = [m.create_rec_simple(n), m.create_rec_packed(n),
|
||||
m.create_rec_nested(n), m.create_enum_array(n)]
|
||||
arrays = [
|
||||
m.create_rec_simple(n),
|
||||
m.create_rec_packed(n),
|
||||
m.create_rec_nested(n),
|
||||
m.create_enum_array(n),
|
||||
]
|
||||
funcs = [m.f_simple, m.f_packed, m.f_nested]
|
||||
|
||||
for i, func in enumerate(funcs):
|
||||
@ -290,7 +355,7 @@ def test_scalar_conversion():
|
||||
else:
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
func(arr[0])
|
||||
assert 'incompatible function arguments' in str(excinfo.value)
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_vectorize():
|
||||
@ -304,14 +369,14 @@ def test_vectorize():
|
||||
|
||||
def test_cls_and_dtype_conversion(simple_dtype):
|
||||
s = m.SimpleStruct()
|
||||
assert s.astuple() == (False, 0, 0., 0.)
|
||||
assert s.astuple() == (False, 0, 0.0, 0.0)
|
||||
assert m.SimpleStruct.fromtuple(s.astuple()).astuple() == s.astuple()
|
||||
|
||||
s.uint_ = 2
|
||||
assert m.f_simple(s) == 20
|
||||
|
||||
# Try as recarray of shape==(1,).
|
||||
s_recarray = np.array([(False, 2, 0., 0.)], dtype=simple_dtype)
|
||||
s_recarray = np.array([(False, 2, 0.0, 0.0)], dtype=simple_dtype)
|
||||
# Show that this will work for vectorized case.
|
||||
np.testing.assert_array_equal(m.f_simple_vectorized(s_recarray), [20])
|
||||
|
||||
@ -327,17 +392,16 @@ def test_cls_and_dtype_conversion(simple_dtype):
|
||||
assert s_recarray_scalar.dtype == simple_dtype
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.f_simple(s_recarray_scalar)
|
||||
assert 'incompatible function arguments' in str(excinfo.value)
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
# Explicitly convert to m.SimpleStruct.
|
||||
assert m.f_simple(
|
||||
m.SimpleStruct.fromtuple(s_recarray_scalar.item())) == 20
|
||||
assert m.f_simple(m.SimpleStruct.fromtuple(s_recarray_scalar.item())) == 20
|
||||
|
||||
# Show that an array of dtype=object does *not* convert.
|
||||
s_array_object = np.array([s])
|
||||
assert s_array_object.dtype == object
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.f_simple_vectorized(s_array_object)
|
||||
assert 'incompatible function arguments' in str(excinfo.value)
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
# Explicitly convert to `np.array(..., dtype=simple_dtype)`
|
||||
s_array = np.array([s.astuple()], dtype=simple_dtype)
|
||||
np.testing.assert_array_equal(m.f_simple_vectorized(s_array), [20])
|
||||
@ -346,12 +410,13 @@ def test_cls_and_dtype_conversion(simple_dtype):
|
||||
def test_register_dtype():
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.register_dtype()
|
||||
assert 'dtype is already registered' in str(excinfo.value)
|
||||
assert "dtype is already registered" in str(excinfo.value)
|
||||
|
||||
|
||||
@pytest.mark.xfail("env.PYPY")
|
||||
def test_str_leak():
|
||||
from sys import getrefcount
|
||||
|
||||
fmt = "f4"
|
||||
pytest.gc_collect()
|
||||
start = getrefcount(fmt)
|
||||
|
@ -17,28 +17,40 @@ def test_vectorize(capture):
|
||||
assert capture == "my_func(x:int=1, y:float=2, z:float=3)"
|
||||
with capture:
|
||||
assert np.allclose(f(np.array([1, 3]), np.array([2, 4]), 3), [6, 36])
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
my_func(x:int=1, y:float=2, z:float=3)
|
||||
my_func(x:int=3, y:float=4, z:float=3)
|
||||
"""
|
||||
)
|
||||
with capture:
|
||||
a = np.array([[1, 2], [3, 4]], order='F')
|
||||
b = np.array([[10, 20], [30, 40]], order='F')
|
||||
a = np.array([[1, 2], [3, 4]], order="F")
|
||||
b = np.array([[10, 20], [30, 40]], order="F")
|
||||
c = 3
|
||||
result = f(a, b, c)
|
||||
assert np.allclose(result, a * b * c)
|
||||
assert result.flags.f_contiguous
|
||||
# All inputs are F order and full or singletons, so we the result is in col-major order:
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
my_func(x:int=1, y:float=10, z:float=3)
|
||||
my_func(x:int=3, y:float=30, z:float=3)
|
||||
my_func(x:int=2, y:float=20, z:float=3)
|
||||
my_func(x:int=4, y:float=40, z:float=3)
|
||||
"""
|
||||
)
|
||||
with capture:
|
||||
a, b, c = np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3
|
||||
a, b, c = (
|
||||
np.array([[1, 3, 5], [7, 9, 11]]),
|
||||
np.array([[2, 4, 6], [8, 10, 12]]),
|
||||
3,
|
||||
)
|
||||
assert np.allclose(f(a, b, c), a * b * c)
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
my_func(x:int=1, y:float=2, z:float=3)
|
||||
my_func(x:int=3, y:float=4, z:float=3)
|
||||
my_func(x:int=5, y:float=6, z:float=3)
|
||||
@ -46,10 +58,13 @@ def test_vectorize(capture):
|
||||
my_func(x:int=9, y:float=10, z:float=3)
|
||||
my_func(x:int=11, y:float=12, z:float=3)
|
||||
"""
|
||||
)
|
||||
with capture:
|
||||
a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2
|
||||
assert np.allclose(f(a, b, c), a * b * c)
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
my_func(x:int=1, y:float=2, z:float=2)
|
||||
my_func(x:int=2, y:float=3, z:float=2)
|
||||
my_func(x:int=3, y:float=4, z:float=2)
|
||||
@ -57,10 +72,13 @@ def test_vectorize(capture):
|
||||
my_func(x:int=5, y:float=3, z:float=2)
|
||||
my_func(x:int=6, y:float=4, z:float=2)
|
||||
"""
|
||||
)
|
||||
with capture:
|
||||
a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2
|
||||
assert np.allclose(f(a, b, c), a * b * c)
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
my_func(x:int=1, y:float=2, z:float=2)
|
||||
my_func(x:int=2, y:float=2, z:float=2)
|
||||
my_func(x:int=3, y:float=2, z:float=2)
|
||||
@ -68,10 +86,17 @@ def test_vectorize(capture):
|
||||
my_func(x:int=5, y:float=3, z:float=2)
|
||||
my_func(x:int=6, y:float=3, z:float=2)
|
||||
"""
|
||||
)
|
||||
with capture:
|
||||
a, b, c = np.array([[1, 2, 3], [4, 5, 6]], order='F'), np.array([[2], [3]]), 2
|
||||
a, b, c = (
|
||||
np.array([[1, 2, 3], [4, 5, 6]], order="F"),
|
||||
np.array([[2], [3]]),
|
||||
2,
|
||||
)
|
||||
assert np.allclose(f(a, b, c), a * b * c)
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
my_func(x:int=1, y:float=2, z:float=2)
|
||||
my_func(x:int=2, y:float=2, z:float=2)
|
||||
my_func(x:int=3, y:float=2, z:float=2)
|
||||
@ -79,36 +104,53 @@ def test_vectorize(capture):
|
||||
my_func(x:int=5, y:float=3, z:float=2)
|
||||
my_func(x:int=6, y:float=3, z:float=2)
|
||||
"""
|
||||
)
|
||||
with capture:
|
||||
a, b, c = np.array([[1, 2, 3], [4, 5, 6]])[::, ::2], np.array([[2], [3]]), 2
|
||||
assert np.allclose(f(a, b, c), a * b * c)
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
my_func(x:int=1, y:float=2, z:float=2)
|
||||
my_func(x:int=3, y:float=2, z:float=2)
|
||||
my_func(x:int=4, y:float=3, z:float=2)
|
||||
my_func(x:int=6, y:float=3, z:float=2)
|
||||
"""
|
||||
)
|
||||
with capture:
|
||||
a, b, c = np.array([[1, 2, 3], [4, 5, 6]], order='F')[::, ::2], np.array([[2], [3]]), 2
|
||||
a, b, c = (
|
||||
np.array([[1, 2, 3], [4, 5, 6]], order="F")[::, ::2],
|
||||
np.array([[2], [3]]),
|
||||
2,
|
||||
)
|
||||
assert np.allclose(f(a, b, c), a * b * c)
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
my_func(x:int=1, y:float=2, z:float=2)
|
||||
my_func(x:int=3, y:float=2, z:float=2)
|
||||
my_func(x:int=4, y:float=3, z:float=2)
|
||||
my_func(x:int=6, y:float=3, z:float=2)
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def test_type_selection():
|
||||
assert m.selective_func(np.array([1], dtype=np.int32)) == "Int branch taken."
|
||||
assert m.selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken."
|
||||
assert m.selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken."
|
||||
assert (
|
||||
m.selective_func(np.array([1.0j], dtype=np.complex64))
|
||||
== "Complex float branch taken."
|
||||
)
|
||||
|
||||
|
||||
def test_docs(doc):
|
||||
assert doc(m.vectorized_func) == """
|
||||
assert (
|
||||
doc(m.vectorized_func)
|
||||
== """
|
||||
vectorized_func(arg0: numpy.ndarray[numpy.int32], arg1: numpy.ndarray[numpy.float32], arg2: numpy.ndarray[numpy.float64]) -> object
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
|
||||
|
||||
def test_trivial_broadcasting():
|
||||
@ -116,16 +158,24 @@ def test_trivial_broadcasting():
|
||||
|
||||
assert vectorized_is_trivial(1, 2, 3) == trivial.c_trivial
|
||||
assert vectorized_is_trivial(np.array(1), np.array(2), 3) == trivial.c_trivial
|
||||
assert vectorized_is_trivial(np.array([1, 3]), np.array([2, 4]), 3) == trivial.c_trivial
|
||||
assert (
|
||||
vectorized_is_trivial(np.array([1, 3]), np.array([2, 4]), 3)
|
||||
== trivial.c_trivial
|
||||
)
|
||||
assert trivial.c_trivial == vectorized_is_trivial(
|
||||
np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3)
|
||||
assert vectorized_is_trivial(
|
||||
np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2) == trivial.non_trivial
|
||||
assert vectorized_is_trivial(
|
||||
np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2) == trivial.non_trivial
|
||||
z1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype='int32')
|
||||
z2 = np.array(z1, dtype='float32')
|
||||
z3 = np.array(z1, dtype='float64')
|
||||
np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3
|
||||
)
|
||||
assert (
|
||||
vectorized_is_trivial(np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2)
|
||||
== trivial.non_trivial
|
||||
)
|
||||
assert (
|
||||
vectorized_is_trivial(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2)
|
||||
== trivial.non_trivial
|
||||
)
|
||||
z1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype="int32")
|
||||
z2 = np.array(z1, dtype="float32")
|
||||
z3 = np.array(z1, dtype="float64")
|
||||
assert vectorized_is_trivial(z1, z2, z3) == trivial.c_trivial
|
||||
assert vectorized_is_trivial(1, z2, z3) == trivial.c_trivial
|
||||
assert vectorized_is_trivial(z1, 1, z3) == trivial.c_trivial
|
||||
@ -135,7 +185,7 @@ def test_trivial_broadcasting():
|
||||
assert vectorized_is_trivial(1, 1, z3[::2, ::2]) == trivial.non_trivial
|
||||
assert vectorized_is_trivial(z1, 1, z3[1::4, 1::4]) == trivial.c_trivial
|
||||
|
||||
y1 = np.array(z1, order='F')
|
||||
y1 = np.array(z1, order="F")
|
||||
y2 = np.array(y1)
|
||||
y3 = np.array(y1)
|
||||
assert vectorized_is_trivial(y1, y2, y3) == trivial.f_trivial
|
||||
@ -156,30 +206,41 @@ def test_trivial_broadcasting():
|
||||
|
||||
def test_passthrough_arguments(doc):
|
||||
assert doc(m.vec_passthrough) == (
|
||||
"vec_passthrough(" + ", ".join([
|
||||
"arg0: float",
|
||||
"arg1: numpy.ndarray[numpy.float64]",
|
||||
"arg2: numpy.ndarray[numpy.float64]",
|
||||
"arg3: numpy.ndarray[numpy.int32]",
|
||||
"arg4: int",
|
||||
"arg5: m.numpy_vectorize.NonPODClass",
|
||||
"arg6: numpy.ndarray[numpy.float64]"]) + ") -> object")
|
||||
"vec_passthrough("
|
||||
+ ", ".join(
|
||||
[
|
||||
"arg0: float",
|
||||
"arg1: numpy.ndarray[numpy.float64]",
|
||||
"arg2: numpy.ndarray[numpy.float64]",
|
||||
"arg3: numpy.ndarray[numpy.int32]",
|
||||
"arg4: int",
|
||||
"arg5: m.numpy_vectorize.NonPODClass",
|
||||
"arg6: numpy.ndarray[numpy.float64]",
|
||||
]
|
||||
)
|
||||
+ ") -> object"
|
||||
)
|
||||
|
||||
b = np.array([[10, 20, 30]], dtype='float64')
|
||||
b = np.array([[10, 20, 30]], dtype="float64")
|
||||
c = np.array([100, 200]) # NOT a vectorized argument
|
||||
d = np.array([[1000], [2000], [3000]], dtype='int')
|
||||
g = np.array([[1000000, 2000000, 3000000]], dtype='int') # requires casting
|
||||
d = np.array([[1000], [2000], [3000]], dtype="int")
|
||||
g = np.array([[1000000, 2000000, 3000000]], dtype="int") # requires casting
|
||||
assert np.all(
|
||||
m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g) ==
|
||||
np.array([[1111111, 2111121, 3111131],
|
||||
[1112111, 2112121, 3112131],
|
||||
[1113111, 2113121, 3113131]]))
|
||||
m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g)
|
||||
== np.array(
|
||||
[
|
||||
[1111111, 2111121, 3111131],
|
||||
[1112111, 2112121, 3112131],
|
||||
[1113111, 2113121, 3113131],
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_method_vectorization():
|
||||
o = m.VectorizeTestClass(3)
|
||||
x = np.array([1, 2], dtype='int')
|
||||
y = np.array([[10], [20]], dtype='float32')
|
||||
x = np.array([1, 2], dtype="int")
|
||||
y = np.array([[10], [20]], dtype="float32")
|
||||
assert np.all(o.method(x, y) == [[14, 15], [24, 25]])
|
||||
|
||||
|
||||
@ -188,7 +249,7 @@ def test_array_collapse():
|
||||
assert not isinstance(m.vectorized_func(np.array(1), 2, 3), np.ndarray)
|
||||
z = m.vectorized_func([1], 2, 3)
|
||||
assert isinstance(z, np.ndarray)
|
||||
assert z.shape == (1, )
|
||||
assert z.shape == (1,)
|
||||
z = m.vectorized_func(1, [[[2]]], 3)
|
||||
assert isinstance(z, np.ndarray)
|
||||
assert z.shape == (1, 1, 1)
|
||||
|
@ -32,12 +32,15 @@ def test_pointers(msg):
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.get_void_ptr_value([1, 2, 3]) # This should not work
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
get_void_ptr_value(): incompatible function arguments. The following argument types are supported:
|
||||
1. (arg0: capsule) -> int
|
||||
|
||||
Invoked with: [1, 2, 3]
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
|
||||
assert m.return_null_str() is None
|
||||
assert m.get_null_str_value(m.return_null_str()) is not None
|
||||
|
@ -56,23 +56,23 @@ def test_operator_overloading():
|
||||
del v3
|
||||
assert cstats.alive() == 0
|
||||
assert cstats.values() == [
|
||||
'[1.000000, 2.000000]',
|
||||
'[3.000000, -1.000000]',
|
||||
'[1.000000, 2.000000]',
|
||||
'[-3.000000, 1.000000]',
|
||||
'[4.000000, 1.000000]',
|
||||
'[-2.000000, 3.000000]',
|
||||
'[-7.000000, -6.000000]',
|
||||
'[9.000000, 10.000000]',
|
||||
'[8.000000, 16.000000]',
|
||||
'[0.125000, 0.250000]',
|
||||
'[7.000000, 6.000000]',
|
||||
'[9.000000, 10.000000]',
|
||||
'[8.000000, 16.000000]',
|
||||
'[8.000000, 4.000000]',
|
||||
'[3.000000, -2.000000]',
|
||||
'[3.000000, -0.500000]',
|
||||
'[6.000000, -2.000000]',
|
||||
"[1.000000, 2.000000]",
|
||||
"[3.000000, -1.000000]",
|
||||
"[1.000000, 2.000000]",
|
||||
"[-3.000000, 1.000000]",
|
||||
"[4.000000, 1.000000]",
|
||||
"[-2.000000, 3.000000]",
|
||||
"[-7.000000, -6.000000]",
|
||||
"[9.000000, 10.000000]",
|
||||
"[8.000000, 16.000000]",
|
||||
"[0.125000, 0.250000]",
|
||||
"[7.000000, 6.000000]",
|
||||
"[9.000000, 10.000000]",
|
||||
"[8.000000, 16.000000]",
|
||||
"[8.000000, 4.000000]",
|
||||
"[3.000000, -2.000000]",
|
||||
"[3.000000, -0.500000]",
|
||||
"[6.000000, -2.000000]",
|
||||
]
|
||||
assert cstats.default_constructions == 0
|
||||
assert cstats.copy_constructions == 0
|
||||
|
@ -42,5 +42,6 @@ def test_roundtrip_with_dict(cls_name):
|
||||
|
||||
def test_enum_pickle():
|
||||
from pybind11_tests import enums as e
|
||||
|
||||
data = pickle.dumps(e.EOne, 2)
|
||||
assert e.EOne == pickle.loads(data)
|
||||
|
@ -28,13 +28,16 @@ def test_list(capture, doc):
|
||||
|
||||
lst.append("value2")
|
||||
m.print_list(lst)
|
||||
assert capture.unordered == """
|
||||
assert (
|
||||
capture.unordered
|
||||
== """
|
||||
Entry at position 0: value
|
||||
list item 0: inserted-0
|
||||
list item 1: overwritten
|
||||
list item 2: inserted-2
|
||||
list item 3: value2
|
||||
"""
|
||||
)
|
||||
|
||||
assert doc(m.get_list) == "get_list() -> list"
|
||||
assert doc(m.print_list) == "print_list(arg0: list) -> None"
|
||||
@ -52,12 +55,15 @@ def test_set(capture, doc):
|
||||
with capture:
|
||||
s.add("key4")
|
||||
m.print_set(s)
|
||||
assert capture.unordered == """
|
||||
assert (
|
||||
capture.unordered
|
||||
== """
|
||||
key: key1
|
||||
key: key2
|
||||
key: key3
|
||||
key: key4
|
||||
"""
|
||||
)
|
||||
|
||||
assert not m.set_contains(set([]), 42)
|
||||
assert m.set_contains({42}, 42)
|
||||
@ -74,10 +80,13 @@ def test_dict(capture, doc):
|
||||
with capture:
|
||||
d["key2"] = "value2"
|
||||
m.print_dict(d)
|
||||
assert capture.unordered == """
|
||||
assert (
|
||||
capture.unordered
|
||||
== """
|
||||
key: key, value=value
|
||||
key: key2, value=value2
|
||||
"""
|
||||
)
|
||||
|
||||
assert not m.dict_contains({}, 42)
|
||||
assert m.dict_contains({42: None}, 42)
|
||||
@ -137,28 +146,37 @@ def test_capsule(capture):
|
||||
a = m.return_capsule_with_destructor()
|
||||
del a
|
||||
pytest.gc_collect()
|
||||
assert capture.unordered == """
|
||||
assert (
|
||||
capture.unordered
|
||||
== """
|
||||
creating capsule
|
||||
destructing capsule
|
||||
"""
|
||||
)
|
||||
|
||||
with capture:
|
||||
a = m.return_capsule_with_destructor_2()
|
||||
del a
|
||||
pytest.gc_collect()
|
||||
assert capture.unordered == """
|
||||
assert (
|
||||
capture.unordered
|
||||
== """
|
||||
creating capsule
|
||||
destructing capsule: 1234
|
||||
"""
|
||||
)
|
||||
|
||||
with capture:
|
||||
a = m.return_capsule_with_name_and_destructor()
|
||||
del a
|
||||
pytest.gc_collect()
|
||||
assert capture.unordered == """
|
||||
assert (
|
||||
capture.unordered
|
||||
== """
|
||||
created capsule (1234, 'pointer type description')
|
||||
destructing capsule (1234, 'pointer type description')
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def test_accessors():
|
||||
@ -212,7 +230,7 @@ def test_constructors():
|
||||
assert m.default_constructors() == expected
|
||||
|
||||
data = {
|
||||
bytes: b'41', # Currently no supported or working conversions.
|
||||
bytes: b"41", # Currently no supported or working conversions.
|
||||
str: 42,
|
||||
bool: "Not empty",
|
||||
int: "42",
|
||||
@ -221,14 +239,14 @@ def test_constructors():
|
||||
list: range(3),
|
||||
dict: [("two", 2), ("one", 1), ("three", 3)],
|
||||
set: [4, 4, 5, 6, 6, 6],
|
||||
memoryview: b'abc'
|
||||
memoryview: b"abc",
|
||||
}
|
||||
inputs = {k.__name__: v for k, v in data.items()}
|
||||
expected = {k.__name__: k(v) for k, v in data.items()}
|
||||
if env.PY2: # Similar to the above. See comments above.
|
||||
inputs["bytes"] = b'41'
|
||||
inputs["bytes"] = b"41"
|
||||
inputs["str"] = 42
|
||||
expected["bytes"] = b'41'
|
||||
expected["bytes"] = b"41"
|
||||
expected["str"] = u"42"
|
||||
|
||||
assert m.converting_constructors(inputs) == expected
|
||||
@ -255,7 +273,8 @@ def test_non_converting_constructors():
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.nonconverting_constructor(t, v)
|
||||
expected_error = "Object of type '{}' is not an instance of '{}'".format(
|
||||
type(v).__name__, t)
|
||||
type(v).__name__, t
|
||||
)
|
||||
assert str(excinfo.value) == expected_error
|
||||
|
||||
|
||||
@ -263,12 +282,12 @@ def test_pybind11_str_raw_str():
|
||||
# specifically to exercise pybind11::str::raw_str
|
||||
cvt = m.convert_to_pybind11_str
|
||||
assert cvt(u"Str") == u"Str"
|
||||
assert cvt(b'Bytes') == u"Bytes" if env.PY2 else "b'Bytes'"
|
||||
assert cvt(b"Bytes") == u"Bytes" if env.PY2 else "b'Bytes'"
|
||||
assert cvt(None) == u"None"
|
||||
assert cvt(False) == u"False"
|
||||
assert cvt(True) == u"True"
|
||||
assert cvt(42) == u"42"
|
||||
assert cvt(2**65) == u"36893488147419103232"
|
||||
assert cvt(2 ** 65) == u"36893488147419103232"
|
||||
assert cvt(-1.50) == u"-1.5"
|
||||
assert cvt(()) == u"()"
|
||||
assert cvt((18,)) == u"(18,)"
|
||||
@ -283,29 +302,40 @@ def test_pybind11_str_raw_str():
|
||||
valid_utf8 = valid_orig.encode("utf-8")
|
||||
valid_cvt = cvt(valid_utf8)
|
||||
assert type(valid_cvt) == bytes # Probably surprising.
|
||||
assert valid_cvt == b'\xc7\xb1'
|
||||
assert valid_cvt == b"\xc7\xb1"
|
||||
|
||||
malformed_utf8 = b'\x80'
|
||||
malformed_utf8 = b"\x80"
|
||||
malformed_cvt = cvt(malformed_utf8)
|
||||
assert type(malformed_cvt) == bytes # Probably surprising.
|
||||
assert malformed_cvt == b'\x80'
|
||||
assert malformed_cvt == b"\x80"
|
||||
|
||||
|
||||
def test_implicit_casting():
|
||||
"""Tests implicit casting when assigning or appending to dicts and lists."""
|
||||
z = m.get_implicit_casting()
|
||||
assert z['d'] == {
|
||||
'char*_i1': 'abc', 'char*_i2': 'abc', 'char*_e': 'abc', 'char*_p': 'abc',
|
||||
'str_i1': 'str', 'str_i2': 'str1', 'str_e': 'str2', 'str_p': 'str3',
|
||||
'int_i1': 42, 'int_i2': 42, 'int_e': 43, 'int_p': 44
|
||||
assert z["d"] == {
|
||||
"char*_i1": "abc",
|
||||
"char*_i2": "abc",
|
||||
"char*_e": "abc",
|
||||
"char*_p": "abc",
|
||||
"str_i1": "str",
|
||||
"str_i2": "str1",
|
||||
"str_e": "str2",
|
||||
"str_p": "str3",
|
||||
"int_i1": 42,
|
||||
"int_i2": 42,
|
||||
"int_e": 43,
|
||||
"int_p": 44,
|
||||
}
|
||||
assert z['l'] == [3, 6, 9, 12, 15]
|
||||
assert z["l"] == [3, 6, 9, 12, 15]
|
||||
|
||||
|
||||
def test_print(capture):
|
||||
with capture:
|
||||
m.print_function()
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
Hello, World!
|
||||
1 2.0 three True -- multiple args
|
||||
*args-and-a-custom-separator
|
||||
@ -313,14 +343,15 @@ def test_print(capture):
|
||||
flush
|
||||
py::print + str.format = this
|
||||
"""
|
||||
)
|
||||
assert capture.stderr == "this goes to stderr"
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.print_failure()
|
||||
assert str(excinfo.value) == "make_tuple(): unable to convert " + (
|
||||
"argument of type 'UnregisteredType' to Python object"
|
||||
if debug_enabled else
|
||||
"arguments to Python object (compile in debug mode for details)"
|
||||
if debug_enabled
|
||||
else "arguments to Python object (compile in debug mode for details)"
|
||||
)
|
||||
|
||||
|
||||
@ -342,8 +373,23 @@ def test_hash():
|
||||
|
||||
def test_number_protocol():
|
||||
for a, b in [(1, 1), (3, 5)]:
|
||||
li = [a == b, a != b, a < b, a <= b, a > b, a >= b, a + b,
|
||||
a - b, a * b, a / b, a | b, a & b, a ^ b, a >> b, a << b]
|
||||
li = [
|
||||
a == b,
|
||||
a != b,
|
||||
a < b,
|
||||
a <= b,
|
||||
a > b,
|
||||
a >= b,
|
||||
a + b,
|
||||
a - b,
|
||||
a * b,
|
||||
a / b,
|
||||
a | b,
|
||||
a & b,
|
||||
a ^ b,
|
||||
a >> b,
|
||||
a << b,
|
||||
]
|
||||
assert m.test_number_protocol(a, b) == li
|
||||
|
||||
|
||||
@ -360,13 +406,16 @@ def test_issue2361():
|
||||
assert "'NoneType' object is not iterable" in str(excinfo.value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('method, args, fmt, expected_view', [
|
||||
(m.test_memoryview_object, (b'red',), 'B', b'red'),
|
||||
(m.test_memoryview_buffer_info, (b'green',), 'B', b'green'),
|
||||
(m.test_memoryview_from_buffer, (False,), 'h', [3, 1, 4, 1, 5]),
|
||||
(m.test_memoryview_from_buffer, (True,), 'H', [2, 7, 1, 8]),
|
||||
(m.test_memoryview_from_buffer_nativeformat, (), '@i', [4, 7, 5]),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"method, args, fmt, expected_view",
|
||||
[
|
||||
(m.test_memoryview_object, (b"red",), "B", b"red"),
|
||||
(m.test_memoryview_buffer_info, (b"green",), "B", b"green"),
|
||||
(m.test_memoryview_from_buffer, (False,), "h", [3, 1, 4, 1, 5]),
|
||||
(m.test_memoryview_from_buffer, (True,), "H", [2, 7, 1, 8]),
|
||||
(m.test_memoryview_from_buffer_nativeformat, (), "@i", [4, 7, 5]),
|
||||
],
|
||||
)
|
||||
def test_memoryview(method, args, fmt, expected_view):
|
||||
view = method(*args)
|
||||
assert isinstance(view, memoryview)
|
||||
@ -380,12 +429,15 @@ def test_memoryview(method, args, fmt, expected_view):
|
||||
|
||||
|
||||
@pytest.mark.xfail("env.PYPY", reason="getrefcount is not available")
|
||||
@pytest.mark.parametrize('method', [
|
||||
m.test_memoryview_object,
|
||||
m.test_memoryview_buffer_info,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"method",
|
||||
[
|
||||
m.test_memoryview_object,
|
||||
m.test_memoryview_buffer_info,
|
||||
],
|
||||
)
|
||||
def test_memoryview_refcount(method):
|
||||
buf = b'\x0a\x0b\x0c\x0d'
|
||||
buf = b"\x0a\x0b\x0c\x0d"
|
||||
ref_before = sys.getrefcount(buf)
|
||||
view = method(buf)
|
||||
ref_after = sys.getrefcount(buf)
|
||||
@ -396,13 +448,13 @@ def test_memoryview_refcount(method):
|
||||
def test_memoryview_from_buffer_empty_shape():
|
||||
view = m.test_memoryview_from_buffer_empty_shape()
|
||||
assert isinstance(view, memoryview)
|
||||
assert view.format == 'B'
|
||||
assert view.format == "B"
|
||||
if env.PY2:
|
||||
# Python 2 behavior is weird, but Python 3 (the future) is fine.
|
||||
# PyPy3 has <memoryview, while CPython 2 has <memory
|
||||
assert bytes(view).startswith(b'<memory')
|
||||
assert bytes(view).startswith(b"<memory")
|
||||
else:
|
||||
assert bytes(view) == b''
|
||||
assert bytes(view) == b""
|
||||
|
||||
|
||||
def test_test_memoryview_from_buffer_invalid_strides():
|
||||
@ -422,13 +474,15 @@ def test_test_memoryview_from_buffer_nullptr():
|
||||
def test_memoryview_from_memory():
|
||||
view = m.test_memoryview_from_memory()
|
||||
assert isinstance(view, memoryview)
|
||||
assert view.format == 'B'
|
||||
assert bytes(view) == b'\xff\xe1\xab\x37'
|
||||
assert view.format == "B"
|
||||
assert bytes(view) == b"\xff\xe1\xab\x37"
|
||||
|
||||
|
||||
def test_builtin_functions():
|
||||
assert m.get_len([i for i in range(42)]) == 42
|
||||
with pytest.raises(TypeError) as exc_info:
|
||||
m.get_len(i for i in range(42))
|
||||
assert str(exc_info.value) in ["object of type 'generator' has no len()",
|
||||
"'generator' has no length"] # PyPy
|
||||
assert str(exc_info.value) in [
|
||||
"object of type 'generator' has no len()",
|
||||
"'generator' has no length",
|
||||
] # PyPy
|
||||
|
@ -10,7 +10,9 @@ def isclose(a, b, rel_tol=1e-05, abs_tol=0.0):
|
||||
|
||||
|
||||
def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0):
|
||||
return all(isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list))
|
||||
return all(
|
||||
isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list)
|
||||
)
|
||||
|
||||
|
||||
def test_generalized_iterators():
|
||||
@ -51,7 +53,7 @@ def test_sequence():
|
||||
cstats = ConstructorStats.get(m.Sequence)
|
||||
|
||||
s = m.Sequence(5)
|
||||
assert cstats.values() == ['of size', '5']
|
||||
assert cstats.values() == ["of size", "5"]
|
||||
|
||||
assert "Sequence" in repr(s)
|
||||
assert len(s) == 5
|
||||
@ -62,16 +64,16 @@ def test_sequence():
|
||||
assert isclose(s[0], 12.34) and isclose(s[3], 56.78)
|
||||
|
||||
rev = reversed(s)
|
||||
assert cstats.values() == ['of size', '5']
|
||||
assert cstats.values() == ["of size", "5"]
|
||||
|
||||
rev2 = s[::-1]
|
||||
assert cstats.values() == ['of size', '5']
|
||||
assert cstats.values() == ["of size", "5"]
|
||||
|
||||
it = iter(m.Sequence(0))
|
||||
for _ in range(3): # __next__ must continue to raise StopIteration
|
||||
with pytest.raises(StopIteration):
|
||||
next(it)
|
||||
assert cstats.values() == ['of size', '0']
|
||||
assert cstats.values() == ["of size", "0"]
|
||||
|
||||
expected = [0, 56.78, 0, 0, 12.34]
|
||||
assert allclose(rev, expected)
|
||||
@ -79,7 +81,7 @@ def test_sequence():
|
||||
assert rev == rev2
|
||||
|
||||
rev[0::2] = m.Sequence([2.0, 2.0, 2.0])
|
||||
assert cstats.values() == ['of size', '3', 'from std::vector']
|
||||
assert cstats.values() == ["of size", "3", "from std::vector"]
|
||||
|
||||
assert allclose(rev, [2, 56.78, 2, 0, 2])
|
||||
|
||||
@ -103,10 +105,11 @@ def test_sequence():
|
||||
|
||||
def test_sequence_length():
|
||||
"""#2076: Exception raised by len(arg) should be propagated """
|
||||
|
||||
class BadLen(RuntimeError):
|
||||
pass
|
||||
|
||||
class SequenceLike():
|
||||
class SequenceLike:
|
||||
def __getitem__(self, i):
|
||||
return None
|
||||
|
||||
@ -121,17 +124,17 @@ def test_sequence_length():
|
||||
|
||||
|
||||
def test_map_iterator():
|
||||
sm = m.StringMap({'hi': 'bye', 'black': 'white'})
|
||||
assert sm['hi'] == 'bye'
|
||||
sm = m.StringMap({"hi": "bye", "black": "white"})
|
||||
assert sm["hi"] == "bye"
|
||||
assert len(sm) == 2
|
||||
assert sm['black'] == 'white'
|
||||
assert sm["black"] == "white"
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
assert sm['orange']
|
||||
sm['orange'] = 'banana'
|
||||
assert sm['orange'] == 'banana'
|
||||
assert sm["orange"]
|
||||
sm["orange"] = "banana"
|
||||
assert sm["orange"] == "banana"
|
||||
|
||||
expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'}
|
||||
expected = {"hi": "bye", "black": "white", "orange": "banana"}
|
||||
for k in sm:
|
||||
assert sm[k] == expected[k]
|
||||
for k, v in sm.items():
|
||||
@ -179,7 +182,8 @@ def test_iterator_passthrough():
|
||||
"""#181: iterator passthrough did not compile"""
|
||||
from pybind11_tests.sequences_and_iterators import iterator_passthrough
|
||||
|
||||
assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15]
|
||||
values = [3, 5, 7, 9, 11, 13, 15]
|
||||
assert list(iterator_passthrough(iter(values))) == values
|
||||
|
||||
|
||||
def test_iterator_rvp():
|
||||
|
@ -7,7 +7,9 @@ from pybind11_tests import ConstructorStats # noqa: E402
|
||||
|
||||
def test_smart_ptr(capture):
|
||||
# Object1
|
||||
for i, o in enumerate([m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1):
|
||||
for i, o in enumerate(
|
||||
[m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1
|
||||
):
|
||||
assert o.getRefCount() == 1
|
||||
with capture:
|
||||
m.print_object_1(o)
|
||||
@ -16,8 +18,9 @@ def test_smart_ptr(capture):
|
||||
m.print_object_4(o)
|
||||
assert capture == "MyObject1[{i}]\n".format(i=i) * 4
|
||||
|
||||
for i, o in enumerate([m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7],
|
||||
start=4):
|
||||
for i, o in enumerate(
|
||||
[m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], start=4
|
||||
):
|
||||
print(o)
|
||||
with capture:
|
||||
if not isinstance(o, int):
|
||||
@ -29,11 +32,15 @@ def test_smart_ptr(capture):
|
||||
m.print_myobject1_2(o)
|
||||
m.print_myobject1_3(o)
|
||||
m.print_myobject1_4(o)
|
||||
assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8)
|
||||
|
||||
times = 4 if isinstance(o, int) else 8
|
||||
assert capture == "MyObject1[{i}]\n".format(i=i) * times
|
||||
|
||||
cstats = ConstructorStats.get(m.MyObject1)
|
||||
assert cstats.alive() == 0
|
||||
expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4
|
||||
expected_values = ["MyObject1[{}]".format(i) for i in range(1, 7)] + [
|
||||
"MyObject1[7]"
|
||||
] * 4
|
||||
assert cstats.values() == expected_values
|
||||
assert cstats.default_constructions == 0
|
||||
assert cstats.copy_constructions == 0
|
||||
@ -42,7 +49,9 @@ def test_smart_ptr(capture):
|
||||
assert cstats.move_assignments == 0
|
||||
|
||||
# Object2
|
||||
for i, o in zip([8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]):
|
||||
for i, o in zip(
|
||||
[8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]
|
||||
):
|
||||
print(o)
|
||||
with capture:
|
||||
m.print_myobject2_1(o)
|
||||
@ -55,7 +64,7 @@ def test_smart_ptr(capture):
|
||||
assert cstats.alive() == 1
|
||||
o = None
|
||||
assert cstats.alive() == 0
|
||||
assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]']
|
||||
assert cstats.values() == ["MyObject2[8]", "MyObject2[6]", "MyObject2[7]"]
|
||||
assert cstats.default_constructions == 0
|
||||
assert cstats.copy_constructions == 0
|
||||
# assert cstats.move_constructions >= 0 # Doesn't invoke any
|
||||
@ -63,7 +72,9 @@ def test_smart_ptr(capture):
|
||||
assert cstats.move_assignments == 0
|
||||
|
||||
# Object3
|
||||
for i, o in zip([9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]):
|
||||
for i, o in zip(
|
||||
[9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]
|
||||
):
|
||||
print(o)
|
||||
with capture:
|
||||
m.print_myobject3_1(o)
|
||||
@ -76,7 +87,7 @@ def test_smart_ptr(capture):
|
||||
assert cstats.alive() == 1
|
||||
o = None
|
||||
assert cstats.alive() == 0
|
||||
assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]']
|
||||
assert cstats.values() == ["MyObject3[9]", "MyObject3[8]", "MyObject3[9]"]
|
||||
assert cstats.default_constructions == 0
|
||||
assert cstats.copy_constructions == 0
|
||||
# assert cstats.move_constructions >= 0 # Doesn't invoke any
|
||||
@ -96,7 +107,7 @@ def test_smart_ptr(capture):
|
||||
# ref<>
|
||||
cstats = m.cstats_ref()
|
||||
assert cstats.alive() == 0
|
||||
assert cstats.values() == ['from pointer'] * 10
|
||||
assert cstats.values() == ["from pointer"] * 10
|
||||
assert cstats.default_constructions == 30
|
||||
assert cstats.copy_constructions == 12
|
||||
# assert cstats.move_constructions >= 0 # Doesn't invoke any
|
||||
@ -186,7 +197,9 @@ def test_shared_ptr_from_this_and_references():
|
||||
ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
|
||||
assert stats.alive() == 2
|
||||
assert s.set_ref(ref)
|
||||
assert s.set_holder(ref) # std::enable_shared_from_this can create a holder from a reference
|
||||
assert s.set_holder(
|
||||
ref
|
||||
) # std::enable_shared_from_this can create a holder from a reference
|
||||
|
||||
bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
|
||||
assert stats.alive() == 2
|
||||
@ -200,12 +213,16 @@ def test_shared_ptr_from_this_and_references():
|
||||
assert s.set_ref(copy)
|
||||
assert s.set_holder(copy)
|
||||
|
||||
holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
|
||||
holder_ref = (
|
||||
s.holder_ref
|
||||
) # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
|
||||
assert stats.alive() == 3
|
||||
assert s.set_ref(holder_ref)
|
||||
assert s.set_holder(holder_ref)
|
||||
|
||||
holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
|
||||
holder_copy = (
|
||||
s.holder_copy
|
||||
) # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
|
||||
assert stats.alive() == 3
|
||||
assert s.set_ref(holder_copy)
|
||||
assert s.set_holder(holder_copy)
|
||||
@ -277,8 +294,10 @@ def test_smart_ptr_from_default():
|
||||
instance = m.HeldByDefaultHolder()
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.HeldByDefaultHolder.load_shared_ptr(instance)
|
||||
assert "Unable to load a custom holder type from a " \
|
||||
"default-holder instance" in str(excinfo.value)
|
||||
assert (
|
||||
"Unable to load a custom holder type from a "
|
||||
"default-holder instance" in str(excinfo.value)
|
||||
)
|
||||
|
||||
|
||||
def test_shared_ptr_gc():
|
||||
|
@ -88,7 +88,7 @@ def test_recursive_casting():
|
||||
assert m.cast_rv_nested() == [[[{"b": "rvalue", "c": "rvalue"}], [{"a": "rvalue"}]]]
|
||||
assert m.cast_lv_nested() == {
|
||||
"a": [[["lvalue", "lvalue"]], [["lvalue", "lvalue"]]],
|
||||
"b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]]
|
||||
"b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]],
|
||||
}
|
||||
|
||||
# Issue #853 test case:
|
||||
@ -106,15 +106,15 @@ def test_move_out_container():
|
||||
assert [x.value for x in moved_out_list] == [0, 1, 2]
|
||||
|
||||
|
||||
@pytest.mark.skipif(not hasattr(m, "has_optional"), reason='no <optional>')
|
||||
@pytest.mark.skipif(not hasattr(m, "has_optional"), reason="no <optional>")
|
||||
def test_optional():
|
||||
assert m.double_or_zero(None) == 0
|
||||
assert m.double_or_zero(42) == 84
|
||||
pytest.raises(TypeError, m.double_or_zero, 'foo')
|
||||
pytest.raises(TypeError, m.double_or_zero, "foo")
|
||||
|
||||
assert m.half_or_none(0) is None
|
||||
assert m.half_or_none(42) == 21
|
||||
pytest.raises(TypeError, m.half_or_none, 'foo')
|
||||
pytest.raises(TypeError, m.half_or_none, "foo")
|
||||
|
||||
assert m.test_nullopt() == 42
|
||||
assert m.test_nullopt(None) == 42
|
||||
@ -134,15 +134,17 @@ def test_optional():
|
||||
assert holder.member_initialized()
|
||||
|
||||
|
||||
@pytest.mark.skipif(not hasattr(m, "has_exp_optional"), reason='no <experimental/optional>')
|
||||
@pytest.mark.skipif(
|
||||
not hasattr(m, "has_exp_optional"), reason="no <experimental/optional>"
|
||||
)
|
||||
def test_exp_optional():
|
||||
assert m.double_or_zero_exp(None) == 0
|
||||
assert m.double_or_zero_exp(42) == 84
|
||||
pytest.raises(TypeError, m.double_or_zero_exp, 'foo')
|
||||
pytest.raises(TypeError, m.double_or_zero_exp, "foo")
|
||||
|
||||
assert m.half_or_none_exp(0) is None
|
||||
assert m.half_or_none_exp(42) == 21
|
||||
pytest.raises(TypeError, m.half_or_none_exp, 'foo')
|
||||
pytest.raises(TypeError, m.half_or_none_exp, "foo")
|
||||
|
||||
assert m.test_nullopt_exp() == 42
|
||||
assert m.test_nullopt_exp(None) == 42
|
||||
@ -160,7 +162,7 @@ def test_exp_optional():
|
||||
assert holder.member_initialized()
|
||||
|
||||
|
||||
@pytest.mark.skipif(not hasattr(m, "load_variant"), reason='no <variant>')
|
||||
@pytest.mark.skipif(not hasattr(m, "load_variant"), reason="no <variant>")
|
||||
def test_variant(doc):
|
||||
assert m.load_variant(1) == "int"
|
||||
assert m.load_variant("1") == "std::string"
|
||||
@ -172,34 +174,44 @@ def test_variant(doc):
|
||||
|
||||
assert m.cast_variant() == (5, "Hello")
|
||||
|
||||
assert doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str"
|
||||
assert (
|
||||
doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str"
|
||||
)
|
||||
|
||||
|
||||
def test_vec_of_reference_wrapper():
|
||||
"""#171: Can't return reference wrappers (or STL structures containing them)"""
|
||||
assert str(m.return_vec_of_reference_wrapper(UserType(4))) == \
|
||||
"[UserType(1), UserType(2), UserType(3), UserType(4)]"
|
||||
assert (
|
||||
str(m.return_vec_of_reference_wrapper(UserType(4)))
|
||||
== "[UserType(1), UserType(2), UserType(3), UserType(4)]"
|
||||
)
|
||||
|
||||
|
||||
def test_stl_pass_by_pointer(msg):
|
||||
"""Passing nullptr or None to an STL container pointer is not expected to work"""
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.stl_pass_by_pointer() # default value is `nullptr`
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
|
||||
1. (v: List[int] = None) -> List[int]
|
||||
|
||||
Invoked with:
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.stl_pass_by_pointer(None)
|
||||
assert msg(excinfo.value) == """
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
|
||||
1. (v: List[int] = None) -> List[int]
|
||||
|
||||
Invoked with: None
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
|
||||
assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3]
|
||||
|
||||
@ -209,10 +221,12 @@ def test_missing_header_message():
|
||||
<pybind11/stl.h> should result in a helpful suggestion in the error message"""
|
||||
import pybind11_cross_module_tests as cm
|
||||
|
||||
expected_message = ("Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\n"
|
||||
"<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\n"
|
||||
"conversions are optional and require extra headers to be included\n"
|
||||
"when compiling your pybind11 module.")
|
||||
expected_message = (
|
||||
"Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\n"
|
||||
"<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\n"
|
||||
"conversions are optional and require extra headers to be included\n"
|
||||
"when compiling your pybind11 module."
|
||||
)
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
cm.missing_header_arg([1.0, 2.0, 3.0])
|
||||
@ -226,9 +240,9 @@ def test_missing_header_message():
|
||||
def test_function_with_string_and_vector_string_arg():
|
||||
"""Check if a string is NOT implicitly converted to a list, which was the
|
||||
behavior before fix of issue #1258"""
|
||||
assert m.func_with_string_or_vector_string_arg_overload(('A', 'B', )) == 2
|
||||
assert m.func_with_string_or_vector_string_arg_overload(['A', 'B']) == 2
|
||||
assert m.func_with_string_or_vector_string_arg_overload('A') == 3
|
||||
assert m.func_with_string_or_vector_string_arg_overload(("A", "B")) == 2
|
||||
assert m.func_with_string_or_vector_string_arg_overload(["A", "B"]) == 2
|
||||
assert m.func_with_string_or_vector_string_arg_overload("A") == 3
|
||||
|
||||
|
||||
def test_stl_ownership():
|
||||
@ -247,6 +261,6 @@ def test_array_cast_sequence():
|
||||
def test_issue_1561():
|
||||
""" check fix for issue #1561 """
|
||||
bar = m.Issue1561Outer()
|
||||
bar.list = [m.Issue1561Inner('bar')]
|
||||
bar.list = [m.Issue1561Inner("bar")]
|
||||
bar.list
|
||||
assert bar.list[0].data == 'bar'
|
||||
assert bar.list[0].data == "bar"
|
||||
|
@ -45,7 +45,7 @@ def test_vector_int():
|
||||
|
||||
# test error handling, and that the vector is unchanged
|
||||
with pytest.raises(RuntimeError):
|
||||
v_int2.extend([8, 'a'])
|
||||
v_int2.extend([8, "a"])
|
||||
|
||||
assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7])
|
||||
|
||||
@ -79,8 +79,8 @@ def test_vector_buffer():
|
||||
assert mv[2] == 5
|
||||
mv[2] = 6
|
||||
else:
|
||||
assert mv[2] == '\x05'
|
||||
mv[2] = '\x06'
|
||||
assert mv[2] == "\x05"
|
||||
mv[2] = "\x06"
|
||||
assert v[2] == 6
|
||||
|
||||
if not env.PY2:
|
||||
@ -114,11 +114,17 @@ def test_vector_buffer_numpy():
|
||||
v = m.get_vectorstruct()
|
||||
assert v[0].x == 5
|
||||
ma = np.asarray(v)
|
||||
ma[1]['x'] = 99
|
||||
ma[1]["x"] = 99
|
||||
assert v[1].x == 99
|
||||
|
||||
v = m.VectorStruct(np.zeros(3, dtype=np.dtype([('w', 'bool'), ('x', 'I'),
|
||||
('y', 'float64'), ('z', 'bool')], align=True)))
|
||||
v = m.VectorStruct(
|
||||
np.zeros(
|
||||
3,
|
||||
dtype=np.dtype(
|
||||
[("w", "bool"), ("x", "I"), ("y", "float64"), ("z", "bool")], align=True
|
||||
),
|
||||
)
|
||||
)
|
||||
assert len(v) == 3
|
||||
|
||||
b = np.array([1, 2, 3, 4], dtype=np.uint8)
|
||||
@ -151,31 +157,31 @@ def test_vector_custom():
|
||||
|
||||
def test_map_string_double():
|
||||
mm = m.MapStringDouble()
|
||||
mm['a'] = 1
|
||||
mm['b'] = 2.5
|
||||
mm["a"] = 1
|
||||
mm["b"] = 2.5
|
||||
|
||||
assert list(mm) == ['a', 'b']
|
||||
assert list(mm.items()) == [('a', 1), ('b', 2.5)]
|
||||
assert list(mm) == ["a", "b"]
|
||||
assert list(mm.items()) == [("a", 1), ("b", 2.5)]
|
||||
assert str(mm) == "MapStringDouble{a: 1, b: 2.5}"
|
||||
|
||||
um = m.UnorderedMapStringDouble()
|
||||
um['ua'] = 1.1
|
||||
um['ub'] = 2.6
|
||||
um["ua"] = 1.1
|
||||
um["ub"] = 2.6
|
||||
|
||||
assert sorted(list(um)) == ['ua', 'ub']
|
||||
assert sorted(list(um.items())) == [('ua', 1.1), ('ub', 2.6)]
|
||||
assert sorted(list(um)) == ["ua", "ub"]
|
||||
assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)]
|
||||
assert "UnorderedMapStringDouble" in str(um)
|
||||
|
||||
|
||||
def test_map_string_double_const():
|
||||
mc = m.MapStringDoubleConst()
|
||||
mc['a'] = 10
|
||||
mc['b'] = 20.5
|
||||
mc["a"] = 10
|
||||
mc["b"] = 20.5
|
||||
assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}"
|
||||
|
||||
umc = m.UnorderedMapStringDoubleConst()
|
||||
umc['a'] = 11
|
||||
umc['b'] = 21.5
|
||||
umc["a"] = 11
|
||||
umc["b"] = 21.5
|
||||
|
||||
str(umc)
|
||||
|
||||
@ -196,7 +202,7 @@ def test_noncopyable_containers():
|
||||
|
||||
i = 1
|
||||
for j in dnc:
|
||||
assert(j.value == i)
|
||||
assert j.value == i
|
||||
i += 1
|
||||
|
||||
# std::map
|
||||
@ -265,21 +271,21 @@ def test_noncopyable_containers():
|
||||
|
||||
def test_map_delitem():
|
||||
mm = m.MapStringDouble()
|
||||
mm['a'] = 1
|
||||
mm['b'] = 2.5
|
||||
mm["a"] = 1
|
||||
mm["b"] = 2.5
|
||||
|
||||
assert list(mm) == ['a', 'b']
|
||||
assert list(mm.items()) == [('a', 1), ('b', 2.5)]
|
||||
del mm['a']
|
||||
assert list(mm) == ['b']
|
||||
assert list(mm.items()) == [('b', 2.5)]
|
||||
assert list(mm) == ["a", "b"]
|
||||
assert list(mm.items()) == [("a", 1), ("b", 2.5)]
|
||||
del mm["a"]
|
||||
assert list(mm) == ["b"]
|
||||
assert list(mm.items()) == [("b", 2.5)]
|
||||
|
||||
um = m.UnorderedMapStringDouble()
|
||||
um['ua'] = 1.1
|
||||
um['ub'] = 2.6
|
||||
um["ua"] = 1.1
|
||||
um["ub"] = 2.6
|
||||
|
||||
assert sorted(list(um)) == ['ua', 'ub']
|
||||
assert sorted(list(um.items())) == [('ua', 1.1), ('ub', 2.6)]
|
||||
del um['ua']
|
||||
assert sorted(list(um)) == ['ub']
|
||||
assert sorted(list(um.items())) == [('ub', 2.6)]
|
||||
assert sorted(list(um)) == ["ua", "ub"]
|
||||
assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)]
|
||||
del um["ua"]
|
||||
assert sorted(list(um)) == ["ub"]
|
||||
assert sorted(list(um.items())) == [("ub", 2.6)]
|
||||
|
@ -5,16 +5,24 @@ from pybind11_tests import tagbased_polymorphic as m
|
||||
def test_downcast():
|
||||
zoo = m.create_zoo()
|
||||
assert [type(animal) for animal in zoo] == [
|
||||
m.Labrador, m.Dog, m.Chihuahua, m.Cat, m.Panther
|
||||
m.Labrador,
|
||||
m.Dog,
|
||||
m.Chihuahua,
|
||||
m.Cat,
|
||||
m.Panther,
|
||||
]
|
||||
assert [animal.name for animal in zoo] == [
|
||||
"Fido", "Ginger", "Hertzl", "Tiger", "Leo"
|
||||
"Fido",
|
||||
"Ginger",
|
||||
"Hertzl",
|
||||
"Tiger",
|
||||
"Leo",
|
||||
]
|
||||
zoo[1].sound = "woooooo"
|
||||
assert [dog.bark() for dog in zoo[:3]] == [
|
||||
"Labrador Fido goes WOOF!",
|
||||
"Dog Ginger goes woooooo",
|
||||
"Chihuahua Hertzl goes iyiyiyiyiyi and runs in circles"
|
||||
"Chihuahua Hertzl goes iyiyiyiyiyi and runs in circles",
|
||||
]
|
||||
assert [cat.purr() for cat in zoo[3:]] == ["mrowr", "mrrrRRRRRR"]
|
||||
zoo[0].excitement -= 1000
|
||||
|
@ -14,18 +14,18 @@ def test_override(capture, msg):
|
||||
self.data = "Hello world"
|
||||
|
||||
def run(self, value):
|
||||
print('ExtendedExampleVirt::run(%i), calling parent..' % value)
|
||||
print("ExtendedExampleVirt::run(%i), calling parent.." % value)
|
||||
return super(ExtendedExampleVirt, self).run(value + 1)
|
||||
|
||||
def run_bool(self):
|
||||
print('ExtendedExampleVirt::run_bool()')
|
||||
print("ExtendedExampleVirt::run_bool()")
|
||||
return False
|
||||
|
||||
def get_string1(self):
|
||||
return "override1"
|
||||
|
||||
def pure_virtual(self):
|
||||
print('ExtendedExampleVirt::pure_virtual(): %s' % self.data)
|
||||
print("ExtendedExampleVirt::pure_virtual(): %s" % self.data)
|
||||
|
||||
class ExtendedExampleVirt2(ExtendedExampleVirt):
|
||||
def __init__(self, state):
|
||||
@ -37,21 +37,30 @@ def test_override(capture, msg):
|
||||
ex12 = m.ExampleVirt(10)
|
||||
with capture:
|
||||
assert m.runExampleVirt(ex12, 20) == 30
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.runExampleVirtVirtual(ex12)
|
||||
assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== 'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
|
||||
)
|
||||
|
||||
ex12p = ExtendedExampleVirt(10)
|
||||
with capture:
|
||||
assert m.runExampleVirt(ex12p, 20) == 32
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
ExtendedExampleVirt::run(20), calling parent..
|
||||
Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
with capture:
|
||||
assert m.runExampleVirtBool(ex12p) is False
|
||||
assert capture == "ExtendedExampleVirt::run_bool()"
|
||||
@ -62,16 +71,19 @@ def test_override(capture, msg):
|
||||
ex12p2 = ExtendedExampleVirt2(15)
|
||||
with capture:
|
||||
assert m.runExampleVirt(ex12p2, 50) == 68
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
ExtendedExampleVirt::run(50), calling parent..
|
||||
Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
|
||||
""" # noqa: E501 line too long
|
||||
)
|
||||
|
||||
cstats = ConstructorStats.get(m.ExampleVirt)
|
||||
assert cstats.alive() == 3
|
||||
del ex12, ex12p, ex12p2
|
||||
assert cstats.alive() == 0
|
||||
assert cstats.values() == ['10', '11', '17']
|
||||
assert cstats.values() == ["10", "11", "17"]
|
||||
assert cstats.copy_constructions == 0
|
||||
assert cstats.move_constructions >= 0
|
||||
|
||||
@ -82,6 +94,7 @@ def test_alias_delay_initialization1(capture):
|
||||
If we just create and use an A instance directly, the trampoline initialization is
|
||||
bypassed and we only initialize an A() instead (for performance reasons).
|
||||
"""
|
||||
|
||||
class B(m.A):
|
||||
def __init__(self):
|
||||
super(B, self).__init__()
|
||||
@ -103,12 +116,15 @@ def test_alias_delay_initialization1(capture):
|
||||
m.call_f(b)
|
||||
del b
|
||||
pytest.gc_collect()
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
PyA.PyA()
|
||||
PyA.f()
|
||||
In python f()
|
||||
PyA.~PyA()
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def test_alias_delay_initialization2(capture):
|
||||
@ -118,6 +134,7 @@ def test_alias_delay_initialization2(capture):
|
||||
performance penalty, it also allows us to do more things with the trampoline
|
||||
class such as defining local variables and performing construction/destruction.
|
||||
"""
|
||||
|
||||
class B2(m.A2):
|
||||
def __init__(self):
|
||||
super(B2, self).__init__()
|
||||
@ -135,7 +152,9 @@ def test_alias_delay_initialization2(capture):
|
||||
m.call_f(a3)
|
||||
del a3
|
||||
pytest.gc_collect()
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
PyA2.PyA2()
|
||||
PyA2.f()
|
||||
A2.f()
|
||||
@ -145,6 +164,7 @@ def test_alias_delay_initialization2(capture):
|
||||
A2.f()
|
||||
PyA2.~PyA2()
|
||||
"""
|
||||
)
|
||||
|
||||
# Python subclass version
|
||||
with capture:
|
||||
@ -152,20 +172,22 @@ def test_alias_delay_initialization2(capture):
|
||||
m.call_f(b2)
|
||||
del b2
|
||||
pytest.gc_collect()
|
||||
assert capture == """
|
||||
assert (
|
||||
capture
|
||||
== """
|
||||
PyA2.PyA2()
|
||||
PyA2.f()
|
||||
In python B2.f()
|
||||
PyA2.~PyA2()
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
# PyPy: Reference count > 1 causes call with noncopyable instance
|
||||
# to fail in ncv1.print_nc()
|
||||
@pytest.mark.xfail("env.PYPY")
|
||||
@pytest.mark.skipif(
|
||||
not hasattr(m, "NCVirt"),
|
||||
reason="NCVirt does not work on Intel/PGI/NVCC compilers"
|
||||
not hasattr(m, "NCVirt"), reason="NCVirt does not work on Intel/PGI/NVCC compilers"
|
||||
)
|
||||
def test_move_support():
|
||||
class NCVirtExt(m.NCVirt):
|
||||
@ -205,8 +227,8 @@ def test_move_support():
|
||||
del ncv1, ncv2
|
||||
assert nc_stats.alive() == 0
|
||||
assert mv_stats.alive() == 0
|
||||
assert nc_stats.values() == ['4', '9', '9', '9']
|
||||
assert mv_stats.values() == ['4', '5', '7', '7']
|
||||
assert nc_stats.values() == ["4", "9", "9", "9"]
|
||||
assert mv_stats.values() == ["4", "5", "7", "7"]
|
||||
assert nc_stats.copy_constructions == 0
|
||||
assert mv_stats.copy_constructions == 1
|
||||
assert nc_stats.move_constructions >= 0
|
||||
@ -215,6 +237,7 @@ def test_move_support():
|
||||
|
||||
def test_dispatch_issue(msg):
|
||||
"""#159: virtual function dispatch has problems with similar-named functions"""
|
||||
|
||||
class PyClass1(m.DispatchIssue):
|
||||
def dispatch(self):
|
||||
return "Yay.."
|
||||
@ -223,7 +246,10 @@ def test_dispatch_issue(msg):
|
||||
def dispatch(self):
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
super(PyClass2, self).dispatch()
|
||||
assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== 'Tried to call pure virtual function "Base::dispatch"'
|
||||
)
|
||||
|
||||
p = PyClass1()
|
||||
return m.dispatch_issue_go(p)
|
||||
@ -339,7 +365,7 @@ def test_inherited_virtuals():
|
||||
|
||||
class DT(m.D_Tpl):
|
||||
def say_something(self, times):
|
||||
return "DT says:" + (' quack' * times)
|
||||
return "DT says:" + (" quack" * times)
|
||||
|
||||
def unlucky_number(self):
|
||||
return 1234
|
||||
@ -355,7 +381,7 @@ def test_inherited_virtuals():
|
||||
|
||||
class DT2(DT):
|
||||
def say_something(self, times):
|
||||
return "DT2: " + ('QUACK' * times)
|
||||
return "DT2: " + ("QUACK" * times)
|
||||
|
||||
def unlucky_number(self):
|
||||
return -3
|
||||
|
Loading…
Reference in New Issue
Block a user