Repository: astropy/extension-helpers

Issue:
Support for `pyproject.toml` configuration
In this https://github.com/astropy/astropy/pull/14361#issuecomment-1419210239, it was requested that `extension-helpers` support something like:

```ini
[extension-helpers]
use_extension_helpers = true
```

configurations, but in the `pyproject.toml` instead of the `setup.cfg`. This is so that projects like `astropy` can move towards adopting [PEP621](https://peps.python.org/pep-0621/) (storing all project metadata in `pyproject.toml` instead of across the `setup.cfg` and `setup.py` files).

Comments:

Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 0df9e73..6d63f25 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,6 +5,8 @@
   recommends the ``-Qopenmp`` flag rather than ``-fopenmp`` for greater
   performance.
 
+* Add support for enabling extension-helpers from pyproject.toml. [#48]
+
 1.0.0 (2022-03-16)
 ------------------
 
diff --git a/docs/using.rst b/docs/using.rst
index b6002e0..6e29ea8 100644
--- a/docs/using.rst
+++ b/docs/using.rst
@@ -45,3 +45,13 @@ It is also possible to enable extension-helpers in ``setup.cfg`` instead of
 
     [extension-helpers]
     use_extension_helpers = true
+
+Moreover, one can also enable extension-helpers in ``pyproject.toml`` by adding
+the following configuration to the ``pyproject.toml`` file::
+
+    [tool.extension-helpers]
+    use_extension_helpers = true
+
+.. note::
+  For backwards compatibility, the setting of ``use_extension_helpers`` in
+  ``setup.cfg`` will override any setting of it in ``pyproject.toml``.
diff --git a/extension_helpers/__init__.py b/extension_helpers/__init__.py
index 98f7953..d6323fc 100644
--- a/extension_helpers/__init__.py
+++ b/extension_helpers/__init__.py
@@ -11,11 +11,31 @@ def _finalize_distribution_hook(distribution):
     Entry point for setuptools which allows extension-helpers to be enabled
     from setup.cfg without the need for setup.py.
     """
+    import os
+    from pathlib import Path
+
+    import tomli
+
     config_files = distribution.find_config_files()
     if len(config_files) == 0:
         return
+
     cfg = ConfigParser()
     cfg.read(config_files[0])
-    if (cfg.has_option("extension-helpers", "use_extension_helpers") and
-            cfg.get("extension-helpers", "use_extension_helpers").lower() == 'true'):
-        distribution.ext_modules = get_extensions()
+    found_config = False
+    if cfg.has_option("extension-helpers", "use_extension_helpers"):
+        found_config = True
+
+        if cfg.get("extension-helpers", "use_extension_helpers").lower() == 'true':
+            distribution.ext_modules = get_extensions()
+
+    pyproject = Path(distribution.src_root or os.curdir, "pyproject.toml")
+    if pyproject.exists() and not found_config:
+        with pyproject.open("rb") as f:
+            pyproject_cfg = tomli.load(f)
+            if ('tool' in pyproject_cfg and
+                    'extension-helpers' in pyproject_cfg['tool'] and
+                    'use_extension_helpers' in pyproject_cfg['tool']['extension-helpers'] and
+                    pyproject_cfg['tool']['extension-helpers']['use_extension_helpers']):
+
+                distribution.ext_modules = get_extensions()
diff --git a/setup.cfg b/setup.cfg
index 5769b70..93c9b8f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -26,6 +26,7 @@ python_requires = >=3.7
 packages = find:
 install_requires =
     setuptools>=40.2
+    tomli>=1.0.0
 
 [options.package_data]
 extension_helpers = src/compiler.c


Test patch:
diff --git a/extension_helpers/tests/test_setup_helpers.py b/extension_helpers/tests/test_setup_helpers.py
index 05fc7ab..8eeea0c 100644
--- a/extension_helpers/tests/test_setup_helpers.py
+++ b/extension_helpers/tests/test_setup_helpers.py
@@ -184,7 +184,8 @@ def test_compiler_module(capsys, c_extension_test_package):
 
 
 @pytest.mark.parametrize('use_extension_helpers', [None, False, True])
-def test_no_setup_py(tmpdir, use_extension_helpers):
+@pytest.mark.parametrize('pyproject_use_helpers', [None, False, True])
+def test_no_setup_py(tmpdir, use_extension_helpers, pyproject_use_helpers):
     """
     Test that makes sure that extension-helpers can be enabled without a
     setup.py file.
@@ -242,12 +243,23 @@ def test_no_setup_py(tmpdir, use_extension_helpers):
             use_extension_helpers = {str(use_extension_helpers).lower()}
         """))
 
-    test_pkg.join('pyproject.toml').write(dedent("""\
-        [build-system]
-        requires = ["setuptools>=43.0.0",
-                    "wheel"]
-        build-backend = 'setuptools.build_meta'
-    """))
+    if pyproject_use_helpers is None:
+        test_pkg.join('pyproject.toml').write(dedent("""\
+            [build-system]
+            requires = ["setuptools>=43.0.0",
+                        "wheel"]
+            build-backend = 'setuptools.build_meta'
+        """))
+    else:
+        test_pkg.join('pyproject.toml').write(dedent(f"""\
+            [build-system]
+            requires = ["setuptools>=43.0.0",
+                        "wheel"]
+            build-backend = 'setuptools.build_meta'
+
+            [tool.extension-helpers]
+            use_extension_helpers = {str(pyproject_use_helpers).lower()}
+        """))
 
     install_temp = test_pkg.mkdir('install_temp')
 
@@ -267,7 +279,7 @@ def test_no_setup_py(tmpdir, use_extension_helpers):
 
         importlib.import_module(package_name)
 
-        if use_extension_helpers:
+        if use_extension_helpers or (use_extension_helpers is None and pyproject_use_helpers):
             compiler_version_mod = importlib.import_module(package_name + '.compiler_version')
             assert compiler_version_mod.compiler != 'unknown'
         else: