setuptools_scm
setuptools_scm copied to clipboard
`UserWarning: tag '0.0' no version found` in a fresh Git repo when `tag_regex` is defined
Trying to use setuptools_scm==7.1.0
on a brand new repository with no tags fails if tag_regex
has been specified that does not match the default fallback version 0.0
, like the example below:
^(?P<prefix>packagename[-_])(?P<version>[vV]?\d+(?:\.\d+){0,2}[^\+]*)(?:\+.*)?$
After a little troubleshooting and inspecting the source code, the problem seems to be that if no tags are found in the parent git repo matching the provided regex, setuptools_scm.git._git_parse_inner
attempts to fake a tag 0.0
to provide to setuptools_scm.version.meta
as a default.
This later causes a panic when setuptools_scm.version.tag_to_version
attempts to match 0.0
against the configured regular expression and returns None
.
For context, I'm trying to introduce setuptools_scm
to a pre-existing monorepo containing multiple Python projects that need to be individually versioned. As such, I can't use an optional prefix as tags without a prefix would have a chance to override the version of every package in the repository.
sampleproject/pyproject.toml
[project]
name = "sampleproject"
dynamic = ["version"]
requires-python = ">=3.7"
[tool.setuptools_scm]
root = ".."
write_to = "sampleproject/src/sample/_version.py"
tag_regex = "^(?P<prefix>sampleproject[-_])(?P<version>[vV]?\\d+(?:\\.\\d+){0,2}[^\\+]*)(?:\\+.*)?$"
fallback_version = "0.0.0"
[build-system]
requires = ["setuptools>=45.0.0", "setuptools_scm[toml]>=7.1", "wheel"]
build-backend = "setuptools.build_meta"
$ export SETUPTOOLS_SCM_DEBUG=1; pip3 install sampleproject/
Defaulting to user installation because normal site-packages is not writeable
Processing ./sampleproject
Installing build dependencies ... done
Getting requirements to build wheel ... error
error: subprocess-exited-with-error
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> [125 lines of output]
finalize hook {'name': None, 'version': None, 'author': None, 'author_email': None, 'maintainer': None, 'maintainer_email': None, 'url': None, 'license': None, 'description': None, 'long_description': None, 'keywords': None, 'platforms': None, 'classifiers': None, 'download_url': None, 'provides': None, 'requires': None, 'obsoletes': None}
abs root {'root': '..', 'relative_to': 'pyproject.toml'}
file pyproject.toml
root '/workspaces/setuptools_scm_test'
relative_to 'pyproject.toml'
dist name: sampleproject
version_from_ep setuptools_scm.parse_scm /workspaces/setuptools_scm_test
looking for ep setuptools_scm.parse_scm /workspaces/setuptools_scm_test
found ep EntryPoint(name='.git', value='setuptools_scm.git:parse', group='setuptools_scm.parse_scm') in /workspaces/setuptools_scm_test
GIT_ASKPASS /vscode/vscode-server/bin/linux-x64/e8a3071ea4344d9d48ef8a4df2c097372b0c5161/extensions/git/dist/askpass.sh
GIT_EDITOR code --wait
----
cmd:
git --git-dir /workspaces/setuptools_scm_test/.git rev-parse --show-prefix
in: /workspaces/setuptools_scm_test
GIT_ASKPASS /vscode/vscode-server/bin/linux-x64/e8a3071ea4344d9d48ef8a4df2c097372b0c5161/extensions/git/dist/askpass.sh
GIT_EDITOR code --wait
out:
real root /workspaces/setuptools_scm_test
GIT_ASKPASS /vscode/vscode-server/bin/linux-x64/e8a3071ea4344d9d48ef8a4df2c097372b0c5161/extensions/git/dist/askpass.sh
GIT_EDITOR code --wait
----
cmd:
git --git-dir /workspaces/setuptools_scm_test/.git describe --dirty --tags --long --match "*[0-9]*"
in: /workspaces/setuptools_scm_test
GIT_ASKPASS /vscode/vscode-server/bin/linux-x64/e8a3071ea4344d9d48ef8a4df2c097372b0c5161/extensions/git/dist/askpass.sh
GIT_EDITOR code --wait
err:
fatal: No names found, cannot describe anything.
ret: 128
----
cmd:
git --git-dir /workspaces/setuptools_scm_test/.git rev-parse --verify --quiet HEAD
in: /workspaces/setuptools_scm_test
GIT_ASKPASS /vscode/vscode-server/bin/linux-x64/e8a3071ea4344d9d48ef8a4df2c097372b0c5161/extensions/git/dist/askpass.sh
GIT_EDITOR code --wait
out:
c89112a048f30200569cd48efcd796c7833f062d
----
cmd:
git --git-dir /workspaces/setuptools_scm_test/.git rev-list HEAD
in: /workspaces/setuptools_scm_test
GIT_ASKPASS /vscode/vscode-server/bin/linux-x64/e8a3071ea4344d9d48ef8a4df2c097372b0c5161/extensions/git/dist/askpass.sh
GIT_EDITOR code --wait
out:
c89112a048f30200569cd48efcd796c7833f062d
a3a2a2c86e1e71761ea9581d3026313732c137bb
----
cmd:
git --git-dir /workspaces/setuptools_scm_test/.git status --porcelain --untracked-files=no
in: /workspaces/setuptools_scm_test
GIT_ASKPASS /vscode/vscode-server/bin/linux-x64/e8a3071ea4344d9d48ef8a4df2c097372b0c5161/extensions/git/dist/askpass.sh
GIT_EDITOR code --wait
----
cmd:
git --git-dir /workspaces/setuptools_scm_test/.git rev-parse --abbrev-ref HEAD
in: /workspaces/setuptools_scm_test
GIT_ASKPASS /vscode/vscode-server/bin/linux-x64/e8a3071ea4344d9d48ef8a4df2c097372b0c5161/extensions/git/dist/askpass.sh
GIT_EDITOR code --wait
out:
master
----
cmd:
git --git-dir /workspaces/setuptools_scm_test/.git -c log.showSignature=false log -n 1 HEAD --format=%cI
in: /workspaces/setuptools_scm_test
GIT_ASKPASS /vscode/vscode-server/bin/linux-x64/e8a3071ea4344d9d48ef8a4df2c097372b0c5161/extensions/git/dist/askpass.sh
GIT_EDITOR code --wait
out:
2023-02-15T07:09:11+00:00
tag 0.0
tag '0.0' parsed to None
/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools_scm/version.py:84: UserWarning: tag '0.0' no version found
warnings.warn(f"tag {tag!r} no version found")
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 363, in <module>
main()
File "/usr/local/lib/python3.8/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 345, in main
json_out['return_val'] = hook(**hook_input['kwargs'])
File "/usr/local/lib/python3.8/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 130, in get_requires_for_build_wheel
return hook(config_settings)
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 338, in get_requires_for_build_wheel
return self._get_build_requires(config_settings, requirements=['wheel'])
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 320, in _get_build_requires
self.run_setup()
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 335, in run_setup
exec(code, locals())
File "<string>", line 1, in <module>
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools/__init__.py", line 108, in setup
return distutils.core.setup(**attrs)
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools/_distutils/core.py", line 147, in setup
_setup_distribution = dist = klass(attrs)
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools/dist.py", line 488, in __init__
_Distribution.__init__(
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools/_distutils/dist.py", line 283, in __init__
self.finalize_options()
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools/dist.py", line 912, in finalize_options
ep(self)
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools_scm/integration.py", line 127, in infer_version
_assign_version(dist, config)
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools_scm/integration.py", line 60, in _assign_version
maybe_version = _get_version(config)
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools_scm/__init__.py", line 153, in _get_version
parsed_version = _do_parse(config)
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools_scm/__init__.py", line 100, in _do_parse
version = _version_from_entrypoints(config) or _version_from_entrypoints(
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools_scm/_entrypoints.py", line 66, in _version_from_entrypoints
version: ScmVersion | None = _call_entrypoint_fn(root, config, ep.load())
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools_scm/_entrypoints.py", line 40, in _call_entrypoint_fn
return fn(root, config=config)
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools_scm/git.py", line 181, in parse
return _git_parse_inner(
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools_scm/git.py", line 224, in _git_parse_inner
return meta(
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools_scm/version.py", line 226, in meta
parsed_version = _parse_tag(tag, preformatted, config)
File "/tmp/pip-build-env-tt745vl_/overlay/lib/python3.8/site-packages/setuptools_scm/version.py", line 203, in _parse_tag
assert version is not None
AssertionError
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
error: subprocess-exited-with-error
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> See above for output.
note: This error originates from a subprocess, and is likely not a problem with pip.
Good catch, the tag regex ought not to be applied to the fallback version when none is found
For what it's worth, this issue happens whether the user has specified a fallback_version
or not.
The culprit is a hard-coded default in git.py
.
I'm currently working around the issue by specifying a custom git_describe_command
that calls out to a shell script that provides its own default value if git describe
returns an error.
sampleproject/pyproject.toml
[project]
name = "sampleproject"
dynamic = ["version"]
requires-python = ">=3.7"
[tool.setuptools_scm]
root = ".."
write_to = "sampleproject/src/sample/_version.py"
tag_regex = "^(?P<prefix>sampleproject[-_])(?P<version>[vV]?\\d+(?:\\.\\d+){0,2}[^\\+]*)(?:\\+.*)?$"
git_describe_command = ["common/scripts/git-describe.bash", "sampleproject"]
[build-system]
requires = ["setuptools>=45.0.0", "setuptools_scm[toml]>=7.1", "wheel"]
build-backend = "setuptools.build_meta"
common/scripts/git-describe.bash
#!/usr/bin/env bash
set -euo pipefail
if [[ $# != 1 || $@ == "--help" || $@ == "-h" ]]
then
echo "Usage: $0 TAG_PREFIX"
exit 1
fi
TAG_PREFIX=$1
git describe --dirty --tags --long --match '*[0-9]*' || echo "${TAG_PREFIX}-0.0.0-1-g$(git rev-parse --short HEAD)$(git diff --quiet || echo -dirty)"
IMHO, I got this UserWarning which effectively translated to a full runtime error while having two tags, one matching the pattern and one not. IMHO, the whole point of this tag_regex
was to filter the list of tags in order to determine which ones are safe to be used. Still, what happens is that it picks the bad one first and instead of ignoring it and picking the next one, it fails ugly.
My pattern is tag_regex = "^(?P<prefix>v)?(?P<version>[0-9]+.[0-9.]+)(?P<suffix>.*)?$"
* Getting build dependencies for sdist...
/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/version.py:95: UserWarning: tag 'v6' no version found
warnings.warn(f"tag {tag!r} no version found")
Traceback (most recent call last):
File "/Users/ssbarnea/c/a/ansible-lint/.tox/pkg/lib/python3.12/site-packages/pyproject_hooks/_in_process/_in_process.py", line 353, in <module>
main()
File "/Users/ssbarnea/c/a/ansible-lint/.tox/pkg/lib/python3.12/site-packages/pyproject_hooks/_in_process/_in_process.py", line 335, in main
json_out['return_val'] = hook(**hook_input['kwargs'])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/ssbarnea/c/a/ansible-lint/.tox/pkg/lib/python3.12/site-packages/pyproject_hooks/_in_process/_in_process.py", line 287, in get_requires_for_build_sdist
return hook(config_settings)
^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools/build_meta.py", line 358, in get_requires_for_build_sdist
return self._get_build_requires(config_settings, requirements=[])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools/build_meta.py", line 325, in _get_build_requires
self.run_setup()
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools/build_meta.py", line 341, in run_setup
exec(code, locals())
File "<string>", line 1, in <module>
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools/__init__.py", line 103, in setup
return distutils.core.setup(**attrs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools/_distutils/core.py", line 147, in setup
_setup_distribution = dist = klass(attrs)
^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools/dist.py", line 303, in __init__
_Distribution.__init__(self, dist_attrs)
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools/_distutils/dist.py", line 283, in __init__
self.finalize_options()
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools/dist.py", line 680, in finalize_options
ep(self)
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/_integration/setuptools.py", line 121, in infer_version
_assign_version(dist, config)
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/_integration/setuptools.py", line 53, in _assign_version
maybe_version = _get_version(config, force_write_version_files=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/_get_version_impl.py", line 93, in _get_version
parsed_version = parse_version(config)
^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/_get_version_impl.py", line 56, in parse_version
or parse_scm_version(config)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/_get_version_impl.py", line 35, in parse_scm_version
return _entrypoints.version_from_entrypoint(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/_entrypoints.py", line 55, in version_from_entrypoint
maybe_version: version.ScmVersion | None = fn(root, config=config)
^^^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/git.py", line 211, in parse
return _git_parse_inner(
^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/git.py", line 255, in _git_parse_inner
version = version_from_describe(wd, config, describe_command)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/git.py", line 243, in version_from_describe
return describe_res.parse_success(parse=parse_describe)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/_run_cmd.py", line 77, in parse_success
return parse(self.stdout)
^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/git.py", line 241, in parse_describe
return meta(tag=tag, distance=distance, dirty=dirty, node=node, config=config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/version.py", line 210, in meta
parsed_version = _parse_tag(tag, preformatted, config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/private/var/folders/32/1xrphgzd4xv777syxjtkpdw80000gn/T/build-env-nffze1n6/lib/python3.12/site-packages/setuptools_scm/version.py", line 193, in _parse_tag
assert version is not None
AssertionError
ERROR Backend subprocess exited when trying to invoke get_requires_for_build_sdist
Any suggestings?
@ssbarnea custom describe command in the git case - theres no direct control over the tag thats picked for describe, so both have to be adapted atm