style: use Black everywhere (#2594)

* style: use Black everywhere

* style: minor touchup from review
This commit is contained in:
Henry Schreiner 2020-10-16 16:38:13 -04:00 committed by GitHub
parent 2e31e466dc
commit c50f90eca6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1653 additions and 941 deletions

View File

@ -36,8 +36,7 @@ repos:
- id: black - id: black
# By default, this ignores pyi files, though black supports them # By default, this ignores pyi files, though black supports them
types: [text] types: [text]
# Not all Python files are Blacked, yet files: \.pyi?$
files: ^(setup.py|pybind11|tests/extra|tools).*\.pyi?$
# Changes tabs to spaces # Changes tabs to spaces
- repo: https://github.com/Lucas-C/pre-commit-hooks - repo: https://github.com/Lucas-C/pre-commit-hooks

View File

@ -14,7 +14,7 @@ def generate_dummy_code_pybind11(nclasses=10):
for cl in range(nclasses): for cl in range(nclasses):
decl += "class cl%03i;\n" % cl decl += "class cl%03i;\n" % cl
decl += '\n' decl += "\n"
for cl in range(nclasses): for cl in range(nclasses):
decl += "class cl%03i {\n" % cl 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) bindings += ' py::class_<cl%03i>(m, "cl%03i")\n' % (cl, cl)
for fn in range(nfns): for fn in range(nfns):
ret = random.randint(0, nclasses - 1) 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 += " cl%03i *fn_%03i(" % (ret, fn)
decl += ", ".join("cl%03i *" % p for p in params) decl += ", ".join("cl%03i *" % p for p in params)
decl += ");\n" decl += ");\n"
bindings += ' .def("fn_%03i", &cl%03i::fn_%03i)\n' % \ bindings += ' .def("fn_%03i", &cl%03i::fn_%03i)\n' % (fn, cl, fn)
(fn, cl, fn)
decl += "};\n\n" decl += "};\n\n"
bindings += ' ;\n' bindings += " ;\n"
result = "#include <pybind11/pybind11.h>\n\n" result = "#include <pybind11/pybind11.h>\n\n"
result += "namespace py = pybind11;\n\n" result += "namespace py = pybind11;\n\n"
result += decl + '\n' result += decl + "\n"
result += "PYBIND11_MODULE(example, m) {\n" result += "PYBIND11_MODULE(example, m) {\n"
result += bindings result += bindings
result += "}" result += "}"
@ -46,7 +45,7 @@ def generate_dummy_code_boost(nclasses=10):
for cl in range(nclasses): for cl in range(nclasses):
decl += "class cl%03i;\n" % cl decl += "class cl%03i;\n" % cl
decl += '\n' decl += "\n"
for cl in range(nclasses): for cl in range(nclasses):
decl += "class cl%03i {\n" % cl 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) bindings += ' py::class_<cl%03i>("cl%03i")\n' % (cl, cl)
for fn in range(nfns): for fn in range(nfns):
ret = random.randint(0, nclasses - 1) 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 += " cl%03i *fn_%03i(" % (ret, fn)
decl += ", ".join("cl%03i *" % p for p in params) decl += ", ".join("cl%03i *" % p for p in params)
decl += ");\n" decl += ");\n"
bindings += ' .def("fn_%03i", &cl%03i::fn_%03i, py::return_value_policy<py::manage_new_object>())\n' % \ bindings += (
(fn, cl, fn) ' .def("fn_%03i", &cl%03i::fn_%03i, py::return_value_policy<py::manage_new_object>())\n'
% (fn, cl, fn)
)
decl += "};\n\n" decl += "};\n\n"
bindings += ' ;\n' bindings += " ;\n"
result = "#include <boost/python.hpp>\n\n" result = "#include <boost/python.hpp>\n\n"
result += "namespace py = boost::python;\n\n" result += "namespace py = boost::python;\n\n"
result += decl + '\n' result += decl + "\n"
result += "BOOST_PYTHON_MODULE(example) {\n" result += "BOOST_PYTHON_MODULE(example) {\n"
result += bindings result += bindings
result += "}" result += "}"
@ -73,17 +74,19 @@ def generate_dummy_code_boost(nclasses=10):
for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]: for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]:
print ("{") print("{")
for i in range(0, 10): for i in range(0, 10):
nclasses = 2 ** i nclasses = 2 ** i
with open("test.cpp", "w") as f: with open("test.cpp", "w") as f:
f.write(codegen(nclasses)) f.write(codegen(nclasses))
n1 = dt.datetime.now() 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 " "-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() n2 = dt.datetime.now()
elapsed = (n2 - n1).total_seconds() 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(" {%i, %f, %i}," % (nclasses * nfns, elapsed, size))
print ("}") print("}")

View File

@ -21,40 +21,44 @@ import subprocess
# If extensions (or modules to document with autodoc) are in another directory, # 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 # 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. # 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 ------------------------------------------------ # -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here. # 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 # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = ['breathe', 'sphinxcontrib.rsvgconverter', 'sphinxcontrib.moderncmakedomain'] extensions = [
"breathe",
"sphinxcontrib.rsvgconverter",
"sphinxcontrib.moderncmakedomain",
]
breathe_projects = {'pybind11': '.build/doxygenxml/'} breathe_projects = {"pybind11": ".build/doxygenxml/"}
breathe_default_project = 'pybind11' breathe_default_project = "pybind11"
breathe_domain_by_extension = {'h': 'cpp'} breathe_domain_by_extension = {"h": "cpp"}
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates'] templates_path = [".templates"]
# The suffix(es) of source filenames. # The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string: # You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md'] # source_suffix = ['.rst', '.md']
source_suffix = '.rst' source_suffix = ".rst"
# The encoding of source files. # The encoding of source files.
#source_encoding = 'utf-8-sig' # source_encoding = 'utf-8-sig'
# The master toctree document. # The master toctree document.
master_doc = 'index' master_doc = "index"
# General information about the project. # General information about the project.
project = 'pybind11' project = "pybind11"
copyright = '2017, Wenzel Jakob' copyright = "2017, Wenzel Jakob"
author = 'Wenzel Jakob' author = "Wenzel Jakob"
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the # |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 # There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used: # non-false value, then it is used:
#today = '' # today = ''
# Else, today_fmt is used as the format for a strftime call. # 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 # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # 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 # The reST default role (used for this markup: `text`) to use for all
# documents. # documents.
default_role = 'any' default_role = "any"
# If true, '()' will be appended to :func: etc. cross-reference text. # 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 # If true, the current module name will be prepended to all description
# unit titles (such as .. function::). # unit titles (such as .. function::).
#add_module_names = True # add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the # If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default. # output. They are ignored by default.
#show_authors = False # show_authors = False
# The name of the Pygments (syntax highlighting) style to use. # 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. # 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. # 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. # If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False 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 # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # 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 if not on_rtd: # only import and set the theme if we're building docs locally
import sphinx_rtd_theme 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_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
html_context = { html_context = {"css_files": ["_static/theme_overrides.css"]}
'css_files': [
'_static/theme_overrides.css'
]
}
else: else:
html_context = { html_context = {
'css_files': [ "css_files": [
'//media.readthedocs.org/css/sphinx_rtd_theme.css', "//media.readthedocs.org/css/sphinx_rtd_theme.css",
'//media.readthedocs.org/css/readthedocs-doc-embed.css', "//media.readthedocs.org/css/readthedocs-doc-embed.css",
'_static/theme_overrides.css' "_static/theme_overrides.css",
] ]
} }
# Theme options are theme-specific and customize the look and feel of a theme # 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 # further. For a list of options available for each theme, see the
# documentation. # documentation.
#html_theme_options = {} # html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory. # 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 # The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<version> documentation". # "<project> v<version> documentation".
#html_title = None # html_title = None
# A shorter title for the navigation bar. Default is the same as html_title. # 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 # The name of an image file (relative to this directory) to place at the top
# of the sidebar. # 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 # 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 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large. # pixels large.
#html_favicon = None # html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here, # 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, # relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css". # 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 # Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied # .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation. # 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, # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format. # 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 # If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities. # typographically correct entities.
#html_use_smartypants = True # html_use_smartypants = True
# Custom sidebar templates, maps document names to template names. # 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 # Additional templates that should be rendered to pages, maps page names to
# template names. # template names.
#html_additional_pages = {} # html_additional_pages = {}
# If false, no module index is generated. # If false, no module index is generated.
#html_domain_indices = True # html_domain_indices = True
# If false, no index is generated. # 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. # 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. # 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. # 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. # 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 # 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 # contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served. # 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"). # 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. # Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages: # Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' # '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. # A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value # 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 # The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used. # 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. # Output file base name for HTML help builder.
htmlhelp_basename = 'pybind11doc' htmlhelp_basename = "pybind11doc"
# -- Options for LaTeX output --------------------------------------------- # -- Options for LaTeX output ---------------------------------------------
latex_elements = { latex_elements = {
# The paper size ('letterpaper' or 'a4paper'). # The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper', # 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
# The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt',
#'pointsize': '10pt', # Additional stuff for the LaTeX preamble.
"preamble": r"""
# Additional stuff for the LaTeX preamble.
'preamble': r'''
\DeclareUnicodeCharacter{00A0}{} \DeclareUnicodeCharacter{00A0}{}
\DeclareUnicodeCharacter{2194}{<->} \DeclareUnicodeCharacter{2194}{<->}
''', """,
# Latex figure (float) alignment
# Latex figure (float) alignment # 'figure_align': 'htbp',
#'figure_align': 'htbp',
} }
# Grouping the document tree into LaTeX files. List of tuples # Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, # (source start file, target name, title,
# author, documentclass [howto, manual, or own class]). # author, documentclass [howto, manual, or own class]).
latex_documents = [ latex_documents = [
(master_doc, 'pybind11.tex', 'pybind11 Documentation', (master_doc, "pybind11.tex", "pybind11 Documentation", "Wenzel Jakob", "manual"),
'Wenzel Jakob', 'manual'),
] ]
# The name of an image file (relative to this directory) to place at the top of # 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, # For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters. # not chapters.
#latex_use_parts = False # latex_use_parts = False
# If true, show page references after internal links. # If true, show page references after internal links.
#latex_show_pagerefs = False # latex_show_pagerefs = False
# If true, show URL addresses after external links. # 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. # Documents to append as an appendix to all manuals.
#latex_appendices = [] # latex_appendices = []
# If false, no module index is generated. # If false, no module index is generated.
#latex_domain_indices = True # latex_domain_indices = True
# -- Options for manual page output --------------------------------------- # -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
man_pages = [ man_pages = [(master_doc, "pybind11", "pybind11 Documentation", [author], 1)]
(master_doc, 'pybind11', 'pybind11 Documentation',
[author], 1)
]
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
#man_show_urls = False # man_show_urls = False
# -- Options for Texinfo output ------------------------------------------- # -- Options for Texinfo output -------------------------------------------
@ -299,35 +293,41 @@ man_pages = [
# (source start file, target name, title, author, # (source start file, target name, title, author,
# dir menu entry, description, category) # dir menu entry, description, category)
texinfo_documents = [ texinfo_documents = [
(master_doc, 'pybind11', 'pybind11 Documentation', (
author, 'pybind11', 'One line description of project.', master_doc,
'Miscellaneous'), "pybind11",
"pybind11 Documentation",
author,
"pybind11",
"One line description of project.",
"Miscellaneous",
),
] ]
# Documents to append as an appendix to all manuals. # Documents to append as an appendix to all manuals.
#texinfo_appendices = [] # texinfo_appendices = []
# If false, no module index is generated. # If false, no module index is generated.
#texinfo_domain_indices = True # texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'. # 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. # If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False # texinfo_no_detailmenu = False
primary_domain = 'cpp' primary_domain = "cpp"
highlight_language = 'cpp' highlight_language = "cpp"
def generate_doxygen_xml(app): 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): if not os.path.exists(build_dir):
os.mkdir(build_dir) os.mkdir(build_dir)
try: try:
subprocess.call(['doxygen', '--version']) subprocess.call(["doxygen", "--version"])
retcode = subprocess.call(['doxygen'], cwd=app.confdir) retcode = subprocess.call(["doxygen"], cwd=app.confdir)
if retcode < 0: if retcode < 0:
sys.stderr.write("doxygen error code: {}\n".format(-retcode)) sys.stderr.write("doxygen error code: {}\n".format(-retcode))
except OSError as e: except OSError as e:

View File

