Skip to content

Commit

Permalink
Implement optional per-env lockfiles in tox setup
Browse files Browse the repository at this point in the history
  • Loading branch information
webknjaz committed Jan 3, 2022
1 parent aa21d83 commit c30cfa8
Show file tree
Hide file tree
Showing 9 changed files with 593 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ extend-exclude =
# Metadata of `pip wheel` cmd is autogenerated
pip-wheel-metadata,

# IMPORTANT: avoid using ignore option, always use extend-ignore instead
# Completely and unconditionally ignore the following errors:
extend-ignore =
# Legitimate cases, no need to "fix" these violations:
WPS326 # "Found implicit string concatenation" -- nothing bad about this

# https://wemake-python-stylegui.de/en/latest/pages/usage/formatter.html
#format = wemake

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

# WPS102 Found incorrect module name pattern
# This is not a regular module but a standalone script:
bin/pip-wrapper: WPS102

# FIXME:
cheroot/__init__.py: I003, WPS100, WPS412, WPS420, WPS422, WPS433
cheroot/__main__.py: WPS130, WPS300
Expand Down
121 changes: 121 additions & 0 deletions bin/pip-wrapper
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#! /usr/bin/env python
"""A pip-wrapper that injects platform-specific constraints into pip."""
from __future__ import print_function # noqa: WPS422

import functools
import os
import platform
import subprocess # noqa: S404
import sys

print_info = functools.partial(print, file=sys.stderr)


def get_runtime_python_tag():
"""Identify the Python tag of the current runtime.
:returns: Python tag.
"""
python_minor_ver = sys.version_info[:2]
python_implementation = platform.python_implementation()

if python_implementation == 'PyPy':
python_tag_prefix = 'py'
else:
python_tag_prefix = 'cp'

# pylint: disable=possibly-unused-variable
python_minor_ver_tag = ''.join(map(str, python_minor_ver))

python_tag = (
'{python_tag_prefix!s}{python_minor_ver_tag!s}'.
format(**locals()) # noqa: WPS421
)

if python_tag_prefix == 'cp' and python_implementation == 'CPython':
print_info(
'WARNING: The chosen Python interpreter tag "{python_tag}" '
'may not match the current '
'Python implementation "{python_implementation}"'.
format(**locals()), # noqa: WPS421
)

return python_tag


def get_constraint_file_path(req_dir, toxenv, python_tag):
"""Identify the constraints filename for the current environment.
:param req_dir: Requirements directory.
:param toxenv: tox testenv.
:param python_tag: Python tag.
:returns: Constraints filename for the current environment.
"""
sys_platform = sys.platform
platform_machine = platform.machine()

if toxenv in {'py', 'python'}:
toxenv = 'py{ver}'.format(ver=python_tag[2:])

if sys_platform == 'linux2':
sys_platform = 'linux'

constraint_name = (
'tox-{toxenv}-{python_tag}-{sys_platform}-{platform_machine}'.
format(**locals()) # noqa: WPS421
)
return os.path.join(req_dir, os.path.extsep.join((constraint_name, 'txt')))


def make_pip_cmd(pip_args, constraint_file_path):
"""Inject a lockfile constraint into the pip command if present.
:param pip_args: pip arguments.
:param constraint_file_path: Path to a ``constraints.txt``-compatible file.
:returns: pip command.
"""
pip_cmd = [sys.executable, '-m', 'pip'] + pip_args
if os.path.isfile(constraint_file_path):
pip_cmd += ['--constraint', constraint_file_path]
else:
print_info(
'WARNING: The expected pinned constraints file for the current env'
'does not exist (should be "{constraint_file_path}").'.
format(**locals()), # noqa: WPS421
)
return pip_cmd


def run_cmd(cmd):
"""Invoke a shell command after logging it.
:param cmd: The command to invoke.
"""
print_info(
'Invoking the following command: {cmd}'.
format(cmd=' '.join(cmd)),
)
subprocess.check_call(cmd) # noqa: S603


def main(argv):
"""Invoke pip with the matching constraints file, if present.
:param argv: List of command-line arguments.
"""
constraint_file_path = get_constraint_file_path(
req_dir=argv[1],
toxenv=argv[0],
python_tag=get_runtime_python_tag(),
)
pip_cmd = make_pip_cmd(
pip_args=argv[2:],
constraint_file_path=constraint_file_path,
)
run_cmd(pip_cmd)


