1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
# SPDX-License-Identifier: MIT
import os
import os.path
import platform
import re
import shutil
import subprocess
import sys
import tarfile
import urllib.request
import filelock
import pytest
import build.__main__
IS_WINDOWS = sys.platform.startswith('win')
IS_PYPY3 = platform.python_implementation() == 'PyPy'
INTEGRATION_SOURCES = {
'dateutil': ('dateutil/dateutil', '2.8.1'),
'pip': ('pypa/pip', '20.2.1'),
'Solaar': ('pwr-Solaar/Solaar', '1.0.3'),
'flit': ('takluyver/flit', '2.3.0'),
}
_SDIST = re.compile('.*.tar.gz')
_WHEEL = re.compile('.*.whl')
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
def get_project(name, tmp_path):
dest = tmp_path / name
if name == 'build':
# our own project is available in-source, just ignore development files
def _ignore_folder(base, filenames):
ignore = [n for n in filenames if n in excl or any(n.endswith(i) for i in ('_cache', '.egg-info', '.pyc'))]
if os.path.basename == ROOT and 'build' in filenames: # ignore build only at root (our module is build too)
ignore.append('build')
return ignore
excl = '.tox', 'dist', '.git', '__pycache__', '.integration-sources', '.github', 'tests', 'docs'
shutil.copytree(ROOT, str(dest), ignore=_ignore_folder)
return dest
# for other projects download from github and cache it
tar_store = os.path.join(ROOT, '.integration-sources')
try:
os.makedirs(tar_store)
except OSError: # python 2 has no exist_ok, and checking with exists is not parallel safe
pass # just ignore, if the creation failed we will have another failure soon that will notify the user
github_org_repo, version = INTEGRATION_SOURCES[name]
tar_filename = f'{name}-{version}.tar.gz'
tarball = os.path.join(tar_store, tar_filename)
with filelock.FileLock(os.path.join(tar_store, f'{tar_filename}.lock')):
if not os.path.exists(tarball):
url = f'https://github.com/{github_org_repo}/archive/{version}.tar.gz'
with urllib.request.urlopen(url) as request, open(tarball, 'wb') as file_handler:
shutil.copyfileobj(request, file_handler)
with tarfile.open(tarball, 'r:gz') as tar_handler:
tar_handler.extractall(str(dest))
return dest / f'{name}-{version}'
@pytest.mark.parametrize(
'call',
[
None, # via code
[sys.executable, '-m', 'build'], # module
['pyproject-build'], # entrypoint
],
ids=['code', 'module', 'entrypoint'],
)
@pytest.mark.parametrize(
'args',
[[], ['-x', '--no-isolation']],
ids=['isolated', 'no_isolation'],
)
@pytest.mark.parametrize(
'project',
[
'build',
'pip',
'dateutil',
'Solaar',
'flit',
],
)
@pytest.mark.isolated
def test_build(monkeypatch, project, args, call, tmp_path):
if project == 'flit' and '--no-isolation' in args:
pytest.xfail("can't build flit without isolation due to missing dependencies")
if project == 'Solaar' and IS_WINDOWS and IS_PYPY3:
pytest.xfail('Solaar fails building wheels via sdists on Windows on PyPy 3')
monkeypatch.chdir(tmp_path)
monkeypatch.setenv('SETUPTOOLS_SCM_PRETEND_VERSION', '0+dummy') # for the projects that use setuptools_scm
if call and call[0] == 'pyproject-build':
exe_name = f"pyproject-build{'.exe' if sys.platform.startswith('win') else ''}"
exe = os.path.join(os.path.dirname(sys.executable), exe_name)
if os.path.exists(exe):
call[0] = exe
else:
pytest.skip('Running via PYTHONPATH, so the pyproject-build entrypoint is not available')
path = get_project(project, tmp_path)
pkgs = tmp_path / 'pkgs'
args = [str(path), '-o', str(pkgs)] + args
if call is None:
build.__main__.main(args)
else:
subprocess.check_call(call + args)
pkg_names = os.listdir(str(pkgs))
assert list(filter(_SDIST.match, pkg_names))
assert list(filter(_WHEEL.match, pkg_names))
def test_isolation(tmp_dir, package_test_flit, mocker):
try:
import flit_core # noqa: F401
except ModuleNotFoundError:
pass
else:
pytest.xfail('flit_core is available -- we want it missing!') # pragma: no cover
mocker.patch('build.__main__._error')
build.__main__.main([package_test_flit, '-o', tmp_dir, '--no-isolation'])
build.__main__._error.assert_called_with("Backend 'flit_core.buildapi' is not available.")
|