diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index 77285f61..16bd832a 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -103,4 +103,5 @@ class DependencyConstraints(object): return self.base_file_path -get_pip_script = os.path.abspath(os.path.join(os.path.dirname(__file__), 'resources', 'get-pip.py')) +resources_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'resources')) +get_pip_script = os.path.join(resources_dir, 'get-pip.py') diff --git a/test/11_dependency_versions/cibuildwheel_test.py b/test/11_dependency_versions/cibuildwheel_test.py new file mode 100644 index 00000000..a664978f --- /dev/null +++ b/test/11_dependency_versions/cibuildwheel_test.py @@ -0,0 +1,82 @@ +import os +import re +import cibuildwheel.util +import pytest + +import utils + +VERSION_REGEX = r'([\w-]+)==([^\s]+)' + + +def get_version_from_constraint_file(package_name, constraint_file): + version_pattern = package_name + r'==([^\s]+)' + + with open(constraint_file, encoding='utf8') as f: + constraint_file_text = f.read() + + match = re.search(version_pattern, constraint_file_text) + + if not match: + raise Exception("couldn't find version spec matching " + version_pattern) + + return match.group(1) + + +def get_versions_from_constraint_file(python2=False): + if python2: + constraint_filename = 'constraints-python27.txt' + else: + constraint_filename = 'constraints.txt' + + constraint_file = os.path.join(cibuildwheel.util.resources_dir, constraint_filename) + + with open(constraint_file, encoding='utf8') as f: + constraint_file_text = f.read() + + versions = {} + + for line in constraint_file_text.strip().splitlines(): + match = re.match(VERSION_REGEX, line) + if match: + versions[match.group(1)] = match.group(2) + + return versions + + +@pytest.mark.parametrize('python_version', ['2.7', '3.x']) +def test_pinned_versions(python_version): + if utils.platform == 'linux': + pytest.skip('linux doesn\'t pin individual tool versions, it pins manylinux images instead') + + project_dir = os.path.dirname(__file__) + + build_environment = {} + + if python_version == '2.7': + constraint_filename = 'constraints-python27.txt' + else: + constraint_filename = 'constraints.txt' + + constraint_file = os.path.join(cibuildwheel.util.resources_dir, constraint_filename) + + for package in ['pip', 'setuptools', 'wheel', 'virtualenv']: + env_name = 'EXPECTED_{}_VERSION'.format(package.upper()) + build_environment[env_name] = get_version_from_constraint_file(package, constraint_file) + + cibw_environment_option = ' '.join(['{}={}'.format(k, v) for k, v in build_environment.items()]) + cibw_build_option = 'cp27-*' if python_version == '2.7' else 'cp3*' + + # build and test the wheels + actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ + 'CIBW_BUILD': cibw_build_option, + 'CIBW_ENVIRONMENT': cibw_environment_option, + 'CIBW_TEST_REQUIRES': 'pytest', + 'CIBW_TEST_COMMAND': 'pytest {project}/test', + }) + + # also check that we got the right wheels + expected_wheels = utils.expected_wheels('spam', '0.1.0') + assert set(actual_wheels) == set(expected_wheels) + + +# TODO: add a test with a user-specified constraints file diff --git a/test/11_dependency_versions/setup.py b/test/11_dependency_versions/setup.py new file mode 100644 index 00000000..209f45b0 --- /dev/null +++ b/test/11_dependency_versions/setup.py @@ -0,0 +1,10 @@ +from setuptools import ( + Extension, + setup, +) + +setup( + name="spam", + ext_modules=[Extension('spam', sources=['spam.c'])], + version="0.1.0", +) diff --git a/test/11_dependency_versions/spam.c b/test/11_dependency_versions/spam.c new file mode 100644 index 00000000..d1ab0f22 --- /dev/null +++ b/test/11_dependency_versions/spam.c @@ -0,0 +1,48 @@ +#include + +static PyObject * +spam_system(PyObject *self, PyObject *args) +{ + const char *command; + int sts; + + if (!PyArg_ParseTuple(args, "s", &command)) + return NULL; + sts = system(command); + return PyLong_FromLong(sts); +} + +/* Module initialization */ + +#if PY_MAJOR_VERSION >= 3 + #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void) + #define MOD_DEF(m, name, doc, methods, module_state_size) \ + static struct PyModuleDef moduledef = { \ + PyModuleDef_HEAD_INIT, name, doc, module_state_size, methods, }; \ + m = PyModule_Create(&moduledef); + #define MOD_RETURN(m) return m; +#else + #define MOD_INIT(name) PyMODINIT_FUNC init##name(void) + #define MOD_DEF(m, name, doc, methods, module_state_size) \ + m = Py_InitModule3(name, methods, doc); + #define MOD_RETURN(m) return; +#endif + +static PyMethodDef module_methods[] = { + {"system", (PyCFunction)spam_system, METH_VARARGS, + "Execute a shell command."}, + {NULL} /* Sentinel */ +}; + +MOD_INIT(spam) +{ + PyObject* m; + + MOD_DEF(m, + "spam", + "Example module", + module_methods, + -1) + + MOD_RETURN(m) +} diff --git a/test/11_dependency_versions/test/spam_test.py b/test/11_dependency_versions/test/spam_test.py new file mode 100644 index 00000000..58ed31c9 --- /dev/null +++ b/test/11_dependency_versions/test/spam_test.py @@ -0,0 +1,17 @@ +import os +import subprocess + + +def test_expected_pip_version(): + expected_pip_version = os.environ['EXPECTED_PIP_VERSION'] + + versions_output_text = subprocess.check_output( + ['pip', 'freeze', '--all', '-qq'], + universal_newlines=True, + ) + versions = versions_output_text.strip().splitlines() + + # `versions` now looks like: + # ['pip==x.x.x', 'setuptools==x.x.x', 'wheel==x.x.x'] + + assert 'pip=={}'.format(expected_pip_version) in versions