Skip to content

Commit 62c71df

Browse files
committed
Implement optional per-env lockfiles in tox setup
1 parent 9675f3e commit 62c71df

19 files changed

+704
-9
lines changed

.flake8

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ extend-exclude =
2828
# Metadata of `pip wheel` cmd is autogenerated
2929
pip-wheel-metadata,
3030

31+
# IMPORTANT: avoid using ignore option, always use extend-ignore instead
32+
# Completely and unconditionally ignore the following errors:
33+
extend-ignore =
34+
# Legitimate cases, no need to "fix" these violations:
35+
WPS326 # "Found implicit string concatenation" -- nothing bad about this
36+
3137
# https://wemake-python-stylegui.de/en/latest/pages/usage/formatter.html
3238
#format = wemake
3339

@@ -43,6 +49,10 @@ per-file-ignores =
4349
# and subprocesses (import – S404; call – S603) in tests:
4450
cheroot/test/test_*.py: S101, S404, S603
4551

52+
# WPS102 Found incorrect module name pattern
53+
# This is not a regular module but a standalone script:
54+
bin/pip-wrapper: WPS102
55+
4656
# FIXME:
4757
cheroot/__init__.py: I003, WPS100, WPS412, WPS420, WPS422, WPS433
4858
cheroot/__main__.py: WPS130, WPS300