@ -18,9 +18,9 @@ import env
# Early diagnostic for failed imports # Early diagnostic for failed imports
import pybind11_tests # noqa: F401 import pybind11_tests # noqa: F401
_unicode_marker = re.compile(r'u(\'[^\']*\')') _unicode_marker = re.compile(r"u(\'[^\']*\')")
_long_marker = re.compile(r'([0-9])L') _long_marker = re.compile(r"([0-9])L")
_hexadecimal = re.compile(r'0x[0-9a-fA-F]+') _hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
# Avoid collecting Python3 only files # Avoid collecting Python3 only files
collect_ignore = [] collect_ignore = []
@ -30,7 +30,7 @@ if env.PY2:
def _strip_and_dedent(s): def _strip_and_dedent(s):
"""For triple-quote strings""" """For triple-quote strings"""
return textwrap.dedent(s.lstrip('\n').rstrip()) return textwrap.dedent(s.lstrip("\n").rstrip())
def _split_and_sort(s): def _split_and_sort(s):
@ -40,11 +40,14 @@ def _split_and_sort(s):
def _make_explanation(a, b): def _make_explanation(a, b):
"""Explanation for a failed assert -- the a and b arguments are List[str]""" """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): class Output(object):
"""Basic output post-processing and comparison""" """Basic output post-processing and comparison"""
def __init__(self, string): def __init__(self, string):
self.string = string self.string = string
self.explanation = [] self.explanation = []
@ -54,7 +57,11 @@ class Output(object):
def __eq__(self, other): def __eq__(self, other):
# Ignore constructor/destructor output which is prefixed with "###" # 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() b = _strip_and_dedent(other).splitlines()
if a == b: if a == b:
return True return True
@ -65,6 +72,7 @@ class Output(object):
class Unordered(Output): class Unordered(Output):
"""Custom comparison for output without strict line ordering""" """Custom comparison for output without strict line ordering"""
def __eq__(self, other): def __eq__(self, other):
a = _split_and_sort(self.string) a = _split_and_sort(self.string)
b = _split_and_sort(other) b = _split_and_sort(other)
@ -175,7 +183,7 @@ def msg():
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
def pytest_assertrepr_compare(op, left, right): def pytest_assertrepr_compare(op, left, right):
"""Hook to insert custom failure explanation""" """Hook to insert custom failure explanation"""
if hasattr(left, 'explanation'): if hasattr(left, "explanation"):
return left.explanation return left.explanation
@ -189,8 +197,8 @@ def suppress(exception):
def gc_collect(): def gc_collect():
''' Run the garbage collector twice (needed when running """Run the garbage collector twice (needed when running
reference counting tests with PyPy) ''' reference counting tests with PyPy)"""
gc.collect() gc.collect()
gc.collect() gc.collect()

View File

@ -46,8 +46,8 @@ def test_to_python():
mat[3, 2] = 7.0 mat[3, 2] = 7.0
assert mat[2, 3] == 4 assert mat[2, 3] == 4
assert mat[3, 2] == 7 assert mat[3, 2] == 7
assert struct.unpack_from('f', mat, (3 * 4 + 2) * 4) == (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, (2 * 4 + 3) * 4) == (4,)
mat2 = np.array(mat, copy=False) mat2 = np.array(mat, copy=False)
assert mat2.shape == (5, 4) assert mat2.shape == (5, 4)
@ -83,31 +83,31 @@ def test_pointer_to_member_fn():
for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]: for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]:
buf = cls() buf = cls()
buf.value = 0x12345678 buf.value = 0x12345678
value = struct.unpack('i', bytearray(buf))[0] value = struct.unpack("i", bytearray(buf))[0]
assert value == 0x12345678 assert value == 0x12345678
def test_readonly_buffer(): def test_readonly_buffer():
buf = m.BufferReadOnly(0x64) buf = m.BufferReadOnly(0x64)
view = memoryview(buf) 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 assert view.readonly
def test_selective_readonly_buffer(): def test_selective_readonly_buffer():
buf = m.BufferReadOnlySelect() 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 assert buf.value == 0x64
io.BytesIO(b'A').readinto(buf) io.BytesIO(b"A").readinto(buf)
assert buf.value == ord(b'A') assert buf.value == ord(b"A")
buf.readonly = True buf.readonly = True
with pytest.raises(TypeError): 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): with pytest.raises(TypeError):
io.BytesIO(b'1').readinto(buf) io.BytesIO(b"1").readinto(buf)
def test_ctypes_array_1d(): def test_ctypes_array_1d():

View File

@ -37,79 +37,85 @@ def test_unicode_conversion():
with pytest.raises(UnicodeDecodeError): with pytest.raises(UnicodeDecodeError):
m.bad_utf8_u8string() m.bad_utf8_u8string()
assert m.u8_Z() == 'Z' assert m.u8_Z() == "Z"
assert m.u8_eacute() == u'é' assert m.u8_eacute() == u"é"
assert m.u16_ibang() == u'' assert m.u16_ibang() == u""
assert m.u32_mathbfA() == u'𝐀' assert m.u32_mathbfA() == u"𝐀"
assert m.wchar_heart() == u'' assert m.wchar_heart() == u""
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
assert m.u8_char8_Z() == 'Z' assert m.u8_char8_Z() == "Z"
def test_single_char_arguments(): def test_single_char_arguments():
"""Tests failures for passing invalid inputs to char-accepting functions""" """Tests failures for passing invalid inputs to char-accepting functions"""
def toobig_message(r): def toobig_message(r):
return "Character code point not in range({0:#x})".format(r) return "Character code point not in range({0:#x})".format(r)
toolong_message = "Expected a character, but multi-character string found" toolong_message = "Expected a character, but multi-character string found"
assert m.ord_char(u'a') == 0x61 # simple ASCII assert m.ord_char(u"a") == 0x61 # simple ASCII
assert m.ord_char_lv(u'b') == 0x62 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"é") == 0xE9
) # requires 2 bytes in utf-8, but can be stuffed in a char
with pytest.raises(ValueError) as excinfo: 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) assert str(excinfo.value) == toobig_message(0x100)
with pytest.raises(ValueError) as excinfo: 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 str(excinfo.value) == toolong_message
assert m.ord_char16(u'a') == 0x61 assert m.ord_char16(u"a") == 0x61
assert m.ord_char16(u'é') == 0xE9 assert m.ord_char16(u"é") == 0xE9
assert m.ord_char16_lv(u'ê') == 0xEA assert m.ord_char16_lv(u"ê") == 0xEA
assert m.ord_char16(u'Ā') == 0x100 assert m.ord_char16(u"Ā") == 0x100
assert m.ord_char16(u'') == 0x203d assert m.ord_char16(u"") == 0x203D
assert m.ord_char16(u'') == 0x2665 assert m.ord_char16(u"") == 0x2665
assert m.ord_char16_lv(u'') == 0x2661 assert m.ord_char16_lv(u"") == 0x2661
with pytest.raises(ValueError) as excinfo: 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) assert str(excinfo.value) == toobig_message(0x10000)
with pytest.raises(ValueError) as excinfo: 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 str(excinfo.value) == toolong_message
assert m.ord_char32(u'a') == 0x61 assert m.ord_char32(u"a") == 0x61
assert m.ord_char32(u'é') == 0xE9 assert m.ord_char32(u"é") == 0xE9
assert m.ord_char32(u'Ā') == 0x100 assert m.ord_char32(u"Ā") == 0x100
assert m.ord_char32(u'') == 0x203d assert m.ord_char32(u"") == 0x203D
assert m.ord_char32(u'') == 0x2665 assert m.ord_char32(u"") == 0x2665
assert m.ord_char32(u'🎂') == 0x1F382 assert m.ord_char32(u"🎂") == 0x1F382
with pytest.raises(ValueError) as excinfo: 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 str(excinfo.value) == toolong_message
assert m.ord_wchar(u'a') == 0x61 assert m.ord_wchar(u"a") == 0x61
assert m.ord_wchar(u'é') == 0xE9 assert m.ord_wchar(u"é") == 0xE9
assert m.ord_wchar(u'Ā') == 0x100 assert m.ord_wchar(u"Ā") == 0x100
assert m.ord_wchar(u'') == 0x203d assert m.ord_wchar(u"") == 0x203D
assert m.ord_wchar(u'') == 0x2665 assert m.ord_wchar(u"") == 0x2665
if m.wchar_size == 2: if m.wchar_size == 2:
with pytest.raises(ValueError) as excinfo: 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) assert str(excinfo.value) == toobig_message(0x10000)
else: else:
assert m.ord_wchar(u'🎂') == 0x1F382 assert m.ord_wchar(u"🎂") == 0x1F382
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
assert m.ord_wchar(u'aa') assert m.ord_wchar(u"aa")
assert str(excinfo.value) == toolong_message assert str(excinfo.value) == toolong_message
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
assert m.ord_char8(u'a') == 0x61 # simple ASCII assert m.ord_char8(u"a") == 0x61 # simple ASCII
assert m.ord_char8_lv(u'b') == 0x62 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"é") == 0xE9
) # requires 2 bytes in utf-8, but can be stuffed in a char
with pytest.raises(ValueError) as excinfo: 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) assert str(excinfo.value) == toobig_message(0x100)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
assert m.ord_char8(u'ab') assert m.ord_char8(u"ab")
assert str(excinfo.value) == toolong_message 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 assert m.strlen(to_bytes("a\x00b")) == 1 # C-string limitation
# passing in a utf8 encoded string should work # 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>") @pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
def test_string_view(capture): def test_string_view(capture):
"""Tests support for C++17 string_view arguments and return values""" """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]
assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82] 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_view16_chars(u"Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
assert m.string_view32_chars(u"Hi 🎂") == [72, 105, 32, 127874] assert m.string_view32_chars(u"Hi 🎂") == [72, 105, 32, 127874]
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
assert m.string_view8_chars("Hi") == [72, 105] 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_view_return() == u"utf8 secret 🎂"
assert m.string_view16_return() == u"utf16 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_view_print("utf8 🎂")
m.string_view16_print(u"utf16 🎂") m.string_view16_print(u"utf16 🎂")
m.string_view32_print(u"utf32 🎂") m.string_view32_print(u"utf32 🎂")
assert capture == u""" assert (
capture
== u"""
Hi 2 Hi 2
utf8 🎂 9 utf8 🎂 9
utf16 🎂 8 utf16 🎂 8
utf32 🎂 7 utf32 🎂 7
""" """
)
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
with capture: with capture:
m.string_view8_print("Hi") m.string_view8_print("Hi")
m.string_view8_print(u"utf8 🎂") m.string_view8_print(u"utf8 🎂")
assert capture == u""" assert (
capture
== u"""
Hi 2 Hi 2
utf8 🎂 9 utf8 🎂 9
""" """
)
with capture: with capture:
m.string_view_print("Hi, ascii") m.string_view_print("Hi, ascii")
m.string_view_print("Hi, utf8 🎂") m.string_view_print("Hi, utf8 🎂")
m.string_view16_print(u"Hi, utf16 🎂") m.string_view16_print(u"Hi, utf16 🎂")
m.string_view32_print(u"Hi, utf32 🎂") m.string_view32_print(u"Hi, utf32 🎂")
assert capture == u""" assert (
capture
== u"""
Hi, ascii 9 Hi, ascii 9
Hi, utf8 🎂 13 Hi, utf8 🎂 13
Hi, utf16 🎂 12 Hi, utf16 🎂 12
Hi, utf32 🎂 11 Hi, utf32 🎂 11
""" """
)
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
with capture: with capture:
m.string_view8_print("Hi, ascii") m.string_view8_print("Hi, ascii")
m.string_view8_print(u"Hi, utf8 🎂") m.string_view8_print(u"Hi, utf8 🎂")
assert capture == u""" assert (
capture
== u"""
Hi, ascii 9 Hi, ascii 9
Hi, utf8 🎂 13 Hi, utf8 🎂 13
""" """
)
def test_integer_casting(): def test_integer_casting():
@ -199,8 +217,14 @@ def test_integer_casting():
if env.PY2: if env.PY2:
assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long' 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(-1)) == "-1" # noqa: F821 undefined name 'long'
assert m.i64_str(long(-999999999999)) == "-999999999999" # noqa: F821 undefined name assert (
assert m.u64_str(long(999999999999)) == "999999999999" # noqa: F821 undefined name 'long' m.i64_str(long(-999999999999)) # noqa: F821 undefined name 'long'
== "-999999999999"
)
assert (
m.u64_str(long(999999999999)) # noqa: F821 undefined name 'long'
== "999999999999"
)
else: else:
assert m.i64_str(-999999999999) == "-999999999999" assert m.i64_str(-999999999999) == "-999999999999"
assert m.u64_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.tuple_passthrough([True, "test", 5]) == (5, "test", True)
assert m.empty_tuple() == () assert m.empty_tuple() == ()
assert doc(m.pair_passthrough) == """ assert (
doc(m.pair_passthrough)
== """
pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool] pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool]
Return a pair in reversed order 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] tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool]
Return a triple in reversed order Return a triple in reversed order
""" """
)
assert m.rvalue_pair() == ("rvalue", "rvalue") assert m.rvalue_pair() == ("rvalue", "rvalue")
assert m.lvalue_pair() == ("lvalue", "lvalue") assert m.lvalue_pair() == ("lvalue", "lvalue")
@ -372,7 +402,7 @@ def test_numpy_bool():
assert convert(np.bool_(False)) is False assert convert(np.bool_(False)) is False
assert noconvert(np.bool_(True)) is True assert noconvert(np.bool_(True)) is True
assert noconvert(np.bool_(False)) is False 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(): def test_int_long():
@ -382,7 +412,8 @@ def test_int_long():
long.""" long."""
import sys 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.int_cast(), int)
assert isinstance(m.long_cast(), int) assert isinstance(m.long_cast(), int)
assert isinstance(m.longlong_cast(), must_be_long) assert isinstance(m.longlong_cast(), must_be_long)

View File

@ -16,10 +16,13 @@ def test_keep_alive_argument(capture):
with capture: with capture:
p.addChild(m.Child()) p.addChild(m.Child())
assert ConstructorStats.detail_reg_inst() == n_inst + 1 assert ConstructorStats.detail_reg_inst() == n_inst + 1
assert capture == """ assert (
capture
== """
Allocating child. Allocating child.
Releasing child. Releasing child.
""" """
)
with capture: with capture:
del p del p
assert ConstructorStats.detail_reg_inst() == n_inst assert ConstructorStats.detail_reg_inst() == n_inst
@ -35,10 +38,13 @@ def test_keep_alive_argument(capture):
with capture: with capture:
del p del p
assert ConstructorStats.detail_reg_inst() == n_inst assert ConstructorStats.detail_reg_inst() == n_inst
assert capture == """ assert (
capture
== """
Releasing parent. Releasing parent.
Releasing child. Releasing child.
""" """
)
def test_keep_alive_return_value(capture): def test_keep_alive_return_value(capture):
@ -49,10 +55,13 @@ def test_keep_alive_return_value(capture):
with capture: with capture:
p.returnChild() p.returnChild()
assert ConstructorStats.detail_reg_inst() == n_inst + 1 assert ConstructorStats.detail_reg_inst() == n_inst + 1
assert capture == """ assert (
capture
== """
Allocating child. Allocating child.
Releasing child. Releasing child.
""" """
)
with capture: with capture:
del p del p
assert ConstructorStats.detail_reg_inst() == n_inst assert ConstructorStats.detail_reg_inst() == n_inst
@ -68,10 +77,13 @@ def test_keep_alive_return_value(capture):
with capture: with capture:
del p del p
assert ConstructorStats.detail_reg_inst() == n_inst assert ConstructorStats.detail_reg_inst() == n_inst
assert capture == """ assert (
capture
== """
Releasing parent. Releasing parent.
Releasing child. Releasing child.
""" """
)
# https://foss.heptapod.net/pypy/pypy/-/issues/2447 # https://foss.heptapod.net/pypy/pypy/-/issues/2447
@ -82,14 +94,17 @@ def test_alive_gc(capture):
p.addChildKeepAlive(m.Child()) p.addChildKeepAlive(m.Child())
assert ConstructorStats.detail_reg_inst() == n_inst + 2 assert ConstructorStats.detail_reg_inst() == n_inst + 2
lst = [p] lst = [p]
lst.append(lst) # creates a circular reference lst.append(lst) # creates a circular reference
with capture: with capture:
del p, lst del p, lst
assert ConstructorStats.detail_reg_inst() == n_inst assert ConstructorStats.detail_reg_inst() == n_inst
assert capture == """ assert (
capture
== """
Releasing parent. Releasing parent.
Releasing child. Releasing child.
""" """
)
def test_alive_gc_derived(capture): def test_alive_gc_derived(capture):
@ -101,14 +116,17 @@ def test_alive_gc_derived(capture):
p.addChildKeepAlive(m.Child()) p.addChildKeepAlive(m.Child())
assert ConstructorStats.detail_reg_inst() == n_inst + 2 assert ConstructorStats.detail_reg_inst() == n_inst + 2
lst = [p] lst = [p]
lst.append(lst) # creates a circular reference lst.append(lst) # creates a circular reference
with capture: with capture:
del p, lst del p, lst
assert ConstructorStats.detail_reg_inst() == n_inst assert ConstructorStats.detail_reg_inst() == n_inst
assert capture == """ assert (
capture
== """
Releasing parent. Releasing parent.
Releasing child. Releasing child.
""" """
)
def test_alive_gc_multi_derived(capture): 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 # +3 rather than +2 because Derived corresponds to two registered instances
assert ConstructorStats.detail_reg_inst() == n_inst + 3 assert ConstructorStats.detail_reg_inst() == n_inst + 3
lst = [p] lst = [p]
lst.append(lst) # creates a circular reference lst.append(lst) # creates a circular reference
with capture: with capture:
del p, lst del p, lst
assert ConstructorStats.detail_reg_inst() == n_inst assert ConstructorStats.detail_reg_inst() == n_inst
assert capture == """ assert (
capture
== """
Releasing parent. Releasing parent.
Releasing child. Releasing child.
Releasing child. Releasing child.
""" """
)
def test_return_none(capture): def test_return_none(capture):
@ -167,17 +188,23 @@ def test_keep_alive_constructor(capture):
with capture: with capture:
p = m.Parent(m.Child()) p = m.Parent(m.Child())
assert ConstructorStats.detail_reg_inst() == n_inst + 2 assert ConstructorStats.detail_reg_inst() == n_inst + 2
assert capture == """ assert (
capture
== """
Allocating child. Allocating child.
Allocating parent. Allocating parent.
""" """
)
with capture: with capture:
del p del p
assert ConstructorStats.detail_reg_inst() == n_inst assert ConstructorStats.detail_reg_inst() == n_inst
assert capture == """ assert (
capture
== """
Releasing parent. Releasing parent.
Releasing child. Releasing child.
""" """
)
def test_call_guard(): def test_call_guard():

View File

@ -42,17 +42,19 @@ def test_bound_method_callback():
def test_keyword_args_and_generalized_unpacking(): def test_keyword_args_and_generalized_unpacking():
def f(*args, **kwargs): def f(*args, **kwargs):
return args, kwargs return args, kwargs
assert m.test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {}) 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_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_keywords1(f) == ((1, 2), {"c": 3, "d": 4})
assert m.test_unpacking_and_keywords2(f) == ( assert m.test_unpacking_and_keywords2(f) == (
("positional", 1, 2, 3, 4, 5), ("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: with pytest.raises(TypeError) as excinfo:
@ -83,12 +85,18 @@ def test_lambda_closure_cleanup():
def test_cpp_function_roundtrip(): def test_cpp_function_roundtrip():
"""Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer""" """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 (
assert (m.test_dummy_function(m.roundtrip(m.dummy_function)) == m.test_dummy_function(m.dummy_function) == "matches dummy_function: eval(1) = 2"
"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.roundtrip(None, expect_none=True) is None
assert (m.test_dummy_function(lambda x: x + 2) == assert (
"can't convert to function pointer: eval(1) = 3") m.test_dummy_function(lambda x: x + 2)
== "can't convert to function pointer: eval(1) = 3"
)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.test_dummy_function(m.dummy_function2) m.test_dummy_function(m.dummy_function2)
@ -96,8 +104,10 @@ def test_cpp_function_roundtrip():
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.test_dummy_function(lambda x, y: x + y) m.test_dummy_function(lambda x, y: x + y)
assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument", assert any(
"takes exactly 2 arguments")) s in str(excinfo.value)
for s in ("missing 1 required positional argument", "takes exactly 2 arguments")
)
def test_function_signatures(doc): def test_function_signatures(doc):
@ -127,6 +137,7 @@ def test_async_callbacks():
m.test_async_callback(gen_f(), work) m.test_async_callback(gen_f(), work)
# wait until work is done # wait until work is done
from time import sleep from time import sleep
sleep(0.5) sleep(0.5)
assert sum(res) == sum([x + 3 for x in work]) assert sum(res) == sum([x + 3 for x in work])

View File

@ -80,22 +80,28 @@ SKIP_TZ_ENV_ON_WIN = pytest.mark.skipif(
) )
@pytest.mark.parametrize("time1", [ @pytest.mark.parametrize(
datetime.datetime.today().time(), "time1",
datetime.time(0, 0, 0), [
datetime.time(0, 0, 0, 1), datetime.datetime.today().time(),
datetime.time(0, 28, 45, 109827), datetime.time(0, 0, 0),
datetime.time(0, 59, 59, 999999), datetime.time(0, 0, 0, 1),
datetime.time(1, 0, 0), datetime.time(0, 28, 45, 109827),
datetime.time(5, 59, 59, 0), datetime.time(0, 59, 59, 999999),
datetime.time(5, 59, 59, 1), datetime.time(1, 0, 0),
]) datetime.time(5, 59, 59, 0),
@pytest.mark.parametrize("tz", [ datetime.time(5, 59, 59, 1),
None, ],
pytest.param("Europe/Brussels", marks=SKIP_TZ_ENV_ON_WIN), )
pytest.param("Asia/Pyongyang", marks=SKIP_TZ_ENV_ON_WIN), @pytest.mark.parametrize(
pytest.param("America/New_York", marks=SKIP_TZ_ENV_ON_WIN), "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): def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch):
if tz is not None: if tz is not None:
monkeypatch.setenv("TZ", "/usr/share/zoneinfo/{}".format(tz)) monkeypatch.setenv("TZ", "/usr/share/zoneinfo/{}".format(tz))
@ -199,7 +205,7 @@ def test_floating_point_duration():
def test_nano_timepoint(): def test_nano_timepoint():
time = datetime.datetime.now() time = datetime.datetime.now()
time1 = m.test_nano_timepoint(time, datetime.timedelta(seconds=60)) 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(): def test_chrono_different_resolutions():

View File

@ -31,8 +31,10 @@ def test_type():
with pytest.raises(RuntimeError) as execinfo: with pytest.raises(RuntimeError) as execinfo:
m.check_type(0) m.check_type(0)
assert 'pybind11::detail::get_type_info: unable to find type info' in str(execinfo.value) assert "pybind11::detail::get_type_info: unable to find type info" in str(
assert 'Invalid' in str(execinfo.value) execinfo.value
)
assert "Invalid" in str(execinfo.value)
# Currently not supported # Currently not supported
# See https://github.com/pybind/pybind11/issues/2486 # 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.__name__ == "get_value"
assert UserType.get_value.__module__ == "pybind11_tests" 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(self: m.UserType) -> int
Get value using a method Get value using a method
""" """
)
assert doc(UserType.value) == "Get/set value using a property" 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 new_instance() -> m.class_.NoConstructor
Return an instance Return an instance
""" """
)
def test_qualname(doc): def test_qualname(doc):
@ -93,51 +101,69 @@ def test_qualname(doc):
assert m.NestBase.__qualname__ == "NestBase" assert m.NestBase.__qualname__ == "NestBase"
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested" assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
assert doc(m.NestBase.__init__) == """ assert (
doc(m.NestBase.__init__)
== """
__init__(self: m.class_.NestBase) -> None __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 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 __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 fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
""" # noqa: E501 line too long """ # 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 fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
assert m.NestBase.__module__ == "pybind11_tests.class_" assert m.NestBase.__module__ == "pybind11_tests.class_"
assert m.NestBase.Nested.__module__ == "pybind11_tests.class_" assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
def test_inheritance(msg): def test_inheritance(msg):
roger = m.Rabbit('Rabbit') roger = m.Rabbit("Rabbit")
assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot" assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
assert m.pet_name_species(roger) == "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 polly.name() + " is a " + polly.species() == "Polly is a parrot"
assert m.pet_name_species(polly) == "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 molly.name() + " is a " + molly.species() == "Molly is a dog"
assert m.pet_name_species(molly) == "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 fred.name() + " is a " + fred.species() == "Fred is a rodent"
assert m.dog_bark(molly) == "Woof!" assert m.dog_bark(molly) == "Woof!"
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.dog_bark(polly) m.dog_bark(polly)
assert msg(excinfo.value) == """ assert (
msg(excinfo.value)
== """
dog_bark(): incompatible function arguments. The following argument types are supported: dog_bark(): incompatible function arguments. The following argument types are supported:
1. (arg0: m.class_.Dog) -> str 1. (arg0: m.class_.Dog) -> str
Invoked with: <m.class_.Pet object at 0> Invoked with: <m.class_.Pet object at 0>
""" """
)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.Chimera("lion", "goat") m.Chimera("lion", "goat")
@ -150,6 +176,7 @@ def test_inheritance_init(msg):
class Python(m.Pet): class Python(m.Pet):
def __init__(self): def __init__(self):
pass pass
with pytest.raises(TypeError) as exc_info: with pytest.raises(TypeError) as exc_info:
Python() Python()
expected = "m.class_.Pet.__init__() must be called when overriding __init__" 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: with pytest.raises(RuntimeError) as excinfo:
m.mismatched_holder_1() m.mismatched_holder_1()
assert re.match('generic_type: type ".*MismatchDerived1" does not have a non-default ' assert re.match(
'holder type while its base ".*MismatchBase1" does', str(excinfo.value)) '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: with pytest.raises(RuntimeError) as excinfo:
m.mismatched_holder_2() m.mismatched_holder_2()
assert re.match('generic_type: type ".*MismatchDerived2" has a non-default holder type ' assert re.match(
'while its base ".*MismatchBase2" does not', str(excinfo.value)) 'generic_type: type ".*MismatchDerived2" has a non-default holder type '
'while its base ".*MismatchBase2" does not',
str(excinfo.value),
)
def test_override_static(): def test_override_static():
@ -229,20 +262,20 @@ def test_operator_new_delete(capture):
a = m.HasOpNewDel() a = m.HasOpNewDel()
b = m.HasOpNewDelSize() b = m.HasOpNewDelSize()
d = m.HasOpNewDelBoth() d = m.HasOpNewDelBoth()
assert capture == """ assert (
capture
== """
A new 8 A new 8
B new 4 B new 4
D new 32 D new 32
""" """
)
sz_alias = str(m.AliasedHasOpNewDelSize.size_alias) sz_alias = str(m.AliasedHasOpNewDelSize.size_alias)
sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias) sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias)
with capture: with capture:
c = m.AliasedHasOpNewDelSize() c = m.AliasedHasOpNewDelSize()
c2 = SubAliased() c2 = SubAliased()
assert capture == ( assert capture == ("C new " + sz_noalias + "\n" + "C new " + sz_alias + "\n")
"C new " + sz_noalias + "\n" +
"C new " + sz_alias + "\n"
)
with capture: with capture:
del a del a
@ -251,21 +284,21 @@ def test_operator_new_delete(capture):
pytest.gc_collect() pytest.gc_collect()
del d del d
pytest.gc_collect() pytest.gc_collect()
assert capture == """ assert (
capture
== """
A delete A delete
B delete 4 B delete 4
D delete D delete
""" """
)
with capture: with capture:
del c del c
pytest.gc_collect() pytest.gc_collect()
del c2 del c2
pytest.gc_collect() pytest.gc_collect()
assert capture == ( assert capture == ("C delete " + sz_noalias + "\n" + "C delete " + sz_alias + "\n")
"C delete " + sz_noalias + "\n" +
"C delete " + sz_alias + "\n"
)
def test_bind_protected_functions(): 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) # ensure that there is no runaway reentrant implicit conversion (#1035)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.BogusImplicitConversion(0) m.BogusImplicitConversion(0)
assert msg(excinfo.value) == ''' assert (
msg(excinfo.value)
== """
__init__(): incompatible constructor arguments. The following argument types are supported: __init__(): incompatible constructor arguments. The following argument types are supported:
1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion) 1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
Invoked with: 0 Invoked with: 0
''' """
)
def test_error_after_conversions(): def test_error_after_conversions():
with pytest.raises(TypeError) as exc_info: with pytest.raises(TypeError) as exc_info:
m.test_error_after_conversions("hello") m.test_error_after_conversions("hello")
assert str(exc_info.value).startswith( 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(): def test_aligned():
@ -350,8 +387,10 @@ def test_aligned():
@pytest.mark.xfail("env.PYPY") @pytest.mark.xfail("env.PYPY")
def test_final(): def test_final():
with pytest.raises(TypeError) as exc_info: with pytest.raises(TypeError) as exc_info:
class PyFinalChild(m.IsFinal): class PyFinalChild(m.IsFinal):
pass pass
assert str(exc_info.value).endswith("is not an acceptable base type") assert str(exc_info.value).endswith("is not an acceptable base type")
@ -359,8 +398,10 @@ def test_final():
@pytest.mark.xfail("env.PYPY") @pytest.mark.xfail("env.PYPY")
def test_non_final_final(): def test_non_final_final():
with pytest.raises(TypeError) as exc_info: with pytest.raises(TypeError) as exc_info:
class PyNonFinalFinalChild(m.IsNonFinalFinal): class PyNonFinalFinalChild(m.IsNonFinalFinal):
pass pass
assert str(exc_info.value).endswith("is not an acceptable base type") 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") @pytest.mark.skip("See https://github.com/pybind/pybind11/pull/2564")
def test_register_duplicate_class(): def test_register_duplicate_class():
import types import types
module_scope = types.ModuleType("module_scope") module_scope = types.ModuleType("module_scope")
with pytest.raises(RuntimeError) as exc_info: with pytest.raises(RuntimeError) as exc_info:
m.register_duplicate_class_name(module_scope) m.register_duplicate_class_name(module_scope)
expected = ('generic_type: cannot initialize type "Duplicate": ' expected = (
'an object with that name is already defined') 'generic_type: cannot initialize type "Duplicate": '
"an object with that name is already defined"
)
assert str(exc_info.value) == expected assert str(exc_info.value) == expected
with pytest.raises(RuntimeError) as exc_info: with pytest.raises(RuntimeError) as exc_info:
m.register_duplicate_class_type(module_scope) m.register_duplicate_class_type(module_scope)
@ -409,10 +453,13 @@ def test_register_duplicate_class():
class ClassScope: class ClassScope:
pass pass
with pytest.raises(RuntimeError) as exc_info: with pytest.raises(RuntimeError) as exc_info:
m.register_duplicate_nested_class_name(ClassScope) m.register_duplicate_nested_class_name(ClassScope)
expected = ('generic_type: cannot initialize type "DuplicateNested": ' expected = (
'an object with that name is already defined') 'generic_type: cannot initialize type "DuplicateNested": '
"an object with that name is already defined"
)
assert str(exc_info.value) == expected assert str(exc_info.value) == expected
with pytest.raises(RuntimeError) as exc_info: with pytest.raises(RuntimeError) as exc_info:
m.register_duplicate_nested_class_type(ClassScope) m.register_duplicate_nested_class_type(ClassScope)

View File

@ -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.""" """Cast some values in C++ via custom type casters and count the number of moves/copies."""
cstats = m.move_and_copy_cstats() 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 # 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 # 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.""" moves/copies."""
cstats = m.move_and_copy_cstats() 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_only(10) == 10 # 1 move, c_m
assert m.move_or_copy(11) == 11 # 1 move, c_mc 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 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(): def test_move_and_copy_load_optional():
"""Tests move/copy loads of std::optional arguments""" """Tests move/copy loads of std::optional arguments"""
cstats = m.move_and_copy_cstats() 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 # The extra move/copy constructions below come from the std::optional move (which has to move
# its arguments): # its arguments):

View File

@ -5,65 +5,91 @@ from pybind11_tests import custom_type_casters as m
def test_noconvert_args(msg): def test_noconvert_args(msg):
a = m.ArgInspector() a = m.ArgInspector()
assert msg(a.f("hi")) == """ assert (
msg(a.f("hi"))
== """
loading ArgInspector1 argument WITH conversion allowed. Argument value = 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 WITHOUT conversion allowed. Argument value = this is a
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
13 13
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
""" # noqa: E501 line too long """ # 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 WITHOUT conversion allowed. Argument value = this is a
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
42 42
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
""" # noqa: E501 line too long """ # 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 WITHOUT conversion allowed. Argument value = this is a
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
42 42
loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d 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 (
assert msg(m.arg_inspect_func("A1", "A2")) == """ 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 ArgInspector2 argument WITH conversion allowed. Argument value = A1
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2 loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
""" """
)
assert m.floats_preferred(4) == 2.0 assert m.floats_preferred(4) == 2.0
assert m.floats_only(4.0) == 2.0 assert m.floats_only(4.0) == 2.0
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.floats_only(4) m.floats_only(4)
assert msg(excinfo.value) == """ assert (
msg(excinfo.value)
== """
floats_only(): incompatible function arguments. The following argument types are supported: floats_only(): incompatible function arguments. The following argument types are supported:
1. (f: float) -> float 1. (f: float) -> float
Invoked with: 4 Invoked with: 4
""" """
)
assert m.ints_preferred(4) == 2 assert m.ints_preferred(4) == 2
assert m.ints_preferred(True) == 0 assert m.ints_preferred(True) == 0
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.ints_preferred(4.0) m.ints_preferred(4.0)
assert msg(excinfo.value) == """ assert (
msg(excinfo.value)
== """
ints_preferred(): incompatible function arguments. The following argument types are supported: ints_preferred(): incompatible function arguments. The following argument types are supported:
1. (i: int) -> int 1. (i: int) -> int
Invoked with: 4.0 Invoked with: 4.0
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
assert m.ints_only(4) == 2 assert m.ints_only(4) == 2
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.ints_only(4.0) m.ints_only(4.0)
assert msg(excinfo.value) == """ assert (
msg(excinfo.value)
== """
ints_only(): incompatible function arguments. The following argument types are supported: ints_only(): incompatible function arguments. The following argument types are supported:
1. (i: int) -> int 1. (i: int) -> int
Invoked with: 4.0 Invoked with: 4.0
""" """
)
def test_custom_caster_destruction(): def test_custom_caster_destruction():

View File

@ -18,10 +18,10 @@ def test_docstring_options():
assert m.test_overloaded3.__doc__ == "Overload docstr" assert m.test_overloaded3.__doc__ == "Overload docstr"
# options.enable_function_signatures() # 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__.startswith("test_function4(a: int, b: int) -> None")
assert m.test_function4.__doc__ .endswith("A custom docstring\n") assert m.test_function4.__doc__.endswith("A custom docstring\n")
# options.disable_function_signatures() # options.disable_function_signatures()
# options.disable_user_defined_docstrings() # options.disable_user_defined_docstrings()
@ -31,8 +31,8 @@ def test_docstring_options():
assert m.test_function6.__doc__ == "A custom docstring" assert m.test_function6.__doc__ == "A custom docstring"
# RAII destructor # RAII destructor
assert m.test_function7.__doc__ .startswith("test_function7(a: int, b: int) -> None") 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__.endswith("A custom docstring\n")
# Suppression of user-defined docstrings for non-function objects # Suppression of user-defined docstrings for non-function objects
assert not m.DocstringTestFoo.__doc__ assert not m.DocstringTestFoo.__doc__

View File

@ -6,11 +6,15 @@ np = pytest.importorskip("numpy")
m = pytest.importorskip("pybind11_tests.eigen") m = pytest.importorskip("pybind11_tests.eigen")
ref = np.array([[ 0., 3, 0, 0, 0, 11], ref = np.array(
[22, 0, 0, 0, 17, 11], [
[ 7, 5, 0, 1, 0, 11], [0.0, 3, 0, 0, 0, 11],
[ 0, 0, 0, 0, 0, 11], [22, 0, 0, 0, 17, 11],
[ 0, 0, 14, 0, 8, 11]]) [7, 5, 0, 1, 0, 11],
[0, 0, 0, 0, 0, 11],
[0, 0, 14, 0, 8, 11],
]
)
def assert_equal_ref(mat): def assert_equal_ref(mat):
@ -40,28 +44,37 @@ def test_dense():
def test_partially_fixed(): 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_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_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_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_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( 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_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_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_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_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( 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 # TypeError should be raise for a shape mismatch
functions = [m.partial_copy_four_rm_r, m.partial_copy_four_rm_c, functions = [
m.partial_copy_four_cm_r, m.partial_copy_four_cm_c] m.partial_copy_four_rm_r,
matrix_with_wrong_shape = [[1, 2], m.partial_copy_four_rm_c,
[3, 4]] m.partial_copy_four_cm_r,
m.partial_copy_four_cm_c,
]
matrix_with_wrong_shape = [[1, 2], [3, 4]]
for f in functions: for f in functions:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
f(matrix_with_wrong_shape) f(matrix_with_wrong_shape)
@ -69,7 +82,7 @@ def test_partially_fixed():
def test_mutator_descriptors(): 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 zc = zr.reshape(6, 5).transpose() # column-major
m.fixed_mutator_r(zr) m.fixed_mutator_r(zr)
@ -78,18 +91,21 @@ def test_mutator_descriptors():
m.fixed_mutator_a(zc) m.fixed_mutator_a(zc)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.fixed_mutator_r(zc) m.fixed_mutator_r(zc)
assert ('(arg0: numpy.ndarray[numpy.float32[5, 6],' assert (
' flags.writeable, flags.c_contiguous]) -> None' "(arg0: numpy.ndarray[numpy.float32[5, 6],"
in str(excinfo.value)) " flags.writeable, flags.c_contiguous]) -> None" in str(excinfo.value)
)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.fixed_mutator_c(zr) m.fixed_mutator_c(zr)
assert ('(arg0: numpy.ndarray[numpy.float32[5, 6],' assert (
' flags.writeable, flags.f_contiguous]) -> None' "(arg0: numpy.ndarray[numpy.float32[5, 6],"
in str(excinfo.value)) " flags.writeable, flags.f_contiguous]) -> None" in str(excinfo.value)
)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype='float32')) m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype="float32"))
assert ('(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None' assert "(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None" in str(
in str(excinfo.value)) excinfo.value
)
zr.flags.writeable = False zr.flags.writeable = False
with pytest.raises(TypeError): with pytest.raises(TypeError):
m.fixed_mutator_r(zr) m.fixed_mutator_r(zr)
@ -98,26 +114,26 @@ def test_mutator_descriptors():
def test_cpp_casting(): def test_cpp_casting():
assert m.cpp_copy(m.fixed_r()) == 22. assert m.cpp_copy(m.fixed_r()) == 22.0
assert m.cpp_copy(m.fixed_c()) == 22. assert m.cpp_copy(m.fixed_c()) == 22.0
z = np.array([[5., 6], [7, 8]]) z = np.array([[5.0, 6], [7, 8]])
assert m.cpp_copy(z) == 7. assert m.cpp_copy(z) == 7.0
assert m.cpp_copy(m.get_cm_ref()) == 21. assert m.cpp_copy(m.get_cm_ref()) == 21.0
assert m.cpp_copy(m.get_rm_ref()) == 21. assert m.cpp_copy(m.get_rm_ref()) == 21.0
assert m.cpp_ref_c(m.get_cm_ref()) == 21. assert m.cpp_ref_c(m.get_cm_ref()) == 21.0
assert m.cpp_ref_r(m.get_rm_ref()) == 21. assert m.cpp_ref_r(m.get_rm_ref()) == 21.0
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
# Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles # Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles
m.cpp_ref_any(m.fixed_c()) 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: with pytest.raises(RuntimeError) as excinfo:
# Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles # Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles
m.cpp_ref_any(m.fixed_r()) m.cpp_ref_any(m.fixed_r())
assert 'Unable to cast Python instance' in str(excinfo.value) assert "Unable to cast Python instance" in str(excinfo.value)
assert m.cpp_ref_any(m.ReturnTester.create()) == 1. 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.0
assert m.cpp_ref_any(m.get_cm_ref()) == 21. assert m.cpp_ref_any(m.get_cm_ref()) == 21.0
def test_pass_readonly_array(): def test_pass_readonly_array():
@ -149,7 +165,7 @@ def test_nonunit_stride_from_python():
# Mutator: # Mutator:
m.double_threer(second_row) m.double_threer(second_row)
m.double_threec(second_col) 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): def test_negative_stride_from_python(msg):
@ -178,26 +194,36 @@ def test_negative_stride_from_python(msg):
# Mutator: # Mutator:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.double_threer(second_row) m.double_threer(second_row)
assert msg(excinfo.value) == """ assert (
msg(excinfo.value)
== """
double_threer(): incompatible function arguments. The following argument types are supported: double_threer(): incompatible function arguments. The following argument types are supported:
1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None 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: with pytest.raises(TypeError) as excinfo:
m.double_threec(second_col) m.double_threec(second_col)
assert msg(excinfo.value) == """ assert (
msg(excinfo.value)
== """
double_threec(): incompatible function arguments. The following argument types are supported: double_threec(): incompatible function arguments. The following argument types are supported:
1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None 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(): def test_nonunit_stride_to_python():
assert np.all(m.diagonal(ref) == ref.diagonal()) assert np.all(m.diagonal(ref) == ref.diagonal())
assert np.all(m.diagonal_1(ref) == ref.diagonal(1)) assert np.all(m.diagonal_1(ref) == ref.diagonal(1))
for i in range(-5, 7): 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, 2, 1, 3, 3) == ref[2:5, 1:4])
assert np.all(m.block(ref, 1, 4, 4, 2) == ref[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(): def test_eigen_ref_to_python():
chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4] chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4]
for i, chol in enumerate(chols, start=1): for i, chol in enumerate(chols, start=1):
mymat = chol(np.array([[1., 2, 4], [2, 13, 23], [4, 23, 77]])) 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) 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): 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_block1, master[3:5, 3:5])
np.testing.assert_array_equal(a_block2, master[2:5, 2:4]) 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_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(
np.testing.assert_array_equal(a_corn2, master[0::master.shape[0] - 1, 0::master.shape[1] - 1]) 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_copy1, c1want)
np.testing.assert_array_equal(a_copy2, c2want) np.testing.assert_array_equal(a_copy2, c2want)
@ -355,16 +387,28 @@ def test_eigen_keepalive():
cstats = ConstructorStats.get(m.ReturnTester) cstats = ConstructorStats.get(m.ReturnTester)
assert cstats.alive() == 1 assert cstats.alive() == 1
unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)] 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(), copies = [
a.copy_block(4, 3, 2, 1)] a.copy_get(),
a.copy_view(),
a.copy_ref(),
a.copy_ref_const(),
a.copy_block(4, 3, 2, 1),
]
del a del a
assert cstats.alive() == 0 assert cstats.alive() == 0
del unsafe del unsafe
del copies del copies
for meth in [m.ReturnTester.get, m.ReturnTester.get_ptr, m.ReturnTester.view, for meth in [
m.ReturnTester.view_ptr, m.ReturnTester.ref_safe, m.ReturnTester.ref_const_safe, m.ReturnTester.get,
m.ReturnTester.corners, m.ReturnTester.corners_const]: 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) assert_keeps_alive(m.ReturnTester, meth)
for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]: for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]:
@ -374,18 +418,18 @@ def test_eigen_keepalive():
def test_eigen_ref_mutators(): def test_eigen_ref_mutators():
"""Tests Eigen's ability to mutate numpy values""" """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) zr = np.array(orig)
zc = np.array(orig, order='F') zc = np.array(orig, order="F")
m.add_rm(zr, 1, 0, 100) 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) 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) 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) 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: # Can't reference a col-major array with a row-major Ref, and vice versa:
with pytest.raises(TypeError): with pytest.raises(TypeError):
@ -406,8 +450,8 @@ def test_eigen_ref_mutators():
cornersr = zr[0::2, 0::2] cornersr = zr[0::2, 0::2]
cornersc = zc[0::2, 0::2] cornersc = zc[0::2, 0::2]
assert np.all(cornersr == np.array([[1., 3], [7, 9]])) assert np.all(cornersr == np.array([[1.0, 3], [7, 9]]))
assert np.all(cornersc == np.array([[1., 3], [7, 9]])) assert np.all(cornersc == np.array([[1.0, 3], [7, 9]]))
with pytest.raises(TypeError): with pytest.raises(TypeError):
m.add_rm(cornersr, 0, 1, 25) 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_cm(cornersc, 0, 1, 25)
m.add_any(cornersr, 0, 1, 25) m.add_any(cornersr, 0, 1, 25)
m.add_any(cornersc, 0, 1, 44) 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(zr == np.array([[1.0, 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(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: # You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method:
zro = zr[0:4, 0:4] 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 assert not zrro.flags.owndata and not zrro.flags.writeable
zc[1, 2] = 99 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 # We should have just changed zc, of course, but also zcro and the original eigen matrix
assert np.all(zc == expect) assert np.all(zc == expect)
assert np.all(zcro == expect) assert np.all(zcro == expect)
@ -506,18 +550,20 @@ def test_both_ref_mutators():
assert np.all(z == z3) assert np.all(z == z3)
assert np.all(z == z4) assert np.all(z == z4)
assert np.all(z == z5) 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) 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 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) y4 = m.even_rows(y3) # numpy -> eigen slice -> (... y3)
y5 = m.even_cols(y4) # numpy -> eigen slice -> (... y4) y5 = m.even_cols(y4) # numpy -> eigen slice -> (... y4)
y6 = m.incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5) y6 = m.incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5)
# Apply same mutations using just numpy: # 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 += 10
yexpect[0::2, 0::2] -= 33 yexpect[0::2, 0::2] -= 33
yexpect[0::4, 0::4] += 1000 yexpect[0::4, 0::4] += 1000
@ -532,10 +578,14 @@ def test_both_ref_mutators():
def test_nocopy_wrapper(): def test_nocopy_wrapper():
# get_elem requires a column-contiguous matrix reference, but should be # get_elem requires a column-contiguous matrix reference, but should be
# callable with other types of matrix (via copying): # callable with other types of matrix (via copying):
int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order='F') 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) dbl_matrix_colmajor = np.array(
int_matrix_rowmajor = np.array(int_matrix_colmajor, order='C', copy=True) int_matrix_colmajor, dtype="double", order="F", copy=True
dbl_matrix_rowmajor = np.array(int_matrix_rowmajor, dtype='double', order='C', 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: # All should be callable via get_elem:
assert m.get_elem(int_matrix_colmajor) == 8 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: # All but the second should fail with m.get_elem_nocopy:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_nocopy(int_matrix_colmajor) m.get_elem_nocopy(int_matrix_colmajor)
assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and assert "get_elem_nocopy(): incompatible function arguments." in str(
', flags.f_contiguous' in str(excinfo.value)) excinfo.value
) and ", flags.f_contiguous" in str(excinfo.value)
assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8 assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_nocopy(int_matrix_rowmajor) m.get_elem_nocopy(int_matrix_rowmajor)
assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and assert "get_elem_nocopy(): incompatible function arguments." in str(
', flags.f_contiguous' in str(excinfo.value)) excinfo.value
) and ", flags.f_contiguous" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_nocopy(dbl_matrix_rowmajor) m.get_elem_nocopy(dbl_matrix_rowmajor)
assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and assert "get_elem_nocopy(): incompatible function arguments." in str(
', flags.f_contiguous' in str(excinfo.value)) 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: # 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: with pytest.raises(TypeError) as excinfo:
m.get_elem_rm_nocopy(int_matrix_colmajor) m.get_elem_rm_nocopy(int_matrix_colmajor)
assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
', flags.c_contiguous' in str(excinfo.value)) excinfo.value
) and ", flags.c_contiguous" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_rm_nocopy(dbl_matrix_colmajor) m.get_elem_rm_nocopy(dbl_matrix_colmajor)
assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
', flags.c_contiguous' in str(excinfo.value)) excinfo.value
) and ", flags.c_contiguous" in str(excinfo.value)
assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8 assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_rm_nocopy(dbl_matrix_rowmajor) m.get_elem_rm_nocopy(dbl_matrix_rowmajor)
assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
', flags.c_contiguous' in str(excinfo.value)) excinfo.value
) and ", flags.c_contiguous" in str(excinfo.value)
def test_eigen_ref_life_support(): def test_eigen_ref_life_support():
@ -589,12 +645,9 @@ def test_eigen_ref_life_support():
def test_special_matrix_objects(): 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], asymm = np.array([[1.0, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16]])
symm_lower = np.array(asymm) symm_lower = np.array(asymm)
symm_upper = np.array(asymm) symm_upper = np.array(asymm)
for i in range(4): for i in range(4):
@ -607,41 +660,51 @@ def test_special_matrix_objects():
def test_dense_signature(doc): 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]] 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]] 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]])""" double_complex(arg0: numpy.ndarray[numpy.complex64[m, 1]])"""
""" -> numpy.ndarray[numpy.complex64[m, 1]] """ -> numpy.ndarray[numpy.complex64[m, 1]]
""") """
assert doc(m.double_mat_rm) == (""" )
assert doc(m.double_mat_rm) == (
"""
double_mat_rm(arg0: numpy.ndarray[numpy.float32[m, n]])""" 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(): def test_named_arguments():
a = np.array([[1.0, 2], [3, 4], [5, 6]]) a = np.array([[1.0, 2], [3, 4], [5, 6]])
b = np.ones((2, 1)) 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, b) == np.array([[3.0], [7], [11]]))
assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.], [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.], [7], [11]])) assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.0], [7], [11]]))
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
m.matrix_multiply(b, a) m.matrix_multiply(b, a)
assert str(excinfo.value) == 'Nonconformable matrices!' assert str(excinfo.value) == "Nonconformable matrices!"
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
m.matrix_multiply(A=b, B=a) 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: with pytest.raises(ValueError) as excinfo:
m.matrix_multiply(B=a, A=b) m.matrix_multiply(B=a, A=b)
assert str(excinfo.value) == 'Nonconformable matrices!' assert str(excinfo.value) == "Nonconformable matrices!"
def test_sparse(): def test_sparse():
@ -656,21 +719,31 @@ def test_sparse():
def test_sparse_signature(doc): def test_sparse_signature(doc):
pytest.importorskip("scipy") 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] sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32]
""" # noqa: E501 line too long """ # 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] sparse_copy_c(arg0: scipy.sparse.csc_matrix[numpy.float32]) -> scipy.sparse.csc_matrix[numpy.float32]
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
def test_issue738(): def test_issue738():
"""Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)""" """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.0, 2, 3]])) == np.array([[1.0, 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], [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.0, 2, 3]])) == np.array([[1.0, 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], [12], [23]])
)
def test_issue1105(): def test_issue1105():

View File

@ -24,18 +24,24 @@ def test_unscoped_enum():
assert m.UnscopedEnum.EOne.name == "EOne" assert m.UnscopedEnum.EOne.name == "EOne"
# __members__ property # __members__ property
assert m.UnscopedEnum.__members__ == \ assert m.UnscopedEnum.__members__ == {
{"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree} "EOne": m.UnscopedEnum.EOne,
"ETwo": m.UnscopedEnum.ETwo,
"EThree": m.UnscopedEnum.EThree,
}
# __members__ readonly # __members__ readonly
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
m.UnscopedEnum.__members__ = {} m.UnscopedEnum.__members__ = {}
# __members__ returns a copy # __members__ returns a copy
foo = m.UnscopedEnum.__members__ foo = m.UnscopedEnum.__members__
foo["bar"] = "baz" foo["bar"] = "baz"
assert m.UnscopedEnum.__members__ == \ assert m.UnscopedEnum.__members__ == {
{"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree} "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: Members:
@ -43,7 +49,9 @@ Members:
ETwo : Docstring for ETwo ETwo : Docstring for ETwo
EThree : Docstring for EThree'''.split('\n'): EThree : Docstring for EThree""".split(
"\n"
):
assert docstring_line in m.UnscopedEnum.__doc__ assert docstring_line in m.UnscopedEnum.__doc__
# Unscoped enums will accept ==/!= int comparisons # Unscoped enums will accept ==/!= int comparisons
@ -53,10 +61,10 @@ Members:
assert y != 3 assert y != 3
assert 3 != y assert 3 != y
# Compare with None # Compare with None
assert (y != None) # noqa: E711 assert y != None # noqa: E711
assert not (y == None) # noqa: E711 assert not (y == None) # noqa: E711
# Compare with an object # Compare with an object
assert (y != object()) assert y != object()
assert not (y == object()) assert not (y == object())
# Compare with string # Compare with string
assert y != "2" assert y != "2"
@ -119,10 +127,10 @@ def test_scoped_enum():
assert z != 3 assert z != 3
assert 3 != z assert 3 != z
# Compare with None # Compare with None
assert (z != None) # noqa: E711 assert z != None # noqa: E711
assert not (z == None) # noqa: E711 assert not (z == None) # noqa: E711
# Compare with an object # Compare with an object
assert (z != object()) assert z != object()
assert not (z == object()) assert not (z == object())
# Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions) # Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions)
with pytest.raises(TypeError): with pytest.raises(TypeError):

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is called from 'test_eval.py' # 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 call_test2(y) # noqa: F821 undefined name

View File

@ -54,27 +54,27 @@ def test_python_alreadyset_in_destructor(monkeypatch, capsys):
hooked = False hooked = False
triggered = [False] # mutable, so Python 2.7 closure can modify it 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 hooked = True
default_hook = sys.unraisablehook default_hook = sys.unraisablehook
def hook(unraisable_hook_args): def hook(unraisable_hook_args):
exc_type, exc_value, exc_tb, err_msg, obj = 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 triggered[0] = True
default_hook(unraisable_hook_args) default_hook(unraisable_hook_args)
return return
# Use monkeypatch so pytest can apply and remove the patch as appropriate # 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: if hooked:
assert triggered[0] is True assert triggered[0] is True
_, captured_stderr = capsys.readouterr() _, captured_stderr = capsys.readouterr()
# Error message is different in Python 2 and 3, check for words that appear in both # 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(): def test_exception_matches():
@ -107,7 +107,9 @@ def test_custom(msg):
# Can we fall-through to the default handler? # Can we fall-through to the default handler?
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.throws_logic_error() 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. # OverFlow error translation.
with pytest.raises(OverflowError) as excinfo: with pytest.raises(OverflowError) as excinfo:
@ -166,7 +168,13 @@ def test_nested_throws(capture):
# C++ -> Python -> C++ -> Python # C++ -> Python -> C++ -> Python
with capture: with capture:
m.try_catch( 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") assert str(capture).startswith("MyException5: nested error 5")
# C++ -> Python -> C++ # 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 # This can often happen if you wrap a pybind11 class in a Python wrapper
def test_invalid_repr(): def test_invalid_repr():
class MyRepr(object): class MyRepr(object):
def __repr__(self): def __repr__(self):
raise AttributeError("Example error") raise AttributeError("Example error")

View File

@ -12,7 +12,10 @@ from pybind11_tests import ConstructorStats
def test_init_factory_basic(): def test_init_factory_basic():
"""Tests py::init_factory() wrapper around various ways of returning the object""" """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 cstats[0].alive() # force gc
n_inst = ConstructorStats.detail_reg_inst() n_inst = ConstructorStats.detail_reg_inst()
@ -41,12 +44,12 @@ def test_init_factory_basic():
z3 = m.TestFactory3("bye") z3 = m.TestFactory3("bye")
assert z3.value == "bye" assert z3.value == "bye"
for null_ptr_kind in [tag.null_ptr, for null_ptr_kind in [tag.null_ptr, tag.null_unique_ptr, tag.null_shared_ptr]:
tag.null_unique_ptr,
tag.null_shared_ptr]:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.TestFactory3(null_ptr_kind) 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 [i.alive() for i in cstats] == [3, 3, 3]
assert ConstructorStats.detail_reg_inst() == n_inst + 9 assert ConstructorStats.detail_reg_inst() == n_inst + 9
@ -61,7 +64,7 @@ def test_init_factory_basic():
assert [i.values() for i in cstats] == [ assert [i.values() for i in cstats] == [
["3", "hi!"], ["3", "hi!"],
["7", "hi again"], ["7", "hi again"],
["42", "bye"] ["42", "bye"],
] ]
assert [i.default_constructions for i in cstats] == [1, 1, 1] 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): def test_init_factory_signature(msg):
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.TestFactory1("invalid", "constructor", "arguments") m.TestFactory1("invalid", "constructor", "arguments")
assert msg(excinfo.value) == """ assert (
msg(excinfo.value)
== """
__init__(): incompatible constructor arguments. The following argument types are supported: __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) 1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int)
2. m.factory_constructors.TestFactory1(arg0: str) 2. m.factory_constructors.TestFactory1(arg0: str)
@ -78,8 +83,11 @@ def test_init_factory_signature(msg):
Invoked with: 'invalid', 'constructor', 'arguments' Invoked with: 'invalid', 'constructor', 'arguments'
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
assert msg(m.TestFactory1.__init__.__doc__) == """ assert (
msg(m.TestFactory1.__init__.__doc__)
== """
__init__(*args, **kwargs) __init__(*args, **kwargs)
Overloaded function. 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 4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
def test_init_factory_casting(): def test_init_factory_casting():
"""Tests py::init_factory() wrapper with various upcasting and downcasting returns""" """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 cstats[0].alive() # force gc
n_inst = ConstructorStats.detail_reg_inst() n_inst = ConstructorStats.detail_reg_inst()
@ -134,7 +146,7 @@ def test_init_factory_casting():
assert [i.values() for i in cstats] == [ assert [i.values() for i in cstats] == [
["4", "5", "6", "7", "8"], ["4", "5", "6", "7", "8"],
["4", "5", "8"], ["4", "5", "8"],
["6", "7"] ["6", "7"],
] ]
@ -204,7 +216,7 @@ def test_init_factory_alias():
assert [i.values() for i in cstats] == [ assert [i.values() for i in cstats] == [
["1", "8", "3", "4", "5", "6", "123", "10", "47"], ["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() assert not g1.has_alias()
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
PythFactory7(tag.shared_ptr, tag.invalid_base, 14) PythFactory7(tag.shared_ptr, tag.invalid_base, 14)
assert (str(excinfo.value) == assert (
"pybind11::init(): construction failed: returned holder-wrapped instance is not an " str(excinfo.value)
"alias instance") == "pybind11::init(): construction failed: returned holder-wrapped instance is not an "
"alias instance"
)
assert [i.alive() for i in cstats] == [13, 7] assert [i.alive() for i in cstats] == [13, 7]
assert ConstructorStats.detail_reg_inst() == n_inst + 13 assert ConstructorStats.detail_reg_inst() == n_inst + 13
@ -284,7 +298,7 @@ def test_init_factory_dual():
assert [i.values() for i in cstats] == [ assert [i.values() for i in cstats] == [
["1", "2", "3", "4", "5", "6", "7", "8", "9", "100", "11", "12", "13", "14"], ["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: with capture:
a = m.NoPlacementNew(123) 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 found
assert a.i == 123 assert a.i == 123
with capture: with capture:
@ -305,7 +319,7 @@ def test_no_placement_new(capture):
with capture: with capture:
b = m.NoPlacementNew() 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 found
assert b.i == 100 assert b.i == 100
with capture: with capture:
@ -333,7 +347,7 @@ def create_and_destroy(*args):
def strip_comments(s): def strip_comments(s):
return re.sub(r'\s+#.*', '', s) return re.sub(r"\s+#.*", "", s)
def test_reallocation_a(capture, msg): def test_reallocation_a(capture, msg):
@ -345,7 +359,9 @@ def test_reallocation_a(capture, msg):
with capture: with capture:
create_and_destroy(1) create_and_destroy(1)
assert msg(capture) == """ assert (
msg(capture)
== """
noisy new noisy new
noisy placement new noisy placement new
NoisyAlloc(int 1) NoisyAlloc(int 1)
@ -353,12 +369,14 @@ def test_reallocation_a(capture, msg):
~NoisyAlloc() ~NoisyAlloc()
noisy delete noisy delete
""" """
)
def test_reallocation_b(capture, msg): def test_reallocation_b(capture, msg):
with capture: with capture:
create_and_destroy(1.5) create_and_destroy(1.5)
assert msg(capture) == strip_comments(""" assert msg(capture) == strip_comments(
"""
noisy new # allocation required to attempt first overload noisy new # allocation required to attempt first overload
noisy delete # have to dealloc before considering factory init overload noisy delete # have to dealloc before considering factory init overload
noisy new # pointer factory calling "new", part 1: allocation noisy new # pointer factory calling "new", part 1: allocation
@ -366,51 +384,59 @@ def test_reallocation_b(capture, msg):
--- ---
~NoisyAlloc() # Destructor ~NoisyAlloc() # Destructor
noisy delete # operator delete noisy delete # operator delete
""") """
)
def test_reallocation_c(capture, msg): def test_reallocation_c(capture, msg):
with capture: with capture:
create_and_destroy(2, 3) create_and_destroy(2, 3)
assert msg(capture) == strip_comments(""" assert msg(capture) == strip_comments(
"""
noisy new # pointer factory calling "new", allocation noisy new # pointer factory calling "new", allocation
NoisyAlloc(int 2) # constructor NoisyAlloc(int 2) # constructor
--- ---
~NoisyAlloc() # Destructor ~NoisyAlloc() # Destructor
noisy delete # operator delete noisy delete # operator delete
""") """
)
def test_reallocation_d(capture, msg): def test_reallocation_d(capture, msg):
with capture: with capture:
create_and_destroy(2.5, 3) 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) NoisyAlloc(double 2.5) # construction (local func variable: operator_new not called)
noisy new # return-by-value "new" part 1: allocation noisy new # return-by-value "new" part 1: allocation
~NoisyAlloc() # moved-away local func variable destruction ~NoisyAlloc() # moved-away local func variable destruction
--- ---
~NoisyAlloc() # Destructor ~NoisyAlloc() # Destructor
noisy delete # operator delete noisy delete # operator delete
""") """
)
def test_reallocation_e(capture, msg): def test_reallocation_e(capture, msg):
with capture: with capture:
create_and_destroy(3.5, 4.5) 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 new # preallocation needed before invoking placement-new overload
noisy placement new # Placement new noisy placement new # Placement new
NoisyAlloc(double 3.5) # construction NoisyAlloc(double 3.5) # construction
--- ---
~NoisyAlloc() # Destructor ~NoisyAlloc() # Destructor
noisy delete # operator delete noisy delete # operator delete
""") """
)
def test_reallocation_f(capture, msg): def test_reallocation_f(capture, msg):
with capture: with capture:
create_and_destroy(4, 0.5) 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 new # preallocation needed before invoking placement-new overload
noisy delete # deallocation of preallocated storage noisy delete # deallocation of preallocated storage
noisy new # Factory pointer allocation noisy new # Factory pointer allocation
@ -418,13 +444,15 @@ def test_reallocation_f(capture, msg):
--- ---
~NoisyAlloc() # Destructor ~NoisyAlloc() # Destructor
noisy delete # operator delete noisy delete # operator delete
""") """
)
def test_reallocation_g(capture, msg): def test_reallocation_g(capture, msg):
with capture: with capture:
create_and_destroy(5, "hi") 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 new # preallocation needed before invoking first placement new
noisy delete # delete before considering new-style constructor noisy delete # delete before considering new-style constructor
noisy new # preallocation for second placement new noisy new # preallocation for second placement new
@ -433,13 +461,15 @@ def test_reallocation_g(capture, msg):
--- ---
~NoisyAlloc() # Destructor ~NoisyAlloc() # Destructor
noisy delete # operator delete noisy delete # operator delete
""") """
)
@pytest.mark.skipif("env.PY2") @pytest.mark.skipif("env.PY2")
def test_invalid_self(): def test_invalid_self():
"""Tests invocation of the pybind-registered base class with an invalid `self` argument. You """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.""" can only actually do this on Python 3: Python 2 raises an exception itself if you try."""
class NotPybindDerived(object): class NotPybindDerived(object):
pass pass
@ -463,16 +493,26 @@ def test_invalid_self():
a = m.TestFactory2(tag.pointer, 1) a = m.TestFactory2(tag.pointer, 1)
m.TestFactory6.__init__(a, tag.alias, 1) m.TestFactory6.__init__(a, tag.alias, 1)
elif bad == 3: elif bad == 3:
m.TestFactory6.__init__(NotPybindDerived.__new__(NotPybindDerived), tag.base, 1) m.TestFactory6.__init__(
NotPybindDerived.__new__(NotPybindDerived), tag.base, 1
)
elif bad == 4: 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): for arg in (1, 2):
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
BrokenTF1(arg) 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): for arg in (1, 2, 3, 4):
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
BrokenTF6(arg) BrokenTF6(arg)
assert str(excinfo.value) == "__init__(self, ...) called with invalid `self` argument" assert (
str(excinfo.value)
== "__init__(self, ...) called with invalid `self` argument"
)

View File

@ -21,6 +21,7 @@ def _run_in_process(target, *args, **kwargs):
def _python_to_cpp_to_python(): def _python_to_cpp_to_python():
"""Calls different C++ functions that come back to Python.""" """Calls different C++ functions that come back to Python."""
class ExtendedVirtClass(m.VirtClass): class ExtendedVirtClass(m.VirtClass):
def virtual_func(self): def virtual_func(self):
pass 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. 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 # TODO: FIXME on macOS Python 3.9

View File

@ -18,6 +18,7 @@ try:
# Python 3.4 # Python 3.4
from contextlib import redirect_stdout from contextlib import redirect_stdout
except ImportError: except ImportError:
@contextmanager @contextmanager
def redirect_stdout(target): def redirect_stdout(target):
original = sys.stdout original = sys.stdout
@ -25,10 +26,12 @@ except ImportError:
yield yield
sys.stdout = original sys.stdout = original
try: try:
# Python 3.5 # Python 3.5
from contextlib import redirect_stderr from contextlib import redirect_stderr
except ImportError: except ImportError:
@contextmanager @contextmanager
def redirect_stderr(target): def redirect_stderr(target):
original = sys.stderr original = sys.stderr
@ -42,16 +45,16 @@ def test_captured(capsys):
m.captured_output(msg) m.captured_output(msg)
stdout, stderr = capsys.readouterr() stdout, stderr = capsys.readouterr()
assert stdout == msg assert stdout == msg
assert stderr == '' assert stderr == ""
m.captured_output_default(msg) m.captured_output_default(msg)
stdout, stderr = capsys.readouterr() stdout, stderr = capsys.readouterr()
assert stdout == msg assert stdout == msg
assert stderr == '' assert stderr == ""
m.captured_err(msg) m.captured_err(msg)
stdout, stderr = capsys.readouterr() stdout, stderr = capsys.readouterr()
assert stdout == '' assert stdout == ""
assert stderr == msg assert stderr == msg
@ -63,7 +66,7 @@ def test_captured_large_string(capsys):
m.captured_output_default(msg) m.captured_output_default(msg)
stdout, stderr = capsys.readouterr() stdout, stderr = capsys.readouterr()
assert stdout == msg assert stdout == msg
assert stderr == '' assert stderr == ""
def test_guard_capture(capsys): def test_guard_capture(capsys):
@ -71,7 +74,7 @@ def test_guard_capture(capsys):
m.guard_output(msg) m.guard_output(msg)
stdout, stderr = capsys.readouterr() stdout, stderr = capsys.readouterr()
assert stdout == msg assert stdout == msg
assert stderr == '' assert stderr == ""
def test_series_captured(capture): def test_series_captured(capture):
@ -88,7 +91,7 @@ def test_flush(capfd):
with m.ostream_redirect(): with m.ostream_redirect():
m.noisy_function(msg, flush=False) m.noisy_function(msg, flush=False)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == '' assert stdout == ""
m.noisy_function(msg2, flush=True) m.noisy_function(msg2, flush=True)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
@ -107,15 +110,15 @@ def test_not_captured(capfd):
m.raw_output(msg) m.raw_output(msg)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == msg assert stdout == msg
assert stderr == '' assert stderr == ""
assert stream.getvalue() == '' assert stream.getvalue() == ""
stream = StringIO() stream = StringIO()
with redirect_stdout(stream): with redirect_stdout(stream):
m.captured_output(msg) m.captured_output(msg)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == '' assert stdout == ""
assert stderr == '' assert stderr == ""
assert stream.getvalue() == msg assert stream.getvalue() == msg
@ -125,16 +128,16 @@ def test_err(capfd):
with redirect_stderr(stream): with redirect_stderr(stream):
m.raw_err(msg) m.raw_err(msg)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == '' assert stdout == ""
assert stderr == msg assert stderr == msg
assert stream.getvalue() == '' assert stream.getvalue() == ""
stream = StringIO() stream = StringIO()
with redirect_stderr(stream): with redirect_stderr(stream):
m.captured_err(msg) m.captured_err(msg)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == '' assert stdout == ""
assert stderr == '' assert stderr == ""
assert stream.getvalue() == msg assert stream.getvalue() == msg
@ -146,8 +149,8 @@ def test_multi_captured(capfd):
m.captured_output("c") m.captured_output("c")
m.raw_output("d") m.raw_output("d")
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == 'bd' assert stdout == "bd"
assert stream.getvalue() == 'ac' assert stream.getvalue() == "ac"
def test_dual(capsys): def test_dual(capsys):
@ -164,14 +167,14 @@ def test_redirect(capfd):
m.raw_output(msg) m.raw_output(msg)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == msg assert stdout == msg
assert stream.getvalue() == '' assert stream.getvalue() == ""
stream = StringIO() stream = StringIO()
with redirect_stdout(stream): with redirect_stdout(stream):
with m.ostream_redirect(): with m.ostream_redirect():
m.raw_output(msg) m.raw_output(msg)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == '' assert stdout == ""
assert stream.getvalue() == msg assert stream.getvalue() == msg
stream = StringIO() stream = StringIO()
@ -179,7 +182,7 @@ def test_redirect(capfd):
m.raw_output(msg) m.raw_output(msg)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == msg assert stdout == msg
assert stream.getvalue() == '' assert stream.getvalue() == ""
def test_redirect_err(capfd): def test_redirect_err(capfd):
@ -193,7 +196,7 @@ def test_redirect_err(capfd):
m.raw_err(msg2) m.raw_err(msg2)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == msg assert stdout == msg
assert stderr == '' assert stderr == ""
assert stream.getvalue() == msg2 assert stream.getvalue() == msg2
@ -209,7 +212,7 @@ def test_redirect_both(capfd):
m.raw_output(msg) m.raw_output(msg)
m.raw_err(msg2) m.raw_err(msg2)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == '' assert stdout == ""
assert stderr == '' assert stderr == ""
assert stream.getvalue() == msg assert stream.getvalue() == msg
assert stream2.getvalue() == msg2 assert stream2.getvalue() == msg2

View File

@ -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) == "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.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_function) == "args_function(*args) -> tuple"
assert doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple" assert (
assert doc(m.KWClass.foo0) == \ doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple"
"foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None" )
assert doc(m.KWClass.foo1) == \ assert (
"foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None" 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): def test_named_arguments(msg):
@ -40,7 +46,9 @@ def test_named_arguments(msg):
# noinspection PyArgumentList # noinspection PyArgumentList
m.kw_func2(x=5, y=10, z=12) m.kw_func2(x=5, y=10, z=12)
assert excinfo.match( 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() == "{13 17}"
assert m.kw_func4(myList=[1, 2, 3]) == "{1 2 3}" 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(): def test_arg_and_kwargs():
args = 'arg1_value', 'arg2_value', 3 args = "arg1_value", "arg2_value", 3
assert m.args_function(*args) == args assert m.args_function(*args) == args
args = 'a1', 'a2' args = "a1", "a2"
kwargs = dict(arg3='a3', arg4=4) kwargs = dict(arg3="a3", arg4=4)
assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs) 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, ()) assert mpa(1, 2.5) == (1, 2.5, ())
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert mpa(1) assert mpa(1)
assert msg(excinfo.value) == """ assert (
msg(excinfo.value)
== """
mixed_plus_args(): incompatible function arguments. The following argument types are supported: mixed_plus_args(): incompatible function arguments. The following argument types are supported:
1. (arg0: int, arg1: float, *args) -> tuple 1. (arg0: int, arg1: float, *args) -> tuple
Invoked with: 1 Invoked with: 1
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert mpa() assert mpa()
assert msg(excinfo.value) == """ assert (
msg(excinfo.value)
== """
mixed_plus_args(): incompatible function arguments. The following argument types are supported: mixed_plus_args(): incompatible function arguments. The following argument types are supported:
1. (arg0: int, arg1: float, *args) -> tuple 1. (arg0: int, arg1: float, *args) -> tuple
Invoked with: Invoked with:
""" # noqa: E501 line too long """ # 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) == ( 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() == (1, 3.14159, (), {})
assert mpakd(3) == (3, 3.14159, (), {}) assert mpakd(3) == (3, 3.14159, (), {})
assert mpakd(j=2.71828) == (1, 2.71828, (), {}) 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) == ( 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: # Arguments specified both positionally and via kwargs should fail:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert mpakd(1, i=1) 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: 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 1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
Invoked with: 1; kwargs: i=1 Invoked with: 1; kwargs: i=1
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert mpakd(1, 2, j=1) 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: 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 1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
Invoked with: 1, 2; kwargs: j=1 Invoked with: 1, 2; kwargs: j=1
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
def test_keyword_only_args(msg): 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(j=2, i=3) == (3, 2)
assert m.kw_only_mixed(i=2, j=3) == (2, 3) 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(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(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(2, k=3, extra=4) == (2, -1, 3, {"extra": 4})
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert m.kw_only_mixed(i=1) == (1,) assert m.kw_only_mixed(i=1) == (1,)
@ -144,9 +176,12 @@ def test_keyword_only_args(msg):
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.register_invalid_kw_only(m) 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 arg(): cannot specify an unnamed argument after an kw_only() annotation
""" """
)
def test_positional_only_args(msg): 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 "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_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_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") @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 m.args_function(-1, myval) == (-1, myval)
assert refcount(myval) == expected 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 refcount(myval) == expected
assert m.args_kwargs_function(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}) (7, 8, myval),
{"a": 1, "b": myval},
)
assert refcount(myval) == expected assert refcount(myval) == expected
exp3 = refcount(myval, myval, myval) exp3 = refcount(myval, myval, myval)