if __name__ == '__main__':
main(sys.argv[1:])
1 change: 1 addition & 0 deletions requirements/tox-py27-cp27-linux-x86_64.in
202 changes: 202 additions & 0 deletions requirements/tox-py27-cp27-linux-x86_64.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile --allow-unsafe --output-file=requirements/tox-py27-cp27-linux-x86_64.txt requirements/tox-py27-cp27-linux-x86_64.in
#
atomicwrites==1.4.0
# via pytest
attrs==21.2.0
# via pytest
backports.functools-lru-cache==1.6.4
# via
# jaraco.functools
# wcwidth
certifi==2021.10.8
# via requests
cffi==1.15.0
# via cryptography
chardet==4.0.0
# via
# -r requirements/tox-py27-cp27-linux-x86_64.in
# requests
colorama==0.4.4
# via pytest-watch
configparser==4.0.2
# via importlib-metadata
contextlib2==0.6.0.post1
# via
# importlib-metadata
# importlib-resources
# jaraco.context
# yg.lockfile
# zipp
coverage[toml]==5.5 ; python_version < "3.6" and python_version != "3.4"
# via
# -r requirements/tox-py27-cp27-linux-x86_64.in
# pytest-cov
cryptography==3.3.2
# via
# pyopenssl
# trustme
docopt==0.6.2
# via pytest-watch
enum34==1.1.10
# via cryptography
execnet==1.9.0
# via pytest-xdist
funcsigs==1.0.2
# via
# mock
# pytest
futures==3.3.0 ; python_version == "2.7"
# via -r requirements/tox-py27-cp27-linux-x86_64.in
idna==2.10
# via
# requests
# trustme
importlib-metadata==2.1.2
# via
# pluggy
# pytest
importlib-resources==3.3.1
# via jaraco.text
ipaddress==1.0.23
# via
# cryptography
# trustme
jaraco.apt==2.0
# via jaraco.context
jaraco.context==2.0
# via -r requirements/tox-py27-cp27-linux-x86_64.in
jaraco.functools==2.0
# via
# jaraco.text
# tempora
# yg.lockfile
jaraco.text==3.2.0
# via -r requirements/tox-py27-cp27-linux-x86_64.in
mock==3.0.5
# via pytest-mock
more-itertools==5.0.0
# via
# jaraco.functools
# pytest
packaging==20.9
# via
# pytest
# pytest-sugar
pathlib2==2.3.6
# via
# importlib-metadata
# importlib-resources
# pytest
pathtools==0.1.2
# via watchdog
pluggy==0.13.1
# via pytest
portend==2.6
# via -r requirements/tox-py27-cp27-linux-x86_64.in
py==1.11.0
# via
# pypytools
# pytest
# pytest-forked
pycparser==2.21
# via cffi
pyopenssl==21.0.0
# via -r requirements/tox-py27-cp27-linux-x86_64.in
pyparsing==2.4.7
# via packaging
pypytools==0.6.2
# via -r requirements/tox-py27-cp27-linux-x86_64.in
pytest-cov==2.12.0 ; python_version != "3.4"
# via -r requirements/tox-py27-cp27-linux-x86_64.in
pytest-forked==1.3.0 ; sys_platform != "win32" and (python_version < "3.0" or python_version > "3.4")
# via
# -r requirements/tox-py27-cp27-linux-x86_64.in
# pytest-xdist
pytest-mock==2.0.0
# via -r requirements/tox-py27-cp27-linux-x86_64.in
pytest-rerunfailures==8.0 ; python_version <= "2.7"
# via -r requirements/tox-py27-cp27-linux-x86_64.in
pytest-sugar==0.9.4
# via -r requirements/tox-py27-cp27-linux-x86_64.in
pytest-watch==4.2.0
# via -r requirements/tox-py27-cp27-linux-x86_64.in
pytest-xdist==1.34.0
# via -r requirements/tox-py27-cp27-linux-x86_64.in
pytest==4.6.11
# via
# -r requirements/tox-py27-cp27-linux-x86_64.in
# pytest-cov
# pytest-forked
# pytest-mock
# pytest-rerunfailures
# pytest-sugar
# pytest-watch
# pytest-xdist
pytz==2021.3
# via tempora
requests-toolbelt==0.9.1
# via -r requirements/tox-py27-cp27-linux-x86_64.in
requests-unixsocket==0.2.0
# via -r requirements/tox-py27-cp27-linux-x86_64.in
requests==2.26.0
# via
# requests-toolbelt
# requests-unixsocket
scandir==1.10.0
# via pathlib2
singledispatch==3.7.0
# via importlib-resources
six==1.16.0
# via
# cryptography
# jaraco.apt
# jaraco.text
# mock
# more-itertools
# pathlib2
# pyopenssl
# pytest
# pytest-xdist
# singledispatch
# tempora
tempora==1.14.1
# via
# portend
# yg.lockfile
termcolor==1.1.0
# via pytest-sugar
toml==0.10.2
# via coverage
trustme==0.9.0
# via -r requirements/tox-py27-cp27-linux-x86_64.in
typing==3.10.0.0
# via importlib-resources
urllib3==1.26.7 ; python_version != "3.4"
# via
# -r requirements/tox-py27-cp27-linux-x86_64.in
# requests
# requests-unixsocket
watchdog==0.10.7 ; python_version < "3.6"
# via
# -r requirements/tox-py27-cp27-linux-x86_64.in
# pytest-watch
wcwidth==0.2.5
# via pytest
yg.lockfile==2.3
# via jaraco.context
zc.lockfile==2.0
# via yg.lockfile
zipp==1.2.0
# via
# importlib-metadata
# importlib-resources

# The following packages are considered to be unsafe in a requirements file:
setuptools==44.1.1
# via
# pytest-rerunfailures
# zc.lockfile
1 change: 1 addition & 0 deletions requirements/tox-py310-cp310-linux-x86_64.in
Loading

0 comments on commit c30cfa8

Please sign in to comment.