bin/pip-wrapper

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#! /usr/bin/env python
2+
"""A pip-wrapper that injects platform-specific constraints into pip."""
3+
from __future__ import print_function # noqa: WPS422
4+
5+
import functools
6+
import os
7+
import platform
8+
import subprocess # noqa: S404
9+
import sys
10+
11+
print_info = functools.partial(print, file=sys.stderr)
12+
13+
14+
def get_runtime_python_tag():
15+
"""Identify the Python tag of the current runtime.
16+
17+
:returns: Python tag.
18+
"""
19+
python_minor_ver = sys.version_info[:2]
20+
python_implementation = platform.python_implementation()
21+
22+
if python_implementation == 'PyPy':
23+
python_tag_prefix = 'py'
24+
else:
25+
python_tag_prefix = 'cp'
26+
27+
# pylint: disable=possibly-unused-variable
28+
python_minor_ver_tag = ''.join(map(str, python_minor_ver))
29+
30+
python_tag = (
31+
'{python_tag_prefix!s}{python_minor_ver_tag!s}'.
32+
format(**locals()) # noqa: WPS421
33+
)
34+
35+
if python_tag_prefix == 'cp' and python_implementation == 'CPython':
36+
print_info(
37+
'WARNING: The chosen Python interpreter tag "{python_tag}" '
38+
'may not match the current '
39+
'Python implementation "{python_implementation}"'.
40+
format(**locals()), # noqa: WPS421
41+
)
42+
43+
return python_tag
44+
45+
46+
def get_constraint_file_path(req_dir, toxenv, python_tag):
47+
"""Identify the constraints filename for the current environment.
48+
49+
:param req_dir: Requirements directory.
50+
:param toxenv: tox testenv.
51+
:param python_tag: Python tag.
52+
53+
:returns: Constraints filename for the current environment.
54+
"""
55+
sys_platform = sys.platform
56+
# pylint: disable=possibly-unused-variable
57+
platform_machine = platform.machine()
58+
59+
if toxenv in {'py', 'python'}:
60+
toxenv = 'py{ver}'.format(ver=python_tag[2:])
61+
62+
if sys_platform == 'linux2':
63+
sys_platform = 'linux'
64+
65+
constraint_name = (
66+
'tox-{toxenv}-{python_tag}-{sys_platform}-{platform_machine}'.
67+
format(**locals()) # noqa: WPS421
68+
)
69+
return os.path.join(req_dir, os.path.extsep.join((constraint_name, 'txt')))
70+
71+
72+
def make_pip_cmd(pip_args, constraint_file_path):
73+
"""Inject a lockfile constraint into the pip command if present.
74+
75+
:param pip_args: pip arguments.
76+
:param constraint_file_path: Path to a ``constraints.txt``-compatible file.
77+
78+
:returns: pip command.
79+
"""
80+
pip_cmd = [sys.executable, '-m', 'pip'] + pip_args
81+
if os.path.isfile(constraint_file_path):
82+
pip_cmd += ['--constraint', constraint_file_path]
83+
else:
84+
print_info(
85+
'WARNING: The expected pinned constraints file for the current env'
86+
'does not exist (should be "{constraint_file_path}").'.
87+
format(**locals()), # noqa: WPS421
88+
)
89+
return pip_cmd
90+
91+
92+
def run_cmd(cmd):
93+
"""Invoke a shell command after logging it.
94+
95+
:param cmd: The command to invoke.
96+
"""
97+
print_info(
98+
'Invoking the following command: {cmd}'.
99+
format(cmd=' '.join(cmd)),
100+
)
101+
subprocess.check_call(cmd) # noqa: S603
102+
103+
104+
def main(argv):
105+
"""Invoke pip with the matching constraints file, if present.
106+
107+
:param argv: List of command-line arguments.
108+
"""
109+
constraint_file_path = get_constraint_file_path(
110+
req_dir=argv[1],
111+
toxenv=argv[0],
112+
python_tag=get_runtime_python_tag(),
113+
)
114+
pip_cmd = make_pip_cmd(
115+
pip_args=argv[2:],
116+
constraint_file_path=constraint_file_path,
117+
)
118+
run_cmd(pip_cmd)
119+
120+
121+
if __name__ == '__main__':
122+
main(sys.argv[1:])
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tox-build-dists.in
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#
2+
# This file is autogenerated by pip-compile with python 3.10
3+
# To update, run:
4+
#
5+
# pip-compile --allow-unsafe --output-file=requirements/tox-build-dists-cp310-linux-x86_64.txt --strip-extras requirements/tox-build-dists-cp310-linux-x86_64.in
6+
#
7+
build==0.7.0
8+
# via -r requirements/tox-build-dists-cp310-linux-x86_64.in
9+
packaging==21.3
10+
# via build
11+
pep517==0.12.0
12+
# via build
13+
pyparsing==3.0.6
14+
# via packaging
15+
tomli==2.0.0
16+
# via
17+
# build
18+
# pep517
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tox-build-dists.in
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#
2+
# This file is autogenerated by pip-compile with python 3.9
3+
# To update, run:
4+
#
5+
# pip-compile --allow-unsafe --output-file=requirements/tox-build-dists-cp39-linux-x86_64.txt --strip-extras requirements/tox-build-dists-cp39-linux-x86_64.in
6+
#
7+
build==0.7.0
8+
# via -r requirements/tox-build-dists-cp39-linux-x86_64.in
9+
packaging==21.3
10+
# via build
11+
pep517==0.12.0
12+
# via build
13+
pyparsing==3.0.6
14+
# via packaging
15+
tomli==2.0.0
16+
# via
17+
# build
18+
# pep517

requirements/tox-build-dists.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build ~= 0.7.0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tox-pre-commit.in
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#
2+
# This file is autogenerated by pip-compile with python 3.10
3+
# To update, run:
4+
#
5+
# pip-compile --allow-unsafe --output-file=requirements/tox-pre-commit-cp310-linux-x86_64.txt --strip-extras requirements/tox-pre-commit-cp310-linux-x86_64.in
6+
#
7+
cfgv==3.3.1
8+
# via pre-commit
9+
distlib==0.3.4
10+
# via virtualenv
11+
filelock==3.4.2
12+
# via virtualenv
13+
identify==2.4.1
14+
# via pre-commit
15+
nodeenv==1.6.0
16+
# via pre-commit
17+
platformdirs==2.4.1
18+
# via virtualenv
19+
pre-commit==2.16.0
20+
# via -r requirements/tox-pre-commit-cp310-linux-x86_64.in
21+
pyyaml==6.0
22+
# via pre-commit
23+
six==1.16.0
24+
# via virtualenv
25+
toml==0.10.2
26+
# via pre-commit
27+
virtualenv==20.13.0
28+
# via pre-commit
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tox-pre-commit.in

0 commit comments

Comments
 (0)