View File

@ -36,8 +36,8 @@ def test_local_bindings():
assert i2.get() == 11 assert i2.get() == 11
assert i2.get2() == 12 assert i2.get2() == 12
assert not hasattr(i1, 'get2') assert not hasattr(i1, "get2")
assert not hasattr(i2, 'get3') assert not hasattr(i2, "get3")
# Loading within the local module # Loading within the local module
assert m.local_value(i1) == 5 assert m.local_value(i1) == 5
@ -55,7 +55,9 @@ def test_nonlocal_failure():
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
cm.register_nonlocal() 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(): def test_duplicate_local():
@ -63,9 +65,12 @@ def test_duplicate_local():
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.register_local_external() m.register_local_external()
import pybind11_tests import pybind11_tests
assert str(excinfo.value) == ( assert str(excinfo.value) == (
'generic_type: type "LocalExternal" is already registered!' '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(): def test_stl_bind_local():
@ -98,8 +103,8 @@ def test_stl_bind_local():
d1["b"] = v1[1] d1["b"] = v1[1]
d2["c"] = v2[0] d2["c"] = v2[0]
d2["d"] = v2[1] d2["d"] = v2[1]
assert {i: d1[i].get() for i in d1} == {'a': 0, 'b': 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: d2[i].get() for i in d2} == {"c": 2, "d": 3}
def test_stl_bind_global(): def test_stl_bind_global():
@ -107,15 +112,21 @@ def test_stl_bind_global():
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
cm.register_nonlocal_map() 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: with pytest.raises(RuntimeError) as excinfo:
cm.register_nonlocal_vec() 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: with pytest.raises(RuntimeError) as excinfo:
cm.register_nonlocal_map2() 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(): 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, 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.""" casting will go to the local type; outside the module casting goes to the global type."""
import pybind11_cross_module_tests as cm import pybind11_cross_module_tests as cm
m.register_mixed_global() m.register_mixed_global()
m.register_mixed_local() 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_gl(11))
a.append(cm.get_mixed_lg(12)) a.append(cm.get_mixed_lg(12))
assert [x.get() for x in a] == \ assert [x.get() for x in a] == [
[101, 1002, 103, 1004, 105, 1006, 207, 2008, 109, 1010, 211, 2012] 101,
1002,
103,
1004,
105,
1006,
207,
2008,
109,
1010,
211,
2012,
]
def test_internal_locals_differ(): def test_internal_locals_differ():
"""Makes sure the internal local type map differs across the two modules""" """Makes sure the internal local type map differs across the two modules"""
import pybind11_cross_module_tests as cm import pybind11_cross_module_tests as cm
assert m.local_cpp_types_addr() != cm.local_cpp_types_addr() 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 assert m.load_vector_via_caster(v2) == 6
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
cm.load_vector_via_binding(v2) == 6 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: load_vector_via_binding(): incompatible function arguments. The following argument types are supported:
1. (arg0: pybind11_cross_module_tests.VectorInt) -> int 1. (arg0: pybind11_cross_module_tests.VectorInt) -> int
Invoked with: [1, 2, 3] Invoked with: [1, 2, 3]
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
def test_cross_module_calls(): def test_cross_module_calls():

View File

@ -40,17 +40,17 @@ def test_methods_and_attributes():
assert instance1.overloaded(0) == "(int)" assert instance1.overloaded(0) == "(int)"
assert instance1.overloaded(1, 1.0) == "(int, float)" assert instance1.overloaded(1, 1.0) == "(int, float)"
assert instance1.overloaded(2.0, 2) == "(float, int)" assert instance1.overloaded(2.0, 2) == "(float, int)"
assert instance1.overloaded(3, 3) == "(int, int)" assert instance1.overloaded(3, 3) == "(int, int)"
assert instance1.overloaded(4., 4.) == "(float, float)" assert instance1.overloaded(4.0, 4.0) == "(float, float)"
assert instance1.overloaded_const(-3) == "(int) const" assert instance1.overloaded_const(-3) == "(int) const"
assert instance1.overloaded_const(5, 5.0) == "(int, float) 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(6.0, 6) == "(float, int) const"
assert instance1.overloaded_const(7, 7) == "(int, int) const" assert instance1.overloaded_const(7, 7) == "(int, int) const"
assert instance1.overloaded_const(8., 8.) == "(float, float) 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.0) == "(float, float)"
assert instance1.overloaded_float(1., 1) == "(float, float)" assert instance1.overloaded_float(1.0, 1) == "(float, float)"
assert instance1.overloaded_float(1., 1.) == "(float, float)" assert instance1.overloaded_float(1.0, 1.0) == "(float, float)"
assert instance1.value == 320 assert instance1.value == 320
instance1.value = 100 instance1.value = 100
@ -193,7 +193,10 @@ def test_metaclass_override():
assert type(m.MetaclassOverride).__name__ == "type" assert type(m.MetaclassOverride).__name__ == "type"
assert m.MetaclassOverride.readonly == 1 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__()` # Regular `type` replaces the property instead of calling `__set__()`
m.MetaclassOverride.readonly = 2 m.MetaclassOverride.readonly = 2
@ -206,22 +209,26 @@ def test_no_mixed_overloads():
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.ExampleMandA.add_mixed_overloads1() m.ExampleMandA.add_mixed_overloads1()
assert (str(excinfo.value) == assert str(
"overloading a method with both static and instance methods is not supported; " + excinfo.value
("compile in debug mode for more details" if not debug_enabled else ) == "overloading a method with both static and instance methods is not supported; " + (
"error while attempting to bind static method ExampleMandA.overload_mixed1" "compile in debug mode for more details"
"(arg0: float) -> str") if not debug_enabled
) else "error while attempting to bind static method ExampleMandA.overload_mixed1"
"(arg0: float) -> str"
)
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.ExampleMandA.add_mixed_overloads2() m.ExampleMandA.add_mixed_overloads2()
assert (str(excinfo.value) == assert str(
"overloading a method with both static and instance methods is not supported; " + excinfo.value
("compile in debug mode for more details" if not debug_enabled else ) == "overloading a method with both static and instance methods is not supported; " + (
"error while attempting to bind instance method ExampleMandA.overload_mixed2" "compile in debug mode for more details"
"(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)" if not debug_enabled
" -> str") 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"]) @pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
@ -333,8 +340,8 @@ def test_bad_arg_default(msg):
assert msg(excinfo.value) == ( assert msg(excinfo.value) == (
"arg(): could not convert default argument 'a: UnregisteredType' in function " "arg(): could not convert default argument 'a: UnregisteredType' in function "
"'should_fail' into a Python object (type not registered yet?)" "'should_fail' into a Python object (type not registered yet?)"
if debug_enabled else if debug_enabled
"arg(): could not convert default argument into a Python object (type not registered " else "arg(): could not convert default argument into a Python object (type not registered "
"yet?). Compile in debug mode for more information." "yet?). Compile in debug mode for more information."
) )
@ -343,8 +350,8 @@ def test_bad_arg_default(msg):
assert msg(excinfo.value) == ( assert msg(excinfo.value) == (
"arg(): could not convert default argument 'UnregisteredType' in function " "arg(): could not convert default argument 'UnregisteredType' in function "
"'should_fail' into a Python object (type not registered yet?)" "'should_fail' into a Python object (type not registered yet?)"
if debug_enabled else if debug_enabled
"arg(): could not convert default argument into a Python object (type not registered " else "arg(): could not convert default argument into a Python object (type not registered "
"yet?). Compile in debug mode for more information." "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: # The first one still raises because you can't pass None as a lvalue reference arg:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert m.ok_none1(None) == -1 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: ok_none1(): incompatible function arguments. The following argument types are supported:
1. (arg0: m.methods_and_attributes.NoneTester) -> int 1. (arg0: m.methods_and_attributes.NoneTester) -> int
Invoked with: None Invoked with: None
""" """
)
# The rest take the argument as pointer or holder, and accept None: # The rest take the argument as pointer or holder, and accept None:
assert m.ok_none2(None) == -1 assert m.ok_none2(None) == -1
@ -402,13 +412,16 @@ def test_str_issue(msg):
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
str(m.StrIssue("no", "such", "constructor")) str(m.StrIssue("no", "such", "constructor"))
assert msg(excinfo.value) == """ assert (
msg(excinfo.value)
== """
__init__(): incompatible constructor arguments. The following argument types are supported: __init__(): incompatible constructor arguments. The following argument types are supported:
1. m.methods_and_attributes.StrIssue(arg0: int) 1. m.methods_and_attributes.StrIssue(arg0: int)
2. m.methods_and_attributes.StrIssue() 2. m.methods_and_attributes.StrIssue()
Invoked with: 'no', 'such', 'constructor' Invoked with: 'no', 'such', 'constructor'
""" """
)
def test_unregistered_base_implementations(): def test_unregistered_base_implementations():
@ -441,7 +454,7 @@ def test_ref_qualified():
def test_overload_ordering(): 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("string") == 1
assert m.overload_order(0) == 4 assert m.overload_order(0) == 4
@ -449,8 +462,14 @@ def test_overload_ordering():
uni_name = type(u"").__name__ uni_name = type(u"").__name__
assert "1. overload_order(arg0: int) -> int" in m.overload_order.__doc__ 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 (
assert "3. overload_order(arg0: {}) -> int".format(uni_name) in m.overload_order.__doc__ "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__ assert "4. overload_order(arg0: int) -> int" in m.overload_order.__doc__
with pytest.raises(TypeError) as err: with pytest.raises(TypeError) as err:

View File

@ -6,9 +6,13 @@ from pybind11_tests import ConstructorStats
def test_nested_modules(): def test_nested_modules():
import pybind11_tests import pybind11_tests
assert pybind11_tests.__name__ == "pybind11_tests" assert pybind11_tests.__name__ == "pybind11_tests"
assert pybind11_tests.modules.__name__ == "pybind11_tests.modules" 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 m.__name__ == "pybind11_tests.modules"
assert ms.__name__ == "pybind11_tests.modules.subsubmodule" assert ms.__name__ == "pybind11_tests.modules.subsubmodule"
@ -35,7 +39,7 @@ def test_reference_internal():
del b del b
assert astats.alive() == 0 assert astats.alive() == 0
assert bstats.alive() == 0 assert bstats.alive() == 0
assert astats.values() == ['1', '2', '42', '43'] assert astats.values() == ["1", "2", "42", "43"]
assert bstats.values() == [] assert bstats.values() == []
assert astats.default_constructions == 0 assert astats.default_constructions == 0
assert bstats.default_constructions == 1 assert bstats.default_constructions == 1
@ -54,7 +58,7 @@ def test_importing():
from collections import OrderedDict from collections import OrderedDict
assert OD is 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(): def test_pydoc():

View File

@ -57,7 +57,6 @@ def test_multiple_inheritance_mix2():
@pytest.mark.skipif("env.PYPY and env.PY2") @pytest.mark.skipif("env.PYPY and env.PY2")
@pytest.mark.xfail("env.PYPY and not env.PY2") @pytest.mark.xfail("env.PYPY and not env.PY2")
def test_multiple_inheritance_python(): def test_multiple_inheritance_python():
class MI1(m.Base1, m.Base2): class MI1(m.Base1, m.Base2):
def __init__(self, i, j): def __init__(self, i, j):
m.Base1.__init__(self, i) m.Base1.__init__(self, i)
@ -163,7 +162,6 @@ def test_multiple_inheritance_python():
def test_multiple_inheritance_python_many_bases(): def test_multiple_inheritance_python_many_bases():
class MIMany14(m.BaseN1, m.BaseN2, m.BaseN3, m.BaseN4): class MIMany14(m.BaseN1, m.BaseN2, m.BaseN3, m.BaseN4):
def __init__(self): def __init__(self):
m.BaseN1.__init__(self, 1) m.BaseN1.__init__(self, 1)
@ -178,8 +176,16 @@ def test_multiple_inheritance_python_many_bases():
m.BaseN7.__init__(self, 7) m.BaseN7.__init__(self, 7)
m.BaseN8.__init__(self, 8) m.BaseN8.__init__(self, 8)
class MIMany916(m.BaseN9, m.BaseN10, m.BaseN11, m.BaseN12, m.BaseN13, m.BaseN14, m.BaseN15, class MIMany916(
m.BaseN16): m.BaseN9,
m.BaseN10,
m.BaseN11,
m.BaseN12,
m.BaseN13,
m.BaseN14,
m.BaseN15,
m.BaseN16,
):
def __init__(self): def __init__(self):
m.BaseN9.__init__(self, 9) m.BaseN9.__init__(self, 9)
m.BaseN10.__init__(self, 10) m.BaseN10.__init__(self, 10)
@ -225,7 +231,6 @@ def test_multiple_inheritance_python_many_bases():
def test_multiple_inheritance_virtbase(): def test_multiple_inheritance_virtbase():
class MITypePy(m.Base12a): class MITypePy(m.Base12a):
def __init__(self, i, j): def __init__(self, i, j):
m.Base12a.__init__(self, i, j) m.Base12a.__init__(self, i, j)
@ -238,7 +243,7 @@ def test_multiple_inheritance_virtbase():
def test_mi_static_properties(): def test_mi_static_properties():
"""Mixing bases with and without static properties should be possible """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()): for d in (m.VanillaStaticMix1(), m.VanillaStaticMix2()):
assert d.vanilla() == "Vanilla" assert d.vanilla() == "Vanilla"

View File

@ -19,33 +19,36 @@ def test_dtypes():
print(check) print(check)
assert check.numpy == check.pybind11, check assert check.numpy == check.pybind11, check
if check.numpy.num != check.pybind11.num: if check.numpy.num != check.pybind11.num:
print("NOTE: typenum mismatch for {}: {} != {}".format( print(
check, check.numpy.num, check.pybind11.num)) "NOTE: typenum mismatch for {}: {} != {}".format(
check, check.numpy.num, check.pybind11.num
)
)
@pytest.fixture(scope='function') @pytest.fixture(scope="function")
def arr(): 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(): def test_array_attributes():
a = np.array(0, 'f8') a = np.array(0, "f8")
assert m.ndim(a) == 0 assert m.ndim(a) == 0
assert all(m.shape(a) == []) assert all(m.shape(a) == [])
assert all(m.strides(a) == []) assert all(m.strides(a) == [])
with pytest.raises(IndexError) as excinfo: with pytest.raises(IndexError) as excinfo:
m.shape(a, 0) 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: with pytest.raises(IndexError) as excinfo:
m.strides(a, 0) 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.writeable(a)
assert m.size(a) == 1 assert m.size(a) == 1
assert m.itemsize(a) == 8 assert m.itemsize(a) == 8
assert m.nbytes(a) == 8 assert m.nbytes(a) == 8
assert m.owndata(a) 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 a.flags.writeable = False
assert m.ndim(a) == 2 assert m.ndim(a) == 2
assert all(m.shape(a) == [2, 3]) assert all(m.shape(a) == [2, 3])
@ -56,10 +59,10 @@ def test_array_attributes():
assert m.strides(a, 1) == 2 assert m.strides(a, 1) == 2
with pytest.raises(IndexError) as excinfo: with pytest.raises(IndexError) as excinfo:
m.shape(a, 2) 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: with pytest.raises(IndexError) as excinfo:
m.strides(a, 2) 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 not m.writeable(a)
assert m.size(a) == 6 assert m.size(a) == 6
assert m.itemsize(a) == 2 assert m.itemsize(a) == 2
@ -67,7 +70,9 @@ def test_array_attributes():
assert not m.owndata(a) 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): def test_index_offset(arr, args, ret):
assert m.index_at(arr, *args) == ret assert m.index_at(arr, *args) == ret
assert m.index_at_t(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): 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, for func in (
m.mutate_data, m.mutate_data_t): 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: with pytest.raises(IndexError) as excinfo:
func(arr, 1, 2, 3) 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', @pytest.mark.parametrize(
[([], [1, 2, 3, 4, 5, 6]), "args, ret",
([1], [4, 5, 6]), [
([0, 1], [2, 3, 4, 5, 6]), ([], [1, 2, 3, 4, 5, 6]),
([1, 2], [6])]) ([1], [4, 5, 6]),
([0, 1], [2, 3, 4, 5, 6]),
([1, 2], [6]),
],
)
def test_data(arr, args, ret): def test_data(arr, args, ret):
from sys import byteorder from sys import byteorder
assert all(m.data_t(arr, *args) == ret) 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)[(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)[(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): def test_at_fail(arr, dim):
for func in m.at_t, m.mutate_at_t: for func in m.at_t, m.mutate_at_t:
with pytest.raises(IndexError) as excinfo: with pytest.raises(IndexError) as excinfo:
func(arr, *([0] * dim)) 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): def test_at(arr):
@ -113,10 +133,14 @@ def test_at(arr):
def test_mutate_readonly(arr): def test_mutate_readonly(arr):
arr.flags.writeable = False 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: with pytest.raises(ValueError) as excinfo:
func(arr, *args) func(arr, *args)
assert str(excinfo.value) == 'array is not writeable' assert str(excinfo.value) == "array is not writeable"
def test_mutate_data(arr): def test_mutate_data(arr):
@ -134,14 +158,22 @@ def test_mutate_data(arr):
def test_bounds_check(arr): def test_bounds_check(arr):
for func in (m.index_at, m.index_at_t, m.data, m.data_t, for func in (
m.mutate_data, m.mutate_data_t, m.at_t, m.mutate_at_t): 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: with pytest.raises(IndexError) as excinfo:
func(arr, 2, 0) 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: with pytest.raises(IndexError) as excinfo:
func(arr, 0, 4) 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(): def test_make_c_f_array():
@ -163,10 +195,11 @@ def test_make_empty_shaped_array():
def test_wrap(): def test_wrap():
def assert_references(a, b, base=None): def assert_references(a, b, base=None):
from distutils.version import LooseVersion from distutils.version import LooseVersion
if base is None: if base is None:
base = a base = a
assert a is not b 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.shape == b.shape
assert a.strides == b.strides assert a.strides == b.strides
assert a.flags.c_contiguous == b.flags.c_contiguous assert a.flags.c_contiguous == b.flags.c_contiguous
@ -189,12 +222,12 @@ def test_wrap():
a2 = m.wrap(a1) a2 = m.wrap(a1)
assert_references(a1, a2) 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 assert a1.flags.owndata and a1.base is None
a2 = m.wrap(a1) a2 = m.wrap(a1)
assert_references(a1, a2) 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 a1.flags.writeable = False
a2 = m.wrap(a1) a2 = m.wrap(a1)
assert_references(a1, a2) 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)) assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32))
del ac del ac
pytest.gc_collect() pytest.gc_collect()
assert capture == """ assert (
capture
== """
ArrayClass() ArrayClass()
ArrayClass::numpy_view() ArrayClass::numpy_view()
ArrayClass::numpy_view() ArrayClass::numpy_view()
""" """
)
ac_view_1[0] = 4 ac_view_1[0] = 4
ac_view_1[1] = 3 ac_view_1[1] = 3
assert ac_view_2[0] == 4 assert ac_view_2[0] == 4
@ -238,9 +274,12 @@ def test_numpy_view(capture):
del ac_view_2 del ac_view_2
pytest.gc_collect() pytest.gc_collect()
pytest.gc_collect() pytest.gc_collect()
assert capture == """ assert (
capture
== """
~ArrayClass() ~ArrayClass()
""" """
)
def test_cast_numpy_int64_to_uint64(): def test_cast_numpy_int64_to_uint64():
@ -271,20 +310,22 @@ def test_constructors():
def test_overload_resolution(msg): def test_overload_resolution(msg):
# Exact overload matches: # Exact overload matches:
assert m.overloaded(np.array([1], dtype='float64')) == 'double' 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="float32")) == "float"
assert m.overloaded(np.array([1], dtype='ushort')) == 'unsigned short' 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="intc")) == "int"
assert m.overloaded(np.array([1], dtype='longlong')) == 'long long' 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="complex")) == "double complex"
assert m.overloaded(np.array([1], dtype='csingle')) == 'float complex' assert m.overloaded(np.array([1], dtype="csingle")) == "float complex"
# No exact match, should call first convertible version: # 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: with pytest.raises(TypeError) as excinfo:
m.overloaded("not an array") m.overloaded("not an array")
assert msg(excinfo.value) == """ assert (
msg(excinfo.value)
== """
overloaded(): incompatible function arguments. The following argument types are supported: overloaded(): incompatible function arguments. The following argument types are supported:
1. (arg0: numpy.ndarray[numpy.float64]) -> str 1. (arg0: numpy.ndarray[numpy.float64]) -> str
2. (arg0: numpy.ndarray[numpy.float32]) -> str 2. (arg0: numpy.ndarray[numpy.float32]) -> str
@ -296,15 +337,16 @@ def test_overload_resolution(msg):
Invoked with: 'not an array' Invoked with: 'not an array'
""" """
)
assert m.overloaded2(np.array([1], dtype='float64')) == 'double' 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="float32")) == "float"
assert m.overloaded2(np.array([1], dtype='complex64')) == 'float complex' 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="complex128")) == "double complex"
assert m.overloaded2(np.array([1], dtype='float32')) == 'float' 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="float64")) == "double"
assert m.overloaded3(np.array([1], dtype='intc')) == 'int' assert m.overloaded3(np.array([1], dtype="intc")) == "int"
expected_exc = """ expected_exc = """
overloaded3(): incompatible function arguments. The following argument types are supported: overloaded3(): incompatible function arguments. The following argument types are supported:
1. (arg0: numpy.ndarray[numpy.int32]) -> str 1. (arg0: numpy.ndarray[numpy.int32]) -> str
@ -313,47 +355,49 @@ def test_overload_resolution(msg):
Invoked with: """ Invoked with: """
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.overloaded3(np.array([1], dtype='uintc')) m.overloaded3(np.array([1], dtype="uintc"))
assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype='uint32')) assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype="uint32"))
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.overloaded3(np.array([1], dtype='float32')) m.overloaded3(np.array([1], dtype="float32"))
assert msg(excinfo.value) == expected_exc + repr(np.array([1.], dtype='float32')) assert msg(excinfo.value) == expected_exc + repr(np.array([1.0], dtype="float32"))
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.overloaded3(np.array([1], dtype='complex')) m.overloaded3(np.array([1], dtype="complex"))
assert msg(excinfo.value) == expected_exc + repr(np.array([1. + 0.j])) assert msg(excinfo.value) == expected_exc + repr(np.array([1.0 + 0.0j]))
# Exact matches: # Exact matches:
assert m.overloaded4(np.array([1], dtype='double')) == 'double' 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="longlong")) == "long long"
# Non-exact matches requiring conversion. Since float to integer isn't a # 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 # 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). # 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="float32")) == "double"
assert m.overloaded4(np.array([1], dtype='short')) == 'long long' 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="double")) == "double"
assert m.overloaded5(np.array([1], dtype='uintc')) == 'unsigned int' 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="float32")) == "unsigned int"
def test_greedy_string_overload(): def test_greedy_string_overload():
"""Tests fix for #685 - ndarray shouldn't go to std::string overload""" """Tests fix for #685 - ndarray shouldn't go to std::string overload"""
assert m.issue685("abc") == "string" 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" assert m.issue685(123) == "other"
def test_array_unchecked_fixed_dims(msg): 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) m.proxy_add2(z1, 10)
assert np.all(z1 == [[11, 12], [13, 14]]) assert np.all(z1 == [[11, 12], [13, 14]])
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
m.proxy_add2(np.array([1., 2, 3]), 5.0) m.proxy_add2(np.array([1.0, 2, 3]), 5.0)
assert msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2" 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) assert np.all(m.proxy_init3(3.0) == expect_c)
expect_f = np.transpose(expect_c) expect_f = np.transpose(expect_c)
assert np.all(m.proxy_init3F(3.0) == expect_f) 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): 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) m.proxy_add2_dyn(z1, 10)
assert np.all(z1 == [[11, 12], [13, 14]]) 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 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] 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(): def test_array_failure():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
m.array_fail_test() 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: with pytest.raises(ValueError) as excinfo:
m.array_t_fail_test() 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: with pytest.raises(ValueError) as excinfo:
m.array_fail_test_negative_size() 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(): def test_initializer_list():
@ -402,35 +446,35 @@ def test_initializer_list():
def test_array_resize(msg): 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) m.array_reshape2(a)
assert(a.size == 9) assert a.size == 9
assert(np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]])) assert np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# total size change should succced with refcheck off # total size change should succced with refcheck off
m.array_resize3(a, 4, False) m.array_resize3(a, 4, False)
assert(a.size == 64) assert a.size == 64
# ... and fail with refcheck on # ... and fail with refcheck on
try: try:
m.array_resize3(a, 3, True) m.array_resize3(a, 3, True)
except ValueError as e: 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 # transposed array doesn't own data
b = a.transpose() b = a.transpose()
try: try:
m.array_resize3(b, 3, False) m.array_resize3(b, 3, False)
except ValueError as e: 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 # ... but reshape should be fine
m.array_reshape2(b) m.array_reshape2(b)
assert(b.shape == (8, 8)) assert b.shape == (8, 8)
@pytest.mark.xfail("env.PYPY") @pytest.mark.xfail("env.PYPY")
def test_array_create_and_resize(msg): def test_array_create_and_resize(msg):
a = m.create_and_resize(2) a = m.create_and_resize(2)
assert(a.size == 4) assert a.size == 4
assert(np.all(a == 42.)) assert np.all(a == 42.0)
def test_index_using_ellipsis(): def test_index_using_ellipsis():
@ -439,16 +483,16 @@ def test_index_using_ellipsis():
@pytest.mark.parametrize("forcecast", [False, True]) @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.parametrize("noconvert", [False, True])
@pytest.mark.filterwarnings( @pytest.mark.filterwarnings(
"ignore:Casting complex values to real discards the imaginary part:numpy.ComplexWarning" "ignore:Casting complex values to real discards the imaginary part:numpy.ComplexWarning"
) )
def test_argument_conversions(forcecast, contiguity, noconvert): def test_argument_conversions(forcecast, contiguity, noconvert):
function_name = "accept_double" function_name = "accept_double"
if contiguity == 'C': if contiguity == "C":
function_name += "_c_style" function_name += "_c_style"
elif contiguity == 'F': elif contiguity == "F":
function_name += "_f_style" function_name += "_f_style"
if forcecast: if forcecast:
function_name += "_forcecast" function_name += "_forcecast"
@ -456,37 +500,39 @@ def test_argument_conversions(forcecast, contiguity, noconvert):
function_name += "_noconvert" function_name += "_noconvert"
function = getattr(m, function_name) function = getattr(m, function_name)
for dtype in [np.dtype('float32'), np.dtype('float64'), np.dtype('complex128')]: for dtype in [np.dtype("float32"), np.dtype("float64"), np.dtype("complex128")]:
for order in ['C', 'F']: for order in ["C", "F"]:
for shape in [(2, 2), (1, 3, 1, 1), (1, 1, 1), (0,)]: for shape in [(2, 2), (1, 3, 1, 1), (1, 1, 1), (0,)]:
if not noconvert: if not noconvert:
# If noconvert is not passed, only complex128 needs to be truncated and # If noconvert is not passed, only complex128 needs to be truncated and
# "cannot be safely obtained". So without `forcecast`, the argument shouldn't # "cannot be safely obtained". So without `forcecast`, the argument shouldn't
# be accepted. # be accepted.
should_raise = dtype.name == 'complex128' and not forcecast should_raise = dtype.name == "complex128" and not forcecast
else: else:
# If noconvert is passed, only float64 and the matching order is accepted. # 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 # If at most one dimension has a size greater than 1, the array is also
# trivially contiguous. # trivially contiguous.
trivially_contiguous = sum(1 for d in shape if d > 1) <= 1 trivially_contiguous = sum(1 for d in shape if d > 1) <= 1
should_raise = ( should_raise = dtype.name != "float64" or (
dtype.name != 'float64' or contiguity is not None
(contiguity is not None and and contiguity != order
contiguity != order and and not trivially_contiguous
not trivially_contiguous)
) )
array = np.zeros(shape, dtype=dtype, order=order) array = np.zeros(shape, dtype=dtype, order=order)
if not should_raise: if not should_raise:
function(array) function(array)
else: else:
with pytest.raises(TypeError, match="incompatible function arguments"): with pytest.raises(
TypeError, match="incompatible function arguments"
):
function(array) function(array)
@pytest.mark.xfail("env.PYPY") @pytest.mark.xfail("env.PYPY")
def test_dtype_refcount_leak(): def test_dtype_refcount_leak():
from sys import getrefcount from sys import getrefcount
dtype = np.dtype(np.float_) dtype = np.dtype(np.float_)
a = np.array([1], dtype=dtype) a = np.array([1], dtype=dtype)
before = getrefcount(dtype) before = getrefcount(dtype)

View File

@ -10,57 +10,71 @@ from pybind11_tests import numpy_dtypes as m
np = pytest.importorskip("numpy") np = pytest.importorskip("numpy")
@pytest.fixture(scope='module') @pytest.fixture(scope="module")
def simple_dtype(): def simple_dtype():
ld = np.dtype('longdouble') ld = np.dtype("longdouble")
return np.dtype({'names': ['bool_', 'uint_', 'float_', 'ldbl_'], return np.dtype(
'formats': ['?', 'u4', 'f4', 'f{}'.format(ld.itemsize)], {
'offsets': [0, 4, 8, (16 if ld.alignment > 4 else 12)]}) "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(): 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(): def dt_fmt():
from sys import byteorder from sys import byteorder
e = '<' if byteorder == 'little' else '>'
return ("{{'names':['bool_','uint_','float_','ldbl_']," e = "<" if byteorder == "little" else ">"
" 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}']," return (
" 'offsets':[0,4,8,{}], 'itemsize':{}}}") "{{'names':['bool_','uint_','float_','ldbl_'],"
" 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}'],"
" 'offsets':[0,4,8,{}], 'itemsize':{}}}"
)
def simple_dtype_fmt(): def simple_dtype_fmt():
ld = np.dtype('longdouble') ld = np.dtype("longdouble")
simple_ld_off = 12 + 4 * (ld.alignment > 4) simple_ld_off = 12 + 4 * (ld.alignment > 4)
return dt_fmt().format(ld.itemsize, simple_ld_off, simple_ld_off + ld.itemsize) return dt_fmt().format(ld.itemsize, simple_ld_off, simple_ld_off + ld.itemsize)
def packed_dtype_fmt(): def packed_dtype_fmt():
from sys import byteorder from sys import byteorder
return "[('bool_', '?'), ('uint_', '{e}u4'), ('float_', '{e}f4'), ('ldbl_', '{e}f{}')]".format( 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(): def partial_ld_offset():
return 12 + 4 * (np.dtype('uint64').alignment > 4) + 8 + 8 * ( return (
np.dtype('longdouble').alignment > 8) 12
+ 4 * (np.dtype("uint64").alignment > 4)
+ 8
+ 8 * (np.dtype("longdouble").alignment > 8)
)
def partial_dtype_fmt(): def partial_dtype_fmt():
ld = np.dtype('longdouble') ld = np.dtype("longdouble")
partial_ld_off = partial_ld_offset() partial_ld_off = partial_ld_offset()
return dt_fmt().format(ld.itemsize, partial_ld_off, partial_ld_off + ld.itemsize) return dt_fmt().format(ld.itemsize, partial_ld_off, partial_ld_off + ld.itemsize)
def partial_nested_fmt(): def partial_nested_fmt():
ld = np.dtype('longdouble') ld = np.dtype("longdouble")
partial_nested_off = 8 + 8 * (ld.alignment > 8) partial_nested_off = 8 + 8 * (ld.alignment > 8)
partial_ld_off = partial_ld_offset() partial_ld_off = partial_ld_offset()
partial_nested_size = partial_nested_off * 2 + partial_ld_off + ld.itemsize partial_nested_size = partial_nested_off * 2 + partial_ld_off + ld.itemsize
return "{{'names':['a'], 'formats':[{}], 'offsets':[{}], 'itemsize':{}}}".format( 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): def assert_equal(actual, expected_data, expected_dtype):
@ -70,15 +84,19 @@ def assert_equal(actual, expected_data, expected_dtype):
def test_format_descriptors(): def test_format_descriptors():
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.get_format_unbound() 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') ld = np.dtype("longdouble")
ldbl_fmt = ('4x' if ld.alignment > 4 else '') + ld.char ldbl_fmt = ("4x" if ld.alignment > 4 else "") + ld.char
ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}" ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}"
dbl = np.dtype('double') dbl = np.dtype("double")
partial_fmt = ("^T{?:bool_:3xI:uint_:f:float_:" + partial_fmt = (
str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) + "^T{?:bool_:3xI:uint_:f:float_:"
"xg:ldbl_:}") + str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8))
+ "xg:ldbl_:}"
)
nested_extra = str(max(8, ld.alignment)) nested_extra = str(max(8, ld.alignment))
assert m.print_format_descriptors() == [ assert m.print_format_descriptors() == [
ss_fmt, ss_fmt,
@ -88,14 +106,15 @@ def test_format_descriptors():
"^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}", "^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}",
"^T{3s:a:3s:b:}", "^T{3s:a:3s:b:}",
"^T{(3)4s:a:(2)i:b:(3)B:c:1x(4, 2)f:d:}", "^T{(3)4s:a:(2)i:b:(3)B:c:1x(4, 2)f:d:}",
'^T{q:e1:B:e2:}', "^T{q:e1:B:e2:}",
'^T{Zf:cflt:Zd:cdbl:}' "^T{Zf:cflt:Zd:cdbl:}",
] ]
def test_dtype(simple_dtype): def test_dtype(simple_dtype):
from sys import byteorder from sys import byteorder
e = '<' if byteorder == 'little' else '>'
e = "<" if byteorder == "little" else ">"
assert m.print_dtypes() == [ assert m.print_dtypes() == [
simple_dtype_fmt(), simple_dtype_fmt(),
@ -104,30 +123,60 @@ def test_dtype(simple_dtype):
partial_dtype_fmt(), partial_dtype_fmt(),
partial_nested_fmt(), partial_nested_fmt(),
"[('a', 'S3'), ('b', 'S3')]", "[('a', 'S3'), ('b', 'S3')]",
("{{'names':['a','b','c','d'], " + (
"'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('" + e + "f4', (4, 2))], " + "{{'names':['a','b','c','d'], "
"'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e), + "'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')]", "[('e1', '" + e + "i8'), ('e2', 'u1')]",
"[('x', 'i1'), ('y', '" + e + "u8')]", "[('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'], d1 = np.dtype(
'offsets': [1, 10], 'itemsize': 20}) {
d2 = np.dtype([('a', 'i4'), ('b', 'f4')]) "names": ["a", "b"],
assert m.test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'), "formats": ["int32", "float64"],
np.dtype('bool'), d1, d1, np.dtype('uint32'), d2] "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, assert m.test_dtype_methods() == [
np.dtype('int32').itemsize, simple_dtype.itemsize] 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): 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)] 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) arr = func(0)
assert arr.dtype == dtype assert arr.dtype == dtype
assert_equal(arr, [], simple_dtype) assert_equal(arr, [], simple_dtype)
@ -146,16 +195,16 @@ def test_recarray(simple_dtype, packed_dtype):
assert m.print_rec_simple(arr) == [ assert m.print_rec_simple(arr) == [
"s:0,0,0,-0", "s:0,0,0,-0",
"s:1,1,1.5,-2.5", "s:1,1,1.5,-2.5",
"s:0,2,3,-5" "s:0,2,3,-5",
] ]
else: else:
assert m.print_rec_packed(arr) == [ assert m.print_rec_packed(arr) == [
"p:0,0,0,-0", "p:0,0,0,-0",
"p:1,1,1.5,-2.5", "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) arr = m.create_rec_nested(0)
assert arr.dtype == nested_dtype assert arr.dtype == nested_dtype
@ -163,33 +212,39 @@ def test_recarray(simple_dtype, packed_dtype):
arr = m.create_rec_nested(3) arr = m.create_rec_nested(3)
assert arr.dtype == nested_dtype assert arr.dtype == nested_dtype
assert_equal(arr, [((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)), assert_equal(
((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)), arr,
((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5))], nested_dtype) [
((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) == [ assert m.print_rec_nested(arr) == [
"n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5", "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: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) arr = m.create_rec_partial(3)
assert str(arr.dtype) == partial_dtype_fmt() assert str(arr.dtype) == partial_dtype_fmt()
partial_dtype = arr.dtype partial_dtype = arr.dtype
assert '' not in arr.dtype.fields assert "" not in arr.dtype.fields
assert partial_dtype.itemsize > simple_dtype.itemsize assert partial_dtype.itemsize > simple_dtype.itemsize
assert_equal(arr, elements, simple_dtype) assert_equal(arr, elements, simple_dtype)
assert_equal(arr, elements, packed_dtype) assert_equal(arr, elements, packed_dtype)
arr = m.create_rec_partial_nested(3) arr = m.create_rec_partial_nested(3)
assert str(arr.dtype) == partial_nested_fmt() assert str(arr.dtype) == partial_nested_fmt()
assert '' not in arr.dtype.fields assert "" not in arr.dtype.fields
assert '' not in arr.dtype.fields['a'][0].fields assert "" not in arr.dtype.fields["a"][0].fields
assert arr.dtype.itemsize > partial_dtype.itemsize 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(): def test_array_constructors():
data = np.arange(1, 7, dtype='int32') data = np.arange(1, 7, dtype="int32")
for i in range(8): 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(10 + i), data.reshape((3, 2)))
np.testing.assert_array_equal(m.test_array_ctors(20 + 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='',b=''",
"a='a',b='a'", "a='a',b='a'",
"a='ab',b='ab'", "a='ab',b='ab'",
"a='abc',b='abc'" "a='abc',b='abc'",
] ]
dtype = arr.dtype dtype = arr.dtype
assert arr['a'].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'] assert arr["b"].tolist() == [b"", b"a", b"ab", b"abc"]
arr = m.create_string_array(False) arr = m.create_string_array(False)
assert dtype == arr.dtype assert dtype == arr.dtype
def test_array_array(): def test_array_array():
from sys import byteorder from sys import byteorder
e = '<' if byteorder == 'little' else '>'
e = "<" if byteorder == "little" else ">"
arr = m.create_array_array(3) arr = m.create_array_array(3)
assert str(arr.dtype) == ( assert str(arr.dtype) == (
"{{'names':['a','b','c','d'], " + "{{'names':['a','b','c','d'], "
"'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " + + "'formats':[('S4', (3,)),('"
"'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e) + 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) == [ assert m.print_array_array(arr) == [
"a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," + "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}}", + "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}," + "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}}", + "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}," + "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}}", + "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}",
] ]
assert arr['a'].tolist() == [[b'ABCD', b'KLMN', b'UVWX'], assert arr["a"].tolist() == [
[b'WXYZ', b'GHIJ', b'QRST'], [b"ABCD", b"KLMN", b"UVWX"],
[b'STUV', b'CDEF', b'MNOP']] [b"WXYZ", b"GHIJ", b"QRST"],
assert arr['b'].tolist() == [[0, 1], [1000, 1001], [2000, 2001]] [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 assert m.create_array_array(0).dtype == arr.dtype
def test_enum_array(): def test_enum_array():
from sys import byteorder from sys import byteorder
e = '<' if byteorder == 'little' else '>'
e = "<" if byteorder == "little" else ">"
arr = m.create_enum_array(3) arr = m.create_enum_array(3)
dtype = arr.dtype dtype = arr.dtype
assert dtype == np.dtype([('e1', e + 'i8'), ('e2', 'u1')]) assert dtype == np.dtype([("e1", e + "i8"), ("e2", "u1")])
assert m.print_enum_array(arr) == [ assert m.print_enum_array(arr) == ["e1=A,e2=X", "e1=B,e2=Y", "e1=A,e2=X"]
"e1=A,e2=X", assert arr["e1"].tolist() == [-1, 1, -1]
"e1=B,e2=Y", assert arr["e2"].tolist() == [1, 2, 1]
"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 assert m.create_enum_array(0).dtype == dtype
def test_complex_array(): def test_complex_array():
from sys import byteorder from sys import byteorder
e = '<' if byteorder == 'little' else '>'
e = "<" if byteorder == "little" else ">"
arr = m.create_complex_array(3) arr = m.create_complex_array(3)
dtype = arr.dtype 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) == [ assert m.print_complex_array(arr) == [
"c:(0,0.25),(0.5,0.75)", "c:(0,0.25),(0.5,0.75)",
"c:(1,1.25),(1.5,1.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["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["cdbl"].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j]
assert m.create_complex_array(0).dtype == dtype assert m.create_complex_array(0).dtype == dtype
def test_signature(doc): def test_signature(doc):
assert doc(m.create_rec_nested) == \ assert (
"create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]" doc(m.create_rec_nested)
== "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
)
def test_scalar_conversion(): def test_scalar_conversion():
n = 3 n = 3
arrays = [m.create_rec_simple(n), m.create_rec_packed(n), arrays = [
m.create_rec_nested(n), m.create_enum_array(n)] 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] funcs = [m.f_simple, m.f_packed, m.f_nested]
for i, func in enumerate(funcs): for i, func in enumerate(funcs):
@ -290,7 +355,7 @@ def test_scalar_conversion():
else: else:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
func(arr[0]) func(arr[0])
assert 'incompatible function arguments' in str(excinfo.value) assert "incompatible function arguments" in str(excinfo.value)
def test_vectorize(): def test_vectorize():
@ -304,14 +369,14 @@ def test_vectorize():
def test_cls_and_dtype_conversion(simple_dtype): def test_cls_and_dtype_conversion(simple_dtype):
s = m.SimpleStruct() 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() assert m.SimpleStruct.fromtuple(s.astuple()).astuple() == s.astuple()
s.uint_ = 2 s.uint_ = 2
assert m.f_simple(s) == 20 assert m.f_simple(s) == 20
# Try as recarray of shape==(1,). # 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. # Show that this will work for vectorized case.
np.testing.assert_array_equal(m.f_simple_vectorized(s_recarray), [20]) 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 assert s_recarray_scalar.dtype == simple_dtype
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.f_simple(s_recarray_scalar) 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. # Explicitly convert to m.SimpleStruct.
assert m.f_simple( assert m.f_simple(m.SimpleStruct.fromtuple(s_recarray_scalar.item())) == 20
m.SimpleStruct.fromtuple(s_recarray_scalar.item())) == 20
# Show that an array of dtype=object does *not* convert. # Show that an array of dtype=object does *not* convert.
s_array_object = np.array([s]) s_array_object = np.array([s])
assert s_array_object.dtype == object assert s_array_object.dtype == object
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.f_simple_vectorized(s_array_object) 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)` # Explicitly convert to `np.array(..., dtype=simple_dtype)`
s_array = np.array([s.astuple()], dtype=simple_dtype) s_array = np.array([s.astuple()], dtype=simple_dtype)
np.testing.assert_array_equal(m.f_simple_vectorized(s_array), [20]) 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(): def test_register_dtype():
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.register_dtype() 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") @pytest.mark.xfail("env.PYPY")
def test_str_leak(): def test_str_leak():
from sys import getrefcount from sys import getrefcount
fmt = "f4" fmt = "f4"
pytest.gc_collect() pytest.gc_collect()
start = getrefcount(fmt) start = getrefcount(fmt)

View File

@ -17,28 +17,40 @@ def test_vectorize(capture):
assert capture == "my_func(x:int=1, y:float=2, z:float=3)" assert capture == "my_func(x:int=1, y:float=2, z:float=3)"
with capture: with capture:
assert np.allclose(f(np.array([1, 3]), np.array([2, 4]), 3), [6, 36]) 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=1, y:float=2, z:float=3)
my_func(x:int=3, y:float=4, z:float=3) my_func(x:int=3, y:float=4, z:float=3)
""" """
)
with capture: with capture:
a = np.array([[1, 2], [3, 4]], order='F') a = np.array([[1, 2], [3, 4]], order="F")
b = np.array([[10, 20], [30, 40]], order='F') b = np.array([[10, 20], [30, 40]], order="F")
c = 3 c = 3
result = f(a, b, c) result = f(a, b, c)
assert np.allclose(result, a * b * c) assert np.allclose(result, a * b * c)
assert result.flags.f_contiguous assert result.flags.f_contiguous
# All inputs are F order and full or singletons, so we the result is in col-major order: # 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=1, y:float=10, z:float=3)
my_func(x:int=3, y:float=30, 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=2, y:float=20, z:float=3)
my_func(x:int=4, y:float=40, z:float=3) my_func(x:int=4, y:float=40, z:float=3)
""" """
)
with capture: 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 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=1, y:float=2, z:float=3)
my_func(x:int=3, y:float=4, 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) 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=9, y:float=10, z:float=3)
my_func(x:int=11, y:float=12, z:float=3) my_func(x:int=11, y:float=12, z:float=3)
""" """
)
with capture: with capture:
a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2 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 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=1, y:float=2, z:float=2)
my_func(x:int=2, y:float=3, 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) 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=5, y:float=3, z:float=2)
my_func(x:int=6, y:float=4, z:float=2) my_func(x:int=6, y:float=4, z:float=2)
""" """
)
with capture: with capture:
a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2 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 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=1, y:float=2, z:float=2)
my_func(x:int=2, 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) 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=5, y:float=3, z:float=2)
my_func(x:int=6, y:float=3, z:float=2) my_func(x:int=6, y:float=3, z:float=2)
""" """
)
with capture: 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 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=1, y:float=2, z:float=2)
my_func(x:int=2, 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) 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=5, y:float=3, z:float=2)
my_func(x:int=6, y:float=3, z:float=2) my_func(x:int=6, y:float=3, z:float=2)
""" """
)
with capture: with capture:
a, b, c = np.array([[1, 2, 3], [4, 5, 6]])[::, ::2], np.array([[2], [3]]), 2 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 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=1, y:float=2, z:float=2)
my_func(x:int=3, 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=4, y:float=3, z:float=2)
my_func(x:int=6, y:float=3, z:float=2) my_func(x:int=6, y:float=3, z:float=2)
""" """
)
with capture: 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 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=1, y:float=2, z:float=2)
my_func(x:int=3, 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=4, y:float=3, z:float=2)
my_func(x:int=6, y:float=3, z:float=2) my_func(x:int=6, y:float=3, z:float=2)
""" """
)
def test_type_selection(): def test_type_selection():
assert m.selective_func(np.array([1], dtype=np.int32)) == "Int branch taken." 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.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): 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 vectorized_func(arg0: numpy.ndarray[numpy.int32], arg1: numpy.ndarray[numpy.float32], arg2: numpy.ndarray[numpy.float64]) -> object
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
def test_trivial_broadcasting(): 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(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), 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( assert trivial.c_trivial == vectorized_is_trivial(
np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3) 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 (
assert vectorized_is_trivial( vectorized_is_trivial(np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2)
np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2) == trivial.non_trivial == trivial.non_trivial
z1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype='int32') )
z2 = np.array(z1, dtype='float32') assert (
z3 = np.array(z1, dtype='float64') 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(z1, z2, z3) == trivial.c_trivial
assert vectorized_is_trivial(1, 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 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(1, 1, z3[::2, ::2]) == trivial.non_trivial
assert vectorized_is_trivial(z1, 1, z3[1::4, 1::4]) == trivial.c_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) y2 = np.array(y1)
y3 = np.array(y1) y3 = np.array(y1)
assert vectorized_is_trivial(y1, y2, y3) == trivial.f_trivial assert vectorized_is_trivial(y1, y2, y3) == trivial.f_trivial
@ -156,30 +206,41 @@ def test_trivial_broadcasting():
def test_passthrough_arguments(doc): def test_passthrough_arguments(doc):
assert doc(m.vec_passthrough) == ( assert doc(m.vec_passthrough) == (
"vec_passthrough(" + ", ".join([ "vec_passthrough("
"arg0: float", + ", ".join(
"arg1: numpy.ndarray[numpy.float64]", [
"arg2: numpy.ndarray[numpy.float64]", "arg0: float",
"arg3: numpy.ndarray[numpy.int32]", "arg1: numpy.ndarray[numpy.float64]",
"arg4: int", "arg2: numpy.ndarray[numpy.float64]",
"arg5: m.numpy_vectorize.NonPODClass", "arg3: numpy.ndarray[numpy.int32]",
"arg6: numpy.ndarray[numpy.float64]"]) + ") -> object") "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 c = np.array([100, 200]) # NOT a vectorized argument
d = np.array([[1000], [2000], [3000]], dtype='int') d = np.array([[1000], [2000], [3000]], dtype="int")
g = np.array([[1000000, 2000000, 3000000]], dtype='int') # requires casting g = np.array([[1000000, 2000000, 3000000]], dtype="int") # requires casting
assert np.all( assert np.all(
m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g) == m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g)
np.array([[1111111, 2111121, 3111131], == np.array(
[1112111, 2112121, 3112131], [
[1113111, 2113121, 3113131]])) [1111111, 2111121, 3111131],
[1112111, 2112121, 3112131],
[1113111, 2113121, 3113131],
]
)
)
def test_method_vectorization(): def test_method_vectorization():
o = m.VectorizeTestClass(3) o = m.VectorizeTestClass(3)
x = np.array([1, 2], dtype='int') x = np.array([1, 2], dtype="int")
y = np.array([[10], [20]], dtype='float32') y = np.array([[10], [20]], dtype="float32")
assert np.all(o.method(x, y) == [[14, 15], [24, 25]]) 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) assert not isinstance(m.vectorized_func(np.array(1), 2, 3), np.ndarray)
z = m.vectorized_func([1], 2, 3) z = m.vectorized_func([1], 2, 3)
assert isinstance(z, np.ndarray) assert isinstance(z, np.ndarray)
assert z.shape == (1, ) assert z.shape == (1,)
z = m.vectorized_func(1, [[[2]]], 3) z = m.vectorized_func(1, [[[2]]], 3)
assert isinstance(z, np.ndarray) assert isinstance(z, np.ndarray)
assert z.shape == (1, 1, 1) assert z.shape == (1, 1, 1)

View File

@ -32,12 +32,15 @@ def test_pointers(msg):
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_void_ptr_value([1, 2, 3]) # This should not work 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: get_void_ptr_value(): incompatible function arguments. The following argument types are supported:
1. (arg0: capsule) -> int 1. (arg0: capsule) -> int
Invoked with: [1, 2, 3] Invoked with: [1, 2, 3]
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
assert m.return_null_str() is None assert m.return_null_str() is None
assert m.get_null_str_value(m.return_null_str()) is not None assert m.get_null_str_value(m.return_null_str()) is not None

View File

@ -56,23 +56,23 @@ def test_operator_overloading():
del v3 del v3
assert cstats.alive() == 0 assert cstats.alive() == 0
assert cstats.values() == [ assert cstats.values() == [
'[1.000000, 2.000000]', "[1.000000, 2.000000]",
'[3.000000, -1.000000]', "[3.000000, -1.000000]",
'[1.000000, 2.000000]', "[1.000000, 2.000000]",
'[-3.000000, 1.000000]', "[-3.000000, 1.000000]",
'[4.000000, 1.000000]', "[4.000000, 1.000000]",
'[-2.000000, 3.000000]', "[-2.000000, 3.000000]",
'[-7.000000, -6.000000]', "[-7.000000, -6.000000]",
'[9.000000, 10.000000]', "[9.000000, 10.000000]",
'[8.000000, 16.000000]', "[8.000000, 16.000000]",
'[0.125000, 0.250000]', "[0.125000, 0.250000]",
'[7.000000, 6.000000]', "[7.000000, 6.000000]",
'[9.000000, 10.000000]', "[9.000000, 10.000000]",
'[8.000000, 16.000000]', "[8.000000, 16.000000]",
'[8.000000, 4.000000]', "[8.000000, 4.000000]",
'[3.000000, -2.000000]', "[3.000000, -2.000000]",
'[3.000000, -0.500000]', "[3.000000, -0.500000]",
'[6.000000, -2.000000]', "[6.000000, -2.000000]",
] ]
assert cstats.default_constructions == 0 assert cstats.default_constructions == 0
assert cstats.copy_constructions == 0 assert cstats.copy_constructions == 0

View File

@ -42,5 +42,6 @@ def test_roundtrip_with_dict(cls_name):
def test_enum_pickle(): def test_enum_pickle():
from pybind11_tests import enums as e from pybind11_tests import enums as e
data = pickle.dumps(e.EOne, 2) data = pickle.dumps(e.EOne, 2)
assert e.EOne == pickle.loads(data) assert e.EOne == pickle.loads(data)

View File

@ -28,13 +28,16 @@ def test_list(capture, doc):
lst.append("value2") lst.append("value2")
m.print_list(lst) m.print_list(lst)
assert capture.unordered == """ assert (
capture.unordered
== """
Entry at position 0: value Entry at position 0: value
list item 0: inserted-0 list item 0: inserted-0
list item 1: overwritten list item 1: overwritten
list item 2: inserted-2 list item 2: inserted-2
list item 3: value2 list item 3: value2
""" """
)
assert doc(m.get_list) == "get_list() -> list" assert doc(m.get_list) == "get_list() -> list"
assert doc(m.print_list) == "print_list(arg0: list) -> None" assert doc(m.print_list) == "print_list(arg0: list) -> None"
@ -52,12 +55,15 @@ def test_set(capture, doc):
with capture: with capture:
s.add("key4") s.add("key4")
m.print_set(s) m.print_set(s)
assert capture.unordered == """ assert (
capture.unordered
== """
key: key1 key: key1
key: key2 key: key2
key: key3 key: key3
key: key4 key: key4
""" """
)
assert not m.set_contains(set([]), 42) assert not m.set_contains(set([]), 42)
assert m.set_contains({42}, 42) assert m.set_contains({42}, 42)
@ -74,10 +80,13 @@ def test_dict(capture, doc):
with capture: with capture:
d["key2"] = "value2" d["key2"] = "value2"
m.print_dict(d) m.print_dict(d)
assert capture.unordered == """ assert (
capture.unordered
== """
key: key, value=value key: key, value=value
key: key2, value=value2 key: key2, value=value2
""" """
)
assert not m.dict_contains({}, 42) assert not m.dict_contains({}, 42)
assert m.dict_contains({42: None}, 42) assert m.dict_contains({42: None}, 42)
@ -137,28 +146,37 @@ def test_capsule(capture):
a = m.return_capsule_with_destructor() a = m.return_capsule_with_destructor()
del a del a
pytest.gc_collect() pytest.gc_collect()
assert capture.unordered == """ assert (
capture.unordered
== """
creating capsule creating capsule
destructing capsule destructing capsule
""" """
)
with capture: with capture:
a = m.return_capsule_with_destructor_2() a = m.return_capsule_with_destructor_2()
del a del a
pytest.gc_collect() pytest.gc_collect()
assert capture.unordered == """ assert (
capture.unordered
== """
creating capsule creating capsule
destructing capsule: 1234 destructing capsule: 1234
""" """
)
with capture: with capture:
a = m.return_capsule_with_name_and_destructor() a = m.return_capsule_with_name_and_destructor()
del a del a
pytest.gc_collect() pytest.gc_collect()
assert capture.unordered == """ assert (
capture.unordered
== """
created capsule (1234, 'pointer type description') created capsule (1234, 'pointer type description')
destructing capsule (1234, 'pointer type description') destructing capsule (1234, 'pointer type description')
""" """
)
def test_accessors(): def test_accessors():
@ -212,7 +230,7 @@ def test_constructors():
assert m.default_constructors() == expected assert m.default_constructors() == expected
data = { data = {
bytes: b'41', # Currently no supported or working conversions. bytes: b"41", # Currently no supported or working conversions.
str: 42, str: 42,
bool: "Not empty", bool: "Not empty",
int: "42", int: "42",
@ -221,14 +239,14 @@ def test_constructors():
list: range(3), list: range(3),
dict: [("two", 2), ("one", 1), ("three", 3)], dict: [("two", 2), ("one", 1), ("three", 3)],
set: [4, 4, 5, 6, 6, 6], set: [4, 4, 5, 6, 6, 6],
memoryview: b'abc' memoryview: b"abc",
} }
inputs = {k.__name__: v for k, v in data.items()} inputs = {k.__name__: v for k, v in data.items()}
expected = {k.__name__: k(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. if env.PY2: # Similar to the above. See comments above.
inputs["bytes"] = b'41' inputs["bytes"] = b"41"
inputs["str"] = 42 inputs["str"] = 42
expected["bytes"] = b'41' expected["bytes"] = b"41"
expected["str"] = u"42" expected["str"] = u"42"
assert m.converting_constructors(inputs) == expected assert m.converting_constructors(inputs) == expected
@ -255,7 +273,8 @@ def test_non_converting_constructors():
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.nonconverting_constructor(t, v) m.nonconverting_constructor(t, v)
expected_error = "Object of type '{}' is not an instance of '{}'".format( 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 assert str(excinfo.value) == expected_error
@ -263,12 +282,12 @@ def test_pybind11_str_raw_str():
# specifically to exercise pybind11::str::raw_str # specifically to exercise pybind11::str::raw_str
cvt = m.convert_to_pybind11_str cvt = m.convert_to_pybind11_str
assert cvt(u"Str") == u"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(None) == u"None"
assert cvt(False) == u"False" assert cvt(False) == u"False"
assert cvt(True) == u"True" assert cvt(True) == u"True"
assert cvt(42) == u"42" 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(-1.50) == u"-1.5"
assert cvt(()) == u"()" assert cvt(()) == u"()"
assert cvt((18,)) == u"(18,)" assert cvt((18,)) == u"(18,)"
@ -283,29 +302,40 @@ def test_pybind11_str_raw_str():
valid_utf8 = valid_orig.encode("utf-8") valid_utf8 = valid_orig.encode("utf-8")
valid_cvt = cvt(valid_utf8) valid_cvt = cvt(valid_utf8)
assert type(valid_cvt) == bytes # Probably surprising. 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) malformed_cvt = cvt(malformed_utf8)
assert type(malformed_cvt) == bytes # Probably surprising. assert type(malformed_cvt) == bytes # Probably surprising.
assert malformed_cvt == b'\x80' assert malformed_cvt == b"\x80"
def test_implicit_casting(): def test_implicit_casting():
"""Tests implicit casting when assigning or appending to dicts and lists.""" """Tests implicit casting when assigning or appending to dicts and lists."""
z = m.get_implicit_casting() z = m.get_implicit_casting()
assert z['d'] == { assert z["d"] == {
'char*_i1': 'abc', 'char*_i2': 'abc', 'char*_e': 'abc', 'char*_p': 'abc', "char*_i1": "abc",
'str_i1': 'str', 'str_i2': 'str1', 'str_e': 'str2', 'str_p': 'str3', "char*_i2": "abc",
'int_i1': 42, 'int_i2': 42, 'int_e': 43, 'int_p': 44 "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): def test_print(capture):
with capture: with capture:
m.print_function() m.print_function()
assert capture == """ assert (
capture
== """
Hello, World! Hello, World!
1 2.0 three True -- multiple args 1 2.0 three True -- multiple args
*args-and-a-custom-separator *args-and-a-custom-separator
@ -313,14 +343,15 @@ def test_print(capture):
flush flush
py::print + str.format = this py::print + str.format = this
""" """
)
assert capture.stderr == "this goes to stderr" assert capture.stderr == "this goes to stderr"
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.print_failure() m.print_failure()
assert str(excinfo.value) == "make_tuple(): unable to convert " + ( assert str(excinfo.value) == "make_tuple(): unable to convert " + (
"argument of type 'UnregisteredType' to Python object" "argument of type 'UnregisteredType' to Python object"
if debug_enabled else if debug_enabled
"arguments to Python object (compile in debug mode for details)" else "arguments to Python object (compile in debug mode for details)"
) )
@ -342,8 +373,23 @@ def test_hash():
def test_number_protocol(): def test_number_protocol():
for a, b in [(1, 1), (3, 5)]: for a, b in [(1, 1), (3, 5)]:
li = [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,
a - b,
a * b,
a / b,
a | b,
a & b,
a ^ b,
a >> b,
a << b,
]
assert m.test_number_protocol(a, b) == li 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) assert "'NoneType' object is not iterable" in str(excinfo.value)
@pytest.mark.parametrize('method, args, fmt, expected_view', [ @pytest.mark.parametrize(
(m.test_memoryview_object, (b'red',), 'B', b'red'), "method, args, fmt, expected_view",
(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_object, (b"red",), "B", b"red"),
(m.test_memoryview_from_buffer, (True,), 'H', [2, 7, 1, 8]), (m.test_memoryview_buffer_info, (b"green",), "B", b"green"),
(m.test_memoryview_from_buffer_nativeformat, (), '@i', [4, 7, 5]), (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): def test_memoryview(method, args, fmt, expected_view):
view = method(*args) view = method(*args)
assert isinstance(view, memoryview) 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.xfail("env.PYPY", reason="getrefcount is not available")
@pytest.mark.parametrize('method', [ @pytest.mark.parametrize(
m.test_memoryview_object, "method",
m.test_memoryview_buffer_info, [
]) m.test_memoryview_object,
m.test_memoryview_buffer_info,
],
)
def test_memoryview_refcount(method): def test_memoryview_refcount(method):
buf = b'\x0a\x0b\x0c\x0d' buf = b"\x0a\x0b\x0c\x0d"
ref_before = sys.getrefcount(buf) ref_before = sys.getrefcount(buf)
view = method(buf) view = method(buf)
ref_after = sys.getrefcount(buf) ref_after = sys.getrefcount(buf)
@ -396,13 +448,13 @@ def test_memoryview_refcount(method):
def test_memoryview_from_buffer_empty_shape(): def test_memoryview_from_buffer_empty_shape():
view = m.test_memoryview_from_buffer_empty_shape() view = m.test_memoryview_from_buffer_empty_shape()
assert isinstance(view, memoryview) assert isinstance(view, memoryview)
assert view.format == 'B' assert view.format == "B"
if env.PY2: if env.PY2:
# Python 2 behavior is weird, but Python 3 (the future) is fine. # Python 2 behavior is weird, but Python 3 (the future) is fine.
# PyPy3 has <memoryview, while CPython 2 has <memory # PyPy3 has <memoryview, while CPython 2 has <memory
assert bytes(view).startswith(b'<memory') assert bytes(view).startswith(b"<memory")
else: else:
assert bytes(view) == b'' assert bytes(view) == b""
def test_test_memoryview_from_buffer_invalid_strides(): def test_test_memoryview_from_buffer_invalid_strides():
@ -422,13 +474,15 @@ def test_test_memoryview_from_buffer_nullptr():
def test_memoryview_from_memory(): def test_memoryview_from_memory():
view = m.test_memoryview_from_memory() view = m.test_memoryview_from_memory()
assert isinstance(view, memoryview) assert isinstance(view, memoryview)
assert view.format == 'B' assert view.format == "B"
assert bytes(view) == b'\xff\xe1\xab\x37' assert bytes(view) == b"\xff\xe1\xab\x37"
def test_builtin_functions(): def test_builtin_functions():
assert m.get_len([i for i in range(42)]) == 42 assert m.get_len([i for i in range(42)]) == 42
with pytest.raises(TypeError) as exc_info: with pytest.raises(TypeError) as exc_info:
m.get_len(i for i in range(42)) m.get_len(i for i in range(42))
assert str(exc_info.value) in ["object of type 'generator' has no len()", assert str(exc_info.value) in [
"'generator' has no length"] # PyPy "object of type 'generator' has no len()",
"'generator' has no length",
] # PyPy

View File

@ -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): 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(): def test_generalized_iterators():
@ -51,7 +53,7 @@ def test_sequence():
cstats = ConstructorStats.get(m.Sequence) cstats = ConstructorStats.get(m.Sequence)
s = m.Sequence(5) s = m.Sequence(5)
assert cstats.values() == ['of size', '5'] assert cstats.values() == ["of size", "5"]
assert "Sequence" in repr(s) assert "Sequence" in repr(s)
assert len(s) == 5 assert len(s) == 5
@ -62,16 +64,16 @@ def test_sequence():
assert isclose(s[0], 12.34) and isclose(s[3], 56.78) assert isclose(s[0], 12.34) and isclose(s[3], 56.78)
rev = reversed(s) rev = reversed(s)
assert cstats.values() == ['of size', '5'] assert cstats.values() == ["of size", "5"]
rev2 = s[::-1] rev2 = s[::-1]
assert cstats.values() == ['of size', '5'] assert cstats.values() == ["of size", "5"]
it = iter(m.Sequence(0)) it = iter(m.Sequence(0))
for _ in range(3): # __next__ must continue to raise StopIteration for _ in range(3): # __next__ must continue to raise StopIteration
with pytest.raises(StopIteration): with pytest.raises(StopIteration):
next(it) next(it)
assert cstats.values() == ['of size', '0'] assert cstats.values() == ["of size", "0"]
expected = [0, 56.78, 0, 0, 12.34] expected = [0, 56.78, 0, 0, 12.34]
assert allclose(rev, expected) assert allclose(rev, expected)
@ -79,7 +81,7 @@ def test_sequence():
assert rev == rev2 assert rev == rev2
rev[0::2] = m.Sequence([2.0, 2.0, 2.0]) 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]) assert allclose(rev, [2, 56.78, 2, 0, 2])
@ -103,10 +105,11 @@ def test_sequence():
def test_sequence_length(): def test_sequence_length():
"""#2076: Exception raised by len(arg) should be propagated """ """#2076: Exception raised by len(arg) should be propagated """
class BadLen(RuntimeError): class BadLen(RuntimeError):
pass pass
class SequenceLike(): class SequenceLike:
def __getitem__(self, i): def __getitem__(self, i):
return None return None
@ -121,17 +124,17 @@ def test_sequence_length():
def test_map_iterator(): def test_map_iterator():
sm = m.StringMap({'hi': 'bye', 'black': 'white'}) sm = m.StringMap({"hi": "bye", "black": "white"})
assert sm['hi'] == 'bye' assert sm["hi"] == "bye"
assert len(sm) == 2 assert len(sm) == 2
assert sm['black'] == 'white' assert sm["black"] == "white"
with pytest.raises(KeyError): with pytest.raises(KeyError):
assert sm['orange'] assert sm["orange"]
sm['orange'] = 'banana' sm["orange"] = "banana"
assert 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: for k in sm:
assert sm[k] == expected[k] assert sm[k] == expected[k]
for k, v in sm.items(): for k, v in sm.items():
@ -179,7 +182,8 @@ def test_iterator_passthrough():
"""#181: iterator passthrough did not compile""" """#181: iterator passthrough did not compile"""
from pybind11_tests.sequences_and_iterators import iterator_passthrough 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(): def test_iterator_rvp():

View File

@ -7,7 +7,9 @@ from pybind11_tests import ConstructorStats # noqa: E402
def test_smart_ptr(capture): def test_smart_ptr(capture):
# Object1 # 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 assert o.getRefCount() == 1
with capture: with capture:
m.print_object_1(o) m.print_object_1(o)
@ -16,8 +18,9 @@ def test_smart_ptr(capture):
m.print_object_4(o) m.print_object_4(o)
assert capture == "MyObject1[{i}]\n".format(i=i) * 4 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], for i, o in enumerate(
start=4): [m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], start=4
):
print(o) print(o)
with capture: with capture:
if not isinstance(o, int): if not isinstance(o, int):
@ -29,11 +32,15 @@ def test_smart_ptr(capture):
m.print_myobject1_2(o) m.print_myobject1_2(o)
m.print_myobject1_3(o) m.print_myobject1_3(o)
m.print_myobject1_4(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) cstats = ConstructorStats.get(m.MyObject1)
assert cstats.alive() == 0 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.values() == expected_values
assert cstats.default_constructions == 0 assert cstats.default_constructions == 0
assert cstats.copy_constructions == 0 assert cstats.copy_constructions == 0
@ -42,7 +49,9 @@ def test_smart_ptr(capture):
assert cstats.move_assignments == 0 assert cstats.move_assignments == 0
# Object2 # 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) print(o)
with capture: with capture:
m.print_myobject2_1(o) m.print_myobject2_1(o)
@ -55,7 +64,7 @@ def test_smart_ptr(capture):
assert cstats.alive() == 1 assert cstats.alive() == 1
o = None o = None
assert cstats.alive() == 0 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.default_constructions == 0
assert cstats.copy_constructions == 0 assert cstats.copy_constructions == 0
# assert cstats.move_constructions >= 0 # Doesn't invoke any # assert cstats.move_constructions >= 0 # Doesn't invoke any
@ -63,7 +72,9 @@ def test_smart_ptr(capture):
assert cstats.move_assignments == 0 assert cstats.move_assignments == 0
# Object3 # 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) print(o)
with capture: with capture:
m.print_myobject3_1(o) m.print_myobject3_1(o)
@ -76,7 +87,7 @@ def test_smart_ptr(capture):
assert cstats.alive() == 1 assert cstats.alive() == 1
o = None o = None
assert cstats.alive() == 0 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.default_constructions == 0
assert cstats.copy_constructions == 0 assert cstats.copy_constructions == 0
# assert cstats.move_constructions >= 0 # Doesn't invoke any # assert cstats.move_constructions >= 0 # Doesn't invoke any
@ -96,7 +107,7 @@ def test_smart_ptr(capture):
# ref<> # ref<>
cstats = m.cstats_ref() cstats = m.cstats_ref()
assert cstats.alive() == 0 assert cstats.alive() == 0
assert cstats.values() == ['from pointer'] * 10 assert cstats.values() == ["from pointer"] * 10
assert cstats.default_constructions == 30 assert cstats.default_constructions == 30
assert cstats.copy_constructions == 12 assert cstats.copy_constructions == 12
# assert cstats.move_constructions >= 0 # Doesn't invoke any # 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) ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
assert stats.alive() == 2 assert stats.alive() == 2
assert s.set_ref(ref) 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) bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
assert stats.alive() == 2 assert stats.alive() == 2
@ -200,12 +213,16 @@ def test_shared_ptr_from_this_and_references():
assert s.set_ref(copy) assert s.set_ref(copy)
assert s.set_holder(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 stats.alive() == 3
assert s.set_ref(holder_ref) assert s.set_ref(holder_ref)
assert s.set_holder(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 stats.alive() == 3
assert s.set_ref(holder_copy) assert s.set_ref(holder_copy)
assert s.set_holder(holder_copy) assert s.set_holder(holder_copy)
@ -277,8 +294,10 @@ def test_smart_ptr_from_default():
instance = m.HeldByDefaultHolder() instance = m.HeldByDefaultHolder()
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.HeldByDefaultHolder.load_shared_ptr(instance) m.HeldByDefaultHolder.load_shared_ptr(instance)
assert "Unable to load a custom holder type from a " \ assert (
"default-holder instance" in str(excinfo.value) "Unable to load a custom holder type from a "
"default-holder instance" in str(excinfo.value)
)
def test_shared_ptr_gc(): def test_shared_ptr_gc():

View File

@ -88,7 +88,7 @@ def test_recursive_casting():
assert m.cast_rv_nested() == [[[{"b": "rvalue", "c": "rvalue"}], [{"a": "rvalue"}]]] assert m.cast_rv_nested() == [[[{"b": "rvalue", "c": "rvalue"}], [{"a": "rvalue"}]]]
assert m.cast_lv_nested() == { assert m.cast_lv_nested() == {
"a": [[["lvalue", "lvalue"]], [["lvalue", "lvalue"]]], "a": [[["lvalue", "lvalue"]], [["lvalue", "lvalue"]]],
"b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]] "b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]],
} }
# Issue #853 test case: # 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] 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(): def test_optional():
assert m.double_or_zero(None) == 0 assert m.double_or_zero(None) == 0
assert m.double_or_zero(42) == 84 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(0) is None
assert m.half_or_none(42) == 21 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() == 42
assert m.test_nullopt(None) == 42 assert m.test_nullopt(None) == 42
@ -134,15 +134,17 @@ def test_optional():
assert holder.member_initialized() 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(): def test_exp_optional():
assert m.double_or_zero_exp(None) == 0 assert m.double_or_zero_exp(None) == 0
assert m.double_or_zero_exp(42) == 84 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(0) is None
assert m.half_or_none_exp(42) == 21 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() == 42
assert m.test_nullopt_exp(None) == 42 assert m.test_nullopt_exp(None) == 42
@ -160,7 +162,7 @@ def test_exp_optional():
assert holder.member_initialized() 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): def test_variant(doc):
assert m.load_variant(1) == "int" assert m.load_variant(1) == "int"
assert m.load_variant("1") == "std::string" assert m.load_variant("1") == "std::string"
@ -172,34 +174,44 @@ def test_variant(doc):
assert m.cast_variant() == (5, "Hello") 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(): def test_vec_of_reference_wrapper():
"""#171: Can't return reference wrappers (or STL structures containing them)""" """#171: Can't return reference wrappers (or STL structures containing them)"""
assert str(m.return_vec_of_reference_wrapper(UserType(4))) == \ assert (
"[UserType(1), UserType(2), UserType(3), UserType(4)]" str(m.return_vec_of_reference_wrapper(UserType(4)))
== "[UserType(1), UserType(2), UserType(3), UserType(4)]"
)
def test_stl_pass_by_pointer(msg): def test_stl_pass_by_pointer(msg):
"""Passing nullptr or None to an STL container pointer is not expected to work""" """Passing nullptr or None to an STL container pointer is not expected to work"""
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.stl_pass_by_pointer() # default value is `nullptr` 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: stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
1. (v: List[int] = None) -> List[int] 1. (v: List[int] = None) -> List[int]
Invoked with: Invoked with:
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.stl_pass_by_pointer(None) 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: stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
1. (v: List[int] = None) -> List[int] 1. (v: List[int] = None) -> List[int]
Invoked with: None Invoked with: None
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3] 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""" <pybind11/stl.h> should result in a helpful suggestion in the error message"""
import pybind11_cross_module_tests as cm import pybind11_cross_module_tests as cm
expected_message = ("Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\n" expected_message = (
"<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\n" "Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\n"
"conversions are optional and require extra headers to be included\n" "<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\n"
"when compiling your pybind11 module.") "conversions are optional and require extra headers to be included\n"
"when compiling your pybind11 module."
)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
cm.missing_header_arg([1.0, 2.0, 3.0]) 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(): def test_function_with_string_and_vector_string_arg():
"""Check if a string is NOT implicitly converted to a list, which was the """Check if a string is NOT implicitly converted to a list, which was the
behavior before fix of issue #1258""" 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', '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") == 3
def test_stl_ownership(): def test_stl_ownership():
@ -247,6 +261,6 @@ def test_array_cast_sequence():
def test_issue_1561(): def test_issue_1561():
""" check fix for issue #1561 """ """ check fix for issue #1561 """
bar = m.Issue1561Outer() bar = m.Issue1561Outer()
bar.list = [m.Issue1561Inner('bar')] bar.list = [m.Issue1561Inner("bar")]
bar.list bar.list
assert bar.list[0].data == 'bar' assert bar.list[0].data == "bar"

