mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-21 20:55:11 +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:
|
||||
- PYTHON: 36
|
||||
CONFIG: Debug
|
||||
- PYTHON: 27
|
||||
CONFIG: Debug
|
||||
install:
|
||||
- ps: |
|
||||
$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:
|
||||
runs-on: [ubuntu-latest, windows-2022, macos-latest]
|
||||
python:
|
||||
- '2.7'
|
||||
- '3.5'
|
||||
- '3.6'
|
||||
- '3.9'
|
||||
@ -49,13 +48,9 @@ jobs:
|
||||
python: '3.6'
|
||||
args: >
|
||||
-DPYBIND11_FINDPYTHON=ON
|
||||
- runs-on: macos-latest
|
||||
python: 'pypy-2.7'
|
||||
# Inject a couple Windows 2019 runs
|
||||
- runs-on: windows-2019
|
||||
python: '3.9'
|
||||
- runs-on: windows-2019
|
||||
python: '2.7'
|
||||
|
||||
name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}"
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
@ -168,22 +163,6 @@ jobs:
|
||||
- name: Interface test
|
||||
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
|
||||
# setuptools
|
||||
- name: Setuptools helpers test
|
||||
@ -784,7 +763,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python:
|
||||
- 2.7
|
||||
- 3.6
|
||||
- 3.7
|
||||
# todo: check/cpptest does not support 3.8+ yet
|
||||
@ -832,17 +810,12 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python:
|
||||
- 2.7
|
||||
- 3.5
|
||||
- 3.7
|
||||
std:
|
||||
- 14
|
||||
|
||||
include:
|
||||
- python: 2.7
|
||||
std: 17
|
||||
args: >
|
||||
-DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR"
|
||||
- python: 3.7
|
||||
std: 17
|
||||
args: >
|
||||
|
8
.github/workflows/pip.yml
vendored
8
.github/workflows/pip.yml
vendored
@ -17,19 +17,19 @@ env:
|
||||
|
||||
jobs:
|
||||
# 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.
|
||||
test-packaging:
|
||||
name: 🐍 2.7 • 📦 tests • windows-latest
|
||||
name: 🐍 3.6 • 📦 tests • windows-latest
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup 🐍 2.7
|
||||
- name: Setup 🐍 3.6
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 2.7
|
||||
python-version: 3.6
|
||||
|
||||
- name: Prepare env
|
||||
run: |
|
||||
|
@ -29,14 +29,15 @@ repos:
|
||||
- id: mixed-line-ending
|
||||
- id: requirements-txt-fixer
|
||||
- id: trailing-whitespace
|
||||
- id: fix-encoding-pragma
|
||||
exclude: ^noxfile.py$
|
||||
|
||||
# Upgrade old Python syntax
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.31.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py3-plus]
|
||||
|
||||
# Nicely sort includes
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.10.1
|
||||
hooks:
|
||||
@ -44,20 +45,21 @@ repos:
|
||||
|
||||
# Black, the code formatter, natively supports pre-commit
|
||||
- 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:
|
||||
- id: black
|
||||
|
||||
# Also code format the docs
|
||||
- repo: https://github.com/asottile/blacken-docs
|
||||
rev: v1.12.0
|
||||
rev: v1.12.1
|
||||
hooks:
|
||||
- id: blacken-docs
|
||||
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
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||
rev: v1.1.10
|
||||
rev: v1.1.11
|
||||
hooks:
|
||||
- id: remove-tabs
|
||||
|
||||
@ -67,12 +69,15 @@ repos:
|
||||
hooks:
|
||||
- id: pycln
|
||||
|
||||
# Checking for common mistakes
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.9.0
|
||||
hooks:
|
||||
- id: python-check-blanket-noqa
|
||||
- id: python-check-blanket-type-ignore
|
||||
- id: python-no-log-warn
|
||||
# Python 3.6
|
||||
# - id: python-use-type-annotations
|
||||
- id: rst-backticks
|
||||
- id: rst-directive-colons
|
||||
- id: rst-inline-touching-normal
|
||||
@ -87,6 +92,7 @@ repos:
|
||||
- pep8-naming
|
||||
exclude: ^(docs/.*|tools/.*)$
|
||||
|
||||
# Automatically remove noqa that are not used
|
||||
- repo: https://github.com/asottile/yesqa
|
||||
rev: v1.3.0
|
||||
hooks:
|
||||
@ -107,9 +113,9 @@ repos:
|
||||
rev: v0.931
|
||||
hooks:
|
||||
- id: mypy
|
||||
# Running per-file misbehaves a bit, so just run on all files, it's fast
|
||||
pass_filenames: false
|
||||
additional_dependencies: [typed_ast]
|
||||
args: [--show-error-codes]
|
||||
exclude: ^(tests|docs)/
|
||||
additional_dependencies: [nox, rich]
|
||||
|
||||
# Checks the manifest for missing files (native support)
|
||||
- repo: https://github.com/mgedmin/check-manifest
|
||||
@ -120,6 +126,7 @@ repos:
|
||||
stages: [manual]
|
||||
additional_dependencies: [cmake, ninja]
|
||||
|
||||
# Check for spelling
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.1.0
|
||||
hooks:
|
||||
@ -127,20 +134,22 @@ repos:
|
||||
exclude: ".supp$"
|
||||
args: ["-L", "nd,ot,thist"]
|
||||
|
||||
# Check for common shell mistakes
|
||||
- repo: https://github.com/shellcheck-py/shellcheck-py
|
||||
rev: v0.8.0.3
|
||||
rev: v0.8.0.4
|
||||
hooks:
|
||||
- id: shellcheck
|
||||
|
||||
# The original pybind11 checks for a few C++ style items
|
||||
# Disallow some common capitalization mistakes
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: disallow-caps
|
||||
name: Disallow improper capitalization
|
||||
language: pygrep
|
||||
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
|
||||
rev: "v13.0.0"
|
||||
hooks:
|
||||
|
@ -1,6 +1,5 @@
|
||||
recursive-include pybind11/include/pybind11 *.h
|
||||
recursive-include pybind11 *.py
|
||||
recursive-include pybind11 py.typed
|
||||
recursive-include pybind11 *.pyi
|
||||
include pybind11/share/cmake/pybind11/*.cmake
|
||||
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
|
||||
with everything stripped away that isn’t relevant for binding
|
||||
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
|
||||
some of the new C++11 language features (specifically: tuples, lambda
|
||||
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
|
||||
goodies:
|
||||
|
||||
- Python 2.7, 3.5+, and PyPy/PyPy3 7.3 are supported with an
|
||||
implementation-agnostic interface.
|
||||
- Python 3.5+, and PyPy3 7.3 are supported with an implementation-agnostic
|
||||
interface (pybind11 2.9 was the last version to support Python 2).
|
||||
|
||||
- It is possible to bind C++11 lambda functions with captured
|
||||
variables. The lambda capture data is stored inside the resulting
|
||||
|
@ -18,5 +18,4 @@ ALIASES += "endrst=\endverbatim"
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
PREDEFINED = PY_MAJOR_VERSION=3 \
|
||||
PYBIND11_NOINLINE
|
||||
PREDEFINED = PYBIND11_NOINLINE
|
||||
|
@ -1,14 +1,6 @@
|
||||
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++
|
||||
=============================
|
||||
|
||||
@ -58,9 +50,9 @@ Passing bytes to C++
|
||||
--------------------
|
||||
|
||||
A Python ``bytes`` object will be passed to C++ functions that accept
|
||||
``std::string`` or ``char*`` *without* conversion. On Python 3, in order to
|
||||
make a function *only* accept ``bytes`` (and not ``str``), declare it as taking
|
||||
a ``py::bytes`` argument.
|
||||
``std::string`` or ``char*`` *without* conversion. In order to make a function
|
||||
*only* accept ``bytes`` (and not ``str``), declare it as taking a ``py::bytes``
|
||||
argument.
|
||||
|
||||
|
||||
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
|
||||
UTF-8/16/32 before being returned to Python.
|
||||
|
||||
|
@ -133,14 +133,14 @@ a virtual method call.
|
||||
>>> from example import *
|
||||
>>> d = Dog()
|
||||
>>> call_go(d)
|
||||
u'woof! woof! woof! '
|
||||
'woof! woof! woof! '
|
||||
>>> class Cat(Animal):
|
||||
... def go(self, n_times):
|
||||
... return "meow! " * n_times
|
||||
...
|
||||
>>> c = Cat()
|
||||
>>> call_go(c)
|
||||
u'meow! meow! meow! '
|
||||
'meow! meow! meow! '
|
||||
|
||||
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__``,
|
||||
@ -813,26 +813,21 @@ An instance can now be pickled as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
try:
|
||||
import cPickle as pickle # Use cPickle on Python 2.7
|
||||
except ImportError:
|
||||
import pickle
|
||||
|
||||
p = Pickleable("test_value")
|
||||
p.setExtra(15)
|
||||
data = pickle.dumps(p, 2)
|
||||
data = pickle.dumps(p)
|
||||
|
||||
|
||||
.. note::
|
||||
Note that only the cPickle module is supported on Python 2.7.
|
||||
|
||||
The second argument to ``dumps`` is also crucial: it selects the pickle
|
||||
protocol version 2, since the older version 1 is not supported. Newer
|
||||
versions are also fine—for instance, specify ``-1`` to always use the
|
||||
latest available version. Beware: failure to follow these instructions
|
||||
will cause important pybind11 memory allocation routines to be skipped
|
||||
during unpickling, which will likely lead to memory corruption and/or
|
||||
segmentation faults.
|
||||
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
|
||||
always use the latest available version. Beware: failure to follow these
|
||||
instructions will cause important pybind11 memory allocation routines to be
|
||||
skipped during unpickling, which will likely lead to memory corruption
|
||||
and/or segmentation faults. Python defaults to version 3 (Python 3-3.7) and
|
||||
version 4 for Python 3.8+.
|
||||
|
||||
.. 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
|
||||
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
|
||||
``__copy__`` and ``__deepcopy__`` methods. With Python 2.7, these custom methods
|
||||
are mandatory for (deep)copy compatibility, because pybind11 only supports
|
||||
cPickle.
|
||||
``__copy__`` and ``__deepcopy__`` methods.
|
||||
|
||||
For simple classes (deep)copy can be enabled by using the copy constructor,
|
||||
which should look as follows:
|
||||
|
@ -328,8 +328,8 @@ an invalid state.
|
||||
Chaining exceptions ('raise from')
|
||||
==================================
|
||||
|
||||
In Python 3.3 a mechanism for indicating that exceptions were caused by other
|
||||
exceptions was introduced:
|
||||
Python has a mechanism for indicating that exceptions were caused by other
|
||||
exceptions:
|
||||
|
||||
.. 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
|
||||
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
|
||||
|
||||
|
@ -398,8 +398,6 @@ Ellipsis
|
||||
Python 3 provides a convenient ``...`` ellipsis notation that is often used to
|
||||
slice multidimensional arrays. For instance, the following snippet extracts the
|
||||
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
|
||||
|
||||
@ -414,8 +412,6 @@ operation on the C++ side:
|
||||
py::array a = /* A NumPy array */;
|
||||
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
|
||||
===========
|
||||
@ -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
|
||||
``memoryview::from_memory`` added.
|
||||
|
@ -166,12 +166,12 @@ load and execute the example:
|
||||
.. code-block:: pycon
|
||||
|
||||
$ python
|
||||
Python 2.7.10 (default, Aug 22 2015, 20:33:39)
|
||||
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.1)] on darwin
|
||||
Python 3.9.10 (main, Jan 15 2022, 11:48:04)
|
||||
[Clang 13.0.0 (clang-1300.0.29.3)] on darwin
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> import example
|
||||
>>> example.add(1, 2)
|
||||
3L
|
||||
3
|
||||
>>>
|
||||
|
||||
.. _keyword_args:
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime as dt
|
||||
import os
|
||||
import random
|
||||
|
@ -48,10 +48,10 @@ interactive Python session demonstrating this example is shown below:
|
||||
>>> print(p)
|
||||
<example.Pet object at 0x10cd98060>
|
||||
>>> p.getName()
|
||||
u'Molly'
|
||||
'Molly'
|
||||
>>> p.setName("Charly")
|
||||
>>> p.getName()
|
||||
u'Charly'
|
||||
'Charly'
|
||||
|
||||
.. seealso::
|
||||
|
||||
@ -124,10 +124,10 @@ This makes it possible to write
|
||||
|
||||
>>> p = example.Pet("Molly")
|
||||
>>> p.name
|
||||
u'Molly'
|
||||
'Molly'
|
||||
>>> p.name = "Charly"
|
||||
>>> p.name
|
||||
u'Charly'
|
||||
'Charly'
|
||||
|
||||
Now suppose that ``Pet::name`` was a private internal variable
|
||||
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.name
|
||||
u'Molly'
|
||||
'Molly'
|
||||
>>> p.bark()
|
||||
u'woof!'
|
||||
'woof!'
|
||||
|
||||
The C++ classes defined above are regular non-polymorphic types with an
|
||||
inheritance relationship. This is reflected in Python:
|
||||
@ -332,7 +332,7 @@ will automatically recognize this:
|
||||
>>> type(p)
|
||||
PolymorphicDog # automatically downcast
|
||||
>>> p.bark()
|
||||
u'woof!'
|
||||
'woof!'
|
||||
|
||||
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
|
||||
|
@ -462,11 +462,8 @@ available in all modes. The targets provided are:
|
||||
``pybind11::headers``
|
||||
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``
|
||||
Python headers + ``pybind11::headers`` + ``pybind11::python2_no_register`` (Python 2 only)
|
||||
Python headers + ``pybind11::headers``
|
||||
|
||||
``pybind11::python_link_helper``
|
||||
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)
|
||||
|
||||
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
|
||||
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
|
||||
``-I <path-to-pybind11>/include`` together with the Python includes path
|
||||
``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
|
||||
the ``-undefined dynamic_lookup`` flag so as to ignore missing symbols when
|
||||
building the module:
|
||||
|
@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# pybind11 documentation build configuration file, created by
|
||||
# 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``).
|
||||
|
||||
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
|
||||
Python 2, while the interpreter is running on top of some version of Python
|
||||
3, or vice versa).
|
||||
version of Python that does not match what you compiled with.
|
||||
|
||||
"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.
|
||||
|
||||
This difference may cause inconsistencies and errors if *both* mechanisms are
|
||||
used in the same project. Consider the following CMake code executed in a
|
||||
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.
|
||||
used in the same project.
|
||||
|
||||
There are three possible solutions:
|
||||
|
||||
|
@ -325,7 +325,7 @@ public:
|
||||
res = 0; // None is implicitly converted to False
|
||||
}
|
||||
#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)) {
|
||||
res = PyObject_IsTrue(src.ptr());
|
||||
}
|
||||
@ -375,37 +375,16 @@ struct string_caster {
|
||||
static constexpr size_t UTF_N = 8 * sizeof(CharT);
|
||||
|
||||
bool load(handle src, bool) {
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
object temp;
|
||||
#endif
|
||||
handle load_src = src;
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
if (!PyUnicode_Check(load_src.ptr())) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
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
|
||||
// On Python >= 3.3, for UTF-8 we avoid the need for a temporary `bytes`
|
||||
// object by using `PyUnicode_AsUTF8AndSize`.
|
||||
// For UTF-8 we avoid the need for a temporary `bytes` object by using
|
||||
// `PyUnicode_AsUTF8AndSize`.
|
||||
if (PYBIND11_SILENCE_MSVC_C4127(UTF_N == 8)) {
|
||||
Py_ssize_t size = -1;
|
||||
const auto *buffer
|
||||
@ -417,7 +396,6 @@ struct string_caster {
|
||||
value = StringType(buffer, static_cast<size_t>(size));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto utfNbytes
|
||||
= reinterpret_steal<object>(PyUnicode_AsEncodedString(load_src.ptr(),
|
||||
@ -486,7 +464,7 @@ private:
|
||||
template <typename C = CharT>
|
||||
bool load_bytes(enable_if_t<std::is_same<C, char>::value, handle> src) {
|
||||
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.
|
||||
const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr());
|
||||
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>
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
@ -1313,7 +1279,7 @@ public:
|
||||
|
||||
/// \ingroup annotations
|
||||
/// 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 {};
|
||||
|
||||
/// \ingroup annotations
|
||||
|
@ -15,12 +15,12 @@
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03030000 && !defined(PYPY_VERSION)
|
||||
#if !defined(PYPY_VERSION)
|
||||
# define PYBIND11_BUILTIN_QUALNAME
|
||||
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
|
||||
#else
|
||||
// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type
|
||||
// signatures; in 3.3+ this macro expands to nothing:
|
||||
// In PyPy, we still set __qualname__ so that we can produce reliable function type
|
||||
// signatures; in CPython this macro expands to nothing:
|
||||
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \
|
||||
setattr((PyObject *) obj, "__qualname__", nameobj)
|
||||
#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
|
||||
* 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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// metaclass `__call__` function that is used to create all pybind11 objects.
|
||||
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_setattro = pybind11_meta_setattro;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
type->tp_getattro = pybind11_meta_getattro;
|
||||
#endif
|
||||
|
||||
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.
|
||||
inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
|
||||
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_releasebuffer = pybind11_releasebuffer;
|
||||
@ -628,12 +621,8 @@ inline PyObject *make_new_python_type(const type_record &rec) {
|
||||
|
||||
auto qualname = name;
|
||||
if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
qualname = reinterpret_steal<object>(
|
||||
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_;
|
||||
@ -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_sequence = &heap_type->as_sequence;
|
||||
type->tp_as_mapping = &heap_type->as_mapping;
|
||||
#if PY_VERSION_HEX >= 0x03050000
|
||||
type->tp_as_async = &heap_type->as_async;
|
||||
#endif
|
||||
|
||||
/* Flags */
|
||||
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) {
|
||||
type->tp_flags |= Py_TPFLAGS_BASETYPE;
|
||||
}
|
||||
|
@ -211,6 +211,9 @@
|
||||
#endif
|
||||
|
||||
#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 <pythread.h>
|
||||
|
||||
@ -266,11 +269,11 @@
|
||||
// If UNDEFINED, pybind11::str can only hold PyUnicodeObject, and
|
||||
// pybind11::isinstance<str>() is true only for pybind11::str.
|
||||
// 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
|
||||
// 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_CHECK PyInstanceMethod_Check
|
||||
#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION
|
||||
@ -298,38 +301,6 @@
|
||||
extern "C" PYBIND11_MAYBE_UNUSED 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
|
||||
extern "C" {
|
||||
struct _Py_atomic_address {
|
||||
@ -362,8 +333,6 @@ PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current;
|
||||
} \
|
||||
}
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03030000
|
||||
|
||||
#define PYBIND11_CATCH_INIT_EXCEPTIONS \
|
||||
catch (pybind11::error_already_set & e) { \
|
||||
pybind11::raise_from(e, PyExc_ImportError, "initialization failed"); \
|
||||
@ -374,20 +343,6 @@ PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current;
|
||||
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
|
||||
***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_CREATE(var) (((var) = PyThread_create_key()) != -1)
|
||||
# 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
|
||||
// the value if it has already been set. Instead, it must first be deleted and
|
||||
// then set again.
|
||||
@ -294,7 +294,6 @@ inline internals **&get_internals_pp() {
|
||||
return internals_pp;
|
||||
}
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03030000
|
||||
// forward decl
|
||||
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;
|
||||
}
|
||||
|
||||
#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) {
|
||||
#if PY_VERSION_HEX >= 0x03030000
|
||||
if (PyErr_Occurred()) {
|
||||
raise_from(exc_type, msg);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
PyErr_SetString(exc_type, msg);
|
||||
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
|
||||
// like the one we're doing here; in earlier versions (and for larger allocations) they are
|
||||
// just wrappers around malloc.
|
||||
#if PY_VERSION_HEX >= 0x03050000
|
||||
nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));
|
||||
if (!nonsimple.values_and_holders) {
|
||||
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
|
||||
= 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);
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
if (scope.trace != nullptr) {
|
||||
PyException_SetTraceback(scope.value, scope.trace);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(PYPY_VERSION)
|
||||
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() {
|
||||
#if defined(PYPY_VERSION)
|
||||
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
|
||||
return (PyThreadState *) _PyThreadState_Current.value;
|
||||
#else
|
||||
|
@ -19,15 +19,9 @@
|
||||
# error Embedding the interpreter is not supported with PyPy
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||
extern "C" PyObject *pybind11_init_impl_##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
|
||||
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.
|
||||
struct embedded_module {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
using init_t = PyObject *(*) ();
|
||||
#else
|
||||
using init_t = void (*)();
|
||||
#endif
|
||||
embedded_module(const char *name, init_t init) {
|
||||
if (Py_IsInitialized() != 0) {
|
||||
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 {
|
||||
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
|
||||
PyMem_RawFree(ptr);
|
||||
#else
|
||||
delete[] ptr;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
inline wchar_t *widen_chars(const char *safe_arg) {
|
||||
#if PY_VERSION_HEX >= 0x030500f0
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
// 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::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();
|
||||
#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));
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,10 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
|
||||
inline void ensure_builtins_in_globals(object &global) {
|
||||
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
|
||||
// Running exec and eval on Python 2 and 3 adds `builtins` module under
|
||||
// `__builtins__` key to globals if not yet present.
|
||||
// Python 3.8 made PyRun_String behave similarly. Let's also do that for
|
||||
// older versions, for consistency. This was missing from PyPy3.8 7.3.7.
|
||||
// Running exec and eval adds `builtins` module under `__builtins__` key to
|
||||
// globals if not yet present. Python 3.8 made PyRun_String behave
|
||||
// similarly. Let's also do that for older versions, for consistency. This
|
||||
// was missing from PyPy3.8 7.3.7.
|
||||
if (!global.contains("__builtins__"))
|
||||
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
|
||||
#else
|
||||
@ -94,7 +94,7 @@ void exec(const char (&s)[N], object global = globals(), object local = object()
|
||||
eval<eval_statements>(s, global, local);
|
||||
}
|
||||
|
||||
#if defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03000000
|
||||
#if defined(PYPY_VERSION)
|
||||
template <eval_mode mode = eval_statements>
|
||||
object eval_file(str, object, object) {
|
||||
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;
|
||||
std::string fname_str = (std::string) fname;
|
||||
# if PY_VERSION_HEX >= 0x03040000
|
||||
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) {
|
||||
PyErr_Clear();
|
||||
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__")) {
|
||||
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
|
||||
= PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
|
||||
# endif
|
||||
|
||||
if (!result) {
|
||||
throw error_already_set();
|
||||
|
@ -263,11 +263,7 @@ private:
|
||||
static npy_api lookup() {
|
||||
module_ m = module_::import("numpy.core.multiarray");
|
||||
auto c = m.attr("_ARRAY_API");
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL);
|
||||
#else
|
||||
void **api_ptr = (void **) PyCObject_AsVoidPtr(c.ptr());
|
||||
#endif
|
||||
npy_api api;
|
||||
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
|
||||
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 op = op_impl<id, ot, Base, L_type, R_type>;
|
||||
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>
|
||||
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 op = op_impl<id, ot, Base, L_type, R_type>;
|
||||
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)) {
|
||||
handle th((PyObject *) tinfo->type);
|
||||
signature += th.attr("__module__").cast<std::string>() + "." +
|
||||
// Python 3.3+, but we backport it to earlier versions
|
||||
th.attr("__qualname__").cast<std::string>();
|
||||
signature += th.attr("__module__").cast<std::string>() + "."
|
||||
+ th.attr("__qualname__").cast<std::string>();
|
||||
} else if (rec->is_new_style_constructor && arg_index == 0) {
|
||||
// A new-style `__init__` takes `self` as `value_and_holder`.
|
||||
// Rewrite it to the proper class type.
|
||||
@ -453,15 +452,6 @@ protected:
|
||||
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->args.shrink_to_fit();
|
||||
rec->nargs = (std::uint16_t) args;
|
||||
@ -1107,14 +1097,12 @@ protected:
|
||||
}
|
||||
|
||||
append_note_if_missing_header_is_suspected(msg);
|
||||
#if PY_VERSION_HEX >= 0x03030000
|
||||
// Attach additional error info to the exception if supported
|
||||
if (PyErr_Occurred()) {
|
||||
// #HelpAppreciated: unit test coverage for this branch.
|
||||
raise_from(PyExc_TypeError, msg.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
@ -1123,13 +1111,11 @@ protected:
|
||||
"Python type! The signature was\n\t";
|
||||
msg += it->signature;
|
||||
append_note_if_missing_header_is_suspected(msg);
|
||||
#if PY_VERSION_HEX >= 0x03030000
|
||||
// Attach additional error info to the exception if supported
|
||||
if (PyErr_Occurred()) {
|
||||
raise_from(PyExc_TypeError, msg.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
@ -1149,11 +1135,7 @@ public:
|
||||
/// Create a new top-level Python module with the given name and docstring
|
||||
PYBIND11_DEPRECATED("Use PYBIND11_MODULE or module_::create_extension_module instead")
|
||||
explicit module_(const char *name, const char *doc = nullptr) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
*this = create_extension_module(name, doc, new PyModuleDef());
|
||||
#else
|
||||
*this = create_extension_module(name, doc, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \rst
|
||||
@ -1231,20 +1213,14 @@ public:
|
||||
PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */);
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
using module_def = PyModuleDef;
|
||||
#else
|
||||
struct module_def {};
|
||||
#endif
|
||||
|
||||
/** \rst
|
||||
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.
|
||||
For Python 2, ``def`` can be a nullptr and is completely ignored.
|
||||
``def`` should point to a statically allocated module_def.
|
||||
\endrst */
|
||||
static module_ create_extension_module(const char *name, const char *doc, module_def *def) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
// module_def is PyModuleDef
|
||||
// Placement new (not an allocation).
|
||||
def = new (def)
|
||||
@ -1258,12 +1234,6 @@ public:
|
||||
/* m_clear */ nullptr,
|
||||
/* m_free */ nullptr};
|
||||
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 (PyErr_Occurred()) {
|
||||
throw error_already_set();
|
||||
@ -1290,14 +1260,12 @@ inline dict globals() {
|
||||
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...>()>>
|
||||
PYBIND11_DEPRECATED("make_simple_namespace should be replaced with "
|
||||
"py::module_::import(\"types\").attr(\"SimpleNamespace\") ")
|
||||
object make_simple_namespace(Args &&...args_) {
|
||||
return module_::import("types").attr("SimpleNamespace")(std::forward<Args>(args_)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
/// Generic support for creating new Python heap types
|
||||
@ -2173,9 +2141,6 @@ public:
|
||||
def_property_readonly("value", [](Type value) { return (Scalar) value; });
|
||||
def("__int__", [](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(
|
||||
[](detail::value_and_holder &v_h, Scalar arg) {
|
||||
detail::initimpl::setstate<Base>(
|
||||
|
@ -434,8 +434,6 @@ private:
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03030000
|
||||
|
||||
/// 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.
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/** \defgroup python_builtins const_name
|
||||
Unless stated otherwise, the following C++ functions behave the same
|
||||
as their Python counterparts.
|
||||
@ -591,12 +587,9 @@ inline ssize_t hash(handle obj) {
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
inline handle get_function(handle value) {
|
||||
if (value) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
if (PyInstanceMethod_Check(value.ptr())) {
|
||||
value = PyInstanceMethod_GET_FUNCTION(value.ptr());
|
||||
} else
|
||||
#endif
|
||||
if (PyMethod_Check(value.ptr())) {
|
||||
} else if (PyMethod_Check(value.ptr())) {
|
||||
value = PyMethod_GET_FUNCTION(value.ptr());
|
||||
}
|
||||
}
|
||||
@ -608,7 +601,6 @@ inline handle get_function(handle value) {
|
||||
|
||||
// copied from cpython _PyDict_GetItemStringWithError
|
||||
inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *kv = nullptr, *rv = nullptr;
|
||||
kv = PyUnicode_FromString(key);
|
||||
if (kv == NULL) {
|
||||
@ -621,21 +613,14 @@ inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
|
||||
throw error_already_set();
|
||||
}
|
||||
return rv;
|
||||
#else
|
||||
return PyDict_GetItemString(v, key);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline PyObject *dict_getitem(PyObject *v, PyObject *key) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *rv = PyDict_GetItemWithError(v, key);
|
||||
if (rv == NULL && PyErr_Occurred()) {
|
||||
throw error_already_set();
|
||||
}
|
||||
return rv;
|
||||
#else
|
||||
return PyDict_GetItem(v, key);
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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
|
||||
static PyObject *raw_str(PyObject *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;
|
||||
}
|
||||
};
|
||||
@ -1459,11 +1437,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
|
||||
template <typename Unsigned>
|
||||
Unsigned as_unsigned(PyObject *o) {
|
||||
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(Unsigned) <= sizeof(unsigned long))
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
|| PyInt_Check(o)
|
||||
#endif
|
||||
) {
|
||||
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(Unsigned) <= sizeof(unsigned long))) {
|
||||
unsigned long v = PyLong_AsUnsignedLong(o);
|
||||
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);
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
/** \rst
|
||||
Creates ``memoryview`` from static memory.
|
||||
|
||||
@ -1930,8 +1903,6 @@ public:
|
||||
managed by Python. The caller is responsible for managing the lifetime
|
||||
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`_.
|
||||
|
||||
.. _PyMemoryView_FromMemory:
|
||||
@ -1955,8 +1926,6 @@ public:
|
||||
return from_memory(const_cast<char *>(mem.data()), static_cast<ssize_t>(mem.size()), true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond DUPLICATE
|
||||
@ -2010,11 +1979,7 @@ inline size_t len(handle h) {
|
||||
/// Get the length hint of a Python object.
|
||||
/// Returns 0 when this cannot be determined.
|
||||
inline size_t len_hint(handle h) {
|
||||
#if PY_VERSION_HEX >= 0x03040000
|
||||
ssize_t result = PyObject_LengthHint(h.ptr(), 0);
|
||||
#else
|
||||
ssize_t result = PyObject_Length(h.ptr());
|
||||
#endif
|
||||
if (result < 0) {
|
||||
// Sometimes a length can't be determined at all (eg generators)
|
||||
// In which case simply return 0
|
||||
@ -2029,13 +1994,6 @@ inline str repr(handle h) {
|
||||
if (!str_value) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ import nox
|
||||
|
||||
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)
|
||||
|
@ -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 .commands import get_cmake_dir, get_include
|
||||
|
@ -1,6 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import sysconfig
|
||||
@ -8,8 +5,7 @@ import sysconfig
|
||||
from .commands import get_cmake_dir, get_include
|
||||
|
||||
|
||||
def print_includes():
|
||||
# type: () -> None
|
||||
def print_includes() -> None:
|
||||
dirs = [
|
||||
sysconfig.get_path("include"),
|
||||
sysconfig.get_path("platinclude"),
|
||||
@ -25,8 +21,7 @@ def print_includes():
|
||||
print(" ".join("-I" + d for d in unique_dirs))
|
||||
|
||||
|
||||
def main():
|
||||
# type: () -> None
|
||||
def main() -> None:
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
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:
|
||||
return int(s)
|
||||
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
|
||||
|
||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
def get_include(user=False):
|
||||
# type: (bool) -> str
|
||||
def get_include(user: bool = False) -> str:
|
||||
installed_path = os.path.join(DIR, "include")
|
||||
source_path = os.path.join(os.path.dirname(DIR), "include")
|
||||
return installed_path if os.path.exists(installed_path) else source_path
|
||||
|
||||
|
||||
def get_cmake_dir():
|
||||
# type: () -> str
|
||||
def get_cmake_dir() -> str:
|
||||
cmake_installed_path = os.path.join(DIR, "share", "cmake", "pybind11")
|
||||
if os.path.exists(cmake_installed_path):
|
||||
return cmake_installed_path
|
||||
|
@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This module provides helpers for C++11+ projects using pybind11.
|
||||
|
||||
@ -49,6 +47,20 @@ import sysconfig
|
||||
import tempfile
|
||||
import threading
|
||||
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:
|
||||
from setuptools import Extension as _Extension
|
||||
@ -61,7 +73,6 @@ import distutils.ccompiler
|
||||
import distutils.errors
|
||||
|
||||
WIN = sys.platform.startswith("win32") and "mingw" not in sysconfig.get_platform()
|
||||
PY2 = sys.version_info[0] < 3
|
||||
MACOS = sys.platform.startswith("darwin")
|
||||
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.
|
||||
|
||||
|
||||
class Pybind11Extension(_Extension):
|
||||
class Pybind11Extension(_Extension): # type: ignore[misc]
|
||||
"""
|
||||
Build a C++11+ Extension module with pybind11. This automatically adds the
|
||||
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
|
||||
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
|
||||
# ``extra_compile_args=["-g"]``.
|
||||
|
||||
def _add_cflags(self, flags):
|
||||
def _add_cflags(self, flags: List[str]) -> None:
|
||||
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
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
|
||||
self._cxx_level = 0
|
||||
cxx_std = kwargs.pop("cxx_std", 0)
|
||||
@ -119,9 +127,7 @@ class Pybind11Extension(_Extension):
|
||||
|
||||
include_pybind11 = kwargs.pop("include_pybind11", True)
|
||||
|
||||
# Can't use super here because distutils has old-style classes in
|
||||
# Python 2!
|
||||
_Extension.__init__(self, *args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Include the installed package pybind11 headers
|
||||
if include_pybind11:
|
||||
@ -133,11 +139,10 @@ class Pybind11Extension(_Extension):
|
||||
|
||||
if pyinc not in self.include_dirs:
|
||||
self.include_dirs.append(pyinc)
|
||||
except ImportError:
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
# Have to use the accessor manually to support Python 2 distutils
|
||||
Pybind11Extension.cxx_std.__set__(self, cxx_std)
|
||||
self.cxx_std = cxx_std
|
||||
|
||||
cflags = []
|
||||
ldflags = []
|
||||
@ -157,18 +162,18 @@ class Pybind11Extension(_Extension):
|
||||
self._add_ldflags(ldflags)
|
||||
|
||||
@property
|
||||
def cxx_std(self):
|
||||
def cxx_std(self) -> int:
|
||||
"""
|
||||
The CXX standard level. If set, will add the required flags. If left
|
||||
at 0, it will trigger an automatic search when pybind11's build_ext
|
||||
is used. If None, will have no effect. Besides just the flags, this
|
||||
may add a register warning/error fix for Python 2 or macos-min 10.9
|
||||
or 10.14.
|
||||
The CXX standard level. If set, will add the required flags. If left at
|
||||
0, it will trigger an automatic search when pybind11's build_ext is
|
||||
used. If None, will have no effect. Besides just the flags, this may
|
||||
add a macos-min 10.9 or 10.14 flag if MACOSX_DEPLOYMENT_TARGET is
|
||||
unset.
|
||||
"""
|
||||
return self._cxx_level
|
||||
|
||||
@cxx_std.setter
|
||||
def cxx_std(self, level):
|
||||
def cxx_std(self, level: int) -> None:
|
||||
|
||||
if self._cxx_level:
|
||||
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])
|
||||
desired_macos = (10, 9) if level < 17 else (10, 14)
|
||||
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]
|
||||
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_ldflags(ldflags)
|
||||
|
||||
|
||||
# Just in case someone clever tries to multithread
|
||||
tmp_chdir_lock = threading.Lock()
|
||||
cpp_cache_lock = threading.Lock()
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def tmp_chdir():
|
||||
def tmp_chdir() -> Iterator[str]:
|
||||
"Prepare and enter a temporary directory, cleanup when done"
|
||||
|
||||
# Threadsafe
|
||||
@ -235,7 +229,7 @@ def tmp_chdir():
|
||||
|
||||
|
||||
# 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
|
||||
specified compiler, otherwise None (can be used as a boolean).
|
||||
@ -243,13 +237,12 @@ def has_flag(compiler, flag):
|
||||
"""
|
||||
|
||||
with tmp_chdir():
|
||||
fname = "flagcheck.cpp"
|
||||
with open(fname, "w") as f:
|
||||
fname = Path("flagcheck.cpp")
|
||||
# Don't trigger -Wunused-parameter.
|
||||
f.write("int main (int, char **) { return 0; }")
|
||||
fname.write_text("int main (int, char **) { return 0; }")
|
||||
|
||||
try:
|
||||
compiler.compile([fname], extra_postargs=[flag])
|
||||
compiler.compile([str(fname)], extra_postargs=[flag])
|
||||
except distutils.errors.CompileError:
|
||||
return False
|
||||
return True
|
||||
@ -259,7 +252,8 @@ def has_flag(compiler, flag):
|
||||
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.
|
||||
"""
|
||||
@ -267,48 +261,38 @@ def auto_cpp_level(compiler):
|
||||
if WIN:
|
||||
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]
|
||||
|
||||
for level in levels:
|
||||
if has_flag(compiler, STD_TMPL.format(level)):
|
||||
with cpp_cache_lock:
|
||||
cpp_flag_cache = level
|
||||
return level
|
||||
|
||||
msg = "Unsupported compiler -- at least C++11 support is needed!"
|
||||
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
|
||||
C++ level for Pybind11Extension. This is only needed for the auto-search
|
||||
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.
|
||||
"""
|
||||
|
||||
for ext in self.extensions:
|
||||
if hasattr(ext, "_cxx_level") and ext._cxx_level == 0:
|
||||
# Python 2 syntax - old-style distutils class
|
||||
ext.__class__.cxx_std.__set__(ext, auto_cpp_level(self.compiler))
|
||||
ext.cxx_std = auto_cpp_level(self.compiler)
|
||||
|
||||
# Python 2 doesn't allow super here, since distutils uses old-style
|
||||
# classes!
|
||||
_build_ext.build_extensions(self)
|
||||
super().build_extensions()
|
||||
|
||||
|
||||
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
|
||||
source tree.
|
||||
@ -318,6 +302,7 @@ def intree_extensions(paths, package_dir=None):
|
||||
not contain an ``__init__.py`` file.
|
||||
"""
|
||||
exts = []
|
||||
|
||||
for path in paths:
|
||||
if package_dir is None:
|
||||
parent, _ = os.path.split(path)
|
||||
@ -327,24 +312,25 @@ def intree_extensions(paths, package_dir=None):
|
||||
qualified_name = relname.replace(os.path.sep, ".")
|
||||
exts.append(Pybind11Extension(qualified_name, [path]))
|
||||
else:
|
||||
found = False
|
||||
for prefix, parent in package_dir.items():
|
||||
if path.startswith(parent):
|
||||
found = True
|
||||
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
||||
qualified_name = relname.replace(os.path.sep, ".")
|
||||
if prefix:
|
||||
qualified_name = prefix + "." + qualified_name
|
||||
exts.append(Pybind11Extension(qualified_name, [path]))
|
||||
if not found:
|
||||
raise ValueError(
|
||||
"path {} is not a child of any of the directories listed "
|
||||
"in 'package_dir' ({})".format(path, package_dir)
|
||||
)
|
||||
|
||||
if not exts:
|
||||
msg = (
|
||||
"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
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
recompile sources.
|
||||
@ -361,15 +347,33 @@ def no_recompile(obg, src):
|
||||
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
|
||||
# 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 NumPy's parallel distutils module:
|
||||
# https://github.com/numpy/numpy/blob/master/numpy/distutils/ccompiler.py
|
||||
class ParallelCompile(object):
|
||||
class ParallelCompile:
|
||||
"""
|
||||
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
|
||||
function created:
|
||||
@ -404,35 +408,41 @@ class ParallelCompile(object):
|
||||
|
||||
__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.default = default
|
||||
self.max = max
|
||||
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.
|
||||
"""
|
||||
|
||||
def compile_function(
|
||||
compiler,
|
||||
sources,
|
||||
output_dir=None,
|
||||
macros=None,
|
||||
include_dirs=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
depends=None,
|
||||
):
|
||||
compiler: distutils.ccompiler.CCompiler,
|
||||
sources: List[str],
|
||||
output_dir: Optional[str] = None,
|
||||
macros: Optional[Union[Tuple[str], Tuple[str, Optional[str]]]] = None,
|
||||
include_dirs: Optional[List[str]] = None,
|
||||
debug: bool = False,
|
||||
extra_preargs: Optional[List[str]] = None,
|
||||
extra_postargs: Optional[List[str]] = None,
|
||||
depends: Optional[List[str]] = None,
|
||||
) -> Any:
|
||||
|
||||
# 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
|
||||
)
|
||||
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.
|
||||
threads = self.default
|
||||
@ -441,14 +451,14 @@ class ParallelCompile(object):
|
||||
if self.envvar is not None:
|
||||
threads = int(os.environ.get(self.envvar, self.default))
|
||||
|
||||
def _single_compile(obj):
|
||||
def _single_compile(obj: Any) -> None:
|
||||
try:
|
||||
src, ext = build[obj]
|
||||
except KeyError:
|
||||
return
|
||||
|
||||
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:
|
||||
# Importing .synchronize checks for platforms that have some multiprocessing
|
||||
@ -466,14 +476,9 @@ class ParallelCompile(object):
|
||||
threads = 1
|
||||
|
||||
if threads > 1:
|
||||
pool = ThreadPool(threads)
|
||||
# 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:
|
||||
with ThreadPool(threads) as pool:
|
||||
for _ in pool.imap_unordered(_single_compile, objects):
|
||||
pass
|
||||
finally:
|
||||
pool.terminate()
|
||||
else:
|
||||
for ob in objects:
|
||||
_single_compile(ob)
|
||||
@ -482,13 +487,13 @@ class ParallelCompile(object):
|
||||
|
||||
return compile_function
|
||||
|
||||
def install(self):
|
||||
distutils.ccompiler.CCompiler.compile = self.function()
|
||||
def install(self: S) -> S:
|
||||
distutils.ccompiler.CCompiler.compile = self.function() # type: ignore[assignment]
|
||||
return self
|
||||
|
||||
def __enter__(self):
|
||||
def __enter__(self: S) -> S:
|
||||
self._old.append(distutils.ccompiler.CCompiler.compile)
|
||||
return self.install()
|
||||
|
||||
def __exit__(self, *args):
|
||||
distutils.ccompiler.CCompiler.compile = self._old.pop()
|
||||
def __exit__(self, *args: Any) -> None:
|
||||
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"
|
||||
|
||||
[tool.mypy]
|
||||
files = "pybind11"
|
||||
python_version = "2.7"
|
||||
files = ["pybind11"]
|
||||
python_version = "3.6"
|
||||
warn_unused_configs = true
|
||||
strict = true
|
||||
|
||||
disallow_any_generics = true
|
||||
disallow_subclassing_any = true
|
||||
disallow_untyped_calls = 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
|
||||
[[tool.mypy.overrides]]
|
||||
module = ["ghapi.*", "setuptools.*"]
|
||||
ignore_missing_imports = true
|
||||
|
10
setup.cfg
10
setup.cfg
@ -13,8 +13,7 @@ classifiers =
|
||||
Topic :: Software Development :: Libraries :: Python Modules
|
||||
Topic :: Utilities
|
||||
Programming Language :: C++
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3 :: Only
|
||||
Programming Language :: Python :: 3.5
|
||||
Programming Language :: Python :: 3.6
|
||||
Programming Language :: Python :: 3.7
|
||||
@ -39,15 +38,12 @@ project_urls =
|
||||
Chat = https://gitter.im/pybind/Lobby
|
||||
|
||||
[options]
|
||||
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
|
||||
python_requires = >=3.5
|
||||
zip_safe = False
|
||||
|
||||
[bdist_wheel]
|
||||
universal=1
|
||||
|
||||
|
||||
[flake8]
|
||||
max-line-length = 99
|
||||
max-line-length = 120
|
||||
show_source = True
|
||||
exclude = .git, __pycache__, build, dist, docs, tools, venv
|
||||
ignore =
|
||||
|
96
setup.py
96
setup.py
@ -1,36 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Setup script for PyPI; use CMakeFile.txt to build extension modules
|
||||
|
||||
import contextlib
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
from typing import Dict, Iterator, List, Union
|
||||
|
||||
import setuptools.command.sdist
|
||||
|
||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
DIR = Path(__file__).parent.absolute()
|
||||
VERSION_REGEX = re.compile(
|
||||
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"]
|
||||
serial = None
|
||||
try:
|
||||
major = int(matches["MAJOR"])
|
||||
minor = int(matches["MINOR"])
|
||||
flds = patch_level_serial.split(".")
|
||||
if flds:
|
||||
patch = int(flds[0])
|
||||
level = None
|
||||
if len(flds) == 1:
|
||||
level = "0"
|
||||
serial = 0
|
||||
@ -40,17 +40,13 @@ def build_expected_version_hex(matches):
|
||||
if level_serial.startswith(level):
|
||||
serial = int(level_serial[len(level) :])
|
||||
break
|
||||
except ValueError:
|
||||
pass
|
||||
if serial is None:
|
||||
msg = 'Invalid PYBIND11_VERSION_PATCH: "{}"'.format(patch_level_serial)
|
||||
raise RuntimeError(msg)
|
||||
return (
|
||||
"0x"
|
||||
+ "{:02x}{:02x}{:02x}{}{:x}".format(
|
||||
version_hex_str = "{: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
|
||||
@ -58,24 +54,25 @@ def build_expected_version_hex(matches):
|
||||
|
||||
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'
|
||||
|
||||
to_src = (
|
||||
("pyproject.toml", "tools/pyproject.toml"),
|
||||
("setup.py", setup_py),
|
||||
(Path("pyproject.toml"), Path("tools/pyproject.toml")),
|
||||
(Path("setup.py"), setup_py),
|
||||
)
|
||||
|
||||
|
||||
# Read the listed version
|
||||
with open("pybind11/_version.py") as f:
|
||||
code = compile(f.read(), "pybind11/_version.py", "exec")
|
||||
loc = {}
|
||||
loc = {} # type: Dict[str, str]
|
||||
code = compile(VERSION_FILE.read_text(encoding="utf-8"), "pybind11/_version.py", "exec")
|
||||
exec(code, loc)
|
||||
version = loc["__version__"]
|
||||
|
||||
# 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(f.read()))
|
||||
matches = dict(VERSION_REGEX.findall(COMMON_FILE.read_text(encoding="utf8")))
|
||||
cpp_version = "{MAJOR}.{MINOR}.{PATCH}".format(**matches)
|
||||
if version != cpp_version:
|
||||
msg = "Python version {} does not match C++ version {}!".format(
|
||||
@ -84,56 +81,44 @@ if version != cpp_version:
|
||||
raise RuntimeError(msg)
|
||||
|
||||
version_hex = matches.get("HEX", "MISSING")
|
||||
expected_version_hex = build_expected_version_hex(matches)
|
||||
if version_hex != expected_version_hex:
|
||||
exp_version_hex = build_expected_version_hex(matches)
|
||||
if version_hex != exp_version_hex:
|
||||
msg = "PYBIND11_VERSION_HEX {} does not match expected value {}!".format(
|
||||
version_hex,
|
||||
expected_version_hex,
|
||||
version_hex, exp_version_hex
|
||||
)
|
||||
raise RuntimeError(msg)
|
||||
|
||||
|
||||
def get_and_replace(filename, binary=False, **opts):
|
||||
with open(filename, "rb" if binary else "r") as f:
|
||||
contents = f.read()
|
||||
# Replacement has to be done on text in Python 3 (both work in Python 2)
|
||||
# TODO: use literals & overload (typing extensions or Python 3.8)
|
||||
def get_and_replace(
|
||||
filename: Path, binary: bool = False, **opts: str
|
||||
) -> Union[bytes, str]:
|
||||
if binary:
|
||||
contents = filename.read_bytes()
|
||||
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
|
||||
# on it, like a wheel)
|
||||
class SDist(setuptools.command.sdist.sdist):
|
||||
def make_release_tree(self, base_dir, files):
|
||||
setuptools.command.sdist.sdist.make_release_tree(self, base_dir, files)
|
||||
class SDist(setuptools.command.sdist.sdist): # type: ignore[misc]
|
||||
def make_release_tree(self, base_dir: str, files: List[str]) -> None:
|
||||
super().make_release_tree(base_dir, files)
|
||||
|
||||
for to, src in to_src:
|
||||
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!
|
||||
os.unlink(dest)
|
||||
with open(dest, "wb") as f:
|
||||
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)
|
||||
dest.unlink()
|
||||
dest.write_bytes(txt) # type: ignore[arg-type]
|
||||
|
||||
|
||||
# Remove the CMake install directory when done
|
||||
@contextlib.contextmanager
|
||||
def remove_output(*sources):
|
||||
def remove_output(*sources: str) -> Iterator[None]:
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
@ -156,9 +141,14 @@ with remove_output("pybind11/include", "pybind11/share"):
|
||||
if "DCMAKE_INSTALL_PREFIX" not in c
|
||||
]
|
||||
cmd += fcommand
|
||||
cmake_opts = dict(cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
||||
subprocess.check_call(cmd, **cmake_opts)
|
||||
subprocess.check_call(["cmake", "--install", tmpdir], **cmake_opts)
|
||||
subprocess.run(cmd, check=True, cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
||||
subprocess.run(
|
||||
["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)
|
||||
code = compile(txt, setup_py, "exec")
|
||||
|
@ -179,11 +179,6 @@ if(PYBIND11_TEST_FILTER)
|
||||
pybind11_filter_tests(PYBIND11_TEST_FILES ${PYBIND11_TEST_FILTER})
|
||||
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:
|
||||
# /pybind11/tests/test_constants_and_functions.cpp(125):
|
||||
# error: incompatible exception specifications
|
||||
@ -388,17 +383,6 @@ function(pybind11_enable_warnings target_name)
|
||||
-diag-disable 11074,11076)
|
||||
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()
|
||||
|
||||
set(test_targets pybind11_tests)
|
||||
|
@ -1,8 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""pytest configuration
|
||||
|
||||
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
|
||||
@ -13,19 +12,14 @@ import textwrap
|
||||
|
||||
import pytest
|
||||
|
||||
import env
|
||||
|
||||
# Early diagnostic for failed imports
|
||||
import pybind11_tests # noqa: F401
|
||||
|
||||
_unicode_marker = re.compile(r"u(\'[^\']*\')")
|
||||
_long_marker = re.compile(r"([0-9])L")
|
||||
_hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
|
||||
|
||||
# Avoid collecting Python3 only files
|
||||
collect_ignore = []
|
||||
if env.PY2:
|
||||
collect_ignore.append("test_async.py")
|
||||
|
||||
|
||||
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"""
|
||||
|
||||
def __init__(self, string):
|
||||
@ -83,7 +77,7 @@ class Unordered(Output):
|
||||
return False
|
||||
|
||||
|
||||
class Capture(object):
|
||||
class Capture:
|
||||
def __init__(self, capfd):
|
||||
self.capfd = capfd
|
||||
self.out = ""
|
||||
@ -126,7 +120,7 @@ def capture(capsys):
|
||||
return Capture(capsys)
|
||||
|
||||
|
||||
class SanitizedString(object):
|
||||
class SanitizedString:
|
||||
def __init__(self, sanitizer):
|
||||
self.sanitizer = sanitizer
|
||||
self.string = ""
|
||||
@ -149,9 +143,7 @@ class SanitizedString(object):
|
||||
def _sanitize_general(s):
|
||||
s = s.strip()
|
||||
s = s.replace("pybind11_tests.", "m.")
|
||||
s = s.replace("unicode", "str")
|
||||
s = _long_marker.sub(r"\1", s)
|
||||
s = _unicode_marker.sub(r"\1", s)
|
||||
return s
|
||||
|
||||
|
||||
|
@ -25,31 +25,14 @@ void gil_acquire() { py::gil_scoped_acquire gil; }
|
||||
|
||||
constexpr char kModuleName[] = "cross_module_gil_utils";
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
struct PyModuleDef moduledef
|
||||
= {PyModuleDef_HEAD_INIT, kModuleName, NULL, 0, NULL, NULL, NULL, NULL, NULL};
|
||||
#else
|
||||
PyMethodDef module_methods[] = {{NULL, NULL, 0, NULL}};
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" PYBIND11_EXPORT
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *
|
||||
PyInit_cross_module_gil_utils()
|
||||
#else
|
||||
void
|
||||
initcross_module_gil_utils()
|
||||
#endif
|
||||
{
|
||||
extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() {
|
||||
|
||||
PyObject *m =
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyModule_Create(&moduledef);
|
||||
#else
|
||||
Py_InitModule(kModuleName, module_methods);
|
||||
#endif
|
||||
PyObject *m = PyModule_Create(&moduledef);
|
||||
|
||||
if (m != NULL) {
|
||||
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)));
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return m;
|
||||
#endif
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import platform
|
||||
import sys
|
||||
|
||||
@ -11,10 +10,6 @@ WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
|
||||
CPYTHON = platform.python_implementation() == "CPython"
|
||||
PYPY = platform.python_implementation() == "PyPy"
|
||||
|
||||
PY2 = sys.version_info.major == 2
|
||||
|
||||
PY = sys.version_info
|
||||
|
||||
|
||||
def deprecated_call():
|
||||
"""
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import contextlib
|
||||
import os
|
||||
import string
|
||||
@ -64,11 +63,9 @@ py_files = {
|
||||
"__init__.py",
|
||||
"__main__.py",
|
||||
"_version.py",
|
||||
"_version.pyi",
|
||||
"commands.py",
|
||||
"py.typed",
|
||||
"setup_helpers.py",
|
||||
"setup_helpers.pyi",
|
||||
}
|
||||
|
||||
headers = main_headers | detail_headers | stl_headers
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
@ -19,7 +18,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
||||
|
||||
(tmpdir / "setup.py").write_text(
|
||||
dedent(
|
||||
u"""\
|
||||
"""\
|
||||
import sys
|
||||
sys.path.append({MAIN_DIR!r})
|
||||
|
||||
@ -58,7 +57,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
||||
|
||||
(tmpdir / "main.cpp").write_text(
|
||||
dedent(
|
||||
u"""\
|
||||
"""\
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
int f(int x) {
|
||||
@ -96,7 +95,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
||||
|
||||
(tmpdir / "test.py").write_text(
|
||||
dedent(
|
||||
u"""\
|
||||
"""\
|
||||
import simple_setup
|
||||
assert simple_setup.f(3) == 9
|
||||
"""
|
||||
@ -121,10 +120,11 @@ def test_intree_extensions(monkeypatch, tmpdir):
|
||||
subdir.ensure_dir()
|
||||
src = subdir / "ext.cpp"
|
||||
src.ensure()
|
||||
(ext,) = intree_extensions([src.relto(tmpdir)])
|
||||
relpath = src.relto(tmpdir)
|
||||
(ext,) = intree_extensions([relpath])
|
||||
assert ext.name == "ext"
|
||||
subdir.ensure("__init__.py")
|
||||
(ext,) = intree_extensions([src.relto(tmpdir)])
|
||||
(ext,) = intree_extensions([relpath])
|
||||
assert ext.name == "dir.ext"
|
||||
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
asyncio = pytest.importorskip("asyncio")
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import ctypes
|
||||
import io
|
||||
import struct
|
||||
@ -93,16 +92,16 @@ def test_pointer_to_member_fn():
|
||||
def test_readonly_buffer():
|
||||
buf = m.BufferReadOnly(0x64)
|
||||
view = memoryview(buf)
|
||||
assert view[0] == b"d" if env.PY2 else 0x64
|
||||
assert view[0] == 0x64
|
||||
assert view.readonly
|
||||
with pytest.raises(TypeError):
|
||||
view[0] = b"\0" if env.PY2 else 0
|
||||
view[0] = 0
|
||||
|
||||
|
||||
def test_selective_readonly_buffer():
|
||||
buf = m.BufferReadOnlySelect()
|
||||
|
||||
memoryview(buf)[0] = b"d" if env.PY2 else 0x64
|
||||
memoryview(buf)[0] = 0x64
|
||||
assert buf.value == 0x64
|
||||
|
||||
io.BytesIO(b"A").readinto(buf)
|
||||
@ -110,7 +109,7 @@ def test_selective_readonly_buffer():
|
||||
|
||||
buf.readonly = True
|
||||
with pytest.raises(TypeError):
|
||||
memoryview(buf)[0] = b"\0" if env.PY2 else 0
|
||||
memoryview(buf)[0] = 0
|
||||
with pytest.raises(TypeError):
|
||||
io.BytesIO(b"1").readinto(buf)
|
||||
|
||||
@ -145,9 +144,6 @@ def test_ctypes_array_2d():
|
||||
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():
|
||||
test_pystr = b"0123456789"
|
||||
for pyarray in (test_pystr, bytearray(test_pystr)):
|
||||
|
@ -110,8 +110,7 @@ TEST_SUBMODULE(builtin_casters, m) {
|
||||
"def");
|
||||
});
|
||||
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 don't appear to trigger
|
||||
// Under Python 2.7, invalid unicode UTF-32 characters didn't appear to trigger
|
||||
// UnicodeDecodeError
|
||||
m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
|
||||
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)});
|
||||
});
|
||||
}
|
||||
#endif
|
||||
m.def("u8_Z", []() -> char { return 'Z'; });
|
||||
m.def("u8_eacute", []() -> char { return '\xe9'; });
|
||||
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); });
|
||||
m.def("string_view_from_bytes",
|
||||
[](const py::bytes &b) { return [](std::string_view s) { return s; }(b); });
|
||||
# if PY_MAJOR_VERSION >= 3
|
||||
m.def("string_view_memoryview", []() {
|
||||
static constexpr auto val = "Have some \360\237\216\202"sv;
|
||||
return py::memoryview::from_memory(val);
|
||||
});
|
||||
# endif
|
||||
|
||||
# ifdef PYBIND11_HAS_U8STRING
|
||||
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 env
|
||||
@ -12,12 +13,12 @@ def test_simple_string():
|
||||
|
||||
def test_unicode_conversion():
|
||||
"""Tests unicode conversion and error reporting."""
|
||||
assert m.good_utf8_string() == u"Say utf8‽ 🎂 𝐀"
|
||||
assert m.good_utf16_string() == u"b‽🎂𝐀z"
|
||||
assert m.good_utf32_string() == u"a𝐀🎂‽z"
|
||||
assert m.good_wchar_string() == u"a⸘𝐀z"
|
||||
assert m.good_utf8_string() == "Say utf8‽ 🎂 𝐀"
|
||||
assert m.good_utf16_string() == "b‽🎂𝐀z"
|
||||
assert m.good_utf32_string() == "a𝐀🎂‽z"
|
||||
assert m.good_wchar_string() == "a⸘𝐀z"
|
||||
if hasattr(m, "has_u8string"):
|
||||
assert m.good_utf8_u8string() == u"Say utf8‽ 🎂 𝐀"
|
||||
assert m.good_utf8_u8string() == "Say utf8‽ 🎂 𝐀"
|
||||
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
m.bad_utf8_string()
|
||||
@ -25,7 +26,7 @@ def test_unicode_conversion():
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
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"):
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
m.bad_utf32_string()
|
||||
@ -37,10 +38,10 @@ def test_unicode_conversion():
|
||||
m.bad_utf8_u8string()
|
||||
|
||||
assert m.u8_Z() == "Z"
|
||||
assert m.u8_eacute() == u"é"
|
||||
assert m.u16_ibang() == u"‽"
|
||||
assert m.u32_mathbfA() == u"𝐀"
|
||||
assert m.wchar_heart() == u"♥"
|
||||
assert m.u8_eacute() == "é"
|
||||
assert m.u16_ibang() == "‽"
|
||||
assert m.u32_mathbfA() == "𝐀"
|
||||
assert m.wchar_heart() == "♥"
|
||||
if hasattr(m, "has_u8string"):
|
||||
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"
|
||||
|
||||
assert m.ord_char(u"a") == 0x61 # simple ASCII
|
||||
assert m.ord_char_lv(u"b") == 0x62
|
||||
assert m.ord_char("a") == 0x61 # simple ASCII
|
||||
assert m.ord_char_lv("b") == 0x62
|
||||
assert (
|
||||
m.ord_char(u"é") == 0xE9
|
||||
m.ord_char("é") == 0xE9
|
||||
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
assert m.ord_char(u"Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
||||
assert m.ord_char("Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
||||
assert str(excinfo.value) == toobig_message(0x100)
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
assert m.ord_char(u"ab")
|
||||
assert m.ord_char("ab")
|
||||
assert str(excinfo.value) == toolong_message
|
||||
|
||||
assert m.ord_char16(u"a") == 0x61
|
||||
assert m.ord_char16(u"é") == 0xE9
|
||||
assert m.ord_char16_lv(u"ê") == 0xEA
|
||||
assert m.ord_char16(u"Ā") == 0x100
|
||||
assert m.ord_char16(u"‽") == 0x203D
|
||||
assert m.ord_char16(u"♥") == 0x2665
|
||||
assert m.ord_char16_lv(u"♡") == 0x2661
|
||||
assert m.ord_char16("a") == 0x61
|
||||
assert m.ord_char16("é") == 0xE9
|
||||
assert m.ord_char16_lv("ê") == 0xEA
|
||||
assert m.ord_char16("Ā") == 0x100
|
||||
assert m.ord_char16("‽") == 0x203D
|
||||
assert m.ord_char16("♥") == 0x2665
|
||||
assert m.ord_char16_lv("♡") == 0x2661
|
||||
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)
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
assert m.ord_char16(u"aa")
|
||||
assert m.ord_char16("aa")
|
||||
assert str(excinfo.value) == toolong_message
|
||||
|
||||
assert m.ord_char32(u"a") == 0x61
|
||||
assert m.ord_char32(u"é") == 0xE9
|
||||
assert m.ord_char32(u"Ā") == 0x100
|
||||
assert m.ord_char32(u"‽") == 0x203D
|
||||
assert m.ord_char32(u"♥") == 0x2665
|
||||
assert m.ord_char32(u"🎂") == 0x1F382
|
||||
assert m.ord_char32("a") == 0x61
|
||||
assert m.ord_char32("é") == 0xE9
|
||||
assert m.ord_char32("Ā") == 0x100
|
||||
assert m.ord_char32("‽") == 0x203D
|
||||
assert m.ord_char32("♥") == 0x2665
|
||||
assert m.ord_char32("🎂") == 0x1F382
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
assert m.ord_char32(u"aa")
|
||||
assert m.ord_char32("aa")
|
||||
assert str(excinfo.value) == toolong_message
|
||||
|
||||
assert m.ord_wchar(u"a") == 0x61
|
||||
assert m.ord_wchar(u"é") == 0xE9
|
||||
assert m.ord_wchar(u"Ā") == 0x100
|
||||
assert m.ord_wchar(u"‽") == 0x203D
|
||||
assert m.ord_wchar(u"♥") == 0x2665
|
||||
assert m.ord_wchar("a") == 0x61
|
||||
assert m.ord_wchar("é") == 0xE9
|
||||
assert m.ord_wchar("Ā") == 0x100
|
||||
assert m.ord_wchar("‽") == 0x203D
|
||||
assert m.ord_wchar("♥") == 0x2665
|
||||
if m.wchar_size == 2:
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
assert m.ord_wchar(u"🎂") == 0x1F382 # requires surrogate pair
|
||||
assert m.ord_wchar("🎂") == 0x1F382 # requires surrogate pair
|
||||
assert str(excinfo.value) == toobig_message(0x10000)
|
||||
else:
|
||||
assert m.ord_wchar(u"🎂") == 0x1F382
|
||||
assert m.ord_wchar("🎂") == 0x1F382
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
assert m.ord_wchar(u"aa")
|
||||
assert m.ord_wchar("aa")
|
||||
assert str(excinfo.value) == toolong_message
|
||||
|
||||
if hasattr(m, "has_u8string"):
|
||||
assert m.ord_char8(u"a") == 0x61 # simple ASCII
|
||||
assert m.ord_char8_lv(u"b") == 0x62
|
||||
assert m.ord_char8("a") == 0x61 # simple ASCII
|
||||
assert m.ord_char8_lv("b") == 0x62
|
||||
assert (
|
||||
m.ord_char8(u"é") == 0xE9
|
||||
m.ord_char8("é") == 0xE9
|
||||
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
assert m.ord_char8(u"Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
||||
assert m.ord_char8("Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
||||
assert str(excinfo.value) == toobig_message(0x100)
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
assert m.ord_char8(u"ab")
|
||||
assert m.ord_char8("ab")
|
||||
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."""
|
||||
# Issue #816
|
||||
|
||||
def to_bytes(s):
|
||||
b = s if env.PY2 else s.encode("utf8")
|
||||
assert isinstance(b, bytes)
|
||||
return b
|
||||
|
||||
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
|
||||
assert m.strlen(b"hi") == 2
|
||||
assert m.string_length(b"world") == 5
|
||||
assert m.string_length("a\x00b".encode()) == 3
|
||||
assert m.strlen("a\x00b".encode()) == 1 # C-string limitation
|
||||
|
||||
# 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>")
|
||||
@ -142,26 +138,26 @@ def test_string_view(capture):
|
||||
"""Tests support for C++17 string_view arguments and return values"""
|
||||
assert m.string_view_chars("Hi") == [72, 105]
|
||||
assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
||||
assert m.string_view16_chars(u"Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
|
||||
assert m.string_view32_chars(u"Hi 🎂") == [72, 105, 32, 127874]
|
||||
assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
|
||||
assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874]
|
||||
if hasattr(m, "has_u8string"):
|
||||
assert m.string_view8_chars("Hi") == [72, 105]
|
||||
assert m.string_view8_chars(u"Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
||||
assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
||||
|
||||
assert m.string_view_return() == u"utf8 secret 🎂"
|
||||
assert m.string_view16_return() == u"utf16 secret 🎂"
|
||||
assert m.string_view32_return() == u"utf32 secret 🎂"
|
||||
assert m.string_view_return() == "utf8 secret 🎂"
|
||||
assert m.string_view16_return() == "utf16 secret 🎂"
|
||||
assert m.string_view32_return() == "utf32 secret 🎂"
|
||||
if hasattr(m, "has_u8string"):
|
||||
assert m.string_view8_return() == u"utf8 secret 🎂"
|
||||
assert m.string_view8_return() == "utf8 secret 🎂"
|
||||
|
||||
with capture:
|
||||
m.string_view_print("Hi")
|
||||
m.string_view_print("utf8 🎂")
|
||||
m.string_view16_print(u"utf16 🎂")
|
||||
m.string_view32_print(u"utf32 🎂")
|
||||
m.string_view16_print("utf16 🎂")
|
||||
m.string_view32_print("utf32 🎂")
|
||||
assert (
|
||||
capture
|
||||
== u"""
|
||||
== """
|
||||
Hi 2
|
||||
utf8 🎂 9
|
||||
utf16 🎂 8
|
||||
@ -171,10 +167,10 @@ def test_string_view(capture):
|
||||
if hasattr(m, "has_u8string"):
|
||||
with capture:
|
||||
m.string_view8_print("Hi")
|
||||
m.string_view8_print(u"utf8 🎂")
|
||||
m.string_view8_print("utf8 🎂")
|
||||
assert (
|
||||
capture
|
||||
== u"""
|
||||
== """
|
||||
Hi 2
|
||||
utf8 🎂 9
|
||||
"""
|
||||
@ -183,11 +179,11 @@ def test_string_view(capture):
|
||||
with capture:
|
||||
m.string_view_print("Hi, ascii")
|
||||
m.string_view_print("Hi, utf8 🎂")
|
||||
m.string_view16_print(u"Hi, utf16 🎂")
|
||||
m.string_view32_print(u"Hi, utf32 🎂")
|
||||
m.string_view16_print("Hi, utf16 🎂")
|
||||
m.string_view32_print("Hi, utf32 🎂")
|
||||
assert (
|
||||
capture
|
||||
== u"""
|
||||
== """
|
||||
Hi, ascii 9
|
||||
Hi, utf8 🎂 13
|
||||
Hi, utf16 🎂 12
|
||||
@ -197,21 +193,20 @@ def test_string_view(capture):
|
||||
if hasattr(m, "has_u8string"):
|
||||
with capture:
|
||||
m.string_view8_print("Hi, ascii")
|
||||
m.string_view8_print(u"Hi, utf8 🎂")
|
||||
m.string_view8_print("Hi, utf8 🎂")
|
||||
assert (
|
||||
capture
|
||||
== u"""
|
||||
== """
|
||||
Hi, ascii 9
|
||||
Hi, utf8 🎂 13
|
||||
"""
|
||||
)
|
||||
|
||||
assert m.string_view_bytes() == b"abc \x80\x80 def"
|
||||
assert m.string_view_str() == u"abc ‽ def"
|
||||
assert m.string_view_from_bytes(u"abc ‽ def".encode("utf-8")) == u"abc ‽ def"
|
||||
assert m.string_view_str() == "abc ‽ def"
|
||||
assert m.string_view_from_bytes("abc ‽ def".encode()) == "abc ‽ def"
|
||||
if hasattr(m, "has_u8string"):
|
||||
assert m.string_view8_str() == u"abc ‽ def"
|
||||
if not env.PY2:
|
||||
assert m.string_view8_str() == "abc ‽ def"
|
||||
assert m.string_view_memoryview() == "Have some 🎂".encode()
|
||||
|
||||
assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success"
|
||||
@ -224,18 +219,6 @@ def test_integer_casting():
|
||||
assert m.i64_str(-1) == "-1"
|
||||
assert m.i32_str(2000000000) == "2000000000"
|
||||
assert m.u32_str(2000000000) == "2000000000"
|
||||
if env.PY2:
|
||||
assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
||||
assert m.i64_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
||||
assert (
|
||||
m.i64_str(long(-999999999999)) # 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"
|
||||
|
||||
@ -252,46 +235,38 @@ def test_integer_casting():
|
||||
m.i32_str(3000000000)
|
||||
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():
|
||||
class Int(object):
|
||||
class Int:
|
||||
def __int__(self):
|
||||
return 42
|
||||
|
||||
class NotInt(object):
|
||||
class NotInt:
|
||||
pass
|
||||
|
||||
class Float(object):
|
||||
class Float:
|
||||
def __float__(self):
|
||||
return 41.99999
|
||||
|
||||
class Index(object):
|
||||
class Index:
|
||||
def __index__(self):
|
||||
return 42
|
||||
|
||||
class IntAndIndex(object):
|
||||
class IntAndIndex:
|
||||
def __int__(self):
|
||||
return 42
|
||||
|
||||
def __index__(self):
|
||||
return 0
|
||||
|
||||
class RaisingTypeErrorOnIndex(object):
|
||||
class RaisingTypeErrorOnIndex:
|
||||
def __index__(self):
|
||||
raise TypeError
|
||||
|
||||
def __int__(self):
|
||||
return 42
|
||||
|
||||
class RaisingValueErrorOnIndex(object):
|
||||
class RaisingValueErrorOnIndex:
|
||||
def __index__(self):
|
||||
raise ValueError
|
||||
|
||||
@ -311,7 +286,7 @@ def test_int_convert():
|
||||
cant_convert(3.14159)
|
||||
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
||||
# 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():
|
||||
assert convert(Int()) == 42
|
||||
else:
|
||||
@ -348,7 +323,7 @@ def test_numpy_int_convert():
|
||||
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
||||
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
||||
# 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():
|
||||
assert convert(np.float32(3.14159)) == 3
|
||||
else:
|
||||
@ -475,7 +450,7 @@ def test_bool_caster():
|
||||
require_implicit(None)
|
||||
assert convert(None) is False
|
||||
|
||||
class A(object):
|
||||
class A:
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
|
||||
@ -485,7 +460,7 @@ def test_bool_caster():
|
||||
def __bool__(self):
|
||||
return self.x
|
||||
|
||||
class B(object):
|
||||
class B:
|
||||
pass
|
||||
|
||||
# Arbitrary objects are not accepted
|
||||
@ -515,17 +490,9 @@ def test_numpy_bool():
|
||||
|
||||
|
||||
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.long_cast(), int)
|
||||
assert isinstance(m.longlong_cast(), must_be_long)
|
||||
assert isinstance(m.longlong_cast(), int)
|
||||
|
||||
|
||||
def test_void_caster_2():
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
from threading import Thread
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
@ -7,7 +6,6 @@ from pybind11_tests import class_ as m
|
||||
|
||||
|
||||
def test_repr():
|
||||
# In Python 3.3+, repr() accesses __qualname__
|
||||
assert "pybind11_type" in repr(type(UserType))
|
||||
assert "UserType" in repr(UserType)
|
||||
|
||||
@ -103,8 +101,8 @@ def test_docstrings(doc):
|
||||
|
||||
|
||||
def test_qualname(doc):
|
||||
"""Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we
|
||||
backport the attribute) and that generated docstrings properly use it and the module name"""
|
||||
"""Tests that a properly qualified name is set in __qualname__ and that
|
||||
generated docstrings properly use it and the module name"""
|
||||
assert m.NestBase.__qualname__ == "NestBase"
|
||||
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
|
||||
|
||||
@ -130,13 +128,13 @@ def test_qualname(doc):
|
||||
doc(m.NestBase.Nested.fn)
|
||||
== """
|
||||
fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
assert (
|
||||
doc(m.NestBase.Nested.fa)
|
||||
== """
|
||||
fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
assert m.NestBase.__module__ == "pybind11_tests.class_"
|
||||
assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
|
||||
|
@ -1,9 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
|
||||
import test_cmake_build
|
||||
|
||||
if str is not bytes: # If not Python2
|
||||
assert isinstance(__file__, str) # Test this is properly set
|
||||
|
||||
assert test_cmake_build.add(1, 2) == 3
|
||||
|
@ -1,7 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env
|
||||
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):
|
||||
if isinstance(func, type(u"") if env.PY2 else str):
|
||||
if isinstance(func, str):
|
||||
pytest.skip(func)
|
||||
text = func(selector)
|
||||
assert text == expected
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
from pybind11_tests import copy_move_policies as m
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
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
|
||||
13
|
||||
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
assert (
|
||||
msg(a.g("this is a", "this is b", 42))
|
||||
@ -28,7 +27,7 @@ def test_noconvert_args(msg):
|
||||
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
||||
42
|
||||
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
assert (
|
||||
msg(a.g("this is a", "this is b", 42, "this is d"))
|
||||
@ -76,7 +75,7 @@ def test_noconvert_args(msg):
|
||||
1. (i: int) -> int
|
||||
|
||||
Invoked with: 4.0
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
|
||||
assert m.ints_only(4) == 2
|
||||
|
@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import gc
|
||||
import weakref
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pybind11_tests import docstring_options as m
|
||||
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
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:
|
||||
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"))
|
||||
)
|
||||
|
||||
@ -213,7 +212,7 @@ def test_negative_stride_from_python(msg):
|
||||
double_threec(): incompatible function arguments. The following argument types are supported:
|
||||
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"))
|
||||
)
|
||||
|
||||
@ -724,13 +723,13 @@ def test_sparse_signature(doc):
|
||||
doc(m.sparse_copy_r)
|
||||
== """
|
||||
sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32]
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
assert (
|
||||
doc(m.sparse_copy_c)
|
||||
== """
|
||||
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") {
|
||||
REQUIRE_NOTHROW(py::module_::import("widget_module"));
|
||||
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"),
|
||||
Catch::Contains("ImportError: initialization failed"));
|
||||
|
||||
@ -142,10 +141,6 @@ TEST_CASE("Import error handling") {
|
||||
locals);
|
||||
REQUIRE(locals["is_keyerror"].cast<bool>() == true);
|
||||
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") {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
|
||||
from widget_module import Widget
|
||||
@ -6,7 +5,7 @@ from widget_module import Widget
|
||||
|
||||
class DerivedWidget(Widget):
|
||||
def __init__(self, message):
|
||||
super(DerivedWidget, self).__init__(message)
|
||||
super().__init__(message)
|
||||
|
||||
def the_answer(self):
|
||||
return 42
|
||||
|
@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import trampoline_module
|
||||
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env
|
||||
from pybind11_tests import enums as m
|
||||
|
||||
|
||||
@ -241,9 +239,6 @@ def test_char_underlying_enum(): # Issue #1331/PR #1334:
|
||||
assert type(m.ScopedCharEnum.Positive.__int__()) is int
|
||||
assert int(m.ScopedChar16Enum.Zero) == 0
|
||||
assert hash(m.ScopedChar32Enum.Positive) == 1
|
||||
if env.PY2:
|
||||
assert m.ScopedCharEnum.Positive.__getstate__() == 1 # long
|
||||
else:
|
||||
assert type(m.ScopedCharEnum.Positive.__getstate__()) is int
|
||||
assert m.ScopedWCharEnum(1) == m.ScopedWCharEnum.Positive
|
||||
with pytest.raises(TypeError):
|
||||
@ -255,9 +250,6 @@ def test_bool_underlying_enum():
|
||||
assert type(m.ScopedBoolEnum.TRUE.__int__()) is int
|
||||
assert int(m.ScopedBoolEnum.FALSE) == 0
|
||||
assert hash(m.ScopedBoolEnum.TRUE) == 1
|
||||
if env.PY2:
|
||||
assert m.ScopedBoolEnum.TRUE.__getstate__() == 1 # long
|
||||
else:
|
||||
assert type(m.ScopedBoolEnum.TRUE.__getstate__()) is int
|
||||
assert m.ScopedBoolEnum(1) == m.ScopedBoolEnum.TRUE
|
||||
# Enum could construct with a bool
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
|
||||
import pytest
|
||||
@ -18,7 +17,7 @@ def test_evals(capture):
|
||||
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():
|
||||
filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
|
||||
assert m.test_eval_file(filename)
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# This file is called from 'test_eval.py'
|
||||
|
||||
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(); });
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03030000
|
||||
|
||||
m.def("raise_from", []() {
|
||||
PyErr_SetString(PyExc_ValueError, "inner");
|
||||
py::raise_from(PyExc_ValueError, "outer");
|
||||
@ -301,5 +299,4 @@ TEST_SUBMODULE(exceptions, m) {
|
||||
std::throw_with_nested(std::runtime_error("Outer Exception"));
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
@ -24,7 +23,6 @@ def test_error_already_set(msg):
|
||||
assert msg(excinfo.value) == "foo"
|
||||
|
||||
|
||||
@pytest.mark.skipif("env.PY2")
|
||||
def test_raise_from(msg):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
m.raise_from()
|
||||
@ -32,7 +30,6 @@ def test_raise_from(msg):
|
||||
assert msg(excinfo.value.__cause__) == "inner"
|
||||
|
||||
|
||||
@pytest.mark.skipif("env.PY2")
|
||||
def test_raise_from_already_set(msg):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
m.raise_from_already_set()
|
||||
@ -102,7 +99,7 @@ def ignore_pytest_unraisable_warning(f):
|
||||
@ignore_pytest_unraisable_warning
|
||||
def test_python_alreadyset_in_destructor(monkeypatch, capsys):
|
||||
hooked = False
|
||||
triggered = [False] # mutable, so Python 2.7 closure can modify it
|
||||
triggered = False
|
||||
|
||||
if hasattr(sys, "unraisablehook"): # Python 3.8+
|
||||
hooked = True
|
||||
@ -112,7 +109,8 @@ def test_python_alreadyset_in_destructor(monkeypatch, capsys):
|
||||
def hook(unraisable_hook_args):
|
||||
exc_type, exc_value, exc_tb, err_msg, obj = unraisable_hook_args
|
||||
if obj == "already_set demo":
|
||||
triggered[0] = True
|
||||
nonlocal triggered
|
||||
triggered = True
|
||||
default_hook(unraisable_hook_args)
|
||||
return
|
||||
|
||||
@ -121,11 +119,11 @@ def test_python_alreadyset_in_destructor(monkeypatch, capsys):
|
||||
|
||||
assert m.python_alreadyset_in_destructor("already_set demo") is True
|
||||
if hooked:
|
||||
assert triggered[0] is True
|
||||
assert triggered is True
|
||||
|
||||
_, captured_stderr = capsys.readouterr()
|
||||
# Error message is different in Python 2 and 3, check for words that appear in both
|
||||
assert "ignored" in captured_stderr and "already_set demo" in captured_stderr
|
||||
assert captured_stderr.startswith("Exception ignored in: 'already_set demo'")
|
||||
assert captured_stderr.rstrip().endswith("KeyError: 'bar'")
|
||||
|
||||
|
||||
def test_exception_matches():
|
||||
@ -239,7 +237,6 @@ def test_nested_throws(capture):
|
||||
assert str(excinfo.value) == "this is a helper-defined translated exception"
|
||||
|
||||
|
||||
@pytest.mark.skipif("env.PY2")
|
||||
def test_throw_nested_exception():
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
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
|
||||
def test_invalid_repr():
|
||||
class MyRepr(object):
|
||||
class MyRepr:
|
||||
def __repr__(self):
|
||||
raise AttributeError("Example error")
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
from pybind11_tests import ConstructorStats
|
||||
from pybind11_tests import factory_constructors as m
|
||||
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)
|
||||
|
||||
Invoked with: 'invalid', 'constructor', 'arguments'
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
|
||||
assert (
|
||||
@ -465,12 +463,10 @@ def test_reallocation_g(capture, msg):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif("env.PY2")
|
||||
def test_invalid_self():
|
||||
"""Tests invocation of the pybind-registered base class with an invalid `self` argument. You
|
||||
can only actually do this on Python 3: Python 2 raises an exception itself if you try."""
|
||||
"""Tests invocation of the pybind-registered base class with an invalid `self` argument."""
|
||||
|
||||
class NotPybindDerived(object):
|
||||
class NotPybindDerived:
|
||||
pass
|
||||
|
||||
# Attempts to initialize with an invalid type passed as `self`:
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import multiprocessing
|
||||
import threading
|
||||
|
||||
|
@ -1,44 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from contextlib import redirect_stderr, redirect_stdout
|
||||
from io import StringIO
|
||||
|
||||
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):
|
||||
msg = "I've been redirected to Python, I hope!"
|
||||
|
@ -1,7 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
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
|
||||
|
||||
Invoked with: 1
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
assert mpa()
|
||||
@ -93,7 +91,7 @@ def test_mixed_args_and_kwargs(msg):
|
||||
1. (arg0: int, arg1: float, *args) -> tuple
|
||||
|
||||
Invoked with:
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
|
||||
assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (
|
||||
@ -127,7 +125,7 @@ def test_mixed_args_and_kwargs(msg):
|
||||
1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
|
||||
|
||||
Invoked with: 1; kwargs: i=1
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
assert mpakd(1, 2, j=1)
|
||||
@ -138,7 +136,7 @@ def test_mixed_args_and_kwargs(msg):
|
||||
1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
|
||||
|
||||
Invoked with: 1, 2; kwargs: j=1
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
|
||||
# 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():
|
||||
"""Issue/PR #1216 - py::args elements get double-inc_ref()ed when combined with regular
|
||||
arguments"""
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
@ -200,7 +199,7 @@ def test_stl_caster_vs_stl_bind(msg):
|
||||
1. (arg0: pybind11_cross_module_tests.VectorInt) -> int
|
||||
|
||||
Invoked with: [1, 2, 3]
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
@ -494,26 +493,17 @@ def test_overload_ordering():
|
||||
assert m.overload_order("string") == 1
|
||||
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 (
|
||||
"2. overload_order(arg0: {}) -> int".format(uni_name)
|
||||
in m.overload_order.__doc__
|
||||
)
|
||||
assert (
|
||||
"3. overload_order(arg0: {}) -> int".format(uni_name)
|
||||
in m.overload_order.__doc__
|
||||
)
|
||||
assert "2. overload_order(arg0: str) -> int" in m.overload_order.__doc__
|
||||
assert "3. overload_order(arg0: str) -> int" in m.overload_order.__doc__
|
||||
assert "4. overload_order(arg0: int) -> int" in m.overload_order.__doc__
|
||||
|
||||
with pytest.raises(TypeError) as err:
|
||||
m.overload_order(1.1)
|
||||
|
||||
assert "1. (arg0: int) -> int" in str(err.value)
|
||||
assert "2. (arg0: {}) -> int".format(uni_name) in str(err.value)
|
||||
assert "3. (arg0: {}) -> int".format(uni_name) in str(err.value)
|
||||
assert "2. (arg0: str) -> int" in str(err.value)
|
||||
assert "3. (arg0: str) -> 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 modules as m
|
||||
from pybind11_tests.modules import subsubmodule as ms
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
@ -13,8 +12,7 @@ def test_multiple_inheritance_cpp():
|
||||
assert mt.bar() == 4
|
||||
|
||||
|
||||
@pytest.mark.skipif("env.PYPY and env.PY2")
|
||||
@pytest.mark.xfail("env.PYPY and not env.PY2")
|
||||
@pytest.mark.xfail("env.PYPY")
|
||||
def test_multiple_inheritance_mix1():
|
||||
class Base1:
|
||||
def __init__(self, i):
|
||||
@ -53,15 +51,14 @@ def test_multiple_inheritance_mix2():
|
||||
assert mt.bar() == 4
|
||||
|
||||
|
||||
@pytest.mark.skipif("env.PYPY and env.PY2")
|
||||
@pytest.mark.xfail("env.PYPY and not env.PY2")
|
||||
@pytest.mark.xfail("env.PYPY")
|
||||
def test_multiple_inheritance_python():
|
||||
class MI1(m.Base1, m.Base2):
|
||||
def __init__(self, i, j):
|
||||
m.Base1.__init__(self, i)
|
||||
m.Base2.__init__(self, j)
|
||||
|
||||
class B1(object):
|
||||
class B1:
|
||||
def v(self):
|
||||
return 1
|
||||
|
||||
@ -96,7 +93,7 @@ def test_multiple_inheritance_python():
|
||||
def v(self):
|
||||
return 2
|
||||
|
||||
class B3(object):
|
||||
class B3:
|
||||
def v(self):
|
||||
return 3
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
from pybind11_tests import numpy_vectorize as m
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
from pybind11_tests import ConstructorStats, UserType
|
||||
@ -40,7 +39,7 @@ def test_pointers(msg):
|
||||
1. (arg0: capsule) -> int
|
||||
|
||||
Invoked with: [1, 2, 3]
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
|
||||
assert m.return_null_str() is None
|
||||
|
@ -1,7 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env
|
||||
from pybind11_tests import ConstructorStats
|
||||
from pybind11_tests import operators as m
|
||||
|
||||
@ -151,5 +149,4 @@ def test_overriding_eq_reset_hash():
|
||||
def test_return_set_of_unhashable():
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.get_unhashable_HashMe_set()
|
||||
if not env.PY2:
|
||||
assert str(excinfo.value.__cause__).startswith("unhashable type:")
|
||||
|
@ -1,14 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pickle
|
||||
|
||||
import pytest
|
||||
|
||||
import env
|
||||
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"])
|
||||
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("get_tuple", []() { return py::make_tuple(42, py::none(), "spam"); });
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03030000
|
||||
// test_simple_namespace
|
||||
m.def("get_simple_namespace", []() {
|
||||
auto ns = py::module_::import("types").attr("SimpleNamespace")(
|
||||
@ -96,7 +95,6 @@ TEST_SUBMODULE(pytypes, m) {
|
||||
py::setattr(ns, "right", py::int_(2));
|
||||
return ns;
|
||||
});
|
||||
#endif
|
||||
|
||||
// test_str
|
||||
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", {}, {});
|
||||
});
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
m.def("test_memoryview_from_memory", []() {
|
||||
const char *buf = "\xff\xe1\xab\x37";
|
||||
return py::memoryview::from_memory(buf, static_cast<py::ssize_t>(strlen(buf)));
|
||||
});
|
||||
#endif
|
||||
|
||||
// test_builtin_functions
|
||||
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 pytest
|
||||
|
||||
import env
|
||||
import env # noqa: F401
|
||||
from pybind11_tests import debug_enabled
|
||||
from pybind11_tests import pytypes as m
|
||||
|
||||
@ -123,7 +120,6 @@ def test_tuple():
|
||||
assert m.get_tuple() == (42, None, "spam")
|
||||
|
||||
|
||||
@pytest.mark.skipif("env.PY2")
|
||||
def test_simple_namespace():
|
||||
ns = m.get_simple_namespace()
|
||||
assert ns.attr == 42
|
||||
@ -140,7 +136,7 @@ def test_str(doc):
|
||||
|
||||
assert doc(m.str_from_bytes) == "str_from_bytes() -> str"
|
||||
|
||||
class A(object):
|
||||
class A:
|
||||
def __str__(self):
|
||||
return "this is a str"
|
||||
|
||||
@ -158,22 +154,12 @@ def test_str(doc):
|
||||
malformed_utf8 = b"\x80"
|
||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||
assert m.str_from_object(malformed_utf8) is malformed_utf8
|
||||
elif env.PY2:
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
m.str_from_object(malformed_utf8)
|
||||
else:
|
||||
assert m.str_from_object(malformed_utf8) == "b'\\x80'"
|
||||
if env.PY2:
|
||||
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"
|
||||
ucs_surrogates_str = u"\udcc3"
|
||||
if env.PY2:
|
||||
assert u"\udcc3" == m.str_from_string_from_str(ucs_surrogates_str)
|
||||
else:
|
||||
ucs_surrogates_str = "\udcc3"
|
||||
with pytest.raises(UnicodeEncodeError):
|
||||
m.str_from_string_from_str(ucs_surrogates_str)
|
||||
|
||||
@ -184,9 +170,7 @@ def test_bytes(doc):
|
||||
assert m.bytes_from_string().decode() == "foo"
|
||||
assert m.bytes_from_str().decode() == "bar"
|
||||
|
||||
assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format(
|
||||
"str" if env.PY2 else "bytes"
|
||||
)
|
||||
assert doc(m.bytes_from_str) == "bytes_from_str() -> bytes"
|
||||
|
||||
|
||||
def test_bytearray(doc):
|
||||
@ -278,11 +262,6 @@ def test_constructors():
|
||||
"""C++ default and converting constructors are equivalent to type calls in Python"""
|
||||
types = [bytes, bytearray, str, bool, int, float, tuple, list, dict, set]
|
||||
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
|
||||
|
||||
data = {
|
||||
@ -300,11 +279,6 @@ def test_constructors():
|
||||
}
|
||||
inputs = {k.__name__: v for k, v in data.items()}
|
||||
expected = {k.__name__: k(v) for k, v in data.items()}
|
||||
if env.PY2: # Similar to the above. See comments above.
|
||||
inputs["bytes"] = b"41"
|
||||
inputs["str"] = 42
|
||||
expected["bytes"] = b"41"
|
||||
expected["str"] = u"42"
|
||||
|
||||
assert m.converting_constructors(inputs) == expected
|
||||
assert m.cast_functions(inputs) == expected
|
||||
@ -340,42 +314,35 @@ def test_non_converting_constructors():
|
||||
def test_pybind11_str_raw_str():
|
||||
# specifically to exercise pybind11::str::raw_str
|
||||
cvt = m.convert_to_pybind11_str
|
||||
assert cvt(u"Str") == u"Str"
|
||||
assert cvt(b"Bytes") == u"Bytes" if env.PY2 else "b'Bytes'"
|
||||
assert cvt(None) == u"None"
|
||||
assert cvt(False) == u"False"
|
||||
assert cvt(True) == u"True"
|
||||
assert cvt(42) == u"42"
|
||||
assert cvt(2 ** 65) == u"36893488147419103232"
|
||||
assert cvt(-1.50) == u"-1.5"
|
||||
assert cvt(()) == u"()"
|
||||
assert cvt((18,)) == u"(18,)"
|
||||
assert cvt([]) == u"[]"
|
||||
assert cvt([28]) == u"[28]"
|
||||
assert cvt({}) == u"{}"
|
||||
assert cvt({3: 4}) == u"{3: 4}"
|
||||
assert cvt(set()) == u"set([])" if env.PY2 else "set()"
|
||||
assert cvt({3, 3}) == u"set([3])" if env.PY2 else "{3}"
|
||||
assert cvt("Str") == "Str"
|
||||
assert cvt(b"Bytes") == "b'Bytes'"
|
||||
assert cvt(None) == "None"
|
||||
assert cvt(False) == "False"
|
||||
assert cvt(True) == "True"
|
||||
assert cvt(42) == "42"
|
||||
assert cvt(2**65) == "36893488147419103232"
|
||||
assert cvt(-1.50) == "-1.5"
|
||||
assert cvt(()) == "()"
|
||||
assert cvt((18,)) == "(18,)"
|
||||
assert cvt([]) == "[]"
|
||||
assert cvt([28]) == "[28]"
|
||||
assert cvt({}) == "{}"
|
||||
assert cvt({3: 4}) == "{3: 4}"
|
||||
assert cvt(set()) == "set()"
|
||||
assert cvt({3, 3}) == "{3}"
|
||||
|
||||
valid_orig = u"DZ"
|
||||
valid_orig = "DZ"
|
||||
valid_utf8 = valid_orig.encode("utf-8")
|
||||
valid_cvt = cvt(valid_utf8)
|
||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||
assert valid_cvt is valid_utf8
|
||||
else:
|
||||
assert type(valid_cvt) is unicode if env.PY2 else str # noqa: F821
|
||||
if env.PY2:
|
||||
assert valid_cvt == valid_orig
|
||||
else:
|
||||
assert type(valid_cvt) is str
|
||||
assert valid_cvt == "b'\\xc7\\xb1'"
|
||||
|
||||
malformed_utf8 = b"\x80"
|
||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||
assert cvt(malformed_utf8) is malformed_utf8
|
||||
else:
|
||||
if env.PY2:
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
cvt(malformed_utf8)
|
||||
else:
|
||||
malformed_cvt = cvt(malformed_utf8)
|
||||
assert type(malformed_cvt) is str
|
||||
@ -428,14 +395,14 @@ def test_print(capture):
|
||||
|
||||
|
||||
def test_hash():
|
||||
class Hashable(object):
|
||||
class Hashable:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __hash__(self):
|
||||
return self.value
|
||||
|
||||
class Unhashable(object):
|
||||
class Unhashable:
|
||||
__hash__ = None
|
||||
|
||||
assert m.hash_function(Hashable(42)) == 42
|
||||
@ -493,12 +460,7 @@ def test_memoryview(method, args, fmt, expected_view):
|
||||
view = method(*args)
|
||||
assert isinstance(view, memoryview)
|
||||
assert view.format == fmt
|
||||
if isinstance(expected_view, bytes) or not env.PY2:
|
||||
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)
|
||||
assert list(view) == list(expected_view)
|
||||
|
||||
|
||||
@pytest.mark.xfail("env.PYPY", reason="getrefcount is not available")
|
||||
@ -522,11 +484,6 @@ def test_memoryview_from_buffer_empty_shape():
|
||||
view = m.test_memoryview_from_buffer_empty_shape()
|
||||
assert isinstance(view, memoryview)
|
||||
assert view.format == "B"
|
||||
if env.PY2:
|
||||
# Python 2 behavior is weird, but Python 3 (the future) is fine.
|
||||
# PyPy3 has <memoryview, while CPython 2 has <memory
|
||||
assert bytes(view).startswith(b"<memory")
|
||||
else:
|
||||
assert bytes(view) == b""
|
||||
|
||||
|
||||
@ -536,14 +493,10 @@ def test_test_memoryview_from_buffer_invalid_strides():
|
||||
|
||||
|
||||
def test_test_memoryview_from_buffer_nullptr():
|
||||
if env.PY2:
|
||||
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():
|
||||
view = m.test_memoryview_from_memory()
|
||||
assert isinstance(view, memoryview)
|
||||
@ -563,9 +516,9 @@ def test_builtin_functions():
|
||||
|
||||
def test_isinstance_string_types():
|
||||
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"):
|
||||
assert m.isinstance_pybind11_str(b"")
|
||||
else:
|
||||
@ -575,24 +528,21 @@ def test_isinstance_string_types():
|
||||
def test_pass_bytes_or_unicode_to_string_types():
|
||||
assert m.pass_to_pybind11_bytes(b"Bytes") == 5
|
||||
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
|
||||
else:
|
||||
with pytest.raises(TypeError):
|
||||
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(u"Str") == 3
|
||||
assert m.pass_to_std_string("Str") == 3
|
||||
|
||||
malformed_utf8 = b"\x80"
|
||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||
assert m.pass_to_pybind11_str(malformed_utf8) == 1
|
||||
elif env.PY2:
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
m.pass_to_pybind11_str(malformed_utf8)
|
||||
else:
|
||||
with pytest.raises(TypeError):
|
||||
m.pass_to_pybind11_str(malformed_utf8)
|
||||
@ -609,12 +559,14 @@ def test_weakref(create_weakref, create_weakref_with_callback):
|
||||
from weakref import getweakrefcount
|
||||
|
||||
# Apparently, you cannot weakly reference an object()
|
||||
class WeaklyReferenced(object):
|
||||
class WeaklyReferenced:
|
||||
pass
|
||||
|
||||
callback_called = False
|
||||
|
||||
def callback(wr):
|
||||
# No `nonlocal` in Python 2
|
||||
callback.called = True
|
||||
nonlocal callback_called
|
||||
callback_called = True
|
||||
|
||||
obj = WeaklyReferenced()
|
||||
assert getweakrefcount(obj) == 0
|
||||
@ -623,13 +575,12 @@ def test_weakref(create_weakref, create_weakref_with_callback):
|
||||
|
||||
obj = WeaklyReferenced()
|
||||
assert getweakrefcount(obj) == 0
|
||||
callback.called = False
|
||||
wr = create_weakref_with_callback(obj, callback) # noqa: F841
|
||||
assert getweakrefcount(obj) == 1
|
||||
assert not callback.called
|
||||
assert not callback_called
|
||||
del obj
|
||||
pytest.gc_collect()
|
||||
assert callback.called
|
||||
assert callback_called
|
||||
|
||||
|
||||
def test_cpp_iterators():
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
from pybind11_tests import ConstructorStats
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
m = pytest.importorskip("pybind11_tests.smart_ptr")
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
from pybind11_tests import ConstructorStats, UserType
|
||||
@ -283,7 +282,7 @@ def test_stl_pass_by_pointer(msg):
|
||||
1. (v: List[int] = None) -> List[int]
|
||||
|
||||
Invoked with:
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
@ -295,7 +294,7 @@ def test_stl_pass_by_pointer(msg):
|
||||
1. (v: List[int] = None) -> List[int]
|
||||
|
||||
Invoked with: None
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
|
||||
assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3]
|
||||
|
@ -1,7 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env
|
||||
from pybind11_tests import stl_binders as m
|
||||
|
||||
|
||||
@ -74,15 +72,10 @@ def test_vector_buffer():
|
||||
assert v[1] == 2
|
||||
v[2] = 5
|
||||
mv = memoryview(v) # We expose the buffer interface
|
||||
if not env.PY2:
|
||||
assert mv[2] == 5
|
||||
mv[2] = 6
|
||||
else:
|
||||
assert mv[2] == "\x05"
|
||||
mv[2] = "\x06"
|
||||
assert v[2] == 6
|
||||
|
||||
if not env.PY2:
|
||||
mv = memoryview(b)
|
||||
v = m.VectorUChar(mv[::2])
|
||||
assert v[1] == 3
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pybind11_tests import tagbased_polymorphic as m
|
||||
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import threading
|
||||
|
||||
from pybind11_tests import thread as m
|
||||
@ -7,7 +5,7 @@ from pybind11_tests import thread as m
|
||||
|
||||
class Thread(threading.Thread):
|
||||
def __init__(self, fn):
|
||||
super(Thread, self).__init__()
|
||||
super().__init__()
|
||||
self.fn = fn
|
||||
self.e = None
|
||||
|
||||
@ -19,7 +17,7 @@ class Thread(threading.Thread):
|
||||
self.e = e
|
||||
|
||||
def join(self):
|
||||
super(Thread, self).join()
|
||||
super().join()
|
||||
if self.e:
|
||||
raise self.e
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pybind11_tests import union_ as m
|
||||
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
@ -10,12 +9,12 @@ from pybind11_tests import ConstructorStats # noqa: E402
|
||||
def test_override(capture, msg):
|
||||
class ExtendedExampleVirt(m.ExampleVirt):
|
||||
def __init__(self, state):
|
||||
super(ExtendedExampleVirt, self).__init__(state + 1)
|
||||
super().__init__(state + 1)
|
||||
self.data = "Hello world"
|
||||
|
||||
def run(self, value):
|
||||
print("ExtendedExampleVirt::run(%i), calling parent.." % value)
|
||||
return super(ExtendedExampleVirt, self).run(value + 1)
|
||||
return super().run(value + 1)
|
||||
|
||||
def run_bool(self):
|
||||
print("ExtendedExampleVirt::run_bool()")
|
||||
@ -29,7 +28,7 @@ def test_override(capture, msg):
|
||||
|
||||
class ExtendedExampleVirt2(ExtendedExampleVirt):
|
||||
def __init__(self, state):
|
||||
super(ExtendedExampleVirt2, self).__init__(state + 1)
|
||||
super().__init__(state + 1)
|
||||
|
||||
def get_string2(self):
|
||||
return "override2"
|
||||
@ -41,7 +40,7 @@ def test_override(capture, msg):
|
||||
capture
|
||||
== """
|
||||
Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
@ -59,7 +58,7 @@ def test_override(capture, msg):
|
||||
== """
|
||||
ExtendedExampleVirt::run(20), calling parent..
|
||||
Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
with capture:
|
||||
assert m.runExampleVirtBool(ex12p) is False
|
||||
@ -76,7 +75,7 @@ def test_override(capture, msg):
|
||||
== """
|
||||
ExtendedExampleVirt::run(50), calling parent..
|
||||
Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
|
||||
""" # noqa: E501 line too long
|
||||
"""
|
||||
)
|
||||
|
||||
cstats = ConstructorStats.get(m.ExampleVirt)
|
||||
@ -97,7 +96,7 @@ def test_alias_delay_initialization1(capture):
|
||||
|
||||
class B(m.A):
|
||||
def __init__(self):
|
||||
super(B, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def f(self):
|
||||
print("In python f()")
|
||||
@ -137,7 +136,7 @@ def test_alias_delay_initialization2(capture):
|
||||
|
||||
class B2(m.A2):
|
||||
def __init__(self):
|
||||
super(B2, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def f(self):
|
||||
print("In python B2.f()")
|
||||
@ -245,7 +244,7 @@ def test_dispatch_issue(msg):
|
||||
class PyClass2(m.DispatchIssue):
|
||||
def dispatch(self):
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
super(PyClass2, self).dispatch()
|
||||
super().dispatch()
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== 'Tried to call pure virtual function "Base::dispatch"'
|
||||
@ -262,7 +261,7 @@ def test_recursive_dispatch_issue(msg):
|
||||
|
||||
class Data(m.Data):
|
||||
def __init__(self, value):
|
||||
super(Data, self).__init__()
|
||||
super().__init__()
|
||||
self.value = value
|
||||
|
||||
class Adder(m.Adder):
|
||||
|
@ -92,7 +92,7 @@ endif()
|
||||
|
||||
# Use the Python interpreter to find the libs.
|
||||
if(NOT PythonLibsNew_FIND_VERSION)
|
||||
set(PythonLibsNew_FIND_VERSION "")
|
||||
set(PythonLibsNew_FIND_VERSION "3.5")
|
||||
endif()
|
||||
|
||||
find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} ${_pythonlibs_required}
|
||||
|
@ -1,6 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
|
||||
|
@ -8,7 +8,6 @@ Adds the following targets::
|
||||
pybind11::lto - Link time optimizations (manual selection)
|
||||
pybind11::thin_lto - Link time optimizations (manual selection)
|
||||
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::opt_size - avoid optimizations that increase code size
|
||||
|
||||
@ -66,31 +65,6 @@ set_property(
|
||||
APPEND
|
||||
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 ---------------------------
|
||||
|
||||
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.
|
||||
``pybind11::python_link_helper``
|
||||
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``
|
||||
An alternative to ``INTERPROCEDURAL_OPTIMIZATION``.
|
||||
``pybind11::lto``
|
||||
|
@ -22,9 +22,7 @@ else()
|
||||
set(_pybind11_quiet "")
|
||||
endif()
|
||||
|
||||
if(NOT Python_FOUND
|
||||
AND NOT Python3_FOUND
|
||||
AND NOT Python2_FOUND)
|
||||
if(NOT Python_FOUND AND NOT Python3_FOUND)
|
||||
if(NOT DEFINED Python_FIND_IMPLEMENTATIONS)
|
||||
set(Python_FIND_IMPLEMENTATIONS CPython PyPy)
|
||||
endif()
|
||||
@ -34,7 +32,7 @@ if(NOT Python_FOUND
|
||||
set(Python_ROOT_DIR "$ENV{pythonLocation}")
|
||||
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 this behavior is not desired, FindPython _before_ pybind11.
|
||||
@ -51,19 +49,10 @@ if(Python_FOUND)
|
||||
set(_Python
|
||||
Python
|
||||
CACHE INTERNAL "" FORCE)
|
||||
elseif(Python3_FOUND AND NOT Python2_FOUND)
|
||||
elseif(Python3_FOUND)
|
||||
set(_Python
|
||||
Python3
|
||||
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()
|
||||
|
||||
if(PYBIND11_MASTER_PROJECT)
|
||||
@ -137,7 +126,7 @@ if(PYTHON_IS_DEBUG)
|
||||
PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)
|
||||
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)
|
||||
# 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")
|
||||
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
|
||||
if(TARGET ${_Python}::Python)
|
||||
set_property(
|
||||
@ -205,8 +187,6 @@ function(pybind11_add_module target_name)
|
||||
python_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})
|
||||
elseif("${_Python}" STREQUAL "Python3")
|
||||
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()
|
||||
message(FATAL_ERROR "Cannot detect FindPython version: ${_Python}")
|
||||
endif()
|
||||
@ -223,10 +203,6 @@ function(pybind11_add_module target_name)
|
||||
target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
|
||||
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
|
||||
# different pybind versions to work properly, and for some features (e.g.
|
||||
# py::module_local). We force it on everything inside the `pybind11`
|
||||
|
@ -43,7 +43,7 @@ endif()
|
||||
|
||||
# A user can set versions manually too
|
||||
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 "")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
||||
@ -122,13 +122,6 @@ set_property(
|
||||
INTERFACE_LINK_LIBRARIES pybind11::python_link_helper
|
||||
"$<$<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(
|
||||
TARGET pybind11::embed
|
||||
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