From e2c3cf164ac19770c11fee552ffbda99ec8b36db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E4=B8=80=E6=B6=B5?= Date: Tue, 23 Apr 2024 15:28:11 +0800 Subject: [PATCH] add ci && format code --- .github/workflows/ci.yml | 49 ++++++++++++++++++++++++++ .github/workflows/python-publish.yml | 41 ++++++++++++++++++++++ jillw/__init__.py | 13 ++++--- jillw/cli.py | 47 +++++++++++++------------ jillw/configloader.py | 51 +++++++++++++++++----------- pyproject.toml | 22 ++++++++++++ tests/test_jillw.py | 2 ++ 7 files changed, 180 insertions(+), 45 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/python-publish.yml create mode 100644 tests/test_jillw.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c7dba23 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: CI +on: [ push, pull_request ] +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + OS: [ Ubuntu, macOS, Windows ] + python-version: [ "3.8" ] + include: + - os: Ubuntu + image: ubuntu-22.04 + - os: Windows + image: windows-2022 + - os: macOS + image: macos-12 + fail-fast: false + defaults: + run: + shell: bash + steps: + + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Static check + run: | + pip install isort==5.11.5 black==22.12.0 mypy==1.9.0 + isort --check . + black --check . + mypy . + + - name: Test + run: | + pip install . + pip install pytest coverage + coverage run --source=jillw -m pytest -s && coverage report && coverage xml + + - name: Python Cov + uses: codecov/codecov-action@v2 + with: + files: coverage.xml + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true \ No newline at end of file diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..232a4ed --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,41 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [ published ] + # 提交代码时,手动触发 + + +permissions: + contents: read + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + - name: Publish package + uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/jillw/__init__.py b/jillw/__init__.py index a1101b2..9b07d2e 100644 --- a/jillw/__init__.py +++ b/jillw/__init__.py @@ -1,17 +1,20 @@ from __future__ import annotations -import venv -import wisepy2 -import shutil + import json +import shutil import sys +import venv from pathlib import Path +from typing import Any, Dict, Union + +import wisepy2 root = Path("~/.jlenvs").expanduser() class Ops: @staticmethod - def get_config(new_conf: "dict | None" = None) -> dict: + def get_config(new_conf: "dict | None" = None) -> Union[Dict, Any]: root.mkdir(mode=0o755, parents=True, exist_ok=True) config_file = root.joinpath("config.json") if config_file.exists(): @@ -48,7 +51,7 @@ def create_( upstream=upstream, unstable=unstable, skip_symlinks=True, - reinstall=True + reinstall=True, ) print(wisepy2.Green(f"Environment {name} created at {envdir.as_posix()}.")) diff --git a/jillw/cli.py b/jillw/cli.py index 73088c0..5d891a3 100644 --- a/jillw/cli.py +++ b/jillw/cli.py @@ -1,14 +1,17 @@ from __future__ import annotations -from jillw import Ops -from wisepy2 import wise -from pathlib import Path -import os + import contextlib import io -import sys +import os +import shlex import subprocess +import sys +from pathlib import Path + import wisepy2 -import shlex +from wisepy2 import wise + +from jillw import Ops def find_julia_binary_dir(env: Path): @@ -37,11 +40,10 @@ def expect_no_stdout(): msg = sio.getvalue() print(wisepy2.Red(msg)) + def append_PATH(PATH: str, *paths: Path): - return os.pathsep.join([ - *map(os.path.normpath, paths), - *PATH.split(os.pathsep) - ]) + return os.pathsep.join([*map(os.path.normpath, paths), *PATH.split(os.pathsep)]) + def run_with_activated_env(cmd: list[str]): config = Ops.get_config() @@ -67,7 +69,9 @@ def run_with_activated_env(cmd: list[str]): del envdict["PYTHONHOME"] except KeyError: pass - envdict['PATH'] = append_PATH(os.environ["PATH"], jlbindir, env, env / "Scripts") + envdict["PATH"] = append_PATH( + os.environ["PATH"], jlbindir, env, env / "Scripts" + ) else: envdict = os.environ.copy() envdict["VIRTUAL_ENV"] = str(env) @@ -75,10 +79,11 @@ def run_with_activated_env(cmd: list[str]): del envdict["PYTHONHOME"] except KeyError: pass - envdict['PATH'] = append_PATH(os.environ["PATH"], jlbindir, env, env / "bin") + envdict["PATH"] = append_PATH(os.environ["PATH"], jlbindir, env, env / "bin") subprocess.run(cmd, env=envdict, shell=False) + class Main: @staticmethod def switch(name: str): @@ -103,42 +108,42 @@ def create( confirm: bool = False, unstable: bool = False, ): - """Create a new Julia environment - """ + """Create a new Julia environment""" with cmd_session(): Ops.create_(name, upstream, version, confirm, unstable) @staticmethod def remove(name: str): - """Remove a Julia environment - """ + """Remove a Julia environment""" with cmd_session(): Ops.remove_(name) @staticmethod def list(): - """List all Julia environments - """ + """List all Julia environments""" with cmd_session(): for each in Ops.list(): print(wisepy2.Purple(each.name, "=>", each.as_posix(), sep=" ")) @staticmethod def devhere(): - """Create a Development.toml at the current directory. - """ + """Create a Development.toml at the current directory.""" with cmd_session(): - from . configloader import write_empty_config_ + from .configloader import write_empty_config_ + write_empty_config_() + def main(): wise(Main)() + def julia(): extra_options: list[str] = [] if os.environ.get("DEV", "").strip(): from jillw.configloader import get_options + extra_options = get_options() run_with_activated_env(["julia", *extra_options, *sys.argv[1:]]) diff --git a/jillw/configloader.py b/jillw/configloader.py index 425f902..dbc5d62 100644 --- a/jillw/configloader.py +++ b/jillw/configloader.py @@ -1,12 +1,14 @@ from __future__ import annotations -import tomli + +import json import os import pathlib +from typing import Any, List, Union + +import tomli import wisepy2 -import json -EMPTY_CONFIG = \ -r""" +EMPTY_CONFIG = r""" [julia] min-latency = false quiet-start = false @@ -26,12 +28,15 @@ files = [] """ + def get_bool(conf: dict, name: str) -> bool | None: if conf.get(name, name): var = conf[name] if not isinstance(var, bool): raise ValueError("'{}' must be a boolean".format(name)) return var + return None + def get_int(conf: dict, name: str) -> int | None: if conf.get(name, name): @@ -39,13 +44,17 @@ def get_int(conf: dict, name: str) -> int | None: if not isinstance(var, int): raise ValueError("'{}' must be a int".format(name)) return var + return None + -def get_str_list(conf: dict, name: str) -> list[str] | None: +def get_str_list(conf: dict, name: str) -> Union[List[str], Any]: if conf.get(name, name): var = conf[name] if not isinstance(var, list) and not (all(isinstance(e, str) for e in var)): raise ValueError("'{}' must be a string list".format(name)) return var + return None + def get_str(conf: dict, name: str) -> str | None: if conf.get(name, name): @@ -53,6 +62,8 @@ def get_str(conf: dict, name: str) -> str | None: if not isinstance(var, str): raise ValueError("'{}' must be a string".format(name)) return var + return None + def write_empty_config_(): cwd = pathlib.Path(os.getcwd()) @@ -64,32 +75,33 @@ def write_empty_config_(): with dev.open("w", encoding="utf-8") as f: f.write(EMPTY_CONFIG) -def get_options() -> list[str]: + +def get_options() -> List[str]: cwd = pathlib.Path(os.getcwd()) dev = cwd / "Development.toml" if dev.is_file(): - io = dev.open('rb') - conf = tomli.load(io) # type: ignore + io = dev.open("rb") + conf = tomli.load(io) if not isinstance(conf, dict): return [] - conf = conf.get("julia") - if not isinstance(conf, dict): + julia_conf = conf.get("julia") + if not isinstance(julia_conf, dict): return [] else: return [] - opts: list[str] = [] + opts: List = [] - if get_bool(conf, 'min-latency'): + if get_bool(julia_conf, "min-latency"): opts.append("--compile=min") opts.append("-O0") - if project := get_str(conf, "project"): + if project := get_str(julia_conf, "project"): opts.append("--project={}".format(project)) if get_bool(conf, "interactive"): opts.append("-i") - if get_bool(conf, 'quiet-start'): + if get_bool(conf, "quiet-start"): opts.append("--quiet") if sysimage := get_str(conf, "sysimage"): @@ -99,18 +111,19 @@ def get_options() -> list[str]: if get_bool(conf, "no-startup-file"): opts.append("--startup-file=no") - if preload_modules := get_str_list(conf, 'using'): + if preload_modules := get_str_list(conf, "using"): for each in preload_modules: opts.append("-e") opts.append("using {}".format(each)) - if preincluded_files := get_str_list(conf, 'files'): + if preincluded_files := get_str_list(conf, "files"): for file in preincluded_files: opts.append("-e") opts.append( - 'include(' + - 'raw' +json.dumps(str(cwd / file), ensure_ascii=False) + - ')' + "include(" + + "raw" + + json.dumps(str(cwd / file), ensure_ascii=False) + + ")" ) return opts diff --git a/pyproject.toml b/pyproject.toml index 5d5bd1f..b17f13c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,3 +19,25 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] jillw = 'jillw.cli:main' julia = 'jillw.cli:julia' + +[tool.poetry.group.test.dependencies] +pytest = "^7.2.2" +pytest-cov = "^4.1.0" + +[tool.poetry.group.dev.dependencies] +isort = "5.11.5" +black = "22.12.0" +mypy = "^1.9.0" + +[tool.isort] +profile = "black" +skip = [".venv", "logs"] + + +[tool.mypy] +python_version = "3.8" +warn_return_any = true +warn_unused_configs = true +check_untyped_defs = true +ignore_missing_imports = true +exclude = [".venv", "logs"] diff --git a/tests/test_jillw.py b/tests/test_jillw.py new file mode 100644 index 0000000..c6e729d --- /dev/null +++ b/tests/test_jillw.py @@ -0,0 +1,2 @@ +def test_all(): + assert 1 + 1 == 2