Skip to content

Implement declarative config for compatibility with setuptools declarative config #364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Nov 25, 2019
Merged
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
v3.4.0
======

* fix #181 - add support for projects built under setuptools declarative config
by way of the setuptools.finalize_distribution_options hook in Setuptools 42.

* fix #305 - ensure the git file finder closes filedescriptors even when errors happen

v3.3.3
Expand Down
54 changes: 54 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,63 @@ It also handles file finders for the supported SCMs.
.. image:: https://tidelift.com/badges/github/pypa/setuptools_scm
:target: https://tidelift.com/subscription/pkg/pypi-setuptools_scm?utm_source=pypi-setuptools_scm&utm_medium=readme

``pyproject.toml`` usage
------------------------

The preferred way to configure ``setuptools_scm`` is to author
settings in a ``tool.setuptools_scm`` section of ``pyproject.toml``.

This feature requires Setuptools 42 or later, released in Nov, 2019.
If your project needs to support build from sdist on older versions
of Setuptools, you will need to also implement the ``setup.py usage``
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you placed the closing backticks too far...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't quite sure how to handle that, given that the backticks are in the title. I'm happy to accept edits on it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. I'm not sure either. Could probably try using a link syntax.

for those legacy environments.

First, ensure that ``setuptools_scm`` is present during the project's
built step by specifying it as one of the build requirements.

.. code:: ini

# pyproject.toml
[build-system]
requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4"]

Note that the ``toml`` extra must be supplied.

That will be sufficient to require ``setuptools_scm`` for projects
that support PEP 518 (`pip <https://pypi.org/project/pip>`_ and
`pep517 <https://pypi.org/project/pep517/>`_). Many tools,
especially those that invoke ``setup.py`` for any reason, may
continue to rely on ``setup_requires``. For maximum compatibility
with those uses, consider also including a ``setup_requires`` directive
(described below in ``setup.py usage`` and ``setup.cfg``).

To enable version inference, add this section to your pyproject.toml:

.. code:: ini

# pyproject.toml
[tools.setuptools_scm]

Including this section is comparable to supplying
``use_scm_version=True`` in ``setup.py``. Additionally,
include arbitrary keyword arguments in that section
to be supplied to ``get_version()``. For example::

.. code:: ini

# pyproject.toml
[tools.setuptools_scm]
write_to = pkg/version.py


``setup.py`` usage
------------------

The following settings are considered legacy behavior and
superseded by the ``pyproject.toml`` usage, but for maximal
compatibility, projects may also supply the configuration in
this older form.

To use ``setuptools_scm`` just modify your project's ``setup.py`` file
like this:

Expand Down
4 changes: 4 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ def parse(root):
[setuptools.file_finders]
setuptools_scm = setuptools_scm.integration:find_files

[setuptools.finalize_distribution_options]
setuptools_scm = setuptools_scm.integration:infer_version

[setuptools_scm.parse_scm]
.hg = setuptools_scm.hg:parse
.git = setuptools_scm.git:parse
Expand Down Expand Up @@ -111,6 +114,7 @@ def parse(root):
"Topic :: Utilities",
],
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
extras_require=dict(toml=["toml"]),
)

if __name__ == "__main__":
Expand Down
13 changes: 9 additions & 4 deletions src/setuptools_scm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,18 +146,23 @@ def get_version(
config.fallback_version = fallback_version
config.parse = parse
config.git_describe_command = git_describe_command
return _get_version(config)


def _get_version(config):
parsed_version = _do_parse(config)

if parsed_version:
version_string = format_version(
parsed_version, version_scheme=version_scheme, local_scheme=local_scheme
parsed_version,
version_scheme=config.version_scheme,
local_scheme=config.local_scheme,
)
dump_version(
root=root,
root=config.root,
version=version_string,
write_to=write_to,
template=write_to_template,
write_to=config.write_to,
template=config.write_to_template,
)

return version_string
16 changes: 16 additions & 0 deletions src/setuptools_scm/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,19 @@ def tag_regex(self):
@tag_regex.setter
def tag_regex(self, value):
self._tag_regex = _check_tag_regex(value)

def _load(self, values):
vars(self).update(values)
return self

@classmethod
def from_file(cls, name="pyproject.toml"):
"""
Read Configuration from pyproject.toml (or similar).
Raises exceptions when file is not found or toml is
not installed or the file has invalid format or does
not contain the [tool.setuptools_scm] section.
"""
with open(name) as strm:
defn = __import__("toml").load(strm)
return cls()._load(defn.get("tool", {})["setuptools_scm"])
13 changes: 11 additions & 2 deletions src/setuptools_scm/integration.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from pkg_resources import iter_entry_points

from .version import _warn_if_setuptools_outdated
from .utils import do
from . import get_version
from .config import Configuration
from .utils import do, trace_exception
from . import get_version, _get_version


def version_keyword(dist, keyword, value):
Expand All @@ -28,3 +29,11 @@ def find_files(path=""):
if res:
return res
return []


def infer_version(dist):
try:
config = Configuration.from_file()
except Exception:
return trace_exception()
dist.metadata.version = _get_version(config)
5 changes: 5 additions & 0 deletions src/setuptools_scm/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import os
import io
import platform
import traceback


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


def trace_exception():
DEBUG and traceback.print_exc()


def ensure_stripped_str(str_or_bytes):
if isinstance(str_or_bytes, str):
return str_or_bytes.strip()
Expand Down
8 changes: 8 additions & 0 deletions testing/test_config.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import unicode_literals

from setuptools_scm.config import Configuration

import pytest
Expand All @@ -18,3 +20,9 @@ def test_tag_regex(tag, expected_version):
match = config.tag_regex.match(tag)
version = match.group("version")
assert version == expected_version


def test_config_from_pyproject(tmpdir):
fn = tmpdir / "pyproject.toml"
fn.write_text("[tool.setuptools_scm]\n", encoding="utf-8")
assert Configuration.from_file(str(fn))
16 changes: 16 additions & 0 deletions testing/test_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import sys

from setuptools_scm.utils import do


def test_pyproject_support(tmpdir, monkeypatch):
monkeypatch.delenv("SETUPTOOLS_SCM_DEBUG")
pkg = tmpdir.ensure("package", dir=42)
pkg.join("pyproject.toml").write(
"""[tool.setuptools_scm]
fallback_version = "12.34"
"""
)
pkg.join("setup.py").write("__import__('setuptools').setup()")
res = do((sys.executable, "setup.py", "--version"), pkg)
assert res == "12.34"
3 changes: 3 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ skip_install=
test: False
deps=
pytest
setuptools >= 42
commands=
test: py.test []
selfcheck: python setup.py --version
extras =
toml

[testenv:flake8]
skip_install=True
Expand Down