Skip to content
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

#432 Use importlib.metadata.version to get the version #502

Merged
merged 22 commits into from
May 22, 2024
Merged
Changes from 5 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c933cbb
#432 An initial attempt
agriyakhetarpal Apr 29, 2023
89c3232
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 29, 2023
d8e281f
Merge branch 'trunk' into 432-poetry-version
agriyakhetarpal May 2, 2023
3aff9fb
Merge branch 'trunk' into 432-poetry-version
adiroiban Jun 4, 2023
ff05eed
Merge branch 'trunk' into 432-poetry-version
adiroiban Jul 17, 2023
69b197a
Merge branch 'trunk' into 432-poetry-version
adiroiban Apr 28, 2024
c2a23df
Get metadata version from packages_distributions
SmileyChris May 7, 2024
2af8e80
Fix dependency format
SmileyChris May 21, 2024
6b85972
Safer check in _get_metadata_version
SmileyChris May 21, 2024
819d160
Update test to match new "no version found" exception text
SmileyChris May 21, 2024
7f1d8ce
logic style nitpick
SmileyChris May 21, 2024
1f28954
Mypy fixes
SmileyChris May 21, 2024
770eb48
Fix incremental test
SmileyChris May 21, 2024
9bbcb70
Add test to check version from metadata
SmileyChris May 22, 2024
85a769e
Remove a redundant try/except
SmileyChris May 22, 2024
30fe7ed
Looser pin for importlib-metadata
SmileyChris May 22, 2024
6ec518d
Use a pyupgrade compatible format for the importlib_metadata fallback…
SmileyChris May 22, 2024
d5e0a60
Improve comments for the version-related methods
SmileyChris May 22, 2024
f02a26a
Small tweak to the version error message
SmileyChris May 22, 2024
8050a0b
Revert missing version name change in test
SmileyChris May 22, 2024
5bee9d4
Add a newsfragment
SmileyChris May 22, 2024
783e122
Merge branch 'trunk' into 432-poetry-version
SmileyChris May 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/towncrier/_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import sys

from importlib import import_module
from importlib.metadata import PackageNotFoundError
from importlib.metadata import version as metadata_version
from types import ModuleType

from incremental import Version as IncrementalVersion
Expand Down Expand Up @@ -39,8 +41,10 @@ def _get_package(package_dir: str, package: str) -> ModuleType:

def get_version(package_dir: str, package: str) -> str:
SmileyChris marked this conversation as resolved.
Show resolved Hide resolved
module = _get_package(package_dir, package)
SmileyChris marked this conversation as resolved.
Show resolved Hide resolved

version = getattr(module, "__version__", None)
try:
version = metadata_version(f"{module}")
Copy link

Choose a reason for hiding this comment

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

The str of a module is not something you can pass to importlib.metadata.version because you get a repr-like string:

>>> module = importlib.import_module("towncrier")
>>> print(f"{module}")
<module 'towncrier' from '/Users/.../site-packages/towncrier/__init__.py'>

which is probably just a small mistake here, but it reminds me that in fact version() does not accept an Import Package name at all, but rather a Distribution Package. They're commonly the same but not necessarily so, to use some popular examples:

Import Package Distribution Package
attr1 attrs
yaml PyYAML

As an example, let's say I'm the PyYAML developer, and I'm using towncrier with a __version__ variable via package = "yaml". If I want to drop that variable and specify my version in pyproject.toml instead, then we can't pass yaml to importlib.metadata.version. We have to load a mapping from one to the other:

>>> import importlib.metadata
>>> importlib.metadata.packages_distributions()['yaml']
['PyYAML']
>>> importlib.metadata.version('PyYAML')
'6.0.1'

which in the context of get_version would be something like:

dist_packages = distributions_packages()
try:
    dist_package = dist_packages[package]
except KeyError:
    # do fallback to package.__version__ here
else:
    if len(dist_package) > 1:
        raise Exception("I found more than one package")
    version = metadata_version(dist_package[0])

So that's how we'd make towncrier use importlib.metadata in a backwards-compatible way (user doesn't have to change their tool.towncrier config).

It's a little unfortunate, though, that I have to do this:

[project]
name = "PyYAML"
version = "1.2.3"

[tool.towncrier]
package = "yaml"

The version associated with the distribution package is right there, but then I have to tell towncrier one of the import packages I have so that it can look up the name of my distribution package.

PEP 621 says that the project.name is required to be statically defined, which means towncrier could try to read project.name by default if package is not defined and --version is not passed.

Notably Poetry doesn't yet support PEP 621 but the package would still be there for Poetry users.

Footnotes

  1. attrs also has its newer attrs namespace of course :-)

except PackageNotFoundError:
version = getattr(module, "__version__", None)

if not version:
raise Exception("No __version__, I don't know how else to look")
Expand Down