summaryrefslogtreecommitdiff
path: root/src/setuptools_scm/_integration/setuptools.py
blob: 94981d75ec2d350ed34284cd0b451434e4fb1768 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
from __future__ import annotations

import logging
import os
import warnings
from typing import Any
from typing import Callable

import setuptools

from .. import _config
from .._version_cls import _validate_version_cls

log = logging.getLogger(__name__)


def read_dist_name_from_setup_cfg(
    input: str | os.PathLike[str] = "setup.cfg",
) -> str | None:
    # minimal effort to read dist_name off setup.cfg metadata
    import configparser

    parser = configparser.ConfigParser()
    parser.read([input], encoding="utf-8")
    dist_name = parser.get("metadata", "name", fallback=None)
    return dist_name


def _warn_on_old_setuptools(_version: str = setuptools.__version__) -> None:
    if int(_version.split(".")[0]) < 61:
        warnings.warn(
            RuntimeWarning(
                f"""
ERROR: setuptools=={_version} is used in combination with setuptools_scm>=8.x

Your build configuration is incomplete and previously worked by accident!
setuptools_scm requires setuptools>=61

Suggested workaround if applicable:
 - migrating from the deprecated setup_requires mechanism to pep517/518
   and using a pyproject.toml to declare build dependencies
   which are reliably pre-installed before running the build tools
"""
            )
        )


def _assign_version(
    dist: setuptools.Distribution, config: _config.Configuration
) -> None:
    from .. import _get_version, _version_missing

    maybe_version = _get_version(config)

    if maybe_version is None:
        _version_missing(config)
    else:
        assert dist.metadata.version is None
        dist.metadata.version = maybe_version


_warn_on_old_setuptools()


def version_keyword(
    dist: setuptools.Distribution,
    keyword: str,
    value: bool | dict[str, Any] | Callable[[], dict[str, Any]],
) -> None:
    if not value:
        return
    elif value is True:
        value = {}
    elif callable(value):
        value = value()
    assert (
        "dist_name" not in value
    ), "dist_name may not be specified in the setup keyword "
    dist_name: str | None = dist.metadata.name
    if dist.metadata.version is not None:
        warnings.warn(f"version of {dist_name} already set")
        return
    log.debug(
        "version keyword %r",
        vars(dist.metadata),
    )
    log.debug("dist %s %s", id(dist), id(dist.metadata))

    if dist_name is None:
        dist_name = read_dist_name_from_setup_cfg()
    version_cls = value.pop("version_cls", None)
    normalize = value.pop("normalize", True)
    final_version = _validate_version_cls(version_cls, normalize)
    config = _config.Configuration(
        dist_name=dist_name, version_cls=final_version, **value
    )
    _assign_version(dist, config)


def infer_version(dist: setuptools.Distribution) -> None:
    log.debug(
        "finalize hook %r",
        vars(dist.metadata),
    )
    log.debug("dist %s %s", id(dist), id(dist.metadata))
    if dist.metadata.version is not None:
        return  # metadata already added by hook
    dist_name = dist.metadata.name
    if dist_name is None:
        dist_name = read_dist_name_from_setup_cfg()
    if not os.path.isfile("pyproject.toml"):
        return
    if dist_name == "setuptools_scm":
        return
    try:
        config = _config.Configuration.from_file(dist_name=dist_name)
    except LookupError as e:
        log.exception(e)
    else:
        _assign_version(dist, config)