Skip to content

Commit 8a69f1c

Browse files
Merge pull request #364 from pypa/feature/declarative-config
Implement declarative config for compatibility with setuptools declarative config
2 parents 6aaf8bb + 0fa6272 commit 8a69f1c

File tree

10 files changed

+132
-6
lines changed

10 files changed

+132
-6
lines changed

CHANGELOG.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
v3.4.0
2+
======
3+
4+
* fix #181 - add support for projects built under setuptools declarative config
5+
by way of the setuptools.finalize_distribution_options hook in Setuptools 42.
6+
17
* fix #305 - ensure the git file finder closes filedescriptors even when errors happen
28

39
v3.3.3

README.rst

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,63 @@ It also handles file finders for the supported SCMs.
1313
.. image:: https://tidelift.com/badges/github/pypa/setuptools_scm
1414
:target: https://tidelift.com/subscription/pkg/pypi-setuptools_scm?utm_source=pypi-setuptools_scm&utm_medium=readme
1515

16+
``pyproject.toml`` usage
17+
------------------------
18+
19+
The preferred way to configure ``setuptools_scm`` is to author
20+
settings in a ``tool.setuptools_scm`` section of ``pyproject.toml``.
21+
22+
This feature requires Setuptools 42 or later, released in Nov, 2019.
23+
If your project needs to support build from sdist on older versions
24+
of Setuptools, you will need to also implement the ``setup.py usage``
25+
for those legacy environments.
26+
27+
First, ensure that ``setuptools_scm`` is present during the project's
28+
built step by specifying it as one of the build requirements.
29+
30+
.. code:: ini
31+
32+
# pyproject.toml
33+
[build-system]
34+
requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4"]
35+
36+
Note that the ``toml`` extra must be supplied.
37+
38+
That will be sufficient to require ``setuptools_scm`` for projects
39+
that support PEP 518 (`pip <https://pypi.org/project/pip>`_ and
40+
`pep517 <https://pypi.org/project/pep517/>`_). Many tools,
41+
especially those that invoke ``setup.py`` for any reason, may
42+
continue to rely on ``setup_requires``. For maximum compatibility
43+
with those uses, consider also including a ``setup_requires`` directive
44+
(described below in ``setup.py usage`` and ``setup.cfg``).
45+
46+
To enable version inference, add this section to your pyproject.toml:
47+
48+
.. code:: ini
49+
50+
# pyproject.toml
51+
[tools.setuptools_scm]
52+
53+
Including this section is comparable to supplying
54+
``use_scm_version=True`` in ``setup.py``. Additionally,
55+
include arbitrary keyword arguments in that section
56+
to be supplied to ``get_version()``. For example::
57+
58+
.. code:: ini
59+
60+
# pyproject.toml
61+
[tools.setuptools_scm]
62+
write_to = pkg/version.py
63+
64+
1665
``setup.py`` usage
1766
------------------
1867

68+
The following settings are considered legacy behavior and
69+
superseded by the ``pyproject.toml`` usage, but for maximal
70+
compatibility, projects may also supply the configuration in
71+
this older form.
72+
1973
To use ``setuptools_scm`` just modify your project's ``setup.py`` file
2074
like this:
2175

setup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ def parse(root):
6868
[setuptools.file_finders]
6969
setuptools_scm = setuptools_scm.integration:find_files
7070
71+
[setuptools.finalize_distribution_options]
72+
setuptools_scm = setuptools_scm.integration:infer_version
73+
7174
[setuptools_scm.parse_scm]
7275
.hg = setuptools_scm.hg:parse
7376
.git = setuptools_scm.git:parse
@@ -111,6 +114,7 @@ def parse(root):
111114
"Topic :: Utilities",
112115
],
113116
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
117+
extras_require=dict(toml=["toml"]),
114118
)
115119

116120
if __name__ == "__main__":

src/setuptools_scm/__init__.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,18 +146,23 @@ def get_version(
146146
config.fallback_version = fallback_version
147147
config.parse = parse
148148
config.git_describe_command = git_describe_command
149+
return _get_version(config)
149150

151+
152+
def _get_version(config):
150153
parsed_version = _do_parse(config)
151154

152155
if parsed_version:
153156
version_string = format_version(
154-
parsed_version, version_scheme=version_scheme, local_scheme=local_scheme
157+
parsed_version,
158+
version_scheme=config.version_scheme,
159+
local_scheme=config.local_scheme,
155160
)
156161
dump_version(
157-
root=root,
162+
root=config.root,
158163
version=version_string,
159-
write_to=write_to,
160-
template=write_to_template,
164+
write_to=config.write_to,
165+
template=config.write_to_template,
161166
)
162167

163168
return version_string

src/setuptools_scm/config.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,19 @@ def tag_regex(self):
105105
@tag_regex.setter
106106
def tag_regex(self, value):
107107
self._tag_regex = _check_tag_regex(value)
108+
109+
def _load(self, values):
110+
vars(self).update(values)
111+
return self
112+
113+
@classmethod
114+
def from_file(cls, name="pyproject.toml"):
115+
"""
116+
Read Configuration from pyproject.toml (or similar).
117+
Raises exceptions when file is not found or toml is
118+
not installed or the file has invalid format or does
119+
not contain the [tool.setuptools_scm] section.
120+
"""
121+
with open(name) as strm:
122+
defn = __import__("toml").load(strm)
123+
return cls()._load(defn.get("tool", {})["setuptools_scm"])

src/setuptools_scm/integration.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from pkg_resources import iter_entry_points
22

33
from .version import _warn_if_setuptools_outdated
4-
from .utils import do
5-
from . import get_version
4+
from .config import Configuration
5+
from .utils import do, trace_exception
6+
from . import get_version, _get_version
67

78

89
def version_keyword(dist, keyword, value):
@@ -28,3 +29,11 @@ def find_files(path=""):
2829
if res:
2930
return res
3031
return []
32+
33+
34+
def infer_version(dist):
35+
try:
36+
config = Configuration.from_file()
37+
except Exception:
38+
return trace_exception()
39+
dist.metadata.version = _get_version(config)

src/setuptools_scm/utils.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import os
1111
import io
1212
import platform
13+
import traceback
1314

1415

1516
DEBUG = bool(os.environ.get("SETUPTOOLS_SCM_DEBUG"))
@@ -25,6 +26,10 @@ def trace(*k):
2526
sys.stdout.flush()
2627

2728

29+
def trace_exception():
30+
DEBUG and traceback.print_exc()
31+
32+
2833
def ensure_stripped_str(str_or_bytes):
2934
if isinstance(str_or_bytes, str):
3035
return str_or_bytes.strip()

testing/test_config.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import unicode_literals
2+
13
from setuptools_scm.config import Configuration
24

35
import pytest
@@ -18,3 +20,9 @@ def test_tag_regex(tag, expected_version):
1820
match = config.tag_regex.match(tag)
1921
version = match.group("version")
2022
assert version == expected_version
23+
24+
25+
def test_config_from_pyproject(tmpdir):
26+
fn = tmpdir / "pyproject.toml"
27+
fn.write_text("[tool.setuptools_scm]\n", encoding="utf-8")
28+
assert Configuration.from_file(str(fn))

testing/test_integration.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import sys
2+
3+
from setuptools_scm.utils import do
4+
5+
6+
def test_pyproject_support(tmpdir, monkeypatch):
7+
monkeypatch.delenv("SETUPTOOLS_SCM_DEBUG")
8+
pkg = tmpdir.ensure("package", dir=42)
9+
pkg.join("pyproject.toml").write(
10+
"""[tool.setuptools_scm]
11+
fallback_version = "12.34"
12+
"""
13+
)
14+
pkg.join("setup.py").write("__import__('setuptools').setup()")
15+
res = do((sys.executable, "setup.py", "--version"), pkg)
16+
assert res == "12.34"

tox.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ skip_install=
2525
test: False
2626
deps=
2727
pytest
28+
setuptools >= 42
2829
commands=
2930
test: py.test []
3031
selfcheck: python setup.py --version
32+
extras =
33+
toml
3134

3235
[testenv:flake8]
3336
skip_install=True

0 commit comments

Comments
 (0)