View File

@ -45,7 +45,7 @@ def test_vector_int():
# test error handling, and that the vector is unchanged # test error handling, and that the vector is unchanged
with pytest.raises(RuntimeError): 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]) 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 assert mv[2] == 5
mv[2] = 6 mv[2] = 6
else: else:
assert mv[2] == '\x05' assert mv[2] == "\x05"
mv[2] = '\x06' mv[2] = "\x06"
assert v[2] == 6 assert v[2] == 6
if not env.PY2: if not env.PY2:
@ -114,11 +114,17 @@ def test_vector_buffer_numpy():
v = m.get_vectorstruct() v = m.get_vectorstruct()
assert v[0].x == 5 assert v[0].x == 5
ma = np.asarray(v) ma = np.asarray(v)
ma[1]['x'] = 99 ma[1]["x"] = 99
assert v[1].x == 99 assert v[1].x == 99
v = m.VectorStruct(np.zeros(3, dtype=np.dtype([('w', 'bool'), ('x', 'I'), v = m.VectorStruct(
('y', 'float64'), ('z', 'bool')], align=True))) np.zeros(
3,
dtype=np.dtype(
[("w", "bool"), ("x", "I"), ("y", "float64"), ("z", "bool")], align=True
),
)
)
assert len(v) == 3 assert len(v) == 3
b = np.array([1, 2, 3, 4], dtype=np.uint8) b = np.array([1, 2, 3, 4], dtype=np.uint8)
@ -151,31 +157,31 @@ def test_vector_custom():
def test_map_string_double(): def test_map_string_double():
mm = m.MapStringDouble() mm = m.MapStringDouble()
mm['a'] = 1 mm["a"] = 1
mm['b'] = 2.5 mm["b"] = 2.5
assert list(mm) == ['a', 'b'] assert list(mm) == ["a", "b"]
assert list(mm.items()) == [('a', 1), ('b', 2.5)] assert list(mm.items()) == [("a", 1), ("b", 2.5)]
assert str(mm) == "MapStringDouble{a: 1, b: 2.5}" assert str(mm) == "MapStringDouble{a: 1, b: 2.5}"
um = m.UnorderedMapStringDouble() um = m.UnorderedMapStringDouble()
um['ua'] = 1.1 um["ua"] = 1.1
um['ub'] = 2.6 um["ub"] = 2.6
assert sorted(list(um)) == ['ua', 'ub'] assert sorted(list(um)) == ["ua", "ub"]
assert sorted(list(um.items())) == [('ua', 1.1), ('ub', 2.6)] assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)]
assert "UnorderedMapStringDouble" in str(um) assert "UnorderedMapStringDouble" in str(um)
def test_map_string_double_const(): def test_map_string_double_const():
mc = m.MapStringDoubleConst() mc = m.MapStringDoubleConst()
mc['a'] = 10 mc["a"] = 10
mc['b'] = 20.5 mc["b"] = 20.5
assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}" assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}"
umc = m.UnorderedMapStringDoubleConst() umc = m.UnorderedMapStringDoubleConst()
umc['a'] = 11 umc["a"] = 11
umc['b'] = 21.5 umc["b"] = 21.5
str(umc) str(umc)
@ -196,7 +202,7 @@ def test_noncopyable_containers():
i = 1 i = 1
for j in dnc: for j in dnc:
assert(j.value == i) assert j.value == i
i += 1 i += 1
# std::map # std::map
@ -265,21 +271,21 @@ def test_noncopyable_containers():
def test_map_delitem(): def test_map_delitem():
mm = m.MapStringDouble() mm = m.MapStringDouble()
mm['a'] = 1 mm["a"] = 1
mm['b'] = 2.5 mm["b"] = 2.5
assert list(mm) == ['a', 'b'] assert list(mm) == ["a", "b"]
assert list(mm.items()) == [('a', 1), ('b', 2.5)] assert list(mm.items()) == [("a", 1), ("b", 2.5)]
del mm['a'] del mm["a"]
assert list(mm) == ['b'] assert list(mm) == ["b"]
assert list(mm.items()) == [('b', 2.5)] assert list(mm.items()) == [("b", 2.5)]
um = m.UnorderedMapStringDouble() um = m.UnorderedMapStringDouble()
um['ua'] = 1.1 um["ua"] = 1.1
um['ub'] = 2.6 um["ub"] = 2.6
assert sorted(list(um)) == ['ua', 'ub'] assert sorted(list(um)) == ["ua", "ub"]
assert sorted(list(um.items())) == [('ua', 1.1), ('ub', 2.6)] assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)]
del um['ua'] del um["ua"]
assert sorted(list(um)) == ['ub'] assert sorted(list(um)) == ["ub"]
assert sorted(list(um.items())) == [('ub', 2.6)] assert sorted(list(um.items())) == [("ub", 2.6)]

