-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Hi @jwodder ,
I've been playing around with versioningit and hatchling to maybe adapt to it and I am facing an issue with local version specs in the format process. Let's take a tag like poc-2.6.0+dt, where we explicitly track a local version spec due to some internal modifications of a public package.
However, with the initial config below I try to fetch the version incl. the local-version-spec from git to hand it over to versioningit. See the first 2 steps (vcs, tag2version).
Now, obviously on a dirty tag (and the two other states will have the same outcome) the result is not pep440 compliant due to the double + while using the formatting in the "format" step.
-
When I exclude the local version spec from the version-capture-group in the regex pattern (tag2version) and instead add the local version
+dtto the three format states, so that the versions stay pep440 compliant, I get a proper result for dirty/distance/distance-dirty versions containing the local version spec.- When I call
versioningit -nI will only get the basenext_versionwithout the +dt suffix, which makes sence in terms of templating/formating. But not nice though. - When I'm on a clean tag ref, then the current version also im missing the +dt as I excluded it from the version-capture-group. Also not nice for building releases.
- When I call
-
Now, when I instead keep the initial version-capture-group to include the local-version-spec, I can somehow overcome the initial issue in the format step with this config (see the trailing comments):
[tool.hatch.version.format] method = "basic" # Distance Example: 1.2.4.dev42+dt.ge174a1f distance = "{next_version}.dev{distance}+dt.{vcs}{rev}" # +dt is hard-coded now as part of the local version # Dirty Example: 1.2.3+dt.d20230922 dirty = "{base_version}.d{build_date:%Y%m%d}" # base_version contains +dt due to the version-capture-group # Distance-Dirty Example: 1.2.4.dev42+dt.ge174a1f.d20230922 distance-dirty = "{next_version}.dev{distance}+dt.{vcs}{rev}.d{build_date:%Y%m%d}" # +dt is hard-coded now as part of the local version
This leads to correct dirty/distance/distance-dirty versions as also to correct versions on a clean tag ref. However, the next_version never contains the +dt, which is still not perfect. And I have to hard-code the local-version-spec in the config, which is not good if the repo would use different types of local-version-specs.
As you can see in 2. the format config is more like a workaround with limits than a good intuitive handling. I would like you to consider to implement a better handling for the local version spec as it is part of PEP440 (canonical compliance is out of scope here).
Suggestions:
When the user decides to capture the local version spec in tag2version, then:
- extract it internally from the captured version tag and save it for later use
- maybe remove it also from the base_version for the
whole processingprocessing in "next_version" (already done?) and "format" steps, so that the 3 states in "format" become more consistent (the user has to hard-code the local version manually). Or even better: provide a template-variable like {local_version} containing the initially captured "+abcd123.abcd123" string for the "format" step. - finally append the previously extracted/saved local version spec back to a CLEAN current version or CLEAN next version (as these cannot be templated by the user) BEFORE moving on to "template-fields", "write" or "onbuild", so that the splitting, writing or the replacement in onbuild will be consistent.
- This approach would also fit the "template_fields" step as then:
- base_version would not contain the local version spec
- there would be a new variable local_version covering this
- the final version and version_tuple would be complete as mentioned in 3.
I hope you can pick this request up and implement it soon and that I did not make any mistakes in my suggestion. :D Send me a reply if you have further questions. Cheers. :D
Initial Config:
[tool.hatch.version]
source = "versioningit"
default-version = "0.0.0+unknown"
[tool.hatch.version.vcs]
method = "git"
match = ["*[0-9].[0-9].[0-9]*"]
default-tag = "0.0.0+unknown"
[tool.hatch.version.tag2version]
method = "basic"
# [ prefix ](?P<version>[ canonical version identifier ][ local version identifier ])[ git-describe suffix ]
regex = "^([\\w-]+-)?[vV]?(?P<version>([1-9][0-9]*!)?(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\\.post(0|[1-9][0-9]*))?(\\.dev(0|[1-9][0-9]*))?(\\+[a-z0-9]+(\\.[a-z0-9]+)*)?)(\\-[0-9]+\\-g[a-f0-9]+)?$"
require-match = true
[tool.hatch.version.next-version]
method = "smallest"
[tool.hatch.version.format]
method = "basic"
# Example: 1.2.4.dev42+ge174a1f
distance = "{next_version}.dev{distance}+{vcs}{rev}"
# Example: 1.2.3+d20230922
dirty = "{base_version}+d{build_date:%Y%m%d}"
# Example: 1.2.4.dev42+ge174a1f.d20230922
distance-dirty = "{next_version}.dev{distance}+{vcs}{rev}.d{build_date:%Y%m%d}"
[tool.hatch.version.template-fields]
method = "basic"
version-tuple = {pep440 = true, double-quote = true}Initial Result:
╰─▶ Call to `hatchling.build.build_editable` failed (exit code: 1)
[stderr]
[INFO ] versioningit: Project dir: C:\Users\A761188\Sandbox\private\pdm-vs-uv\poc
[DEBUG ] versioningit: Loading entry point 'git' in group versioningit.vcs
[DEBUG ] versioningit: Loading entry point 'basic' in group versioningit.tag2version
[DEBUG ] versioningit: Loading entry point 'smallest' in group versioningit.next_version
[DEBUG ] versioningit: Loading entry point 'basic' in group versioningit.format
[DEBUG ] versioningit: Loading entry point 'basic' in group versioningit.template_fields
[DEBUG ] versioningit: Loading entry point 'basic' in group versioningit.write
[DEBUG ] versioningit: Running: git rev-parse --is-inside-work-tree
[DEBUG ] versioningit: Running: git ls-files --error-unmatch .
[DEBUG ] versioningit: Running: git describe --long --dirty --always --tags '--match=*[0-9].[0-9].[0-9]*'
[DEBUG ] versioningit: Running: git symbolic-ref --short -q HEAD
[DEBUG ] versioningit: Running: git --no-pager show -s --format=%H%n%at%n%ct
[INFO ] versioningit: vcs returned tag poc-2.6.0+dt
[DEBUG ] versioningit: vcs state: dirty
[DEBUG ] versioningit: vcs branch: main
[DEBUG ] versioningit: vcs fields: {'distance': 0, 'rev': '9c87160', 'build_date': datetime.datetime(2025, 6, 26, 23, 56, 28, 91666, tzinfo=datetime.timezone.utc), 'vcs':
'g', 'vcs_name': 'git', 'revision': '9c87160ae9b3cc38dab86f67708173ca3b05919d', 'author_date': datetime.datetime(2025, 6, 26, 20, 21, 26, tzinfo=datetime.timezone.utc),
'committer_date': datetime.datetime(2025, 6, 26, 20, 21, 26, tzinfo=datetime.timezone.utc)}
[INFO ] versioningit: tag2version returned version 2.6.0+dt
[INFO ] versioningit: next-version returned version 2.6.1
[INFO ] versioningit: VCS state is 'dirty'; formatting version
[INFO ] versioningit: Final version: 2.6.0+dt+d20250626
[WARNING ] versioningit: Final version '2.6.0+dt+d20250626' is not PEP 440-compliant
Traceback (most recent call last):
File "<string>", line 11, in <module>
File "C:\Users\A761188\AppData\Local\uv\cache\builds-v0\.tmpjSh1sz\Lib\site-packages\hatchling\build.py", line 83, in build_editable
return os.path.basename(next(builder.build(directory=wheel_directory, versions=['editable'])))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\A761188\AppData\Local\uv\cache\builds-v0\.tmpjSh1sz\Lib\site-packages\hatchling\builders\plugin\interface.py", line 90, in build
self.metadata.validate_fields()
File "C:\Users\A761188\AppData\Local\uv\cache\builds-v0\.tmpjSh1sz\Lib\site-packages\hatchling\metadata\core.py", line 265, in validate_fields
_ = self.version
^^^^^^^^^^^^
File "C:\Users\A761188\AppData\Local\uv\cache\builds-v0\.tmpjSh1sz\Lib\site-packages\hatchling\metadata\core.py", line 149, in version
self._version = self._get_version()
^^^^^^^^^^^^^^^^^^^
File "C:\Users\A761188\AppData\Local\uv\cache\builds-v0\.tmpjSh1sz\Lib\site-packages\hatchling\metadata\core.py", line 248, in _get_version
version = self.hatch.version.cached
^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\A761188\AppData\Local\uv\cache\builds-v0\.tmpjSh1sz\Lib\site-packages\hatchling\metadata\core.py", line 1456, in cached
raise type(e)(message) from None
versioningit.errors.InvalidVersionError: Error getting the version from source `versioningit`: '2.6.0+dt+d20250626' is not a valid PEP 440 version