From 4f75eaabcde91251e593f221c23285a172803a48 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 25 Apr 2020 16:09:11 +0100 Subject: [PATCH 01/32] Inprogress refactor trying f-strings as template language --- .travis.yml | 26 ++++++------- test/template_projects/__init__.py | 0 test/template_projects/base.py | 18 +++++++++ test/template_projects/c.py | 60 ++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 13 deletions(-) create mode 100644 test/template_projects/__init__.py create mode 100644 test/template_projects/base.py create mode 100644 test/template_projects/c.py diff --git a/.travis.yml b/.travis.yml index 4bda329c..855b565c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,22 +6,22 @@ branches: jobs: include: - - name: Linux | x86_64 + i686 | Python 3.5 + - name: Linux | x86_64 + i686 | Python 3.6 language: python - python: 3.5 + python: 3.6 services: docker env: PYTHON=python - - name: Linux | arm64 | Python 3.5 + - name: Linux | arm64 | Python 3.6 language: python - python: 3.5 + python: 3.6 services: docker arch: arm64 env: PYTHON=python - - name: Linux | ppc64le | Python 3.5 + - name: Linux | ppc64le | Python 3.6 language: python - python: 3.5 + python: 3.6 services: docker arch: ppc64le env: PYTHON=python @@ -30,25 +30,25 @@ jobs: os: osx env: PYTHON=python3 - - name: Windows | x86_64 | Python 3.5 + - name: Windows | x86_64 | Python 3.6 os: windows language: shell before_install: - - choco install python3 --version 3.5.4 --no-progress -y + - choco install python3 --version 3.6.8 --no-progress -y env: - - PYTHON=C:\\Python35\\python + - PYTHON=C:\\Python36\\python - - &linux_s390x_35 - name: Linux | s390x | Python 3.5 + - &linux_s390x_36 + name: Linux | s390x | Python 3.6 language: python - python: 3.5 + python: 3.6 services: docker arch: s390x env: PYTHON=python allow_failures: # must repeat the s390x job above exactly to match - - *linux_s390x_35 + - *linux_s390x_36 install: $PYTHON -m pip install -r requirements-dev.txt diff --git a/test/template_projects/__init__.py b/test/template_projects/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/template_projects/base.py b/test/template_projects/base.py new file mode 100644 index 00000000..87e57b9a --- /dev/null +++ b/test/template_projects/base.py @@ -0,0 +1,18 @@ +import os +import io +from typing import List, Tuple + + +class TemplateProject: + files: List[Tuple[str, str]] + + def __init__(self, files): + self.files = files + + def generate(self, path): + for filename, content in self.files: + file_path = os.path.join(path, filename) + os.makedirs(os.path.dirname(file_path), exist_ok=True) + + with io.open(file_path, 'w', encoding='utf8') as f: + f.write(content) diff --git a/test/template_projects/c.py b/test/template_projects/c.py new file mode 100644 index 00000000..2f2af1b0 --- /dev/null +++ b/test/template_projects/c.py @@ -0,0 +1,60 @@ +import textwrap + +def indent(str, level): + return str + +def CTemplateProject(TemplateProject): + files = { + 'spam.c': textwrap.dedent(fr''' + #include + + {spam_c_top_level_add} + + static PyObject * + spam_system(PyObject *self, PyObject *args) + {{ + const char *command; + int sts; + if (!PyArg_ParseTuple(args, "s", &command)) + return NULL; + sts = system(command); + {indent(spam_c_function_add, 4)} + 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) + } + ''') + } From c38bc9064a363197d592d5de25099a04b5062b80 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 2 May 2020 09:59:55 +0100 Subject: [PATCH 02/32] Reintroduce jinja2 --- test/template_projects/base.py | 21 ++++++++++++----- test/template_projects/c.py | 41 +++++++++++++++++++++++++--------- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/test/template_projects/base.py b/test/template_projects/base.py index 87e57b9a..33d2f1a0 100644 --- a/test/template_projects/base.py +++ b/test/template_projects/base.py @@ -1,18 +1,29 @@ import os import io -from typing import List, Tuple +import jinja2 +from typing import Union, Dict, Any + + +FilesDict = Dict[str, Union[str, jinja2.Template]] class TemplateProject: - files: List[Tuple[str, str]] + default_files: FilesDict = {} + files: FilesDict + context: Dict[str, Any] - def __init__(self, files): - self.files = files + def __init__(self, *, extra_files: FilesDict): + self.files = self.default_files.copy() + self.files.update(extra_files) + self.context = {} def generate(self, path): - for filename, content in self.files: + for filename, content in self.files.items(): file_path = os.path.join(path, filename) os.makedirs(os.path.dirname(file_path), exist_ok=True) with io.open(file_path, 'w', encoding='utf8') as f: + if isinstance(content, jinja2.Template): + content = content.render(self.context) + f.write(content) diff --git a/test/template_projects/c.py b/test/template_projects/c.py index 2f2af1b0..579e283e 100644 --- a/test/template_projects/c.py +++ b/test/template_projects/c.py @@ -1,26 +1,30 @@ import textwrap +import jinja2 +from .base import TemplateProject -def indent(str, level): - return str -def CTemplateProject(TemplateProject): - files = { - 'spam.c': textwrap.dedent(fr''' +class CTemplateProject(TemplateProject): + default_files = { + 'spam.c': jinja2.Template(textwrap.dedent(r''' #include - {spam_c_top_level_add} + {{ spam_c_top_level_add }} static PyObject * spam_system(PyObject *self, PyObject *args) - {{ + { const char *command; int sts; + if (!PyArg_ParseTuple(args, "s", &command)) return NULL; + sts = system(command); - {indent(spam_c_function_add, 4)} + + {{ spam_c_function_add | indent(4) }} + return PyLong_FromLong(sts); - }} + } /* Module initialization */ @@ -56,5 +60,22 @@ def CTemplateProject(TemplateProject): MOD_RETURN(m) } - ''') + ''')), + 'setup.py': jinja2.Template(textwrap.dedent(r''' + from setuptools import setup, Extension + + {{ setup_py_add }} + + setup( + name="spam", + ext_modules=[Extension("spam", sources=["spam.c"])], + version="0.1.0", + {{ setup_py_setup_args_add | indent(4) }} + ) + ''')) } + + def __init__(self, spam_c_top_level_add, spam_c_function_add, setup_py_add, + setup_py_setup_args_add, extra_files): + super().__init__(extra_files) + self.context = {} From 616e9dd6ebb9839b94d1c9dfd5ac42b79cd01299 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 2 May 2020 16:54:19 +0100 Subject: [PATCH 03/32] Converting tests to the new-style --- test/11_before_test/cibuildwheel_test.py | 23 --- test/__init__.py | 0 test/conftest.py | 4 - test/{ => old}/01_basic/cibuildwheel_test.py | 9 ++ test/{ => old}/01_basic/setup.py | 0 test/{ => old}/01_basic/spam.c | 0 test/{ => old}/02_test/cibuildwheel_test.py | 0 test/{ => old}/02_test/setup.py | 0 test/{ => old}/02_test/spam.c | 0 test/{ => old}/02_test/test/spam_test.py | 0 .../03_before_build/cibuildwheel_test.py | 0 test/{ => old}/03_before_build/setup.py | 0 test/{ => old}/03_before_build/spam.c | 0 .../04_build_skip/cibuildwheel_test.py | 0 test/{ => old}/04_build_skip/setup.py | 0 test/{ => old}/04_build_skip/spam.c | 0 .../05_environment/cibuildwheel_test.py | 0 test/{ => old}/05_environment/setup.py | 0 test/{ => old}/05_environment/spam.c | 0 .../06_docker_images/cibuildwheel_test.py | 0 test/{ => old}/06_docker_images/setup.py | 0 test/{ => old}/06_docker_images/spam.c | 0 test/{ => old}/07_ssl/cibuildwheel_test.py | 0 test/{ => old}/07_ssl/setup.py | 0 test/{ => old}/07_ssl/spam.c | 0 .../cibuildwheel_test.py | 0 test/{ => old}/08_manylinuxXXXX_only/setup.py | 0 test/{ => old}/08_manylinuxXXXX_only/spam.c | 0 .../09_setup_cfg/cibuildwheel_test.py | 0 test/{ => old}/09_setup_cfg/setup.cfg | 0 test/{ => old}/09_setup_cfg/setup.py | 0 test/{ => old}/09_setup_cfg/spam/__init__.py | 0 test/{ => old}/09_setup_cfg/spam/spam.c | 0 .../10_cpp_standards/cibuildwheel_test.py | 0 test/{ => old}/10_cpp_standards/setup.py | 0 test/{ => old}/10_cpp_standards/spam.cpp | 0 test/{ => old}/11_before_test/setup.py | 0 test/{ => old}/11_before_test/spam.c | 0 .../11_before_test/test/spam_test.py | 0 .../{ => old}/12_dependency_versions/setup.py | 0 test/{ => old}/12_dependency_versions/spam.c | 0 .../13_subdir_package/bin/before_build.py | 0 .../13_subdir_package/cibuildwheel_test.py | 0 .../13_subdir_package/src/spam/setup.py | 0 .../13_subdir_package/src/spam/spam.c | 0 .../src/spam/test/run_tests.py | 0 test/template_projects/__init__.py | 3 + test/template_projects/base.py | 17 +- test/template_projects/c.py | 128 +++++++-------- test/template_projects/setuptools.py | 38 +++++ test/test_01_basic.py | 42 +++++ test/test_02_testing.py | 75 +++++++++ test/test_03_before_build.py | 55 +++++++ test/test_04_build_skip.py | 31 ++++ test/test_05_environment.py | 44 +++++ test/test_06_docker_images.py | 42 +++++ test/test_07_ssl.py | 30 ++++ test/test_08_manylinuxXXXX_only.py | 67 ++++++++ test/test_09_cpp_standards.py | 150 ++++++++++++++++++ test/test_10_before_test.py | 56 +++++++ ...test.py => test_11_dependency_versions.py} | 39 ++++- test/{shared => }/utils.py | 0 62 files changed, 750 insertions(+), 103 deletions(-) delete mode 100644 test/11_before_test/cibuildwheel_test.py create mode 100644 test/__init__.py delete mode 100644 test/conftest.py rename test/{ => old}/01_basic/cibuildwheel_test.py (80%) rename test/{ => old}/01_basic/setup.py (100%) rename test/{ => old}/01_basic/spam.c (100%) rename test/{ => old}/02_test/cibuildwheel_test.py (100%) rename test/{ => old}/02_test/setup.py (100%) rename test/{ => old}/02_test/spam.c (100%) rename test/{ => old}/02_test/test/spam_test.py (100%) rename test/{ => old}/03_before_build/cibuildwheel_test.py (100%) rename test/{ => old}/03_before_build/setup.py (100%) rename test/{ => old}/03_before_build/spam.c (100%) rename test/{ => old}/04_build_skip/cibuildwheel_test.py (100%) rename test/{ => old}/04_build_skip/setup.py (100%) rename test/{ => old}/04_build_skip/spam.c (100%) rename test/{ => old}/05_environment/cibuildwheel_test.py (100%) rename test/{ => old}/05_environment/setup.py (100%) rename test/{ => old}/05_environment/spam.c (100%) rename test/{ => old}/06_docker_images/cibuildwheel_test.py (100%) rename test/{ => old}/06_docker_images/setup.py (100%) rename test/{ => old}/06_docker_images/spam.c (100%) rename test/{ => old}/07_ssl/cibuildwheel_test.py (100%) rename test/{ => old}/07_ssl/setup.py (100%) rename test/{ => old}/07_ssl/spam.c (100%) rename test/{ => old}/08_manylinuxXXXX_only/cibuildwheel_test.py (100%) rename test/{ => old}/08_manylinuxXXXX_only/setup.py (100%) rename test/{ => old}/08_manylinuxXXXX_only/spam.c (100%) rename test/{ => old}/09_setup_cfg/cibuildwheel_test.py (100%) rename test/{ => old}/09_setup_cfg/setup.cfg (100%) rename test/{ => old}/09_setup_cfg/setup.py (100%) rename test/{ => old}/09_setup_cfg/spam/__init__.py (100%) rename test/{ => old}/09_setup_cfg/spam/spam.c (100%) rename test/{ => old}/10_cpp_standards/cibuildwheel_test.py (100%) rename test/{ => old}/10_cpp_standards/setup.py (100%) rename test/{ => old}/10_cpp_standards/spam.cpp (100%) rename test/{ => old}/11_before_test/setup.py (100%) rename test/{ => old}/11_before_test/spam.c (100%) rename test/{ => old}/11_before_test/test/spam_test.py (100%) rename test/{ => old}/12_dependency_versions/setup.py (100%) rename test/{ => old}/12_dependency_versions/spam.c (100%) rename test/{ => old}/13_subdir_package/bin/before_build.py (100%) rename test/{ => old}/13_subdir_package/cibuildwheel_test.py (100%) rename test/{ => old}/13_subdir_package/src/spam/setup.py (100%) rename test/{ => old}/13_subdir_package/src/spam/spam.c (100%) rename test/{ => old}/13_subdir_package/src/spam/test/run_tests.py (100%) create mode 100644 test/template_projects/setuptools.py create mode 100644 test/test_01_basic.py create mode 100644 test/test_02_testing.py create mode 100644 test/test_03_before_build.py create mode 100644 test/test_04_build_skip.py create mode 100644 test/test_05_environment.py create mode 100644 test/test_06_docker_images.py create mode 100644 test/test_07_ssl.py create mode 100644 test/test_08_manylinuxXXXX_only.py create mode 100644 test/test_09_cpp_standards.py create mode 100644 test/test_10_before_test.py rename test/{12_dependency_versions/cibuildwheel_test.py => test_11_dependency_versions.py} (77%) rename test/{shared => }/utils.py (100%) diff --git a/test/11_before_test/cibuildwheel_test.py b/test/11_before_test/cibuildwheel_test.py deleted file mode 100644 index 5aa1c4ca..00000000 --- a/test/11_before_test/cibuildwheel_test.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import utils - - -def test(): - project_dir = os.path.dirname(__file__) - - # build the wheels - actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ - # write python version information to a temporary file, this is - # checked in setup.py - 'CIBW_BEFORE_TEST': '''python -c "import sys; open('/tmp/pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonprefix.txt', 'w').write(sys.prefix)"''', - 'CIBW_BEFORE_TEST_WINDOWS': '''python -c "import sys; open('c:\\pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonprefix.txt', 'w').write(sys.prefix)"''', - 'CIBW_TEST_REQUIRES': 'nose', - # the 'false ||' bit is to ensure this command runs in a shell on - # mac/linux. - 'CIBW_TEST_COMMAND': 'false || nosetests {project}/test', - 'CIBW_TEST_COMMAND_WINDOWS': 'nosetests {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) diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/conftest.py b/test/conftest.py deleted file mode 100644 index d89278e8..00000000 --- a/test/conftest.py +++ /dev/null @@ -1,4 +0,0 @@ -import os -import sys - -sys.path.append(os.path.join(os.path.dirname(__file__), 'shared')) diff --git a/test/01_basic/cibuildwheel_test.py b/test/old/01_basic/cibuildwheel_test.py similarity index 80% rename from test/01_basic/cibuildwheel_test.py rename to test/old/01_basic/cibuildwheel_test.py index 51875a8a..d8deee4f 100644 --- a/test/01_basic/cibuildwheel_test.py +++ b/test/old/01_basic/cibuildwheel_test.py @@ -1,10 +1,19 @@ import os import platform +import textwrap import utils project_dir = os.path.dirname(__file__) +project_spec = TemplateProjectC( + setup_py_add=textwrap.dedent(''' + import os + if os.environ.get("CIBUILDWHEEL", "0") != "1": + raise Exception("CIBUILDWHEEL environment variable is not set to 1") + ''') +) + def test(): # build the wheels diff --git a/test/01_basic/setup.py b/test/old/01_basic/setup.py similarity index 100% rename from test/01_basic/setup.py rename to test/old/01_basic/setup.py diff --git a/test/01_basic/spam.c b/test/old/01_basic/spam.c similarity index 100% rename from test/01_basic/spam.c rename to test/old/01_basic/spam.c diff --git a/test/02_test/cibuildwheel_test.py b/test/old/02_test/cibuildwheel_test.py similarity index 100% rename from test/02_test/cibuildwheel_test.py rename to test/old/02_test/cibuildwheel_test.py diff --git a/test/02_test/setup.py b/test/old/02_test/setup.py similarity index 100% rename from test/02_test/setup.py rename to test/old/02_test/setup.py diff --git a/test/02_test/spam.c b/test/old/02_test/spam.c similarity index 100% rename from test/02_test/spam.c rename to test/old/02_test/spam.c diff --git a/test/02_test/test/spam_test.py b/test/old/02_test/test/spam_test.py similarity index 100% rename from test/02_test/test/spam_test.py rename to test/old/02_test/test/spam_test.py diff --git a/test/03_before_build/cibuildwheel_test.py b/test/old/03_before_build/cibuildwheel_test.py similarity index 100% rename from test/03_before_build/cibuildwheel_test.py rename to test/old/03_before_build/cibuildwheel_test.py diff --git a/test/03_before_build/setup.py b/test/old/03_before_build/setup.py similarity index 100% rename from test/03_before_build/setup.py rename to test/old/03_before_build/setup.py diff --git a/test/03_before_build/spam.c b/test/old/03_before_build/spam.c similarity index 100% rename from test/03_before_build/spam.c rename to test/old/03_before_build/spam.c diff --git a/test/04_build_skip/cibuildwheel_test.py b/test/old/04_build_skip/cibuildwheel_test.py similarity index 100% rename from test/04_build_skip/cibuildwheel_test.py rename to test/old/04_build_skip/cibuildwheel_test.py diff --git a/test/04_build_skip/setup.py b/test/old/04_build_skip/setup.py similarity index 100% rename from test/04_build_skip/setup.py rename to test/old/04_build_skip/setup.py diff --git a/test/04_build_skip/spam.c b/test/old/04_build_skip/spam.c similarity index 100% rename from test/04_build_skip/spam.c rename to test/old/04_build_skip/spam.c diff --git a/test/05_environment/cibuildwheel_test.py b/test/old/05_environment/cibuildwheel_test.py similarity index 100% rename from test/05_environment/cibuildwheel_test.py rename to test/old/05_environment/cibuildwheel_test.py diff --git a/test/05_environment/setup.py b/test/old/05_environment/setup.py similarity index 100% rename from test/05_environment/setup.py rename to test/old/05_environment/setup.py diff --git a/test/05_environment/spam.c b/test/old/05_environment/spam.c similarity index 100% rename from test/05_environment/spam.c rename to test/old/05_environment/spam.c diff --git a/test/06_docker_images/cibuildwheel_test.py b/test/old/06_docker_images/cibuildwheel_test.py similarity index 100% rename from test/06_docker_images/cibuildwheel_test.py rename to test/old/06_docker_images/cibuildwheel_test.py diff --git a/test/06_docker_images/setup.py b/test/old/06_docker_images/setup.py similarity index 100% rename from test/06_docker_images/setup.py rename to test/old/06_docker_images/setup.py diff --git a/test/06_docker_images/spam.c b/test/old/06_docker_images/spam.c similarity index 100% rename from test/06_docker_images/spam.c rename to test/old/06_docker_images/spam.c diff --git a/test/07_ssl/cibuildwheel_test.py b/test/old/07_ssl/cibuildwheel_test.py similarity index 100% rename from test/07_ssl/cibuildwheel_test.py rename to test/old/07_ssl/cibuildwheel_test.py diff --git a/test/07_ssl/setup.py b/test/old/07_ssl/setup.py similarity index 100% rename from test/07_ssl/setup.py rename to test/old/07_ssl/setup.py diff --git a/test/07_ssl/spam.c b/test/old/07_ssl/spam.c similarity index 100% rename from test/07_ssl/spam.c rename to test/old/07_ssl/spam.c diff --git a/test/08_manylinuxXXXX_only/cibuildwheel_test.py b/test/old/08_manylinuxXXXX_only/cibuildwheel_test.py similarity index 100% rename from test/08_manylinuxXXXX_only/cibuildwheel_test.py rename to test/old/08_manylinuxXXXX_only/cibuildwheel_test.py diff --git a/test/08_manylinuxXXXX_only/setup.py b/test/old/08_manylinuxXXXX_only/setup.py similarity index 100% rename from test/08_manylinuxXXXX_only/setup.py rename to test/old/08_manylinuxXXXX_only/setup.py diff --git a/test/08_manylinuxXXXX_only/spam.c b/test/old/08_manylinuxXXXX_only/spam.c similarity index 100% rename from test/08_manylinuxXXXX_only/spam.c rename to test/old/08_manylinuxXXXX_only/spam.c diff --git a/test/09_setup_cfg/cibuildwheel_test.py b/test/old/09_setup_cfg/cibuildwheel_test.py similarity index 100% rename from test/09_setup_cfg/cibuildwheel_test.py rename to test/old/09_setup_cfg/cibuildwheel_test.py diff --git a/test/09_setup_cfg/setup.cfg b/test/old/09_setup_cfg/setup.cfg similarity index 100% rename from test/09_setup_cfg/setup.cfg rename to test/old/09_setup_cfg/setup.cfg diff --git a/test/09_setup_cfg/setup.py b/test/old/09_setup_cfg/setup.py similarity index 100% rename from test/09_setup_cfg/setup.py rename to test/old/09_setup_cfg/setup.py diff --git a/test/09_setup_cfg/spam/__init__.py b/test/old/09_setup_cfg/spam/__init__.py similarity index 100% rename from test/09_setup_cfg/spam/__init__.py rename to test/old/09_setup_cfg/spam/__init__.py diff --git a/test/09_setup_cfg/spam/spam.c b/test/old/09_setup_cfg/spam/spam.c similarity index 100% rename from test/09_setup_cfg/spam/spam.c rename to test/old/09_setup_cfg/spam/spam.c diff --git a/test/10_cpp_standards/cibuildwheel_test.py b/test/old/10_cpp_standards/cibuildwheel_test.py similarity index 100% rename from test/10_cpp_standards/cibuildwheel_test.py rename to test/old/10_cpp_standards/cibuildwheel_test.py diff --git a/test/10_cpp_standards/setup.py b/test/old/10_cpp_standards/setup.py similarity index 100% rename from test/10_cpp_standards/setup.py rename to test/old/10_cpp_standards/setup.py diff --git a/test/10_cpp_standards/spam.cpp b/test/old/10_cpp_standards/spam.cpp similarity index 100% rename from test/10_cpp_standards/spam.cpp rename to test/old/10_cpp_standards/spam.cpp diff --git a/test/11_before_test/setup.py b/test/old/11_before_test/setup.py similarity index 100% rename from test/11_before_test/setup.py rename to test/old/11_before_test/setup.py diff --git a/test/11_before_test/spam.c b/test/old/11_before_test/spam.c similarity index 100% rename from test/11_before_test/spam.c rename to test/old/11_before_test/spam.c diff --git a/test/11_before_test/test/spam_test.py b/test/old/11_before_test/test/spam_test.py similarity index 100% rename from test/11_before_test/test/spam_test.py rename to test/old/11_before_test/test/spam_test.py diff --git a/test/12_dependency_versions/setup.py b/test/old/12_dependency_versions/setup.py similarity index 100% rename from test/12_dependency_versions/setup.py rename to test/old/12_dependency_versions/setup.py diff --git a/test/12_dependency_versions/spam.c b/test/old/12_dependency_versions/spam.c similarity index 100% rename from test/12_dependency_versions/spam.c rename to test/old/12_dependency_versions/spam.c diff --git a/test/13_subdir_package/bin/before_build.py b/test/old/13_subdir_package/bin/before_build.py similarity index 100% rename from test/13_subdir_package/bin/before_build.py rename to test/old/13_subdir_package/bin/before_build.py diff --git a/test/13_subdir_package/cibuildwheel_test.py b/test/old/13_subdir_package/cibuildwheel_test.py similarity index 100% rename from test/13_subdir_package/cibuildwheel_test.py rename to test/old/13_subdir_package/cibuildwheel_test.py diff --git a/test/13_subdir_package/src/spam/setup.py b/test/old/13_subdir_package/src/spam/setup.py similarity index 100% rename from test/13_subdir_package/src/spam/setup.py rename to test/old/13_subdir_package/src/spam/setup.py diff --git a/test/13_subdir_package/src/spam/spam.c b/test/old/13_subdir_package/src/spam/spam.c similarity index 100% rename from test/13_subdir_package/src/spam/spam.c rename to test/old/13_subdir_package/src/spam/spam.c diff --git a/test/13_subdir_package/src/spam/test/run_tests.py b/test/old/13_subdir_package/src/spam/test/run_tests.py similarity index 100% rename from test/13_subdir_package/src/spam/test/run_tests.py rename to test/old/13_subdir_package/src/spam/test/run_tests.py diff --git a/test/template_projects/__init__.py b/test/template_projects/__init__.py index e69de29b..d9346449 100644 --- a/test/template_projects/__init__.py +++ b/test/template_projects/__init__.py @@ -0,0 +1,3 @@ +from .base import TemplateProject # noqa +from .c import CTemplateProject # noqa +from .setuptools import SetuptoolsTemplateProject # noqa diff --git a/test/template_projects/base.py b/test/template_projects/base.py index 33d2f1a0..7882e73a 100644 --- a/test/template_projects/base.py +++ b/test/template_projects/base.py @@ -1,29 +1,28 @@ import os import io import jinja2 -from typing import Union, Dict, Any +from typing import Union, Dict, Any, Optional FilesDict = Dict[str, Union[str, jinja2.Template]] +TemplateContext = Dict[str, Any] class TemplateProject: - default_files: FilesDict = {} files: FilesDict - context: Dict[str, Any] + template_context: TemplateContext - def __init__(self, *, extra_files: FilesDict): - self.files = self.default_files.copy() - self.files.update(extra_files) - self.context = {} + def __init__(self): + self.files = {} + self.template_context = {} - def generate(self, path): + def generate(self, path: str): for filename, content in self.files.items(): file_path = os.path.join(path, filename) os.makedirs(os.path.dirname(file_path), exist_ok=True) with io.open(file_path, 'w', encoding='utf8') as f: if isinstance(content, jinja2.Template): - content = content.render(self.context) + content = content.render(self.template_context) f.write(content) diff --git a/test/template_projects/c.py b/test/template_projects/c.py index 579e283e..e1a24ca7 100644 --- a/test/template_projects/c.py +++ b/test/template_projects/c.py @@ -1,81 +1,83 @@ -import textwrap import jinja2 -from .base import TemplateProject +from .setuptools import SetuptoolsTemplateProject -class CTemplateProject(TemplateProject): - default_files = { - 'spam.c': jinja2.Template(textwrap.dedent(r''' - #include +spam_c_template = r''' +#include - {{ spam_c_top_level_add }} +{{ spam_c_top_level_add }} - static PyObject * - spam_system(PyObject *self, PyObject *args) - { - const char *command; - int sts; +static PyObject * +spam_system(PyObject *self, PyObject *args) +{ + const char *command; + int sts; - if (!PyArg_ParseTuple(args, "s", &command)) - return NULL; + if (!PyArg_ParseTuple(args, "s", &command)) + return NULL; - sts = system(command); + sts = system(command); - {{ spam_c_function_add | indent(4) }} + {{ spam_c_function_add | indent(4) }} - return PyLong_FromLong(sts); - } + return PyLong_FromLong(sts); +} - /* Module initialization */ +/* 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 +#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 */ - }; +static PyMethodDef module_methods[] = { + {"system", (PyCFunction)spam_system, METH_VARARGS, + "Execute a shell command."}, + {NULL} /* Sentinel */ +}; - MOD_INIT(spam) - { - PyObject* m; +MOD_INIT(spam) +{ + PyObject* m; - MOD_DEF(m, - "spam", - "Example module", - module_methods, - -1) + MOD_DEF(m, + "spam", + "Example module", + module_methods, + -1) - MOD_RETURN(m) - } - ''')), - 'setup.py': jinja2.Template(textwrap.dedent(r''' - from setuptools import setup, Extension + MOD_RETURN(m) +} +''' - {{ setup_py_add }} - setup( - name="spam", - ext_modules=[Extension("spam", sources=["spam.c"])], - version="0.1.0", - {{ setup_py_setup_args_add | indent(4) }} - ) - ''')) - } +class CTemplateProject(SetuptoolsTemplateProject): + def __init__(self, *, spam_c_top_level_add='', spam_c_function_add='', setup_py_add='', + setup_py_setup_args_add='', setup_cfg_add=''): + setup_py_setup_args_add += ''' + ext_modules=[Extension('spam', sources=['spam.c'])], + ''' - def __init__(self, spam_c_top_level_add, spam_c_function_add, setup_py_add, - setup_py_setup_args_add, extra_files): - super().__init__(extra_files) - self.context = {} + super().__init__( + setup_py_add=setup_py_add, + setup_py_setup_args_add=setup_py_setup_args_add, + setup_cfg_add=setup_cfg_add + ) + + self.files.update({ + 'spam.c': jinja2.Template(spam_c_template), + }) + + self.template_context.update({ + 'spam_c_top_level_add': spam_c_top_level_add, + 'spam_c_function_add': spam_c_function_add, + }) diff --git a/test/template_projects/setuptools.py b/test/template_projects/setuptools.py new file mode 100644 index 00000000..6dcbfe23 --- /dev/null +++ b/test/template_projects/setuptools.py @@ -0,0 +1,38 @@ + +import jinja2 +from .base import TemplateProject + + +setup_py_template = r''' +from setuptools import setup, Extension + +{{ setup_py_add }} + +setup( + {{ setup_py_setup_args_add | indent(4) }} +) +''' + +setup_cfg_template = r''' +[metadata] +name = spam +version = 0.1.0 + +{{ setup_cfg_add }} +''' + + +class SetuptoolsTemplateProject(TemplateProject): + def __init__(self, *, setup_py_add='', setup_py_setup_args_add='', setup_cfg_add=''): + super().__init__() + + self.files.update({ + 'setup.py': jinja2.Template(setup_py_template), + 'setup.cfg': jinja2.Template(setup_cfg_template), + }) + + self.template_context.update({ + 'setup_py_add': setup_py_add, + 'setup_py_setup_args_add': setup_py_setup_args_add, + 'setup_cfg_add': setup_cfg_add, + }) diff --git a/test/test_01_basic.py b/test/test_01_basic.py new file mode 100644 index 00000000..600e3416 --- /dev/null +++ b/test/test_01_basic.py @@ -0,0 +1,42 @@ +import os +import textwrap +from .template_projects import CTemplateProject +from . import utils + +basic_project = CTemplateProject( + setup_py_add=textwrap.dedent(''' + import os + + if os.environ.get("CIBUILDWHEEL", "0") != "1": + raise Exception("CIBUILDWHEEL environment variable is not set to 1") + ''') +) + +def test(tmpdir): + project_dir = str(tmpdir) + basic_project.generate(project_dir) + + # build the wheels + actual_wheels = utils.cibuildwheel_run(project_dir) + + # check that the expected wheels are produced + expected_wheels = utils.expected_wheels("spam", "0.1.0") + assert set(actual_wheels) == set(expected_wheels) + + +def test_build_identifiers(tmpdir): + project_dir = str(tmpdir) + basic_project.generate(project_dir) + + # check that the number of expected wheels matches the number of build + # identifiers + # after adding CIBW_MANYLINUX_IMAGE to support manylinux2010, there + # can be multiple wheels for each wheel, though, so we need to limit + # the expected wheels + expected_wheels = [ + w + for w in utils.expected_wheels("spam", "0.1.0") + if not "-manylinux" in w or "-manylinux1" in w + ] + build_identifiers = utils.cibuildwheel_get_build_identifiers(project_dir) + assert len(expected_wheels) == len(build_identifiers) diff --git a/test/test_02_testing.py b/test/test_02_testing.py new file mode 100644 index 00000000..df2f51be --- /dev/null +++ b/test/test_02_testing.py @@ -0,0 +1,75 @@ +import os, subprocess +import pytest, textwrap +from . import utils +from .template_projects import CTemplateProject + +project_with_a_test = CTemplateProject() + +project_with_a_test.files['test/spam_test.py'] = r''' +from unittest import TestCase +import spam + +class TestSpam(TestCase): + def test_system(self): + self.assertEqual(0, spam.system('python -c "exit(0)"')) + self.assertNotEqual(0, spam.system('python -c "exit(1)"')) +''' + + +def test(tmpdir): + project_dir = str(tmpdir) + project_with_a_test.generate(project_dir) + + # build and test the wheels + actual_wheels = utils.cibuildwheel_run( + project_dir, + add_env={ + "CIBW_TEST_REQUIRES": "nose", + # the 'false ||' bit is to ensure this command runs in a shell on + # mac/linux. + "CIBW_TEST_COMMAND": "false || nosetests {project}/test", + "CIBW_TEST_COMMAND_WINDOWS": "nosetests {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) + + +def test_extras_require(tmpdir): + project_dir = str(tmpdir) + project_with_a_test.generate(project_dir) + + # build and test the wheels + actual_wheels = utils.cibuildwheel_run( + project_dir, + add_env={ + "CIBW_TEST_EXTRAS": "test", + "CIBW_TEST_COMMAND": "nosetests {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) + + +def test_failing_test(tmpdir): + """Ensure a failing test causes cibuildwheel to error out and exit""" + project_dir = str(tmpdir) + project_with_a_test.generate(project_dir) + + with pytest.raises(subprocess.CalledProcessError): + utils.cibuildwheel_run( + project_dir, + add_env={ + "CIBW_TEST_COMMAND": "false", + # manylinux1 has a version of bash that's been shown to have + # problems with this, so let's check that. + "CIBW_MANYLINUX_I686_IMAGE": "manylinux1", + "CIBW_MANYLINUX_X86_64_IMAGE": "manylinux1", + }, + ) + + assert len(os.listdir("wheelhouse")) diff --git a/test/test_03_before_build.py b/test/test_03_before_build.py new file mode 100644 index 00000000..69b4ff20 --- /dev/null +++ b/test/test_03_before_build.py @@ -0,0 +1,55 @@ +import os, textwrap +from . import utils +from .template_projects import CTemplateProject + + +project_with_before_build_asserts = CTemplateProject( + setup_py_add=textwrap.dedent(r''' + import sys, os + + # assert that the Python version as written to pythonversion.txt in the CIBW_BEFORE_BUILD step + # is the same one as is currently running. + version_file = ( + "c:\\pythonversion.txt" if sys.platform == "win32" else "/tmp/pythonversion.txt" + ) + with open(version_file) as f: + stored_version = f.read() + print("stored_version", stored_version) + print("sys.version", sys.version) + assert stored_version == sys.version + + # check that the executable also was written + executable_file = ( + "c:\\pythonexecutable.txt" if sys.platform == "win32" else "/tmp/pythonexecutable.txt" + ) + with open(executable_file) as f: + stored_executable = f.read() + print("stored_executable", stored_executable) + print("sys.executable", sys.executable) + # windows/mac are case insensitive + assert ( + os.path.realpath(stored_executable).lower() + == os.path.realpath(sys.executable).lower() + ) + ''') +) + + +def test(tmpdir): + project_dir = str(tmpdir) + project_with_before_build_asserts.generate(project_dir) + + # build the wheels + actual_wheels = utils.cibuildwheel_run( + project_dir, + add_env={ + # write python version information to a temporary file, this is + # checked in setup.py + "CIBW_BEFORE_BUILD": '''python -c "import sys; open('/tmp/pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonexecutable.txt', 'w').write(sys.executable)"''', + "CIBW_BEFORE_BUILD_WINDOWS": '''python -c "import sys; open('c:\\pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonexecutable.txt', 'w').write(sys.executable)"''', + }, + ) + + # also check that we got the right wheels + expected_wheels = utils.expected_wheels("spam", "0.1.0") + assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_04_build_skip.py b/test/test_04_build_skip.py new file mode 100644 index 00000000..0505f20d --- /dev/null +++ b/test/test_04_build_skip.py @@ -0,0 +1,31 @@ +import os, textwrap +from . import utils +from .template_projects import CTemplateProject + + +project_with_skip_asserts = CTemplateProject( + setup_py_add=textwrap.dedent(r''' + # explode if run on Python 2.7 or Python 3.4 (these should be skipped) + if sys.version_info[0:2] == (2, 7): + raise Exception("Python 2.7 should not be built") + if sys.version_info[0:2] == (3, 4): + raise Exception("Python 3.4 should be skipped") + ''') +) + +def test(tmpdir): + project_dir = str(tmpdir) + project_with_skip_asserts.generate(project_dir) + + # build the wheels + actual_wheels = utils.cibuildwheel_run( + project_dir, add_env={"CIBW_BUILD": "cp3?-*", "CIBW_SKIP": "cp37-*",} + ) + + # check that we got the right wheels. There should be no 2.7 or 3.7. + expected_wheels = [ + w + for w in utils.expected_wheels("spam", "0.1.0") + if ("-cp3" in w) and ("-cp37" not in w) + ] + assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_05_environment.py b/test/test_05_environment.py new file mode 100644 index 00000000..1e6f25b5 --- /dev/null +++ b/test/test_05_environment.py @@ -0,0 +1,44 @@ +import os, inspect, textwrap +from . import utils +from .template_projects import CTemplateProject + + +project_with_environment_asserts = CTemplateProject( + setup_py_add=textwrap.dedent(r''' + import os + + # explode if environment isn't correct, as set in CIBW_ENVIRONMENT + CIBW_TEST_VAR = os.environ.get("CIBW_TEST_VAR") + CIBW_TEST_VAR_2 = os.environ.get("CIBW_TEST_VAR_2") + PATH = os.environ.get("PATH") + + if CIBW_TEST_VAR != "a b c": + raise Exception('CIBW_TEST_VAR should equal "a b c". It was "%s"' % CIBW_TEST_VAR) + if CIBW_TEST_VAR_2 != "1": + raise Exception('CIBW_TEST_VAR_2 should equal "1". It was "%s"' % CIBW_TEST_VAR_2) + if "/opt/cibw_test_path" not in PATH: + raise Exception('PATH should contain "/opt/cibw_test_path". It was "%s"' % PATH) + if "$PATH" in PATH: + raise Exception('$PATH should be expanded in PATH. It was "%s"' % PATH) + ''') +) + + +def test(tmpdir): + project_dir = str(tmpdir) + project_with_environment_asserts.generate(project_dir) + + # write some information into the CIBW_ENVIRONMENT, for expansion and + # insertion into the environment by cibuildwheel. This is checked + # in setup_py_add + actual_wheels = utils.cibuildwheel_run( + project_dir, + add_env={ + "CIBW_ENVIRONMENT": """CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH=$PATH:/opt/cibw_test_path""", + "CIBW_ENVIRONMENT_WINDOWS": '''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH="$PATH;/opt/cibw_test_path"''', + }, + ) + + # also check that we got the right wheels built + expected_wheels = utils.expected_wheels("spam", "0.1.0") + assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_06_docker_images.py b/test/test_06_docker_images.py new file mode 100644 index 00000000..57a487d3 --- /dev/null +++ b/test/test_06_docker_images.py @@ -0,0 +1,42 @@ +import os, pytest, textwrap +from . import utils +from .template_projects import CTemplateProject + + +dockcross_only_project = CTemplateProject( + setup_py_add=textwrap.dedent(r''' + import os, sys + + # check that we're running in the correct docker image as specified in the + # environment options CIBW_MANYLINUX1_*_IMAGE + if "linux" in sys.platform and not os.path.exists("/dockcross"): + raise Exception( + "/dockcross directory not found. Is this test running in the correct docker image?" + ) + ''') +) + +def test(tmpdir): + if utils.platform != "linux": + pytest.skip("the test is only relevant to the linux build") + + project_dir = str(tmpdir) + dockcross_only_project.generate(project_dir) + + actual_wheels = utils.cibuildwheel_run( + project_dir, + add_env={ + "CIBW_MANYLINUX_X86_64_IMAGE": "dockcross/manylinux2010-x64", + "CIBW_MANYLINUX_I686_IMAGE": "dockcross/manylinux1-x86", + "CIBW_BEFORE_BUILD": "/opt/python/cp36-cp36m/bin/pip install -U auditwheel", # Currently necessary on dockcross images to get auditwheel 2.1 supporting AUDITWHEEL_PLAT + "CIBW_ENVIRONMENT": 'AUDITWHEEL_PLAT=`if [ $(uname -i) == "x86_64" ]; then echo "manylinux2010_x86_64"; else echo "manylinux1_i686"; fi`', + }, + ) + + # also check that we got the right wheels built + expected_wheels = [ + w + for w in utils.expected_wheels("spam", "0.1.0") + if "-manylinux2010_i686" not in w + ] + assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_07_ssl.py b/test/test_07_ssl.py new file mode 100644 index 00000000..18440d3e --- /dev/null +++ b/test/test_07_ssl.py @@ -0,0 +1,30 @@ +import os, textwrap +from . import utils +from .template_projects import CTemplateProject + + +project_with_ssl_tests = CTemplateProject( + setup_py_add=textwrap.dedent(r''' + import ssl + import sys + + if sys.version_info[0] == 2: + from urllib2 import urlopen + else: + from urllib.request import urlopen + + if sys.version_info[0:2] == (3, 3): + data = urlopen("https://www.nist.gov") + else: + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + data = urlopen("https://www.nist.gov", context=context) + ''') +) + +def test(tmpdir): + # this test checks that SSL is working in the build environment using + # some checks in setup.py. + project_dir = str(tmpdir) + project_with_ssl_tests.generate(project_dir) + + utils.cibuildwheel_run(project_dir) diff --git a/test/test_08_manylinuxXXXX_only.py b/test/test_08_manylinuxXXXX_only.py new file mode 100644 index 00000000..07db23eb --- /dev/null +++ b/test/test_08_manylinuxXXXX_only.py @@ -0,0 +1,67 @@ +import os, pytest, textwrap, platform +from . import utils +from .template_projects import CTemplateProject + +# TODO: specify these at runtime according to manylinux_image +project_with_manylinux_symbols = CTemplateProject( + spam_c_top_level_add=textwrap.dedent(r''' + #include + + #if !defined(__GLIBC_PREREQ) + #error "Must run on a glibc linux environment" + #endif + + #if !__GLIBC_PREREQ(2, 5) /* manylinux1 is glibc 2.5 */ + #error "Must run on a glibc >= 2.5 linux environment" + #endif + '''), + spam_c_function_add=textwrap.dedent(r''' + #if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 17) /* manylinux2014 is glibc 2.17 */ + // secure_getenv is only available in manylinux2014, ensuring + // that only a manylinux2014 wheel is produced + secure_getenv("NON_EXISTING_ENV_VARIABLE"); + #elif defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 10) /* manylinux2010 is glibc 2.12 */ + // malloc_info is only available on manylinux2010+ + malloc_info(0, stdout); + #endif + '''), +) + + +@pytest.mark.parametrize('manylinux_image', ['manylinux1', 'manylinux2010', 'manylinux2014']) +def test(manylinux_image, tmpdir): + if utils.platform != 'linux': + pytest.skip('the docker test is only relevant to the linux build') + elif platform.machine() not in ['x86_64', 'i686']: + if manylinux_image in ['manylinux1', 'manylinux2010']: + pytest.skip("manylinux1 and 2010 doesn't exist for non-x86 architectures") + + project_dir = str(tmpdir) + project_with_manylinux_symbols.generate(project_dir) + + # build the wheels + # CFLAGS environment variable is necessary to fail on 'malloc_info' (on manylinux1) during compilation/linking, + # rather than when dynamically loading the Python + add_env = { + 'CIBW_ENVIRONMENT': 'CFLAGS="$CFLAGS -Werror=implicit-function-declaration"', + 'CIBW_MANYLINUX_X86_64_IMAGE': manylinux_image, + 'CIBW_MANYLINUX_I686_IMAGE': manylinux_image, + 'CIBW_MANYLINUX_PYPY_X86_64_IMAGE': manylinux_image, + 'CIBW_MANYLINUX_AARCH64_IMAGE': manylinux_image, + 'CIBW_MANYLINUX_PPC64LE_IMAGE': manylinux_image, + 'CIBW_MANYLINUX_S390X_IMAGE': manylinux_image, + } + if manylinux_image == 'manylinux1': + # We don't have a manylinux1 image for PyPy + add_env['CIBW_SKIP'] = 'pp*' + elif manylinux_image == 'manylinux2014': + # We don't have a manylinux2014 image for PyPy (yet?) + add_env['CIBW_SKIP'] = 'cp27* pp*' # Python 2.7 not available on manylinux2014 + actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) + + expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0', manylinux_versions=[manylinux_image])] + if manylinux_image == 'manylinux2014': + expected_wheels = [w for w in expected_wheels if '-cp27' not in w] + if manylinux_image in ['manylinux1', 'manylinux2014']: + expected_wheels = [w for w in expected_wheels if '-pp' not in w] + assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_09_cpp_standards.py b/test/test_09_cpp_standards.py new file mode 100644 index 00000000..32719df7 --- /dev/null +++ b/test/test_09_cpp_standards.py @@ -0,0 +1,150 @@ +import os +import textwrap + +import pytest + +from . import utils +from .template_projects import SetuptoolsTemplateProject +import jinja2 + +# TODO: specify these at runtime according to manylinux_image +cpp_project = SetuptoolsTemplateProject( + setup_py_add='''ext_modules=[Extension('spam', sources=['spam.cpp'])],''' +) +cpp_project.files['spam.cpp'] = jinja2.Template(r''' +#include + +{{ spam_cpp_add }} + +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) +} +''') + +spam_cpp_top_level_add = ''' +// Depending on the requested standard, use a modern C++ feature +// that was introduced in that standard. +#if STANDARD == 11 + #include +#elif STANDARD == 14 + int a = 100'000; +#elif STANDARD == 17 + #include + auto a = std::pair(5.0, false); +#else + #error Standard needed +#endif +''' + +project_dir = os.path.dirname(__file__) + +def test_cpp11(tmpdir): + # This test checks that the C++11 standard is supported + project_dir = str(tmpdir) + + cpp_project.template_context['spam_cpp_add'] = '#include ' + cpp_project.generate(project_dir) + + # VC++ for Python 2.7 does not support modern standards + add_env = {'CIBW_SKIP': 'cp27-win* pp27-win32'} + + actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) + expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') + if 'cp27-cp27m-win' not in w and 'pp27-pypy_73-win32' not in w] + + assert set(actual_wheels) == set(expected_wheels) + + +def test_cpp14(tmpdir): + # This test checks that the C++14 standard is supported + project_dir = str(tmpdir) + + cpp_project.template_context['spam_cpp_add'] = "int a = 100'000;" + cpp_project.generate(project_dir) + + # VC++ for Python 2.7 does not support modern standards + # The manylinux1 docker image does not have a compiler which supports C++11 + # Python 3.4 and 3.5 are compiled with MSVC 10, which does not support C++14 + add_env = {'CIBW_SKIP': 'cp27-win* pp27-win32 cp35-win*'} + + actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) + expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') + if 'cp27-cp27m-win' not in w + and 'pp27-pypy_73-win32' not in w + and 'cp35-cp35m-win' not in w] + + assert set(actual_wheels) == set(expected_wheels) + + +def test_cpp17(tmpdir): + # This test checks that the C++17 standard is supported + project_dir = str(tmpdir) + + cpp_project.template_context['spam_cpp_add'] = textwrap.dedent(''' + #include + auto a = std::pair(5.0, false); + ''') + cpp_project.generate(project_dir) + + # Python and PyPy 2.7 use the `register` keyword which is forbidden in the C++17 standard + # The manylinux1 docker image does not have a compiler which supports C++11 + # Python 3.5 and PyPy 3.6 are compiled with MSVC 10, which does not support C++17 + if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') == 'Visual Studio 2015': + pytest.skip('Visual Studio 2015 does not support C++17') + + add_env = {'CIBW_SKIP': 'cp27-win* pp27-win32 cp35-win* pp36-win32'} + + if utils.platform == 'macos': + add_env['MACOSX_DEPLOYMENT_TARGET'] = '10.13' + + actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) + expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0', macosx_deployment_target='10.13') + if 'cp27-cp27m-win' not in w + and 'pp27-pypy_73-win32' not in w + and 'cp35-cp35m-win' not in w + and 'pp36-pypy36_pp73-win32' not in w] + + assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_10_before_test.py b/test/test_10_before_test.py new file mode 100644 index 00000000..6455ac50 --- /dev/null +++ b/test/test_10_before_test.py @@ -0,0 +1,56 @@ +import os +import utils +from test.template_projects.c import CTemplateProject + +before_test_project = CTemplateProject() +before_test_project.files['test/spam_test.py'] = r''' +import sys +import os +from unittest import TestCase + + +class TestBeforeTest(TestCase): + def test_version(self): + # assert that the Python version as written to pythonversion.txt in the CIBW_BEFORE_TEST step + # is the same one as is currently running. + # because of use symlinks in MacOS run this test is also need + version_file = 'c:\\pythonversion.txt' if sys.platform == 'win32' else '/tmp/pythonversion.txt' + with open(version_file) as f: + stored_version = f.read() + print('stored_version', stored_version) + print('sys.version', sys.version) + assert stored_version == sys.version + + def test_prefix(self): + # check that the prefix also was written + prefix_file = 'c:\\pythonprefix.txt' if sys.platform == 'win32' else '/tmp/pythonprefix.txt' + with open(prefix_file) as f: + stored_prefix = f.read() + print('stored_prefix', stored_prefix) + print('sys.prefix', sys.prefix) + # Works around path-comparison bugs caused by short-paths on Windows e.g. + # vssadm~1 instead of vssadministrator + + assert os.stat(stored_prefix) == os.stat(sys.prefix) +''' + +def test(tmpdir): + project_dir = str(tmpdir) + before_test_project.generate(project_dir) + + # build the wheels + actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ + # write python version information to a temporary file, this is + # checked in setup.py + 'CIBW_BEFORE_TEST': '''python -c "import sys; open('/tmp/pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonprefix.txt', 'w').write(sys.prefix)"''', + 'CIBW_BEFORE_TEST_WINDOWS': '''python -c "import sys; open('c:\\pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonprefix.txt', 'w').write(sys.prefix)"''', + 'CIBW_TEST_REQUIRES': 'nose', + # the 'false ||' bit is to ensure this command runs in a shell on + # mac/linux. + 'CIBW_TEST_COMMAND': 'false || nosetests {project}/test', + 'CIBW_TEST_COMMAND_WINDOWS': 'nosetests {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) diff --git a/test/12_dependency_versions/cibuildwheel_test.py b/test/test_11_dependency_versions.py similarity index 77% rename from test/12_dependency_versions/cibuildwheel_test.py rename to test/test_11_dependency_versions.py index 55248bf2..c4f899ae 100644 --- a/test/12_dependency_versions/cibuildwheel_test.py +++ b/test/test_11_dependency_versions.py @@ -4,7 +4,36 @@ import pytest import textwrap import cibuildwheel.util -import utils +from . import utils +from .template_projects import CTemplateProject + + +project_with_expected_version_checks = CTemplateProject( + setup_py_add=textwrap.dedent(r''' + import subprocess + import os + + 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'] + + print('Gathered versions', versions) + + for package_name in ['pip', 'setuptools', 'wheel']: + env_name = 'EXPECTED_{}_VERSION'.format(package_name.upper()) + expected_version = os.environ[env_name] + + assert '{}=={}'.format(package_name, expected_version) in versions, ( + 'error: {} version should equal {}'.format(package_name, expected_version) + ) + ''') +) + VERSION_REGEX = r'([\w-]+)==([^\s]+)' @@ -22,11 +51,12 @@ def get_versions_from_constraint_file(constraint_file): @pytest.mark.parametrize('python_version', ['2.7', '3.5', '3.8']) -def test_pinned_versions(python_version): +def test_pinned_versions(tmpdir, 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__) + project_dir = str(tmpdir) + project_with_expected_version_checks.generate(project_dir) build_environment = {} @@ -78,7 +108,8 @@ def test_dependency_constraints_file(tmp_path, 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__) + project_dir = str(tmp_path / 'project') + project_with_expected_version_checks.generate(project_dir) tool_versions = { 'pip': '20.0.2', diff --git a/test/shared/utils.py b/test/utils.py similarity index 100% rename from test/shared/utils.py rename to test/utils.py From 3b35882f8743f138024d245a8f2113deb647fd76 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 2 May 2020 21:00:58 +0100 Subject: [PATCH 04/32] Complete migration to new style. remove old reference tests --- test/old/01_basic/cibuildwheel_test.py | 39 ----------- test/old/01_basic/setup.py | 15 ---- test/old/01_basic/spam.c | 48 ------------- test/old/02_test/cibuildwheel_test.py | 55 --------------- test/old/02_test/setup.py | 11 --- test/old/02_test/spam.c | 48 ------------- test/old/02_test/test/spam_test.py | 45 ------------ test/old/03_before_build/cibuildwheel_test.py | 19 ------ test/old/03_before_build/setup.py | 31 --------- test/old/03_before_build/spam.c | 48 ------------- test/old/04_build_skip/cibuildwheel_test.py | 18 ----- test/old/04_build_skip/setup.py | 18 ----- test/old/04_build_skip/spam.c | 48 ------------- test/old/05_environment/cibuildwheel_test.py | 32 --------- test/old/05_environment/setup.py | 26 ------- test/old/05_environment/spam.c | 48 ------------- .../old/06_docker_images/cibuildwheel_test.py | 26 ------- test/old/06_docker_images/setup.py | 18 ----- test/old/06_docker_images/spam.c | 48 ------------- test/old/07_ssl/cibuildwheel_test.py | 11 --- test/old/07_ssl/setup.py | 24 ------- test/old/07_ssl/spam.c | 48 ------------- .../cibuildwheel_test.py | 44 ------------ test/old/08_manylinuxXXXX_only/setup.py | 10 --- test/old/08_manylinuxXXXX_only/spam.c | 68 ------------------- test/old/09_setup_cfg/cibuildwheel_test.py | 14 ---- test/old/09_setup_cfg/setup.cfg | 6 -- test/old/09_setup_cfg/setup.py | 8 --- test/old/09_setup_cfg/spam/__init__.py | 1 - test/old/09_setup_cfg/spam/spam.c | 48 ------------- .../old/10_cpp_standards/cibuildwheel_test.py | 61 ----------------- test/old/10_cpp_standards/setup.py | 25 ------- test/old/10_cpp_standards/spam.cpp | 62 ----------------- test/old/11_before_test/setup.py | 8 --- test/old/11_before_test/spam.c | 48 ------------- test/old/11_before_test/test/spam_test.py | 28 -------- test/old/12_dependency_versions/setup.py | 31 --------- test/old/12_dependency_versions/spam.c | 48 ------------- .../old/13_subdir_package/bin/before_build.py | 1 - test/old/13_subdir_package/src/spam/setup.py | 8 --- test/old/13_subdir_package/src/spam/spam.c | 48 ------------- .../src/spam/test/run_tests.py | 1 - test/test_02_testing.py | 7 +- ...heel_test.py => test_12_subdir_package.py} | 29 +++++++- 44 files changed, 33 insertions(+), 1295 deletions(-) delete mode 100644 test/old/01_basic/cibuildwheel_test.py delete mode 100644 test/old/01_basic/setup.py delete mode 100644 test/old/01_basic/spam.c delete mode 100644 test/old/02_test/cibuildwheel_test.py delete mode 100644 test/old/02_test/setup.py delete mode 100644 test/old/02_test/spam.c delete mode 100644 test/old/02_test/test/spam_test.py delete mode 100644 test/old/03_before_build/cibuildwheel_test.py delete mode 100644 test/old/03_before_build/setup.py delete mode 100644 test/old/03_before_build/spam.c delete mode 100644 test/old/04_build_skip/cibuildwheel_test.py delete mode 100644 test/old/04_build_skip/setup.py delete mode 100644 test/old/04_build_skip/spam.c delete mode 100644 test/old/05_environment/cibuildwheel_test.py delete mode 100644 test/old/05_environment/setup.py delete mode 100644 test/old/05_environment/spam.c delete mode 100644 test/old/06_docker_images/cibuildwheel_test.py delete mode 100644 test/old/06_docker_images/setup.py delete mode 100644 test/old/06_docker_images/spam.c delete mode 100644 test/old/07_ssl/cibuildwheel_test.py delete mode 100644 test/old/07_ssl/setup.py delete mode 100644 test/old/07_ssl/spam.c delete mode 100644 test/old/08_manylinuxXXXX_only/cibuildwheel_test.py delete mode 100644 test/old/08_manylinuxXXXX_only/setup.py delete mode 100644 test/old/08_manylinuxXXXX_only/spam.c delete mode 100644 test/old/09_setup_cfg/cibuildwheel_test.py delete mode 100644 test/old/09_setup_cfg/setup.cfg delete mode 100644 test/old/09_setup_cfg/setup.py delete mode 100644 test/old/09_setup_cfg/spam/__init__.py delete mode 100644 test/old/09_setup_cfg/spam/spam.c delete mode 100644 test/old/10_cpp_standards/cibuildwheel_test.py delete mode 100644 test/old/10_cpp_standards/setup.py delete mode 100644 test/old/10_cpp_standards/spam.cpp delete mode 100644 test/old/11_before_test/setup.py delete mode 100644 test/old/11_before_test/spam.c delete mode 100644 test/old/11_before_test/test/spam_test.py delete mode 100644 test/old/12_dependency_versions/setup.py delete mode 100644 test/old/12_dependency_versions/spam.c delete mode 100755 test/old/13_subdir_package/bin/before_build.py delete mode 100644 test/old/13_subdir_package/src/spam/setup.py delete mode 100644 test/old/13_subdir_package/src/spam/spam.c delete mode 100644 test/old/13_subdir_package/src/spam/test/run_tests.py rename test/{old/13_subdir_package/cibuildwheel_test.py => test_12_subdir_package.py} (53%) diff --git a/test/old/01_basic/cibuildwheel_test.py b/test/old/01_basic/cibuildwheel_test.py deleted file mode 100644 index d8deee4f..00000000 --- a/test/old/01_basic/cibuildwheel_test.py +++ /dev/null @@ -1,39 +0,0 @@ -import os -import platform -import textwrap - -import utils - -project_dir = os.path.dirname(__file__) - -project_spec = TemplateProjectC( - setup_py_add=textwrap.dedent(''' - import os - if os.environ.get("CIBUILDWHEEL", "0") != "1": - raise Exception("CIBUILDWHEEL environment variable is not set to 1") - ''') -) - - -def test(): - # build the wheels - actual_wheels = utils.cibuildwheel_run(project_dir) - - # check that the expected wheels are produced - expected_wheels = utils.expected_wheels('spam', '0.1.0') - assert set(actual_wheels) == set(expected_wheels) - - -def test_build_identifiers(): - # check that the number of expected wheels matches the number of build - # identifiers - # after adding CIBW_MANYLINUX_IMAGE to support manylinux2010, there - # can be multiple wheels for each wheel, though, so we need to limit - # the expected wheels - if platform.machine() in ['x86_64', 'i686']: - expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') - if '-manylinux' not in w or '-manylinux1' in w] - else: - expected_wheels = utils.expected_wheels('spam', '0.1.0') - build_identifiers = utils.cibuildwheel_get_build_identifiers(project_dir) - assert len(expected_wheels) == len(build_identifiers) diff --git a/test/old/01_basic/setup.py b/test/old/01_basic/setup.py deleted file mode 100644 index 83f6d53d..00000000 --- a/test/old/01_basic/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -import os - -from setuptools import ( - Extension, - setup, -) - -if os.environ.get('CIBUILDWHEEL', '0') != '1': - raise Exception('CIBUILDWHEEL environment variable is not set to 1') - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.c'])], - version="0.1.0", -) diff --git a/test/old/01_basic/spam.c b/test/old/01_basic/spam.c deleted file mode 100644 index d1ab0f22..00000000 --- a/test/old/01_basic/spam.c +++ /dev/null @@ -1,48 +0,0 @@ -#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/old/02_test/cibuildwheel_test.py b/test/old/02_test/cibuildwheel_test.py deleted file mode 100644 index 21878d2c..00000000 --- a/test/old/02_test/cibuildwheel_test.py +++ /dev/null @@ -1,55 +0,0 @@ -import os -import subprocess - -import pytest - -import utils - - -def test(): - project_dir = os.path.dirname(__file__) - - # build and test the wheels - actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ - 'CIBW_TEST_REQUIRES': 'nose', - # the 'false ||' bit is to ensure this command runs in a shell on - # mac/linux. - 'CIBW_TEST_COMMAND': 'false || nosetests {project}/test', - 'CIBW_TEST_COMMAND_WINDOWS': 'COLOR 00 || nosetests {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) - - -def test_extras_require(): - project_dir = os.path.dirname(__file__) - - # build and test the wheels - actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ - 'CIBW_TEST_EXTRAS': 'test', - # the 'false ||' bit is to ensure this command runs in a shell on - # mac/linux. - 'CIBW_TEST_COMMAND': 'false || nosetests {project}/test', - 'CIBW_TEST_COMMAND_WINDOWS': 'COLOR 00 || nosetests {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) - - -def test_failing_test(tmp_path): - '''Ensure a failing test causes cibuildwheel to error out and exit''' - project_dir = os.path.dirname(__file__) - - with pytest.raises(subprocess.CalledProcessError): - utils.cibuildwheel_run(project_dir, output_dir=tmp_path, add_env={ - 'CIBW_TEST_COMMAND': 'false', - # manylinux1 has a version of bash that's been shown to have - # problems with this, so let's check that. - 'CIBW_MANYLINUX_I686_IMAGE': 'manylinux1', - 'CIBW_MANYLINUX_X86_64_IMAGE': 'manylinux1', - }) - assert len(os.listdir(str(tmp_path))) == 0 diff --git a/test/old/02_test/setup.py b/test/old/02_test/setup.py deleted file mode 100644 index 3a150b3d..00000000 --- a/test/old/02_test/setup.py +++ /dev/null @@ -1,11 +0,0 @@ -from setuptools import ( - Extension, - setup, -) - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.c'])], - extras_require={'test': ['nose']}, - version="0.1.0", -) diff --git a/test/old/02_test/spam.c b/test/old/02_test/spam.c deleted file mode 100644 index d1ab0f22..00000000 --- a/test/old/02_test/spam.c +++ /dev/null @@ -1,48 +0,0 @@ -#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/old/02_test/test/spam_test.py b/test/old/02_test/test/spam_test.py deleted file mode 100644 index ba5f5e91..00000000 --- a/test/old/02_test/test/spam_test.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import print_function -import os -import sys -from unittest import TestCase - -import spam - - -def path_contains(parent, child): - ''' returns True if `child` is inside `parent`. - - Works around path-comparison bugs caused by short-paths on Windows e.g. - vssadm~1 instead of vssadministrator - ''' - parent = os.path.abspath(parent) - child = os.path.abspath(child) - - while child != os.path.dirname(child): - child = os.path.dirname(child) - if os.stat(parent) == os.stat(child): - # parent and child refer to the same directory on the filesystem - return True - return False - - -class TestSpam(TestCase): - def test_system(self): - self.assertEqual(0, spam.system('python -c "exit(0)"')) - self.assertNotEqual(0, spam.system('python -c "exit(1)"')) - - def test_virtualenv(self): - virtualenv_path = os.environ.get("__CIBW_VIRTUALENV_PATH__") - if not virtualenv_path: - self.fail("No virtualenv path defined in environment variable __CIBW_VIRTUALENV_PATH__") - - print("=[executable]", sys.executable) - print("=[spam location]", spam.__file__) - print("=[virtualenv path]", virtualenv_path) - print("=[listdir]", os.listdir(virtualenv_path)) - if os.path.exists(os.path.join(virtualenv_path, 'Scripts')): - print("=[listdir]2", os.listdir(os.path.join(virtualenv_path, 'Scripts'))) - if os.path.exists(os.path.join(virtualenv_path, 'bin')): - print("=[listdir]2", os.listdir(os.path.join(virtualenv_path, 'bin'))) - self.assertTrue(path_contains(virtualenv_path, sys.executable)) - self.assertTrue(path_contains(virtualenv_path, spam.__file__)) diff --git a/test/old/03_before_build/cibuildwheel_test.py b/test/old/03_before_build/cibuildwheel_test.py deleted file mode 100644 index 8b0bfcb6..00000000 --- a/test/old/03_before_build/cibuildwheel_test.py +++ /dev/null @@ -1,19 +0,0 @@ -import os - -import utils - - -def test(): - project_dir = os.path.dirname(__file__) - - # build the wheels - actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ - # write python version information to a temporary file, this is - # checked in setup.py - 'CIBW_BEFORE_BUILD': '''python -c "import sys; open('/tmp/pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonexecutable.txt', 'w').write(sys.executable)"''', - 'CIBW_BEFORE_BUILD_WINDOWS': '''python -c "import sys; open('c:\\pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonexecutable.txt', 'w').write(sys.executable)"''', - }) - - # also check that we got the right wheels - expected_wheels = utils.expected_wheels('spam', '0.1.0') - assert set(actual_wheels) == set(expected_wheels) diff --git a/test/old/03_before_build/setup.py b/test/old/03_before_build/setup.py deleted file mode 100644 index fd78c005..00000000 --- a/test/old/03_before_build/setup.py +++ /dev/null @@ -1,31 +0,0 @@ -import os -import sys - -from setuptools import ( - Extension, - setup, -) - -# assert that the Python version as written to pythonversion.txt in the CIBW_BEFORE_BUILD step -# is the same one as is currently running. -version_file = 'c:\\pythonversion.txt' if sys.platform == 'win32' else '/tmp/pythonversion.txt' -with open(version_file) as f: - stored_version = f.read() -print('stored_version', stored_version) -print('sys.version', sys.version) -assert stored_version == sys.version - -# check that the executable also was written -executable_file = 'c:\\pythonexecutable.txt' if sys.platform == 'win32' else '/tmp/pythonexecutable.txt' -with open(executable_file) as f: - stored_executable = f.read() -print('stored_executable', stored_executable) -print('sys.executable', sys.executable) -# windows/mac are case insensitive -assert os.path.realpath(stored_executable).lower() == os.path.realpath(sys.executable).lower() - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.c'])], - version="0.1.0", -) diff --git a/test/old/03_before_build/spam.c b/test/old/03_before_build/spam.c deleted file mode 100644 index d1ab0f22..00000000 --- a/test/old/03_before_build/spam.c +++ /dev/null @@ -1,48 +0,0 @@ -#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/old/04_build_skip/cibuildwheel_test.py b/test/old/04_build_skip/cibuildwheel_test.py deleted file mode 100644 index 2c6a622c..00000000 --- a/test/old/04_build_skip/cibuildwheel_test.py +++ /dev/null @@ -1,18 +0,0 @@ -import os - -import utils - - -def test(): - project_dir = os.path.dirname(__file__) - - # build the wheels - actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ - 'CIBW_BUILD': 'cp3?-*', - 'CIBW_SKIP': 'cp37-*', - }) - - # check that we got the right wheels. There should be no 2.7 or 3.7. - expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') - if ('-cp3' in w) and ('-cp37' not in w)] - assert set(actual_wheels) == set(expected_wheels) diff --git a/test/old/04_build_skip/setup.py b/test/old/04_build_skip/setup.py deleted file mode 100644 index 2e3fd5c6..00000000 --- a/test/old/04_build_skip/setup.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys - -from setuptools import ( - Extension, - setup, -) - -# explode if run on Python 2.7 or Python 3.4 (these should be skipped) -if sys.version_info[0:2] == (2, 7): - raise Exception('Python 2.7 should not be built') -if sys.version_info[0:2] == (3, 4): - raise Exception('Python 3.4 should be skipped') - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.c'])], - version="0.1.0", -) diff --git a/test/old/04_build_skip/spam.c b/test/old/04_build_skip/spam.c deleted file mode 100644 index d1ab0f22..00000000 --- a/test/old/04_build_skip/spam.c +++ /dev/null @@ -1,48 +0,0 @@ -#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/old/05_environment/cibuildwheel_test.py b/test/old/05_environment/cibuildwheel_test.py deleted file mode 100644 index ab467111..00000000 --- a/test/old/05_environment/cibuildwheel_test.py +++ /dev/null @@ -1,32 +0,0 @@ -import os -import pytest -import subprocess -import utils - - -def test(): - project_dir = os.path.dirname(__file__) - - # write some information into the CIBW_ENVIRONMENT, for expansion and - # insertion into the environment by cibuildwheel. This is checked - # in setup.py - actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ - 'CIBW_ENVIRONMENT': '''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH=$PATH:/opt/cibw_test_path''', - 'CIBW_ENVIRONMENT_WINDOWS': '''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH="$PATH;/opt/cibw_test_path"''', - }) - - # also check that we got the right wheels built - expected_wheels = utils.expected_wheels('spam', '0.1.0') - assert set(actual_wheels) == set(expected_wheels) - - -def test_overridden_path(tmp_path): - project_dir = os.path.dirname(__file__) - - # mess up PATH, somehow - with pytest.raises(subprocess.CalledProcessError): - utils.cibuildwheel_run(project_dir, output_dir=tmp_path, add_env={ - 'CIBW_ENVIRONMENT': '''SOMETHING="$(mkdir new_path && touch new_path/python)" PATH="$(realpath new_path):$PATH"''', - 'CIBW_ENVIRONMENT_WINDOWS': '''SOMETHING="$(mkdir new_path && type nul > new_path/python.exe)" PATH="$CD\\new_path;$PATH"''', - }) - assert len(os.listdir(str(tmp_path))) == 0 diff --git a/test/old/05_environment/setup.py b/test/old/05_environment/setup.py deleted file mode 100644 index da5e8d59..00000000 --- a/test/old/05_environment/setup.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from setuptools import ( - Extension, - setup, -) - -# explode if environment isn't correct, as set in CIBW_ENVIRONMENT -CIBW_TEST_VAR = os.environ.get('CIBW_TEST_VAR') -CIBW_TEST_VAR_2 = os.environ.get('CIBW_TEST_VAR_2') -PATH = os.environ.get('PATH') - -if CIBW_TEST_VAR != 'a b c': - raise Exception('CIBW_TEST_VAR should equal "a b c". It was "%s"' % CIBW_TEST_VAR) -if CIBW_TEST_VAR_2 != '1': - raise Exception('CIBW_TEST_VAR_2 should equal "1". It was "%s"' % CIBW_TEST_VAR_2) -if '/opt/cibw_test_path' not in PATH: - raise Exception('PATH should contain "/opt/cibw_test_path". It was "%s"' % PATH) -if '$PATH' in PATH: - raise Exception('$PATH should be expanded in PATH. It was "%s"' % PATH) - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.c'])], - version="0.1.0", -) diff --git a/test/old/05_environment/spam.c b/test/old/05_environment/spam.c deleted file mode 100644 index d1ab0f22..00000000 --- a/test/old/05_environment/spam.c +++ /dev/null @@ -1,48 +0,0 @@ -#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/old/06_docker_images/cibuildwheel_test.py b/test/old/06_docker_images/cibuildwheel_test.py deleted file mode 100644 index 7be4a4c3..00000000 --- a/test/old/06_docker_images/cibuildwheel_test.py +++ /dev/null @@ -1,26 +0,0 @@ -import os -import platform - -import pytest - -import utils - - -def test(): - project_dir = os.path.dirname(__file__) - - if utils.platform != 'linux': - pytest.skip('the test is only relevant to the linux build') - if platform.machine() not in ['x86_64', 'i686']: - pytest.skip('this test is currently only possible on x86_64/i686 due to availability of alternative images') - - actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ - 'CIBW_MANYLINUX_X86_64_IMAGE': 'dockcross/manylinux2010-x64', - 'CIBW_MANYLINUX_I686_IMAGE': 'dockcross/manylinux2010-x86', - 'CIBW_SKIP': 'pp*', - }) - - # also check that we got the right wheels built - expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') - if '-pp' not in w] - assert set(actual_wheels) == set(expected_wheels) diff --git a/test/old/06_docker_images/setup.py b/test/old/06_docker_images/setup.py deleted file mode 100644 index 5680349d..00000000 --- a/test/old/06_docker_images/setup.py +++ /dev/null @@ -1,18 +0,0 @@ -import os -import sys - -from setuptools import ( - Extension, - setup, -) - -# check that we're running in the correct docker image as specified in the -# environment options CIBW_MANYLINUX1_*_IMAGE -if 'linux' in sys.platform and not os.path.exists('/dockcross'): - raise Exception('/dockcross directory not found. Is this test running in the correct docker image?') - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.c'])], - version="0.1.0", -) diff --git a/test/old/06_docker_images/spam.c b/test/old/06_docker_images/spam.c deleted file mode 100644 index d1ab0f22..00000000 --- a/test/old/06_docker_images/spam.c +++ /dev/null @@ -1,48 +0,0 @@ -#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/old/07_ssl/cibuildwheel_test.py b/test/old/07_ssl/cibuildwheel_test.py deleted file mode 100644 index 787ba866..00000000 --- a/test/old/07_ssl/cibuildwheel_test.py +++ /dev/null @@ -1,11 +0,0 @@ -import os - -import utils - - -def test(): - project_dir = os.path.dirname(__file__) - # this test checks that SSL is working in the build environment using - # some checks in setup.py. - - utils.cibuildwheel_run(project_dir) diff --git a/test/old/07_ssl/setup.py b/test/old/07_ssl/setup.py deleted file mode 100644 index 4b6a4f24..00000000 --- a/test/old/07_ssl/setup.py +++ /dev/null @@ -1,24 +0,0 @@ -import ssl -import sys - -from setuptools import ( - Extension, - setup, -) - -if sys.version_info[0] == 2: - from urllib2 import urlopen -else: - from urllib.request import urlopen - -if sys.version_info[0:2] == (3, 3): - data = urlopen('https://www.nist.gov') -else: - context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) - data = urlopen('https://www.nist.gov', context=context) - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.c'])], - version="0.1.0", -) diff --git a/test/old/07_ssl/spam.c b/test/old/07_ssl/spam.c deleted file mode 100644 index d1ab0f22..00000000 --- a/test/old/07_ssl/spam.c +++ /dev/null @@ -1,48 +0,0 @@ -#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/old/08_manylinuxXXXX_only/cibuildwheel_test.py b/test/old/08_manylinuxXXXX_only/cibuildwheel_test.py deleted file mode 100644 index 2c20441d..00000000 --- a/test/old/08_manylinuxXXXX_only/cibuildwheel_test.py +++ /dev/null @@ -1,44 +0,0 @@ -import os -import platform - -import pytest - -import utils - - -@pytest.mark.parametrize('manylinux_image', ['manylinux1', 'manylinux2010', 'manylinux2014']) -def test(manylinux_image): - project_dir = os.path.dirname(__file__) - - if utils.platform != 'linux': - pytest.skip('the docker test is only relevant to the linux build') - elif platform.machine() not in ['x86_64', 'i686']: - if manylinux_image in ['manylinux1', 'manylinux2010']: - pytest.skip("manylinux1 and 2010 doesn't exist for non-x86 architectures") - - # build the wheels - # CFLAGS environment variable is necessary to fail on 'malloc_info' (on manylinux1) during compilation/linking, - # rather than when dynamically loading the Python - add_env = { - 'CIBW_ENVIRONMENT': 'CFLAGS="$CFLAGS -Werror=implicit-function-declaration"', - 'CIBW_MANYLINUX_X86_64_IMAGE': manylinux_image, - 'CIBW_MANYLINUX_I686_IMAGE': manylinux_image, - 'CIBW_MANYLINUX_PYPY_X86_64_IMAGE': manylinux_image, - 'CIBW_MANYLINUX_AARCH64_IMAGE': manylinux_image, - 'CIBW_MANYLINUX_PPC64LE_IMAGE': manylinux_image, - 'CIBW_MANYLINUX_S390X_IMAGE': manylinux_image, - } - if manylinux_image == 'manylinux1': - # We don't have a manylinux1 image for PyPy - add_env['CIBW_SKIP'] = 'pp*' - elif manylinux_image == 'manylinux2014': - # We don't have a manylinux2014 image for PyPy (yet?) - add_env['CIBW_SKIP'] = 'cp27* pp*' # Python 2.7 not available on manylinux2014 - actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) - - expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0', manylinux_versions=[manylinux_image])] - if manylinux_image == 'manylinux2014': - expected_wheels = [w for w in expected_wheels if '-cp27' not in w] - if manylinux_image in ['manylinux1', 'manylinux2014']: - expected_wheels = [w for w in expected_wheels if '-pp' not in w] - assert set(actual_wheels) == set(expected_wheels) diff --git a/test/old/08_manylinuxXXXX_only/setup.py b/test/old/08_manylinuxXXXX_only/setup.py deleted file mode 100644 index 209f45b0..00000000 --- a/test/old/08_manylinuxXXXX_only/setup.py +++ /dev/null @@ -1,10 +0,0 @@ -from setuptools import ( - Extension, - setup, -) - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.c'])], - version="0.1.0", -) diff --git a/test/old/08_manylinuxXXXX_only/spam.c b/test/old/08_manylinuxXXXX_only/spam.c deleted file mode 100644 index 0e7c5597..00000000 --- a/test/old/08_manylinuxXXXX_only/spam.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include - -#if !defined(__GLIBC_PREREQ) -#error "Must run on a glibc linux environment" -#endif - -#if !__GLIBC_PREREQ(2, 5) /* manylinux1 is glibc 2.5 */ -#error "Must run on a glibc >= 2.5 linux environment" -#endif - -static PyObject * -spam_system(PyObject *self, PyObject *args) -{ - const char *command; - int sts = 0; - - if (!PyArg_ParseTuple(args, "s", &command)) - return NULL; - -#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 17) /* manylinux2014 is glibc 2.17 */ - // secure_getenv is only available in manylinux2014, ensuring - // that only a manylinux2014 wheel is produced - sts = (int)secure_getenv("NON_EXISTING_ENV_VARIABLE"); -#elif defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 10) /* manylinux2010 is glibc 2.12 */ - // malloc_info is only available on manylinux2010+ - sts = malloc_info(0, stdout); -#endif - if (sts == 0) { - 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/old/09_setup_cfg/cibuildwheel_test.py b/test/old/09_setup_cfg/cibuildwheel_test.py deleted file mode 100644 index b6c3de01..00000000 --- a/test/old/09_setup_cfg/cibuildwheel_test.py +++ /dev/null @@ -1,14 +0,0 @@ -import os - -import utils - -project_dir = os.path.dirname(__file__) - - -def test(): - # build the wheels - actual_wheels = utils.cibuildwheel_run(project_dir) - - # check that the expected wheels are produced - expected_wheels = utils.expected_wheels('spam', '0.1.0') - assert set(actual_wheels) == set(expected_wheels) diff --git a/test/old/09_setup_cfg/setup.cfg b/test/old/09_setup_cfg/setup.cfg deleted file mode 100644 index b42c221a..00000000 --- a/test/old/09_setup_cfg/setup.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[metadata] -name = spam -version = attr: spam.__version__ - -[options] -packages = find: \ No newline at end of file diff --git a/test/old/09_setup_cfg/setup.py b/test/old/09_setup_cfg/setup.py deleted file mode 100644 index a4c19252..00000000 --- a/test/old/09_setup_cfg/setup.py +++ /dev/null @@ -1,8 +0,0 @@ -from setuptools import ( - Extension, - setup, -) - -setup( - ext_modules=[Extension('spam.spam', sources=['spam/spam.c'])], -) diff --git a/test/old/09_setup_cfg/spam/__init__.py b/test/old/09_setup_cfg/spam/__init__.py deleted file mode 100644 index 3dc1f76b..00000000 --- a/test/old/09_setup_cfg/spam/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "0.1.0" diff --git a/test/old/09_setup_cfg/spam/spam.c b/test/old/09_setup_cfg/spam/spam.c deleted file mode 100644 index d1ab0f22..00000000 --- a/test/old/09_setup_cfg/spam/spam.c +++ /dev/null @@ -1,48 +0,0 @@ -#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/old/10_cpp_standards/cibuildwheel_test.py b/test/old/10_cpp_standards/cibuildwheel_test.py deleted file mode 100644 index 72a8f676..00000000 --- a/test/old/10_cpp_standards/cibuildwheel_test.py +++ /dev/null @@ -1,61 +0,0 @@ -import os - -import pytest - -import utils - -project_dir = os.path.dirname(__file__) - - -def test_cpp11(tmp_path): - # This test checks that the C++11 standard is supported - - # VC++ for Python 2.7 does not support modern standards - add_env = {'CIBW_SKIP': 'cp27-win* pp27-win32', 'CIBW_ENVIRONMENT': 'STANDARD=11'} - - actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) - expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') - if 'cp27-cp27m-win' not in w and 'pp27-pypy_73-win32' not in w] - - assert set(actual_wheels) == set(expected_wheels) - - -def test_cpp14(): - # This test checks that the C++14 standard is supported - - # VC++ for Python 2.7 does not support modern standards - # The manylinux1 docker image does not have a compiler which supports C++11 - # Python 3.4 and 3.5 are compiled with MSVC 10, which does not support C++14 - add_env = {'CIBW_SKIP': 'cp27-win* pp27-win32 cp35-win*', 'CIBW_ENVIRONMENT': 'STANDARD=14'} - - actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) - expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') - if 'cp27-cp27m-win' not in w - and 'pp27-pypy_73-win32' not in w - and 'cp35-cp35m-win' not in w] - - assert set(actual_wheels) == set(expected_wheels) - - -def test_cpp17(): - # This test checks that the C++17 standard is supported - - # Python and PyPy 2.7 use the `register` keyword which is forbidden in the C++17 standard - # The manylinux1 docker image does not have a compiler which supports C++11 - # Python 3.5 and PyPy 3.6 are compiled with MSVC 10, which does not support C++17 - if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') == 'Visual Studio 2015': - pytest.skip('Visual Studio 2015 does not support C++17') - - add_env = {'CIBW_SKIP': 'cp27-win* pp27-win32 cp35-win* pp36-win32', 'CIBW_ENVIRONMENT': 'STANDARD=17'} - - if utils.platform == 'macos': - add_env['MACOSX_DEPLOYMENT_TARGET'] = '10.13' - - actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) - expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0', macosx_deployment_target='10.13') - if 'cp27-cp27m-win' not in w - and 'pp27-pypy_73-win32' not in w - and 'cp35-cp35m-win' not in w - and 'pp36-pypy36_pp73-win32' not in w] - - assert set(actual_wheels) == set(expected_wheels) diff --git a/test/old/10_cpp_standards/setup.py b/test/old/10_cpp_standards/setup.py deleted file mode 100644 index f848d0b1..00000000 --- a/test/old/10_cpp_standards/setup.py +++ /dev/null @@ -1,25 +0,0 @@ -import os -import platform - -from setuptools import ( - Extension, - setup, -) - -standard = os.environ["STANDARD"] - -language_standard = "/std:c++" + standard if platform.system() == "Windows" else "-std=c++" + standard - -extra_compile_args = [language_standard, "-DSTANDARD=" + standard] - -if standard == "17": - if platform.system() == "Windows": - extra_compile_args.append("/wd5033") - else: - extra_compile_args.append("-Wno-register") - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.cpp'], language="c++", extra_compile_args=extra_compile_args)], - version="0.1.0", -) diff --git a/test/old/10_cpp_standards/spam.cpp b/test/old/10_cpp_standards/spam.cpp deleted file mode 100644 index f9b56d07..00000000 --- a/test/old/10_cpp_standards/spam.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -// Depending on the requested standard, use a modern C++ feature -// that was introduced in that standard. -#if STANDARD == 11 - #include -#elif STANDARD == 14 - int a = 100'000; -#elif STANDARD == 17 - #include - auto a = std::pair(5.0, false); -#else - #error Standard needed -#endif - -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/old/11_before_test/setup.py b/test/old/11_before_test/setup.py deleted file mode 100644 index e3ea2938..00000000 --- a/test/old/11_before_test/setup.py +++ /dev/null @@ -1,8 +0,0 @@ -from setuptools import setup, Extension - - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.c'])], - version="0.1.0", -) diff --git a/test/old/11_before_test/spam.c b/test/old/11_before_test/spam.c deleted file mode 100644 index d1ab0f22..00000000 --- a/test/old/11_before_test/spam.c +++ /dev/null @@ -1,48 +0,0 @@ -#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/old/11_before_test/test/spam_test.py b/test/old/11_before_test/test/spam_test.py deleted file mode 100644 index 21bad8c2..00000000 --- a/test/old/11_before_test/test/spam_test.py +++ /dev/null @@ -1,28 +0,0 @@ -import sys -import os -from unittest import TestCase - - -class TestBeforeTest(TestCase): - def test_version(self): - # assert that the Python version as written to pythonversion.txt in the CIBW_BEFORE_TEST step - # is the same one as is currently running. - # because of use symlinks in MacOS run this test is also need - version_file = 'c:\\pythonversion.txt' if sys.platform == 'win32' else '/tmp/pythonversion.txt' - with open(version_file) as f: - stored_version = f.read() - print('stored_version', stored_version) - print('sys.version', sys.version) - assert stored_version == sys.version - - def test_prefix(self): - # check that the prefix also was written - prefix_file = 'c:\\pythonprefix.txt' if sys.platform == 'win32' else '/tmp/pythonprefix.txt' - with open(prefix_file) as f: - stored_prefix = f.read() - print('stored_prefix', stored_prefix) - print('sys.prefix', sys.prefix) - # Works around path-comparison bugs caused by short-paths on Windows e.g. - # vssadm~1 instead of vssadministrator - - assert os.stat(stored_prefix) == os.stat(sys.prefix) diff --git a/test/old/12_dependency_versions/setup.py b/test/old/12_dependency_versions/setup.py deleted file mode 100644 index 61e4719e..00000000 --- a/test/old/12_dependency_versions/setup.py +++ /dev/null @@ -1,31 +0,0 @@ -import os -import subprocess -from setuptools import ( - Extension, - setup, -) - -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'] - -print('Gathered versions', versions) - -for package_name in ['pip', 'setuptools', 'wheel']: - env_name = 'EXPECTED_{}_VERSION'.format(package_name.upper()) - expected_version = os.environ[env_name] - - assert '{}=={}'.format(package_name, expected_version) in versions, ( - 'error: {} version should equal {}'.format(package_name, expected_version) - ) - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.c'])], - version="0.1.0", -) diff --git a/test/old/12_dependency_versions/spam.c b/test/old/12_dependency_versions/spam.c deleted file mode 100644 index d1ab0f22..00000000 --- a/test/old/12_dependency_versions/spam.c +++ /dev/null @@ -1,48 +0,0 @@ -#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/old/13_subdir_package/bin/before_build.py b/test/old/13_subdir_package/bin/before_build.py deleted file mode 100755 index 3bc8ab16..00000000 --- a/test/old/13_subdir_package/bin/before_build.py +++ /dev/null @@ -1 +0,0 @@ -print('before_build.py executed!') diff --git a/test/old/13_subdir_package/src/spam/setup.py b/test/old/13_subdir_package/src/spam/setup.py deleted file mode 100644 index 637d7ff0..00000000 --- a/test/old/13_subdir_package/src/spam/setup.py +++ /dev/null @@ -1,8 +0,0 @@ -from setuptools import Extension, setup - - -setup( - name="spam", - ext_modules=[Extension('spam', sources=['spam.c'])], - version="0.1.0", -) diff --git a/test/old/13_subdir_package/src/spam/spam.c b/test/old/13_subdir_package/src/spam/spam.c deleted file mode 100644 index d1ab0f22..00000000 --- a/test/old/13_subdir_package/src/spam/spam.c +++ /dev/null @@ -1,48 +0,0 @@ -#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/old/13_subdir_package/src/spam/test/run_tests.py b/test/old/13_subdir_package/src/spam/test/run_tests.py deleted file mode 100644 index 8104e1b3..00000000 --- a/test/old/13_subdir_package/src/spam/test/run_tests.py +++ /dev/null @@ -1 +0,0 @@ -print('run_tests.py executed!') diff --git a/test/test_02_testing.py b/test/test_02_testing.py index df2f51be..59dda512 100644 --- a/test/test_02_testing.py +++ b/test/test_02_testing.py @@ -3,7 +3,12 @@ import pytest, textwrap from . import utils from .template_projects import CTemplateProject -project_with_a_test = CTemplateProject() +project_with_a_test = CTemplateProject( + setup_cfg_add=textwrap.dedent(r''' + [options.extras_require] + test = nose + ''') +) project_with_a_test.files['test/spam_test.py'] = r''' from unittest import TestCase diff --git a/test/old/13_subdir_package/cibuildwheel_test.py b/test/test_12_subdir_package.py similarity index 53% rename from test/old/13_subdir_package/cibuildwheel_test.py rename to test/test_12_subdir_package.py index 404811db..bd520110 100644 --- a/test/old/13_subdir_package/cibuildwheel_test.py +++ b/test/test_12_subdir_package.py @@ -1,10 +1,35 @@ import os import utils +from .template_projects.c import spam_c_template +from .template_projects import TemplateProject -project_dir = os.path.dirname(__file__) +subdir_package_project = TemplateProject() + +subdir_package_project.files['src/spam/spam.c'] = spam_c_template + +subdir_package_project.files['src/spam/setup.py'] = r''' +from setuptools import Extension, setup + +setup( + name="spam", + ext_modules=[Extension('spam', sources=['spam.c'])], + version="0.1.0", +) +''' + +subdir_package_project.files['src/spam/test/run_tests.py'] = r''' +print('run_tests.py executed!') +''' + +subdir_package_project.files['bin/before_build.py'] = r''' +print('before_build.py executed!') +''' -def test(capfd): +def test(capfd, tmpdir): + project_dir = str(tmpdir) + subdir_package_project.generate(project_dir) + package_dir = os.path.join(project_dir, 'src', 'spam') # build the wheels actual_wheels = utils.cibuildwheel_run(project_dir, package_dir=package_dir, add_env={ From 007be7aea734802b6ec865b67b703a3dcb37000a Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 2 May 2020 22:42:35 +0100 Subject: [PATCH 05/32] Ensure tests are up-to-date with master --- test/test_02_testing.py | 61 ++++++++++++++++------------------ test/test_03_before_build.py | 38 ++++++++------------- test/test_04_build_skip.py | 20 +++++------ test/test_05_environment.py | 34 +++++++++++++------ test/test_06_docker_images.py | 27 ++++++--------- test/test_09_cpp_standards.py | 24 +++---------- test/test_10_before_test.py | 2 +- test/test_12_subdir_package.py | 5 ++- 8 files changed, 94 insertions(+), 117 deletions(-) diff --git a/test/test_02_testing.py b/test/test_02_testing.py index 59dda512..369f1505 100644 --- a/test/test_02_testing.py +++ b/test/test_02_testing.py @@ -26,55 +26,52 @@ def test(tmpdir): project_with_a_test.generate(project_dir) # build and test the wheels - actual_wheels = utils.cibuildwheel_run( - project_dir, - add_env={ - "CIBW_TEST_REQUIRES": "nose", - # the 'false ||' bit is to ensure this command runs in a shell on - # mac/linux. - "CIBW_TEST_COMMAND": "false || nosetests {project}/test", - "CIBW_TEST_COMMAND_WINDOWS": "nosetests {project}/test", - }, - ) + actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ + 'CIBW_TEST_REQUIRES': 'nose', + # the 'false ||' bit is to ensure this command runs in a shell on + # mac/linux. + 'CIBW_TEST_COMMAND': 'false || nosetests {project}/test', + 'CIBW_TEST_COMMAND_WINDOWS': 'COLOR 00 || nosetests {project}/test', + }) # also check that we got the right wheels - expected_wheels = utils.expected_wheels("spam", "0.1.0") + expected_wheels = utils.expected_wheels('spam', '0.1.0') assert set(actual_wheels) == set(expected_wheels) + def test_extras_require(tmpdir): project_dir = str(tmpdir) project_with_a_test.generate(project_dir) # build and test the wheels - actual_wheels = utils.cibuildwheel_run( - project_dir, - add_env={ - "CIBW_TEST_EXTRAS": "test", - "CIBW_TEST_COMMAND": "nosetests {project}/test", - }, - ) + actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ + 'CIBW_TEST_EXTRAS': 'test', + # the 'false ||' bit is to ensure this command runs in a shell on + # mac/linux. + 'CIBW_TEST_COMMAND': 'false || nosetests {project}/test', + 'CIBW_TEST_COMMAND_WINDOWS': 'COLOR 00 || nosetests {project}/test', + }) # also check that we got the right wheels - expected_wheels = utils.expected_wheels("spam", "0.1.0") + expected_wheels = utils.expected_wheels('spam', '0.1.0') assert set(actual_wheels) == set(expected_wheels) -def test_failing_test(tmpdir): +def test_failing_test(tmp_path): """Ensure a failing test causes cibuildwheel to error out and exit""" - project_dir = str(tmpdir) + project_dir = str(tmp_path / 'project') + output_dir = str(tmp_path / 'output') project_with_a_test.generate(project_dir) with pytest.raises(subprocess.CalledProcessError): - utils.cibuildwheel_run( - project_dir, - add_env={ - "CIBW_TEST_COMMAND": "false", - # manylinux1 has a version of bash that's been shown to have - # problems with this, so let's check that. - "CIBW_MANYLINUX_I686_IMAGE": "manylinux1", - "CIBW_MANYLINUX_X86_64_IMAGE": "manylinux1", - }, - ) + utils.cibuildwheel_run(project_dir, output_dir=output_dir, add_env={ + 'CIBW_TEST_COMMAND': 'false', + # manylinux1 has a version of bash that's been shown to have + # problems with this, so let's check that. + 'CIBW_MANYLINUX_I686_IMAGE': 'manylinux1', + 'CIBW_MANYLINUX_X86_64_IMAGE': 'manylinux1', + }) + + assert len(os.listdir(output_dir)) == 0 - assert len(os.listdir("wheelhouse")) diff --git a/test/test_03_before_build.py b/test/test_03_before_build.py index 69b4ff20..58e51b2d 100644 --- a/test/test_03_before_build.py +++ b/test/test_03_before_build.py @@ -9,28 +9,21 @@ project_with_before_build_asserts = CTemplateProject( # assert that the Python version as written to pythonversion.txt in the CIBW_BEFORE_BUILD step # is the same one as is currently running. - version_file = ( - "c:\\pythonversion.txt" if sys.platform == "win32" else "/tmp/pythonversion.txt" - ) + version_file = 'c:\\pythonversion.txt' if sys.platform == 'win32' else '/tmp/pythonversion.txt' with open(version_file) as f: stored_version = f.read() - print("stored_version", stored_version) - print("sys.version", sys.version) + print('stored_version', stored_version) + print('sys.version', sys.version) assert stored_version == sys.version # check that the executable also was written - executable_file = ( - "c:\\pythonexecutable.txt" if sys.platform == "win32" else "/tmp/pythonexecutable.txt" - ) + executable_file = 'c:\\pythonexecutable.txt' if sys.platform == 'win32' else '/tmp/pythonexecutable.txt' with open(executable_file) as f: stored_executable = f.read() - print("stored_executable", stored_executable) - print("sys.executable", sys.executable) + print('stored_executable', stored_executable) + print('sys.executable', sys.executable) # windows/mac are case insensitive - assert ( - os.path.realpath(stored_executable).lower() - == os.path.realpath(sys.executable).lower() - ) + assert os.path.realpath(stored_executable).lower() == os.path.realpath(sys.executable).lower() ''') ) @@ -40,16 +33,13 @@ def test(tmpdir): project_with_before_build_asserts.generate(project_dir) # build the wheels - actual_wheels = utils.cibuildwheel_run( - project_dir, - add_env={ - # write python version information to a temporary file, this is - # checked in setup.py - "CIBW_BEFORE_BUILD": '''python -c "import sys; open('/tmp/pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonexecutable.txt', 'w').write(sys.executable)"''', - "CIBW_BEFORE_BUILD_WINDOWS": '''python -c "import sys; open('c:\\pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonexecutable.txt', 'w').write(sys.executable)"''', - }, - ) + actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ + # write python version information to a temporary file, this is + # checked in setup.py + 'CIBW_BEFORE_BUILD': '''python -c "import sys; open('/tmp/pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonexecutable.txt', 'w').write(sys.executable)"''', + 'CIBW_BEFORE_BUILD_WINDOWS': '''python -c "import sys; open('c:\\pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonexecutable.txt', 'w').write(sys.executable)"''', + }) # also check that we got the right wheels - expected_wheels = utils.expected_wheels("spam", "0.1.0") + expected_wheels = utils.expected_wheels('spam', '0.1.0') assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_04_build_skip.py b/test/test_04_build_skip.py index 0505f20d..73f0de52 100644 --- a/test/test_04_build_skip.py +++ b/test/test_04_build_skip.py @@ -5,11 +5,11 @@ from .template_projects import CTemplateProject project_with_skip_asserts = CTemplateProject( setup_py_add=textwrap.dedent(r''' - # explode if run on Python 2.7 or Python 3.4 (these should be skipped) + # explode if run on Python 2.7 or Python 3.7 (these should be skipped) if sys.version_info[0:2] == (2, 7): raise Exception("Python 2.7 should not be built") - if sys.version_info[0:2] == (3, 4): - raise Exception("Python 3.4 should be skipped") + if sys.version_info[0:2] == (3, 7): + raise Exception("Python 3.7 should be skipped") ''') ) @@ -18,14 +18,12 @@ def test(tmpdir): project_with_skip_asserts.generate(project_dir) # build the wheels - actual_wheels = utils.cibuildwheel_run( - project_dir, add_env={"CIBW_BUILD": "cp3?-*", "CIBW_SKIP": "cp37-*",} - ) + actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ + 'CIBW_BUILD': 'cp3?-*', + 'CIBW_SKIP': 'cp37-*', + }) # check that we got the right wheels. There should be no 2.7 or 3.7. - expected_wheels = [ - w - for w in utils.expected_wheels("spam", "0.1.0") - if ("-cp3" in w) and ("-cp37" not in w) - ] + expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') + if ('-cp3' in w) and ('-cp37' not in w)] assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_05_environment.py b/test/test_05_environment.py index 1e6f25b5..5e4b9ee6 100644 --- a/test/test_05_environment.py +++ b/test/test_05_environment.py @@ -1,4 +1,7 @@ -import os, inspect, textwrap +import os +import pytest +import subprocess +import textwrap from . import utils from .template_projects import CTemplateProject @@ -30,15 +33,26 @@ def test(tmpdir): # write some information into the CIBW_ENVIRONMENT, for expansion and # insertion into the environment by cibuildwheel. This is checked - # in setup_py_add - actual_wheels = utils.cibuildwheel_run( - project_dir, - add_env={ - "CIBW_ENVIRONMENT": """CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH=$PATH:/opt/cibw_test_path""", - "CIBW_ENVIRONMENT_WINDOWS": '''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH="$PATH;/opt/cibw_test_path"''', - }, - ) + # in setup.py + actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ + 'CIBW_ENVIRONMENT': '''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH=$PATH:/opt/cibw_test_path''', + 'CIBW_ENVIRONMENT_WINDOWS': '''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH="$PATH;/opt/cibw_test_path"''', + }) # also check that we got the right wheels built - expected_wheels = utils.expected_wheels("spam", "0.1.0") + expected_wheels = utils.expected_wheels('spam', '0.1.0') assert set(actual_wheels) == set(expected_wheels) + + +def test_overridden_path(tmp_path): + project_dir = str(tmp_path / 'project') + output_dir = str(tmp_path / 'output') + CTemplateProject().generate(project_dir) + + # mess up PATH, somehow + with pytest.raises(subprocess.CalledProcessError): + utils.cibuildwheel_run(project_dir, output_dir=output_dir, add_env={ + 'CIBW_ENVIRONMENT': '''SOMETHING="$(mkdir new_path && touch new_path/python)" PATH="$(realpath new_path):$PATH"''', + 'CIBW_ENVIRONMENT_WINDOWS': '''SOMETHING="$(mkdir new_path && type nul > new_path/python.exe)" PATH="$CD\\new_path;$PATH"''', + }) + assert len(os.listdir(output_dir)) == 0 diff --git a/test/test_06_docker_images.py b/test/test_06_docker_images.py index 57a487d3..5a0af5ce 100644 --- a/test/test_06_docker_images.py +++ b/test/test_06_docker_images.py @@ -17,26 +17,21 @@ dockcross_only_project = CTemplateProject( ) def test(tmpdir): - if utils.platform != "linux": - pytest.skip("the test is only relevant to the linux build") + if utils.platform != 'linux': + pytest.skip('the test is only relevant to the linux build') + if platform.machine() not in ['x86_64', 'i686']: + pytest.skip('this test is currently only possible on x86_64/i686 due to availability of alternative images') project_dir = str(tmpdir) dockcross_only_project.generate(project_dir) - actual_wheels = utils.cibuildwheel_run( - project_dir, - add_env={ - "CIBW_MANYLINUX_X86_64_IMAGE": "dockcross/manylinux2010-x64", - "CIBW_MANYLINUX_I686_IMAGE": "dockcross/manylinux1-x86", - "CIBW_BEFORE_BUILD": "/opt/python/cp36-cp36m/bin/pip install -U auditwheel", # Currently necessary on dockcross images to get auditwheel 2.1 supporting AUDITWHEEL_PLAT - "CIBW_ENVIRONMENT": 'AUDITWHEEL_PLAT=`if [ $(uname -i) == "x86_64" ]; then echo "manylinux2010_x86_64"; else echo "manylinux1_i686"; fi`', - }, - ) + actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ + 'CIBW_MANYLINUX_X86_64_IMAGE': 'dockcross/manylinux2010-x64', + 'CIBW_MANYLINUX_I686_IMAGE': 'dockcross/manylinux2010-x86', + 'CIBW_SKIP': 'pp*', + }) # also check that we got the right wheels built - expected_wheels = [ - w - for w in utils.expected_wheels("spam", "0.1.0") - if "-manylinux2010_i686" not in w - ] + expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') + if '-pp' not in w] assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_09_cpp_standards.py b/test/test_09_cpp_standards.py index 32719df7..dcf39f72 100644 --- a/test/test_09_cpp_standards.py +++ b/test/test_09_cpp_standards.py @@ -7,14 +7,13 @@ from . import utils from .template_projects import SetuptoolsTemplateProject import jinja2 -# TODO: specify these at runtime according to manylinux_image cpp_project = SetuptoolsTemplateProject( setup_py_add='''ext_modules=[Extension('spam', sources=['spam.cpp'])],''' ) cpp_project.files['spam.cpp'] = jinja2.Template(r''' #include -{{ spam_cpp_add }} +{{ spam_cpp_top_level_add }} static PyObject * spam_system(PyObject *self, PyObject *args) @@ -64,28 +63,13 @@ MOD_INIT(spam) } ''') -spam_cpp_top_level_add = ''' -// Depending on the requested standard, use a modern C++ feature -// that was introduced in that standard. -#if STANDARD == 11 - #include -#elif STANDARD == 14 - int a = 100'000; -#elif STANDARD == 17 - #include - auto a = std::pair(5.0, false); -#else - #error Standard needed -#endif -''' - project_dir = os.path.dirname(__file__) def test_cpp11(tmpdir): # This test checks that the C++11 standard is supported project_dir = str(tmpdir) - cpp_project.template_context['spam_cpp_add'] = '#include ' + cpp_project.template_context['spam_cpp_top_level_add'] = '#include ' cpp_project.generate(project_dir) # VC++ for Python 2.7 does not support modern standards @@ -102,7 +86,7 @@ def test_cpp14(tmpdir): # This test checks that the C++14 standard is supported project_dir = str(tmpdir) - cpp_project.template_context['spam_cpp_add'] = "int a = 100'000;" + cpp_project.template_context['spam_cpp_top_level_add'] = "int a = 100'000;" cpp_project.generate(project_dir) # VC++ for Python 2.7 does not support modern standards @@ -123,7 +107,7 @@ def test_cpp17(tmpdir): # This test checks that the C++17 standard is supported project_dir = str(tmpdir) - cpp_project.template_context['spam_cpp_add'] = textwrap.dedent(''' + cpp_project.template_context['spam_cpp_top_level_add'] = textwrap.dedent(''' #include auto a = std::pair(5.0, false); ''') diff --git a/test/test_10_before_test.py b/test/test_10_before_test.py index 6455ac50..1573fc84 100644 --- a/test/test_10_before_test.py +++ b/test/test_10_before_test.py @@ -1,5 +1,5 @@ import os -import utils +from . import utils from test.template_projects.c import CTemplateProject before_test_project = CTemplateProject() diff --git a/test/test_12_subdir_package.py b/test/test_12_subdir_package.py index bd520110..45a283aa 100644 --- a/test/test_12_subdir_package.py +++ b/test/test_12_subdir_package.py @@ -1,5 +1,5 @@ import os -import utils +from . import utils from .template_projects.c import spam_c_template from .template_projects import TemplateProject @@ -35,8 +35,7 @@ def test(capfd, tmpdir): actual_wheels = utils.cibuildwheel_run(project_dir, package_dir=package_dir, add_env={ 'CIBW_BEFORE_BUILD': 'python {project}/bin/before_build.py', 'CIBW_TEST_COMMAND': 'python {package}/test/run_tests.py', - # this shouldn't depend on the version of python, so build only - # CPython 3.6 + # this shouldn't depend on the version of python, so build only CPython 3.6 'CIBW_BUILD': 'cp36-*', }) From 9bb075aa0b5e6c062ccba3a87924d305d1bd362a Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 2 May 2020 22:50:52 +0100 Subject: [PATCH 06/32] Fix flake8 errors --- test/README.md | 4 +--- test/template_projects/base.py | 2 +- test/test_01_basic.py | 13 +++++++------ test/test_02_testing.py | 10 ++++++---- test/test_03_before_build.py | 4 ++-- test/test_04_build_skip.py | 5 +++-- test/test_06_docker_images.py | 8 ++++++-- test/test_07_ssl.py | 5 +++-- test/test_08_manylinuxXXXX_only.py | 6 +++++- test/test_09_cpp_standards.py | 4 ++-- test/test_10_before_test.py | 4 ++-- 11 files changed, 38 insertions(+), 27 deletions(-) diff --git a/test/README.md b/test/README.md index d95aacea..5f34f5e9 100644 --- a/test/README.md +++ b/test/README.md @@ -1,3 +1 @@ -This folder contains repos that are built by cibuildwheel to test cibuildwheel. Confusing, I know. - -Basically, if cibuildwheel can build these projects, we're good. +This folder contains integration tests for cibuildwheel. diff --git a/test/template_projects/base.py b/test/template_projects/base.py index 7882e73a..81cf9afd 100644 --- a/test/template_projects/base.py +++ b/test/template_projects/base.py @@ -1,7 +1,7 @@ import os import io import jinja2 -from typing import Union, Dict, Any, Optional +from typing import Union, Dict, Any FilesDict = Dict[str, Union[str, jinja2.Template]] diff --git a/test/test_01_basic.py b/test/test_01_basic.py index 600e3416..de663848 100644 --- a/test/test_01_basic.py +++ b/test/test_01_basic.py @@ -1,5 +1,5 @@ -import os import textwrap +import platform from .template_projects import CTemplateProject from . import utils @@ -12,6 +12,7 @@ basic_project = CTemplateProject( ''') ) + def test(tmpdir): project_dir = str(tmpdir) basic_project.generate(project_dir) @@ -33,10 +34,10 @@ def test_build_identifiers(tmpdir): # after adding CIBW_MANYLINUX_IMAGE to support manylinux2010, there # can be multiple wheels for each wheel, though, so we need to limit # the expected wheels - expected_wheels = [ - w - for w in utils.expected_wheels("spam", "0.1.0") - if not "-manylinux" in w or "-manylinux1" in w - ] + if platform.machine() in ['x86_64', 'i686']: + expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') + if '-manylinux' not in w or '-manylinux1' in w] + else: + expected_wheels = utils.expected_wheels('spam', '0.1.0') build_identifiers = utils.cibuildwheel_get_build_identifiers(project_dir) assert len(expected_wheels) == len(build_identifiers) diff --git a/test/test_02_testing.py b/test/test_02_testing.py index 369f1505..37f1009f 100644 --- a/test/test_02_testing.py +++ b/test/test_02_testing.py @@ -1,5 +1,9 @@ -import os, subprocess -import pytest, textwrap +import os +import subprocess +import textwrap + +import pytest + from . import utils from .template_projects import CTemplateProject @@ -39,7 +43,6 @@ def test(tmpdir): assert set(actual_wheels) == set(expected_wheels) - def test_extras_require(tmpdir): project_dir = str(tmpdir) project_with_a_test.generate(project_dir) @@ -74,4 +77,3 @@ def test_failing_test(tmp_path): }) assert len(os.listdir(output_dir)) == 0 - diff --git a/test/test_03_before_build.py b/test/test_03_before_build.py index 58e51b2d..db81bb6b 100644 --- a/test/test_03_before_build.py +++ b/test/test_03_before_build.py @@ -1,8 +1,8 @@ -import os, textwrap +import textwrap + from . import utils from .template_projects import CTemplateProject - project_with_before_build_asserts = CTemplateProject( setup_py_add=textwrap.dedent(r''' import sys, os diff --git a/test/test_04_build_skip.py b/test/test_04_build_skip.py index 73f0de52..f6cb123a 100644 --- a/test/test_04_build_skip.py +++ b/test/test_04_build_skip.py @@ -1,8 +1,8 @@ -import os, textwrap +import textwrap + from . import utils from .template_projects import CTemplateProject - project_with_skip_asserts = CTemplateProject( setup_py_add=textwrap.dedent(r''' # explode if run on Python 2.7 or Python 3.7 (these should be skipped) @@ -13,6 +13,7 @@ project_with_skip_asserts = CTemplateProject( ''') ) + def test(tmpdir): project_dir = str(tmpdir) project_with_skip_asserts.generate(project_dir) diff --git a/test/test_06_docker_images.py b/test/test_06_docker_images.py index 5a0af5ce..c0254408 100644 --- a/test/test_06_docker_images.py +++ b/test/test_06_docker_images.py @@ -1,8 +1,11 @@ -import os, pytest, textwrap +import platform +import textwrap + +import pytest + from . import utils from .template_projects import CTemplateProject - dockcross_only_project = CTemplateProject( setup_py_add=textwrap.dedent(r''' import os, sys @@ -16,6 +19,7 @@ dockcross_only_project = CTemplateProject( ''') ) + def test(tmpdir): if utils.platform != 'linux': pytest.skip('the test is only relevant to the linux build') diff --git a/test/test_07_ssl.py b/test/test_07_ssl.py index 18440d3e..ae42fe77 100644 --- a/test/test_07_ssl.py +++ b/test/test_07_ssl.py @@ -1,8 +1,8 @@ -import os, textwrap +import textwrap + from . import utils from .template_projects import CTemplateProject - project_with_ssl_tests = CTemplateProject( setup_py_add=textwrap.dedent(r''' import ssl @@ -21,6 +21,7 @@ project_with_ssl_tests = CTemplateProject( ''') ) + def test(tmpdir): # this test checks that SSL is working in the build environment using # some checks in setup.py. diff --git a/test/test_08_manylinuxXXXX_only.py b/test/test_08_manylinuxXXXX_only.py index 07db23eb..25aa6255 100644 --- a/test/test_08_manylinuxXXXX_only.py +++ b/test/test_08_manylinuxXXXX_only.py @@ -1,4 +1,8 @@ -import os, pytest, textwrap, platform +import platform +import textwrap + +import pytest + from . import utils from .template_projects import CTemplateProject diff --git a/test/test_09_cpp_standards.py b/test/test_09_cpp_standards.py index dcf39f72..108775b7 100644 --- a/test/test_09_cpp_standards.py +++ b/test/test_09_cpp_standards.py @@ -1,15 +1,16 @@ import os import textwrap +import jinja2 import pytest from . import utils from .template_projects import SetuptoolsTemplateProject -import jinja2 cpp_project = SetuptoolsTemplateProject( setup_py_add='''ext_modules=[Extension('spam', sources=['spam.cpp'])],''' ) + cpp_project.files['spam.cpp'] = jinja2.Template(r''' #include @@ -63,7 +64,6 @@ MOD_INIT(spam) } ''') -project_dir = os.path.dirname(__file__) def test_cpp11(tmpdir): # This test checks that the C++11 standard is supported diff --git a/test/test_10_before_test.py b/test/test_10_before_test.py index 1573fc84..46b3dce3 100644 --- a/test/test_10_before_test.py +++ b/test/test_10_before_test.py @@ -1,6 +1,5 @@ -import os +from .template_projects.c import CTemplateProject from . import utils -from test.template_projects.c import CTemplateProject before_test_project = CTemplateProject() before_test_project.files['test/spam_test.py'] = r''' @@ -34,6 +33,7 @@ class TestBeforeTest(TestCase): assert os.stat(stored_prefix) == os.stat(sys.prefix) ''' + def test(tmpdir): project_dir = str(tmpdir) before_test_project.generate(project_dir) From a204df819b0ee46988ea57481b5d566ac334779e Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 2 May 2020 22:51:40 +0100 Subject: [PATCH 07/32] Add .mypy_cache to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index ed7b532f..3241171a 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,6 @@ env3?/ # VSCode project settings /.vscode + +# mypy +.mypy_cache From 662612685c41cc6f0d77f0f1444245b7d9475a2f Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 2 May 2020 22:53:58 +0100 Subject: [PATCH 08/32] Rename tests to remove the number, but keep 'basic' as the first --- test/{test_01_basic.py => test_0_basic.py} | 0 test/{test_03_before_build.py => test_before_build.py} | 0 test/{test_10_before_test.py => test_before_test.py} | 0 test/{test_04_build_skip.py => test_build_skip.py} | 0 test/{test_09_cpp_standards.py => test_cpp_standards.py} | 0 ...test_11_dependency_versions.py => test_dependency_versions.py} | 0 test/{test_06_docker_images.py => test_docker_images.py} | 0 test/{test_05_environment.py => test_environment.py} | 0 .../{test_08_manylinuxXXXX_only.py => test_manylinuxXXXX_only.py} | 0 test/{test_07_ssl.py => test_ssl.py} | 0 test/{test_12_subdir_package.py => test_subdir_package.py} | 0 test/{test_02_testing.py => test_testing.py} | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename test/{test_01_basic.py => test_0_basic.py} (100%) rename test/{test_03_before_build.py => test_before_build.py} (100%) rename test/{test_10_before_test.py => test_before_test.py} (100%) rename test/{test_04_build_skip.py => test_build_skip.py} (100%) rename test/{test_09_cpp_standards.py => test_cpp_standards.py} (100%) rename test/{test_11_dependency_versions.py => test_dependency_versions.py} (100%) rename test/{test_06_docker_images.py => test_docker_images.py} (100%) rename test/{test_05_environment.py => test_environment.py} (100%) rename test/{test_08_manylinuxXXXX_only.py => test_manylinuxXXXX_only.py} (100%) rename test/{test_07_ssl.py => test_ssl.py} (100%) rename test/{test_12_subdir_package.py => test_subdir_package.py} (100%) rename test/{test_02_testing.py => test_testing.py} (100%) diff --git a/test/test_01_basic.py b/test/test_0_basic.py similarity index 100% rename from test/test_01_basic.py rename to test/test_0_basic.py diff --git a/test/test_03_before_build.py b/test/test_before_build.py similarity index 100% rename from test/test_03_before_build.py rename to test/test_before_build.py diff --git a/test/test_10_before_test.py b/test/test_before_test.py similarity index 100% rename from test/test_10_before_test.py rename to test/test_before_test.py diff --git a/test/test_04_build_skip.py b/test/test_build_skip.py similarity index 100% rename from test/test_04_build_skip.py rename to test/test_build_skip.py diff --git a/test/test_09_cpp_standards.py b/test/test_cpp_standards.py similarity index 100% rename from test/test_09_cpp_standards.py rename to test/test_cpp_standards.py diff --git a/test/test_11_dependency_versions.py b/test/test_dependency_versions.py similarity index 100% rename from test/test_11_dependency_versions.py rename to test/test_dependency_versions.py diff --git a/test/test_06_docker_images.py b/test/test_docker_images.py similarity index 100% rename from test/test_06_docker_images.py rename to test/test_docker_images.py diff --git a/test/test_05_environment.py b/test/test_environment.py similarity index 100% rename from test/test_05_environment.py rename to test/test_environment.py diff --git a/test/test_08_manylinuxXXXX_only.py b/test/test_manylinuxXXXX_only.py similarity index 100% rename from test/test_08_manylinuxXXXX_only.py rename to test/test_manylinuxXXXX_only.py diff --git a/test/test_07_ssl.py b/test/test_ssl.py similarity index 100% rename from test/test_07_ssl.py rename to test/test_ssl.py diff --git a/test/test_12_subdir_package.py b/test/test_subdir_package.py similarity index 100% rename from test/test_12_subdir_package.py rename to test/test_subdir_package.py diff --git a/test/test_02_testing.py b/test/test_testing.py similarity index 100% rename from test/test_02_testing.py rename to test/test_testing.py From 5d665aac39e4adebedccf67c6684ca4c5e373d1c Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 2 May 2020 22:57:03 +0100 Subject: [PATCH 09/32] Fix up test runner scripts --- bin/dev_run_test | 5 +---- bin/run_test.py | 27 --------------------------- bin/run_tests.py | 17 +---------------- 3 files changed, 2 insertions(+), 47 deletions(-) delete mode 100755 bin/run_test.py diff --git a/bin/dev_run_test b/bin/dev_run_test index 86500be2..6515c6b3 100755 --- a/bin/dev_run_test +++ b/bin/dev_run_test @@ -1,6 +1,3 @@ #!/bin/bash -cd "$(dirname "$0")" -cd .. - -CIBW_PLATFORM=linux ./bin/run_test.py $1 +CIBW_PLATFORM=linux pytest $1 diff --git a/bin/run_test.py b/bin/run_test.py deleted file mode 100755 index bee65de4..00000000 --- a/bin/run_test.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import os -import subprocess -import sys - - -def single_run(test_project): - # run the test - subprocess.check_call( - [sys.executable, '-m', 'pytest', '-vv', os.path.join(test_project, 'cibuildwheel_test.py')], - ) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("test_project_dir") - args = parser.parse_args() - - project_path = os.path.abspath(args.test_project_dir) - - if not os.path.exists(project_path): - print('No test project not found.', file=sys.stderr) - exit(2) - - single_run(project_path) diff --git a/bin/run_tests.py b/bin/run_tests.py index 4963a883..1880d4f1 100755 --- a/bin/run_tests.py +++ b/bin/run_tests.py @@ -3,28 +3,13 @@ import os import subprocess import sys -from glob import glob if __name__ == '__main__': # move cwd to the project root os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # run the unit tests - subprocess.check_call([sys.executable, '-m', 'pytest', 'unit_test']) # run the integration tests - - test_projects = sorted(glob('test/??_*')) - - if len(test_projects) == 0: - print('No test projects found. Aborting.', file=sys.stderr) - exit(2) - - print('Testing projects:', test_projects) - - run_test_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'run_test.py') - for project_path in test_projects: - subprocess.check_call([sys.executable, run_test_path, project_path]) - - print('%d projects built successfully.' % len(test_projects)) + subprocess.check_call([sys.executable, '-m', 'pytest', 'test']) From ffd5d44cdc71ba33dbaab19e618bcdc8f4613592 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 3 May 2020 10:30:44 +0100 Subject: [PATCH 10/32] Fix C++ tests --- test/template_projects/base.py | 6 +++++ test/test_cpp_standards.py | 40 +++++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/test/template_projects/base.py b/test/template_projects/base.py index 81cf9afd..2daf53a8 100644 --- a/test/template_projects/base.py +++ b/test/template_projects/base.py @@ -26,3 +26,9 @@ class TemplateProject: content = content.render(self.template_context) f.write(content) + + def copy(self): + other = TemplateProject() + other.files = self.files.copy() + other.template_context = self.template_context.copy() + return other diff --git a/test/test_cpp_standards.py b/test/test_cpp_standards.py index 108775b7..d5c5708a 100644 --- a/test/test_cpp_standards.py +++ b/test/test_cpp_standards.py @@ -5,13 +5,21 @@ import jinja2 import pytest from . import utils -from .template_projects import SetuptoolsTemplateProject +from .template_projects import TemplateProject -cpp_project = SetuptoolsTemplateProject( - setup_py_add='''ext_modules=[Extension('spam', sources=['spam.cpp'])],''' +cpp_template_project = TemplateProject() + +cpp_template_project.files['setup.py'] = jinja2.Template(r''' +from setuptools import Extension, setup + +setup( + name="spam", + ext_modules=[Extension('spam', sources=['spam.cpp'], language="c++", extra_compile_args={{ extra_compile_args }})], + version="0.1.0", ) +''') -cpp_project.files['spam.cpp'] = jinja2.Template(r''' +cpp_template_project.files['spam.cpp'] = jinja2.Template(r''' #include {{ spam_cpp_top_level_add }} @@ -69,8 +77,11 @@ def test_cpp11(tmpdir): # This test checks that the C++11 standard is supported project_dir = str(tmpdir) - cpp_project.template_context['spam_cpp_top_level_add'] = '#include ' - cpp_project.generate(project_dir) + project = cpp_template_project.copy() + extra_compile_args = ['/std:c++11'] if utils.platform == 'windows' else ['-std=c++11'] + project.template_context['extra_compile_args'] = extra_compile_args + project.template_context['spam_cpp_top_level_add'] = '#include ' + project.generate(project_dir) # VC++ for Python 2.7 does not support modern standards add_env = {'CIBW_SKIP': 'cp27-win* pp27-win32'} @@ -86,8 +97,11 @@ def test_cpp14(tmpdir): # This test checks that the C++14 standard is supported project_dir = str(tmpdir) - cpp_project.template_context['spam_cpp_top_level_add'] = "int a = 100'000;" - cpp_project.generate(project_dir) + project = cpp_template_project.copy() + extra_compile_args = ['/std:c++14'] if utils.platform == 'windows' else ['-std=c++14'] + project.template_context['extra_compile_args'] = extra_compile_args + project.template_context['spam_cpp_top_level_add'] = "int a = 100'000;" + project.generate(project_dir) # VC++ for Python 2.7 does not support modern standards # The manylinux1 docker image does not have a compiler which supports C++11 @@ -107,11 +121,17 @@ def test_cpp17(tmpdir): # This test checks that the C++17 standard is supported project_dir = str(tmpdir) - cpp_project.template_context['spam_cpp_top_level_add'] = textwrap.dedent(''' + project = cpp_template_project.copy() + if utils.platform == 'windows': + project.template_context['extra_compile_args'] = ['/std:c++17', '/wd5033'] + else: + project.template_context['extra_compile_args'] = ['-std=c++17', '-Wno-register'] + + project.template_context['spam_cpp_top_level_add'] = textwrap.dedent(''' #include auto a = std::pair(5.0, false); ''') - cpp_project.generate(project_dir) + project.generate(project_dir) # Python and PyPy 2.7 use the `register` keyword which is forbidden in the C++17 standard # The manylinux1 docker image does not have a compiler which supports C++11 From e2cafa487b71a64aadc8e52ead0db5fe61e8a6ed Mon Sep 17 00:00:00 2001 From: Yannick Jadoul Date: Fri, 10 Apr 2020 02:00:29 +0200 Subject: [PATCH 11/32] Cherry pick: Drop 3.5 host support and adapt CI configurations --- CI.md | 12 ++++++------ azure-pipelines.yml | 10 ---------- examples/travis-ci-test-and-deploy.yml | 1 - setup.py | 2 +- 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/CI.md b/CI.md index cd964a41..1b7c3552 100644 --- a/CI.md +++ b/CI.md @@ -1,11 +1,11 @@ This is a summary of the Python versions and platforms covered by the different CI platforms: -| | 3.5 | 3.6 | 3.7 | 3.8 | -|----------|------------------|------------------|---------------------------------------------------|------------------| -| Linux | Travis CI | CircleCI | AppVeyor / GitHub Actions | Azure Pipelines | -| macOS | Azure Pipelines | CircleCI | AppVeyor / Travis CI¹ / CircleCI / GitHub Actions | Azure Pipelines | -| Windows | TravisCI | Azure Pipelines | AppVeyor / GitHub Actions | Azure Pipelines | +| | 3.6 | 3.7 | 3.8 | +|----------|------------------------------|---------------------------------------------------|------------------| +| Linux | Travis CI / CircleCI | AppVeyor / GitHub Actions | Azure Pipelines | +| macOS | CircleCI | AppVeyor / Travis CI¹ / CircleCI / GitHub Actions | Azure Pipelines | +| Windows | Travis CI / Azure Pipelines | AppVeyor / GitHub Actions | Azure Pipelines | > ¹ Python version not really pinned, but dependent on the (default) version of image used. -Non-x86 architectures are covered on Travis CI using Python 3.5. +Non-x86 architectures are covered on Travis CI using Python 3.6. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4b5aabd3..b2d324be 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,16 +9,6 @@ jobs: python -m pip install -r requirements-dev.txt python ./bin/run_tests.py -- job: macos_35 - pool: {vmImage: 'macOS-10.15'} - steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '3.5' - - bash: | - python -m pip install -r requirements-dev.txt - python ./bin/run_tests.py - - job: macos_38 pool: {vmImage: 'macOS-10.15'} steps: diff --git a/examples/travis-ci-test-and-deploy.yml b/examples/travis-ci-test-and-deploy.yml index 9fff17e0..e20d2fad 100644 --- a/examples/travis-ci-test-and-deploy.yml +++ b/examples/travis-ci-test-and-deploy.yml @@ -7,7 +7,6 @@ language: python python: - - 3.5 - 3.6 - 3.7 - 3.8 diff --git a/setup.py b/setup.py index 89fbce52..4c721135 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ setup( 'cibuildwheel': ['resources/*'], }, # Supported python versions - python_requires='>=3.5', + python_requires='>=3.6', keywords='ci wheel packaging pypi travis appveyor macos linux windows', classifiers=[ 'Intended Audience :: Developers', From 33f210b85c4e6a9f4d9415604b731da8b02b2134 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 3 May 2020 10:37:41 +0100 Subject: [PATCH 12/32] Remove 'setuptools' template project --- test/template_projects/__init__.py | 1 - test/template_projects/c.py | 37 +++++++++++++++++++-------- test/template_projects/setuptools.py | 38 ---------------------------- 3 files changed, 27 insertions(+), 49 deletions(-) delete mode 100644 test/template_projects/setuptools.py diff --git a/test/template_projects/__init__.py b/test/template_projects/__init__.py index d9346449..d83df0e4 100644 --- a/test/template_projects/__init__.py +++ b/test/template_projects/__init__.py @@ -1,3 +1,2 @@ from .base import TemplateProject # noqa from .c import CTemplateProject # noqa -from .setuptools import SetuptoolsTemplateProject # noqa diff --git a/test/template_projects/c.py b/test/template_projects/c.py index e1a24ca7..151cc574 100644 --- a/test/template_projects/c.py +++ b/test/template_projects/c.py @@ -1,5 +1,5 @@ import jinja2 -from .setuptools import SetuptoolsTemplateProject +from .base import TemplateProject spam_c_template = r''' @@ -59,25 +59,42 @@ MOD_INIT(spam) } ''' +setup_py_template = r''' +from setuptools import setup, Extension -class CTemplateProject(SetuptoolsTemplateProject): +{{ setup_py_add }} + +setup( + ext_modules=[Extension('spam', sources=['spam.c'])], + {{ setup_py_setup_args_add | indent(4) }} +) +''' + +setup_cfg_template = r''' +[metadata] +name = spam +version = 0.1.0 + +{{ setup_cfg_add }} +''' + + +class CTemplateProject(TemplateProject): def __init__(self, *, spam_c_top_level_add='', spam_c_function_add='', setup_py_add='', setup_py_setup_args_add='', setup_cfg_add=''): - setup_py_setup_args_add += ''' - ext_modules=[Extension('spam', sources=['spam.c'])], - ''' - super().__init__( - setup_py_add=setup_py_add, - setup_py_setup_args_add=setup_py_setup_args_add, - setup_cfg_add=setup_cfg_add - ) + super().__init__() self.files.update({ 'spam.c': jinja2.Template(spam_c_template), + 'setup.py': jinja2.Template(setup_py_template), + 'setup.cfg': jinja2.Template(setup_cfg_template), }) self.template_context.update({ 'spam_c_top_level_add': spam_c_top_level_add, 'spam_c_function_add': spam_c_function_add, + 'setup_py_add': setup_py_add, + 'setup_py_setup_args_add': setup_py_setup_args_add, + 'setup_cfg_add': setup_cfg_add, }) diff --git a/test/template_projects/setuptools.py b/test/template_projects/setuptools.py deleted file mode 100644 index 6dcbfe23..00000000 --- a/test/template_projects/setuptools.py +++ /dev/null @@ -1,38 +0,0 @@ - -import jinja2 -from .base import TemplateProject - - -setup_py_template = r''' -from setuptools import setup, Extension - -{{ setup_py_add }} - -setup( - {{ setup_py_setup_args_add | indent(4) }} -) -''' - -setup_cfg_template = r''' -[metadata] -name = spam -version = 0.1.0 - -{{ setup_cfg_add }} -''' - - -class SetuptoolsTemplateProject(TemplateProject): - def __init__(self, *, setup_py_add='', setup_py_setup_args_add='', setup_cfg_add=''): - super().__init__() - - self.files.update({ - 'setup.py': jinja2.Template(setup_py_template), - 'setup.cfg': jinja2.Template(setup_cfg_template), - }) - - self.template_context.update({ - 'setup_py_add': setup_py_add, - 'setup_py_setup_args_add': setup_py_setup_args_add, - 'setup_cfg_add': setup_cfg_add, - }) From dafe5cd1f7ff5393a3278daa6a4b714b49d937da Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 3 May 2020 14:08:57 +0100 Subject: [PATCH 13/32] Refactor to use tmp_path and pathlib paths --- test/test_0_basic.py | 8 ++++---- test/test_before_build.py | 4 ++-- test/test_before_test.py | 4 ++-- test/test_build_skip.py | 4 ++-- test/test_cpp_standards.py | 12 ++++++------ test/test_dependency_versions.py | 6 +++--- test/test_docker_images.py | 4 ++-- test/test_environment.py | 8 ++++---- test/test_manylinuxXXXX_only.py | 4 ++-- test/test_ssl.py | 4 ++-- test/test_subdir_package.py | 4 ++-- test/test_testing.py | 12 ++++++------ 12 files changed, 37 insertions(+), 37 deletions(-) diff --git a/test/test_0_basic.py b/test/test_0_basic.py index de663848..5bf16822 100644 --- a/test/test_0_basic.py +++ b/test/test_0_basic.py @@ -13,8 +13,8 @@ basic_project = CTemplateProject( ) -def test(tmpdir): - project_dir = str(tmpdir) +def test(tmp_path): + project_dir = tmp_path / 'project' basic_project.generate(project_dir) # build the wheels @@ -25,8 +25,8 @@ def test(tmpdir): assert set(actual_wheels) == set(expected_wheels) -def test_build_identifiers(tmpdir): - project_dir = str(tmpdir) +def test_build_identifiers(tmp_path): + project_dir = tmp_path / 'project' basic_project.generate(project_dir) # check that the number of expected wheels matches the number of build diff --git a/test/test_before_build.py b/test/test_before_build.py index db81bb6b..b1715238 100644 --- a/test/test_before_build.py +++ b/test/test_before_build.py @@ -28,8 +28,8 @@ project_with_before_build_asserts = CTemplateProject( ) -def test(tmpdir): - project_dir = str(tmpdir) +def test(tmp_path): + project_dir = tmp_path / 'project' project_with_before_build_asserts.generate(project_dir) # build the wheels diff --git a/test/test_before_test.py b/test/test_before_test.py index 46b3dce3..988f7b33 100644 --- a/test/test_before_test.py +++ b/test/test_before_test.py @@ -34,8 +34,8 @@ class TestBeforeTest(TestCase): ''' -def test(tmpdir): - project_dir = str(tmpdir) +def test(tmp_path): + project_dir = tmp_path / 'project' before_test_project.generate(project_dir) # build the wheels diff --git a/test/test_build_skip.py b/test/test_build_skip.py index f6cb123a..30bba181 100644 --- a/test/test_build_skip.py +++ b/test/test_build_skip.py @@ -14,8 +14,8 @@ project_with_skip_asserts = CTemplateProject( ) -def test(tmpdir): - project_dir = str(tmpdir) +def test(tmp_path): + project_dir = tmp_path / 'project' project_with_skip_asserts.generate(project_dir) # build the wheels diff --git a/test/test_cpp_standards.py b/test/test_cpp_standards.py index d5c5708a..c00c6791 100644 --- a/test/test_cpp_standards.py +++ b/test/test_cpp_standards.py @@ -73,9 +73,9 @@ MOD_INIT(spam) ''') -def test_cpp11(tmpdir): +def test_cpp11(tmp_path): # This test checks that the C++11 standard is supported - project_dir = str(tmpdir) + project_dir = tmp_path / 'project' project = cpp_template_project.copy() extra_compile_args = ['/std:c++11'] if utils.platform == 'windows' else ['-std=c++11'] @@ -93,9 +93,9 @@ def test_cpp11(tmpdir): assert set(actual_wheels) == set(expected_wheels) -def test_cpp14(tmpdir): +def test_cpp14(tmp_path): # This test checks that the C++14 standard is supported - project_dir = str(tmpdir) + project_dir = tmp_path / 'project' project = cpp_template_project.copy() extra_compile_args = ['/std:c++14'] if utils.platform == 'windows' else ['-std=c++14'] @@ -117,9 +117,9 @@ def test_cpp14(tmpdir): assert set(actual_wheels) == set(expected_wheels) -def test_cpp17(tmpdir): +def test_cpp17(tmp_path): # This test checks that the C++17 standard is supported - project_dir = str(tmpdir) + project_dir = tmp_path / 'project' project = cpp_template_project.copy() if utils.platform == 'windows': diff --git a/test/test_dependency_versions.py b/test/test_dependency_versions.py index c4f899ae..c290c971 100644 --- a/test/test_dependency_versions.py +++ b/test/test_dependency_versions.py @@ -51,11 +51,11 @@ def get_versions_from_constraint_file(constraint_file): @pytest.mark.parametrize('python_version', ['2.7', '3.5', '3.8']) -def test_pinned_versions(tmpdir, python_version): +def test_pinned_versions(tmp_path, python_version): if utils.platform == 'linux': pytest.skip('linux doesn\'t pin individual tool versions, it pins manylinux images instead') - project_dir = str(tmpdir) + project_dir = tmp_path / 'project' project_with_expected_version_checks.generate(project_dir) build_environment = {} @@ -108,7 +108,7 @@ def test_dependency_constraints_file(tmp_path, python_version): if utils.platform == 'linux': pytest.skip('linux doesn\'t pin individual tool versions, it pins manylinux images instead') - project_dir = str(tmp_path / 'project') + project_dir = tmp_path / 'project' project_with_expected_version_checks.generate(project_dir) tool_versions = { diff --git a/test/test_docker_images.py b/test/test_docker_images.py index c0254408..725779f2 100644 --- a/test/test_docker_images.py +++ b/test/test_docker_images.py @@ -20,13 +20,13 @@ dockcross_only_project = CTemplateProject( ) -def test(tmpdir): +def test(tmp_path): if utils.platform != 'linux': pytest.skip('the test is only relevant to the linux build') if platform.machine() not in ['x86_64', 'i686']: pytest.skip('this test is currently only possible on x86_64/i686 due to availability of alternative images') - project_dir = str(tmpdir) + project_dir = tmp_path / 'project' dockcross_only_project.generate(project_dir) actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ diff --git a/test/test_environment.py b/test/test_environment.py index 5e4b9ee6..0d9eb103 100644 --- a/test/test_environment.py +++ b/test/test_environment.py @@ -27,8 +27,8 @@ project_with_environment_asserts = CTemplateProject( ) -def test(tmpdir): - project_dir = str(tmpdir) +def test(tmp_path): + project_dir = tmp_path / 'project' project_with_environment_asserts.generate(project_dir) # write some information into the CIBW_ENVIRONMENT, for expansion and @@ -45,8 +45,8 @@ def test(tmpdir): def test_overridden_path(tmp_path): - project_dir = str(tmp_path / 'project') - output_dir = str(tmp_path / 'output') + project_dir = tmp_path / 'project' + output_dir = tmp_path / 'output' CTemplateProject().generate(project_dir) # mess up PATH, somehow diff --git a/test/test_manylinuxXXXX_only.py b/test/test_manylinuxXXXX_only.py index 25aa6255..e3753ea9 100644 --- a/test/test_manylinuxXXXX_only.py +++ b/test/test_manylinuxXXXX_only.py @@ -33,14 +33,14 @@ project_with_manylinux_symbols = CTemplateProject( @pytest.mark.parametrize('manylinux_image', ['manylinux1', 'manylinux2010', 'manylinux2014']) -def test(manylinux_image, tmpdir): +def test(manylinux_image, tmp_path): if utils.platform != 'linux': pytest.skip('the docker test is only relevant to the linux build') elif platform.machine() not in ['x86_64', 'i686']: if manylinux_image in ['manylinux1', 'manylinux2010']: pytest.skip("manylinux1 and 2010 doesn't exist for non-x86 architectures") - project_dir = str(tmpdir) + project_dir = tmp_path / 'project' project_with_manylinux_symbols.generate(project_dir) # build the wheels diff --git a/test/test_ssl.py b/test/test_ssl.py index ae42fe77..eddb4074 100644 --- a/test/test_ssl.py +++ b/test/test_ssl.py @@ -22,10 +22,10 @@ project_with_ssl_tests = CTemplateProject( ) -def test(tmpdir): +def test(tmp_path): # this test checks that SSL is working in the build environment using # some checks in setup.py. - project_dir = str(tmpdir) + project_dir = tmp_path / 'project' project_with_ssl_tests.generate(project_dir) utils.cibuildwheel_run(project_dir) diff --git a/test/test_subdir_package.py b/test/test_subdir_package.py index 45a283aa..ebfebcf2 100644 --- a/test/test_subdir_package.py +++ b/test/test_subdir_package.py @@ -26,8 +26,8 @@ print('before_build.py executed!') ''' -def test(capfd, tmpdir): - project_dir = str(tmpdir) +def test(capfd, tmp_path): + project_dir = tmp_path / 'project' subdir_package_project.generate(project_dir) package_dir = os.path.join(project_dir, 'src', 'spam') diff --git a/test/test_testing.py b/test/test_testing.py index 37f1009f..ed60fded 100644 --- a/test/test_testing.py +++ b/test/test_testing.py @@ -25,8 +25,8 @@ class TestSpam(TestCase): ''' -def test(tmpdir): - project_dir = str(tmpdir) +def test(tmp_path): + project_dir = tmp_path / 'project' project_with_a_test.generate(project_dir) # build and test the wheels @@ -43,8 +43,8 @@ def test(tmpdir): assert set(actual_wheels) == set(expected_wheels) -def test_extras_require(tmpdir): - project_dir = str(tmpdir) +def test_extras_require(tmp_path): + project_dir = tmp_path / 'project' project_with_a_test.generate(project_dir) # build and test the wheels @@ -63,8 +63,8 @@ def test_extras_require(tmpdir): def test_failing_test(tmp_path): """Ensure a failing test causes cibuildwheel to error out and exit""" - project_dir = str(tmp_path / 'project') - output_dir = str(tmp_path / 'output') + project_dir = tmp_path / 'project' + output_dir = tmp_path / 'output' project_with_a_test.generate(project_dir) with pytest.raises(subprocess.CalledProcessError): From e9803e8fb380eab8c60d9898c4cbafef3fe13185 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 3 May 2020 14:09:10 +0100 Subject: [PATCH 14/32] Fix missing dir --- test/test_environment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_environment.py b/test/test_environment.py index 0d9eb103..ce45990a 100644 --- a/test/test_environment.py +++ b/test/test_environment.py @@ -48,6 +48,7 @@ def test_overridden_path(tmp_path): project_dir = tmp_path / 'project' output_dir = tmp_path / 'output' CTemplateProject().generate(project_dir) + output_dir.mkdir() # mess up PATH, somehow with pytest.raises(subprocess.CalledProcessError): From c568f7ba89da53654162ed04ce64117f5c0b9f99 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 3 May 2020 14:09:35 +0100 Subject: [PATCH 15/32] Add pytest-azurepipelines plugin --- azure-pipelines.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b2d324be..4fb53b11 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -6,7 +6,7 @@ jobs: inputs: versionSpec: '3.8' - bash: | - python -m pip install -r requirements-dev.txt + python -m pip install -r requirements-dev.txt pytest-azurepipelines python ./bin/run_tests.py - job: macos_38 @@ -16,7 +16,7 @@ jobs: inputs: versionSpec: '3.8' - bash: | - python -m pip install -r requirements-dev.txt + python -m pip install -r requirements-dev.txt pytest-azurepipelines python ./bin/run_tests.py - job: windows_36 @@ -28,7 +28,7 @@ jobs: - script: choco install vcpython27 -f -y displayName: Install Visual C++ for Python 2.7 - bash: | - python -m pip install -r requirements-dev.txt + python -m pip install -r requirements-dev.txt pytest-azurepipelines python ./bin/run_tests.py - job: windows_38 @@ -40,6 +40,6 @@ jobs: - script: choco install vcpython27 -f -y displayName: Install Visual C++ for Python 2.7 - bash: | - python -m pip install -r requirements-dev.txt + python -m pip install -r requirements-dev.txt pytest-azurepipelines python ./bin/run_tests.py From 1b38974c602d6d6b198df84020dfefdc40d3ccd0 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 3 May 2020 14:09:47 +0100 Subject: [PATCH 16/32] Fix subdir test --- test/test_subdir_package.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/test_subdir_package.py b/test/test_subdir_package.py index ebfebcf2..67e3eef6 100644 --- a/test/test_subdir_package.py +++ b/test/test_subdir_package.py @@ -1,11 +1,16 @@ import os + +import jinja2 + from . import utils -from .template_projects.c import spam_c_template from .template_projects import TemplateProject +from .template_projects.c import spam_c_template subdir_package_project = TemplateProject() -subdir_package_project.files['src/spam/spam.c'] = spam_c_template +subdir_package_project.files['src/spam/spam.c'] = jinja2.Template(spam_c_template) +subdir_package_project.template_context['spam_c_top_level_add'] = '' +subdir_package_project.template_context['spam_c_function_add'] = '' subdir_package_project.files['src/spam/setup.py'] = r''' from setuptools import Extension, setup From bf882b065db3952297cfa85538c1e204440ea293 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 3 May 2020 14:18:57 +0100 Subject: [PATCH 17/32] Output test timings --- bin/run_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/run_tests.py b/bin/run_tests.py index 1880d4f1..e3275f3f 100755 --- a/bin/run_tests.py +++ b/bin/run_tests.py @@ -12,4 +12,4 @@ if __name__ == '__main__': subprocess.check_call([sys.executable, '-m', 'pytest', 'unit_test']) # run the integration tests - subprocess.check_call([sys.executable, '-m', 'pytest', 'test']) + subprocess.check_call([sys.executable, '-m', 'pytest', '--durations', '0', 'test']) From 566a88009971e25be88919120b521f01bc2af241 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 3 May 2020 16:52:35 +0100 Subject: [PATCH 18/32] Fix warning --- setup.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.cfg b/setup.cfg index c5d51ac7..600c4dff 100644 --- a/setup.cfg +++ b/setup.cfg @@ -11,3 +11,6 @@ exclude = env??/, .venv/, site/ + +[pytest] +junit_family=xunit2 From a9c475a910bc23d69add930685a6280c2b0087c5 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 3 May 2020 16:53:15 +0100 Subject: [PATCH 19/32] Fix pathlib error on Windows --- test/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils.py b/test/utils.py index 609ab9d7..1c2733c6 100644 --- a/test/utils.py +++ b/test/utils.py @@ -33,7 +33,7 @@ def cibuildwheel_get_build_identifiers(project_path, env=None): for the current platform. ''' cmd_output = subprocess.check_output( - [sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers', project_path], + [sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers', str(project_path)], universal_newlines=True, env=env, ) From 729bab42c8d8a2d5c27b2c02843004cb0667b81b Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 3 May 2020 17:03:35 +0100 Subject: [PATCH 20/32] Pytest config header --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 600c4dff..bb41055e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,5 +12,5 @@ exclude = .venv/, site/ -[pytest] +[tool:pytest] junit_family=xunit2 From 73425d4bb8b42717953b816bd71f91ec2e638e43 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Tue, 5 May 2020 21:32:57 +0100 Subject: [PATCH 21/32] Fix indent --- test/test_cpp_standards.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_cpp_standards.py b/test/test_cpp_standards.py index c00c6791..3cc18917 100644 --- a/test/test_cpp_standards.py +++ b/test/test_cpp_standards.py @@ -128,8 +128,8 @@ def test_cpp17(tmp_path): project.template_context['extra_compile_args'] = ['-std=c++17', '-Wno-register'] project.template_context['spam_cpp_top_level_add'] = textwrap.dedent(''' - #include - auto a = std::pair(5.0, false); + #include + auto a = std::pair(5.0, false); ''') project.generate(project_dir) From da4bc0225c119c21810b9db75cdc9f3f417db6f8 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Tue, 5 May 2020 21:56:34 +0100 Subject: [PATCH 22/32] Fix new cpp17 test --- test/test_cpp_standards.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/test/test_cpp_standards.py b/test/test_cpp_standards.py index 5c73a9bc..9779d12e 100644 --- a/test/test_cpp_standards.py +++ b/test/test_cpp_standards.py @@ -1,5 +1,4 @@ import os -import textwrap import jinja2 import pytest @@ -115,21 +114,24 @@ def test_cpp14(tmp_path): assert set(actual_wheels) == set(expected_wheels) +cpp17_project = cpp_template_project.copy() + +if utils.platform == 'windows': + cpp17_project.template_context['extra_compile_args'] = ['/std:c++17', '/wd5033'] +else: + cpp17_project.template_context['extra_compile_args'] = ['-std=c++17', '-Wno-register'] + +cpp17_project.template_context['spam_cpp_top_level_add'] = r''' +#include +auto a = std::pair(5.0, false); +''' + + def test_cpp17(tmp_path): # This test checks that the C++17 standard is supported project_dir = tmp_path / 'project' - project = cpp_template_project.copy() - if utils.platform == 'windows': - project.template_context['extra_compile_args'] = ['/std:c++17', '/wd5033'] - else: - project.template_context['extra_compile_args'] = ['-std=c++17', '-Wno-register'] - - project.template_context['spam_cpp_top_level_add'] = textwrap.dedent(''' - #include - auto a = std::pair(5.0, false); - ''') - project.generate(project_dir) + cpp17_project.generate(project_dir) # Python and PyPy 2.7 use the `register` keyword which is forbidden in the C++17 standard # The manylinux1 docker image does not have a compiler which supports C++11 @@ -150,7 +152,7 @@ def test_cpp17(tmp_path): assert set(actual_wheels) == set(expected_wheels) -def test_cpp17_py27_modern_msvc_workaround(): +def test_cpp17_py27_modern_msvc_workaround(tmp_path): # This test checks the workaround for building Python 2.7 wheel with MSVC 14 if utils.platform != 'windows': @@ -159,6 +161,9 @@ def test_cpp17_py27_modern_msvc_workaround(): if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') == 'Visual Studio 2015': pytest.skip('Visual Studio 2015 does not support C++17') + project_dir = tmp_path / 'project' + cpp17_project.generate(project_dir) + # VC++ for Python 2.7 (i.e., MSVC 9) does not support modern standards # This is a workaround which forces distutils/setupstools to a newer version # Wheels compiled need a more modern C++ redistributable installed, which is not From dbd70067040b864e00eb8d2f9f388e15a317e1e1 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Wed, 6 May 2020 19:51:58 +0100 Subject: [PATCH 23/32] Remove dead code from merge --- test/test_cpp_standards.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/test_cpp_standards.py b/test/test_cpp_standards.py index 9779d12e..2be7584c 100644 --- a/test/test_cpp_standards.py +++ b/test/test_cpp_standards.py @@ -135,7 +135,6 @@ def test_cpp17(tmp_path): # Python and PyPy 2.7 use the `register` keyword which is forbidden in the C++17 standard # The manylinux1 docker image does not have a compiler which supports C++11 - # Python 3.5 and PyPy 3.6 are compiled with MSVC 10, which does not support C++17 if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') == 'Visual Studio 2015': pytest.skip('Visual Studio 2015 does not support C++17') @@ -170,8 +169,7 @@ def test_cpp17_py27_modern_msvc_workaround(tmp_path): # included with Python: see documentation for more info # DISTUTILS_USE_SDK and MSSdk=1 tell distutils/setuptools that we are adding # MSVC's compiler, tools, and libraries to PATH ourselves - add_env = {'CIBW_ENVIRONMENT': 'STANDARD=17', - 'DISTUTILS_USE_SDK': '1', 'MSSdk': '1'} + add_env = {'DISTUTILS_USE_SDK': '1', 'MSSdk': '1'} # Use existing setuptools code to run Visual Studio's vcvarsall.bat and get the # necessary environment variables, since running vcvarsall.bat in a subprocess From cc1ae4a96315a063a051703f16857da957a65bbd Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Wed, 6 May 2020 20:14:03 +0100 Subject: [PATCH 24/32] Add utility function to checkout a generated project --- test/template_projects/__main__.py | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 test/template_projects/__main__.py diff --git a/test/template_projects/__main__.py b/test/template_projects/__main__.py new file mode 100644 index 00000000..87771528 --- /dev/null +++ b/test/template_projects/__main__.py @@ -0,0 +1,37 @@ +from argparse import ArgumentParser +import importlib +import tempfile +import sys +import subprocess + + +def main(): + parser = ArgumentParser( + prog="python -m test.template_projects", + description='Generate a template project to check it out' + ) + parser.add_argument('PROJECT', help=''' + Python path to a project object. E.g. test.test_0_basic.basic_project + ''') + options = parser.parse_args() + + module, _, name = options.PROJECT.rpartition('.') + + project = getattr(importlib.import_module(module), name) + + project_dir = tempfile.mkdtemp() + project.generate(project_dir) + + print('Project generated at', project_dir) + print() + + if sys.platform == 'darwin': + subprocess.check_call(['open', '--', project_dir]) + elif sys.platform == 'linux2': + subprocess.check_call(['xdg-open', '--', project_dir]) + elif sys.platform == 'win32': + subprocess.check_call(['explorer', project_dir]) + + +if __name__ == '__main__': + main() From a679a09212fd4fe4e578b976856deca62a48b46e Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Wed, 6 May 2020 20:24:13 +0100 Subject: [PATCH 25/32] Add missing 3.6 pin test --- test/test_dependency_versions.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/test_dependency_versions.py b/test/test_dependency_versions.py index c290c971..bef12a72 100644 --- a/test/test_dependency_versions.py +++ b/test/test_dependency_versions.py @@ -50,7 +50,7 @@ def get_versions_from_constraint_file(constraint_file): return versions -@pytest.mark.parametrize('python_version', ['2.7', '3.5', '3.8']) +@pytest.mark.parametrize('python_version', ['2.7', '3.5', '3.6', '3.8']) def test_pinned_versions(tmp_path, python_version): if utils.platform == 'linux': pytest.skip('linux doesn\'t pin individual tool versions, it pins manylinux images instead') @@ -66,6 +66,9 @@ def test_pinned_versions(tmp_path, python_version): elif python_version == '3.5': constraint_filename = 'constraints-python35.txt' build_pattern = '[cp]p35-*' + elif python_version == '3.6': + constraint_filename = 'constraints-python36.txt' + build_pattern = '[cp]p36-*' else: constraint_filename = 'constraints.txt' build_pattern = '[cp]p38-*' @@ -94,6 +97,9 @@ def test_pinned_versions(tmp_path, python_version): elif python_version == '3.5': expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') if '-cp35' in w or '-pp35' in w] + elif python_version == '3.6': + expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') + if '-cp36' in w or '-pp36' in w] elif python_version == '3.8': expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') if '-cp38' in w or '-pp38' in w] From 71150a1cb5a818ae2347ba1966a806d46fbb7e50 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Fri, 8 May 2020 13:36:53 +0100 Subject: [PATCH 26/32] Remove pypy from the c++17 test --- test/test_cpp_standards.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/test_cpp_standards.py b/test/test_cpp_standards.py index 2be7584c..b930acee 100644 --- a/test/test_cpp_standards.py +++ b/test/test_cpp_standards.py @@ -133,12 +133,16 @@ def test_cpp17(tmp_path): cpp17_project.generate(project_dir) - # Python and PyPy 2.7 use the `register` keyword which is forbidden in the C++17 standard - # The manylinux1 docker image does not have a compiler which supports C++11 + # - Python and PyPy 2.7 use the `register` keyword which is forbidden in + # the C++17 standard + # - The manylinux1 docker image does not have a compiler which supports + # C++11 + # - Pypy's distutils sets the default compiler to 'msvc9compiler', which + # is too old to support cpp17. if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') == 'Visual Studio 2015': pytest.skip('Visual Studio 2015 does not support C++17') - add_env = {'CIBW_SKIP': 'cp27-win* pp27-win32'} + add_env = {'CIBW_SKIP': 'cp27-win* pp??-*'} if utils.platform == 'macos': add_env['MACOSX_DEPLOYMENT_TARGET'] = '10.13' @@ -146,7 +150,7 @@ def test_cpp17(tmp_path): actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0', macosx_deployment_target='10.13') if 'cp27-cp27m-win' not in w - and 'pp27-pypy_73-win32' not in w] + and '-pp' not in w] assert set(actual_wheels) == set(expected_wheels) From 0411fcc2aed79a6757162c95d1efc7aac7464d35 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Fri, 15 May 2020 12:19:38 +0100 Subject: [PATCH 27/32] As discussed in code review --- bin/dev_run_test | 2 +- bin/run_tests.py | 2 +- test/template_projects/base.py | 2 +- test/test_0_basic.py | 2 +- test/test_cpp_standards.py | 35 ++++++++++++++++++---------------- test/test_ssl.py | 5 ++++- test/utils.py | 2 +- 7 files changed, 28 insertions(+), 22 deletions(-) diff --git a/bin/dev_run_test b/bin/dev_run_test index 6515c6b3..85a0d81c 100755 --- a/bin/dev_run_test +++ b/bin/dev_run_test @@ -1,3 +1,3 @@ #!/bin/bash -CIBW_PLATFORM=linux pytest $1 +CIBW_PLATFORM=linux pytest "$@" diff --git a/bin/run_tests.py b/bin/run_tests.py index e3275f3f..93c23e88 100755 --- a/bin/run_tests.py +++ b/bin/run_tests.py @@ -12,4 +12,4 @@ if __name__ == '__main__': subprocess.check_call([sys.executable, '-m', 'pytest', 'unit_test']) # run the integration tests - subprocess.check_call([sys.executable, '-m', 'pytest', '--durations', '0', 'test']) + subprocess.check_call([sys.executable, '-m', 'pytest', '-x', '--durations', '0', 'test']) diff --git a/test/template_projects/base.py b/test/template_projects/base.py index 2daf53a8..66e7acbc 100644 --- a/test/template_projects/base.py +++ b/test/template_projects/base.py @@ -21,7 +21,7 @@ class TemplateProject: file_path = os.path.join(path, filename) os.makedirs(os.path.dirname(file_path), exist_ok=True) - with io.open(file_path, 'w', encoding='utf8') as f: + with open(file_path, 'w', encoding='utf8') as f: if isinstance(content, jinja2.Template): content = content.render(self.template_context) diff --git a/test/test_0_basic.py b/test/test_0_basic.py index 5bf16822..a38c1180 100644 --- a/test/test_0_basic.py +++ b/test/test_0_basic.py @@ -21,7 +21,7 @@ def test(tmp_path): actual_wheels = utils.cibuildwheel_run(project_dir) # check that the expected wheels are produced - expected_wheels = utils.expected_wheels("spam", "0.1.0") + expected_wheels = utils.expected_wheels('spam', '0.1.0') assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_cpp_standards.py b/test/test_cpp_standards.py index b930acee..7dbca41a 100644 --- a/test/test_cpp_standards.py +++ b/test/test_cpp_standards.py @@ -72,15 +72,18 @@ MOD_INIT(spam) ''') +cpp11_project = cpp_template_project.copy() +cpp11_project.template_context['extra_compile_args'] = ( + ['/std:c++11'] if utils.platform == 'windows' else ['-std=c++11'] +) +cpp11_project.template_context['spam_cpp_top_level_add'] = '#include ' + + def test_cpp11(tmp_path): # This test checks that the C++11 standard is supported project_dir = tmp_path / 'project' - project = cpp_template_project.copy() - extra_compile_args = ['/std:c++11'] if utils.platform == 'windows' else ['-std=c++11'] - project.template_context['extra_compile_args'] = extra_compile_args - project.template_context['spam_cpp_top_level_add'] = '#include ' - project.generate(project_dir) + cpp11_project.generate(project_dir) # VC++ for Python 2.7 does not support modern standards add_env = {'CIBW_SKIP': 'cp27-win* pp27-win32'} @@ -92,15 +95,18 @@ def test_cpp11(tmp_path): assert set(actual_wheels) == set(expected_wheels) +cpp14_project = cpp_template_project.copy() +cpp14_project.template_context['extra_compile_args'] = ( + ['/std:c++14'] if utils.platform == 'windows' else ['-std=c++14'] +) +cpp14_project.template_context['spam_cpp_top_level_add'] = "int a = 100'000;" + + def test_cpp14(tmp_path): # This test checks that the C++14 standard is supported project_dir = tmp_path / 'project' - project = cpp_template_project.copy() - extra_compile_args = ['/std:c++14'] if utils.platform == 'windows' else ['-std=c++14'] - project.template_context['extra_compile_args'] = extra_compile_args - project.template_context['spam_cpp_top_level_add'] = "int a = 100'000;" - project.generate(project_dir) + cpp14_project.generate(project_dir) # VC++ for Python 2.7 does not support modern standards # The manylinux1 docker image does not have a compiler which supports C++11 @@ -115,12 +121,9 @@ def test_cpp14(tmp_path): cpp17_project = cpp_template_project.copy() - -if utils.platform == 'windows': - cpp17_project.template_context['extra_compile_args'] = ['/std:c++17', '/wd5033'] -else: - cpp17_project.template_context['extra_compile_args'] = ['-std=c++17', '-Wno-register'] - +cpp17_project.template_context['extra_compile_args'] = ( + ['/std:c++17', '/wd5033'] if utils.platform == 'windows' else ['-std=c++17', '-Wno-register'] +) cpp17_project.template_context['spam_cpp_top_level_add'] = r''' #include auto a = std::pair(5.0, false); diff --git a/test/test_ssl.py b/test/test_ssl.py index eddb4074..18b9ebb6 100644 --- a/test/test_ssl.py +++ b/test/test_ssl.py @@ -28,4 +28,7 @@ def test(tmp_path): project_dir = tmp_path / 'project' project_with_ssl_tests.generate(project_dir) - utils.cibuildwheel_run(project_dir) + actual_wheels = utils.cibuildwheel_run(project_dir) + + expected_wheels = utils.expected_wheels('spam', '0.1.0') + assert set(actual_wheels) == set(expected_wheels) diff --git a/test/utils.py b/test/utils.py index 1c2733c6..609ab9d7 100644 --- a/test/utils.py +++ b/test/utils.py @@ -33,7 +33,7 @@ def cibuildwheel_get_build_identifiers(project_path, env=None): for the current platform. ''' cmd_output = subprocess.check_output( - [sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers', str(project_path)], + [sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers', project_path], universal_newlines=True, env=env, ) From 2e8fe841ec63e4db64f668f3409349313dc4099a Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Fri, 15 May 2020 12:28:34 +0100 Subject: [PATCH 28/32] Remove TemplateProject subclassing --- test/template_projects/__init__.py | 2 +- test/template_projects/c.py | 38 +++++++++++++++--------------- test/test_0_basic.py | 4 ++-- test/test_before_build.py | 4 ++-- test/test_before_test.py | 4 ++-- test/test_build_skip.py | 4 ++-- test/test_dependency_versions.py | 4 ++-- test/test_docker_images.py | 4 ++-- test/test_environment.py | 6 ++--- test/test_manylinuxXXXX_only.py | 4 ++-- test/test_ssl.py | 4 ++-- test/test_subdir_package.py | 4 ++-- test/test_testing.py | 4 ++-- 13 files changed, 43 insertions(+), 43 deletions(-) diff --git a/test/template_projects/__init__.py b/test/template_projects/__init__.py index d83df0e4..ba6c61b6 100644 --- a/test/template_projects/__init__.py +++ b/test/template_projects/__init__.py @@ -1,2 +1,2 @@ from .base import TemplateProject # noqa -from .c import CTemplateProject # noqa +from .c import new_c_project # noqa diff --git a/test/template_projects/c.py b/test/template_projects/c.py index 151cc574..ef64745f 100644 --- a/test/template_projects/c.py +++ b/test/template_projects/c.py @@ -2,7 +2,7 @@ import jinja2 from .base import TemplateProject -spam_c_template = r''' +SPAM_C_TEMPLATE = r''' #include {{ spam_c_top_level_add }} @@ -59,7 +59,7 @@ MOD_INIT(spam) } ''' -setup_py_template = r''' +SETUP_PY_TEMPLATE = r''' from setuptools import setup, Extension {{ setup_py_add }} @@ -70,7 +70,7 @@ setup( ) ''' -setup_cfg_template = r''' +SETUP_CFG_TEMPLATE = r''' [metadata] name = spam version = 0.1.0 @@ -79,22 +79,22 @@ version = 0.1.0 ''' -class CTemplateProject(TemplateProject): - def __init__(self, *, spam_c_top_level_add='', spam_c_function_add='', setup_py_add='', - setup_py_setup_args_add='', setup_cfg_add=''): +def new_c_project(*, spam_c_top_level_add='', spam_c_function_add='', setup_py_add='', + setup_py_setup_args_add='', setup_cfg_add=''): + project = TemplateProject() - super().__init__() + project.files.update({ + 'spam.c': jinja2.Template(SPAM_C_TEMPLATE), + 'setup.py': jinja2.Template(SETUP_PY_TEMPLATE), + 'setup.cfg': jinja2.Template(SETUP_CFG_TEMPLATE), + }) - self.files.update({ - 'spam.c': jinja2.Template(spam_c_template), - 'setup.py': jinja2.Template(setup_py_template), - 'setup.cfg': jinja2.Template(setup_cfg_template), - }) + project.template_context.update({ + 'spam_c_top_level_add': spam_c_top_level_add, + 'spam_c_function_add': spam_c_function_add, + 'setup_py_add': setup_py_add, + 'setup_py_setup_args_add': setup_py_setup_args_add, + 'setup_cfg_add': setup_cfg_add, + }) - self.template_context.update({ - 'spam_c_top_level_add': spam_c_top_level_add, - 'spam_c_function_add': spam_c_function_add, - 'setup_py_add': setup_py_add, - 'setup_py_setup_args_add': setup_py_setup_args_add, - 'setup_cfg_add': setup_cfg_add, - }) + return project diff --git a/test/test_0_basic.py b/test/test_0_basic.py index a38c1180..0bd6817d 100644 --- a/test/test_0_basic.py +++ b/test/test_0_basic.py @@ -1,9 +1,9 @@ import textwrap import platform -from .template_projects import CTemplateProject +from . import template_projects from . import utils -basic_project = CTemplateProject( +basic_project = template_projects.new_c_project( setup_py_add=textwrap.dedent(''' import os diff --git a/test/test_before_build.py b/test/test_before_build.py index b1715238..0ce92110 100644 --- a/test/test_before_build.py +++ b/test/test_before_build.py @@ -1,9 +1,9 @@ import textwrap from . import utils -from .template_projects import CTemplateProject +from . import template_projects -project_with_before_build_asserts = CTemplateProject( +project_with_before_build_asserts = template_projects.new_c_project( setup_py_add=textwrap.dedent(r''' import sys, os diff --git a/test/test_before_test.py b/test/test_before_test.py index 988f7b33..0ea3e5e0 100644 --- a/test/test_before_test.py +++ b/test/test_before_test.py @@ -1,7 +1,7 @@ -from .template_projects.c import CTemplateProject +from . import template_projects from . import utils -before_test_project = CTemplateProject() +before_test_project = template_projects.new_c_project() before_test_project.files['test/spam_test.py'] = r''' import sys import os diff --git a/test/test_build_skip.py b/test/test_build_skip.py index 30bba181..ad91c8d4 100644 --- a/test/test_build_skip.py +++ b/test/test_build_skip.py @@ -1,9 +1,9 @@ import textwrap from . import utils -from .template_projects import CTemplateProject +from . import template_projects -project_with_skip_asserts = CTemplateProject( +project_with_skip_asserts = template_projects.new_c_project( setup_py_add=textwrap.dedent(r''' # explode if run on Python 2.7 or Python 3.7 (these should be skipped) if sys.version_info[0:2] == (2, 7): diff --git a/test/test_dependency_versions.py b/test/test_dependency_versions.py index bef12a72..87a849c7 100644 --- a/test/test_dependency_versions.py +++ b/test/test_dependency_versions.py @@ -5,10 +5,10 @@ import textwrap import cibuildwheel.util from . import utils -from .template_projects import CTemplateProject +from . import template_projects -project_with_expected_version_checks = CTemplateProject( +project_with_expected_version_checks = template_projects.new_c_project( setup_py_add=textwrap.dedent(r''' import subprocess import os diff --git a/test/test_docker_images.py b/test/test_docker_images.py index 725779f2..be5ceaa8 100644 --- a/test/test_docker_images.py +++ b/test/test_docker_images.py @@ -4,9 +4,9 @@ import textwrap import pytest from . import utils -from .template_projects import CTemplateProject +from . import template_projects -dockcross_only_project = CTemplateProject( +dockcross_only_project = template_projects.new_c_project( setup_py_add=textwrap.dedent(r''' import os, sys diff --git a/test/test_environment.py b/test/test_environment.py index ce45990a..9dcfab07 100644 --- a/test/test_environment.py +++ b/test/test_environment.py @@ -3,10 +3,10 @@ import pytest import subprocess import textwrap from . import utils -from .template_projects import CTemplateProject +from . import template_projects -project_with_environment_asserts = CTemplateProject( +project_with_environment_asserts = template_projects.new_c_project( setup_py_add=textwrap.dedent(r''' import os @@ -47,7 +47,7 @@ def test(tmp_path): def test_overridden_path(tmp_path): project_dir = tmp_path / 'project' output_dir = tmp_path / 'output' - CTemplateProject().generate(project_dir) + new_c_project().generate(project_dir) output_dir.mkdir() # mess up PATH, somehow diff --git a/test/test_manylinuxXXXX_only.py b/test/test_manylinuxXXXX_only.py index e3753ea9..e159cbae 100644 --- a/test/test_manylinuxXXXX_only.py +++ b/test/test_manylinuxXXXX_only.py @@ -4,10 +4,10 @@ import textwrap import pytest from . import utils -from .template_projects import CTemplateProject +from . import template_projects # TODO: specify these at runtime according to manylinux_image -project_with_manylinux_symbols = CTemplateProject( +project_with_manylinux_symbols = template_projects.new_c_project( spam_c_top_level_add=textwrap.dedent(r''' #include diff --git a/test/test_ssl.py b/test/test_ssl.py index 18b9ebb6..13c81b24 100644 --- a/test/test_ssl.py +++ b/test/test_ssl.py @@ -1,9 +1,9 @@ import textwrap from . import utils -from .template_projects import CTemplateProject +from . import template_projects -project_with_ssl_tests = CTemplateProject( +project_with_ssl_tests = template_projects.new_c_project( setup_py_add=textwrap.dedent(r''' import ssl import sys diff --git a/test/test_subdir_package.py b/test/test_subdir_package.py index 67e3eef6..ab52c274 100644 --- a/test/test_subdir_package.py +++ b/test/test_subdir_package.py @@ -4,11 +4,11 @@ import jinja2 from . import utils from .template_projects import TemplateProject -from .template_projects.c import spam_c_template +from .template_projects.c import SPAM_C_TEMPLATE subdir_package_project = TemplateProject() -subdir_package_project.files['src/spam/spam.c'] = jinja2.Template(spam_c_template) +subdir_package_project.files['src/spam/spam.c'] = jinja2.Template(SPAM_C_TEMPLATE) subdir_package_project.template_context['spam_c_top_level_add'] = '' subdir_package_project.template_context['spam_c_function_add'] = '' diff --git a/test/test_testing.py b/test/test_testing.py index 64ad4bac..8c5a92d2 100644 --- a/test/test_testing.py +++ b/test/test_testing.py @@ -5,9 +5,9 @@ import textwrap import pytest from . import utils -from .template_projects import CTemplateProject +from . import template_projects -project_with_a_test = CTemplateProject( +project_with_a_test = template_projects.new_c_project( setup_cfg_add=textwrap.dedent(r''' [options.extras_require] test = nose From 13907188a19d2ff2c5708414ac206ac2f18c0d96 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Fri, 15 May 2020 12:35:14 +0100 Subject: [PATCH 29/32] Fix flake8 errors --- setup.cfg | 2 +- test/template_projects/base.py | 1 - test/test_environment.py | 4 +++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index bb41055e..d678c699 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [flake8] -ignore = E501,W503 +ignore = E501,W503,E741 application-import-names = cibuildwheel exclude = cibuildwheel/resources/, diff --git a/test/template_projects/base.py b/test/template_projects/base.py index 66e7acbc..2ea1bc69 100644 --- a/test/template_projects/base.py +++ b/test/template_projects/base.py @@ -1,5 +1,4 @@ import os -import io import jinja2 from typing import Union, Dict, Any diff --git a/test/test_environment.py b/test/test_environment.py index 9dcfab07..d310e991 100644 --- a/test/test_environment.py +++ b/test/test_environment.py @@ -47,7 +47,9 @@ def test(tmp_path): def test_overridden_path(tmp_path): project_dir = tmp_path / 'project' output_dir = tmp_path / 'output' - new_c_project().generate(project_dir) + + project = template_projects.new_c_project() + project.generate(project_dir) output_dir.mkdir() # mess up PATH, somehow From 420995f5675665ff7055e75ba377b82d45874b76 Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Fri, 15 May 2020 15:18:17 +0100 Subject: [PATCH 30/32] check_call does require paths as strings on CPython 3.6 Windows --- test/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils.py b/test/utils.py index 609ab9d7..1c2733c6 100644 --- a/test/utils.py +++ b/test/utils.py @@ -33,7 +33,7 @@ def cibuildwheel_get_build_identifiers(project_path, env=None): for the current platform. ''' cmd_output = subprocess.check_output( - [sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers', project_path], + [sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers', str(project_path)], universal_newlines=True, env=env, ) From 81f960b17e0b4131f7ce2936df357909fa0f748d Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 17 May 2020 16:54:33 +0100 Subject: [PATCH 31/32] Rename TemplateProject -> TestProject & tidy some comments --- test/template_projects/__init__.py | 2 -- test/test_0_basic.py | 4 +-- test/test_before_build.py | 4 +-- test/test_before_test.py | 4 +-- test/test_build_skip.py | 4 +-- test/test_cpp_standards.py | 25 +++++++++---------- test/test_dependency_versions.py | 4 +-- test/test_docker_images.py | 4 +-- test/test_environment.py | 6 ++--- test/test_manylinuxXXXX_only.py | 4 +-- test/test_projects/__init__.py | 2 ++ .../__main__.py | 4 +-- .../base.py | 10 ++++++-- .../{template_projects => test_projects}/c.py | 4 +-- test/test_ssl.py | 4 +-- test/test_subdir_package.py | 6 ++--- test/test_testing.py | 4 +-- 17 files changed, 50 insertions(+), 45 deletions(-) delete mode 100644 test/template_projects/__init__.py create mode 100644 test/test_projects/__init__.py rename test/{template_projects => test_projects}/__main__.py (88%) rename test/{template_projects => test_projects}/base.py (76%) rename test/{template_projects => test_projects}/c.py (97%) diff --git a/test/template_projects/__init__.py b/test/template_projects/__init__.py deleted file mode 100644 index ba6c61b6..00000000 --- a/test/template_projects/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .base import TemplateProject # noqa -from .c import new_c_project # noqa diff --git a/test/test_0_basic.py b/test/test_0_basic.py index 0bd6817d..60b309ab 100644 --- a/test/test_0_basic.py +++ b/test/test_0_basic.py @@ -1,9 +1,9 @@ import textwrap import platform -from . import template_projects +from . import test_projects from . import utils -basic_project = template_projects.new_c_project( +basic_project = test_projects.new_c_project( setup_py_add=textwrap.dedent(''' import os diff --git a/test/test_before_build.py b/test/test_before_build.py index 0ce92110..11c752f0 100644 --- a/test/test_before_build.py +++ b/test/test_before_build.py @@ -1,9 +1,9 @@ import textwrap from . import utils -from . import template_projects +from . import test_projects -project_with_before_build_asserts = template_projects.new_c_project( +project_with_before_build_asserts = test_projects.new_c_project( setup_py_add=textwrap.dedent(r''' import sys, os diff --git a/test/test_before_test.py b/test/test_before_test.py index 0ea3e5e0..d0dad59d 100644 --- a/test/test_before_test.py +++ b/test/test_before_test.py @@ -1,7 +1,7 @@ -from . import template_projects +from . import test_projects from . import utils -before_test_project = template_projects.new_c_project() +before_test_project = test_projects.new_c_project() before_test_project.files['test/spam_test.py'] = r''' import sys import os diff --git a/test/test_build_skip.py b/test/test_build_skip.py index ad91c8d4..11d125f6 100644 --- a/test/test_build_skip.py +++ b/test/test_build_skip.py @@ -1,9 +1,9 @@ import textwrap from . import utils -from . import template_projects +from . import test_projects -project_with_skip_asserts = template_projects.new_c_project( +project_with_skip_asserts = test_projects.new_c_project( setup_py_add=textwrap.dedent(r''' # explode if run on Python 2.7 or Python 3.7 (these should be skipped) if sys.version_info[0:2] == (2, 7): diff --git a/test/test_cpp_standards.py b/test/test_cpp_standards.py index 7dbca41a..0ecf196d 100644 --- a/test/test_cpp_standards.py +++ b/test/test_cpp_standards.py @@ -4,11 +4,11 @@ import jinja2 import pytest from . import utils -from .template_projects import TemplateProject +from .test_projects import TestProject -cpp_template_project = TemplateProject() +cpp_test_project = TestProject() -cpp_template_project.files['setup.py'] = jinja2.Template(r''' +cpp_test_project.files['setup.py'] = jinja2.Template(r''' from setuptools import Extension, setup setup( @@ -18,7 +18,7 @@ setup( ) ''') -cpp_template_project.files['spam.cpp'] = jinja2.Template(r''' +cpp_test_project.files['spam.cpp'] = jinja2.Template(r''' #include {{ spam_cpp_top_level_add }} @@ -72,7 +72,7 @@ MOD_INIT(spam) ''') -cpp11_project = cpp_template_project.copy() +cpp11_project = cpp_test_project.copy() cpp11_project.template_context['extra_compile_args'] = ( ['/std:c++11'] if utils.platform == 'windows' else ['-std=c++11'] ) @@ -95,7 +95,7 @@ def test_cpp11(tmp_path): assert set(actual_wheels) == set(expected_wheels) -cpp14_project = cpp_template_project.copy() +cpp14_project = cpp_test_project.copy() cpp14_project.template_context['extra_compile_args'] = ( ['/std:c++14'] if utils.platform == 'windows' else ['-std=c++14'] ) @@ -120,7 +120,10 @@ def test_cpp14(tmp_path): assert set(actual_wheels) == set(expected_wheels) -cpp17_project = cpp_template_project.copy() +cpp17_project = cpp_test_project.copy() + +# Python and PyPy 2.7 headers use the `register` keyword, which is forbidden in +# the C++17 standard, so we need the -Wno-register or /wd5033 options cpp17_project.template_context['extra_compile_args'] = ( ['/std:c++17', '/wd5033'] if utils.platform == 'windows' else ['-std=c++17', '-Wno-register'] ) @@ -136,15 +139,11 @@ def test_cpp17(tmp_path): cpp17_project.generate(project_dir) - # - Python and PyPy 2.7 use the `register` keyword which is forbidden in - # the C++17 standard - # - The manylinux1 docker image does not have a compiler which supports - # C++11 - # - Pypy's distutils sets the default compiler to 'msvc9compiler', which - # is too old to support cpp17. if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') == 'Visual Studio 2015': pytest.skip('Visual Studio 2015 does not support C++17') + # Pypy's distutils sets the default compiler to 'msvc9compiler', which + # is too old to support cpp17. add_env = {'CIBW_SKIP': 'cp27-win* pp??-*'} if utils.platform == 'macos': diff --git a/test/test_dependency_versions.py b/test/test_dependency_versions.py index 87a849c7..e6645dec 100644 --- a/test/test_dependency_versions.py +++ b/test/test_dependency_versions.py @@ -5,10 +5,10 @@ import textwrap import cibuildwheel.util from . import utils -from . import template_projects +from . import test_projects -project_with_expected_version_checks = template_projects.new_c_project( +project_with_expected_version_checks = test_projects.new_c_project( setup_py_add=textwrap.dedent(r''' import subprocess import os diff --git a/test/test_docker_images.py b/test/test_docker_images.py index be5ceaa8..f101c4fd 100644 --- a/test/test_docker_images.py +++ b/test/test_docker_images.py @@ -4,9 +4,9 @@ import textwrap import pytest from . import utils -from . import template_projects +from . import test_projects -dockcross_only_project = template_projects.new_c_project( +dockcross_only_project = test_projects.new_c_project( setup_py_add=textwrap.dedent(r''' import os, sys diff --git a/test/test_environment.py b/test/test_environment.py index d310e991..470a151f 100644 --- a/test/test_environment.py +++ b/test/test_environment.py @@ -3,10 +3,10 @@ import pytest import subprocess import textwrap from . import utils -from . import template_projects +from . import test_projects -project_with_environment_asserts = template_projects.new_c_project( +project_with_environment_asserts = test_projects.new_c_project( setup_py_add=textwrap.dedent(r''' import os @@ -48,7 +48,7 @@ def test_overridden_path(tmp_path): project_dir = tmp_path / 'project' output_dir = tmp_path / 'output' - project = template_projects.new_c_project() + project = test_projects.new_c_project() project.generate(project_dir) output_dir.mkdir() diff --git a/test/test_manylinuxXXXX_only.py b/test/test_manylinuxXXXX_only.py index e159cbae..68160688 100644 --- a/test/test_manylinuxXXXX_only.py +++ b/test/test_manylinuxXXXX_only.py @@ -4,10 +4,10 @@ import textwrap import pytest from . import utils -from . import template_projects +from . import test_projects # TODO: specify these at runtime according to manylinux_image -project_with_manylinux_symbols = template_projects.new_c_project( +project_with_manylinux_symbols = test_projects.new_c_project( spam_c_top_level_add=textwrap.dedent(r''' #include diff --git a/test/test_projects/__init__.py b/test/test_projects/__init__.py new file mode 100644 index 00000000..48d7dbec --- /dev/null +++ b/test/test_projects/__init__.py @@ -0,0 +1,2 @@ +from .base import TestProject # noqa +from .c import new_c_project # noqa diff --git a/test/template_projects/__main__.py b/test/test_projects/__main__.py similarity index 88% rename from test/template_projects/__main__.py rename to test/test_projects/__main__.py index 87771528..af5b14dc 100644 --- a/test/template_projects/__main__.py +++ b/test/test_projects/__main__.py @@ -7,8 +7,8 @@ import subprocess def main(): parser = ArgumentParser( - prog="python -m test.template_projects", - description='Generate a template project to check it out' + prog="python -m test.test_projects", + description='Generate a test project to check it out' ) parser.add_argument('PROJECT', help=''' Python path to a project object. E.g. test.test_0_basic.basic_project diff --git a/test/template_projects/base.py b/test/test_projects/base.py similarity index 76% rename from test/template_projects/base.py rename to test/test_projects/base.py index 2ea1bc69..5cac80ad 100644 --- a/test/template_projects/base.py +++ b/test/test_projects/base.py @@ -7,7 +7,13 @@ FilesDict = Dict[str, Union[str, jinja2.Template]] TemplateContext = Dict[str, Any] -class TemplateProject: +class TestProject: + ''' + An object that represents a project that can be built by cibuildwheel. + Can be manipulated in tests by changing `files` and `template_context`. + + Write out to the filesystem using `generate`. + ''' files: FilesDict template_context: TemplateContext @@ -27,7 +33,7 @@ class TemplateProject: f.write(content) def copy(self): - other = TemplateProject() + other = TestProject() other.files = self.files.copy() other.template_context = self.template_context.copy() return other diff --git a/test/template_projects/c.py b/test/test_projects/c.py similarity index 97% rename from test/template_projects/c.py rename to test/test_projects/c.py index ef64745f..6f06c1ba 100644 --- a/test/template_projects/c.py +++ b/test/test_projects/c.py @@ -1,5 +1,5 @@ import jinja2 -from .base import TemplateProject +from .base import TestProject SPAM_C_TEMPLATE = r''' @@ -81,7 +81,7 @@ version = 0.1.0 def new_c_project(*, spam_c_top_level_add='', spam_c_function_add='', setup_py_add='', setup_py_setup_args_add='', setup_cfg_add=''): - project = TemplateProject() + project = TestProject() project.files.update({ 'spam.c': jinja2.Template(SPAM_C_TEMPLATE), diff --git a/test/test_ssl.py b/test/test_ssl.py index 13c81b24..4ade9bb8 100644 --- a/test/test_ssl.py +++ b/test/test_ssl.py @@ -1,9 +1,9 @@ import textwrap from . import utils -from . import template_projects +from . import test_projects -project_with_ssl_tests = template_projects.new_c_project( +project_with_ssl_tests = test_projects.new_c_project( setup_py_add=textwrap.dedent(r''' import ssl import sys diff --git a/test/test_subdir_package.py b/test/test_subdir_package.py index ab52c274..53bd9520 100644 --- a/test/test_subdir_package.py +++ b/test/test_subdir_package.py @@ -3,10 +3,10 @@ import os import jinja2 from . import utils -from .template_projects import TemplateProject -from .template_projects.c import SPAM_C_TEMPLATE +from .test_projects import TestProject +from .test_projects.c import SPAM_C_TEMPLATE -subdir_package_project = TemplateProject() +subdir_package_project = TestProject() subdir_package_project.files['src/spam/spam.c'] = jinja2.Template(SPAM_C_TEMPLATE) subdir_package_project.template_context['spam_c_top_level_add'] = '' diff --git a/test/test_testing.py b/test/test_testing.py index 8c5a92d2..dda833ea 100644 --- a/test/test_testing.py +++ b/test/test_testing.py @@ -5,9 +5,9 @@ import textwrap import pytest from . import utils -from . import template_projects +from . import test_projects -project_with_a_test = template_projects.new_c_project( +project_with_a_test = test_projects.new_c_project( setup_cfg_add=textwrap.dedent(r''' [options.extras_require] test = nose From 0c323cfb5b3ca7a3f38c26e51c9665ba8e8824bb Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sun, 17 May 2020 20:17:34 +0100 Subject: [PATCH 32/32] Add non-strict typechecking to test module 'strict' is a global flag, so I've had to break out the type- checking options to be more specific --- setup.cfg | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index 350db702..d54a42bb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,5 +16,25 @@ exclude = junit_family=xunit2 [mypy] -files=cibuildwheel/ -strict=True +python_version = 3.6 +files = cibuildwheel,test + +warn_unused_configs = True +warn_redundant_casts = True + +[mypy-cibuildwheel] +disallow_any_generics = True +disallow_subclassing_any = True +disallow_untyped_calls = True +disallow_untyped_defs = True +disallow_incomplete_defs = True +check_untyped_defs = True +disallow_untyped_decorators = True +no_implicit_optional = True +warn_unused_ignores = True +warn_return_any = True +no_implicit_reexport = True +strict_equality = True + +[mypy-pytest,setuptools] +ignore_missing_imports = True