Skip to content

Commit 55b7859

Browse files
authored
Merge pull request #33 from Cadair/no_more_setup_py
2 parents 46f6c46 + b3273e0 commit 55b7859

File tree

7 files changed

+149
-16
lines changed

7 files changed

+149
-16
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,6 @@ htmlcov
5353

5454
# PyCharm
5555
.idea
56+
57+
# Hypothesis
58+
.hypothesis

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
* Remove support for the undocumented --compiler argument to setup.py. [#36]
99

10+
* Added support for enabling extension-helpers from setup.cfg. [#33]
11+
1012
0.1 (2019-12-18)
1113
----------------
1214

docs/using.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,9 @@ To use this, you should modify your ``setup.py`` file to use
3939
Note that if you use this, extension-helpers will also we create a
4040
``packagename.compiler_version`` submodule that contain information about the
4141
compilers used.
42+
43+
It is also possible to enable extension-helpers in ``setup.cfg`` instead of
44+
``setup.py`` by adding the following configuration to the ``setup.cfg`` file::
45+
46+
[extension-helpers]
47+
use_extension_helpers = true

extension_helpers/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
1+
from configparser import ConfigParser
2+
13
from ._openmp_helpers import add_openmp_flags_if_available
24
from ._setup_helpers import get_compiler, get_extensions, pkg_config
35
from ._utils import import_file, write_if_different
46
from .version import version as __version__
7+
8+
9+
def _finalize_distribution_hook(distribution):
10+
"""
11+
Entry point for setuptools which allows extension-helpers to be enabled
12+
from setup.cfg without the need for setup.py.
13+
"""
14+
config_files = distribution.find_config_files()
15+
if len(config_files) == 0:
16+
return
17+
cfg = ConfigParser()
18+
cfg.read(config_files[0])
19+
if (cfg.has_option("extension-helpers", "use_extension_helpers") and
20+
cfg.get("extension-helpers", "use_extension_helpers").lower() == 'true'):
21+
distribution.ext_modules = get_extensions()

extension_helpers/tests/test_setup_helpers.py

Lines changed: 113 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import os
22
import sys
3+
import uuid
34
import importlib
5+
import subprocess
46
from textwrap import dedent
57

68
import pytest
@@ -31,14 +33,14 @@ def _extension_test_package(tmpdir, request, extension_type='c',
3133
"""Creates a simple test package with an extension module."""
3234

3335
test_pkg = tmpdir.mkdir('test_pkg')
34-
test_pkg.mkdir('apyhtest_eva').ensure('__init__.py')
36+
test_pkg.mkdir('helpers_test_package').ensure('__init__.py')
3537

3638
# TODO: It might be later worth making this particular test package into a
3739
# reusable fixture for other build_ext tests
3840

3941
if extension_type in ('c', 'both'):
4042
# A minimal C extension for testing
41-
test_pkg.join('apyhtest_eva', 'unit01.c').write(dedent("""\
43+
test_pkg.join('helpers_test_package', 'unit01.c').write(dedent("""\
4244
#include <Python.h>
4345
4446
static struct PyModuleDef moduledef = {
@@ -56,7 +58,7 @@ def _extension_test_package(tmpdir, request, extension_type='c',
5658

5759
if extension_type in ('pyx', 'both'):
5860
# A minimal Cython extension for testing
59-
test_pkg.join('apyhtest_eva', 'unit02.pyx').write(dedent("""\
61+
test_pkg.join('helpers_test_package', 'unit02.pyx').write(dedent("""\
6062
print("Hello cruel angel.")
6163
"""))
6264

@@ -70,11 +72,13 @@ def _extension_test_package(tmpdir, request, extension_type='c',
7072
include_dirs = ['numpy'] if include_numpy else []
7173

7274
extensions_list = [
73-
"Extension('apyhtest_eva.{0}', [join('apyhtest_eva', '{1}')], include_dirs={2})".format(
75+
"Extension('helpers_test_package.{0}', "
76+
"[join('helpers_test_package', '{1}')], "
77+
"include_dirs={2})".format(
7478
os.path.splitext(extension)[0], extension, include_dirs)
7579
for extension in extensions]
7680

77-
test_pkg.join('apyhtest_eva', 'setup_package.py').write(dedent("""\
81+
test_pkg.join('helpers_test_package', 'setup_package.py').write(dedent("""\
7882
from setuptools import Extension
7983
from os.path import join
8084
def get_extensions():
@@ -89,7 +93,7 @@ def get_extensions():
8993
from extension_helpers import get_extensions
9094
9195
setup(
92-
name='apyhtest_eva',
96+
name='helpers_test_package',
9397
version='0.1',
9498
packages=find_packages(),
9599
ext_modules=get_extensions()
@@ -102,7 +106,7 @@ def get_extensions():
102106
sys.path.insert(0, '')
103107

104108
def finalize():
105-
cleanup_import('apyhtest_eva')
109+
cleanup_import('helpers_test_package')
106110

107111
request.addfinalizer(finalize)
108112

@@ -169,11 +173,107 @@ def test_compiler_module(capsys, c_extension_test_package):
169173
'--record={0}'.format(install_temp.join('record.txt'))])
170174

171175
with install_temp.as_cwd():
172-
import apyhtest_eva
176+
import helpers_test_package
173177

174-
# Make sure we imported the apyhtest_eva package from the correct place
175-
dirname = os.path.abspath(os.path.dirname(apyhtest_eva.__file__))
176-
assert dirname == str(install_temp.join('apyhtest_eva'))
178+
# Make sure we imported the helpers_test_package package from the correct place
179+
dirname = os.path.abspath(os.path.dirname(helpers_test_package.__file__))
180+
assert dirname == str(install_temp.join('helpers_test_package'))
177181

178-
import apyhtest_eva.compiler_version
179-
assert apyhtest_eva.compiler_version != 'unknown'
182+
import helpers_test_package.compiler_version
183+
assert helpers_test_package.compiler_version != 'unknown'
184+
185+
186+
@pytest.mark.parametrize('use_extension_helpers', [None, False, True])
187+
def test_no_setup_py(tmpdir, use_extension_helpers):
188+
"""
189+
Test that makes sure that extension-helpers can be enabled without a
190+
setup.py file.
191+
"""
192+
193+
package_name = 'helpers_test_package_' + str(uuid.uuid4()).replace('-', '_')
194+
195+
test_pkg = tmpdir.mkdir('test_pkg')
196+
test_pkg.mkdir(package_name).ensure('__init__.py')
197+
198+
simple_c = test_pkg.join(package_name, 'simple.c')
199+
200+
simple_c.write(dedent("""\
201+
#include <Python.h>
202+
203+
static struct PyModuleDef moduledef = {
204+
PyModuleDef_HEAD_INIT,
205+
"simple",
206+
NULL,
207+
-1,
208+
NULL
209+
};
210+
PyMODINIT_FUNC
211+
PyInit_simple(void) {
212+
return PyModule_Create(&moduledef);
213+
}
214+
"""))
215+
216+
test_pkg.join(package_name, 'setup_package.py').write(dedent(f"""\
217+
from setuptools import Extension
218+
from os.path import join
219+
def get_extensions():
220+
return [Extension('{package_name}.simple', [join('{package_name}', 'simple.c')])]
221+
"""))
222+
223+
if use_extension_helpers is None:
224+
test_pkg.join('setup.cfg').write(dedent(f"""\
225+
[metadata]
226+
name = {package_name}
227+
version = 0.1
228+
229+
[options]
230+
packages = find:
231+
"""))
232+
else:
233+
test_pkg.join('setup.cfg').write(dedent(f"""\
234+
[metadata]
235+
name = {package_name}
236+
version = 0.1
237+
238+
[options]
239+
packages = find:
240+
241+
[extension-helpers]
242+
use_extension_helpers = {str(use_extension_helpers).lower()}
243+
"""))
244+
245+
test_pkg.join('pyproject.toml').write(dedent("""\
246+
[build-system]
247+
requires = ["setuptools>=43.0.0",
248+
"wheel"]
249+
build-backend = 'setuptools.build_meta'
250+
"""))
251+
252+
install_temp = test_pkg.mkdir('install_temp')
253+
254+
with test_pkg.as_cwd():
255+
# NOTE: we disable build isolation as we need to pick up the current
256+
# developer version of extension-helpers
257+
subprocess.call([sys.executable, '-m', 'pip', 'install', '.',
258+
'--no-build-isolation',
259+
f'--target={install_temp}'])
260+
261+
if '' in sys.path:
262+
sys.path.remove('')
263+
264+
sys.path.insert(0, '')
265+
266+
with install_temp.as_cwd():
267+
268+
importlib.import_module(package_name)
269+
270+
if use_extension_helpers:
271+
compiler_version_mod = importlib.import_module(package_name + '.compiler_version')
272+
assert compiler_version_mod.compiler != 'unknown'
273+
else:
274+
try:
275+
importlib.import_module(package_name + '.compiler_version')
276+
except ImportError:
277+
pass
278+
else:
279+
raise AssertionError(package_name + '.compiler_version should not exist')

setup.cfg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ install_requires =
3030
[options.package_data]
3131
extension_helpers = src/compiler.c
3232

33+
[options.entry_points]
34+
setuptools.finalize_distribution_options =
35+
extension_helpers_get_extensions = extension_helpers:_finalize_distribution_hook
36+
3337
[options.extras_require]
3438
test =
3539
pytest

tox.ini

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ passenv =
1313
CONDA_BUILD_SYSROOT
1414
setenv =
1515
osxclang: CC=clang-10
16-
linuxgcc: CC=x86_64-conda_cos6-linux-gnu-gcc
16+
linuxgcc: CC=gcc_linux-64
1717
changedir =
1818
test: .tmp/{envname}
1919
build_docs: docs
@@ -31,13 +31,14 @@ conda_deps =
3131
osxclang: clang_osx-64==10
3232
osxclang: llvm-openmp
3333
linuxgcc: gcc_linux-64
34+
conda_channels =
35+
linuxgcc: conda-forge
3436
extras =
3537
test: test
3638
build_docs: docs
3739
all: all
3840
commands =
39-
dev: bash -ec "rm -rf setuptools_repo; git clone https://github.com/pypa/setuptools.git setuptools_repo && cd setuptools_repo && python bootstrap.py"
40-
dev: pip install setuptools_repo/ --no-build-isolation
41+
dev: pip install git+https://github.com/pypa/setuptools.git
4142
pip freeze
4243
test: python -c 'import setuptools; print(setuptools.__version__)'
4344
test: pytest --pyargs extension_helpers {toxinidir}/docs --cov extension_helpers --cov-config={toxinidir}/setup.cfg {posargs}

0 commit comments

Comments
 (0)