summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2023-08-11 00:04:40 -0700
committerGitHub <noreply@github.com>2023-08-11 09:04:40 +0200
commitea082539e43eaaa489b4bc68f1c823bd6fa278c8 (patch)
tree70c9ebfdaac593902b68ce6051b68149c172474e
parent143146f4f3a01b430540530f70afdaa1bbd1c706 (diff)
downloadspack-ea082539e43eaaa489b4bc68f1c823bd6fa278c8.tar.gz
spack-ea082539e43eaaa489b4bc68f1c823bd6fa278c8.tar.bz2
spack-ea082539e43eaaa489b4bc68f1c823bd6fa278c8.tar.xz
spack-ea082539e43eaaa489b4bc68f1c823bd6fa278c8.zip
Revert "package import: remove magic import line (#39183)" (#39380)
This reverts commit 8e7c53a8ba32e0793e36e66b5fdac8f4f61e644d.
-rw-r--r--lib/spack/spack/build_environment.py6
-rw-r--r--lib/spack/spack/repo.py46
-rw-r--r--lib/spack/spack/test/concretize.py4
-rw-r--r--lib/spack/spack/test/concretize_requirements.py10
-rw-r--r--lib/spack/spack/test/packages.py23
-rw-r--r--share/spack/templates/mock-repository/package.pyt2
6 files changed, 43 insertions, 48 deletions
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index 28df13771e..ff99515d66 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -1265,8 +1265,12 @@ def get_package_context(traceback, context=3):
# Point out the location in the install method where we failed.
filename = inspect.getfile(frame.f_code)
lineno = frame.f_lineno
+ if os.path.basename(filename) == "package.py":
+ # subtract 1 because we inject a magic import at the top of package files.
+ # TODO: get rid of the magic import.
+ lineno -= 1
- lines = [f"{filename}:{lineno:d}, in {frame.f_code.co_name}:"]
+ lines = ["{0}:{1:d}, in {2}:".format(filename, lineno, frame.f_code.co_name)]
# Build a message showing context in the install method.
sourcelines, start = inspect.getsourcelines(frame)
diff --git a/lib/spack/spack/repo.py b/lib/spack/spack/repo.py
index d24c27be10..f57a79aaea 100644
--- a/lib/spack/spack/repo.py
+++ b/lib/spack/spack/repo.py
@@ -78,6 +78,43 @@ def namespace_from_fullname(fullname):
return namespace
+class _PrependFileLoader(importlib.machinery.SourceFileLoader):
+ def __init__(self, fullname, path, prepend=None):
+ super(_PrependFileLoader, self).__init__(fullname, path)
+ self.prepend = prepend
+
+ def path_stats(self, path):
+ stats = super(_PrependFileLoader, self).path_stats(path)
+ if self.prepend:
+ stats["size"] += len(self.prepend) + 1
+ return stats
+
+ def get_data(self, path):
+ data = super(_PrependFileLoader, self).get_data(path)
+ if path != self.path or self.prepend is None:
+ return data
+ else:
+ return self.prepend.encode() + b"\n" + data
+
+
+class RepoLoader(_PrependFileLoader):
+ """Loads a Python module associated with a package in specific repository"""
+
+ #: Code in ``_package_prepend`` is prepended to imported packages.
+ #:
+ #: Spack packages are expected to call `from spack.package import *`
+ #: themselves, but we are allowing a deprecation period before breaking
+ #: external repos that don't do this yet.
+ _package_prepend = "from spack.package import *"
+
+ def __init__(self, fullname, repo, package_name):
+ self.repo = repo
+ self.package_name = package_name
+ self.package_py = repo.filename_for_package_name(package_name)
+ self.fullname = fullname
+ super().__init__(self.fullname, self.package_py, prepend=self._package_prepend)
+
+
class SpackNamespaceLoader:
def create_module(self, spec):
return SpackNamespace(spec.name)
@@ -118,9 +155,7 @@ class ReposFinder:
# With 2 nested conditionals we can call "repo.real_name" only once
package_name = repo.real_name(module_name)
if package_name:
- return importlib.machinery.SourceFileLoader(
- fullname, repo.filename_for_package_name(package_name)
- )
+ return RepoLoader(fullname, repo, package_name)
# We are importing a full namespace like 'spack.pkg.builtin'
if fullname == repo.full_namespace:
@@ -1201,11 +1236,6 @@ class Repo:
raise UnknownPackageError(fullname)
except Exception as e:
msg = f"cannot load package '{pkg_name}' from the '{self.namespace}' repository: {e}"
- if isinstance(e, NameError):
- msg += (
- ". This usually means `from spack.package import *` "
- "is missing at the top of the package.py file."
- )
raise RepoError(msg) from e
cls = getattr(module, class_name)
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index 031eb999e4..465edfdb08 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -145,8 +145,6 @@ repo:
packages_dir = repo_dir.ensure("packages", dir=True)
root_pkg_str = """
-from spack.package import *
-
class Root(Package):
homepage = "http://www.example.com"
url = "http://www.example.com/root-1.0.tar.gz"
@@ -159,8 +157,6 @@ class Root(Package):
packages_dir.join("root", "package.py").write(root_pkg_str, ensure=True)
changing_template = """
-from spack.package import *
-
class Changing(Package):
homepage = "http://www.example.com"
url = "http://www.example.com/changing-1.0.tar.gz"
diff --git a/lib/spack/spack/test/concretize_requirements.py b/lib/spack/spack/test/concretize_requirements.py
index 4436e428c9..ff0e354965 100644
--- a/lib/spack/spack/test/concretize_requirements.py
+++ b/lib/spack/spack/test/concretize_requirements.py
@@ -29,8 +29,6 @@ def update_packages_config(conf_str):
_pkgx = (
"x",
"""\
-from spack.package import *
-
class X(Package):
version("1.1")
version("1.0")
@@ -47,8 +45,6 @@ class X(Package):
_pkgy = (
"y",
"""\
-from spack.package import *
-
class Y(Package):
version("2.5")
version("2.4")
@@ -63,8 +59,6 @@ class Y(Package):
_pkgv = (
"v",
"""\
-from spack.package import *
-
class V(Package):
version("2.1")
version("2.0")
@@ -75,8 +69,6 @@ class V(Package):
_pkgt = (
"t",
"""\
-from spack.package import *
-
class T(Package):
version('2.1')
version('2.0')
@@ -89,8 +81,6 @@ class T(Package):
_pkgu = (
"u",
"""\
-from spack.package import *
-
class U(Package):
version('1.1')
version('1.0')
diff --git a/lib/spack/spack/test/packages.py b/lib/spack/spack/test/packages.py
index bf34155aba..4a5831dce7 100644
--- a/lib/spack/spack/test/packages.py
+++ b/lib/spack/spack/test/packages.py
@@ -4,13 +4,11 @@
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os
-import re
import pytest
import spack.directives
import spack.fetch_strategy
-import spack.package_base
import spack.repo
from spack.paths import mock_packages_path
from spack.spec import Spec
@@ -320,24 +318,3 @@ def test_package_deprecated_version(mock_packages, mock_fetch, mock_stage):
assert spack.package_base.deprecated_version(pkg_cls, "1.1.0")
assert not spack.package_base.deprecated_version(pkg_cls, "1.0.0")
-
-
-def test_package_with_deprecated_magic_import_has_a_useful_error(tmpdir, mutable_config):
- """Test that a package that's missing `from spack.package import *` gets a useful error,
- suggesting that it be added."""
- tmpdir.join("repo.yaml").write("repo:\n namespace: old_package")
- tmpdir.join("packages", "old-package").ensure(dir=True).join("package.py").write(
- """\
-class OldPackage(Package):
- version('1.0', '0123456789abcdef0123456789abcdef')
-"""
- )
- with spack.repo.use_repositories(str(tmpdir)) as repo:
- with pytest.raises(
- spack.repo.RepoError,
- match=re.escape(
- "This usually means `from spack.package import *` "
- "is missing at the top of the package.py file."
- ),
- ):
- repo.get_pkg_class("old-package")
diff --git a/share/spack/templates/mock-repository/package.pyt b/share/spack/templates/mock-repository/package.pyt
index a4a52ec700..82bd50bd05 100644
--- a/share/spack/templates/mock-repository/package.pyt
+++ b/share/spack/templates/mock-repository/package.pyt
@@ -1,5 +1,3 @@
-from spack.package import *
-
class {{ cls_name }}(Package):
homepage = "http://www.example.com"
url = "http://www.example.com/root-1.0.tar.gz"