Compare commits

...

5 Commits

Author SHA1 Message Date
Harmen Stoppels
ecf882c240 fix fullnames 2025-04-25 13:52:09 +02:00
Harmen Stoppels
6822db0fe7 inline packages definitions dont have a name 2025-04-25 13:33:21 +02:00
Harmen Stoppels
868d538958 simplify and speed up external list 2025-04-25 11:53:07 +02:00
Harmen Stoppels
57ac37eb67 set __module__ prop so it's usable in init 2025-04-25 11:48:58 +02:00
Harmen Stoppels
4779322247 package_base.py: correctly compute package name 2025-04-25 11:48:58 +02:00
6 changed files with 60 additions and 44 deletions

View File

@ -121,6 +121,7 @@ def __init__(self, wrapped_pkg_object, root_builder):
new_cls_name, new_cls_name,
bases, bases,
{ {
"__module__": package_cls.__module__,
"run_tests": property(lambda x: x.wrapped_package_object.run_tests), "run_tests": property(lambda x: x.wrapped_package_object.run_tests),
"test_requires_compiler": property( "test_requires_compiler": property(
lambda x: x.wrapped_package_object.test_requires_compiler lambda x: x.wrapped_package_object.test_requires_compiler
@ -129,7 +130,6 @@ def __init__(self, wrapped_pkg_object, root_builder):
"tester": property(lambda x: x.wrapped_package_object.tester), "tester": property(lambda x: x.wrapped_package_object.tester),
}, },
) )
new_cls.__module__ = package_cls.__module__
self.__class__ = new_cls self.__class__ = new_cls
self.__dict__.update(wrapped_pkg_object.__dict__) self.__dict__.update(wrapped_pkg_object.__dict__)

View File

