mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-24 22:25:10 +00:00
Python 2 removal part 1: tests (C++ code is intentionally ~untouched) (#3688)
* `#error BYE_BYE_GOLDEN_SNAKE` * Removing everything related to 2.7 from ci.yml * Commenting-out Centos7 * Removing `PYTHON: 27` from .appveyor.yml * "PY2" removal, mainly from tests. C++ code is not touched. * Systematic removal of `u` prefix from `u"..."` and `u'...'` literals. Collateral cleanup of a couple minor other things. * Cleaning up around case-insensitive hits for `[^a-z]py.*2` in tests/. * Removing obsolete Python 2 mention in compiling.rst * Proper `#error` for Python 2. * Using PY_VERSION_HEX to guard `#error "PYTHON 2 IS NO LONGER SUPPORTED.` * chore: bump pre-commit * style: run pre-commit for pyupgrade 3+ * tests: use sys.version_info, not PY * chore: more Python 2 removal * Uncommenting Centos7 block (PR #3691 showed that it is working again). * Update pre-commit hooks * Fix pre-commit hook * refactor: remove Python 2 from CMake * refactor: remove Python 2 from setup code * refactor: simplify, better static typing * feat: fail with nice messages * refactor: drop Python 2 C++ code * docs: cleanup for Python 3 * revert: intree revert: intree * docs: minor touchup to py2 statement Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com> Co-authored-by: Aaron Gokaslan <skylion.aaron@gmail.com>
This commit is contained in:
parent
46dcd9bc75
commit
6493f496e3
@ -11,8 +11,6 @@ environment:
|
|||||||
matrix:
|
matrix:
|
||||||
- PYTHON: 36
|
- PYTHON: 36
|
||||||
CONFIG: Debug
|
CONFIG: Debug
|
||||||
- PYTHON: 27
|
|
||||||
CONFIG: Debug
|
|
||||||
install:
|
install:
|
||||||
- ps: |
|
- ps: |
|
||||||
$env:CMAKE_GENERATOR = "Visual Studio 14 2015"
|
$env:CMAKE_GENERATOR = "Visual Studio 14 2015"
|
||||||
|
27
.github/workflows/ci.yml
vendored
27
.github/workflows/ci.yml
vendored
@ -25,7 +25,6 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
runs-on: [ubuntu-latest, windows-2022, macos-latest]
|
runs-on: [ubuntu-latest, windows-2022, macos-latest]
|
||||||
python:
|
python:
|
||||||
- '2.7'
|
|
||||||
- '3.5'
|
- '3.5'
|
||||||
- '3.6'
|
- '3.6'
|
||||||
- '3.9'
|
- '3.9'
|
||||||
@ -49,13 +48,9 @@ jobs:
|
|||||||
python: '3.6'
|
python: '3.6'
|
||||||
args: >
|
args: >
|
||||||
-DPYBIND11_FINDPYTHON=ON
|
-DPYBIND11_FINDPYTHON=ON
|
||||||
- runs-on: macos-latest
|
|
||||||
python: 'pypy-2.7'
|
|
||||||
# Inject a couple Windows 2019 runs
|
# Inject a couple Windows 2019 runs
|
||||||
- runs-on: windows-2019
|
- runs-on: windows-2019
|
||||||
python: '3.9'
|
python: '3.9'
|
||||||
- runs-on: windows-2019
|
|
||||||
python: '2.7'
|
|
||||||
|
|
||||||
name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}"
|
name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}"
|
||||||
runs-on: ${{ matrix.runs-on }}
|
runs-on: ${{ matrix.runs-on }}
|
||||||
@ -168,22 +163,6 @@ jobs:
|
|||||||
- name: Interface test
|
- name: Interface test
|
||||||
run: cmake --build build2 --target test_cmake_build
|
run: cmake --build build2 --target test_cmake_build
|
||||||
|
|
||||||
# Eventually Microsoft might have an action for setting up
|
|
||||||
# MSVC, but for now, this action works:
|
|
||||||
- name: Prepare compiler environment for Windows 🐍 2.7
|
|
||||||
if: matrix.python == 2.7 && runner.os == 'Windows'
|
|
||||||
uses: ilammy/msvc-dev-cmd@v1.10.0
|
|
||||||
with:
|
|
||||||
arch: x64
|
|
||||||
|
|
||||||
# This makes two environment variables available in the following step(s)
|
|
||||||
- name: Set Windows 🐍 2.7 environment variables
|
|
||||||
if: matrix.python == 2.7 && runner.os == 'Windows'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "DISTUTILS_USE_SDK=1" >> $GITHUB_ENV
|
|
||||||
echo "MSSdk=1" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
# This makes sure the setup_helpers module can build packages using
|
# This makes sure the setup_helpers module can build packages using
|
||||||
# setuptools
|
# setuptools
|
||||||
- name: Setuptools helpers test
|
- name: Setuptools helpers test
|
||||||
@ -784,7 +763,6 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python:
|
python:
|
||||||
- 2.7
|
|
||||||
- 3.6
|
- 3.6
|
||||||
- 3.7
|
- 3.7
|
||||||
# todo: check/cpptest does not support 3.8+ yet
|
# todo: check/cpptest does not support 3.8+ yet
|
||||||
@ -832,17 +810,12 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python:
|
python:
|
||||||
- 2.7
|
|
||||||
- 3.5
|
- 3.5
|
||||||
- 3.7
|
- 3.7
|
||||||
std:
|
std:
|
||||||
- 14
|
- 14
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- python: 2.7
|
|
||||||
std: 17
|
|
||||||
args: >
|
|
||||||
-DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR"
|
|
||||||
- python: 3.7
|
- python: 3.7
|
||||||
std: 17
|
std: 17
|
||||||
args: >
|
args: >
|
||||||
|
8
.github/workflows/pip.yml
vendored
8
.github/workflows/pip.yml
vendored
@ -17,19 +17,19 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# This builds the sdists and wheels and makes sure the files are exactly as
|
# This builds the sdists and wheels and makes sure the files are exactly as
|
||||||
# expected. Using Windows and Python 2.7, since that is often the most
|
# expected. Using Windows and Python 3.6, since that is often the most
|
||||||
# challenging matrix element.
|
# challenging matrix element.
|
||||||
test-packaging:
|
test-packaging:
|
||||||
name: 🐍 2.7 • 📦 tests • windows-latest
|
name: 🐍 3.6 • 📦 tests • windows-latest
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Setup 🐍 2.7
|
- name: Setup 🐍 3.6
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 2.7
|
python-version: 3.6
|
||||||
|
|
||||||
- name: Prepare env
|
- name: Prepare env
|
||||||
run: |
|
run: |
|
||||||
|
@ -29,14 +29,15 @@ repos:
|
|||||||
- id: mixed-line-ending
|
- id: mixed-line-ending
|
||||||
- id: requirements-txt-fixer
|
- id: requirements-txt-fixer
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: fix-encoding-pragma
|
|
||||||
exclude: ^noxfile.py$
|
|
||||||
|
|
||||||
|
# Upgrade old Python syntax
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v2.31.0
|
rev: v2.31.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
|
args: [--py3-plus]
|
||||||
|
|
||||||
|
# Nicely sort includes
|
||||||
- repo: https://github.com/PyCQA/isort
|
- repo: https://github.com/PyCQA/isort
|
||||||
rev: 5.10.1
|
rev: 5.10.1
|
||||||
hooks:
|
hooks:
|
||||||
@ -44,20 +45,21 @@ repos:
|
|||||||
|
|
||||||
# Black, the code formatter, natively supports pre-commit
|
# Black, the code formatter, natively supports pre-commit
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 21.12b0 # Keep in sync with blacken-docs
|
rev: 22.1.0 # Keep in sync with blacken-docs
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
|
|
||||||
|
# Also code format the docs
|
||||||
- repo: https://github.com/asottile/blacken-docs
|
- repo: https://github.com/asottile/blacken-docs
|
||||||
rev: v1.12.0
|
rev: v1.12.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: blacken-docs
|
- id: blacken-docs
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
- black==21.12b0 # keep in sync with black hook
|
- black==22.1.0 # keep in sync with black hook
|
||||||
|
|
||||||
# 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
|
||||||
rev: v1.1.10
|
rev: v1.1.11
|
||||||
hooks:
|
hooks:
|
||||||
- id: remove-tabs
|
- id: remove-tabs
|
||||||
|
|
||||||
@ -67,12 +69,15 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: pycln
|
- id: pycln
|
||||||
|
|
||||||
|
# Checking for common mistakes
|
||||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||||
rev: v1.9.0
|
rev: v1.9.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: python-check-blanket-noqa
|
- id: python-check-blanket-noqa
|
||||||
- id: python-check-blanket-type-ignore
|
- id: python-check-blanket-type-ignore
|
||||||
- id: python-no-log-warn
|
- id: python-no-log-warn
|
||||||
|
# Python 3.6
|
||||||
|
# - id: python-use-type-annotations
|
||||||
- id: rst-backticks
|
- id: rst-backticks
|
||||||
- id: rst-directive-colons
|
- id: rst-directive-colons
|
||||||
- id: rst-inline-touching-normal
|
- id: rst-inline-touching-normal
|
||||||
@ -87,6 +92,7 @@ repos:
|
|||||||
- pep8-naming
|
- pep8-naming
|
||||||
exclude: ^(docs/.*|tools/.*)$
|
exclude: ^(docs/.*|tools/.*)$
|
||||||
|
|
||||||
|
# Automatically remove noqa that are not used
|
||||||
- repo: https://github.com/asottile/yesqa
|
- repo: https://github.com/asottile/yesqa
|
||||||
rev: v1.3.0
|
rev: v1.3.0
|
||||||
hooks:
|
hooks:
|
||||||
@ -107,9 +113,9 @@ repos:
|
|||||||
rev: v0.931
|
rev: v0.931
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
# Running per-file misbehaves a bit, so just run on all files, it's fast
|
args: [--show-error-codes]
|
||||||
pass_filenames: false
|
exclude: ^(tests|docs)/
|
||||||
additional_dependencies: [typed_ast]
|
additional_dependencies: [nox, rich]
|
||||||
|
|
||||||
# Checks the manifest for missing files (native support)
|
# Checks the manifest for missing files (native support)
|
||||||
- repo: https://github.com/mgedmin/check-manifest
|
- repo: https://github.com/mgedmin/check-manifest
|
||||||
@ -120,6 +126,7 @@ repos:
|
|||||||
stages: [manual]
|
stages: [manual]
|
||||||
additional_dependencies: [cmake, ninja]
|
additional_dependencies: [cmake, ninja]
|
||||||
|
|
||||||
|
# Check for spelling
|
||||||
- repo: https://github.com/codespell-project/codespell
|
- repo: https://github.com/codespell-project/codespell
|
||||||
rev: v2.1.0
|
rev: v2.1.0
|
||||||
hooks:
|
hooks:
|
||||||
@ -127,20 +134,22 @@ repos:
|
|||||||
exclude: ".supp$"
|
exclude: ".supp$"
|
||||||
args: ["-L", "nd,ot,thist"]
|
args: ["-L", "nd,ot,thist"]
|
||||||
|
|
||||||
|
# Check for common shell mistakes
|
||||||
- repo: https://github.com/shellcheck-py/shellcheck-py
|
- repo: https://github.com/shellcheck-py/shellcheck-py
|
||||||
rev: v0.8.0.3
|
rev: v0.8.0.4
|
||||||
hooks:
|
hooks:
|
||||||
- id: shellcheck
|
- id: shellcheck
|
||||||
|
|
||||||
# The original pybind11 checks for a few C++ style items
|
# Disallow some common capitalization mistakes
|
||||||
- repo: local
|
- repo: local
|
||||||
hooks:
|
hooks:
|
||||||
- id: disallow-caps
|
- id: disallow-caps
|
||||||
name: Disallow improper capitalization
|
name: Disallow improper capitalization
|
||||||
language: pygrep
|
language: pygrep
|
||||||
entry: PyBind|Numpy|Cmake|CCache|PyTest
|
entry: PyBind|Numpy|Cmake|CCache|PyTest
|
||||||
exclude: .pre-commit-config.yaml
|
exclude: ^\.pre-commit-config.yaml$
|
||||||
|
|
||||||
|
# Clang format the codebase automatically
|
||||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
rev: "v13.0.0"
|
rev: "v13.0.0"
|
||||||
hooks:
|
hooks:
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
recursive-include pybind11/include/pybind11 *.h
|
recursive-include pybind11/include/pybind11 *.h
|
||||||
recursive-include pybind11 *.py
|
recursive-include pybind11 *.py
|
||||||
recursive-include pybind11 py.typed
|
recursive-include pybind11 py.typed
|
||||||
recursive-include pybind11 *.pyi
|
|
||||||
include pybind11/share/cmake/pybind11/*.cmake
|
include pybind11/share/cmake/pybind11/*.cmake
|
||||||
include LICENSE README.rst pyproject.toml setup.py setup.cfg
|
include LICENSE README.rst pyproject.toml setup.py setup.cfg
|
||||||
|
@ -34,7 +34,7 @@ dependency.
|
|||||||
Think of this library as a tiny self-contained version of Boost.Python
|
Think of this library as a tiny self-contained version of Boost.Python
|
||||||
with everything stripped away that isn’t relevant for binding
|
with everything stripped away that isn’t relevant for binding
|
||||||
generation. Without comments, the core header files only require ~4K
|
generation. Without comments, the core header files only require ~4K
|
||||||
lines of code and depend on Python (2.7 or 3.5+, or PyPy) and the C++
|
lines of code and depend on Python (3.5+, or PyPy) and the C++
|
||||||
standard library. This compact implementation was possible thanks to
|
standard library. This compact implementation was possible thanks to
|
||||||
some of the new C++11 language features (specifically: tuples, lambda
|
some of the new C++11 language features (specifically: tuples, lambda
|
||||||
functions and variadic templates). Since its creation, this library has
|
functions and variadic templates). Since its creation, this library has
|
||||||
@ -78,8 +78,8 @@ Goodies
|
|||||||
In addition to the core functionality, pybind11 provides some extra
|
In addition to the core functionality, pybind11 provides some extra
|
||||||
goodies:
|
goodies:
|
||||||
|
|
||||||
- Python 2.7, 3.5+, and PyPy/PyPy3 7.3 are supported with an
|
- Python 3.5+, and PyPy3 7.3 are supported with an implementation-agnostic
|
||||||
implementation-agnostic interface.
|
interface (pybind11 2.9 was the last version to support Python 2).
|
||||||
|
|
||||||
- It is possible to bind C++11 lambda functions with captured
|
- It is possible to bind C++11 lambda functions with captured
|
||||||
variables. The lambda capture data is stored inside the resulting
|
variables. The lambda capture data is stored inside the resulting
|
||||||
|
@ -18,5 +18,4 @@ ALIASES += "endrst=\endverbatim"
|
|||||||
QUIET = YES
|
QUIET = YES
|
||||||
WARNINGS = YES
|
WARNINGS = YES
|
||||||
WARN_IF_UNDOCUMENTED = NO
|
WARN_IF_UNDOCUMENTED = NO
|
||||||
PREDEFINED = PY_MAJOR_VERSION=3 \
|
PREDEFINED = PYBIND11_NOINLINE
|
||||||
PYBIND11_NOINLINE
|
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
Strings, bytes and Unicode conversions
|
Strings, bytes and Unicode conversions
|
||||||
######################################
|
######################################
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
This section discusses string handling in terms of Python 3 strings. For
|
|
||||||
Python 2.7, replace all occurrences of ``str`` with ``unicode`` and
|
|
||||||
``bytes`` with ``str``. Python 2.7 users may find it best to use ``from
|
|
||||||
__future__ import unicode_literals`` to avoid unintentionally using ``str``
|
|
||||||
instead of ``unicode``.
|
|
||||||
|
|
||||||
Passing Python strings to C++
|
Passing Python strings to C++
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
@ -58,9 +50,9 @@ Passing bytes to C++
|
|||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
A Python ``bytes`` object will be passed to C++ functions that accept
|
A Python ``bytes`` object will be passed to C++ functions that accept
|
||||||
``std::string`` or ``char*`` *without* conversion. On Python 3, in order to
|
``std::string`` or ``char*`` *without* conversion. In order to make a function
|
||||||
make a function *only* accept ``bytes`` (and not ``str``), declare it as taking
|
*only* accept ``bytes`` (and not ``str``), declare it as taking a ``py::bytes``
|
||||||
a ``py::bytes`` argument.
|
argument.
|
||||||
|
|
||||||
|
|
||||||
Returning C++ strings to Python
|
Returning C++ strings to Python
|
||||||
@ -204,11 +196,6 @@ decoded to Python ``str``.
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
Wide character strings may not work as described on Python 2.7 or Python
|
|
||||||
3.3 compiled with ``--enable-unicode=ucs2``.
|
|
||||||
|
|
||||||
Strings in multibyte encodings such as Shift-JIS must transcoded to a
|
Strings in multibyte encodings such as Shift-JIS must transcoded to a
|
||||||
UTF-8/16/32 before being returned to Python.
|
UTF-8/16/32 before being returned to Python.
|
||||||
|
|
||||||
|
@ -133,14 +133,14 @@ a virtual method call.
|
|||||||
>>> from example import *
|
>>> from example import *
|
||||||
>>> d = Dog()
|
>>> d = Dog()
|
||||||
>>> call_go(d)
|
>>> call_go(d)
|
||||||
u'woof! woof! woof! '
|
'woof! woof! woof! '
|
||||||
>>> class Cat(Animal):
|
>>> class Cat(Animal):
|
||||||
... def go(self, n_times):
|
... def go(self, n_times):
|
||||||
... return "meow! " * n_times
|
... return "meow! " * n_times
|
||||||
...
|
...
|
||||||
>>> c = Cat()
|
>>> c = Cat()
|
||||||
>>> call_go(c)
|
>>> call_go(c)
|
||||||
u'meow! meow! meow! '
|
'meow! meow! meow! '
|
||||||
|
|
||||||
If you are defining a custom constructor in a derived Python class, you *must*
|
If you are defining a custom constructor in a derived Python class, you *must*
|
||||||
ensure that you explicitly call the bound C++ constructor using ``__init__``,
|
ensure that you explicitly call the bound C++ constructor using ``__init__``,
|
||||||
@ -813,26 +813,21 @@ An instance can now be pickled as follows:
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
try:
|
import pickle
|
||||||
import cPickle as pickle # Use cPickle on Python 2.7
|
|
||||||
except ImportError:
|
|
||||||
import pickle
|
|
||||||
|
|
||||||
p = Pickleable("test_value")
|
p = Pickleable("test_value")
|
||||||
p.setExtra(15)
|
p.setExtra(15)
|
||||||
data = pickle.dumps(p, 2)
|
data = pickle.dumps(p)
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Note that only the cPickle module is supported on Python 2.7.
|
If given, the second argument to ``dumps`` must be 2 or larger - 0 and 1 are
|
||||||
|
not supported. Newer versions are also fine; for instance, specify ``-1`` to
|
||||||
The second argument to ``dumps`` is also crucial: it selects the pickle
|
always use the latest available version. Beware: failure to follow these
|
||||||
protocol version 2, since the older version 1 is not supported. Newer
|
instructions will cause important pybind11 memory allocation routines to be
|
||||||
versions are also fine—for instance, specify ``-1`` to always use the
|
skipped during unpickling, which will likely lead to memory corruption
|
||||||
latest available version. Beware: failure to follow these instructions
|
and/or segmentation faults. Python defaults to version 3 (Python 3-3.7) and
|
||||||
will cause important pybind11 memory allocation routines to be skipped
|
version 4 for Python 3.8+.
|
||||||
during unpickling, which will likely lead to memory corruption and/or
|
|
||||||
segmentation faults.
|
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
@ -849,11 +844,9 @@ Python normally uses references in assignments. Sometimes a real copy is needed
|
|||||||
to prevent changing all copies. The ``copy`` module [#f5]_ provides these
|
to prevent changing all copies. The ``copy`` module [#f5]_ provides these
|
||||||
capabilities.
|
capabilities.
|
||||||
|
|
||||||
On Python 3, a class with pickle support is automatically also (deep)copy
|
A class with pickle support is automatically also (deep)copy
|
||||||
compatible. However, performance can be improved by adding custom
|
compatible. However, performance can be improved by adding custom
|
||||||
``__copy__`` and ``__deepcopy__`` methods. With Python 2.7, these custom methods
|
``__copy__`` and ``__deepcopy__`` methods.
|
||||||
are mandatory for (deep)copy compatibility, because pybind11 only supports
|
|
||||||
cPickle.
|
|
||||||
|
|
||||||
For simple classes (deep)copy can be enabled by using the copy constructor,
|
For simple classes (deep)copy can be enabled by using the copy constructor,
|
||||||
which should look as follows:
|
which should look as follows:
|
||||||
|
@ -328,8 +328,8 @@ an invalid state.
|
|||||||
Chaining exceptions ('raise from')
|
Chaining exceptions ('raise from')
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
In Python 3.3 a mechanism for indicating that exceptions were caused by other
|
Python has a mechanism for indicating that exceptions were caused by other
|
||||||
exceptions was introduced:
|
exceptions:
|
||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: py
|
||||||
|
|
||||||
@ -340,7 +340,7 @@ exceptions was introduced:
|
|||||||
|
|
||||||
To do a similar thing in pybind11, you can use the ``py::raise_from`` function. It
|
To do a similar thing in pybind11, you can use the ``py::raise_from`` function. It
|
||||||
sets the current python error indicator, so to continue propagating the exception
|
sets the current python error indicator, so to continue propagating the exception
|
||||||
you should ``throw py::error_already_set()`` (Python 3 only).
|
you should ``throw py::error_already_set()``.
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
@ -398,8 +398,6 @@ Ellipsis
|
|||||||
Python 3 provides a convenient ``...`` ellipsis notation that is often used to
|
Python 3 provides a convenient ``...`` ellipsis notation that is often used to
|
||||||
slice multidimensional arrays. For instance, the following snippet extracts the
|
slice multidimensional arrays. For instance, the following snippet extracts the
|
||||||
middle dimensions of a tensor with the first and last index set to zero.
|
middle dimensions of a tensor with the first and last index set to zero.
|
||||||
In Python 2, the syntactic sugar ``...`` is not available, but the singleton
|
|
||||||
``Ellipsis`` (of type ``ellipsis``) can still be used directly.
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@ -414,8 +412,6 @@ operation on the C++ side:
|
|||||||
py::array a = /* A NumPy array */;
|
py::array a = /* A NumPy array */;
|
||||||
py::array b = a[py::make_tuple(0, py::ellipsis(), 0)];
|
py::array b = a[py::make_tuple(0, py::ellipsis(), 0)];
|
||||||
|
|
||||||
.. versionchanged:: 2.6
|
|
||||||
``py::ellipsis()`` is now also available in Python 2.
|
|
||||||
|
|
||||||
Memory view
|
Memory view
|
||||||
===========
|
===========
|
||||||
@ -455,9 +451,5 @@ We can also use ``memoryview::from_memory`` for a simple 1D contiguous buffer:
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
``memoryview::from_memory`` is not available in Python 2.
|
|
||||||
|
|
||||||
.. versionchanged:: 2.6
|
.. versionchanged:: 2.6
|
||||||
``memoryview::from_memory`` added.
|
``memoryview::from_memory`` added.
|
||||||
|
@ -166,12 +166,12 @@ load and execute the example:
|
|||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
$ python
|
$ python
|
||||||
Python 2.7.10 (default, Aug 22 2015, 20:33:39)
|
Python 3.9.10 (main, Jan 15 2022, 11:48:04)
|
||||||
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.1)] on darwin
|
[Clang 13.0.0 (clang-1300.0.29.3)] on darwin
|
||||||
Type "help", "copyright", "credits" or "license" for more information.
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
>>> import example
|
>>> import example
|
||||||
>>> example.add(1, 2)
|
>>> example.add(1, 2)
|
||||||
3L
|
3
|
||||||
>>>
|
>>>
|
||||||
|
|
||||||
.. _keyword_args:
|
.. _keyword_args:
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
@ -75,7 +74,7 @@ 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()
|
||||||
|
@ -48,10 +48,10 @@ interactive Python session demonstrating this example is shown below:
|
|||||||
>>> print(p)
|
>>> print(p)
|
||||||
<example.Pet object at 0x10cd98060>
|
<example.Pet object at 0x10cd98060>
|
||||||
>>> p.getName()
|
>>> p.getName()
|
||||||
u'Molly'
|
'Molly'
|
||||||
>>> p.setName("Charly")
|
>>> p.setName("Charly")
|
||||||
>>> p.getName()
|
>>> p.getName()
|
||||||
u'Charly'
|
'Charly'
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
@ -124,10 +124,10 @@ This makes it possible to write
|
|||||||
|
|
||||||
>>> p = example.Pet("Molly")
|
>>> p = example.Pet("Molly")
|
||||||
>>> p.name
|
>>> p.name
|
||||||
u'Molly'
|
'Molly'
|
||||||
>>> p.name = "Charly"
|
>>> p.name = "Charly"
|
||||||
>>> p.name
|
>>> p.name
|
||||||
u'Charly'
|
'Charly'
|
||||||
|
|
||||||
Now suppose that ``Pet::name`` was a private internal variable
|
Now suppose that ``Pet::name`` was a private internal variable
|
||||||
that can only be accessed via setters and getters.
|
that can only be accessed via setters and getters.
|
||||||
@ -282,9 +282,9 @@ expose fields and methods of both types:
|
|||||||
|
|
||||||
>>> p = example.Dog("Molly")
|
>>> p = example.Dog("Molly")
|
||||||
>>> p.name
|
>>> p.name
|
||||||
u'Molly'
|
'Molly'
|
||||||
>>> p.bark()
|
>>> p.bark()
|
||||||
u'woof!'
|
'woof!'
|
||||||
|
|
||||||
The C++ classes defined above are regular non-polymorphic types with an
|
The C++ classes defined above are regular non-polymorphic types with an
|
||||||
inheritance relationship. This is reflected in Python:
|
inheritance relationship. This is reflected in Python:
|
||||||
@ -332,7 +332,7 @@ will automatically recognize this:
|
|||||||
>>> type(p)
|
>>> type(p)
|
||||||
PolymorphicDog # automatically downcast
|
PolymorphicDog # automatically downcast
|
||||||
>>> p.bark()
|
>>> p.bark()
|
||||||
u'woof!'
|
'woof!'
|
||||||
|
|
||||||
Given a pointer to a polymorphic base, pybind11 performs automatic downcasting
|
Given a pointer to a polymorphic base, pybind11 performs automatic downcasting
|
||||||
to the actual derived type. Note that this goes beyond the usual situation in
|
to the actual derived type. Note that this goes beyond the usual situation in
|
||||||
|
@ -462,11 +462,8 @@ available in all modes. The targets provided are:
|
|||||||
``pybind11::headers``
|
``pybind11::headers``
|
||||||
Just the pybind11 headers and minimum compile requirements
|
Just the pybind11 headers and minimum compile requirements
|
||||||
|
|
||||||
``pybind11::python2_no_register``
|
|
||||||
Quiets the warning/error when mixing C++14 or higher and Python 2
|
|
||||||
|
|
||||||
``pybind11::pybind11``
|
``pybind11::pybind11``
|
||||||
Python headers + ``pybind11::headers`` + ``pybind11::python2_no_register`` (Python 2 only)
|
Python headers + ``pybind11::headers``
|
||||||
|
|
||||||
``pybind11::python_link_helper``
|
``pybind11::python_link_helper``
|
||||||
Just the "linking" part of pybind11:module
|
Just the "linking" part of pybind11:module
|
||||||
@ -577,21 +574,12 @@ On Linux, you can compile an example such as the one given in
|
|||||||
|
|
||||||
$ c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
|
$ c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
|
||||||
|
|
||||||
The flags given here assume that you're using Python 3. For Python 2, just
|
|
||||||
change the executable appropriately (to ``python`` or ``python2``).
|
|
||||||
|
|
||||||
The ``python3 -m pybind11 --includes`` command fetches the include paths for
|
The ``python3 -m pybind11 --includes`` command fetches the include paths for
|
||||||
both pybind11 and Python headers. This assumes that pybind11 has been installed
|
both pybind11 and Python headers. This assumes that pybind11 has been installed
|
||||||
using ``pip`` or ``conda``. If it hasn't, you can also manually specify
|
using ``pip`` or ``conda``. If it hasn't, you can also manually specify
|
||||||
``-I <path-to-pybind11>/include`` together with the Python includes path
|
``-I <path-to-pybind11>/include`` together with the Python includes path
|
||||||
``python3-config --includes``.
|
``python3-config --includes``.
|
||||||
|
|
||||||
Note that Python 2.7 modules don't use a special suffix, so you should simply
|
|
||||||
use ``example.so`` instead of ``example$(python3-config --extension-suffix)``.
|
|
||||||
Besides, the ``--extension-suffix`` option may or may not be available, depending
|
|
||||||
on the distribution; in the latter case, the module extension can be manually
|
|
||||||
set to ``.so``.
|
|
||||||
|
|
||||||
On macOS: the build command is almost the same but it also requires passing
|
On macOS: the build command is almost the same but it also requires passing
|
||||||
the ``-undefined dynamic_lookup`` flag so as to ignore missing symbols when
|
the ``-undefined dynamic_lookup`` flag so as to ignore missing symbols when
|
||||||
building the module:
|
building the module:
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# pybind11 documentation build configuration file, created by
|
# pybind11 documentation build configuration file, created by
|
||||||
# sphinx-quickstart on Sun Oct 11 19:23:48 2015.
|
# sphinx-quickstart on Sun Oct 11 19:23:48 2015.
|
||||||
|
26
docs/faq.rst
26
docs/faq.rst
@ -8,9 +8,7 @@ Frequently asked questions
|
|||||||
filename of the extension library (without suffixes such as ``.so``).
|
filename of the extension library (without suffixes such as ``.so``).
|
||||||
|
|
||||||
2. If the above did not fix the issue, you are likely using an incompatible
|
2. If the above did not fix the issue, you are likely using an incompatible
|
||||||
version of Python (for instance, the extension library was compiled against
|
version of Python that does not match what you compiled with.
|
||||||
Python 2, while the interpreter is running on top of some version of Python
|
|
||||||
3, or vice versa).
|
|
||||||
|
|
||||||
"Symbol not found: ``__Py_ZeroStruct`` / ``_PyInstanceMethod_Type``"
|
"Symbol not found: ``__Py_ZeroStruct`` / ``_PyInstanceMethod_Type``"
|
||||||
========================================================================
|
========================================================================
|
||||||
@ -289,27 +287,7 @@ Conflicts can arise, however, when using pybind11 in a project that *also* uses
|
|||||||
the CMake Python detection in a system with several Python versions installed.
|
the CMake Python detection in a system with several Python versions installed.
|
||||||
|
|
||||||
This difference may cause inconsistencies and errors if *both* mechanisms are
|
This difference may cause inconsistencies and errors if *both* mechanisms are
|
||||||
used in the same project. Consider the following CMake code executed in a
|
used in the same project.
|
||||||
system with Python 2.7 and 3.x installed:
|
|
||||||
|
|
||||||
.. code-block:: cmake
|
|
||||||
|
|
||||||
find_package(PythonInterp)
|
|
||||||
find_package(PythonLibs)
|
|
||||||
find_package(pybind11)
|
|
||||||
|
|
||||||
It will detect Python 2.7 and pybind11 will pick it as well.
|
|
||||||
|
|
||||||
In contrast this code:
|
|
||||||
|
|
||||||
.. code-block:: cmake
|
|
||||||
|
|
||||||
find_package(pybind11)
|
|
||||||
find_package(PythonInterp)
|
|
||||||
find_package(PythonLibs)
|
|
||||||
|
|
||||||
will detect Python 3.x for pybind11 and may crash on
|
|
||||||
``find_package(PythonLibs)`` afterwards.
|
|
||||||
|
|
||||||
There are three possible solutions:
|
There are three possible solutions:
|
||||||
|
|
||||||
|
@ -325,7 +325,7 @@ public:
|
|||||||
res = 0; // None is implicitly converted to False
|
res = 0; // None is implicitly converted to False
|
||||||
}
|
}
|
||||||
#if defined(PYPY_VERSION)
|
#if defined(PYPY_VERSION)
|
||||||
// On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr exists
|
// On PyPy, check that "__bool__" attr exists
|
||||||
else if (hasattr(src, PYBIND11_BOOL_ATTR)) {
|
else if (hasattr(src, PYBIND11_BOOL_ATTR)) {
|
||||||
res = PyObject_IsTrue(src.ptr());
|
res = PyObject_IsTrue(src.ptr());
|
||||||
}
|
}
|
||||||
@ -375,37 +375,16 @@ struct string_caster {
|
|||||||
static constexpr size_t UTF_N = 8 * sizeof(CharT);
|
static constexpr size_t UTF_N = 8 * sizeof(CharT);
|
||||||
|
|
||||||
bool load(handle src, bool) {
|
bool load(handle src, bool) {
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
object temp;
|
|
||||||
#endif
|
|
||||||
handle load_src = src;
|
handle load_src = src;
|
||||||
if (!src) {
|
if (!src) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!PyUnicode_Check(load_src.ptr())) {
|
if (!PyUnicode_Check(load_src.ptr())) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
return load_bytes(load_src);
|
return load_bytes(load_src);
|
||||||
#else
|
|
||||||
if (std::is_same<CharT, char>::value) {
|
|
||||||
return load_bytes(load_src);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false
|
|
||||||
if (!PYBIND11_BYTES_CHECK(load_src.ptr()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
temp = reinterpret_steal<object>(PyUnicode_FromObject(load_src.ptr()));
|
|
||||||
if (!temp) {
|
|
||||||
PyErr_Clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
load_src = temp;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
// For UTF-8 we avoid the need for a temporary `bytes` object by using
|
||||||
// On Python >= 3.3, for UTF-8 we avoid the need for a temporary `bytes`
|
// `PyUnicode_AsUTF8AndSize`.
|
||||||
// object by using `PyUnicode_AsUTF8AndSize`.
|
|
||||||
if (PYBIND11_SILENCE_MSVC_C4127(UTF_N == 8)) {
|
if (PYBIND11_SILENCE_MSVC_C4127(UTF_N == 8)) {
|
||||||
Py_ssize_t size = -1;
|
Py_ssize_t size = -1;
|
||||||
const auto *buffer
|
const auto *buffer
|
||||||
@ -417,7 +396,6 @@ struct string_caster {
|
|||||||
value = StringType(buffer, static_cast<size_t>(size));
|
value = StringType(buffer, static_cast<size_t>(size));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
auto utfNbytes
|
auto utfNbytes
|
||||||
= reinterpret_steal<object>(PyUnicode_AsEncodedString(load_src.ptr(),
|
= reinterpret_steal<object>(PyUnicode_AsEncodedString(load_src.ptr(),
|
||||||
@ -486,7 +464,7 @@ private:
|
|||||||
template <typename C = CharT>
|
template <typename C = CharT>
|
||||||
bool load_bytes(enable_if_t<std::is_same<C, char>::value, handle> src) {
|
bool load_bytes(enable_if_t<std::is_same<C, char>::value, handle> src) {
|
||||||
if (PYBIND11_BYTES_CHECK(src.ptr())) {
|
if (PYBIND11_BYTES_CHECK(src.ptr())) {
|
||||||
// We were passed a Python 3 raw bytes; accept it into a std::string or char*
|
// We were passed raw bytes; accept it into a std::string or char*
|
||||||
// without any encoding attempt.
|
// without any encoding attempt.
|
||||||
const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr());
|
const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr());
|
||||||
if (bytes) {
|
if (bytes) {
|
||||||
@ -922,18 +900,6 @@ struct pyobject_caster {
|
|||||||
|
|
||||||
template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0>
|
template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0>
|
||||||
bool load(handle src, bool /* convert */) {
|
bool load(handle src, bool /* convert */) {
|
||||||
#if PY_MAJOR_VERSION < 3 && !defined(PYBIND11_STR_LEGACY_PERMISSIVE)
|
|
||||||
// For Python 2, without this implicit conversion, Python code would
|
|
||||||
// need to be cluttered with six.ensure_text() or similar, only to be
|
|
||||||
// un-cluttered later after Python 2 support is dropped.
|
|
||||||
if (PYBIND11_SILENCE_MSVC_C4127(std::is_same<T, str>::value) && isinstance<bytes>(src)) {
|
|
||||||
PyObject *str_from_bytes = PyUnicode_FromEncodedObject(src.ptr(), "utf-8", nullptr);
|
|
||||||
if (!str_from_bytes)
|
|
||||||
throw error_already_set();
|
|
||||||
value = reinterpret_steal<type>(str_from_bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!isinstance<type>(src)) {
|
if (!isinstance<type>(src)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1313,7 +1279,7 @@ public:
|
|||||||
|
|
||||||
/// \ingroup annotations
|
/// \ingroup annotations
|
||||||
/// Annotation indicating that all following arguments are keyword-only; the is the equivalent of
|
/// Annotation indicating that all following arguments are keyword-only; the is the equivalent of
|
||||||
/// an unnamed '*' argument (in Python 3)
|
/// an unnamed '*' argument
|
||||||
struct kw_only {};
|
struct kw_only {};
|
||||||
|
|
||||||
/// \ingroup annotations
|
/// \ingroup annotations
|
||||||
|
@ -15,12 +15,12 @@
|
|||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000 && !defined(PYPY_VERSION)
|
#if !defined(PYPY_VERSION)
|
||||||
# define PYBIND11_BUILTIN_QUALNAME
|
# define PYBIND11_BUILTIN_QUALNAME
|
||||||
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
|
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
|
||||||
#else
|
#else
|
||||||
// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type
|
// In PyPy, we still set __qualname__ so that we can produce reliable function type
|
||||||
// signatures; in 3.3+ this macro expands to nothing:
|
// signatures; in CPython this macro expands to nothing:
|
||||||
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \
|
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \
|
||||||
setattr((PyObject *) obj, "__qualname__", nameobj)
|
setattr((PyObject *) obj, "__qualname__", nameobj)
|
||||||
#endif
|
#endif
|
||||||
@ -155,7 +155,6 @@ extern "C" inline int pybind11_meta_setattro(PyObject *obj, PyObject *name, PyOb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
/**
|
/**
|
||||||
* Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing
|
* Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing
|
||||||
* methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function,
|
* methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function,
|
||||||
@ -170,7 +169,6 @@ extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name
|
|||||||
}
|
}
|
||||||
return PyType_Type.tp_getattro(obj, name);
|
return PyType_Type.tp_getattro(obj, name);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/// metaclass `__call__` function that is used to create all pybind11 objects.
|
/// metaclass `__call__` function that is used to create all pybind11 objects.
|
||||||
extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, PyObject *kwargs) {
|
extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, PyObject *kwargs) {
|
||||||
@ -266,9 +264,7 @@ inline PyTypeObject *make_default_metaclass() {
|
|||||||
type->tp_call = pybind11_meta_call;
|
type->tp_call = pybind11_meta_call;
|
||||||
|
|
||||||
type->tp_setattro = pybind11_meta_setattro;
|
type->tp_setattro = pybind11_meta_setattro;
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
type->tp_getattro = pybind11_meta_getattro;
|
type->tp_getattro = pybind11_meta_getattro;
|
||||||
#endif
|
|
||||||
|
|
||||||
type->tp_dealloc = pybind11_meta_dealloc;
|
type->tp_dealloc = pybind11_meta_dealloc;
|
||||||
|
|
||||||
@ -613,9 +609,6 @@ extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) {
|
|||||||
/// Give this type a buffer interface.
|
/// Give this type a buffer interface.
|
||||||
inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
|
inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
|
||||||
heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer;
|
heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer;
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
heap_type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer;
|
heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer;
|
||||||
heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer;
|
heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer;
|
||||||
@ -628,12 +621,8 @@ inline PyObject *make_new_python_type(const type_record &rec) {
|
|||||||
|
|
||||||
auto qualname = name;
|
auto qualname = name;
|
||||||
if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) {
|
if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
qualname = reinterpret_steal<object>(
|
qualname = reinterpret_steal<object>(
|
||||||
PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr()));
|
PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr()));
|
||||||
#else
|
|
||||||
qualname = str(rec.scope.attr("__qualname__").cast<std::string>() + "." + rec.name);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object module_;
|
object module_;
|
||||||
@ -697,15 +686,10 @@ inline PyObject *make_new_python_type(const type_record &rec) {
|
|||||||
type->tp_as_number = &heap_type->as_number;
|
type->tp_as_number = &heap_type->as_number;
|
||||||
type->tp_as_sequence = &heap_type->as_sequence;
|
type->tp_as_sequence = &heap_type->as_sequence;
|
||||||
type->tp_as_mapping = &heap_type->as_mapping;
|
type->tp_as_mapping = &heap_type->as_mapping;
|
||||||
#if PY_VERSION_HEX >= 0x03050000
|
|
||||||
type->tp_as_async = &heap_type->as_async;
|
type->tp_as_async = &heap_type->as_async;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Flags */
|
/* Flags */
|
||||||
type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
|
type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
type->tp_flags |= Py_TPFLAGS_CHECKTYPES;
|
|
||||||
#endif
|
|
||||||
if (!rec.is_final) {
|
if (!rec.is_final) {
|
||||||
type->tp_flags |= Py_TPFLAGS_BASETYPE;
|
type->tp_flags |= Py_TPFLAGS_BASETYPE;
|
||||||
}
|
}
|
||||||
|
@ -211,6 +211,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
#if PY_VERSION_HEX < 0x030500f0
|
||||||
|
# error "PYTHON 2 IS NO LONGER SUPPORTED. pybind11 v2.9 was the last to support Python 2."
|
||||||
|
#endif
|
||||||
#include <frameobject.h>
|
#include <frameobject.h>
|
||||||
#include <pythread.h>
|
#include <pythread.h>
|
||||||
|
|
||||||
@ -266,69 +269,37 @@
|
|||||||
// If UNDEFINED, pybind11::str can only hold PyUnicodeObject, and
|
// If UNDEFINED, pybind11::str can only hold PyUnicodeObject, and
|
||||||
// pybind11::isinstance<str>() is true only for pybind11::str.
|
// pybind11::isinstance<str>() is true only for pybind11::str.
|
||||||
// However, for Python 2 only (!), the pybind11::str caster
|
// However, for Python 2 only (!), the pybind11::str caster
|
||||||
// implicitly decodes bytes to PyUnicodeObject. This is to ease
|
// implicitly decoded bytes to PyUnicodeObject. This was to ease
|
||||||
// the transition from the legacy behavior to the non-permissive
|
// the transition from the legacy behavior to the non-permissive
|
||||||
// behavior.
|
// behavior.
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
|
/// Compatibility macros for Python 2 / Python 3 versions TODO: remove
|
||||||
# define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
|
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
|
||||||
# define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check
|
#define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check
|
||||||
# define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION
|
#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION
|
||||||
# define PYBIND11_BYTES_CHECK PyBytes_Check
|
#define PYBIND11_BYTES_CHECK PyBytes_Check
|
||||||
# define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
|
#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
|
||||||
# define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
|
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
|
||||||
# define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
|
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
|
||||||
# define PYBIND11_BYTES_AS_STRING PyBytes_AsString
|
#define PYBIND11_BYTES_AS_STRING PyBytes_AsString
|
||||||
# define PYBIND11_BYTES_SIZE PyBytes_Size
|
#define PYBIND11_BYTES_SIZE PyBytes_Size
|
||||||
# define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
|
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
|
||||||
# define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
|
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
|
||||||
# define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) (o))
|
#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) (o))
|
||||||
# define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) (o))
|
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) (o))
|
||||||
# define PYBIND11_BYTES_NAME "bytes"
|
#define PYBIND11_BYTES_NAME "bytes"
|
||||||
# define PYBIND11_STRING_NAME "str"
|
#define PYBIND11_STRING_NAME "str"
|
||||||
# define PYBIND11_SLICE_OBJECT PyObject
|
#define PYBIND11_SLICE_OBJECT PyObject
|
||||||
# define PYBIND11_FROM_STRING PyUnicode_FromString
|
#define PYBIND11_FROM_STRING PyUnicode_FromString
|
||||||
# define PYBIND11_STR_TYPE ::pybind11::str
|
#define PYBIND11_STR_TYPE ::pybind11::str
|
||||||
# define PYBIND11_BOOL_ATTR "__bool__"
|
#define PYBIND11_BOOL_ATTR "__bool__"
|
||||||
# define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool)
|
#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool)
|
||||||
# define PYBIND11_BUILTINS_MODULE "builtins"
|
#define PYBIND11_BUILTINS_MODULE "builtins"
|
||||||
// Providing a separate declaration to make Clang's -Wmissing-prototypes happy.
|
// Providing a separate declaration to make Clang's -Wmissing-prototypes happy.
|
||||||
// See comment for PYBIND11_MODULE below for why this is marked "maybe unused".
|
// See comment for PYBIND11_MODULE below for why this is marked "maybe unused".
|
||||||
# define PYBIND11_PLUGIN_IMPL(name) \
|
#define PYBIND11_PLUGIN_IMPL(name) \
|
||||||
extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); \
|
extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); \
|
||||||
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
|
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
|
||||||
|
|
||||||
#else
|
|
||||||
# define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_)
|
|
||||||
# define PYBIND11_INSTANCE_METHOD_CHECK PyMethod_Check
|
|
||||||
# define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyMethod_GET_FUNCTION
|
|
||||||
# define PYBIND11_BYTES_CHECK PyString_Check
|
|
||||||
# define PYBIND11_BYTES_FROM_STRING PyString_FromString
|
|
||||||
# define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
|
|
||||||
# define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize
|
|
||||||
# define PYBIND11_BYTES_AS_STRING PyString_AsString
|
|
||||||
# define PYBIND11_BYTES_SIZE PyString_Size
|
|
||||||
# define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o))
|
|
||||||
# define PYBIND11_LONG_AS_LONGLONG(o) \
|
|
||||||
(PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
|
|
||||||
# define PYBIND11_LONG_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed.
|
|
||||||
# define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed.
|
|
||||||
# define PYBIND11_BYTES_NAME "str"
|
|
||||||
# define PYBIND11_STRING_NAME "unicode"
|
|
||||||
# define PYBIND11_SLICE_OBJECT PySliceObject
|
|
||||||
# define PYBIND11_FROM_STRING PyString_FromString
|
|
||||||
# define PYBIND11_STR_TYPE ::pybind11::bytes
|
|
||||||
# define PYBIND11_BOOL_ATTR "__nonzero__"
|
|
||||||
# define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero)
|
|
||||||
# define PYBIND11_BUILTINS_MODULE "__builtin__"
|
|
||||||
// Providing a separate PyInit decl to make Clang's -Wmissing-prototypes happy.
|
|
||||||
// See comment for PYBIND11_MODULE below for why this is marked "maybe unused".
|
|
||||||
# define PYBIND11_PLUGIN_IMPL(name) \
|
|
||||||
static PyObject *pybind11_init_wrapper(); \
|
|
||||||
extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT void init##name(); \
|
|
||||||
extern "C" PYBIND11_EXPORT void init##name() { (void) pybind11_init_wrapper(); } \
|
|
||||||
PyObject *pybind11_init_wrapper()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200
|
#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -362,31 +333,15 @@ PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current;
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
#define PYBIND11_CATCH_INIT_EXCEPTIONS \
|
||||||
|
catch (pybind11::error_already_set & e) { \
|
||||||
# define PYBIND11_CATCH_INIT_EXCEPTIONS \
|
pybind11::raise_from(e, PyExc_ImportError, "initialization failed"); \
|
||||||
catch (pybind11::error_already_set & e) { \
|
return nullptr; \
|
||||||
pybind11::raise_from(e, PyExc_ImportError, "initialization failed"); \
|
} \
|
||||||
return nullptr; \
|
catch (const std::exception &e) { \
|
||||||
} \
|
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||||
catch (const std::exception &e) { \
|
return nullptr; \
|
||||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
}
|
||||||
return nullptr; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
# define PYBIND11_CATCH_INIT_EXCEPTIONS \
|
|
||||||
catch (pybind11::error_already_set & e) { \
|
|
||||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
|
||||||
return nullptr; \
|
|
||||||
} \
|
|
||||||
catch (const std::exception &e) { \
|
|
||||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
|
||||||
return nullptr; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
***Deprecated in favor of PYBIND11_MODULE***
|
***Deprecated in favor of PYBIND11_MODULE***
|
||||||
|
@ -82,7 +82,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
|
|||||||
# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;
|
# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;
|
||||||
# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)
|
# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)
|
||||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
||||||
# if PY_MAJOR_VERSION < 3 || defined(PYPY_VERSION)
|
# if defined(PYPY_VERSION)
|
||||||
// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set
|
// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set
|
||||||
// the value if it has already been set. Instead, it must first be deleted and
|
// the value if it has already been set. Instead, it must first be deleted and
|
||||||
// then set again.
|
// then set again.
|
||||||
@ -294,7 +294,6 @@ inline internals **&get_internals_pp() {
|
|||||||
return internals_pp;
|
return internals_pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
// forward decl
|
// forward decl
|
||||||
inline void translate_exception(std::exception_ptr);
|
inline void translate_exception(std::exception_ptr);
|
||||||
|
|
||||||
@ -318,21 +317,11 @@ bool handle_nested_exception(const T &exc, const std::exception_ptr &p) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
bool handle_nested_exception(const T &, std::exception_ptr &) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline bool raise_err(PyObject *exc_type, const char *msg) {
|
inline bool raise_err(PyObject *exc_type, const char *msg) {
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
raise_from(exc_type, msg);
|
raise_from(exc_type, msg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
PyErr_SetString(exc_type, msg);
|
PyErr_SetString(exc_type, msg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -443,17 +443,10 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
|
|||||||
// they default to using pymalloc, which is designed to be efficient for small allocations
|
// they default to using pymalloc, which is designed to be efficient for small allocations
|
||||||
// like the one we're doing here; in earlier versions (and for larger allocations) they are
|
// like the one we're doing here; in earlier versions (and for larger allocations) they are
|
||||||
// just wrappers around malloc.
|
// just wrappers around malloc.
|
||||||
#if PY_VERSION_HEX >= 0x03050000
|
|
||||||
nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));
|
nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));
|
||||||
if (!nonsimple.values_and_holders) {
|
if (!nonsimple.values_and_holders) {
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
nonsimple.values_and_holders = (void **) PyMem_New(void *, space);
|
|
||||||
if (!nonsimple.values_and_holders)
|
|
||||||
throw std::bad_alloc();
|
|
||||||
std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *));
|
|
||||||
#endif
|
|
||||||
nonsimple.status
|
nonsimple.status
|
||||||
= reinterpret_cast<std::uint8_t *>(&nonsimple.values_and_holders[flags_at]);
|
= reinterpret_cast<std::uint8_t *>(&nonsimple.values_and_holders[flags_at]);
|
||||||
}
|
}
|
||||||
@ -494,11 +487,9 @@ PYBIND11_NOINLINE std::string error_string() {
|
|||||||
|
|
||||||
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
|
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
if (scope.trace != nullptr) {
|
if (scope.trace != nullptr) {
|
||||||
PyException_SetTraceback(scope.value, scope.trace);
|
PyException_SetTraceback(scope.value, scope.trace);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(PYPY_VERSION)
|
#if !defined(PYPY_VERSION)
|
||||||
if (scope.trace) {
|
if (scope.trace) {
|
||||||
@ -547,10 +538,6 @@ PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_i
|
|||||||
inline PyThreadState *get_thread_state_unchecked() {
|
inline PyThreadState *get_thread_state_unchecked() {
|
||||||
#if defined(PYPY_VERSION)
|
#if defined(PYPY_VERSION)
|
||||||
return PyThreadState_GET();
|
return PyThreadState_GET();
|
||||||
#elif PY_VERSION_HEX < 0x03000000
|
|
||||||
return _PyThreadState_Current;
|
|
||||||
#elif PY_VERSION_HEX < 0x03050000
|
|
||||||
return (PyThreadState *) _Py_atomic_load_relaxed(&_PyThreadState_Current);
|
|
||||||
#elif PY_VERSION_HEX < 0x03050200
|
#elif PY_VERSION_HEX < 0x03050200
|
||||||
return (PyThreadState *) _PyThreadState_Current.value;
|
return (PyThreadState *) _PyThreadState_Current.value;
|
||||||
#else
|
#else
|
||||||
|
@ -19,15 +19,9 @@
|
|||||||
# error Embedding the interpreter is not supported with PyPy
|
# error Embedding the interpreter is not supported with PyPy
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
#define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||||
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
extern "C" PyObject *pybind11_init_impl_##name(); \
|
||||||
extern "C" PyObject *pybind11_init_impl_##name(); \
|
extern "C" PyObject *pybind11_init_impl_##name() { return pybind11_init_wrapper_##name(); }
|
||||||
extern "C" PyObject *pybind11_init_impl_##name() { return pybind11_init_wrapper_##name(); }
|
|
||||||
#else
|
|
||||||
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
|
||||||
extern "C" void pybind11_init_impl_##name(); \
|
|
||||||
extern "C" void pybind11_init_impl_##name() { pybind11_init_wrapper_##name(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
Add a new module to the table of builtins for the interpreter. Must be
|
Add a new module to the table of builtins for the interpreter. Must be
|
||||||
@ -67,11 +61,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||||||
|
|
||||||
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
|
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
|
||||||
struct embedded_module {
|
struct embedded_module {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
using init_t = PyObject *(*) ();
|
using init_t = PyObject *(*) ();
|
||||||
#else
|
|
||||||
using init_t = void (*)();
|
|
||||||
#endif
|
|
||||||
embedded_module(const char *name, init_t init) {
|
embedded_module(const char *name, init_t init) {
|
||||||
if (Py_IsInitialized() != 0) {
|
if (Py_IsInitialized() != 0) {
|
||||||
pybind11_fail("Can't add new modules after the interpreter has been initialized");
|
pybind11_fail("Can't add new modules after the interpreter has been initialized");
|
||||||
@ -86,42 +76,13 @@ struct embedded_module {
|
|||||||
|
|
||||||
struct wide_char_arg_deleter {
|
struct wide_char_arg_deleter {
|
||||||
void operator()(wchar_t *ptr) const {
|
void operator()(wchar_t *ptr) const {
|
||||||
#if PY_VERSION_HEX >= 0x030500f0
|
|
||||||
// API docs: https://docs.python.org/3/c-api/sys.html#c.Py_DecodeLocale
|
// API docs: https://docs.python.org/3/c-api/sys.html#c.Py_DecodeLocale
|
||||||
PyMem_RawFree(ptr);
|
PyMem_RawFree(ptr);
|
||||||
#else
|
|
||||||
delete[] ptr;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline wchar_t *widen_chars(const char *safe_arg) {
|
inline wchar_t *widen_chars(const char *safe_arg) {
|
||||||
#if PY_VERSION_HEX >= 0x030500f0
|
|
||||||
wchar_t *widened_arg = Py_DecodeLocale(safe_arg, nullptr);
|
wchar_t *widened_arg = Py_DecodeLocale(safe_arg, nullptr);
|
||||||
#else
|
|
||||||
wchar_t *widened_arg = nullptr;
|
|
||||||
|
|
||||||
// warning C4996: 'mbstowcs': This function or variable may be unsafe.
|
|
||||||
# if defined(_MSC_VER)
|
|
||||||
# pragma warning(push)
|
|
||||||
# pragma warning(disable : 4996)
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if defined(HAVE_BROKEN_MBSTOWCS) && HAVE_BROKEN_MBSTOWCS
|
|
||||||
size_t count = std::strlen(safe_arg);
|
|
||||||
# else
|
|
||||||
size_t count = std::mbstowcs(nullptr, safe_arg, 0);
|
|
||||||
# endif
|
|
||||||
if (count != static_cast<size_t>(-1)) {
|
|
||||||
widened_arg = new wchar_t[count + 1];
|
|
||||||
std::mbstowcs(widened_arg, safe_arg, count + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
# if defined(_MSC_VER)
|
|
||||||
# pragma warning(pop)
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
return widened_arg;
|
return widened_arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +99,6 @@ inline void set_interpreter_argv(int argc, const char *const *argv, bool add_pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto argv_size = static_cast<size_t>(argc);
|
auto argv_size = static_cast<size_t>(argc);
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
// SetArgv* on python 3 takes wchar_t, so we have to convert.
|
// SetArgv* on python 3 takes wchar_t, so we have to convert.
|
||||||
std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);
|
std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);
|
||||||
std::vector<std::unique_ptr<wchar_t[], wide_char_arg_deleter>> widened_argv_entries;
|
std::vector<std::unique_ptr<wchar_t[], wide_char_arg_deleter>> widened_argv_entries;
|
||||||
@ -154,15 +114,6 @@ inline void set_interpreter_argv(int argc, const char *const *argv, bool add_pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto *pysys_argv = widened_argv.get();
|
auto *pysys_argv = widened_argv.get();
|
||||||
#else
|
|
||||||
// python 2.x
|
|
||||||
std::vector<std::string> strings{safe_argv, safe_argv + argv_size};
|
|
||||||
std::vector<char *> char_strings{argv_size};
|
|
||||||
for (std::size_t i = 0; i < argv_size; ++i)
|
|
||||||
char_strings[i] = &strings[i][0];
|
|
||||||
char **pysys_argv = char_strings.data();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
|
PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,10 +20,10 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||||||
|
|
||||||
inline void ensure_builtins_in_globals(object &global) {
|
inline void ensure_builtins_in_globals(object &global) {
|
||||||
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
|
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
|
||||||
// Running exec and eval on Python 2 and 3 adds `builtins` module under
|
// Running exec and eval adds `builtins` module under `__builtins__` key to
|
||||||
// `__builtins__` key to globals if not yet present.
|
// globals if not yet present. Python 3.8 made PyRun_String behave
|
||||||
// Python 3.8 made PyRun_String behave similarly. Let's also do that for
|
// similarly. Let's also do that for older versions, for consistency. This
|
||||||
// older versions, for consistency. This was missing from PyPy3.8 7.3.7.
|
// was missing from PyPy3.8 7.3.7.
|
||||||
if (!global.contains("__builtins__"))
|
if (!global.contains("__builtins__"))
|
||||||
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
|
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
|
||||||
#else
|
#else
|
||||||
@ -94,7 +94,7 @@ void exec(const char (&s)[N], object global = globals(), object local = object()
|
|||||||
eval<eval_statements>(s, global, local);
|
eval<eval_statements>(s, global, local);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03000000
|
#if defined(PYPY_VERSION)
|
||||||
template <eval_mode mode = eval_statements>
|
template <eval_mode mode = eval_statements>
|
||||||
object eval_file(str, object, object) {
|
object eval_file(str, object, object) {
|
||||||
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
||||||
@ -133,40 +133,18 @@ object eval_file(str fname, object global = globals(), object local = object())
|
|||||||
|
|
||||||
int closeFile = 1;
|
int closeFile = 1;
|
||||||
std::string fname_str = (std::string) fname;
|
std::string fname_str = (std::string) fname;
|
||||||
# if PY_VERSION_HEX >= 0x03040000
|
|
||||||
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
|
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
|
||||||
# elif PY_VERSION_HEX >= 0x03000000
|
|
||||||
FILE *f = _Py_fopen(fname.ptr(), "r");
|
|
||||||
# else
|
|
||||||
/* No unicode support in open() :( */
|
|
||||||
auto fobj = reinterpret_steal<object>(
|
|
||||||
PyFile_FromString(const_cast<char *>(fname_str.c_str()), const_cast<char *>("r")));
|
|
||||||
FILE *f = nullptr;
|
|
||||||
if (fobj)
|
|
||||||
f = PyFile_AsFile(fobj.ptr());
|
|
||||||
closeFile = 0;
|
|
||||||
# endif
|
|
||||||
if (!f) {
|
if (!f) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
|
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// In Python2, this should be encoded by getfilesystemencoding.
|
|
||||||
// We don't boher setting it since Python2 is past EOL anyway.
|
|
||||||
// See PR#3233
|
|
||||||
# if PY_VERSION_HEX >= 0x03000000
|
|
||||||
if (!global.contains("__file__")) {
|
if (!global.contains("__file__")) {
|
||||||
global["__file__"] = std::move(fname);
|
global["__file__"] = std::move(fname);
|
||||||
}
|
}
|
||||||
# endif
|
|
||||||
|
|
||||||
# if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
|
|
||||||
PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(), local.ptr());
|
|
||||||
(void) closeFile;
|
|
||||||
# else
|
|
||||||
PyObject *result
|
PyObject *result
|
||||||
= PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
|
= PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
|
||||||
# endif
|
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
|
@ -263,11 +263,7 @@ private:
|
|||||||
static npy_api lookup() {
|
static npy_api lookup() {
|
||||||
module_ m = module_::import("numpy.core.multiarray");
|
module_ m = module_::import("numpy.core.multiarray");
|
||||||
auto c = m.attr("_ARRAY_API");
|
auto c = m.attr("_ARRAY_API");
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL);
|
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL);
|
||||||
#else
|
|
||||||
void **api_ptr = (void **) PyCObject_AsVoidPtr(c.ptr());
|
|
||||||
#endif
|
|
||||||
npy_api api;
|
npy_api api;
|
||||||
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
|
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
|
||||||
DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
|
DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
|
||||||
|
@ -91,16 +91,6 @@ struct op_ {
|
|||||||
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
||||||
using op = op_impl<id, ot, Base, L_type, R_type>;
|
using op = op_impl<id, ot, Base, L_type, R_type>;
|
||||||
cl.def(op::name(), &op::execute, is_operator(), extra...);
|
cl.def(op::name(), &op::execute, is_operator(), extra...);
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
if (PYBIND11_SILENCE_MSVC_C4127(id == op_truediv)
|
|
||||||
|| PYBIND11_SILENCE_MSVC_C4127(id == op_itruediv))
|
|
||||||
cl.def(id == op_itruediv ? "__idiv__"
|
|
||||||
: ot == op_l ? "__div__"
|
|
||||||
: "__rdiv__",
|
|
||||||
&op::execute,
|
|
||||||
is_operator(),
|
|
||||||
extra...);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
template <typename Class, typename... Extra>
|
template <typename Class, typename... Extra>
|
||||||
void execute_cast(Class &cl, const Extra &...extra) const {
|
void execute_cast(Class &cl, const Extra &...extra) const {
|
||||||
@ -109,15 +99,6 @@ struct op_ {
|
|||||||
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
||||||
using op = op_impl<id, ot, Base, L_type, R_type>;
|
using op = op_impl<id, ot, Base, L_type, R_type>;
|
||||||
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
|
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
if (id == op_truediv || id == op_itruediv)
|
|
||||||
cl.def(id == op_itruediv ? "__idiv__"
|
|
||||||
: ot == op_l ? "__div__"
|
|
||||||
: "__rdiv__",
|
|
||||||
&op::execute,
|
|
||||||
is_operator(),
|
|
||||||
extra...);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -431,9 +431,8 @@ protected:
|
|||||||
}
|
}
|
||||||
if (auto *tinfo = detail::get_type_info(*t)) {
|
if (auto *tinfo = detail::get_type_info(*t)) {
|
||||||
handle th((PyObject *) tinfo->type);
|
handle th((PyObject *) tinfo->type);
|
||||||
signature += th.attr("__module__").cast<std::string>() + "." +
|
signature += th.attr("__module__").cast<std::string>() + "."
|
||||||
// Python 3.3+, but we backport it to earlier versions
|
+ th.attr("__qualname__").cast<std::string>();
|
||||||
th.attr("__qualname__").cast<std::string>();
|
|
||||||
} else if (rec->is_new_style_constructor && arg_index == 0) {
|
} else if (rec->is_new_style_constructor && arg_index == 0) {
|
||||||
// A new-style `__init__` takes `self` as `value_and_holder`.
|
// A new-style `__init__` takes `self` as `value_and_holder`.
|
||||||
// Rewrite it to the proper class type.
|
// Rewrite it to the proper class type.
|
||||||
@ -453,15 +452,6 @@ protected:
|
|||||||
pybind11_fail("Internal error while parsing type signature (2)");
|
pybind11_fail("Internal error while parsing type signature (2)");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
if (std::strcmp(rec->name, "__next__") == 0) {
|
|
||||||
std::free(rec->name);
|
|
||||||
rec->name = guarded_strdup("next");
|
|
||||||
} else if (std::strcmp(rec->name, "__bool__") == 0) {
|
|
||||||
std::free(rec->name);
|
|
||||||
rec->name = guarded_strdup("__nonzero__");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
rec->signature = guarded_strdup(signature.c_str());
|
rec->signature = guarded_strdup(signature.c_str());
|
||||||
rec->args.shrink_to_fit();
|
rec->args.shrink_to_fit();
|
||||||
rec->nargs = (std::uint16_t) args;
|
rec->nargs = (std::uint16_t) args;
|
||||||
@ -1107,14 +1097,12 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
append_note_if_missing_header_is_suspected(msg);
|
append_note_if_missing_header_is_suspected(msg);
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
// Attach additional error info to the exception if supported
|
// Attach additional error info to the exception if supported
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
// #HelpAppreciated: unit test coverage for this branch.
|
// #HelpAppreciated: unit test coverage for this branch.
|
||||||
raise_from(PyExc_TypeError, msg.c_str());
|
raise_from(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -1123,13 +1111,11 @@ protected:
|
|||||||
"Python type! The signature was\n\t";
|
"Python type! The signature was\n\t";
|
||||||
msg += it->signature;
|
msg += it->signature;
|
||||||
append_note_if_missing_header_is_suspected(msg);
|
append_note_if_missing_header_is_suspected(msg);
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
// Attach additional error info to the exception if supported
|
// Attach additional error info to the exception if supported
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
raise_from(PyExc_TypeError, msg.c_str());
|
raise_from(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -1149,11 +1135,7 @@ public:
|
|||||||
/// Create a new top-level Python module with the given name and docstring
|
/// Create a new top-level Python module with the given name and docstring
|
||||||
PYBIND11_DEPRECATED("Use PYBIND11_MODULE or module_::create_extension_module instead")
|
PYBIND11_DEPRECATED("Use PYBIND11_MODULE or module_::create_extension_module instead")
|
||||||
explicit module_(const char *name, const char *doc = nullptr) {
|
explicit module_(const char *name, const char *doc = nullptr) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
*this = create_extension_module(name, doc, new PyModuleDef());
|
*this = create_extension_module(name, doc, new PyModuleDef());
|
||||||
#else
|
|
||||||
*this = create_extension_module(name, doc, nullptr);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
@ -1231,20 +1213,14 @@ public:
|
|||||||
PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */);
|
PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
using module_def = PyModuleDef;
|
using module_def = PyModuleDef;
|
||||||
#else
|
|
||||||
struct module_def {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
Create a new top-level module that can be used as the main module of a C extension.
|
Create a new top-level module that can be used as the main module of a C extension.
|
||||||
|
|
||||||
For Python 3, ``def`` should point to a statically allocated module_def.
|
``def`` should point to a statically allocated module_def.
|
||||||
For Python 2, ``def`` can be a nullptr and is completely ignored.
|
|
||||||
\endrst */
|
\endrst */
|
||||||
static module_ create_extension_module(const char *name, const char *doc, module_def *def) {
|
static module_ create_extension_module(const char *name, const char *doc, module_def *def) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
// module_def is PyModuleDef
|
// module_def is PyModuleDef
|
||||||
// Placement new (not an allocation).
|
// Placement new (not an allocation).
|
||||||
def = new (def)
|
def = new (def)
|
||||||
@ -1258,12 +1234,6 @@ public:
|
|||||||
/* m_clear */ nullptr,
|
/* m_clear */ nullptr,
|
||||||
/* m_free */ nullptr};
|
/* m_free */ nullptr};
|
||||||
auto *m = PyModule_Create(def);
|
auto *m = PyModule_Create(def);
|
||||||
#else
|
|
||||||
// Ignore module_def *def; only necessary for Python 3
|
|
||||||
(void) def;
|
|
||||||
auto m = Py_InitModule3(
|
|
||||||
name, nullptr, options::show_user_defined_docstrings() ? doc : nullptr);
|
|
||||||
#endif
|
|
||||||
if (m == nullptr) {
|
if (m == nullptr) {
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
@ -1290,14 +1260,12 @@ inline dict globals() {
|
|||||||
return reinterpret_borrow<dict>(p ? p : module_::import("__main__").attr("__dict__").ptr());
|
return reinterpret_borrow<dict>(p ? p : module_::import("__main__").attr("__dict__").ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
template <typename... Args, typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>>
|
template <typename... Args, typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>>
|
||||||
PYBIND11_DEPRECATED("make_simple_namespace should be replaced with "
|
PYBIND11_DEPRECATED("make_simple_namespace should be replaced with "
|
||||||
"py::module_::import(\"types\").attr(\"SimpleNamespace\") ")
|
"py::module_::import(\"types\").attr(\"SimpleNamespace\") ")
|
||||||
object make_simple_namespace(Args &&...args_) {
|
object make_simple_namespace(Args &&...args_) {
|
||||||
return module_::import("types").attr("SimpleNamespace")(std::forward<Args>(args_)...);
|
return module_::import("types").attr("SimpleNamespace")(std::forward<Args>(args_)...);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
/// Generic support for creating new Python heap types
|
/// Generic support for creating new Python heap types
|
||||||
@ -2173,9 +2141,6 @@ public:
|
|||||||
def_property_readonly("value", [](Type value) { return (Scalar) value; });
|
def_property_readonly("value", [](Type value) { return (Scalar) value; });
|
||||||
def("__int__", [](Type value) { return (Scalar) value; });
|
def("__int__", [](Type value) { return (Scalar) value; });
|
||||||
def("__index__", [](Type value) { return (Scalar) value; });
|
def("__index__", [](Type value) { return (Scalar) value; });
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
def("__long__", [](Type value) { return (Scalar) value; });
|
|
||||||
#endif
|
|
||||||
attr("__setstate__") = cpp_function(
|
attr("__setstate__") = cpp_function(
|
||||||
[](detail::value_and_holder &v_h, Scalar arg) {
|
[](detail::value_and_holder &v_h, Scalar arg) {
|
||||||
detail::initimpl::setstate<Base>(
|
detail::initimpl::setstate<Base>(
|
||||||
|
@ -434,8 +434,6 @@ private:
|
|||||||
# pragma warning(pop)
|
# pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
|
|
||||||
/// Replaces the current Python error indicator with the chosen error, performing a
|
/// Replaces the current Python error indicator with the chosen error, performing a
|
||||||
/// 'raise from' to indicate that the chosen error was caused by the original error.
|
/// 'raise from' to indicate that the chosen error was caused by the original error.
|
||||||
inline void raise_from(PyObject *type, const char *message) {
|
inline void raise_from(PyObject *type, const char *message) {
|
||||||
@ -473,8 +471,6 @@ inline void raise_from(error_already_set &err, PyObject *type, const char *messa
|
|||||||
raise_from(type, message);
|
raise_from(type, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \defgroup python_builtins const_name
|
/** \defgroup python_builtins const_name
|
||||||
Unless stated otherwise, the following C++ functions behave the same
|
Unless stated otherwise, the following C++ functions behave the same
|
||||||
as their Python counterparts.
|
as their Python counterparts.
|
||||||
@ -591,12 +587,9 @@ inline ssize_t hash(handle obj) {
|
|||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
inline handle get_function(handle value) {
|
inline handle get_function(handle value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
if (PyInstanceMethod_Check(value.ptr())) {
|
if (PyInstanceMethod_Check(value.ptr())) {
|
||||||
value = PyInstanceMethod_GET_FUNCTION(value.ptr());
|
value = PyInstanceMethod_GET_FUNCTION(value.ptr());
|
||||||
} else
|
} else if (PyMethod_Check(value.ptr())) {
|
||||||
#endif
|
|
||||||
if (PyMethod_Check(value.ptr())) {
|
|
||||||
value = PyMethod_GET_FUNCTION(value.ptr());
|
value = PyMethod_GET_FUNCTION(value.ptr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -608,7 +601,6 @@ inline handle get_function(handle value) {
|
|||||||
|
|
||||||
// copied from cpython _PyDict_GetItemStringWithError
|
// copied from cpython _PyDict_GetItemStringWithError
|
||||||
inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
|
inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
PyObject *kv = nullptr, *rv = nullptr;
|
PyObject *kv = nullptr, *rv = nullptr;
|
||||||
kv = PyUnicode_FromString(key);
|
kv = PyUnicode_FromString(key);
|
||||||
if (kv == NULL) {
|
if (kv == NULL) {
|
||||||
@ -621,21 +613,14 @@ inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
|
|||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
#else
|
|
||||||
return PyDict_GetItemString(v, key);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject *dict_getitem(PyObject *v, PyObject *key) {
|
inline PyObject *dict_getitem(PyObject *v, PyObject *key) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
PyObject *rv = PyDict_GetItemWithError(v, key);
|
PyObject *rv = PyDict_GetItemWithError(v, key);
|
||||||
if (rv == NULL && PyErr_Occurred()) {
|
if (rv == NULL && PyErr_Occurred()) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
#else
|
|
||||||
return PyDict_GetItem(v, key);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper aliases/functions to support implicit casting of values given to python
|
// Helper aliases/functions to support implicit casting of values given to python
|
||||||
@ -1273,13 +1258,6 @@ private:
|
|||||||
/// Return string representation -- always returns a new reference, even if already a str
|
/// Return string representation -- always returns a new reference, even if already a str
|
||||||
static PyObject *raw_str(PyObject *op) {
|
static PyObject *raw_str(PyObject *op) {
|
||||||
PyObject *str_value = PyObject_Str(op);
|
PyObject *str_value = PyObject_Str(op);
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
if (!str_value)
|
|
||||||
throw error_already_set();
|
|
||||||
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
|
|
||||||
Py_XDECREF(str_value);
|
|
||||||
str_value = unicode;
|
|
||||||
#endif
|
|
||||||
return str_value;
|
return str_value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1459,11 +1437,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||||||
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
|
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
|
||||||
template <typename Unsigned>
|
template <typename Unsigned>
|
||||||
Unsigned as_unsigned(PyObject *o) {
|
Unsigned as_unsigned(PyObject *o) {
|
||||||
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(Unsigned) <= sizeof(unsigned long))
|
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(Unsigned) <= sizeof(unsigned long))) {
|
||||||
#if PY_VERSION_HEX < 0x03000000
|
|
||||||
|| PyInt_Check(o)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
unsigned long v = PyLong_AsUnsignedLong(o);
|
unsigned long v = PyLong_AsUnsignedLong(o);
|
||||||
return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
|
return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
|
||||||
}
|
}
|
||||||
@ -1922,7 +1896,6 @@ public:
|
|||||||
return memoryview::from_buffer(const_cast<T *>(ptr), shape, strides, true);
|
return memoryview::from_buffer(const_cast<T *>(ptr), shape, strides, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
/** \rst
|
/** \rst
|
||||||
Creates ``memoryview`` from static memory.
|
Creates ``memoryview`` from static memory.
|
||||||
|
|
||||||
@ -1930,8 +1903,6 @@ public:
|
|||||||
managed by Python. The caller is responsible for managing the lifetime
|
managed by Python. The caller is responsible for managing the lifetime
|
||||||
of ``mem``, which MUST outlive the memoryview constructed here.
|
of ``mem``, which MUST outlive the memoryview constructed here.
|
||||||
|
|
||||||
This method is not available in Python 2.
|
|
||||||
|
|
||||||
See also: Python C API documentation for `PyMemoryView_FromBuffer`_.
|
See also: Python C API documentation for `PyMemoryView_FromBuffer`_.
|
||||||
|
|
||||||
.. _PyMemoryView_FromMemory:
|
.. _PyMemoryView_FromMemory:
|
||||||
@ -1950,12 +1921,10 @@ public:
|
|||||||
return memoryview::from_memory(const_cast<void *>(mem), size, true);
|
return memoryview::from_memory(const_cast<void *>(mem), size, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef PYBIND11_HAS_STRING_VIEW
|
#ifdef PYBIND11_HAS_STRING_VIEW
|
||||||
static memoryview from_memory(std::string_view mem) {
|
static memoryview from_memory(std::string_view mem) {
|
||||||
return from_memory(const_cast<char *>(mem.data()), static_cast<ssize_t>(mem.size()), true);
|
return from_memory(const_cast<char *>(mem.data()), static_cast<ssize_t>(mem.size()), true);
|
||||||
}
|
}
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2010,11 +1979,7 @@ inline size_t len(handle h) {
|
|||||||
/// Get the length hint of a Python object.
|
/// Get the length hint of a Python object.
|
||||||
/// Returns 0 when this cannot be determined.
|
/// Returns 0 when this cannot be determined.
|
||||||
inline size_t len_hint(handle h) {
|
inline size_t len_hint(handle h) {
|
||||||
#if PY_VERSION_HEX >= 0x03040000
|
|
||||||
ssize_t result = PyObject_LengthHint(h.ptr(), 0);
|
ssize_t result = PyObject_LengthHint(h.ptr(), 0);
|
||||||
#else
|
|
||||||
ssize_t result = PyObject_Length(h.ptr());
|
|
||||||
#endif
|
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
// Sometimes a length can't be determined at all (eg generators)
|
// Sometimes a length can't be determined at all (eg generators)
|
||||||
// In which case simply return 0
|
// In which case simply return 0
|
||||||
@ -2029,13 +1994,6 @@ inline str repr(handle h) {
|
|||||||
if (!str_value) {
|
if (!str_value) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
|
|
||||||
Py_XDECREF(str_value);
|
|
||||||
str_value = unicode;
|
|
||||||
if (!str_value)
|
|
||||||
throw error_already_set();
|
|
||||||
#endif
|
|
||||||
return reinterpret_steal<str>(str_value);
|
return reinterpret_steal<str>(str_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import nox
|
|||||||
|
|
||||||
nox.options.sessions = ["lint", "tests", "tests_packaging"]
|
nox.options.sessions = ["lint", "tests", "tests_packaging"]
|
||||||
|
|
||||||
PYTHON_VERISONS = ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
|
PYTHON_VERISONS = ["3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
|
||||||
|
|
||||||
|
|
||||||
@nox.session(reuse_venv=True)
|
@nox.session(reuse_venv=True)
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
import sys
|
||||||
|
|
||||||
|
if sys.version_info < (3, 5):
|
||||||
|
msg = "pybind11 does not support Python < 3.5. 2.9 was the last release supporting older Pythons."
|
||||||
|
raise ImportError(msg)
|
||||||
|
|
||||||
|
|
||||||
from ._version import __version__, version_info
|
from ._version import __version__, version_info
|
||||||
from .commands import get_cmake_dir, get_include
|
from .commands import get_cmake_dir, get_include
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
import sysconfig
|
import sysconfig
|
||||||
@ -8,8 +5,7 @@ import sysconfig
|
|||||||
from .commands import get_cmake_dir, get_include
|
from .commands import get_cmake_dir, get_include
|
||||||
|
|
||||||
|
|
||||||
def print_includes():
|
def print_includes() -> None:
|
||||||
# type: () -> None
|
|
||||||
dirs = [
|
dirs = [
|
||||||
sysconfig.get_path("include"),
|
sysconfig.get_path("include"),
|
||||||
sysconfig.get_path("platinclude"),
|
sysconfig.get_path("platinclude"),
|
||||||
@ -25,8 +21,7 @@ def print_includes():
|
|||||||
print(" ".join("-I" + d for d in unique_dirs))
|
print(" ".join("-I" + d for d in unique_dirs))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
# type: () -> None
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
def _to_int(s):
|
def _to_int(s: str) -> Union[int, str]:
|
||||||
try:
|
try:
|
||||||
return int(s)
|
return int(s)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
from typing import Tuple, Union
|
|
||||||
|
|
||||||
def _to_int(s: str) -> Union[int, str]: ...
|
|
||||||
|
|
||||||
__version__: str
|
|
||||||
version_info: Tuple[Union[int, str], ...]
|
|
@ -1,18 +1,15 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
def get_include(user=False):
|
def get_include(user: bool = False) -> str:
|
||||||
# type: (bool) -> str
|
|
||||||
installed_path = os.path.join(DIR, "include")
|
installed_path = os.path.join(DIR, "include")
|
||||||
source_path = os.path.join(os.path.dirname(DIR), "include")
|
source_path = os.path.join(os.path.dirname(DIR), "include")
|
||||||
return installed_path if os.path.exists(installed_path) else source_path
|
return installed_path if os.path.exists(installed_path) else source_path
|
||||||
|
|
||||||
|
|
||||||
def get_cmake_dir():
|
def get_cmake_dir() -> str:
|
||||||
# type: () -> str
|
|
||||||
cmake_installed_path = os.path.join(DIR, "share", "cmake", "pybind11")
|
cmake_installed_path = os.path.join(DIR, "share", "cmake", "pybind11")
|
||||||
if os.path.exists(cmake_installed_path):
|
if os.path.exists(cmake_installed_path):
|
||||||
return cmake_installed_path
|
return cmake_installed_path
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This module provides helpers for C++11+ projects using pybind11.
|
This module provides helpers for C++11+ projects using pybind11.
|
||||||
|
|
||||||
@ -49,6 +47,20 @@ import sysconfig
|
|||||||
import tempfile
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
import warnings
|
import warnings
|
||||||
|
from functools import lru_cache
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
Dict,
|
||||||
|
Iterable,
|
||||||
|
Iterator,
|
||||||
|
List,
|
||||||
|
Optional,
|
||||||
|
Tuple,
|
||||||
|
TypeVar,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from setuptools import Extension as _Extension
|
from setuptools import Extension as _Extension
|
||||||
@ -61,7 +73,6 @@ import distutils.ccompiler
|
|||||||
import distutils.errors
|
import distutils.errors
|
||||||
|
|
||||||
WIN = sys.platform.startswith("win32") and "mingw" not in sysconfig.get_platform()
|
WIN = sys.platform.startswith("win32") and "mingw" not in sysconfig.get_platform()
|
||||||
PY2 = sys.version_info[0] < 3
|
|
||||||
MACOS = sys.platform.startswith("darwin")
|
MACOS = sys.platform.startswith("darwin")
|
||||||
STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}"
|
STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}"
|
||||||
|
|
||||||
@ -73,7 +84,7 @@ STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}"
|
|||||||
# directory into your path if it sits beside your setup.py.
|
# directory into your path if it sits beside your setup.py.
|
||||||
|
|
||||||
|
|
||||||
class Pybind11Extension(_Extension):
|
class Pybind11Extension(_Extension): # type: ignore[misc]
|
||||||
"""
|
"""
|
||||||
Build a C++11+ Extension module with pybind11. This automatically adds the
|
Build a C++11+ Extension module with pybind11. This automatically adds the
|
||||||
recommended flags when you init the extension and assumes C++ sources - you
|
recommended flags when you init the extension and assumes C++ sources - you
|
||||||
@ -95,21 +106,18 @@ class Pybind11Extension(_Extension):
|
|||||||
|
|
||||||
If you want to add pybind11 headers manually, for example for an exact
|
If you want to add pybind11 headers manually, for example for an exact
|
||||||
git checkout, then set ``include_pybind11=False``.
|
git checkout, then set ``include_pybind11=False``.
|
||||||
|
|
||||||
Warning: do not use property-based access to the instance on Python 2 -
|
|
||||||
this is an ugly old-style class due to Distutils.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# flags are prepended, so that they can be further overridden, e.g. by
|
# flags are prepended, so that they can be further overridden, e.g. by
|
||||||
# ``extra_compile_args=["-g"]``.
|
# ``extra_compile_args=["-g"]``.
|
||||||
|
|
||||||
def _add_cflags(self, flags):
|
def _add_cflags(self, flags: List[str]) -> None:
|
||||||
self.extra_compile_args[:0] = flags
|
self.extra_compile_args[:0] = flags
|
||||||
|
|
||||||
def _add_ldflags(self, flags):
|
def _add_ldflags(self, flags: List[str]) -> None:
|
||||||
self.extra_link_args[:0] = flags
|
self.extra_link_args[:0] = flags
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
|
||||||
self._cxx_level = 0
|
self._cxx_level = 0
|
||||||
cxx_std = kwargs.pop("cxx_std", 0)
|
cxx_std = kwargs.pop("cxx_std", 0)
|
||||||
@ -119,9 +127,7 @@ class Pybind11Extension(_Extension):
|
|||||||
|
|
||||||
include_pybind11 = kwargs.pop("include_pybind11", True)
|
include_pybind11 = kwargs.pop("include_pybind11", True)
|
||||||
|
|
||||||
# Can't use super here because distutils has old-style classes in
|
super().__init__(*args, **kwargs)
|
||||||
# Python 2!
|
|
||||||
_Extension.__init__(self, *args, **kwargs)
|
|
||||||
|
|
||||||
# Include the installed package pybind11 headers
|
# Include the installed package pybind11 headers
|
||||||
if include_pybind11:
|
if include_pybind11:
|
||||||
@ -133,11 +139,10 @@ class Pybind11Extension(_Extension):
|
|||||||
|
|
||||||
if pyinc not in self.include_dirs:
|
if pyinc not in self.include_dirs:
|
||||||
self.include_dirs.append(pyinc)
|
self.include_dirs.append(pyinc)
|
||||||
except ImportError:
|
except ModuleNotFoundError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Have to use the accessor manually to support Python 2 distutils
|
self.cxx_std = cxx_std
|
||||||
Pybind11Extension.cxx_std.__set__(self, cxx_std)
|
|
||||||
|
|
||||||
cflags = []
|
cflags = []
|
||||||
ldflags = []
|
ldflags = []
|
||||||
@ -157,18 +162,18 @@ class Pybind11Extension(_Extension):
|
|||||||
self._add_ldflags(ldflags)
|
self._add_ldflags(ldflags)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cxx_std(self):
|
def cxx_std(self) -> int:
|
||||||
"""
|
"""
|
||||||
The CXX standard level. If set, will add the required flags. If left
|
The CXX standard level. If set, will add the required flags. If left at
|
||||||
at 0, it will trigger an automatic search when pybind11's build_ext
|
0, it will trigger an automatic search when pybind11's build_ext is
|
||||||
is used. If None, will have no effect. Besides just the flags, this
|
used. If None, will have no effect. Besides just the flags, this may
|
||||||
may add a register warning/error fix for Python 2 or macos-min 10.9
|
add a macos-min 10.9 or 10.14 flag if MACOSX_DEPLOYMENT_TARGET is
|
||||||
or 10.14.
|
unset.
|
||||||
"""
|
"""
|
||||||
return self._cxx_level
|
return self._cxx_level
|
||||||
|
|
||||||
@cxx_std.setter
|
@cxx_std.setter
|
||||||
def cxx_std(self, level):
|
def cxx_std(self, level: int) -> None:
|
||||||
|
|
||||||
if self._cxx_level:
|
if self._cxx_level:
|
||||||
warnings.warn("You cannot safely change the cxx_level after setting it!")
|
warnings.warn("You cannot safely change the cxx_level after setting it!")
|
||||||
@ -195,31 +200,20 @@ class Pybind11Extension(_Extension):
|
|||||||
current_macos = tuple(int(x) for x in platform.mac_ver()[0].split(".")[:2])
|
current_macos = tuple(int(x) for x in platform.mac_ver()[0].split(".")[:2])
|
||||||
desired_macos = (10, 9) if level < 17 else (10, 14)
|
desired_macos = (10, 9) if level < 17 else (10, 14)
|
||||||
macos_string = ".".join(str(x) for x in min(current_macos, desired_macos))
|
macos_string = ".".join(str(x) for x in min(current_macos, desired_macos))
|
||||||
macosx_min = "-mmacosx-version-min=" + macos_string
|
macosx_min = "-mmacosx-version-min={}".format(macos_string)
|
||||||
cflags += [macosx_min]
|
cflags += [macosx_min]
|
||||||
ldflags += [macosx_min]
|
ldflags += [macosx_min]
|
||||||
|
|
||||||
if PY2:
|
|
||||||
if WIN:
|
|
||||||
# Will be ignored on MSVC 2015, where C++17 is not supported so
|
|
||||||
# this flag is not valid.
|
|
||||||
cflags += ["/wd5033"]
|
|
||||||
elif level >= 17:
|
|
||||||
cflags += ["-Wno-register"]
|
|
||||||
elif level >= 14:
|
|
||||||
cflags += ["-Wno-deprecated-register"]
|
|
||||||
|
|
||||||
self._add_cflags(cflags)
|
self._add_cflags(cflags)
|
||||||
self._add_ldflags(ldflags)
|
self._add_ldflags(ldflags)
|
||||||
|
|
||||||
|
|
||||||
# Just in case someone clever tries to multithread
|
# Just in case someone clever tries to multithread
|
||||||
tmp_chdir_lock = threading.Lock()
|
tmp_chdir_lock = threading.Lock()
|
||||||
cpp_cache_lock = threading.Lock()
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def tmp_chdir():
|
def tmp_chdir() -> Iterator[str]:
|
||||||
"Prepare and enter a temporary directory, cleanup when done"
|
"Prepare and enter a temporary directory, cleanup when done"
|
||||||
|
|
||||||
# Threadsafe
|
# Threadsafe
|
||||||
@ -235,7 +229,7 @@ def tmp_chdir():
|
|||||||
|
|
||||||
|
|
||||||
# cf http://bugs.python.org/issue26689
|
# cf http://bugs.python.org/issue26689
|
||||||
def has_flag(compiler, flag):
|
def has_flag(compiler: Any, flag: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Return the flag if a flag name is supported on the
|
Return the flag if a flag name is supported on the
|
||||||
specified compiler, otherwise None (can be used as a boolean).
|
specified compiler, otherwise None (can be used as a boolean).
|
||||||
@ -243,13 +237,12 @@ def has_flag(compiler, flag):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
with tmp_chdir():
|
with tmp_chdir():
|
||||||
fname = "flagcheck.cpp"
|
fname = Path("flagcheck.cpp")
|
||||||
with open(fname, "w") as f:
|
# Don't trigger -Wunused-parameter.
|
||||||
# Don't trigger -Wunused-parameter.
|
fname.write_text("int main (int, char **) { return 0; }")
|
||||||
f.write("int main (int, char **) { return 0; }")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
compiler.compile([fname], extra_postargs=[flag])
|
compiler.compile([str(fname)], extra_postargs=[flag])
|
||||||
except distutils.errors.CompileError:
|
except distutils.errors.CompileError:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
@ -259,7 +252,8 @@ def has_flag(compiler, flag):
|
|||||||
cpp_flag_cache = None
|
cpp_flag_cache = None
|
||||||
|
|
||||||
|
|
||||||
def auto_cpp_level(compiler):
|
@lru_cache()
|
||||||
|
def auto_cpp_level(compiler: Any) -> Union[str, int]:
|
||||||
"""
|
"""
|
||||||
Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows.
|
Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows.
|
||||||
"""
|
"""
|
||||||
@ -267,48 +261,38 @@ def auto_cpp_level(compiler):
|
|||||||
if WIN:
|
if WIN:
|
||||||
return "latest"
|
return "latest"
|
||||||
|
|
||||||
global cpp_flag_cache
|
|
||||||
|
|
||||||
# If this has been previously calculated with the same args, return that
|
|
||||||
with cpp_cache_lock:
|
|
||||||
if cpp_flag_cache:
|
|
||||||
return cpp_flag_cache
|
|
||||||
|
|
||||||
levels = [17, 14, 11]
|
levels = [17, 14, 11]
|
||||||
|
|
||||||
for level in levels:
|
for level in levels:
|
||||||
if has_flag(compiler, STD_TMPL.format(level)):
|
if has_flag(compiler, STD_TMPL.format(level)):
|
||||||
with cpp_cache_lock:
|
|
||||||
cpp_flag_cache = level
|
|
||||||
return level
|
return level
|
||||||
|
|
||||||
msg = "Unsupported compiler -- at least C++11 support is needed!"
|
msg = "Unsupported compiler -- at least C++11 support is needed!"
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
|
||||||
class build_ext(_build_ext): # noqa: N801
|
class build_ext(_build_ext): # type: ignore[misc] # noqa: N801
|
||||||
"""
|
"""
|
||||||
Customized build_ext that allows an auto-search for the highest supported
|
Customized build_ext that allows an auto-search for the highest supported
|
||||||
C++ level for Pybind11Extension. This is only needed for the auto-search
|
C++ level for Pybind11Extension. This is only needed for the auto-search
|
||||||
for now, and is completely optional otherwise.
|
for now, and is completely optional otherwise.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def build_extensions(self):
|
def build_extensions(self) -> None:
|
||||||
"""
|
"""
|
||||||
Build extensions, injecting C++ std for Pybind11Extension if needed.
|
Build extensions, injecting C++ std for Pybind11Extension if needed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for ext in self.extensions:
|
for ext in self.extensions:
|
||||||
if hasattr(ext, "_cxx_level") and ext._cxx_level == 0:
|
if hasattr(ext, "_cxx_level") and ext._cxx_level == 0:
|
||||||
# Python 2 syntax - old-style distutils class
|
ext.cxx_std = auto_cpp_level(self.compiler)
|
||||||
ext.__class__.cxx_std.__set__(ext, auto_cpp_level(self.compiler))
|
|
||||||
|
|
||||||
# Python 2 doesn't allow super here, since distutils uses old-style
|
super().build_extensions()
|
||||||
# classes!
|
|
||||||
_build_ext.build_extensions(self)
|
|
||||||
|
|
||||||
|
|
||||||
def intree_extensions(paths, package_dir=None):
|
def intree_extensions(
|
||||||
|
paths: Iterable[str], package_dir: Optional[Dict[str, str]] = None
|
||||||
|
) -> List[Pybind11Extension]:
|
||||||
"""
|
"""
|
||||||
Generate Pybind11Extensions from source files directly located in a Python
|
Generate Pybind11Extensions from source files directly located in a Python
|
||||||
source tree.
|
source tree.
|
||||||
@ -318,6 +302,7 @@ def intree_extensions(paths, package_dir=None):
|
|||||||
not contain an ``__init__.py`` file.
|
not contain an ``__init__.py`` file.
|
||||||
"""
|
"""
|
||||||
exts = []
|
exts = []
|
||||||
|
|
||||||
for path in paths:
|
for path in paths:
|
||||||
if package_dir is None:
|
if package_dir is None:
|
||||||
parent, _ = os.path.split(path)
|
parent, _ = os.path.split(path)
|
||||||
@ -327,24 +312,25 @@ def intree_extensions(paths, package_dir=None):
|
|||||||
qualified_name = relname.replace(os.path.sep, ".")
|
qualified_name = relname.replace(os.path.sep, ".")
|
||||||
exts.append(Pybind11Extension(qualified_name, [path]))
|
exts.append(Pybind11Extension(qualified_name, [path]))
|
||||||
else:
|
else:
|
||||||
found = False
|
|
||||||
for prefix, parent in package_dir.items():
|
for prefix, parent in package_dir.items():
|
||||||
if path.startswith(parent):
|
if path.startswith(parent):
|
||||||
found = True
|
|
||||||
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
||||||
qualified_name = relname.replace(os.path.sep, ".")
|
qualified_name = relname.replace(os.path.sep, ".")
|
||||||
if prefix:
|
if prefix:
|
||||||
qualified_name = prefix + "." + qualified_name
|
qualified_name = prefix + "." + qualified_name
|
||||||
exts.append(Pybind11Extension(qualified_name, [path]))
|
exts.append(Pybind11Extension(qualified_name, [path]))
|
||||||
if not found:
|
|
||||||
raise ValueError(
|
if not exts:
|
||||||
"path {} is not a child of any of the directories listed "
|
msg = (
|
||||||
"in 'package_dir' ({})".format(path, package_dir)
|
"path {path} is not a child of any of the directories listed "
|
||||||
)
|
"in 'package_dir' ({package_dir})"
|
||||||
|
).format(path=path, package_dir=package_dir)
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
return exts
|
return exts
|
||||||
|
|
||||||
|
|
||||||
def naive_recompile(obj, src):
|
def naive_recompile(obj: str, src: str) -> bool:
|
||||||
"""
|
"""
|
||||||
This will recompile only if the source file changes. It does not check
|
This will recompile only if the source file changes. It does not check
|
||||||
header files, so a more advanced function or Ccache is better if you have
|
header files, so a more advanced function or Ccache is better if you have
|
||||||
@ -353,7 +339,7 @@ def naive_recompile(obj, src):
|
|||||||
return os.stat(obj).st_mtime < os.stat(src).st_mtime
|
return os.stat(obj).st_mtime < os.stat(src).st_mtime
|
||||||
|
|
||||||
|
|
||||||
def no_recompile(obg, src):
|
def no_recompile(obg: str, src: str) -> bool:
|
||||||
"""
|
"""
|
||||||
This is the safest but slowest choice (and is the default) - will always
|
This is the safest but slowest choice (and is the default) - will always
|
||||||
recompile sources.
|
recompile sources.
|
||||||
@ -361,15 +347,33 @@ def no_recompile(obg, src):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
S = TypeVar("S", bound="ParallelCompile")
|
||||||
|
|
||||||
|
CCompilerMethod = Callable[
|
||||||
|
[
|
||||||
|
distutils.ccompiler.CCompiler,
|
||||||
|
List[str],
|
||||||
|
Optional[str],
|
||||||
|
Optional[Union[Tuple[str], Tuple[str, Optional[str]]]],
|
||||||
|
Optional[List[str]],
|
||||||
|
bool,
|
||||||
|
Optional[List[str]],
|
||||||
|
Optional[List[str]],
|
||||||
|
Optional[List[str]],
|
||||||
|
],
|
||||||
|
List[str],
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# Optional parallel compile utility
|
# Optional parallel compile utility
|
||||||
# inspired by: http://stackoverflow.com/questions/11013851/speeding-up-build-process-with-distutils
|
# inspired by: http://stackoverflow.com/questions/11013851/speeding-up-build-process-with-distutils
|
||||||
# and: https://github.com/tbenthompson/cppimport/blob/stable/cppimport/build_module.py
|
# and: https://github.com/tbenthompson/cppimport/blob/stable/cppimport/build_module.py
|
||||||
# and NumPy's parallel distutils module:
|
# and NumPy's parallel distutils module:
|
||||||
# https://github.com/numpy/numpy/blob/master/numpy/distutils/ccompiler.py
|
# https://github.com/numpy/numpy/blob/master/numpy/distutils/ccompiler.py
|
||||||
class ParallelCompile(object):
|
class ParallelCompile:
|
||||||
"""
|
"""
|
||||||
Make a parallel compile function. Inspired by
|
Make a parallel compile function. Inspired by
|
||||||
numpy.distutils.ccompiler.CCompiler_compile and cppimport.
|
numpy.distutils.ccompiler.CCompiler.compile and cppimport.
|
||||||
|
|
||||||
This takes several arguments that allow you to customize the compile
|
This takes several arguments that allow you to customize the compile
|
||||||
function created:
|
function created:
|
||||||
@ -404,35 +408,41 @@ class ParallelCompile(object):
|
|||||||
|
|
||||||
__slots__ = ("envvar", "default", "max", "_old", "needs_recompile")
|
__slots__ = ("envvar", "default", "max", "_old", "needs_recompile")
|
||||||
|
|
||||||
def __init__(self, envvar=None, default=0, max=0, needs_recompile=no_recompile):
|
def __init__(
|
||||||
|
self,
|
||||||
|
envvar: Optional[str] = None,
|
||||||
|
default: int = 0,
|
||||||
|
max: int = 0,
|
||||||
|
needs_recompile: Callable[[str, str], bool] = no_recompile,
|
||||||
|
) -> None:
|
||||||
self.envvar = envvar
|
self.envvar = envvar
|
||||||
self.default = default
|
self.default = default
|
||||||
self.max = max
|
self.max = max
|
||||||
self.needs_recompile = needs_recompile
|
self.needs_recompile = needs_recompile
|
||||||
self._old = []
|
self._old = [] # type: List[CCompilerMethod]
|
||||||
|
|
||||||
def function(self):
|
def function(self) -> CCompilerMethod:
|
||||||
"""
|
"""
|
||||||
Builds a function object usable as distutils.ccompiler.CCompiler.compile.
|
Builds a function object usable as distutils.ccompiler.CCompiler.compile.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def compile_function(
|
def compile_function(
|
||||||
compiler,
|
compiler: distutils.ccompiler.CCompiler,
|
||||||
sources,
|
sources: List[str],
|
||||||
output_dir=None,
|
output_dir: Optional[str] = None,
|
||||||
macros=None,
|
macros: Optional[Union[Tuple[str], Tuple[str, Optional[str]]]] = None,
|
||||||
include_dirs=None,
|
include_dirs: Optional[List[str]] = None,
|
||||||
debug=0,
|
debug: bool = False,
|
||||||
extra_preargs=None,
|
extra_preargs: Optional[List[str]] = None,
|
||||||
extra_postargs=None,
|
extra_postargs: Optional[List[str]] = None,
|
||||||
depends=None,
|
depends: Optional[List[str]] = None,
|
||||||
):
|
) -> Any:
|
||||||
|
|
||||||
# These lines are directly from distutils.ccompiler.CCompiler
|
# These lines are directly from distutils.ccompiler.CCompiler
|
||||||
macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile(
|
macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile( # type: ignore[attr-defined]
|
||||||
output_dir, macros, include_dirs, sources, depends, extra_postargs
|
output_dir, macros, include_dirs, sources, depends, extra_postargs
|
||||||
)
|
)
|
||||||
cc_args = compiler._get_cc_args(pp_opts, debug, extra_preargs)
|
cc_args = compiler._get_cc_args(pp_opts, debug, extra_preargs) # type: ignore[attr-defined]
|
||||||
|
|
||||||
# The number of threads; start with default.
|
# The number of threads; start with default.
|
||||||
threads = self.default
|
threads = self.default
|
||||||
@ -441,14 +451,14 @@ class ParallelCompile(object):
|
|||||||
if self.envvar is not None:
|
if self.envvar is not None:
|
||||||
threads = int(os.environ.get(self.envvar, self.default))
|
threads = int(os.environ.get(self.envvar, self.default))
|
||||||
|
|
||||||
def _single_compile(obj):
|
def _single_compile(obj: Any) -> None:
|
||||||
try:
|
try:
|
||||||
src, ext = build[obj]
|
src, ext = build[obj]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not os.path.exists(obj) or self.needs_recompile(obj, src):
|
if not os.path.exists(obj) or self.needs_recompile(obj, src):
|
||||||
compiler._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
|
compiler._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) # type: ignore[attr-defined]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Importing .synchronize checks for platforms that have some multiprocessing
|
# Importing .synchronize checks for platforms that have some multiprocessing
|
||||||
@ -466,14 +476,9 @@ class ParallelCompile(object):
|
|||||||
threads = 1
|
threads = 1
|
||||||
|
|
||||||
if threads > 1:
|
if threads > 1:
|
||||||
pool = ThreadPool(threads)
|
with ThreadPool(threads) as pool:
|
||||||
# In Python 2, ThreadPool can't be used as a context manager.
|
|
||||||
# Once we are no longer supporting it, this can be 'with pool:'
|
|
||||||
try:
|
|
||||||
for _ in pool.imap_unordered(_single_compile, objects):
|
for _ in pool.imap_unordered(_single_compile, objects):
|
||||||
pass
|
pass
|
||||||
finally:
|
|
||||||
pool.terminate()
|
|
||||||
else:
|
else:
|
||||||
for ob in objects:
|
for ob in objects:
|
||||||
_single_compile(ob)
|
_single_compile(ob)
|
||||||
@ -482,13 +487,13 @@ class ParallelCompile(object):
|
|||||||
|
|
||||||
return compile_function
|
return compile_function
|
||||||
|
|
||||||
def install(self):
|
def install(self: S) -> S:
|
||||||
distutils.ccompiler.CCompiler.compile = self.function()
|
distutils.ccompiler.CCompiler.compile = self.function() # type: ignore[assignment]
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self: S) -> S:
|
||||||
self._old.append(distutils.ccompiler.CCompiler.compile)
|
self._old.append(distutils.ccompiler.CCompiler.compile)
|
||||||
return self.install()
|
return self.install()
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args: Any) -> None:
|
||||||
distutils.ccompiler.CCompiler.compile = self._old.pop()
|
distutils.ccompiler.CCompiler.compile = self._old.pop() # type: ignore[assignment]
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
# IMPORTANT: Should stay in sync with setup_helpers.py (mostly checked by CI /
|
|
||||||
# pre-commit).
|
|
||||||
|
|
||||||
import contextlib
|
|
||||||
import distutils.ccompiler
|
|
||||||
from distutils.command.build_ext import build_ext as _build_ext # type: ignore
|
|
||||||
from distutils.extension import Extension as _Extension
|
|
||||||
from types import TracebackType
|
|
||||||
from typing import Any, Callable, Dict, Iterator, List, Optional, Type, TypeVar, Union
|
|
||||||
|
|
||||||
WIN: bool
|
|
||||||
PY2: bool
|
|
||||||
MACOS: bool
|
|
||||||
STD_TMPL: str
|
|
||||||
|
|
||||||
class Pybind11Extension(_Extension):
|
|
||||||
def _add_cflags(self, *flags: str) -> None: ...
|
|
||||||
def _add_lflags(self, *flags: str) -> None: ...
|
|
||||||
def __init__(
|
|
||||||
self, *args: Any, cxx_std: int = 0, language: str = "c++", **kwargs: Any
|
|
||||||
) -> None: ...
|
|
||||||
@property
|
|
||||||
def cxx_std(self) -> int: ...
|
|
||||||
@cxx_std.setter
|
|
||||||
def cxx_std(self, level: int) -> None: ...
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def tmp_chdir() -> Iterator[str]: ...
|
|
||||||
def has_flag(compiler: distutils.ccompiler.CCompiler, flag: str) -> bool: ...
|
|
||||||
def auto_cpp_level(compiler: distutils.ccompiler.CCompiler) -> Union[int, str]: ...
|
|
||||||
|
|
||||||
class build_ext(_build_ext): # type: ignore
|
|
||||||
def build_extensions(self) -> None: ...
|
|
||||||
|
|
||||||
def intree_extensions(
|
|
||||||
paths: Iterator[str], package_dir: Optional[Dict[str, str]] = None
|
|
||||||
) -> List[Pybind11Extension]: ...
|
|
||||||
def no_recompile(obj: str, src: str) -> bool: ...
|
|
||||||
def naive_recompile(obj: str, src: str) -> bool: ...
|
|
||||||
|
|
||||||
T = TypeVar("T", bound="ParallelCompile")
|
|
||||||
|
|
||||||
class ParallelCompile:
|
|
||||||
envvar: Optional[str]
|
|
||||||
default: int
|
|
||||||
max: int
|
|
||||||
needs_recompile: Callable[[str, str], bool]
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
envvar: Optional[str] = None,
|
|
||||||
default: int = 0,
|
|
||||||
max: int = 0,
|
|
||||||
needs_recompile: Callable[[str, str], bool] = no_recompile,
|
|
||||||
) -> None: ...
|
|
||||||
def function(self) -> Any: ...
|
|
||||||
def install(self: T) -> T: ...
|
|
||||||
def __enter__(self: T) -> T: ...
|
|
||||||
def __exit__(
|
|
||||||
self,
|
|
||||||
exc_type: Optional[Type[BaseException]],
|
|
||||||
exc_value: Optional[BaseException],
|
|
||||||
traceback: Optional[TracebackType],
|
|
||||||
) -> None: ...
|
|
@ -22,20 +22,11 @@ known_first_party = "env,pybind11_cross_module_tests,pybind11_tests,"
|
|||||||
profile = "black"
|
profile = "black"
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
files = "pybind11"
|
files = ["pybind11"]
|
||||||
python_version = "2.7"
|
python_version = "3.6"
|
||||||
warn_unused_configs = true
|
warn_unused_configs = true
|
||||||
|
strict = true
|
||||||
|
|
||||||
disallow_any_generics = true
|
[[tool.mypy.overrides]]
|
||||||
disallow_subclassing_any = true
|
module = ["ghapi.*", "setuptools.*"]
|
||||||
disallow_untyped_calls = true
|
ignore_missing_imports = true
|
||||||
disallow_untyped_defs = true
|
|
||||||
disallow_incomplete_defs = true
|
|
||||||
check_untyped_defs = true
|
|
||||||
disallow_untyped_decorators = true
|
|
||||||
no_implicit_optional = true
|
|
||||||
warn_redundant_casts = true
|
|
||||||
warn_unused_ignores = true
|
|
||||||
warn_return_any = true
|
|
||||||
no_implicit_reexport = true
|
|
||||||
strict_equality = true
|
|
||||||
|
10
setup.cfg
10
setup.cfg
@ -13,8 +13,7 @@ classifiers =
|
|||||||
Topic :: Software Development :: Libraries :: Python Modules
|
Topic :: Software Development :: Libraries :: Python Modules
|
||||||
Topic :: Utilities
|
Topic :: Utilities
|
||||||
Programming Language :: C++
|
Programming Language :: C++
|
||||||
Programming Language :: Python :: 2.7
|
Programming Language :: Python :: 3 :: Only
|
||||||
Programming Language :: Python :: 3
|
|
||||||
Programming Language :: Python :: 3.5
|
Programming Language :: Python :: 3.5
|
||||||
Programming Language :: Python :: 3.6
|
Programming Language :: Python :: 3.6
|
||||||
Programming Language :: Python :: 3.7
|
Programming Language :: Python :: 3.7
|
||||||
@ -39,15 +38,12 @@ project_urls =
|
|||||||
Chat = https://gitter.im/pybind/Lobby
|
Chat = https://gitter.im/pybind/Lobby
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
|
python_requires = >=3.5
|
||||||
zip_safe = False
|
zip_safe = False
|
||||||
|
|
||||||
[bdist_wheel]
|
|
||||||
universal=1
|
|
||||||
|
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 99
|
max-line-length = 120
|
||||||
show_source = True
|
show_source = True
|
||||||
exclude = .git, __pycache__, build, dist, docs, tools, venv
|
exclude = .git, __pycache__, build, dist, docs, tools, venv
|
||||||
ignore =
|
ignore =
|
||||||
|
126
setup.py
126
setup.py
@ -1,56 +1,52 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Setup script for PyPI; use CMakeFile.txt to build extension modules
|
# Setup script for PyPI; use CMakeFile.txt to build extension modules
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import io
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import string
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
from pathlib import Path
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
from typing import Dict, Iterator, List, Union
|
||||||
|
|
||||||
import setuptools.command.sdist
|
import setuptools.command.sdist
|
||||||
|
|
||||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
DIR = Path(__file__).parent.absolute()
|
||||||
VERSION_REGEX = re.compile(
|
VERSION_REGEX = re.compile(
|
||||||
r"^\s*#\s*define\s+PYBIND11_VERSION_([A-Z]+)\s+(.*)$", re.MULTILINE
|
r"^\s*#\s*define\s+PYBIND11_VERSION_([A-Z]+)\s+(.*)$", re.MULTILINE
|
||||||
)
|
)
|
||||||
|
VERSION_FILE = Path("pybind11/_version.py")
|
||||||
|
COMMON_FILE = Path("include/pybind11/detail/common.h")
|
||||||
|
|
||||||
|
|
||||||
def build_expected_version_hex(matches):
|
def build_expected_version_hex(matches: Dict[str, str]) -> str:
|
||||||
patch_level_serial = matches["PATCH"]
|
patch_level_serial = matches["PATCH"]
|
||||||
serial = None
|
serial = None
|
||||||
try:
|
major = int(matches["MAJOR"])
|
||||||
major = int(matches["MAJOR"])
|
minor = int(matches["MINOR"])
|
||||||
minor = int(matches["MINOR"])
|
flds = patch_level_serial.split(".")
|
||||||
flds = patch_level_serial.split(".")
|
if flds:
|
||||||
if flds:
|
patch = int(flds[0])
|
||||||
patch = int(flds[0])
|
if len(flds) == 1:
|
||||||
level = None
|
level = "0"
|
||||||
if len(flds) == 1:
|
serial = 0
|
||||||
level = "0"
|
elif len(flds) == 2:
|
||||||
serial = 0
|
level_serial = flds[1]
|
||||||
elif len(flds) == 2:
|
for level in ("a", "b", "c", "dev"):
|
||||||
level_serial = flds[1]
|
if level_serial.startswith(level):
|
||||||
for level in ("a", "b", "c", "dev"):
|
serial = int(level_serial[len(level) :])
|
||||||
if level_serial.startswith(level):
|
break
|
||||||
serial = int(level_serial[len(level) :])
|
|
||||||
break
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
if serial is None:
|
if serial is None:
|
||||||
msg = 'Invalid PYBIND11_VERSION_PATCH: "{}"'.format(patch_level_serial)
|
msg = 'Invalid PYBIND11_VERSION_PATCH: "{}"'.format(patch_level_serial)
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
return (
|
version_hex_str = "{:02x}{:02x}{:02x}{}{:x}".format(
|
||||||
"0x"
|
major, minor, patch, level[:1], serial
|
||||||
+ "{:02x}{:02x}{:02x}{}{:x}".format(
|
|
||||||
major, minor, patch, level[:1], serial
|
|
||||||
).upper()
|
|
||||||
)
|
)
|
||||||
|
return "0x{}".format(version_hex_str.upper())
|
||||||
|
|
||||||
|
|
||||||
# PYBIND11_GLOBAL_SDIST will build a different sdist, with the python-headers
|
# PYBIND11_GLOBAL_SDIST will build a different sdist, with the python-headers
|
||||||
@ -58,24 +54,25 @@ def build_expected_version_hex(matches):
|
|||||||
|
|
||||||
global_sdist = os.environ.get("PYBIND11_GLOBAL_SDIST", False)
|
global_sdist = os.environ.get("PYBIND11_GLOBAL_SDIST", False)
|
||||||
|
|
||||||
setup_py = "tools/setup_global.py.in" if global_sdist else "tools/setup_main.py.in"
|
setup_py = Path(
|
||||||
|
"tools/setup_global.py.in" if global_sdist else "tools/setup_main.py.in"
|
||||||
|
)
|
||||||
extra_cmd = 'cmdclass["sdist"] = SDist\n'
|
extra_cmd = 'cmdclass["sdist"] = SDist\n'
|
||||||
|
|
||||||
to_src = (
|
to_src = (
|
||||||
("pyproject.toml", "tools/pyproject.toml"),
|
(Path("pyproject.toml"), Path("tools/pyproject.toml")),
|
||||||
("setup.py", setup_py),
|
(Path("setup.py"), setup_py),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Read the listed version
|
# Read the listed version
|
||||||
with open("pybind11/_version.py") as f:
|
loc = {} # type: Dict[str, str]
|
||||||
code = compile(f.read(), "pybind11/_version.py", "exec")
|
code = compile(VERSION_FILE.read_text(encoding="utf-8"), "pybind11/_version.py", "exec")
|
||||||
loc = {}
|
|
||||||
exec(code, loc)
|
exec(code, loc)
|
||||||
version = loc["__version__"]
|
version = loc["__version__"]
|
||||||
|
|
||||||
# Verify that the version matches the one in C++
|
# Verify that the version matches the one in C++
|
||||||
with io.open("include/pybind11/detail/common.h", encoding="utf8") as f:
|
matches = dict(VERSION_REGEX.findall(COMMON_FILE.read_text(encoding="utf8")))
|
||||||
matches = dict(VERSION_REGEX.findall(f.read()))
|
|
||||||
cpp_version = "{MAJOR}.{MINOR}.{PATCH}".format(**matches)
|
cpp_version = "{MAJOR}.{MINOR}.{PATCH}".format(**matches)
|
||||||
if version != cpp_version:
|
if version != cpp_version:
|
||||||
msg = "Python version {} does not match C++ version {}!".format(
|
msg = "Python version {} does not match C++ version {}!".format(
|
||||||
@ -84,56 +81,44 @@ if version != cpp_version:
|
|||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
version_hex = matches.get("HEX", "MISSING")
|
version_hex = matches.get("HEX", "MISSING")
|
||||||
expected_version_hex = build_expected_version_hex(matches)
|
exp_version_hex = build_expected_version_hex(matches)
|
||||||
if version_hex != expected_version_hex:
|
if version_hex != exp_version_hex:
|
||||||
msg = "PYBIND11_VERSION_HEX {} does not match expected value {}!".format(
|
msg = "PYBIND11_VERSION_HEX {} does not match expected value {}!".format(
|
||||||
version_hex,
|
version_hex, exp_version_hex
|
||||||
expected_version_hex,
|
|
||||||
)
|
)
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
|
||||||
def get_and_replace(filename, binary=False, **opts):
|
# TODO: use literals & overload (typing extensions or Python 3.8)
|
||||||
with open(filename, "rb" if binary else "r") as f:
|
def get_and_replace(
|
||||||
contents = f.read()
|
filename: Path, binary: bool = False, **opts: str
|
||||||
# Replacement has to be done on text in Python 3 (both work in Python 2)
|
) -> Union[bytes, str]:
|
||||||
if binary:
|
if binary:
|
||||||
|
contents = filename.read_bytes()
|
||||||
return string.Template(contents.decode()).substitute(opts).encode()
|
return string.Template(contents.decode()).substitute(opts).encode()
|
||||||
else:
|
|
||||||
return string.Template(contents).substitute(opts)
|
return string.Template(filename.read_text()).substitute(opts)
|
||||||
|
|
||||||
|
|
||||||
# Use our input files instead when making the SDist (and anything that depends
|
# Use our input files instead when making the SDist (and anything that depends
|
||||||
# on it, like a wheel)
|
# on it, like a wheel)
|
||||||
class SDist(setuptools.command.sdist.sdist):
|
class SDist(setuptools.command.sdist.sdist): # type: ignore[misc]
|
||||||
def make_release_tree(self, base_dir, files):
|
def make_release_tree(self, base_dir: str, files: List[str]) -> None:
|
||||||
setuptools.command.sdist.sdist.make_release_tree(self, base_dir, files)
|
super().make_release_tree(base_dir, files)
|
||||||
|
|
||||||
for to, src in to_src:
|
for to, src in to_src:
|
||||||
txt = get_and_replace(src, binary=True, version=version, extra_cmd="")
|
txt = get_and_replace(src, binary=True, version=version, extra_cmd="")
|
||||||
|
|
||||||
dest = os.path.join(base_dir, to)
|
dest = Path(base_dir) / to
|
||||||
|
|
||||||
# This is normally linked, so unlink before writing!
|
# This is normally linked, so unlink before writing!
|
||||||
os.unlink(dest)
|
dest.unlink()
|
||||||
with open(dest, "wb") as f:
|
dest.write_bytes(txt) # type: ignore[arg-type]
|
||||||
f.write(txt)
|
|
||||||
|
|
||||||
|
|
||||||
# Backport from Python 3
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def TemporaryDirectory(): # noqa: N802
|
|
||||||
"Prepare a temporary directory, cleanup when done"
|
|
||||||
try:
|
|
||||||
tmpdir = tempfile.mkdtemp()
|
|
||||||
yield tmpdir
|
|
||||||
finally:
|
|
||||||
shutil.rmtree(tmpdir)
|
|
||||||
|
|
||||||
|
|
||||||
# Remove the CMake install directory when done
|
# Remove the CMake install directory when done
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def remove_output(*sources):
|
def remove_output(*sources: str) -> Iterator[None]:
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
@ -156,9 +141,14 @@ with remove_output("pybind11/include", "pybind11/share"):
|
|||||||
if "DCMAKE_INSTALL_PREFIX" not in c
|
if "DCMAKE_INSTALL_PREFIX" not in c
|
||||||
]
|
]
|
||||||
cmd += fcommand
|
cmd += fcommand
|
||||||
cmake_opts = dict(cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
subprocess.run(cmd, check=True, cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
||||||
subprocess.check_call(cmd, **cmake_opts)
|
subprocess.run(
|
||||||
subprocess.check_call(["cmake", "--install", tmpdir], **cmake_opts)
|
["cmake", "--install", tmpdir],
|
||||||
|
check=True,
|
||||||
|
cwd=DIR,
|
||||||
|
stdout=sys.stdout,
|
||||||
|
stderr=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
txt = get_and_replace(setup_py, version=version, extra_cmd=extra_cmd)
|
txt = get_and_replace(setup_py, version=version, extra_cmd=extra_cmd)
|
||||||
code = compile(txt, setup_py, "exec")
|
code = compile(txt, setup_py, "exec")
|
||||||
|
@ -179,11 +179,6 @@ if(PYBIND11_TEST_FILTER)
|
|||||||
pybind11_filter_tests(PYBIND11_TEST_FILES ${PYBIND11_TEST_FILTER})
|
pybind11_filter_tests(PYBIND11_TEST_FILES ${PYBIND11_TEST_FILTER})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(PYTHON_VERSION VERSION_LESS 3.5)
|
|
||||||
pybind11_filter_tests(PYBIND11_TEST_FILES test_async.cpp MESSAGE
|
|
||||||
"Skipping test_async on Python 2")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Skip tests for CUDA check:
|
# Skip tests for CUDA check:
|
||||||
# /pybind11/tests/test_constants_and_functions.cpp(125):
|
# /pybind11/tests/test_constants_and_functions.cpp(125):
|
||||||
# error: incompatible exception specifications
|
# error: incompatible exception specifications
|
||||||
@ -388,17 +383,6 @@ function(pybind11_enable_warnings target_name)
|
|||||||
-diag-disable 11074,11076)
|
-diag-disable 11074,11076)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Needs to be re-added since the ordering requires these to be after the ones above
|
|
||||||
if(CMAKE_CXX_STANDARD
|
|
||||||
AND CMAKE_CXX_COMPILER_ID MATCHES "Clang"
|
|
||||||
AND PYTHON_VERSION VERSION_LESS 3.0)
|
|
||||||
if(CMAKE_CXX_STANDARD LESS 17)
|
|
||||||
target_compile_options(${target_name} PUBLIC -Wno-deprecated-register)
|
|
||||||
else()
|
|
||||||
target_compile_options(${target_name} PUBLIC -Wno-register)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
set(test_targets pybind11_tests)
|
set(test_targets pybind11_tests)
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""pytest configuration
|
"""pytest configuration
|
||||||
|
|
||||||
Extends output capture as needed by pybind11: ignore constructors, optional unordered lines.
|
Extends output capture as needed by pybind11: ignore constructors, optional unordered lines.
|
||||||
Adds docstring and exceptions message sanitizers: ignore Python 2 vs 3 differences.
|
Adds docstring and exceptions message sanitizers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
@ -13,19 +12,14 @@ import textwrap
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
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(\'[^\']*\')")
|
|
||||||
_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 = []
|
||||||
if env.PY2:
|
|
||||||
collect_ignore.append("test_async.py")
|
|
||||||
|
|
||||||
|
|
||||||
def _strip_and_dedent(s):
|
def _strip_and_dedent(s):
|
||||||
@ -45,7 +39,7 @@ def _make_explanation(a, b):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Output(object):
|
class Output:
|
||||||
"""Basic output post-processing and comparison"""
|
"""Basic output post-processing and comparison"""
|
||||||
|
|
||||||
def __init__(self, string):
|
def __init__(self, string):
|
||||||
@ -83,7 +77,7 @@ class Unordered(Output):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Capture(object):
|
class Capture:
|
||||||
def __init__(self, capfd):
|
def __init__(self, capfd):
|
||||||
self.capfd = capfd
|
self.capfd = capfd
|
||||||
self.out = ""
|
self.out = ""
|
||||||
@ -126,7 +120,7 @@ def capture(capsys):
|
|||||||
return Capture(capsys)
|
return Capture(capsys)
|
||||||
|
|
||||||
|
|
||||||
class SanitizedString(object):
|
class SanitizedString:
|
||||||
def __init__(self, sanitizer):
|
def __init__(self, sanitizer):
|
||||||
self.sanitizer = sanitizer
|
self.sanitizer = sanitizer
|
||||||
self.string = ""
|
self.string = ""
|
||||||
@ -149,9 +143,7 @@ class SanitizedString(object):
|
|||||||
def _sanitize_general(s):
|
def _sanitize_general(s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
s = s.replace("pybind11_tests.", "m.")
|
s = s.replace("pybind11_tests.", "m.")
|
||||||
s = s.replace("unicode", "str")
|
|
||||||
s = _long_marker.sub(r"\1", s)
|
s = _long_marker.sub(r"\1", s)
|
||||||
s = _unicode_marker.sub(r"\1", s)
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,31 +25,14 @@ void gil_acquire() { py::gil_scoped_acquire gil; }
|
|||||||
|
|
||||||
constexpr char kModuleName[] = "cross_module_gil_utils";
|
constexpr char kModuleName[] = "cross_module_gil_utils";
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
struct PyModuleDef moduledef
|
struct PyModuleDef moduledef
|
||||||
= {PyModuleDef_HEAD_INIT, kModuleName, NULL, 0, NULL, NULL, NULL, NULL, NULL};
|
= {PyModuleDef_HEAD_INIT, kModuleName, NULL, 0, NULL, NULL, NULL, NULL, NULL};
|
||||||
#else
|
|
||||||
PyMethodDef module_methods[] = {{NULL, NULL, 0, NULL}};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" PYBIND11_EXPORT
|
extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
PyObject *
|
|
||||||
PyInit_cross_module_gil_utils()
|
|
||||||
#else
|
|
||||||
void
|
|
||||||
initcross_module_gil_utils()
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
|
|
||||||
PyObject *m =
|
PyObject *m = PyModule_Create(&moduledef);
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
PyModule_Create(&moduledef);
|
|
||||||
#else
|
|
||||||
Py_InitModule(kModuleName, module_methods);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (m != NULL) {
|
if (m != NULL) {
|
||||||
static_assert(sizeof(&gil_acquire) == sizeof(void *),
|
static_assert(sizeof(&gil_acquire) == sizeof(void *),
|
||||||
@ -58,7 +41,5 @@ extern "C" PYBIND11_EXPORT
|
|||||||
m, "gil_acquire_funcaddr", PyLong_FromVoidPtr(reinterpret_cast<void *>(&gil_acquire)));
|
m, "gil_acquire_funcaddr", PyLong_FromVoidPtr(reinterpret_cast<void *>(&gil_acquire)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
return m;
|
return m;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -11,10 +10,6 @@ WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
|
|||||||
CPYTHON = platform.python_implementation() == "CPython"
|
CPYTHON = platform.python_implementation() == "CPython"
|
||||||
PYPY = platform.python_implementation() == "PyPy"
|
PYPY = platform.python_implementation() == "PyPy"
|
||||||
|
|
||||||
PY2 = sys.version_info.major == 2
|
|
||||||
|
|
||||||
PY = sys.version_info
|
|
||||||
|
|
||||||
|
|
||||||
def deprecated_call():
|
def deprecated_call():
|
||||||
"""
|
"""
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import string
|
import string
|
||||||
@ -64,11 +63,9 @@ py_files = {
|
|||||||
"__init__.py",
|
"__init__.py",
|
||||||
"__main__.py",
|
"__main__.py",
|
||||||
"_version.py",
|
"_version.py",
|
||||||
"_version.pyi",
|
|
||||||
"commands.py",
|
"commands.py",
|
||||||
"py.typed",
|
"py.typed",
|
||||||
"setup_helpers.py",
|
"setup_helpers.py",
|
||||||
"setup_helpers.pyi",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
headers = main_headers | detail_headers | stl_headers
|
headers = main_headers | detail_headers | stl_headers
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@ -19,7 +18,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
|||||||
|
|
||||||
(tmpdir / "setup.py").write_text(
|
(tmpdir / "setup.py").write_text(
|
||||||
dedent(
|
dedent(
|
||||||
u"""\
|
"""\
|
||||||
import sys
|
import sys
|
||||||
sys.path.append({MAIN_DIR!r})
|
sys.path.append({MAIN_DIR!r})
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
|||||||
|
|
||||||
(tmpdir / "main.cpp").write_text(
|
(tmpdir / "main.cpp").write_text(
|
||||||
dedent(
|
dedent(
|
||||||
u"""\
|
"""\
|
||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
int f(int x) {
|
int f(int x) {
|
||||||
@ -96,7 +95,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
|||||||
|
|
||||||
(tmpdir / "test.py").write_text(
|
(tmpdir / "test.py").write_text(
|
||||||
dedent(
|
dedent(
|
||||||
u"""\
|
"""\
|
||||||
import simple_setup
|
import simple_setup
|
||||||
assert simple_setup.f(3) == 9
|
assert simple_setup.f(3) == 9
|
||||||
"""
|
"""
|
||||||
@ -121,10 +120,11 @@ def test_intree_extensions(monkeypatch, tmpdir):
|
|||||||
subdir.ensure_dir()
|
subdir.ensure_dir()
|
||||||
src = subdir / "ext.cpp"
|
src = subdir / "ext.cpp"
|
||||||
src.ensure()
|
src.ensure()
|
||||||
(ext,) = intree_extensions([src.relto(tmpdir)])
|
relpath = src.relto(tmpdir)
|
||||||
|
(ext,) = intree_extensions([relpath])
|
||||||
assert ext.name == "ext"
|
assert ext.name == "ext"
|
||||||
subdir.ensure("__init__.py")
|
subdir.ensure("__init__.py")
|
||||||
(ext,) = intree_extensions([src.relto(tmpdir)])
|
(ext,) = intree_extensions([relpath])
|
||||||
assert ext.name == "dir.ext"
|
assert ext.name == "dir.ext"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
asyncio = pytest.importorskip("asyncio")
|
asyncio = pytest.importorskip("asyncio")
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import ctypes
|
import ctypes
|
||||||
import io
|
import io
|
||||||
import struct
|
import struct
|
||||||
@ -93,16 +92,16 @@ def test_pointer_to_member_fn():
|
|||||||
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] == 0x64
|
||||||
assert view.readonly
|
assert view.readonly
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
view[0] = b"\0" if env.PY2 else 0
|
view[0] = 0
|
||||||
|
|
||||||
|
|
||||||
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] = 0x64
|
||||||
assert buf.value == 0x64
|
assert buf.value == 0x64
|
||||||
|
|
||||||
io.BytesIO(b"A").readinto(buf)
|
io.BytesIO(b"A").readinto(buf)
|
||||||
@ -110,7 +109,7 @@ def test_selective_readonly_buffer():
|
|||||||
|
|
||||||
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] = 0
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
io.BytesIO(b"1").readinto(buf)
|
io.BytesIO(b"1").readinto(buf)
|
||||||
|
|
||||||
@ -145,9 +144,6 @@ def test_ctypes_array_2d():
|
|||||||
assert not info.readonly
|
assert not info.readonly
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
"env.PYPY and env.PY2", reason="PyPy2 bytes buffer not reported as readonly"
|
|
||||||
)
|
|
||||||
def test_ctypes_from_buffer():
|
def test_ctypes_from_buffer():
|
||||||
test_pystr = b"0123456789"
|
test_pystr = b"0123456789"
|
||||||
for pyarray in (test_pystr, bytearray(test_pystr)):
|
for pyarray in (test_pystr, bytearray(test_pystr)):
|
||||||
|
@ -110,8 +110,7 @@ TEST_SUBMODULE(builtin_casters, m) {
|
|||||||
"def");
|
"def");
|
||||||
});
|
});
|
||||||
m.def("bad_utf16_string", [=]() { return std::u16string({b16, char16_t(0xd800), z16}); });
|
m.def("bad_utf16_string", [=]() { return std::u16string({b16, char16_t(0xd800), z16}); });
|
||||||
#if PY_MAJOR_VERSION >= 3
|
// Under Python 2.7, invalid unicode UTF-32 characters didn't appear to trigger
|
||||||
// Under Python 2.7, invalid unicode UTF-32 characters don't appear to trigger
|
|
||||||
// UnicodeDecodeError
|
// UnicodeDecodeError
|
||||||
m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
|
m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
|
||||||
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(wchar_t) == 2)) {
|
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(wchar_t) == 2)) {
|
||||||
@ -119,7 +118,6 @@ TEST_SUBMODULE(builtin_casters, m) {
|
|||||||
return std::wstring({wchar_t(0x61), wchar_t(0xd800)});
|
return std::wstring({wchar_t(0x61), wchar_t(0xd800)});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
m.def("u8_Z", []() -> char { return 'Z'; });
|
m.def("u8_Z", []() -> char { return 'Z'; });
|
||||||
m.def("u8_eacute", []() -> char { return '\xe9'; });
|
m.def("u8_eacute", []() -> char { return '\xe9'; });
|
||||||
m.def("u16_ibang", [=]() -> char16_t { return ib16; });
|
m.def("u16_ibang", [=]() -> char16_t { return ib16; });
|
||||||
@ -198,12 +196,10 @@ TEST_SUBMODULE(builtin_casters, m) {
|
|||||||
[]() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); });
|
[]() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); });
|
||||||
m.def("string_view_from_bytes",
|
m.def("string_view_from_bytes",
|
||||||
[](const py::bytes &b) { return [](std::string_view s) { return s; }(b); });
|
[](const py::bytes &b) { return [](std::string_view s) { return s; }(b); });
|
||||||
# if PY_MAJOR_VERSION >= 3
|
|
||||||
m.def("string_view_memoryview", []() {
|
m.def("string_view_memoryview", []() {
|
||||||
static constexpr auto val = "Have some \360\237\216\202"sv;
|
static constexpr auto val = "Have some \360\237\216\202"sv;
|
||||||
return py::memoryview::from_memory(val);
|
return py::memoryview::from_memory(val);
|
||||||
});
|
});
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifdef PYBIND11_HAS_U8STRING
|
# ifdef PYBIND11_HAS_U8STRING
|
||||||
m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
|
m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
import sys
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env
|
import env
|
||||||
@ -12,12 +13,12 @@ def test_simple_string():
|
|||||||
|
|
||||||
def test_unicode_conversion():
|
def test_unicode_conversion():
|
||||||
"""Tests unicode conversion and error reporting."""
|
"""Tests unicode conversion and error reporting."""
|
||||||
assert m.good_utf8_string() == u"Say utf8‽ 🎂 𝐀"
|
assert m.good_utf8_string() == "Say utf8‽ 🎂 𝐀"
|
||||||
assert m.good_utf16_string() == u"b‽🎂𝐀z"
|
assert m.good_utf16_string() == "b‽🎂𝐀z"
|
||||||
assert m.good_utf32_string() == u"a𝐀🎂‽z"
|
assert m.good_utf32_string() == "a𝐀🎂‽z"
|
||||||
assert m.good_wchar_string() == u"a⸘𝐀z"
|
assert m.good_wchar_string() == "a⸘𝐀z"
|
||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
assert m.good_utf8_u8string() == u"Say utf8‽ 🎂 𝐀"
|
assert m.good_utf8_u8string() == "Say utf8‽ 🎂 𝐀"
|
||||||
|
|
||||||
with pytest.raises(UnicodeDecodeError):
|
with pytest.raises(UnicodeDecodeError):
|
||||||
m.bad_utf8_string()
|
m.bad_utf8_string()
|
||||||
@ -25,7 +26,7 @@ def test_unicode_conversion():
|
|||||||
with pytest.raises(UnicodeDecodeError):
|
with pytest.raises(UnicodeDecodeError):
|
||||||
m.bad_utf16_string()
|
m.bad_utf16_string()
|
||||||
|
|
||||||
# These are provided only if they actually fail (they don't when 32-bit and under Python 2.7)
|
# These are provided only if they actually fail (they don't when 32-bit)
|
||||||
if hasattr(m, "bad_utf32_string"):
|
if hasattr(m, "bad_utf32_string"):
|
||||||
with pytest.raises(UnicodeDecodeError):
|
with pytest.raises(UnicodeDecodeError):
|
||||||
m.bad_utf32_string()
|
m.bad_utf32_string()
|
||||||
@ -37,10 +38,10 @@ def test_unicode_conversion():
|
|||||||
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() == "é"
|
||||||
assert m.u16_ibang() == u"‽"
|
assert m.u16_ibang() == "‽"
|
||||||
assert m.u32_mathbfA() == u"𝐀"
|
assert m.u32_mathbfA() == "𝐀"
|
||||||
assert m.wchar_heart() == u"♥"
|
assert m.wchar_heart() == "♥"
|
||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
assert m.u8_char8_Z() == "Z"
|
assert m.u8_char8_Z() == "Z"
|
||||||
|
|
||||||
@ -53,68 +54,68 @@ def test_single_char_arguments():
|
|||||||
|
|
||||||
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("a") == 0x61 # simple ASCII
|
||||||
assert m.ord_char_lv(u"b") == 0x62
|
assert m.ord_char_lv("b") == 0x62
|
||||||
assert (
|
assert (
|
||||||
m.ord_char(u"é") == 0xE9
|
m.ord_char("é") == 0xE9
|
||||||
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
) # 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("Ā") == 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("ab")
|
||||||
assert str(excinfo.value) == toolong_message
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
assert m.ord_char16(u"a") == 0x61
|
assert m.ord_char16("a") == 0x61
|
||||||
assert m.ord_char16(u"é") == 0xE9
|
assert m.ord_char16("é") == 0xE9
|
||||||
assert m.ord_char16_lv(u"ê") == 0xEA
|
assert m.ord_char16_lv("ê") == 0xEA
|
||||||
assert m.ord_char16(u"Ā") == 0x100
|
assert m.ord_char16("Ā") == 0x100
|
||||||
assert m.ord_char16(u"‽") == 0x203D
|
assert m.ord_char16("‽") == 0x203D
|
||||||
assert m.ord_char16(u"♥") == 0x2665
|
assert m.ord_char16("♥") == 0x2665
|
||||||
assert m.ord_char16_lv(u"♡") == 0x2661
|
assert m.ord_char16_lv("♡") == 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("🎂") == 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("aa")
|
||||||
assert str(excinfo.value) == toolong_message
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
assert m.ord_char32(u"a") == 0x61
|
assert m.ord_char32("a") == 0x61
|
||||||
assert m.ord_char32(u"é") == 0xE9
|
assert m.ord_char32("é") == 0xE9
|
||||||
assert m.ord_char32(u"Ā") == 0x100
|
assert m.ord_char32("Ā") == 0x100
|
||||||
assert m.ord_char32(u"‽") == 0x203D
|
assert m.ord_char32("‽") == 0x203D
|
||||||
assert m.ord_char32(u"♥") == 0x2665
|
assert m.ord_char32("♥") == 0x2665
|
||||||
assert m.ord_char32(u"🎂") == 0x1F382
|
assert m.ord_char32("🎂") == 0x1F382
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
assert m.ord_char32(u"aa")
|
assert m.ord_char32("aa")
|
||||||
assert str(excinfo.value) == toolong_message
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
assert m.ord_wchar(u"a") == 0x61
|
assert m.ord_wchar("a") == 0x61
|
||||||
assert m.ord_wchar(u"é") == 0xE9
|
assert m.ord_wchar("é") == 0xE9
|
||||||
assert m.ord_wchar(u"Ā") == 0x100
|
assert m.ord_wchar("Ā") == 0x100
|
||||||
assert m.ord_wchar(u"‽") == 0x203D
|
assert m.ord_wchar("‽") == 0x203D
|
||||||
assert m.ord_wchar(u"♥") == 0x2665
|
assert m.ord_wchar("♥") == 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("🎂") == 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("🎂") == 0x1F382
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
assert m.ord_wchar(u"aa")
|
assert m.ord_wchar("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("a") == 0x61 # simple ASCII
|
||||||
assert m.ord_char8_lv(u"b") == 0x62
|
assert m.ord_char8_lv("b") == 0x62
|
||||||
assert (
|
assert (
|
||||||
m.ord_char8(u"é") == 0xE9
|
m.ord_char8("é") == 0xE9
|
||||||
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
) # 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("Ā") == 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("ab")
|
||||||
assert str(excinfo.value) == toolong_message
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
|
|
||||||
@ -123,18 +124,13 @@ def test_bytes_to_string():
|
|||||||
one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
|
one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
|
||||||
# Issue #816
|
# Issue #816
|
||||||
|
|
||||||
def to_bytes(s):
|
assert m.strlen(b"hi") == 2
|
||||||
b = s if env.PY2 else s.encode("utf8")
|
assert m.string_length(b"world") == 5
|
||||||
assert isinstance(b, bytes)
|
assert m.string_length("a\x00b".encode()) == 3
|
||||||
return b
|
assert m.strlen("a\x00b".encode()) == 1 # C-string limitation
|
||||||
|
|
||||||
assert m.strlen(to_bytes("hi")) == 2
|
|
||||||
assert m.string_length(to_bytes("world")) == 5
|
|
||||||
assert m.string_length(to_bytes("a\x00b")) == 3
|
|
||||||
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("💩".encode()) == 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>")
|
||||||
@ -142,26 +138,26 @@ 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("Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
|
||||||
assert m.string_view32_chars(u"Hi 🎂") == [72, 105, 32, 127874]
|
assert m.string_view32_chars("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("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
||||||
|
|
||||||
assert m.string_view_return() == u"utf8 secret 🎂"
|
assert m.string_view_return() == "utf8 secret 🎂"
|
||||||
assert m.string_view16_return() == u"utf16 secret 🎂"
|
assert m.string_view16_return() == "utf16 secret 🎂"
|
||||||
assert m.string_view32_return() == u"utf32 secret 🎂"
|
assert m.string_view32_return() == "utf32 secret 🎂"
|
||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
assert m.string_view8_return() == u"utf8 secret 🎂"
|
assert m.string_view8_return() == "utf8 secret 🎂"
|
||||||
|
|
||||||
with capture:
|
with capture:
|
||||||
m.string_view_print("Hi")
|
m.string_view_print("Hi")
|
||||||
m.string_view_print("utf8 🎂")
|
m.string_view_print("utf8 🎂")
|
||||||
m.string_view16_print(u"utf16 🎂")
|
m.string_view16_print("utf16 🎂")
|
||||||
m.string_view32_print(u"utf32 🎂")
|
m.string_view32_print("utf32 🎂")
|
||||||
assert (
|
assert (
|
||||||
capture
|
capture
|
||||||
== u"""
|
== """
|
||||||
Hi 2
|
Hi 2
|
||||||
utf8 🎂 9
|
utf8 🎂 9
|
||||||
utf16 🎂 8
|
utf16 🎂 8
|
||||||
@ -171,10 +167,10 @@ def test_string_view(capture):
|
|||||||
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("utf8 🎂")
|
||||||
assert (
|
assert (
|
||||||
capture
|
capture
|
||||||
== u"""
|
== """
|
||||||
Hi 2
|
Hi 2
|
||||||
utf8 🎂 9
|
utf8 🎂 9
|
||||||
"""
|
"""
|
||||||
@ -183,11 +179,11 @@ def test_string_view(capture):
|
|||||||
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("Hi, utf16 🎂")
|
||||||
m.string_view32_print(u"Hi, utf32 🎂")
|
m.string_view32_print("Hi, utf32 🎂")
|
||||||
assert (
|
assert (
|
||||||
capture
|
capture
|
||||||
== u"""
|
== """
|
||||||
Hi, ascii 9
|
Hi, ascii 9
|
||||||
Hi, utf8 🎂 13
|
Hi, utf8 🎂 13
|
||||||
Hi, utf16 🎂 12
|
Hi, utf16 🎂 12
|
||||||
@ -197,22 +193,21 @@ def test_string_view(capture):
|
|||||||
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("Hi, utf8 🎂")
|
||||||
assert (
|
assert (
|
||||||
capture
|
capture
|
||||||
== u"""
|
== """
|
||||||
Hi, ascii 9
|
Hi, ascii 9
|
||||||
Hi, utf8 🎂 13
|
Hi, utf8 🎂 13
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
assert m.string_view_bytes() == b"abc \x80\x80 def"
|
assert m.string_view_bytes() == b"abc \x80\x80 def"
|
||||||
assert m.string_view_str() == u"abc ‽ def"
|
assert m.string_view_str() == "abc ‽ def"
|
||||||
assert m.string_view_from_bytes(u"abc ‽ def".encode("utf-8")) == u"abc ‽ def"
|
assert m.string_view_from_bytes("abc ‽ def".encode()) == "abc ‽ def"
|
||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
assert m.string_view8_str() == u"abc ‽ def"
|
assert m.string_view8_str() == "abc ‽ def"
|
||||||
if not env.PY2:
|
assert m.string_view_memoryview() == "Have some 🎂".encode()
|
||||||
assert m.string_view_memoryview() == "Have some 🎂".encode()
|
|
||||||
|
|
||||||
assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success"
|
assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success"
|
||||||
assert m.str_from_type_with_both_operator_string_and_string_view() == "success"
|
assert m.str_from_type_with_both_operator_string_and_string_view() == "success"
|
||||||
@ -224,20 +219,8 @@ def test_integer_casting():
|
|||||||
assert m.i64_str(-1) == "-1"
|
assert m.i64_str(-1) == "-1"
|
||||||
assert m.i32_str(2000000000) == "2000000000"
|
assert m.i32_str(2000000000) == "2000000000"
|
||||||
assert m.u32_str(2000000000) == "2000000000"
|
assert m.u32_str(2000000000) == "2000000000"
|
||||||
if env.PY2:
|
assert m.i64_str(-999999999999) == "-999999999999"
|
||||||
assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
assert m.u64_str(999999999999) == "999999999999"
|
||||||
assert m.i64_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
|
||||||
assert (
|
|
||||||
m.i64_str(long(-999999999999)) # noqa: F821 undefined name 'long'
|
|
||||||
== "-999999999999"
|
|
||||||
)
|
|
||||||
assert (
|
|
||||||
m.u64_str(long(999999999999)) # noqa: F821 undefined name 'long'
|
|
||||||
== "999999999999"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
assert m.i64_str(-999999999999) == "-999999999999"
|
|
||||||
assert m.u64_str(999999999999) == "999999999999"
|
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
m.u32_str(-1)
|
m.u32_str(-1)
|
||||||
@ -252,46 +235,38 @@ def test_integer_casting():
|
|||||||
m.i32_str(3000000000)
|
m.i32_str(3000000000)
|
||||||
assert "incompatible function arguments" in str(excinfo.value)
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
|
||||||
if env.PY2:
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
|
||||||
m.u32_str(long(-1)) # noqa: F821 undefined name 'long'
|
|
||||||
assert "incompatible function arguments" in str(excinfo.value)
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
|
||||||
m.u64_str(long(-1)) # noqa: F821 undefined name 'long'
|
|
||||||
assert "incompatible function arguments" in str(excinfo.value)
|
|
||||||
|
|
||||||
|
|
||||||
def test_int_convert():
|
def test_int_convert():
|
||||||
class Int(object):
|
class Int:
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
class NotInt(object):
|
class NotInt:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Float(object):
|
class Float:
|
||||||
def __float__(self):
|
def __float__(self):
|
||||||
return 41.99999
|
return 41.99999
|
||||||
|
|
||||||
class Index(object):
|
class Index:
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
class IntAndIndex(object):
|
class IntAndIndex:
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
class RaisingTypeErrorOnIndex(object):
|
class RaisingTypeErrorOnIndex:
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
class RaisingValueErrorOnIndex(object):
|
class RaisingValueErrorOnIndex:
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@ -311,7 +286,7 @@ def test_int_convert():
|
|||||||
cant_convert(3.14159)
|
cant_convert(3.14159)
|
||||||
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
||||||
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
||||||
if (3, 8) <= env.PY < (3, 10) and env.CPYTHON:
|
if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
|
||||||
with env.deprecated_call():
|
with env.deprecated_call():
|
||||||
assert convert(Int()) == 42
|
assert convert(Int()) == 42
|
||||||
else:
|
else:
|
||||||
@ -348,7 +323,7 @@ def test_numpy_int_convert():
|
|||||||
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
||||||
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
||||||
# https://github.com/pybind/pybind11/issues/3408
|
# https://github.com/pybind/pybind11/issues/3408
|
||||||
if (3, 8) <= env.PY < (3, 10) and env.CPYTHON:
|
if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
|
||||||
with env.deprecated_call():
|
with env.deprecated_call():
|
||||||
assert convert(np.float32(3.14159)) == 3
|
assert convert(np.float32(3.14159)) == 3
|
||||||
else:
|
else:
|
||||||
@ -475,7 +450,7 @@ def test_bool_caster():
|
|||||||
require_implicit(None)
|
require_implicit(None)
|
||||||
assert convert(None) is False
|
assert convert(None) is False
|
||||||
|
|
||||||
class A(object):
|
class A:
|
||||||
def __init__(self, x):
|
def __init__(self, x):
|
||||||
self.x = x
|
self.x = x
|
||||||
|
|
||||||
@ -485,7 +460,7 @@ def test_bool_caster():
|
|||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
return self.x
|
return self.x
|
||||||
|
|
||||||
class B(object):
|
class B:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Arbitrary objects are not accepted
|
# Arbitrary objects are not accepted
|
||||||
@ -515,17 +490,9 @@ def test_numpy_bool():
|
|||||||
|
|
||||||
|
|
||||||
def test_int_long():
|
def test_int_long():
|
||||||
"""In Python 2, a C++ int should return a Python int rather than long
|
|
||||||
if possible: longs are not always accepted where ints are used (such
|
|
||||||
as the argument to sys.exit()). A C++ long long is always a Python
|
|
||||||
long."""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
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(), int)
|
||||||
|
|
||||||
|
|
||||||
def test_void_caster_2():
|
def test_void_caster_2():
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import time
|
import time
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
@ -7,7 +6,6 @@ from pybind11_tests import class_ as m
|
|||||||
|
|
||||||
|
|
||||||
def test_repr():
|
def test_repr():
|
||||||
# In Python 3.3+, repr() accesses __qualname__
|
|
||||||
assert "pybind11_type" in repr(type(UserType))
|
assert "pybind11_type" in repr(type(UserType))
|
||||||
assert "UserType" in repr(UserType)
|
assert "UserType" in repr(UserType)
|
||||||
|
|
||||||
@ -103,8 +101,8 @@ def test_docstrings(doc):
|
|||||||
|
|
||||||
|
|
||||||
def test_qualname(doc):
|
def test_qualname(doc):
|
||||||
"""Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we
|
"""Tests that a properly qualified name is set in __qualname__ and that
|
||||||
backport the attribute) and that generated docstrings properly use it and the module name"""
|
generated docstrings properly use it and the module name"""
|
||||||
assert m.NestBase.__qualname__ == "NestBase"
|
assert m.NestBase.__qualname__ == "NestBase"
|
||||||
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
|
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
|
||||||
|
|
||||||
@ -130,13 +128,13 @@ def test_qualname(doc):
|
|||||||
doc(m.NestBase.Nested.fn)
|
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
|
"""
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
doc(m.NestBase.Nested.fa)
|
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
|
"""
|
||||||
)
|
)
|
||||||
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_"
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import test_cmake_build
|
import test_cmake_build
|
||||||
|
|
||||||
if str is not bytes: # If not Python2
|
assert isinstance(__file__, str) # Test this is properly set
|
||||||
assert isinstance(__file__, str) # Test this is properly set
|
|
||||||
|
|
||||||
assert test_cmake_build.add(1, 2) == 3
|
assert test_cmake_build.add(1, 2) == 3
|
||||||
print("{} imports, runs, and adds: 1 + 2 = 3".format(sys.argv[1]))
|
print("{} imports, runs, and adds: 1 + 2 = 3".format(sys.argv[1]))
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env
|
|
||||||
from pybind11_tests import const_name as m
|
from pybind11_tests import const_name as m
|
||||||
|
|
||||||
|
|
||||||
@ -25,7 +23,7 @@ from pybind11_tests import const_name as m
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
def test_const_name(func, selector, expected):
|
def test_const_name(func, selector, expected):
|
||||||
if isinstance(func, type(u"") if env.PY2 else str):
|
if isinstance(func, str):
|
||||||
pytest.skip(func)
|
pytest.skip(func)
|
||||||
text = func(selector)
|
text = func(selector)
|
||||||
assert text == expected
|
assert text == expected
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import copy_move_policies as m
|
from pybind11_tests import copy_move_policies as m
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import custom_type_casters as m
|
from pybind11_tests import custom_type_casters as m
|
||||||
@ -19,7 +18,7 @@ def test_noconvert_args(msg):
|
|||||||
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
|
"""
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
msg(a.g("this is a", "this is b", 42))
|
msg(a.g("this is a", "this is b", 42))
|
||||||
@ -28,7 +27,7 @@ def test_noconvert_args(msg):
|
|||||||
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
|
"""
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
msg(a.g("this is a", "this is b", 42, "this is d"))
|
msg(a.g("this is a", "this is b", 42, "this is d"))
|
||||||
@ -76,7 +75,7 @@ def test_noconvert_args(msg):
|
|||||||
1. (i: int) -> int
|
1. (i: int) -> int
|
||||||
|
|
||||||
Invoked with: 4.0
|
Invoked with: 4.0
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
assert m.ints_only(4) == 2
|
assert m.ints_only(4) == 2
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import gc
|
import gc
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from pybind11_tests import docstring_options as m
|
from pybind11_tests import docstring_options as m
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import ConstructorStats
|
from pybind11_tests import ConstructorStats
|
||||||
@ -201,7 +200,7 @@ def test_negative_stride_from_python(msg):
|
|||||||
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: """ # noqa: E501 line too long
|
Invoked with: """
|
||||||
+ repr(np.array([5.0, 4.0, 3.0], dtype="float32"))
|
+ repr(np.array([5.0, 4.0, 3.0], dtype="float32"))
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -213,7 +212,7 @@ def test_negative_stride_from_python(msg):
|
|||||||
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: """ # noqa: E501 line too long
|
Invoked with: """
|
||||||
+ repr(np.array([7.0, 4.0, 1.0], dtype="float32"))
|
+ repr(np.array([7.0, 4.0, 1.0], dtype="float32"))
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -724,13 +723,13 @@ def test_sparse_signature(doc):
|
|||||||
doc(m.sparse_copy_r)
|
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
|
"""
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
doc(m.sparse_copy_c)
|
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
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,7 +126,6 @@ TEST_CASE("Override cache") {
|
|||||||
TEST_CASE("Import error handling") {
|
TEST_CASE("Import error handling") {
|
||||||
REQUIRE_NOTHROW(py::module_::import("widget_module"));
|
REQUIRE_NOTHROW(py::module_::import("widget_module"));
|
||||||
REQUIRE_THROWS_WITH(py::module_::import("throw_exception"), "ImportError: C++ Error");
|
REQUIRE_THROWS_WITH(py::module_::import("throw_exception"), "ImportError: C++ Error");
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
REQUIRE_THROWS_WITH(py::module_::import("throw_error_already_set"),
|
REQUIRE_THROWS_WITH(py::module_::import("throw_error_already_set"),
|
||||||
Catch::Contains("ImportError: initialization failed"));
|
Catch::Contains("ImportError: initialization failed"));
|
||||||
|
|
||||||
@ -142,10 +141,6 @@ TEST_CASE("Import error handling") {
|
|||||||
locals);
|
locals);
|
||||||
REQUIRE(locals["is_keyerror"].cast<bool>() == true);
|
REQUIRE(locals["is_keyerror"].cast<bool>() == true);
|
||||||
REQUIRE(locals["message"].cast<std::string>() == "'missing'");
|
REQUIRE(locals["message"].cast<std::string>() == "'missing'");
|
||||||
#else
|
|
||||||
REQUIRE_THROWS_WITH(py::module_::import("throw_error_already_set"),
|
|
||||||
Catch::Contains("ImportError: KeyError"));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("There can be only one interpreter") {
|
TEST_CASE("There can be only one interpreter") {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from widget_module import Widget
|
from widget_module import Widget
|
||||||
@ -6,7 +5,7 @@ from widget_module import Widget
|
|||||||
|
|
||||||
class DerivedWidget(Widget):
|
class DerivedWidget(Widget):
|
||||||
def __init__(self, message):
|
def __init__(self, message):
|
||||||
super(DerivedWidget, self).__init__(message)
|
super().__init__(message)
|
||||||
|
|
||||||
def the_answer(self):
|
def the_answer(self):
|
||||||
return 42
|
return 42
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import trampoline_module
|
import trampoline_module
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env
|
|
||||||
from pybind11_tests import enums as m
|
from pybind11_tests import enums as m
|
||||||
|
|
||||||
|
|
||||||
@ -241,10 +239,7 @@ def test_char_underlying_enum(): # Issue #1331/PR #1334:
|
|||||||
assert type(m.ScopedCharEnum.Positive.__int__()) is int
|
assert type(m.ScopedCharEnum.Positive.__int__()) is int
|
||||||
assert int(m.ScopedChar16Enum.Zero) == 0
|
assert int(m.ScopedChar16Enum.Zero) == 0
|
||||||
assert hash(m.ScopedChar32Enum.Positive) == 1
|
assert hash(m.ScopedChar32Enum.Positive) == 1
|
||||||
if env.PY2:
|
assert type(m.ScopedCharEnum.Positive.__getstate__()) is int
|
||||||
assert m.ScopedCharEnum.Positive.__getstate__() == 1 # long
|
|
||||||
else:
|
|
||||||
assert type(m.ScopedCharEnum.Positive.__getstate__()) is int
|
|
||||||
assert m.ScopedWCharEnum(1) == m.ScopedWCharEnum.Positive
|
assert m.ScopedWCharEnum(1) == m.ScopedWCharEnum.Positive
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
# Even if the underlying type is char, only an int can be used to construct the enum:
|
# Even if the underlying type is char, only an int can be used to construct the enum:
|
||||||
@ -255,10 +250,7 @@ def test_bool_underlying_enum():
|
|||||||
assert type(m.ScopedBoolEnum.TRUE.__int__()) is int
|
assert type(m.ScopedBoolEnum.TRUE.__int__()) is int
|
||||||
assert int(m.ScopedBoolEnum.FALSE) == 0
|
assert int(m.ScopedBoolEnum.FALSE) == 0
|
||||||
assert hash(m.ScopedBoolEnum.TRUE) == 1
|
assert hash(m.ScopedBoolEnum.TRUE) == 1
|
||||||
if env.PY2:
|
assert type(m.ScopedBoolEnum.TRUE.__getstate__()) is int
|
||||||
assert m.ScopedBoolEnum.TRUE.__getstate__() == 1 # long
|
|
||||||
else:
|
|
||||||
assert type(m.ScopedBoolEnum.TRUE.__getstate__()) is int
|
|
||||||
assert m.ScopedBoolEnum(1) == m.ScopedBoolEnum.TRUE
|
assert m.ScopedBoolEnum(1) == m.ScopedBoolEnum.TRUE
|
||||||
# Enum could construct with a bool
|
# Enum could construct with a bool
|
||||||
# (bool is a strict subclass of int, and False will be converted to 0)
|
# (bool is a strict subclass of int, and False will be converted to 0)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -18,7 +17,7 @@ def test_evals(capture):
|
|||||||
assert m.test_eval_failure()
|
assert m.test_eval_failure()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail("env.PYPY and not env.PY2", raises=RuntimeError)
|
@pytest.mark.xfail("env.PYPY", raises=RuntimeError)
|
||||||
def test_eval_file():
|
def test_eval_file():
|
||||||
filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
|
filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
|
||||||
assert m.test_eval_file(filename)
|
assert m.test_eval_file(filename)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- 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():
|
||||||
|
@ -276,8 +276,6 @@ TEST_SUBMODULE(exceptions, m) {
|
|||||||
|
|
||||||
m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); });
|
m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); });
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
|
|
||||||
m.def("raise_from", []() {
|
m.def("raise_from", []() {
|
||||||
PyErr_SetString(PyExc_ValueError, "inner");
|
PyErr_SetString(PyExc_ValueError, "inner");
|
||||||
py::raise_from(PyExc_ValueError, "outer");
|
py::raise_from(PyExc_ValueError, "outer");
|
||||||
@ -301,5 +299,4 @@ TEST_SUBMODULE(exceptions, m) {
|
|||||||
std::throw_with_nested(std::runtime_error("Outer Exception"));
|
std::throw_with_nested(std::runtime_error("Outer Exception"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -24,7 +23,6 @@ def test_error_already_set(msg):
|
|||||||
assert msg(excinfo.value) == "foo"
|
assert msg(excinfo.value) == "foo"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif("env.PY2")
|
|
||||||
def test_raise_from(msg):
|
def test_raise_from(msg):
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
m.raise_from()
|
m.raise_from()
|
||||||
@ -32,7 +30,6 @@ def test_raise_from(msg):
|
|||||||
assert msg(excinfo.value.__cause__) == "inner"
|
assert msg(excinfo.value.__cause__) == "inner"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif("env.PY2")
|
|
||||||
def test_raise_from_already_set(msg):
|
def test_raise_from_already_set(msg):
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
m.raise_from_already_set()
|
m.raise_from_already_set()
|
||||||
@ -102,7 +99,7 @@ def ignore_pytest_unraisable_warning(f):
|
|||||||
@ignore_pytest_unraisable_warning
|
@ignore_pytest_unraisable_warning
|
||||||
def test_python_alreadyset_in_destructor(monkeypatch, capsys):
|
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
|
||||||
|
|
||||||
if hasattr(sys, "unraisablehook"): # Python 3.8+
|
if hasattr(sys, "unraisablehook"): # Python 3.8+
|
||||||
hooked = True
|
hooked = True
|
||||||
@ -112,7 +109,8 @@ def test_python_alreadyset_in_destructor(monkeypatch, capsys):
|
|||||||
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
|
nonlocal triggered
|
||||||
|
triggered = True
|
||||||
default_hook(unraisable_hook_args)
|
default_hook(unraisable_hook_args)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -121,11 +119,11 @@ def test_python_alreadyset_in_destructor(monkeypatch, capsys):
|
|||||||
|
|
||||||
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 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
|
assert captured_stderr.startswith("Exception ignored in: 'already_set demo'")
|
||||||
assert "ignored" in captured_stderr and "already_set demo" in captured_stderr
|
assert captured_stderr.rstrip().endswith("KeyError: 'bar'")
|
||||||
|
|
||||||
|
|
||||||
def test_exception_matches():
|
def test_exception_matches():
|
||||||
@ -239,7 +237,6 @@ def test_nested_throws(capture):
|
|||||||
assert str(excinfo.value) == "this is a helper-defined translated exception"
|
assert str(excinfo.value) == "this is a helper-defined translated exception"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif("env.PY2")
|
|
||||||
def test_throw_nested_exception():
|
def test_throw_nested_exception():
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
m.throw_nested_exception()
|
m.throw_nested_exception()
|
||||||
@ -249,7 +246,7 @@ def test_throw_nested_exception():
|
|||||||
|
|
||||||
# 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:
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
raise AttributeError("Example error")
|
raise AttributeError("Example error")
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
|
||||||
from pybind11_tests import ConstructorStats
|
from pybind11_tests import ConstructorStats
|
||||||
from pybind11_tests import factory_constructors as m
|
from pybind11_tests import factory_constructors as m
|
||||||
from pybind11_tests.factory_constructors import tag
|
from pybind11_tests.factory_constructors import tag
|
||||||
@ -82,7 +80,7 @@ def test_init_factory_signature(msg):
|
|||||||
4. m.factory_constructors.TestFactory1(arg0: handle, arg1: int, arg2: handle)
|
4. m.factory_constructors.TestFactory1(arg0: handle, arg1: int, arg2: handle)
|
||||||
|
|
||||||
Invoked with: 'invalid', 'constructor', 'arguments'
|
Invoked with: 'invalid', 'constructor', 'arguments'
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
@ -465,12 +463,10 @@ def test_reallocation_g(capture, msg):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@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."""
|
||||||
can only actually do this on Python 3: Python 2 raises an exception itself if you try."""
|
|
||||||
|
|
||||||
class NotPybindDerived(object):
|
class NotPybindDerived:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Attempts to initialize with an invalid type passed as `self`:
|
# Attempts to initialize with an invalid type passed as `self`:
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
@ -1,44 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
from contextlib import redirect_stderr, redirect_stdout
|
||||||
import sys
|
from io import StringIO
|
||||||
from contextlib import contextmanager
|
|
||||||
|
|
||||||
from pybind11_tests import iostream as m
|
from pybind11_tests import iostream as m
|
||||||
|
|
||||||
try:
|
|
||||||
# Python 3
|
|
||||||
from io import StringIO
|
|
||||||
except ImportError:
|
|
||||||
# Python 2
|
|
||||||
try:
|
|
||||||
from cStringIO import StringIO
|
|
||||||
except ImportError:
|
|
||||||
from StringIO import StringIO
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Python 3.4
|
|
||||||
from contextlib import redirect_stdout
|
|
||||||
except ImportError:
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def redirect_stdout(target):
|
|
||||||
original = sys.stdout
|
|
||||||
sys.stdout = target
|
|
||||||
yield
|
|
||||||
sys.stdout = original
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Python 3.5
|
|
||||||
from contextlib import redirect_stderr
|
|
||||||
except ImportError:
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def redirect_stderr(target):
|
|
||||||
original = sys.stderr
|
|
||||||
sys.stderr = target
|
|
||||||
yield
|
|
||||||
sys.stderr = original
|
|
||||||
|
|
||||||
|
|
||||||
def test_captured(capsys):
|
def test_captured(capsys):
|
||||||
msg = "I've been redirected to Python, I hope!"
|
msg = "I've been redirected to Python, I hope!"
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
|
||||||
from pybind11_tests import kwargs_and_defaults as m
|
from pybind11_tests import kwargs_and_defaults as m
|
||||||
|
|
||||||
|
|
||||||
@ -82,7 +80,7 @@ def test_mixed_args_and_kwargs(msg):
|
|||||||
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
|
"""
|
||||||
)
|
)
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
assert mpa()
|
assert mpa()
|
||||||
@ -93,7 +91,7 @@ def test_mixed_args_and_kwargs(msg):
|
|||||||
1. (arg0: int, arg1: float, *args) -> tuple
|
1. (arg0: int, arg1: float, *args) -> tuple
|
||||||
|
|
||||||
Invoked with:
|
Invoked with:
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (
|
assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (
|
||||||
@ -127,7 +125,7 @@ def test_mixed_args_and_kwargs(msg):
|
|||||||
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
|
"""
|
||||||
)
|
)
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
assert mpakd(1, 2, j=1)
|
assert mpakd(1, 2, j=1)
|
||||||
@ -138,7 +136,7 @@ def test_mixed_args_and_kwargs(msg):
|
|||||||
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
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
# Arguments after a py::args are automatically keyword-only (pybind 2.9+)
|
# Arguments after a py::args are automatically keyword-only (pybind 2.9+)
|
||||||
@ -343,7 +341,6 @@ def test_signatures():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail("env.PYPY and env.PY2", reason="PyPy2 doesn't double count")
|
|
||||||
def test_args_refcount():
|
def test_args_refcount():
|
||||||
"""Issue/PR #1216 - py::args elements get double-inc_ref()ed when combined with regular
|
"""Issue/PR #1216 - py::args elements get double-inc_ref()ed when combined with regular
|
||||||
arguments"""
|
arguments"""
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
@ -200,7 +199,7 @@ def test_stl_caster_vs_stl_bind(msg):
|
|||||||
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
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
@ -494,26 +493,17 @@ def test_overload_ordering():
|
|||||||
assert m.overload_order("string") == 1
|
assert m.overload_order("string") == 1
|
||||||
assert m.overload_order(0) == 4
|
assert m.overload_order(0) == 4
|
||||||
|
|
||||||
# Different for Python 2 vs. 3
|
|
||||||
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 (
|
assert "2. overload_order(arg0: str) -> int" in m.overload_order.__doc__
|
||||||
"2. overload_order(arg0: {}) -> int".format(uni_name)
|
assert "3. overload_order(arg0: str) -> int" in m.overload_order.__doc__
|
||||||
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:
|
||||||
m.overload_order(1.1)
|
m.overload_order(1.1)
|
||||||
|
|
||||||
assert "1. (arg0: int) -> int" in str(err.value)
|
assert "1. (arg0: int) -> int" in str(err.value)
|
||||||
assert "2. (arg0: {}) -> int".format(uni_name) in str(err.value)
|
assert "2. (arg0: str) -> int" in str(err.value)
|
||||||
assert "3. (arg0: {}) -> int".format(uni_name) in str(err.value)
|
assert "3. (arg0: str) -> int" in str(err.value)
|
||||||
assert "4. (arg0: int) -> int" in str(err.value)
|
assert "4. (arg0: int) -> int" in str(err.value)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from pybind11_tests import ConstructorStats
|
from pybind11_tests import ConstructorStats
|
||||||
from pybind11_tests import modules as m
|
from pybind11_tests import modules as m
|
||||||
from pybind11_tests.modules import subsubmodule as ms
|
from pybind11_tests.modules import subsubmodule as ms
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
@ -13,8 +12,7 @@ def test_multiple_inheritance_cpp():
|
|||||||
assert mt.bar() == 4
|
assert mt.bar() == 4
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif("env.PYPY and env.PY2")
|
@pytest.mark.xfail("env.PYPY")
|
||||||
@pytest.mark.xfail("env.PYPY and not env.PY2")
|
|
||||||
def test_multiple_inheritance_mix1():
|
def test_multiple_inheritance_mix1():
|
||||||
class Base1:
|
class Base1:
|
||||||
def __init__(self, i):
|
def __init__(self, i):
|
||||||
@ -53,15 +51,14 @@ def test_multiple_inheritance_mix2():
|
|||||||
assert mt.bar() == 4
|
assert mt.bar() == 4
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif("env.PYPY and env.PY2")
|
@pytest.mark.xfail("env.PYPY")
|
||||||
@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)
|
||||||
m.Base2.__init__(self, j)
|
m.Base2.__init__(self, j)
|
||||||
|
|
||||||
class B1(object):
|
class B1:
|
||||||
def v(self):
|
def v(self):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@ -96,7 +93,7 @@ def test_multiple_inheritance_python():
|
|||||||
def v(self):
|
def v(self):
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
class B3(object):
|
class B3:
|
||||||
def v(self):
|
def v(self):
|
||||||
return 3
|
return 3
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import numpy_vectorize as m
|
from pybind11_tests import numpy_vectorize as m
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import ConstructorStats, UserType
|
from pybind11_tests import ConstructorStats, UserType
|
||||||
@ -40,7 +39,7 @@ def test_pointers(msg):
|
|||||||
1. (arg0: capsule) -> int
|
1. (arg0: capsule) -> int
|
||||||
|
|
||||||
Invoked with: [1, 2, 3]
|
Invoked with: [1, 2, 3]
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
assert m.return_null_str() is None
|
assert m.return_null_str() is None
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env
|
|
||||||
from pybind11_tests import ConstructorStats
|
from pybind11_tests import ConstructorStats
|
||||||
from pybind11_tests import operators as m
|
from pybind11_tests import operators as m
|
||||||
|
|
||||||
@ -151,5 +149,4 @@ def test_overriding_eq_reset_hash():
|
|||||||
def test_return_set_of_unhashable():
|
def test_return_set_of_unhashable():
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
m.get_unhashable_HashMe_set()
|
m.get_unhashable_HashMe_set()
|
||||||
if not env.PY2:
|
assert str(excinfo.value.__cause__).startswith("unhashable type:")
|
||||||
assert str(excinfo.value.__cause__).startswith("unhashable type:")
|
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
import pickle
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env
|
import env
|
||||||
from pybind11_tests import pickling as m
|
from pybind11_tests import pickling as m
|
||||||
|
|
||||||
try:
|
|
||||||
import cPickle as pickle # Use cPickle on Python 2.7
|
|
||||||
except ImportError:
|
|
||||||
import pickle
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("cls_name", ["Pickleable", "PickleableNew"])
|
@pytest.mark.parametrize("cls_name", ["Pickleable", "PickleableNew"])
|
||||||
def test_roundtrip(cls_name):
|
def test_roundtrip(cls_name):
|
||||||
|
@ -87,7 +87,6 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
m.def("tuple_size_t", []() { return py::tuple{(py::size_t) 0}; });
|
m.def("tuple_size_t", []() { return py::tuple{(py::size_t) 0}; });
|
||||||
m.def("get_tuple", []() { return py::make_tuple(42, py::none(), "spam"); });
|
m.def("get_tuple", []() { return py::make_tuple(42, py::none(), "spam"); });
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
// test_simple_namespace
|
// test_simple_namespace
|
||||||
m.def("get_simple_namespace", []() {
|
m.def("get_simple_namespace", []() {
|
||||||
auto ns = py::module_::import("types").attr("SimpleNamespace")(
|
auto ns = py::module_::import("types").attr("SimpleNamespace")(
|
||||||
@ -96,7 +95,6 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
py::setattr(ns, "right", py::int_(2));
|
py::setattr(ns, "right", py::int_(2));
|
||||||
return ns;
|
return ns;
|
||||||
});
|
});
|
||||||
#endif
|
|
||||||
|
|
||||||
// test_str
|
// test_str
|
||||||
m.def("str_from_char_ssize_t", []() { return py::str{"red", (py::ssize_t) 3}; });
|
m.def("str_from_char_ssize_t", []() { return py::str{"red", (py::ssize_t) 3}; });
|
||||||
@ -423,12 +421,10 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
return py::memoryview::from_buffer(static_cast<void *>(nullptr), 1, "B", {}, {});
|
return py::memoryview::from_buffer(static_cast<void *>(nullptr), 1, "B", {}, {});
|
||||||
});
|
});
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
m.def("test_memoryview_from_memory", []() {
|
m.def("test_memoryview_from_memory", []() {
|
||||||
const char *buf = "\xff\xe1\xab\x37";
|
const char *buf = "\xff\xe1\xab\x37";
|
||||||
return py::memoryview::from_memory(buf, static_cast<py::ssize_t>(strlen(buf)));
|
return py::memoryview::from_memory(buf, static_cast<py::ssize_t>(strlen(buf)));
|
||||||
});
|
});
|
||||||
#endif
|
|
||||||
|
|
||||||
// test_builtin_functions
|
// test_builtin_functions
|
||||||
m.def("get_len", [](py::handle h) { return py::len(h); });
|
m.def("get_len", [](py::handle h) { return py::len(h); });
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import division
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env
|
import env # noqa: F401
|
||||||
from pybind11_tests import debug_enabled
|
from pybind11_tests import debug_enabled
|
||||||
from pybind11_tests import pytypes as m
|
from pybind11_tests import pytypes as m
|
||||||
|
|
||||||
@ -123,7 +120,6 @@ def test_tuple():
|
|||||||
assert m.get_tuple() == (42, None, "spam")
|
assert m.get_tuple() == (42, None, "spam")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif("env.PY2")
|
|
||||||
def test_simple_namespace():
|
def test_simple_namespace():
|
||||||
ns = m.get_simple_namespace()
|
ns = m.get_simple_namespace()
|
||||||
assert ns.attr == 42
|
assert ns.attr == 42
|
||||||
@ -140,7 +136,7 @@ def test_str(doc):
|
|||||||
|
|
||||||
assert doc(m.str_from_bytes) == "str_from_bytes() -> str"
|
assert doc(m.str_from_bytes) == "str_from_bytes() -> str"
|
||||||
|
|
||||||
class A(object):
|
class A:
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "this is a str"
|
return "this is a str"
|
||||||
|
|
||||||
@ -158,24 +154,14 @@ def test_str(doc):
|
|||||||
malformed_utf8 = b"\x80"
|
malformed_utf8 = b"\x80"
|
||||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||||
assert m.str_from_object(malformed_utf8) is malformed_utf8
|
assert m.str_from_object(malformed_utf8) is malformed_utf8
|
||||||
elif env.PY2:
|
|
||||||
with pytest.raises(UnicodeDecodeError):
|
|
||||||
m.str_from_object(malformed_utf8)
|
|
||||||
else:
|
else:
|
||||||
assert m.str_from_object(malformed_utf8) == "b'\\x80'"
|
assert m.str_from_object(malformed_utf8) == "b'\\x80'"
|
||||||
if env.PY2:
|
assert m.str_from_handle(malformed_utf8) == "b'\\x80'"
|
||||||
with pytest.raises(UnicodeDecodeError):
|
|
||||||
m.str_from_handle(malformed_utf8)
|
|
||||||
else:
|
|
||||||
assert m.str_from_handle(malformed_utf8) == "b'\\x80'"
|
|
||||||
|
|
||||||
assert m.str_from_string_from_str("this is a str") == "this is a str"
|
assert m.str_from_string_from_str("this is a str") == "this is a str"
|
||||||
ucs_surrogates_str = u"\udcc3"
|
ucs_surrogates_str = "\udcc3"
|
||||||
if env.PY2:
|
with pytest.raises(UnicodeEncodeError):
|
||||||
assert u"\udcc3" == m.str_from_string_from_str(ucs_surrogates_str)
|
m.str_from_string_from_str(ucs_surrogates_str)
|
||||||
else:
|
|
||||||
with pytest.raises(UnicodeEncodeError):
|
|
||||||
m.str_from_string_from_str(ucs_surrogates_str)
|
|
||||||
|
|
||||||
|
|
||||||
def test_bytes(doc):
|
def test_bytes(doc):
|
||||||
@ -184,9 +170,7 @@ def test_bytes(doc):
|
|||||||
assert m.bytes_from_string().decode() == "foo"
|
assert m.bytes_from_string().decode() == "foo"
|
||||||
assert m.bytes_from_str().decode() == "bar"
|
assert m.bytes_from_str().decode() == "bar"
|
||||||
|
|
||||||
assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format(
|
assert doc(m.bytes_from_str) == "bytes_from_str() -> bytes"
|
||||||
"str" if env.PY2 else "bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_bytearray(doc):
|
def test_bytearray(doc):
|
||||||
@ -278,11 +262,6 @@ def test_constructors():
|
|||||||
"""C++ default and converting constructors are equivalent to type calls in Python"""
|
"""C++ default and converting constructors are equivalent to type calls in Python"""
|
||||||
types = [bytes, bytearray, str, bool, int, float, tuple, list, dict, set]
|
types = [bytes, bytearray, str, bool, int, float, tuple, list, dict, set]
|
||||||
expected = {t.__name__: t() for t in types}
|
expected = {t.__name__: t() for t in types}
|
||||||
if env.PY2:
|
|
||||||
# Note that bytes.__name__ == 'str' in Python 2.
|
|
||||||
# pybind11::str is unicode even under Python 2.
|
|
||||||
expected["bytes"] = bytes()
|
|
||||||
expected["str"] = unicode() # noqa: F821
|
|
||||||
assert m.default_constructors() == expected
|
assert m.default_constructors() == expected
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
@ -300,11 +279,6 @@ def test_constructors():
|
|||||||
}
|
}
|
||||||
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.
|
|
||||||
inputs["bytes"] = b"41"
|
|
||||||
inputs["str"] = 42
|
|
||||||
expected["bytes"] = b"41"
|
|
||||||
expected["str"] = u"42"
|
|
||||||
|
|
||||||
assert m.converting_constructors(inputs) == expected
|
assert m.converting_constructors(inputs) == expected
|
||||||
assert m.cast_functions(inputs) == expected
|
assert m.cast_functions(inputs) == expected
|
||||||
@ -340,46 +314,39 @@ def test_non_converting_constructors():
|
|||||||
def test_pybind11_str_raw_str():
|
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("Str") == "Str"
|
||||||
assert cvt(b"Bytes") == u"Bytes" if env.PY2 else "b'Bytes'"
|
assert cvt(b"Bytes") == "b'Bytes'"
|
||||||
assert cvt(None) == u"None"
|
assert cvt(None) == "None"
|
||||||
assert cvt(False) == u"False"
|
assert cvt(False) == "False"
|
||||||
assert cvt(True) == u"True"
|
assert cvt(True) == "True"
|
||||||
assert cvt(42) == u"42"
|
assert cvt(42) == "42"
|
||||||
assert cvt(2 ** 65) == u"36893488147419103232"
|
assert cvt(2**65) == "36893488147419103232"
|
||||||
assert cvt(-1.50) == u"-1.5"
|
assert cvt(-1.50) == "-1.5"
|
||||||
assert cvt(()) == u"()"
|
assert cvt(()) == "()"
|
||||||
assert cvt((18,)) == u"(18,)"
|
assert cvt((18,)) == "(18,)"
|
||||||
assert cvt([]) == u"[]"
|
assert cvt([]) == "[]"
|
||||||
assert cvt([28]) == u"[28]"
|
assert cvt([28]) == "[28]"
|
||||||
assert cvt({}) == u"{}"
|
assert cvt({}) == "{}"
|
||||||
assert cvt({3: 4}) == u"{3: 4}"
|
assert cvt({3: 4}) == "{3: 4}"
|
||||||
assert cvt(set()) == u"set([])" if env.PY2 else "set()"
|
assert cvt(set()) == "set()"
|
||||||
assert cvt({3, 3}) == u"set([3])" if env.PY2 else "{3}"
|
assert cvt({3, 3}) == "{3}"
|
||||||
|
|
||||||
valid_orig = u"DZ"
|
valid_orig = "DZ"
|
||||||
valid_utf8 = valid_orig.encode("utf-8")
|
valid_utf8 = valid_orig.encode("utf-8")
|
||||||
valid_cvt = cvt(valid_utf8)
|
valid_cvt = cvt(valid_utf8)
|
||||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||||
assert valid_cvt is valid_utf8
|
assert valid_cvt is valid_utf8
|
||||||
else:
|
else:
|
||||||
assert type(valid_cvt) is unicode if env.PY2 else str # noqa: F821
|
assert type(valid_cvt) is str
|
||||||
if env.PY2:
|
assert valid_cvt == "b'\\xc7\\xb1'"
|
||||||
assert valid_cvt == valid_orig
|
|
||||||
else:
|
|
||||||
assert valid_cvt == "b'\\xc7\\xb1'"
|
|
||||||
|
|
||||||
malformed_utf8 = b"\x80"
|
malformed_utf8 = b"\x80"
|
||||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||||
assert cvt(malformed_utf8) is malformed_utf8
|
assert cvt(malformed_utf8) is malformed_utf8
|
||||||
else:
|
else:
|
||||||
if env.PY2:
|
malformed_cvt = cvt(malformed_utf8)
|
||||||
with pytest.raises(UnicodeDecodeError):
|
assert type(malformed_cvt) is str
|
||||||
cvt(malformed_utf8)
|
assert malformed_cvt == "b'\\x80'"
|
||||||
else:
|
|
||||||
malformed_cvt = cvt(malformed_utf8)
|
|
||||||
assert type(malformed_cvt) is str
|
|
||||||
assert malformed_cvt == "b'\\x80'"
|
|
||||||
|
|
||||||
|
|
||||||
def test_implicit_casting():
|
def test_implicit_casting():
|
||||||
@ -428,14 +395,14 @@ def test_print(capture):
|
|||||||
|
|
||||||
|
|
||||||
def test_hash():
|
def test_hash():
|
||||||
class Hashable(object):
|
class Hashable:
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
class Unhashable(object):
|
class Unhashable:
|
||||||
__hash__ = None
|
__hash__ = None
|
||||||
|
|
||||||
assert m.hash_function(Hashable(42)) == 42
|
assert m.hash_function(Hashable(42)) == 42
|
||||||
@ -493,12 +460,7 @@ def test_memoryview(method, args, fmt, expected_view):
|
|||||||
view = method(*args)
|
view = method(*args)
|
||||||
assert isinstance(view, memoryview)
|
assert isinstance(view, memoryview)
|
||||||
assert view.format == fmt
|
assert view.format == fmt
|
||||||
if isinstance(expected_view, bytes) or not env.PY2:
|
assert list(view) == list(expected_view)
|
||||||
view_as_list = list(view)
|
|
||||||
else:
|
|
||||||
# Using max to pick non-zero byte (big-endian vs little-endian).
|
|
||||||
view_as_list = [max(ord(c) for c in s) for s in view]
|
|
||||||
assert view_as_list == list(expected_view)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail("env.PYPY", reason="getrefcount is not available")
|
@pytest.mark.xfail("env.PYPY", reason="getrefcount is not available")
|
||||||
@ -522,12 +484,7 @@ 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:
|
assert bytes(view) == b""
|
||||||
# Python 2 behavior is weird, but Python 3 (the future) is fine.
|
|
||||||
# PyPy3 has <memoryview, while CPython 2 has <memory
|
|
||||||
assert bytes(view).startswith(b"<memory")
|
|
||||||
else:
|
|
||||||
assert bytes(view) == b""
|
|
||||||
|
|
||||||
|
|
||||||
def test_test_memoryview_from_buffer_invalid_strides():
|
def test_test_memoryview_from_buffer_invalid_strides():
|
||||||
@ -536,14 +493,10 @@ def test_test_memoryview_from_buffer_invalid_strides():
|
|||||||
|
|
||||||
|
|
||||||
def test_test_memoryview_from_buffer_nullptr():
|
def test_test_memoryview_from_buffer_nullptr():
|
||||||
if env.PY2:
|
with pytest.raises(ValueError):
|
||||||
m.test_memoryview_from_buffer_nullptr()
|
m.test_memoryview_from_buffer_nullptr()
|
||||||
else:
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
m.test_memoryview_from_buffer_nullptr()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif("env.PY2")
|
|
||||||
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)
|
||||||
@ -563,9 +516,9 @@ def test_builtin_functions():
|
|||||||
|
|
||||||
def test_isinstance_string_types():
|
def test_isinstance_string_types():
|
||||||
assert m.isinstance_pybind11_bytes(b"")
|
assert m.isinstance_pybind11_bytes(b"")
|
||||||
assert not m.isinstance_pybind11_bytes(u"")
|
assert not m.isinstance_pybind11_bytes("")
|
||||||
|
|
||||||
assert m.isinstance_pybind11_str(u"")
|
assert m.isinstance_pybind11_str("")
|
||||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||||
assert m.isinstance_pybind11_str(b"")
|
assert m.isinstance_pybind11_str(b"")
|
||||||
else:
|
else:
|
||||||
@ -575,24 +528,21 @@ def test_isinstance_string_types():
|
|||||||
def test_pass_bytes_or_unicode_to_string_types():
|
def test_pass_bytes_or_unicode_to_string_types():
|
||||||
assert m.pass_to_pybind11_bytes(b"Bytes") == 5
|
assert m.pass_to_pybind11_bytes(b"Bytes") == 5
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
m.pass_to_pybind11_bytes(u"Str")
|
m.pass_to_pybind11_bytes("Str")
|
||||||
|
|
||||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE") or env.PY2:
|
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||||
assert m.pass_to_pybind11_str(b"Bytes") == 5
|
assert m.pass_to_pybind11_str(b"Bytes") == 5
|
||||||
else:
|
else:
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
m.pass_to_pybind11_str(b"Bytes")
|
m.pass_to_pybind11_str(b"Bytes")
|
||||||
assert m.pass_to_pybind11_str(u"Str") == 3
|
assert m.pass_to_pybind11_str("Str") == 3
|
||||||
|
|
||||||
assert m.pass_to_std_string(b"Bytes") == 5
|
assert m.pass_to_std_string(b"Bytes") == 5
|
||||||
assert m.pass_to_std_string(u"Str") == 3
|
assert m.pass_to_std_string("Str") == 3
|
||||||
|
|
||||||
malformed_utf8 = b"\x80"
|
malformed_utf8 = b"\x80"
|
||||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||||
assert m.pass_to_pybind11_str(malformed_utf8) == 1
|
assert m.pass_to_pybind11_str(malformed_utf8) == 1
|
||||||
elif env.PY2:
|
|
||||||
with pytest.raises(UnicodeDecodeError):
|
|
||||||
m.pass_to_pybind11_str(malformed_utf8)
|
|
||||||
else:
|
else:
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
m.pass_to_pybind11_str(malformed_utf8)
|
m.pass_to_pybind11_str(malformed_utf8)
|
||||||
@ -609,12 +559,14 @@ def test_weakref(create_weakref, create_weakref_with_callback):
|
|||||||
from weakref import getweakrefcount
|
from weakref import getweakrefcount
|
||||||
|
|
||||||
# Apparently, you cannot weakly reference an object()
|
# Apparently, you cannot weakly reference an object()
|
||||||
class WeaklyReferenced(object):
|
class WeaklyReferenced:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
callback_called = False
|
||||||
|
|
||||||
def callback(wr):
|
def callback(wr):
|
||||||
# No `nonlocal` in Python 2
|
nonlocal callback_called
|
||||||
callback.called = True
|
callback_called = True
|
||||||
|
|
||||||
obj = WeaklyReferenced()
|
obj = WeaklyReferenced()
|
||||||
assert getweakrefcount(obj) == 0
|
assert getweakrefcount(obj) == 0
|
||||||
@ -623,13 +575,12 @@ def test_weakref(create_weakref, create_weakref_with_callback):
|
|||||||
|
|
||||||
obj = WeaklyReferenced()
|
obj = WeaklyReferenced()
|
||||||
assert getweakrefcount(obj) == 0
|
assert getweakrefcount(obj) == 0
|
||||||
callback.called = False
|
|
||||||
wr = create_weakref_with_callback(obj, callback) # noqa: F841
|
wr = create_weakref_with_callback(obj, callback) # noqa: F841
|
||||||
assert getweakrefcount(obj) == 1
|
assert getweakrefcount(obj) == 1
|
||||||
assert not callback.called
|
assert not callback_called
|
||||||
del obj
|
del obj
|
||||||
pytest.gc_collect()
|
pytest.gc_collect()
|
||||||
assert callback.called
|
assert callback_called
|
||||||
|
|
||||||
|
|
||||||
def test_cpp_iterators():
|
def test_cpp_iterators():
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import ConstructorStats
|
from pybind11_tests import ConstructorStats
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
m = pytest.importorskip("pybind11_tests.smart_ptr")
|
m = pytest.importorskip("pybind11_tests.smart_ptr")
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import ConstructorStats, UserType
|
from pybind11_tests import ConstructorStats, UserType
|
||||||
@ -283,7 +282,7 @@ def test_stl_pass_by_pointer(msg):
|
|||||||
1. (v: List[int] = None) -> List[int]
|
1. (v: List[int] = None) -> List[int]
|
||||||
|
|
||||||
Invoked with:
|
Invoked with:
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
@ -295,7 +294,7 @@ def test_stl_pass_by_pointer(msg):
|
|||||||
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
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3]
|
assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3]
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env
|
|
||||||
from pybind11_tests import stl_binders as m
|
from pybind11_tests import stl_binders as m
|
||||||
|
|
||||||
|
|
||||||
@ -74,18 +72,13 @@ def test_vector_buffer():
|
|||||||
assert v[1] == 2
|
assert v[1] == 2
|
||||||
v[2] = 5
|
v[2] = 5
|
||||||
mv = memoryview(v) # We expose the buffer interface
|
mv = memoryview(v) # We expose the buffer interface
|
||||||
if not env.PY2:
|
assert mv[2] == 5
|
||||||
assert mv[2] == 5
|
mv[2] = 6
|
||||||
mv[2] = 6
|
|
||||||
else:
|
|
||||||
assert mv[2] == "\x05"
|
|
||||||
mv[2] = "\x06"
|
|
||||||
assert v[2] == 6
|
assert v[2] == 6
|
||||||
|
|
||||||
if not env.PY2:
|
mv = memoryview(b)
|
||||||
mv = memoryview(b)
|
v = m.VectorUChar(mv[::2])
|
||||||
v = m.VectorUChar(mv[::2])
|
assert v[1] == 3
|
||||||
assert v[1] == 3
|
|
||||||
|
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
m.create_undeclstruct() # Undeclared struct contents, no buffer interface
|
m.create_undeclstruct() # Undeclared struct contents, no buffer interface
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from pybind11_tests import tagbased_polymorphic as m
|
from pybind11_tests import tagbased_polymorphic as m
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from pybind11_tests import thread as m
|
from pybind11_tests import thread as m
|
||||||
@ -7,7 +5,7 @@ from pybind11_tests import thread as m
|
|||||||
|
|
||||||
class Thread(threading.Thread):
|
class Thread(threading.Thread):
|
||||||
def __init__(self, fn):
|
def __init__(self, fn):
|
||||||
super(Thread, self).__init__()
|
super().__init__()
|
||||||
self.fn = fn
|
self.fn = fn
|
||||||
self.e = None
|
self.e = None
|
||||||
|
|
||||||
@ -19,7 +17,7 @@ class Thread(threading.Thread):
|
|||||||
self.e = e
|
self.e = e
|
||||||
|
|
||||||
def join(self):
|
def join(self):
|
||||||
super(Thread, self).join()
|
super().join()
|
||||||
if self.e:
|
if self.e:
|
||||||
raise self.e
|
raise self.e
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from pybind11_tests import union_ as m
|
from pybind11_tests import union_ as m
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
@ -10,12 +9,12 @@ from pybind11_tests import ConstructorStats # noqa: E402
|
|||||||
def test_override(capture, msg):
|
def test_override(capture, msg):
|
||||||
class ExtendedExampleVirt(m.ExampleVirt):
|
class ExtendedExampleVirt(m.ExampleVirt):
|
||||||
def __init__(self, state):
|
def __init__(self, state):
|
||||||
super(ExtendedExampleVirt, self).__init__(state + 1)
|
super().__init__(state + 1)
|
||||||
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().run(value + 1)
|
||||||
|
|
||||||
def run_bool(self):
|
def run_bool(self):
|
||||||
print("ExtendedExampleVirt::run_bool()")
|
print("ExtendedExampleVirt::run_bool()")
|
||||||
@ -29,7 +28,7 @@ def test_override(capture, msg):
|
|||||||
|
|
||||||
class ExtendedExampleVirt2(ExtendedExampleVirt):
|
class ExtendedExampleVirt2(ExtendedExampleVirt):
|
||||||
def __init__(self, state):
|
def __init__(self, state):
|
||||||
super(ExtendedExampleVirt2, self).__init__(state + 1)
|
super().__init__(state + 1)
|
||||||
|
|
||||||
def get_string2(self):
|
def get_string2(self):
|
||||||
return "override2"
|
return "override2"
|
||||||
@ -41,7 +40,7 @@ def test_override(capture, msg):
|
|||||||
capture
|
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
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
@ -59,7 +58,7 @@ def test_override(capture, msg):
|
|||||||
== """
|
== """
|
||||||
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
|
"""
|
||||||
)
|
)
|
||||||
with capture:
|
with capture:
|
||||||
assert m.runExampleVirtBool(ex12p) is False
|
assert m.runExampleVirtBool(ex12p) is False
|
||||||
@ -76,7 +75,7 @@ def test_override(capture, msg):
|
|||||||
== """
|
== """
|
||||||
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
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
cstats = ConstructorStats.get(m.ExampleVirt)
|
cstats = ConstructorStats.get(m.ExampleVirt)
|
||||||
@ -97,7 +96,7 @@ def test_alias_delay_initialization1(capture):
|
|||||||
|
|
||||||
class B(m.A):
|
class B(m.A):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(B, self).__init__()
|
super().__init__()
|
||||||
|
|
||||||
def f(self):
|
def f(self):
|
||||||
print("In python f()")
|
print("In python f()")
|
||||||
@ -137,7 +136,7 @@ def test_alias_delay_initialization2(capture):
|
|||||||
|
|
||||||
class B2(m.A2):
|
class B2(m.A2):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(B2, self).__init__()
|
super().__init__()
|
||||||
|
|
||||||
def f(self):
|
def f(self):
|
||||||
print("In python B2.f()")
|
print("In python B2.f()")
|
||||||
@ -245,7 +244,7 @@ def test_dispatch_issue(msg):
|
|||||||
class PyClass2(m.DispatchIssue):
|
class PyClass2(m.DispatchIssue):
|
||||||
def dispatch(self):
|
def dispatch(self):
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
super(PyClass2, self).dispatch()
|
super().dispatch()
|
||||||
assert (
|
assert (
|
||||||
msg(excinfo.value)
|
msg(excinfo.value)
|
||||||
== 'Tried to call pure virtual function "Base::dispatch"'
|
== 'Tried to call pure virtual function "Base::dispatch"'
|
||||||
@ -262,7 +261,7 @@ def test_recursive_dispatch_issue(msg):
|
|||||||
|
|
||||||
class Data(m.Data):
|
class Data(m.Data):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
super(Data, self).__init__()
|
super().__init__()
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
class Adder(m.Adder):
|
class Adder(m.Adder):
|
||||||
|
@ -92,7 +92,7 @@ endif()
|
|||||||
|
|
||||||
# Use the Python interpreter to find the libs.
|
# Use the Python interpreter to find the libs.
|
||||||
if(NOT PythonLibsNew_FIND_VERSION)
|
if(NOT PythonLibsNew_FIND_VERSION)
|
||||||
set(PythonLibsNew_FIND_VERSION "")
|
set(PythonLibsNew_FIND_VERSION "3.5")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} ${_pythonlibs_required}
|
find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} ${_pythonlibs_required}
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import division, print_function
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ Adds the following targets::
|
|||||||
pybind11::lto - Link time optimizations (manual selection)
|
pybind11::lto - Link time optimizations (manual selection)
|
||||||
pybind11::thin_lto - Link time optimizations (manual selection)
|
pybind11::thin_lto - Link time optimizations (manual selection)
|
||||||
pybind11::python_link_helper - Adds link to Python libraries
|
pybind11::python_link_helper - Adds link to Python libraries
|
||||||
pybind11::python2_no_register - Avoid warning/error with Python 2 + C++14/7
|
|
||||||
pybind11::windows_extras - MSVC bigobj and mp for building multithreaded
|
pybind11::windows_extras - MSVC bigobj and mp for building multithreaded
|
||||||
pybind11::opt_size - avoid optimizations that increase code size
|
pybind11::opt_size - avoid optimizations that increase code size
|
||||||
|
|
||||||
@ -66,31 +65,6 @@ set_property(
|
|||||||
APPEND
|
APPEND
|
||||||
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11)
|
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11)
|
||||||
|
|
||||||
# ----------------------- no register ----------------------
|
|
||||||
|
|
||||||
# Workaround for Python 2.7 and C++17 (C++14 as a warning) incompatibility
|
|
||||||
# This adds the flags -Wno-register and -Wno-deprecated-register if the compiler
|
|
||||||
# is Clang 3.9+ or AppleClang and the compile language is CXX, or /wd5033 for MSVC (all languages,
|
|
||||||
# since MSVC didn't recognize COMPILE_LANGUAGE until CMake 3.11+).
|
|
||||||
|
|
||||||
add_library(pybind11::python2_no_register INTERFACE IMPORTED ${optional_global})
|
|
||||||
set(clang_4plus
|
|
||||||
"$<AND:$<CXX_COMPILER_ID:Clang>,$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,3.9>>>")
|
|
||||||
set(no_register "$<OR:${clang_4plus},$<CXX_COMPILER_ID:AppleClang>>")
|
|
||||||
|
|
||||||
if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11)
|
|
||||||
set(cxx_no_register "${no_register}")
|
|
||||||
else()
|
|
||||||
set(cxx_no_register "$<AND:$<COMPILE_LANGUAGE:CXX>,${no_register}>")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(msvc "$<CXX_COMPILER_ID:MSVC>")
|
|
||||||
|
|
||||||
set_property(
|
|
||||||
TARGET pybind11::python2_no_register
|
|
||||||
PROPERTY INTERFACE_COMPILE_OPTIONS
|
|
||||||
"$<${cxx_no_register}:-Wno-register;-Wno-deprecated-register>" "$<${msvc}:/wd5033>")
|
|
||||||
|
|
||||||
# --------------------------- link helper ---------------------------
|
# --------------------------- link helper ---------------------------
|
||||||
|
|
||||||
add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global})
|
add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global})
|
||||||
|
@ -51,8 +51,6 @@ complex applications, and they are available in all modes:
|
|||||||
Python headers too.
|
Python headers too.
|
||||||
``pybind11::python_link_helper``
|
``pybind11::python_link_helper``
|
||||||
Just the "linking" part of ``pybind11:module``, for CMake < 3.15.
|
Just the "linking" part of ``pybind11:module``, for CMake < 3.15.
|
||||||
``pybind11::python2_no_register``
|
|
||||||
Quiets the warning/error when mixing C++14+ and Python 2, also included in ``pybind11::module``.
|
|
||||||
``pybind11::thin_lto``
|
``pybind11::thin_lto``
|
||||||
An alternative to ``INTERPROCEDURAL_OPTIMIZATION``.
|
An alternative to ``INTERPROCEDURAL_OPTIMIZATION``.
|
||||||
``pybind11::lto``
|
``pybind11::lto``
|
||||||
|
@ -22,9 +22,7 @@ else()
|
|||||||
set(_pybind11_quiet "")
|
set(_pybind11_quiet "")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT Python_FOUND
|
if(NOT Python_FOUND AND NOT Python3_FOUND)
|
||||||
AND NOT Python3_FOUND
|
|
||||||
AND NOT Python2_FOUND)
|
|
||||||
if(NOT DEFINED Python_FIND_IMPLEMENTATIONS)
|
if(NOT DEFINED Python_FIND_IMPLEMENTATIONS)
|
||||||
set(Python_FIND_IMPLEMENTATIONS CPython PyPy)
|
set(Python_FIND_IMPLEMENTATIONS CPython PyPy)
|
||||||
endif()
|
endif()
|
||||||
@ -34,7 +32,7 @@ if(NOT Python_FOUND
|
|||||||
set(Python_ROOT_DIR "$ENV{pythonLocation}")
|
set(Python_ROOT_DIR "$ENV{pythonLocation}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Python REQUIRED COMPONENTS Interpreter Development ${_pybind11_quiet})
|
find_package(Python 3.5 REQUIRED COMPONENTS Interpreter Development ${_pybind11_quiet})
|
||||||
|
|
||||||
# If we are in submodule mode, export the Python targets to global targets.
|
# If we are in submodule mode, export the Python targets to global targets.
|
||||||
# If this behavior is not desired, FindPython _before_ pybind11.
|
# If this behavior is not desired, FindPython _before_ pybind11.
|
||||||
@ -51,19 +49,10 @@ if(Python_FOUND)
|
|||||||
set(_Python
|
set(_Python
|
||||||
Python
|
Python
|
||||||
CACHE INTERNAL "" FORCE)
|
CACHE INTERNAL "" FORCE)
|
||||||
elseif(Python3_FOUND AND NOT Python2_FOUND)
|
elseif(Python3_FOUND)
|
||||||
set(_Python
|
set(_Python
|
||||||
Python3
|
Python3
|
||||||
CACHE INTERNAL "" FORCE)
|
CACHE INTERNAL "" FORCE)
|
||||||
elseif(Python2_FOUND AND NOT Python3_FOUND)
|
|
||||||
set(_Python
|
|
||||||
Python2
|
|
||||||
CACHE INTERNAL "" FORCE)
|
|
||||||
else()
|
|
||||||
message(AUTHOR_WARNING "Python2 and Python3 both present, pybind11 in "
|
|
||||||
"PYBIND11_NOPYTHON mode (manually activate to silence warning)")
|
|
||||||
set(_pybind11_nopython ON)
|
|
||||||
return()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(PYBIND11_MASTER_PROJECT)
|
if(PYBIND11_MASTER_PROJECT)
|
||||||
@ -137,7 +126,7 @@ if(PYTHON_IS_DEBUG)
|
|||||||
PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)
|
PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Check on every access - since Python2 and Python3 could have been used - do nothing in that case.
|
# Check on every access - since Python can change - do nothing in that case.
|
||||||
|
|
||||||
if(DEFINED ${_Python}_INCLUDE_DIRS)
|
if(DEFINED ${_Python}_INCLUDE_DIRS)
|
||||||
# Only add Python for build - must be added during the import for config
|
# Only add Python for build - must be added during the import for config
|
||||||
@ -159,13 +148,6 @@ if(DEFINED ${_Python}_INCLUDE_DIRS)
|
|||||||
CACHE INTERNAL "Directories where pybind11 and possibly Python headers are located")
|
CACHE INTERNAL "Directories where pybind11 and possibly Python headers are located")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(DEFINED ${_Python}_VERSION AND ${_Python}_VERSION VERSION_LESS 3)
|
|
||||||
set_property(
|
|
||||||
TARGET pybind11::pybind11
|
|
||||||
APPEND
|
|
||||||
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python2_no_register)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# In CMake 3.18+, you can find these separately, so include an if
|
# In CMake 3.18+, you can find these separately, so include an if
|
||||||
if(TARGET ${_Python}::Python)
|
if(TARGET ${_Python}::Python)
|
||||||
set_property(
|
set_property(
|
||||||
@ -205,8 +187,6 @@ function(pybind11_add_module target_name)
|
|||||||
python_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})
|
python_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})
|
||||||
elseif("${_Python}" STREQUAL "Python3")
|
elseif("${_Python}" STREQUAL "Python3")
|
||||||
python3_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})
|
python3_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})
|
||||||
elseif("${_Python}" STREQUAL "Python2")
|
|
||||||
python2_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})
|
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Cannot detect FindPython version: ${_Python}")
|
message(FATAL_ERROR "Cannot detect FindPython version: ${_Python}")
|
||||||
endif()
|
endif()
|
||||||
@ -223,10 +203,6 @@ function(pybind11_add_module target_name)
|
|||||||
target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
|
target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(DEFINED ${_Python}_VERSION AND ${_Python}_VERSION VERSION_LESS 3)
|
|
||||||
target_link_libraries(${target_name} PRIVATE pybind11::python2_no_register)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# -fvisibility=hidden is required to allow multiple modules compiled against
|
# -fvisibility=hidden is required to allow multiple modules compiled against
|
||||||
# different pybind versions to work properly, and for some features (e.g.
|
# different pybind versions to work properly, and for some features (e.g.
|
||||||
# py::module_local). We force it on everything inside the `pybind11`
|
# py::module_local). We force it on everything inside the `pybind11`
|
||||||
|
@ -43,7 +43,7 @@ endif()
|
|||||||
|
|
||||||
# A user can set versions manually too
|
# A user can set versions manually too
|
||||||
set(Python_ADDITIONAL_VERSIONS
|
set(Python_ADDITIONAL_VERSIONS
|
||||||
"3.11;3.10;3.9;3.8;3.7;3.6;3.5;3.4"
|
"3.11;3.10;3.9;3.8;3.7;3.6;3.5"
|
||||||
CACHE INTERNAL "")
|
CACHE INTERNAL "")
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
||||||
@ -122,13 +122,6 @@ set_property(
|
|||||||
INTERFACE_LINK_LIBRARIES pybind11::python_link_helper
|
INTERFACE_LINK_LIBRARIES pybind11::python_link_helper
|
||||||
"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>>")
|
"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>>")
|
||||||
|
|
||||||
if(PYTHON_VERSION VERSION_LESS 3)
|
|
||||||
set_property(
|
|
||||||
TARGET pybind11::pybind11
|
|
||||||
APPEND
|
|
||||||
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python2_no_register)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_property(
|
set_property(
|
||||||
TARGET pybind11::embed
|
TARGET pybind11::embed
|
||||||
APPEND
|
APPEND
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user