From 919738b7b64fa78b2358b3040d223ebd52add39b Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Fri, 7 Feb 2025 15:18:15 +0100 Subject: [PATCH] Fallback for metadata of conda packages --- src/scippneutron/metadata/_model.py | 37 +++++++++++++++++++++++---- tests/metadata/metadata_model_test.py | 18 ++++++++----- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/scippneutron/metadata/_model.py b/src/scippneutron/metadata/_model.py index cffba87a6..18d71cfd3 100644 --- a/src/scippneutron/metadata/_model.py +++ b/src/scippneutron/metadata/_model.py @@ -255,11 +255,9 @@ def from_package_metadata(cls, package_name: str) -> Software: : A Software instance. """ - from importlib.metadata import version - return cls( name=package_name, - version=version(package_name), + version=_deduce_package_version(package_name), url=_deduce_package_source_url(package_name), doi=None, ) @@ -277,10 +275,39 @@ def compact_repr(self) -> str: return self.name_version +def _deduce_package_version(package_name: str) -> str | None: + from importlib.metadata import PackageNotFoundError, version + + try: + return version(package_name) + except PackageNotFoundError: + # Either the package is not installed or has no metadata. + from importlib import import_module + + try: + package = import_module(package_name) + except ModuleNotFoundError as e: + raise e from None + + try: + return package.__version__ + except AttributeError: + raise RuntimeError( + f"Package '{package_name}' has no metadata and no " + f"__version__ attribute. Specify the version manually." + ) from None + + def _deduce_package_source_url(package_name: str) -> str | None: - from importlib.metadata import metadata + from importlib.metadata import PackageNotFoundError, metadata + + try: + meta = metadata(package_name) + except PackageNotFoundError: + # Either the package is not installed or has no metadata. + return None - if not (urls := metadata(package_name).get_all("project-url")): + if not (urls := meta.get_all("project-url")): return None try: diff --git a/tests/metadata/metadata_model_test.py b/tests/metadata/metadata_model_test.py index 7b4537363..1cb073bee 100644 --- a/tests/metadata/metadata_model_test.py +++ b/tests/metadata/metadata_model_test.py @@ -2,6 +2,7 @@ # Copyright (c) 2025 Scipp contributors (https://github.com/scipp) +import pytest import scipp as sc import scippnexus as snx from dateutil.parser import parse as parse_datetime @@ -44,10 +45,15 @@ def test_software_from_from_package_metadata_first_party() -> None: def test_software_from_from_package_metadata_third_party() -> None: software = metadata.Software.from_package_metadata('scipp') - expected = metadata.Software( - name='scipp', - version=sc.__version__, - url='https://github.com/scipp/scipp', - doi=None, # Cannot be deduced + assert software.name == 'scipp' + assert software.version == sc.__version__ + assert software.url in ( + 'https://github.com/scipp/scipp', # properly deduced + None, # fallback for our conda packages ) - assert software == expected + assert software.doi is None + + +def test_software_from_from_package_metadata_fails_when_package_not_installed() -> None: + with pytest.raises(ModuleNotFoundError): + metadata.Software.from_package_metadata('not-a-package')