PythonPackage: type hints (#40539)

* PythonPackage: nested config_settings, type hints

* No need to quote PythonPackage

* Use narrower types for now until needed
This commit is contained in:
Adam J. Stewart 2023-12-04 11:53:53 +01:00 committed by GitHub
parent 9e0720207a
commit 40d12ed7e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -6,13 +6,14 @@
import os import os
import re import re
import shutil import shutil
from typing import Optional from typing import Iterable, List, Mapping, Optional
import archspec import archspec
import llnl.util.filesystem as fs import llnl.util.filesystem as fs
import llnl.util.lang as lang import llnl.util.lang as lang
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.filesystem import HeaderList, LibraryList
import spack.builder import spack.builder
import spack.config import spack.config
@ -25,14 +26,18 @@
from spack.directives import build_system, depends_on, extends, maintainers from spack.directives import build_system, depends_on, extends, maintainers
from spack.error import NoHeadersError, NoLibrariesError from spack.error import NoHeadersError, NoLibrariesError
from spack.install_test import test_part from spack.install_test import test_part
from spack.spec import Spec
from spack.util.prefix import Prefix
from ._checks import BaseBuilder, execute_install_time_tests from ._checks import BaseBuilder, execute_install_time_tests
def _flatten_dict(dictionary): def _flatten_dict(dictionary: Mapping[str, object]) -> Iterable[str]:
"""Iterable that yields KEY=VALUE paths through a dictionary. """Iterable that yields KEY=VALUE paths through a dictionary.
Args: Args:
dictionary: Possibly nested dictionary of arbitrary keys and values. dictionary: Possibly nested dictionary of arbitrary keys and values.
Yields: Yields:
A single path through the dictionary. A single path through the dictionary.
""" """
@ -50,7 +55,7 @@ class PythonExtension(spack.package_base.PackageBase):
maintainers("adamjstewart") maintainers("adamjstewart")
@property @property
def import_modules(self): def import_modules(self) -> Iterable[str]:
"""Names of modules that the Python package provides. """Names of modules that the Python package provides.
These are used to test whether or not the installation succeeded. These are used to test whether or not the installation succeeded.
@ -65,7 +70,7 @@ def import_modules(self):
detected, this property can be overridden by the package. detected, this property can be overridden by the package.
Returns: Returns:
list: list of strings of module names List of strings of module names.
""" """
modules = [] modules = []
pkg = self.spec["python"].package pkg = self.spec["python"].package
@ -102,14 +107,14 @@ def import_modules(self):
return modules return modules
@property @property
def skip_modules(self): def skip_modules(self) -> Iterable[str]:
"""Names of modules that should be skipped when running tests. """Names of modules that should be skipped when running tests.
These are a subset of import_modules. If a module has submodules, These are a subset of import_modules. If a module has submodules,
they are skipped as well (meaning a.b is skipped if a is contained). they are skipped as well (meaning a.b is skipped if a is contained).
Returns: Returns:
list: list of strings of module names List of strings of module names.
""" """
return [] return []
@ -185,12 +190,12 @@ def remove_files_from_view(self, view, merge_map):
view.remove_files(to_remove) view.remove_files(to_remove)
def test_imports(self): def test_imports(self) -> None:
"""Attempts to import modules of the installed package.""" """Attempts to import modules of the installed package."""
# Make sure we are importing the installed modules, # Make sure we are importing the installed modules,
# not the ones in the source directory # not the ones in the source directory
python = inspect.getmodule(self).python python = inspect.getmodule(self).python # type: ignore[union-attr]
for module in self.import_modules: for module in self.import_modules:
with test_part( with test_part(
self, self,
@ -315,24 +320,27 @@ class PythonPackage(PythonExtension):
py_namespace: Optional[str] = None py_namespace: Optional[str] = None
@lang.classproperty @lang.classproperty
def homepage(cls): def homepage(cls) -> Optional[str]: # type: ignore[override]
if cls.pypi: if cls.pypi:
name = cls.pypi.split("/")[0] name = cls.pypi.split("/")[0]
return "https://pypi.org/project/" + name + "/" return f"https://pypi.org/project/{name}/"
return None
@lang.classproperty @lang.classproperty
def url(cls): def url(cls) -> Optional[str]:
if cls.pypi: if cls.pypi:
return "https://files.pythonhosted.org/packages/source/" + cls.pypi[0] + "/" + cls.pypi return f"https://files.pythonhosted.org/packages/source/{cls.pypi[0]}/{cls.pypi}"
return None
@lang.classproperty @lang.classproperty
def list_url(cls): def list_url(cls) -> Optional[str]: # type: ignore[override]
if cls.pypi: if cls.pypi:
name = cls.pypi.split("/")[0] name = cls.pypi.split("/")[0]
return "https://pypi.org/simple/" + name + "/" return f"https://pypi.org/simple/{name}/"
return None
@property @property
def headers(self): def headers(self) -> HeaderList:
"""Discover header files in platlib.""" """Discover header files in platlib."""
# Remove py- prefix in package name # Remove py- prefix in package name
@ -350,7 +358,7 @@ def headers(self):
raise NoHeadersError(msg.format(self.spec.name, include, platlib)) raise NoHeadersError(msg.format(self.spec.name, include, platlib))
@property @property
def libs(self): def libs(self) -> LibraryList:
"""Discover libraries in platlib.""" """Discover libraries in platlib."""
# Remove py- prefix in package name # Remove py- prefix in package name
@ -384,7 +392,7 @@ class PythonPipBuilder(BaseBuilder):
install_time_test_callbacks = ["test"] install_time_test_callbacks = ["test"]
@staticmethod @staticmethod
def std_args(cls): def std_args(cls) -> List[str]:
return [ return [
# Verbose # Verbose
"-vvv", "-vvv",
@ -409,7 +417,7 @@ def std_args(cls):
] ]
@property @property
def build_directory(self): def build_directory(self) -> str:
"""The root directory of the Python package. """The root directory of the Python package.
This is usually the directory containing one of the following files: This is usually the directory containing one of the following files:
@ -420,51 +428,51 @@ def build_directory(self):
""" """
return self.pkg.stage.source_path return self.pkg.stage.source_path
def config_settings(self, spec, prefix): def config_settings(self, spec: Spec, prefix: Prefix) -> Mapping[str, object]:
"""Configuration settings to be passed to the PEP 517 build backend. """Configuration settings to be passed to the PEP 517 build backend.
Requires pip 22.1 or newer for keys that appear only a single time, Requires pip 22.1 or newer for keys that appear only a single time,
or pip 23.1 or newer if the same key appears multiple times. or pip 23.1 or newer if the same key appears multiple times.
Args: Args:
spec (spack.spec.Spec): build spec spec: Build spec.
prefix (spack.util.prefix.Prefix): installation prefix prefix: Installation prefix.
Returns: Returns:
dict: Possibly nested dictionary of KEY, VALUE settings Possibly nested dictionary of KEY, VALUE settings.
""" """
return {} return {}
def install_options(self, spec, prefix): def install_options(self, spec: Spec, prefix: Prefix) -> Iterable[str]:
"""Extra arguments to be supplied to the setup.py install command. """Extra arguments to be supplied to the setup.py install command.
Requires pip 23.0 or older. Requires pip 23.0 or older.
Args: Args:
spec (spack.spec.Spec): build spec spec: Build spec.
prefix (spack.util.prefix.Prefix): installation prefix prefix: Installation prefix.
Returns: Returns:
list: list of options List of options.
""" """
return [] return []
def global_options(self, spec, prefix): def global_options(self, spec: Spec, prefix: Prefix) -> Iterable[str]:
"""Extra global options to be supplied to the setup.py call before the install """Extra global options to be supplied to the setup.py call before the install
or bdist_wheel command. or bdist_wheel command.
Deprecated in pip 23.1. Deprecated in pip 23.1.
Args: Args:
spec (spack.spec.Spec): build spec spec: Build spec.
prefix (spack.util.prefix.Prefix): installation prefix prefix: Installation prefix.
Returns: Returns:
list: list of options List of options.
""" """
return [] return []
def install(self, pkg, spec, prefix): def install(self, pkg: PythonPackage, spec: Spec, prefix: Prefix) -> None:
"""Install everything from build directory.""" """Install everything from build directory."""
args = PythonPipBuilder.std_args(pkg) + [f"--prefix={prefix}"] args = PythonPipBuilder.std_args(pkg) + [f"--prefix={prefix}"]