diff --git a/setup.py b/setup.py deleted file mode 100644 index 6d0fd7d..0000000 --- a/setup.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python3 -"""Setup script for packaging checkin.""" - -from pathlib import Path -import re -from setuptools import setup, find_packages - - -NAME = "kernel_install" - - -def read(*parts): - """Read the content of a file.""" - script_path = Path(__file__).parent - with script_path.joinpath(*parts).open() as f: - return f.read() - - -def find_version(*parts): - """The the version in a given file.""" - vers_file = read(*parts) - match = re.search(r'^__version__ = "(\d+.\d+.\d+)"', vers_file, re.M) - if match is not None: - return match.group(1) - raise RuntimeError("Unable to find version string.") - - -setup( - name=NAME, - version=find_version("src", "kernel_install", "_version.py"), - author="Martin Bergemann", - author_email="bergemann@dkrz.de", - maintainer="Martin Bergemann", - url="https://gitlab.dkrz.de/k204230/install-kernelspec", - description="utility to install various jupyter kernel specs.", - long_description=read("README.md"), - license="GPLv3", - packages=find_packages("src"), - package_dir={"": "src"}, - entry_points={ - "console_scripts": ["jupyter-kernel-install = kernel_install.cli:cli"] - }, - install_requires=["argparse", "bash_kernel", "ipykernel"], - python_requires=">=3.8", - classifiers=[ - "Development Status :: 3 - Alpha", - "Environment :: Console", - "Intended Audience :: Developers", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: BSD License", - "Operating System :: POSIX :: Linux", - "Programming Language :: Python :: 3", - ], -) diff --git a/src/kernel_install/__init__.py b/src/kernel_install/__init__.py index ea06805..a72919a 100644 --- a/src/kernel_install/__init__.py +++ b/src/kernel_install/__init__.py @@ -1,4 +1,35 @@ -from .install import * -from ._version import __version__ +"""kernel-install +BSD 3-Clause License -__all__ = install.__all__ +Copyright (c) 2023, Climate Informatics and Technologies (CLINT) + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +from .install import bash, python, r + +__version__ = "2309.0.0" +__all__ = ["bash", "r", "python"] diff --git a/src/kernel_install/_version.py b/src/kernel_install/_version.py deleted file mode 100644 index 6bbe708..0000000 --- a/src/kernel_install/_version.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "2309.0.0" diff --git a/src/kernel_install/cli.py b/src/kernel_install/cli.py index 9508ea5..504b1be 100644 --- a/src/kernel_install/cli.py +++ b/src/kernel_install/cli.py @@ -1,9 +1,16 @@ +"""Main command line interface.""" + import argparse -from pathlib import Path -from typing import Dict, List, Optional, Callable import sys +from pathlib import Path +from typing import cast, Callable, Dict, List, Optional + +from rich import print as pprint +from rich_argparse import ArgumentDefaultsRichHelpFormatter + +from kernel_install import __version__, install + from .install import __all__ as methods -from ._version import __version__ def parse_args(argv: Optional[List[str]]) -> Dict[str, str]: @@ -12,7 +19,7 @@ def parse_args(argv: Optional[List[str]]) -> Dict[str, str]: ap = argp( prog="jupyter-kernel-install", description="Install jupyter kernel specs of different languages.", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, + formatter_class=ArgumentDefaultsRichHelpFormatter, ) ap.add_argument( "language", @@ -34,29 +41,30 @@ def parse_args(argv: Optional[List[str]]) -> Dict[str, str]: "-V", help="Display version and exit", action="version", - version="%(prog)s {version}".format(version=__version__), + version=f"%(prog)s {__version__}", ) args = ap.parse_args(argv) args.name = args.name or args.language - return dict( - language=args.language, - name=args.name, - display_name=args.display_name or args.name, - ) + return { + "language": args.language, + "name": args.name, + "display_name": args.display_name or args.name, + } -def get_method(method: str) -> Callable[str, Path]: +def get_method(method: str) -> Callable[[str, str], Path]: """Get the correct install method.""" - from kernel_install import install + return cast(Callable[[str, str], Path], getattr(install, method)) - return getattr(install, method) - -def cli(argv: Optional[List[str]] = None): +def cli(argv: Optional[List[str]] = None) -> None: + """The main cli message.""" config = parse_args(argv or sys.argv[1:]) - kernel_file = get_method(config["language"])(config["name"], config["display_name"]) - print(f"Kernel has been successfully installed to {kernel_file}") + kernel_file = get_method(config["language"])( + config["name"], config["display_name"] + ) + pprint(f"Kernel has been successfully installed to [b]{kernel_file}[/b]") if __name__ == "__main__": diff --git a/src/kernel_install/install.py b/src/kernel_install/install.py index 07ab887..fe91071 100644 --- a/src/kernel_install/install.py +++ b/src/kernel_install/install.py @@ -1,12 +1,16 @@ +"""Definition of install methods.""" + import json import os -from pathlib import Path -from subprocess import CalledProcessError, PIPE, run -import shlex -import sys import shutil +from pathlib import Path +from subprocess import PIPE, CalledProcessError, run from tempfile import TemporaryDirectory -from typing import Optional +from typing import Dict, Optional + +from bash_kernel.install import kernel_json +from ipykernel.kernelspec import install as install_kernel +from jupyter_client.kernelspec import KernelSpecManager __all__ = ["bash", "r", "python"] @@ -18,10 +22,9 @@ def get_ld_library_path_from_bin(binary: str) -> Optional[str]: bin_path = shutil.which(binary) if bin_path is None: return None - path = Path(shutil.which(binary)).parent - python_path = str(Path(path) / "python") + python_path = Path(bin_path).parent / "python" res = run( - [python_path, "-c", "import sys; print(sys.exec_prefix)"], + [str(python_path), "-c", "import sys; print(sys.exec_prefix)"], check=True, stdout=PIPE, stderr=PIPE, @@ -30,24 +33,21 @@ def get_ld_library_path_from_bin(binary: str) -> Optional[str]: out = res.stdout.decode("utf-8").splitlines()[0] if out: return str(Path(out) / "lib") + return None -def get_env(*args): +def get_env(*args: str) -> Dict[str, str]: """Get additional environment varialbes.""" env = {} for arg in args: value = os.environ.get(arg, "") if value: env[arg] = value - if env: - return dict(env=env) - return {} + return env def bash(name: str = "bash", display_name: Optional[str] = None) -> Path: """Install bash kernel spec.""" - from bash_kernel.install import kernel_json - from jupyter_client.kernelspec import KernelSpecManager name = name or "bash" kernel_json["display_name"] = display_name or name @@ -56,10 +56,10 @@ def bash(name: str = "bash", display_name: Optional[str] = None) -> Path: "EVALUATION_SYSTEM_CONFIG_FILE", "EVALUATION_SYSTEM_CONFIG_DIR", "PATH" ) if env: - kernel_json["env"] = env["env"] + kernel_json["env"] = env with TemporaryDirectory() as td: os.chmod(td, 0o755) # Starts off as 700, not user readable - with open(os.path.join(td, "kernel.json"), "w") as f: + with open(os.path.join(td, "kernel.json"), "w", encoding="utf-8") as f: json.dump(kernel_json, f, sort_keys=True, indent=3) KernelSpecManager().install_kernel_spec(td, name, user=True) return KERNEL_DIR / name @@ -78,24 +78,22 @@ def r(name: str = "r", display_name: Optional[str] = None) -> Path: env = get_env( "EVALUATION_SYSTEM_CONFIG_FILE", "EVALUATION_SYSTEM_CONFIG_DIR" ) - env.setdefault("env", {}) ld_lib_path = get_ld_library_path_from_bin("R") if ld_lib_path: - env["env"]["LD_LIBRARY_PATH"] = ld_lib_path + env["LD_LIBRARY_PATH"] = ld_lib_path res = os.system(cmd) if res != 0: raise CalledProcessError(res, cmd) - kernel_json = json.loads((KERNEL_DIR / name / "kernel.json").read_text()) + kernel = json.loads((KERNEL_DIR / name / "kernel.json").read_text()) with (KERNEL_DIR / name / "kernel.json").open("w", encoding="utf-8") as f: - kernel_json["env"] = env["env"] - json.dump(kernel_json, f, indent=3) + kernel["env"] = env + json.dump(kernel, f, indent=3) return KERNEL_DIR / name def python(name: str = "python3", display_name: Optional[str] = None) -> Path: """Install python3 kernel spec.""" - from ipykernel.kernelspec import install as install_kernel env_kw = get_env( "EVALUATION_SYSTEM_CONFIG_FILE", "EVALUATION_SYSTEM_CONFIG_DIR" @@ -104,7 +102,7 @@ def python(name: str = "python3", display_name: Optional[str] = None) -> Path: user=True, kernel_name=name or "python3", display_name=display_name or name, - **env_kw, + env=env_kw, ) return Path(path)