spack style: import-check -> import, fix bugs, exclude spack.pkg (#47690)

This commit is contained in:
Harmen Stoppels 2024-11-20 16:15:28 +01:00 committed by GitHub
parent 0ff3e86315
commit aa2c18e4df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 63 additions and 21 deletions

View File

@ -8,6 +8,7 @@
import spack.cmd.common.arguments import spack.cmd.common.arguments
import spack.cmd.modules import spack.cmd.modules
import spack.config import spack.config
import spack.modules
import spack.modules.lmod import spack.modules.lmod

View File

@ -7,6 +7,7 @@
import spack.cmd.common.arguments import spack.cmd.common.arguments
import spack.cmd.modules import spack.cmd.modules
import spack.config import spack.config
import spack.modules
import spack.modules.tcl import spack.modules.tcl

View File

@ -15,6 +15,7 @@
from llnl.util.filesystem import working_dir from llnl.util.filesystem import working_dir
import spack.paths import spack.paths
import spack.repo
import spack.util.git import spack.util.git
from spack.util.executable import Executable, which from spack.util.executable import Executable, which
@ -38,7 +39,7 @@ def grouper(iterable, n, fillvalue=None):
#: double-check the results of other tools (if, e.g., --fix was provided) #: double-check the results of other tools (if, e.g., --fix was provided)
#: The list maps an executable name to a method to ensure the tool is #: The list maps an executable name to a method to ensure the tool is
#: bootstrapped or present in the environment. #: bootstrapped or present in the environment.
tool_names = ["import-check", "isort", "black", "flake8", "mypy"] tool_names = ["import", "isort", "black", "flake8", "mypy"]
#: warnings to ignore in mypy #: warnings to ignore in mypy
mypy_ignores = [ mypy_ignores = [
@ -370,10 +371,19 @@ def run_black(black_cmd, file_list, args):
def _module_part(root: str, expr: str): def _module_part(root: str, expr: str):
parts = expr.split(".") parts = expr.split(".")
# spack.pkg is for repositories, don't try to resolve it here.
if ".".join(parts[:2]) == spack.repo.ROOT_PYTHON_NAMESPACE:
return None
while parts: while parts:
f1 = os.path.join(root, "lib", "spack", *parts) + ".py" f1 = os.path.join(root, "lib", "spack", *parts) + ".py"
f2 = os.path.join(root, "lib", "spack", *parts, "__init__.py") f2 = os.path.join(root, "lib", "spack", *parts, "__init__.py")
if os.path.exists(f1) or os.path.exists(f2):
if (
os.path.exists(f1)
# ensure case sensitive match
and f"{parts[-1]}.py" in os.listdir(os.path.dirname(f1))
or os.path.exists(f2)
):
return ".".join(parts) return ".".join(parts)
parts.pop() parts.pop()
return None return None
@ -389,7 +399,7 @@ def _run_import_check(
out=sys.stdout, out=sys.stdout,
): ):
if sys.version_info < (3, 9): if sys.version_info < (3, 9):
print("import-check requires Python 3.9 or later") print("import check requires Python 3.9 or later")
return 0 return 0
is_use = re.compile(r"(?<!from )(?<!import )(?:llnl|spack)\.[a-zA-Z0-9_\.]+") is_use = re.compile(r"(?<!from )(?<!import )(?:llnl|spack)\.[a-zA-Z0-9_\.]+")
@ -431,10 +441,11 @@ def _run_import_check(
module = _module_part(root, m.group(0)) module = _module_part(root, m.group(0))
if not module or module in to_add: if not module or module in to_add:
continue continue
if f"import {module}" not in filtered_contents: if re.search(rf"import {re.escape(module)}\b(?!\.)", contents):
continue
to_add.add(module) to_add.add(module)
exit_code = 1 exit_code = 1
print(f"{pretty_path}: missing import: {module}", file=out) print(f"{pretty_path}: missing import: {module} ({m.group(0)})", file=out)
if not fix or not to_add and not to_remove: if not fix or not to_add and not to_remove:
continue continue
@ -465,7 +476,7 @@ def _run_import_check(
return exit_code return exit_code
@tool("import-check", external=False) @tool("import", external=False)
def run_import_check(import_check_cmd, file_list, args): def run_import_check(import_check_cmd, file_list, args):
exit_code = _run_import_check( exit_code = _run_import_check(
file_list, file_list,
@ -474,7 +485,7 @@ def run_import_check(import_check_cmd, file_list, args):
root=args.root, root=args.root,
working_dir=args.initial_working_dir, working_dir=args.initial_working_dir,
) )
print_tool_result("import-check", exit_code) print_tool_result("import", exit_code)
return exit_code return exit_code

View File

@ -36,7 +36,6 @@ class OpenMpi(Package):
import re import re
from typing import Any, Callable, List, Optional, Tuple, Union from typing import Any, Callable, List, Optional, Tuple, Union
import llnl.util.lang
import llnl.util.tty.color import llnl.util.tty.color
import spack.deptypes as dt import spack.deptypes as dt

View File

@ -27,6 +27,7 @@
import spack import spack
import spack.binary_distribution import spack.binary_distribution
import spack.compiler
import spack.compilers import spack.compilers
import spack.concretize import spack.concretize
import spack.config import spack.config

View File

@ -17,6 +17,7 @@
import spack import spack
import spack.binary_distribution import spack.binary_distribution
import spack.ci as ci import spack.ci as ci
import spack.cmd
import spack.cmd.ci import spack.cmd.ci
import spack.environment as ev import spack.environment as ev
import spack.hash_types as ht import spack.hash_types as ht

View File

@ -10,6 +10,7 @@
from llnl.util.filesystem import mkdirp, working_dir from llnl.util.filesystem import mkdirp, working_dir
import spack.cmd
import spack.cmd.pkg import spack.cmd.pkg
import spack.main import spack.main
import spack.paths import spack.paths

View File

@ -295,7 +295,7 @@ def test_style_with_black(flake8_package_with_errors):
def test_skip_tools(): def test_skip_tools():
output = style("--skip", "import-check,isort,mypy,black,flake8") output = style("--skip", "import,isort,mypy,black,flake8")
assert "Nothing to run" in output assert "Nothing to run" in output
@ -314,6 +314,7 @@ class Example(spack.build_systems.autotools.AutotoolsPackage):
def foo(config: "spack.error.SpackError"): def foo(config: "spack.error.SpackError"):
# the type hint is quoted, so it should not be removed # the type hint is quoted, so it should not be removed
spack.util.executable.Executable("example") spack.util.executable.Executable("example")
print(spack.__version__)
''' '''
file.write_text(contents) file.write_text(contents)
root = str(tmp_path) root = str(tmp_path)
@ -330,6 +331,7 @@ def foo(config: "spack.error.SpackError"):
assert "issues.py: redundant import: spack.cmd" in output assert "issues.py: redundant import: spack.cmd" in output
assert "issues.py: redundant import: spack.config" not in output # comment prevents removal assert "issues.py: redundant import: spack.config" not in output # comment prevents removal
assert "issues.py: missing import: spack" in output # used by spack.__version__
assert "issues.py: missing import: spack.build_systems.autotools" in output assert "issues.py: missing import: spack.build_systems.autotools" in output
assert "issues.py: missing import: spack.util.executable" in output assert "issues.py: missing import: spack.util.executable" in output
assert "issues.py: missing import: spack.error" not in output # not directly used assert "issues.py: missing import: spack.error" not in output # not directly used
@ -349,6 +351,7 @@ def foo(config: "spack.error.SpackError"):
output = output_buf.getvalue() output = output_buf.getvalue()
assert exit_code == 1 assert exit_code == 1
assert "issues.py: redundant import: spack.cmd" in output assert "issues.py: redundant import: spack.cmd" in output
assert "issues.py: missing import: spack" in output
assert "issues.py: missing import: spack.build_systems.autotools" in output assert "issues.py: missing import: spack.build_systems.autotools" in output
assert "issues.py: missing import: spack.util.executable" in output assert "issues.py: missing import: spack.util.executable" in output
@ -369,8 +372,9 @@ def foo(config: "spack.error.SpackError"):
# check that the file was fixed # check that the file was fixed
new_contents = file.read_text() new_contents = file.read_text()
assert "import spack.cmd" not in new_contents assert "import spack.cmd" not in new_contents
assert "import spack.build_systems.autotools" in new_contents assert "import spack\n" in new_contents
assert "import spack.util.executable" in new_contents assert "import spack.build_systems.autotools\n" in new_contents
assert "import spack.util.executable\n" in new_contents
@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires Python 3.9+") @pytest.mark.skipif(sys.version_info < (3, 9), reason="requires Python 3.9+")
@ -389,3 +393,16 @@ def test_run_import_check_syntax_error_and_missing(tmp_path: pathlib.Path):
assert "syntax-error.py: could not parse" in output assert "syntax-error.py: could not parse" in output
assert "missing.py: could not parse" in output assert "missing.py: could not parse" in output
assert exit_code == 1 assert exit_code == 1
def test_case_sensitive_imports(tmp_path: pathlib.Path):
# example.Example is a name, while example.example is a module.
(tmp_path / "lib" / "spack" / "example").mkdir(parents=True)
(tmp_path / "lib" / "spack" / "example" / "__init__.py").write_text("class Example:\n pass")
(tmp_path / "lib" / "spack" / "example" / "example.py").write_text("foo = 1")
assert spack.cmd.style._module_part(str(tmp_path), "example.Example") == "example"
def test_pkg_imports():
assert spack.cmd.style._module_part(spack.paths.prefix, "spack.pkg.builtin.boost") is None
assert spack.cmd.style._module_part(spack.paths.prefix, "spack.pkg") is None

View File

@ -15,6 +15,7 @@
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.filesystem import join_path, touch, touchp from llnl.util.filesystem import join_path, touch, touchp
import spack
import spack.config import spack.config
import spack.directory_layout import spack.directory_layout
import spack.environment as ev import spack.environment as ev

View File

@ -12,6 +12,7 @@
import spack.cmd.modules import spack.cmd.modules
import spack.config import spack.config
import spack.error import spack.error
import spack.modules
import spack.modules.common import spack.modules.common
import spack.modules.tcl import spack.modules.tcl
import spack.package_base import spack.package_base

View File

@ -21,6 +21,7 @@
import spack.deptypes as dt import spack.deptypes as dt
import spack.error import spack.error
import spack.install_test import spack.install_test
import spack.package
import spack.package_base import spack.package_base
import spack.repo import spack.repo
import spack.spec import spack.spec

View File

@ -55,6 +55,7 @@ def get_user():
# Substitutions to perform # Substitutions to perform
def replacements(): def replacements():
# break circular imports # break circular imports
import spack
import spack.environment as ev import spack.environment as ev
import spack.paths import spack.paths

View File

@ -26,6 +26,7 @@
from llnl.util import lang, tty from llnl.util import lang, tty
from llnl.util.filesystem import mkdirp, rename, working_dir from llnl.util.filesystem import mkdirp, rename, working_dir
import spack
import spack.config import spack.config
import spack.error import spack.error
import spack.util.executable import spack.util.executable

View File

@ -2908,9 +2908,9 @@ complete -c spack -n '__fish_spack_using_command style' -s f -l fix -d 'format a
complete -c spack -n '__fish_spack_using_command style' -l root -r -f -a root complete -c spack -n '__fish_spack_using_command style' -l root -r -f -a root
complete -c spack -n '__fish_spack_using_command style' -l root -r -d 'style check a different spack instance' complete -c spack -n '__fish_spack_using_command style' -l root -r -d 'style check a different spack instance'
complete -c spack -n '__fish_spack_using_command style' -s t -l tool -r -f -a tool complete -c spack -n '__fish_spack_using_command style' -s t -l tool -r -f -a tool
complete -c spack -n '__fish_spack_using_command style' -s t -l tool -r -d 'specify which tools to run (default: import-check, isort, black, flake8, mypy)' complete -c spack -n '__fish_spack_using_command style' -s t -l tool -r -d 'specify which tools to run (default: import, isort, black, flake8, mypy)'
complete -c spack -n '__fish_spack_using_command style' -s s -l skip -r -f -a skip complete -c spack -n '__fish_spack_using_command style' -s s -l skip -r -f -a skip
complete -c spack -n '__fish_spack_using_command style' -s s -l skip -r -d 'specify tools to skip (choose from import-check, isort, black, flake8, mypy)' complete -c spack -n '__fish_spack_using_command style' -s s -l skip -r -d 'specify tools to skip (choose from import, isort, black, flake8, mypy)'
# spack tags # spack tags
set -g __fish_spack_optspecs_spack_tags h/help i/installed a/all set -g __fish_spack_optspecs_spack_tags h/help i/installed a/all

View File

@ -5,7 +5,6 @@
import os import os
import re import re
import spack.package_base
from spack.package import * from spack.package import *
@ -26,7 +25,7 @@ def determine_spec_details(cls, prefix, exes_in_prefix):
exes = [x for x in exe_to_path.keys() if "find-externals1-exe" in x] exes = [x for x in exe_to_path.keys() if "find-externals1-exe" in x]
if not exes: if not exes:
return return
exe = spack.util.executable.Executable(exe_to_path[exes[0]]) exe = Executable(exe_to_path[exes[0]])
output = exe("--version", output=str) output = exe("--version", output=str)
if output: if output:
match = re.search(r"find-externals1.*version\s+(\S+)", output) match = re.search(r"find-externals1.*version\s+(\S+)", output)

View File

@ -3,6 +3,7 @@
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import spack.builder
import spack.pkg.builtin.mock.python as mp import spack.pkg.builtin.mock.python as mp
from spack.build_systems._checks import BuilderWithDefaults, execute_install_time_tests from spack.build_systems._checks import BuilderWithDefaults, execute_install_time_tests
from spack.package import * from spack.package import *
@ -40,7 +41,7 @@ class MyBuilder(BuilderWithDefaults):
def install(self, pkg, spec, prefix): def install(self, pkg, spec, prefix):
pkg.install(spec, prefix) pkg.install(spec, prefix)
spack.phase_callbacks.run_after("install")(execute_install_time_tests) run_after("install")(execute_install_time_tests)
def test_callback(self): def test_callback(self):
self.pkg.test_callback() self.pkg.test_callback()

View File

@ -6,6 +6,9 @@
import os import os
import subprocess import subprocess
import llnl.util.lang
import spack.platforms
import spack.platforms.cray import spack.platforms.cray
from spack.package import * from spack.package import *
from spack.util.environment import is_system_path, set_env from spack.util.environment import is_system_path, set_env

View File

@ -3,6 +3,8 @@
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import llnl.util.lang
from spack.package import * from spack.package import *

View File

@ -138,9 +138,7 @@ def patch(self):
# Use our provided CMakeLists.txt. The Makefile provided with # Use our provided CMakeLists.txt. The Makefile provided with
# the source is GCC (gfortran) specific, and would have required # the source is GCC (gfortran) specific, and would have required
# additional patching for the +root variant. # additional patching for the +root variant.
llnl.util.filesystem.copy( copy(os.path.join(os.path.dirname(__file__), "CMakeLists.txt"), self.stage.source_path)
os.path.join(os.path.dirname(__file__), "CMakeLists.txt"), self.stage.source_path
)
# Apply the variant value at the relevant place in the source. # Apply the variant value at the relevant place in the source.
filter_file( filter_file(
r"^(\s+PARAMETER\s*\(\s*NMXHEP\s*=\s*)\d+", r"^(\s+PARAMETER\s*\(\s*NMXHEP\s*=\s*)\d+",

View File

@ -6,6 +6,8 @@
import os import os
import re import re
import llnl.util.lang
import spack.platforms import spack.platforms
from spack.package import * from spack.package import *