package import: remove magic import line (#39183)
This commit is contained in:
parent
5e630174a1
commit
8e7c53a8ba
6 changed files with 48 additions and 43 deletions
|
@ -1266,12 +1266,8 @@ def make_stack(tb, stack=None):
|
|||
# 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 = ["{0}:{1:d}, in {2}:".format(filename, lineno, frame.f_code.co_name)]
|
||||
lines = [f"{filename}:{lineno:d}, in {frame.f_code.co_name}:"]
|
||||
|
||||
# Build a message showing context in the install method.
|
||||
sourcelines, start = inspect.getsourcelines(frame)
|
||||
|
|
|
@ -78,43 +78,6 @@ 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)
|
||||
|
@ -155,7 +118,9 @@ def compute_loader(self, fullname):
|
|||
# With 2 nested conditionals we can call "repo.real_name" only once
|
||||
package_name = repo.real_name(module_name)
|
||||
if package_name:
|
||||
return RepoLoader(fullname, repo, package_name)
|
||||
return importlib.machinery.SourceFileLoader(
|
||||
fullname, repo.filename_for_package_name(package_name)
|
||||
)
|
||||
|
||||
# We are importing a full namespace like 'spack.pkg.builtin'
|
||||
if fullname == repo.full_namespace:
|
||||
|
@ -1236,6 +1201,11 @@ def get_pkg_class(self, pkg_name):
|
|||
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)
|
||||
|
|
|
@ -145,6 +145,8 @@ def repo_with_changing_recipe(tmpdir_factory, mutable_mock_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"
|
||||
|
@ -157,6 +159,8 @@ 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"
|
||||
|
|
|
@ -29,6 +29,8 @@ def update_packages_config(conf_str):
|
|||
_pkgx = (
|
||||
"x",
|
||||
"""\
|
||||
from spack.package import *
|
||||
|
||||
class X(Package):
|
||||
version("1.1")
|
||||
version("1.0")
|
||||
|
@ -45,6 +47,8 @@ class X(Package):
|
|||
_pkgy = (
|
||||
"y",
|
||||
"""\
|
||||
from spack.package import *
|
||||
|
||||
class Y(Package):
|
||||
version("2.5")
|
||||
version("2.4")
|
||||
|
@ -59,6 +63,8 @@ class Y(Package):
|
|||
_pkgv = (
|
||||
"v",
|
||||
"""\
|
||||
from spack.package import *
|
||||
|
||||
class V(Package):
|
||||
version("2.1")
|
||||
version("2.0")
|
||||
|
@ -69,6 +75,8 @@ class V(Package):
|
|||
_pkgt = (
|
||||
"t",
|
||||
"""\
|
||||
from spack.package import *
|
||||
|
||||
class T(Package):
|
||||
version('2.1')
|
||||
version('2.0')
|
||||
|
@ -81,6 +89,8 @@ class T(Package):
|
|||
_pkgu = (
|
||||
"u",
|
||||
"""\
|
||||
from spack.package import *
|
||||
|
||||
class U(Package):
|
||||
version('1.1')
|
||||
version('1.0')
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
# 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
|
||||
|
@ -318,3 +320,24 @@ 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")
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from spack.package import *
|
||||
|
||||
class {{ cls_name }}(Package):
|
||||
homepage = "http://www.example.com"
|
||||
url = "http://www.example.com/root-1.0.tar.gz"
|
||||
|
|
Loading…
Reference in a new issue