Repository navigation
Expand file tree
/
Copy pathtest_via_docker.py
More file actions
executable file
·209 lines (201 loc) · 8.61 KB
/
Copy pathtest_via_docker.py
File metadata and controls
executable file
·209 lines (201 loc) · 8.61 KB
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#!/usr/bin/env python3
import argparse
import multiprocessing.pool
import os
import platform
import subprocess
import sys
import threading
containers = {
'python:3.9-slim': {},
'python:3.10-slim': {},
'python:3.11-slim': {},
'python:3.12-slim': {},
'python:3.13-slim': {},
'python:3.14-slim': {},
'liw/python:3.13': {
'skip': True,
'build': {'base': 'debian:stable-slim', 'python': '3.13',
'packages': 'build-essential libffi-dev'}},
'liw/python:3.14': {
'skip': True,
'build': {'base': 'debian:stable-slim', 'python': '3.14',
'packages': 'build-essential libffi-dev'}},
'liw/python:3.14t': {
# 'skip': True,
'skip': platform.machine() in {'aarch64', 'arm64'},
'build': {'base': 'debian:stable-slim', 'python': '3.14t',
'packages': 'build-essential libffi-dev libproj-dev '
'proj-bin libxml2-dev libxmlsec1-dev'},
},
'liw/python:3.15': {
# 'skip': True,
'build': {'base': 'debian:stable-slim', 'python': '3.15',
'packages': 'build-essential libffi-dev'}},
'liw/python:3.15t': {
# 'skip': True,
'skip': platform.machine() in {'aarch64', 'arm64'},
'build': {'base': 'debian:stable-slim', 'python': '3.15t',
'packages': 'build-essential libffi-dev libproj-dev '
'proj-bin libxml2-dev libxmlsec1-dev'},
},
# -- pypy
'pypy:3.9': {'skip': True},
'pypy:3.10': {'skip': True},
'pypy:3.11': {'skip': True},
# -- manylinux_2_28
'almalinux:8 3.9': {'subcmds': ['sed -i -e \'s/^mirrorlist=/#mirrorlist=/\' -e \'s|^# baseurl=|baseurl=|\' /etc/yum.repos.d/almalinux*.repo', 'yum install -y python39-pip']}, # noqa
'liw/almapython:3.10': {'build': {'base': 'almalinux:8', 'python': '3.10'}},
'almalinux:8 3.11': {'subcmds': ['sed -i -e \'s/^mirrorlist=/#mirrorlist=/\' -e \'s|^# baseurl=|baseurl=|\' /etc/yum.repos.d/almalinux*.repo', 'yum install -y python3.11-pip']}, # noqa
# 'almalinux:8 3.12': {'subcmds': ['yum install -y python3.12-pip']},
'liw/almapython:3.12': {'build': {'base': 'almalinux:8', 'python': '3.12'}},
'liw/almapython:3.13': {'build': {'base': 'almalinux:8', 'python': '3.13'}},
'liw/almapython:3.14': {
'build': {'base': 'almalinux:8', 'python': '3.14'},
'subcmds': ['sed -i -e \'s/^mirrorlist=/#mirrorlist=/\' -e \'s|^# baseurl=|baseurl=|\' /etc/yum.repos.d/almalinux*.repo', 'yum install -y libffi-devel gcc']}, # noqa
'liw/almapython:3.14t': {
'build': {'base': 'almalinux:8', 'python': '3.14'},
'subcmds': ['sed -i -e \'s/^mirrorlist=/#mirrorlist=/\' -e \'s|^# baseurl=|baseurl=|\' /etc/yum.repos.d/almalinux*.repo', 'yum install -y libffi-devel gcc']}, # noqa
'liw/almapython:3.15': {
# 'skip': True,
'build': {'base': 'almalinux:8', 'python': '3.15'},
'subcmds': ['sed -i -e \'s/^mirrorlist=/#mirrorlist=/\' -e \'s|^# baseurl=|baseurl=|\' /etc/yum.repos.d/almalinux*.repo', 'yum install -y libffi-devel gcc']}, # noqa
'liw/almapython:3.15t': {
# 'skip': True,
'build': {'base': 'almalinux:8', 'python': '3.15'},
'subcmds': ['sed -i -e \'s/^mirrorlist=/#mirrorlist=/\' -e \'s|^# baseurl=|baseurl=|\' /etc/yum.repos.d/almalinux*.repo', 'yum install -y libffi-devel gcc']}, # noqa
}
if platform.machine() not in {'aarch64', 'arm64'}:
containers.update({
# -- centos
# See https://github.com/molinav/docker-pyenv for some additional images
# 'molinav/pyenv:3.9-centos-7': {},
# -- opensuse
# 'molinav/pyenv:3.9-opensuse-15.3': {},
})
# Without parallelism, this is much simpler:
# for container in containers:
# print('---- Testing in %s ----' % container)
# cmd = [
# 'docker', 'run',
# '-v', '%s/wheels:/wheels' % os.path.dirname(os.path.realpath(__file__)),
# '-v', '%s/test:/test' % os.path.dirname(os.path.realpath(__file__)),
# '--rm', container, 'bash', '-e', '/test/test_script.sh']
# cmd += sys.argv[1:]
# try:
# subprocess.check_call(cmd)
# except Exception:
# print('---- Failed in %s ----' % container)
# raise
# print('Passed')
def test_container(container, entry, full, options=None):
if options is None:
options = {}
subcmds = options.get('subcmds')
lock = entry['lock']
result = entry['out']
with lock:
entry['status'] = 'started'
cmds = []
if 'build' in options:
buildcmd = [
'docker', 'build',
'--build-arg', f'baseimage={options["build"]["base"]}',
'--build-arg', f'PYTHON_VERSION={options["build"]["python"]}',
'--build-arg', f'packages={options["build"].get("packages", "")}',
'-f', 'test/python.Dockerfile', '-t', entry['container'], 'test']
cmds.append(buildcmd)
if subcmds is None:
subcmds = []
subcmds.append('bash /test/test_script.sh')
if full:
subcmds.append('bash /test/li_script.sh')
maincmd = [
'docker', 'run',
'-v', '%s/wheels:/wheels' % os.path.dirname(os.path.realpath(__file__)),
'-v', '%s/test:/test' % os.path.dirname(os.path.realpath(__file__)),
'--rm', container, 'bash', '-e', '-c',
' && '.join(subcmds),
]
# maincmd += sys.argv[1:]
cmds.append(maincmd)
for cmd in cmds:
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
line = proc.stdout.readline()
if not line:
break
with lock:
result.append(line.decode())
returncode = proc.wait()
if returncode:
break
with lock:
entry['status'] = 'passed' if not returncode else 'failed'
if returncode:
entry['exception'] = subprocess.CalledProcessError(returncode, cmd, ''.join(result))
if __name__ == '__main__': # noqa
parser = argparse.ArgumentParser(
description='Test large image wheels in various combinations of '
'python versions and operating systems via docker.')
parser.add_argument(
'spec', nargs='?',
help='Only run versions that include this substring')
parser.add_argument(
'--jobs', '-j', type=int, help='Number of concurrent jobs to run. '
'The maximum number of jobs will always be limited to smaller of this '
'and the number of cpus.')
parser.add_argument(
'--full', action='store_true',
help='Run the large_image tox tests as well.')
parser.add_argument(
'--dry-run', '-n', action='store_true',
help='Just report which tests will be run.')
parser.add_argument(
'--only', action='store_true',
help='Only run tests that exactly match the spec.')
opts = parser.parse_args()
count = multiprocessing.cpu_count()
if opts.jobs:
count = max(1, min(opts.jobs if opts.jobs > 1 else count + opts.jobs, count))
pool = multiprocessing.pool.ThreadPool(processes=count)
results = []
for container in containers:
if opts.spec and opts.spec not in container:
continue
if opts.only and opts.spec and opts.spec != container:
continue
if containers[container].get('skip') and (not opts.spec or not opts.only):
continue
entry = {'out': [], 'lock': threading.Lock(), 'status': 'queued', 'container': container}
if opts.dry_run:
result = 'test'
else:
result = pool.apply_async(
test_container, (container.split()[0], entry, opts.full, containers[container]))
entry['result'] = result
results.append(entry)
pool.close()
for entry in results:
container = entry['container']
if opts.dry_run:
print(container)
continue
print('---- Starting in %s ----' % container)
while True:
with entry['lock']:
while len(entry['out']):
sys.stdout.write(entry['out'].pop(0))
if entry['result'].ready():
break
entry['result'].wait(0.1)
if entry['status'] == 'failed':
print('---- Failed in %s ----' % container)
raise entry['exception']
print('---- Passed in %s ----' % container)
if not opts.dry_run:
print('Passed')
# To test manually, run a container such as
# docker run -v `pwd`/wheels:/wheels -v `pwd`/test:/test --rm -it python:3.11-slim bash
# and then enter the script commands directly, typically starting with
# pip install pyvips large_image[sources,memcached] -f ${1:-/wheels}