View File

@ -5,16 +5,24 @@ from pybind11_tests import tagbased_polymorphic as m
def test_downcast(): def test_downcast():
zoo = m.create_zoo() zoo = m.create_zoo()
assert [type(animal) for animal in 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] == [ assert [animal.name for animal in zoo] == [
"Fido", "Ginger", "Hertzl", "Tiger", "Leo" "Fido",
"Ginger",
"Hertzl",
"Tiger",
"Leo",
] ]
zoo[1].sound = "woooooo" zoo[1].sound = "woooooo"
assert [dog.bark() for dog in zoo[:3]] == [ assert [dog.bark() for dog in zoo[:3]] == [
"Labrador Fido goes WOOF!", "Labrador Fido goes WOOF!",
"Dog Ginger goes woooooo", "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"] assert [cat.purr() for cat in zoo[3:]] == ["mrowr", "mrrrRRRRRR"]
zoo[0].excitement -= 1000 zoo[0].excitement -= 1000

View File

@ -14,18 +14,18 @@ def test_override(capture, msg):
self.data = "Hello world" self.data = "Hello world"
def run(self, value): 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) return super(ExtendedExampleVirt, self).run(value + 1)
def run_bool(self): def run_bool(self):
print('ExtendedExampleVirt::run_bool()') print("ExtendedExampleVirt::run_bool()")
return False return False
def get_string1(self): def get_string1(self):
return "override1" return "override1"
def pure_virtual(self): def pure_virtual(self):
print('ExtendedExampleVirt::pure_virtual(): %s' % self.data) print("ExtendedExampleVirt::pure_virtual(): %s" % self.data)
class ExtendedExampleVirt2(ExtendedExampleVirt): class ExtendedExampleVirt2(ExtendedExampleVirt):
def __init__(self, state): def __init__(self, state):
@ -37,21 +37,30 @@ def test_override(capture, msg):
ex12 = m.ExampleVirt(10) ex12 = m.ExampleVirt(10)
with capture: with capture:
assert m.runExampleVirt(ex12, 20) == 30 assert m.runExampleVirt(ex12, 20) == 30
assert capture == """ assert (
capture
== """
Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2) Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.runExampleVirtVirtual(ex12) 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) ex12p = ExtendedExampleVirt(10)
with capture: with capture:
assert m.runExampleVirt(ex12p, 20) == 32 assert m.runExampleVirt(ex12p, 20) == 32
assert capture == """ assert (
capture
== """
ExtendedExampleVirt::run(20), calling parent.. ExtendedExampleVirt::run(20), calling parent..
Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2) Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
with capture: with capture:
assert m.runExampleVirtBool(ex12p) is False assert m.runExampleVirtBool(ex12p) is False
assert capture == "ExtendedExampleVirt::run_bool()" assert capture == "ExtendedExampleVirt::run_bool()"
@ -62,16 +71,19 @@ def test_override(capture, msg):
ex12p2 = ExtendedExampleVirt2(15) ex12p2 = ExtendedExampleVirt2(15)
with capture: with capture:
assert m.runExampleVirt(ex12p2, 50) == 68 assert m.runExampleVirt(ex12p2, 50) == 68
assert capture == """ assert (
capture
== """
ExtendedExampleVirt::run(50), calling parent.. ExtendedExampleVirt::run(50), calling parent..
Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2) Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
""" # noqa: E501 line too long """ # noqa: E501 line too long
)
cstats = ConstructorStats.get(m.ExampleVirt) cstats = ConstructorStats.get(m.ExampleVirt)
assert cstats.alive() == 3 assert cstats.alive() == 3
del ex12, ex12p, ex12p2 del ex12, ex12p, ex12p2
assert cstats.alive() == 0 assert cstats.alive() == 0
assert cstats.values() == ['10', '11', '17'] assert cstats.values() == ["10", "11", "17"]
assert cstats.copy_constructions == 0 assert cstats.copy_constructions == 0
assert cstats.move_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 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). bypassed and we only initialize an A() instead (for performance reasons).
""" """
class B(m.A): class B(m.A):
def __init__(self): def __init__(self):
super(B, self).__init__() super(B, self).__init__()
@ -103,12 +116,15 @@ def test_alias_delay_initialization1(capture):
m.call_f(b) m.call_f(b)
del b del b
pytest.gc_collect() pytest.gc_collect()
assert capture == """ assert (
capture
== """
PyA.PyA() PyA.PyA()
PyA.f() PyA.f()
In python f() In python f()
PyA.~PyA() PyA.~PyA()
""" """
)
def test_alias_delay_initialization2(capture): 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 performance penalty, it also allows us to do more things with the trampoline
class such as defining local variables and performing construction/destruction. class such as defining local variables and performing construction/destruction.
""" """
class B2(m.A2): class B2(m.A2):
def __init__(self): def __init__(self):
super(B2, self).__init__() super(B2, self).__init__()
@ -135,7 +152,9 @@ def test_alias_delay_initialization2(capture):
m.call_f(a3) m.call_f(a3)
del a3 del a3
pytest.gc_collect() pytest.gc_collect()
assert capture == """ assert (
capture
== """
PyA2.PyA2() PyA2.PyA2()
PyA2.f() PyA2.f()
A2.f() A2.f()
@ -145,6 +164,7 @@ def test_alias_delay_initialization2(capture):
A2.f() A2.f()
PyA2.~PyA2() PyA2.~PyA2()
""" """
)
# Python subclass version # Python subclass version
with capture: with capture:
@ -152,20 +172,22 @@ def test_alias_delay_initialization2(capture):
m.call_f(b2) m.call_f(b2)
del b2 del b2
pytest.gc_collect() pytest.gc_collect()
assert capture == """ assert (
capture
== """
PyA2.PyA2() PyA2.PyA2()
PyA2.f() PyA2.f()
In python B2.f() In python B2.f()
PyA2.~PyA2() PyA2.~PyA2()
""" """
)
# PyPy: Reference count > 1 causes call with noncopyable instance # PyPy: Reference count > 1 causes call with noncopyable instance
# to fail in ncv1.print_nc() # to fail in ncv1.print_nc()
@pytest.mark.xfail("env.PYPY") @pytest.mark.xfail("env.PYPY")
@pytest.mark.skipif( @pytest.mark.skipif(
not hasattr(m, "NCVirt"), not hasattr(m, "NCVirt"), reason="NCVirt does not work on Intel/PGI/NVCC compilers"
reason="NCVirt does not work on Intel/PGI/NVCC compilers"
) )
def test_move_support(): def test_move_support():
class NCVirtExt(m.NCVirt): class NCVirtExt(m.NCVirt):
@ -205,8 +227,8 @@ def test_move_support():
del ncv1, ncv2 del ncv1, ncv2
assert nc_stats.alive() == 0 assert nc_stats.alive() == 0
assert mv_stats.alive() == 0 assert mv_stats.alive() == 0
assert nc_stats.values() == ['4', '9', '9', '9'] assert nc_stats.values() == ["4", "9", "9", "9"]
assert mv_stats.values() == ['4', '5', '7', '7'] assert mv_stats.values() == ["4", "5", "7", "7"]
assert nc_stats.copy_constructions == 0 assert nc_stats.copy_constructions == 0
assert mv_stats.copy_constructions == 1 assert mv_stats.copy_constructions == 1
assert nc_stats.move_constructions >= 0 assert nc_stats.move_constructions >= 0
@ -215,6 +237,7 @@ def test_move_support():
def test_dispatch_issue(msg): def test_dispatch_issue(msg):
"""#159: virtual function dispatch has problems with similar-named functions""" """#159: virtual function dispatch has problems with similar-named functions"""
class PyClass1(m.DispatchIssue): class PyClass1(m.DispatchIssue):
def dispatch(self): def dispatch(self):
return "Yay.." return "Yay.."
@ -223,7 +246,10 @@ def test_dispatch_issue(msg):
def dispatch(self): def dispatch(self):
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
super(PyClass2, self).dispatch() 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() p = PyClass1()
return m.dispatch_issue_go(p) return m.dispatch_issue_go(p)
@ -339,7 +365,7 @@ def test_inherited_virtuals():
class DT(m.D_Tpl): class DT(m.D_Tpl):
def say_something(self, times): def say_something(self, times):
return "DT says:" + (' quack' * times) return "DT says:" + (" quack" * times)
def unlucky_number(self): def unlucky_number(self):
return 1234 return 1234
@ -355,7 +381,7 @@ def test_inherited_virtuals():
class DT2(DT): class DT2(DT):
def say_something(self, times): def say_something(self, times):
return "DT2: " + ('QUACK' * times) return "DT2: " + ("QUACK" * times)
def unlucky_number(self): def unlucky_number(self):
return -3 return -3