@ -5,7 +5,7 @@
import errno import errno
import os import os
import re import re
import sys from collections import defaultdict
from typing import List, Optional, Set from typing import List, Optional, Set
import llnl.util.tty as tty import llnl.util.tty as tty
@ -17,7 +17,6 @@
import spack.cray_manifest as cray_manifest import spack.cray_manifest as cray_manifest
import spack.detection import spack.detection
import spack.error import spack.error
import spack.package_base
import spack.repo import spack.repo
import spack.spec import spack.spec
from spack.cmd.common import arguments from spack.cmd.common import arguments
@ -246,13 +245,16 @@ def _collect_and_consume_cray_manifest_files(
def external_list(args): def external_list(args):
# Trigger a read of all packages, might take a long time.
list(spack.repo.PATH.all_package_classes())
# Print all the detectable packages # Print all the detectable packages
tty.msg("Detectable packages per repository") tty.msg("Detectable packages per repository")
for namespace, pkgs in sorted(spack.package_base.detectable_packages.items()): repo_to_packages = defaultdict(list)
for fullname in spack.repo.PATH.packages_with_tags("detectable", full=True):
repo, _, pkg = fullname.rpartition(".")
repo_to_packages[repo].append(pkg)
for namespace in sorted(repo_to_packages):
print("Repository:", namespace) print("Repository:", namespace)
colify.colify(pkgs, indent=4, output=sys.stdout) colify.colify(repo_to_packages[namespace], indent=4)
def external(parser, args): def external(parser, args):

View File

@ -132,11 +132,6 @@ def windows_establish_runtime_linkage(self):
win_rpath.establish_link() win_rpath.establish_link()
#: Registers which are the detectable packages, by repo and package name
#: Need a pass of package repositories to be filled.
detectable_packages = collections.defaultdict(list)
class DetectablePackageMeta(type): class DetectablePackageMeta(type):
"""Check if a package is detectable and add default implementations """Check if a package is detectable and add default implementations
for the detection function. for the detection function.
@ -242,9 +237,6 @@ def determine_spec_details(cls, prefix, objs_in_prefix):
def determine_variants(cls, objs, version_str): def determine_variants(cls, objs, version_str):
return "" return ""
# Register the class as a detectable package
detectable_packages[cls.namespace].append(cls.name)
# Attach function implementations to the detectable class # Attach function implementations to the detectable class
default = False default = False
if not hasattr(cls, "determine_spec_details"): if not hasattr(cls, "determine_spec_details"):
@ -839,26 +831,17 @@ def fullname(cls):
def fullnames(cls): def fullnames(cls):
"""Fullnames for this package and any packages from which it inherits.""" """Fullnames for this package and any packages from which it inherits."""
fullnames = [] fullnames = []
for cls in cls.__mro__: for base in cls.__mro__:
namespace = getattr(cls, "namespace", None) if not base.__module__.startswith(f"{spack.repo.ROOT_PYTHON_NAMESPACE}."):
if namespace:
fullnames.append("%s.%s" % (namespace, cls.name))
if namespace == "builtin":
# builtin packages cannot inherit from other repos
break break
fullnames.append(base.fullname)
return fullnames return fullnames
@classproperty @classproperty
def name(cls): def name(cls):
"""The name of this package. """The canonical name of this package"""
The name of a package is the name of its Python module, without
the containing module names.
"""
if cls._name is None: if cls._name is None:
cls._name = cls.module.__name__ cls._name = spack.repo.pkg_name_from_module(cls.__module__)
if "." in cls._name:
cls._name = cls._name[cls._name.rindex(".") + 1 :]
return cls._name return cls._name
@classproperty @classproperty

View File

@ -83,6 +83,21 @@ def namespace_from_fullname(fullname):
return namespace 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: class SpackNamespaceLoader:
def create_module(self, spec): def create_module(self, spec):
return SpackNamespace(spec.name) return SpackNamespace(spec.name)

View File

@ -9,6 +9,7 @@
""" """
import os import os
import pathlib
import shutil import shutil
import pytest import pytest
@ -22,6 +23,7 @@
import spack.install_test import spack.install_test
import spack.package import spack.package
import spack.package_base import spack.package_base
import spack.repo
import spack.spec import spack.spec
import spack.store import spack.store
from spack.build_systems.generic import Package from spack.build_systems.generic import Package
@ -245,23 +247,31 @@ class BadDetectablePackage(spack.package.Package):
libraries = ["libFindMe.a"] libraries = ["libFindMe.a"]
def test_package_url_and_urls(): def test_package_url_and_urls(tmp_path: pathlib.Path):
class URLsPackage(spack.package.Package): repo_path = tmp_path / "test-repo"
spack.repo.create_repo(str(repo_path))
package_py = repo_path / "packages" / "urls-package" / "package.py"
package_py.parent.mkdir(parents=True)
package_py.write_text(
"""\
from spack.package import *
class UrlsPackage(Package):
url = "https://www.example.com/url-package-1.0.tgz" url = "https://www.example.com/url-package-1.0.tgz"
urls = ["https://www.example.com/archive"] urls = ["https://www.example.com/archive"]
"""
)
s = spack.spec.Spec("pkg-a") with spack.repo.use_repositories(str(repo_path)) as repo:
pkg_cls = repo.get_pkg_class("urls-package")
s = spack.spec.Spec("urls-package")
with pytest.raises(ValueError, match="defines both"): with pytest.raises(ValueError, match="defines both"):
URLsPackage(s) pkg_cls(s)
def test_package_license(): def test_package_license(mock_packages):
class LicensedPackage(spack.package.Package):
extendees = None # currently a required attribute for is_extension()
license_files = None
s = spack.spec.Spec("pkg-a") s = spack.spec.Spec("pkg-a")
pkg = LicensedPackage(s) pkg = spack.repo.PATH.get_pkg_class("pkg-a")(s)
assert pkg.global_license_file is None assert pkg.global_license_file is None
pkg.license_files = ["license.txt"] pkg.license_files = ["license.txt"]

View File

@ -2,6 +2,7 @@
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import importlib
import os import os
import pytest 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 isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
assert hasattr(fetcher, "git_sparse_paths") assert hasattr(fetcher, "git_sparse_paths")
assert fetcher.git_sparse_paths == pkg_cls.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"