diff --git a/lib/spack/spack/package_base.py b/lib/spack/spack/package_base.py index 54ba4bac32e..cf2ca6c8de6 100644 --- a/lib/spack/spack/package_base.py +++ b/lib/spack/spack/package_base.py @@ -850,15 +850,9 @@ def fullnames(cls): @classproperty def name(cls): - """The name of this package. - - The name of a package is the name of its Python module, without - the containing module names. - """ + """The canonical name of this package""" if cls._name is None: - cls._name = cls.module.__name__ - if "." in cls._name: - cls._name = cls._name[cls._name.rindex(".") + 1 :] + cls._name = spack.repo.pkg_name_from_module(cls.__module__) return cls._name @classproperty diff --git a/lib/spack/spack/repo.py b/lib/spack/spack/repo.py index 2e1b613bd00..3b8427442da 100644 --- a/lib/spack/spack/repo.py +++ b/lib/spack/spack/repo.py @@ -83,6 +83,21 @@ def namespace_from_fullname(fullname): return namespace +def pkg_name_from_module(module_name: str) -> str: + """Return the actual package name from a module name. + + For instance ``spack.pkg.builtin.num3dtk`` has package name ``3dtk`` + and ``spack.pkg.builtin.py_numpy`` has package name ``py-numpy`` + """ + if not module_name.startswith(f"{ROOT_PYTHON_NAMESPACE}."): + raise ValueError(f"Module '{module_name}' is not a Spack package module") + namespace, _, import_name = module_name[len(ROOT_PYTHON_NAMESPACE) + 1 :].rpartition(".") + name = PATH.get_repo(namespace).real_name(import_name) + if name is None: + raise ValueError(f"Module '{module_name}' does not correspond to a known package") + return name + + class SpackNamespaceLoader: def create_module(self, spec): return SpackNamespace(spec.name) diff --git a/lib/spack/spack/test/packages.py b/lib/spack/spack/test/packages.py index 2912c689079..50192f86b6b 100644 --- a/lib/spack/spack/test/packages.py +++ b/lib/spack/spack/test/packages.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import importlib import os import pytest @@ -333,3 +334,8 @@ def test_package_can_have_sparse_checkout_properties(mock_packages, mock_fetch, assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy) assert hasattr(fetcher, "git_sparse_paths") assert fetcher.git_sparse_paths == pkg_cls.git_sparse_paths + + +def test_package_name_from_class_type(mock_packages): + module = importlib.import_module("spack.pkg.builtin.mock.num7zip") + assert module._7zip.name == "7zip"