Skip to content

Commit 2337cfe

Browse files
committed
refactor: simpler design with two outputs
1 parent 9cf0e50 commit 2337cfe

File tree

12 files changed

+421
-188
lines changed

12 files changed

+421
-188
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ jobs:
151151
- name: Interface test
152152
run: cmake --build build2 --target test_cmake_build
153153

154+
154155
clang:
155156
runs-on: ubuntu-latest
156157
strategy:

.github/workflows/configure.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,61 @@ jobs:
7676
working-directory: build dir
7777
if: github.event_name == 'workflow_dispatch'
7878
run: cmake --build . --config Release --target check
79+
80+
test-packaging:
81+
name: 🐍 2.7 • 📦 tests • windows-latest
82+
runs-on: windows-latest
83+
84+
steps:
85+
- uses: actions/checkout@v2
86+
87+
- name: Setup 🐍 2.7
88+
uses: actions/setup-python@v2
89+
with:
90+
python-version: 2.7
91+
92+
- name: Prepare env
93+
run: python -m pip install -r tests/requirements.txt --prefer-binary
94+
95+
- name: Python Packaging tests
96+
run: pytest tests/test_python_package/
97+
98+
99+
packaging:
100+
name: 🐍 3.8 • 📦 & 📦 tests • ubuntu-latest
101+
runs-on: ubuntu-latest
102+
103+
steps:
104+
- uses: actions/checkout@v2
105+
106+
- name: Setup 🐍 3.8
107+
uses: actions/setup-python@v2
108+
with:
109+
python-version: 3.8
110+
111+
- name: Prepare env
112+
run: python -m pip install -r tests/requirements.txt wheel twine --prefer-binary
113+
114+
- name: Python Packaging tests
115+
run: pytest tests/test_python_package/
116+
117+
- name: Build SDist
118+
run: |
119+
python setup.py sdist
120+
PYBIND11_ALT_SDIST=1 python setup.py sdist
121+
122+
- uses: actions/upload-artifact@v2
123+
with:
124+
path: dist/*
125+
126+
- name: Build wheel
127+
run: |
128+
python -m pip wheel . -w wheels
129+
PYBIND11_ALT_SDIST=1 python -m pip wheel . -w wheels
130+
131+
- uses: actions/upload-artifact@v2
132+
with:
133+
path: wheels/pybind11*.whl
134+
135+
- name: Check metadata
136+
run: twine check dist/* wheels/*

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v3.1.0
3+
rev: v3.2.0
44
hooks:
55
- id: check-added-large-files
66
- id: check-case-conflict
@@ -15,10 +15,10 @@ repos:
1515
- id: fix-encoding-pragma
1616

1717
- repo: https://github.com/psf/black
18-
rev: 19.10b0
18+
rev: 20.8b1
1919
hooks:
2020
- id: black
21-
files: ^(setup.py|pybind11)
21+
files: ^(setup.py|pybind11|tests/test_python_package)
2222

2323
- repo: https://github.com/Lucas-C/pre-commit-hooks
2424
rev: v1.1.9

MANIFEST.in

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
recursive-include include/pybind11 *.h
2-
recursive-include pybind11 *.h
3-
recursive-include pybind11 *.cmake
1+
recursive-include pybind11/include/pybind11 *.h
42
recursive-include pybind11 *.py
5-
recursive-include tools *.cmake
6-
recursive-include tools *.in
7-
include CMakeLists.txt LICENSE README.md .github/CONTRIBUTING.md
3+
include pybind11/share/cmake/pybind11/*.cmake
4+
include LICENSE README.md pyproject.toml setup.py setup.cfg

setup.cfg

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
[metadata]
2-
name = pybind11
32
long_description = file: README.md
43
long_description_content_type = text/markdown
54
version = attr: pybind11.__version__
@@ -33,19 +32,7 @@ keywords =
3332

3433
[options]
3534
python_requires = >=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4
36-
find_package_data = True
3735
zip_safe = False
38-
packages =
39-
pybind11
40-
pybind11.include.pybind11
41-
pybind11.include.pybind11.detail
42-
pybind11.share.cmake.pybind11
43-
44-
[options.package_data]
45-
pybind11.include.pybind11 = *.h
46-
pybind11.include.pybind11.detail = *.h
47-
pybind11.share.cmake.pybind11 = *.cmake
48-
4936

5037
[sbdist_wheel]
5138
universal=1
@@ -54,17 +41,17 @@ universal=1
5441
ignore =
5542
tests/**
5643
docs/**
57-
tools/check-style.sh
58-
tools/clang
59-
tools/libsize.py
60-
tools/mkdoc.py
44+
tools/**
45+
include/**
6146
.appveyor.yml
6247
.cmake-format.yaml
6348
.gitmodules
6449
.pre-commit-config.yaml
6550
.readthedocs.yml
6651
pybind11/include/**
6752
pybind11/share/**
53+
CMakeLists.txt
54+
6855

6956
[flake8]
7057
max-line-length = 99
@@ -76,4 +63,4 @@ ignore =
7663
# camelcase 'cPickle' imported as lowercase 'pickle'
7764
N813
7865
# Black conflict
79-
W503
66+
W503, E203

setup.py

Lines changed: 31 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -4,47 +4,41 @@
44
# Setup script for PyPI; use CMakeFile.txt to build extension modules
55

66
import contextlib
7-
import glob
87
import os
9-
import re
108
import shutil
119
import subprocess
1210
import sys
1311
import tempfile
14-
from distutils.command.install_headers import install_headers
1512

16-
from setuptools import setup
13+
# PYBIND11_ALT_SDIST will build a different sdist, with the python-headers
14+
# files, and the sys.prefix files (CMake and headers).
1715

18-
# For now, there are three parts to this package. Besides the "normal" module:
19-
# PYBIND11_USE_HEADERS will include the python-headers files.
20-
# PYBIND11_USE_SYSTEM will include the sys.prefix files (CMake and headers).
21-
# The final version will likely only include the normal module or come in
22-
# different versions.
23-
24-
use_headers = os.environ.get("PYBIND11_USE_HEADERS", False)
25-
use_system = os.environ.get("PYBIND11_USE_SYSTEM", False)
26-
27-
setup_opts = dict()
16+
alt_sdist = os.environ.get("PYBIND11_ALT_SDIST", False)
17+
setup_py = "tools/setup_alt.py" if alt_sdist else "tools/setup_main.py"
18+
pyproject_toml = "tools/pyproject.toml"
2819

2920
# In a PEP 518 build, this will be in its own environment, so it will not
3021
# create extra files in the source
3122

3223
DIR = os.path.abspath(os.path.dirname(__file__))
3324

34-
prexist_include = os.path.exists("pybind11/include")
35-
prexist_share = os.path.exists("pybind11/share")
36-
3725

3826
@contextlib.contextmanager
39-
def monkey_patch_file(input_file):
40-
"Allow a file to be temporarily modified"
27+
def monkey_patch_file(input_file, replacement_file):
28+
"Allow a file to be temporarily replaced"
29+
inp_file = os.path.abspath(os.path.join(DIR, input_file))
30+
rep_file = os.path.abspath(os.path.join(DIR, replacement_file))
4131

42-
with open(os.path.join(DIR, input_file), "r") as f:
32+
with open(inp_file, "rb") as f:
4333
contents = f.read()
34+
with open(rep_file, "rb") as f:
35+
replacement = f.read()
4436
try:
45-
yield contents
37+
with open(inp_file, "wb") as f:
38+
f.write(replacement)
39+
yield
4640
finally:
47-
with open(os.path.join(DIR, input_file), "w") as f:
41+
with open(inp_file, "wb") as f:
4842
f.write(contents)
4943

5044

@@ -67,118 +61,20 @@ def remove_output(*sources):
6761
shutil.rmtree(src)
6862

6963

70-
def check_compare(input_set, *patterns):
71-
"Just a quick way to make sure all files are present"
72-
disk_files = set()
73-
for pattern in patterns:
74-
disk_files |= set(glob.glob(pattern, recursive=True))
75-
76-
assert input_set == disk_files, "{} setup.py only, {} on disk only".format(
77-
input_set - disk_files, disk_files - input_set
78-
)
79-
80-
81-
class InstallHeadersNested(install_headers):
82-
def run(self):
83-
headers = self.distribution.headers or []
84-
for header in headers:
85-
# Remove include/*/
86-
short_header = header.split("/", 2)[-1]
87-
88-
dst = os.path.join(self.install_dir, os.path.dirname(short_header))
89-
self.mkpath(dst)
90-
(out, _) = self.copy_file(header, dst)
91-
self.outfiles.append(out)
92-
93-
94-
main_headers = {
95-
"include/pybind11/attr.h",
96-
"include/pybind11/buffer_info.h",
97-
"include/pybind11/cast.h",
98-
"include/pybind11/chrono.h",
99-
"include/pybind11/common.h",
100-
"include/pybind11/complex.h",
101-
"include/pybind11/eigen.h",
102-
"include/pybind11/embed.h",
103-
"include/pybind11/eval.h",
104-
"include/pybind11/functional.h",
105-
"include/pybind11/iostream.h",
106-
"include/pybind11/numpy.h",
107-
"include/pybind11/operators.h",
108-
"include/pybind11/options.h",
109-
"include/pybind11/pybind11.h",
110-
"include/pybind11/pytypes.h",
111-
"include/pybind11/stl.h",
112-
"include/pybind11/stl_bind.h",
113-
}
114-
115-
detail_headers = {
116-
"include/pybind11/detail/class.h",
117-
"include/pybind11/detail/common.h",
118-
"include/pybind11/detail/descr.h",
119-
"include/pybind11/detail/init.h",
120-
"include/pybind11/detail/internals.h",
121-
"include/pybind11/detail/typeid.h",
122-
}
123-
124-
headers = main_headers | detail_headers
125-
check_compare(headers, "include/**/*.h")
126-
127-
if use_headers:
128-
setup_opts["headers"] = headers
129-
setup_opts["cmdclass"] = {"install_headers": InstallHeadersNested}
130-
131-
cmake_files = {
132-
"pybind11/share/cmake/pybind11/FindPythonLibsNew.cmake",
133-
"pybind11/share/cmake/pybind11/pybind11Common.cmake",
134-
"pybind11/share/cmake/pybind11/pybind11Config.cmake",
135-
"pybind11/share/cmake/pybind11/pybind11ConfigVersion.cmake",
136-
"pybind11/share/cmake/pybind11/pybind11NewTools.cmake",
137-
"pybind11/share/cmake/pybind11/pybind11Targets.cmake",
138-
"pybind11/share/cmake/pybind11/pybind11Tools.cmake",
139-
}
140-
141-
142-
package_headers = set("pybind11/{}".format(h) for h in headers)
143-
package_files = package_headers | cmake_files
144-
145-
# Generate the files if they are not generated (will be present in tarball)
146-
GENERATED = (
147-
[]
148-
if all(os.path.exists(h) for h in package_files)
149-
else ["pybind11/include", "pybind11/share"]
150-
)
151-
with remove_output(*GENERATED):
64+
with remove_output("pybind11/include", "pybind11/share"):
15265
# Generate the files if they are not present.
153-
if GENERATED:
154-
with TemporaryDirectory() as tmpdir:
155-
cmd = ["cmake", "-S", ".", "-B", tmpdir] + [
156-
"-DCMAKE_INSTALL_PREFIX=pybind11",
157-
"-DBUILD_TESTING=OFF",
158-
"-DPYBIND11_NOPYTHON=ON",
159-
]
160-
cmake_opts = dict(cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
161-
subprocess.check_call(cmd, **cmake_opts)
162-
subprocess.check_call(["cmake", "--install", tmpdir], **cmake_opts)
163-
164-
# Make sure all files are present
165-
check_compare(package_files, "pybind11/include/**/*.h", "pybind11/share/**/*.cmake")
166-
167-
if use_system:
168-
setup_opts["data_files"] = [
169-
("share/cmake", cmake_files),
170-
("include/pybind11", main_headers),
171-
("include/pybind11/detail", detail_headers),
66+
with TemporaryDirectory() as tmpdir:
67+
cmd = ["cmake", "-S", ".", "-B", tmpdir] + [
68+
"-DCMAKE_INSTALL_PREFIX=pybind11",
69+
"-DBUILD_TESTING=OFF",
70+
"-DPYBIND11_NOPYTHON=ON",
17271
]
173-
174-
# Remove the cmake / ninja requirements as now all files are guaranteed to exist
175-
if GENERATED:
176-
REQUIRES = re.compile(r"requires\s*=.+?\]", re.DOTALL | re.MULTILINE)
177-
with monkey_patch_file("pyproject.toml") as txt:
178-
with open("pyproject.toml", "w") as f:
179-
new_txt = REQUIRES.sub('requires = ["setuptools", "wheel"]', txt)
180-
f.write(new_txt)
181-
182-
setup(**setup_opts)
183-
else:
184-
setup(**setup_opts)
72+
cmake_opts = dict(cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
73+
subprocess.check_call(cmd, **cmake_opts)
74+
subprocess.check_call(["cmake", "--install", tmpdir], **cmake_opts)
75+
76+
with monkey_patch_file("pyproject.toml", pyproject_toml):
77+
with monkey_patch_file("setup.py", setup_py):
78+
with open(setup_py) as f:
79+
code = compile(f.read(), setup_py, "exec")
80+
exec(code, globals(), {})

0 commit comments

Comments
 (0)