freelance-project-34-market.../python/cli.py
LLM c2bfca5550 [+] ruff line-length 100, add meson:install:list, bump pr34 v0.1.5.66
1. set ruff line-length to 100, reformat 18 files;
  2. move pr34 version to pyproject.common.toml, read via toml in meson.build;
  3. fix meson install_subdir to only include meson/toolchains, not entire meson/;
  4. add meson:install:list command with --mode meson|pyproject for dry-run;
  5. add .venv-whl-cache to .gitignore exceptions and .gitattributes lfs tracking;
  6. release pr34 v0.1.5.66 .whl;
  7. commit python/.venv-whl-cache and archlinux/.venv-whl-cache via lfs;
2026-04-06 09:56:11 +00:00

298 lines
6.7 KiB
Python

import sys
import shutil
import glob
import io
import copy
import subprocess
import pathlib
import logging
import enum
import argparse
import dataclasses
from typing import (
Optional,
# override,
)
from typing_extensions import (
override,
)
from online.fxreader.pr34.commands_typed.logging import setup as logging_setup
from online.fxreader.pr34.commands_typed import cli as _cli
from online.fxreader.pr34.commands_typed import cli_bootstrap
logging_setup()
logger = logging.getLogger(__name__)
class Command(enum.Enum):
mypy = 'mypy'
pyright = 'pyright'
ruff = 'ruff'
deploy_wheel = 'deploy:wheel'
tests = 'tests'
meson_setup = 'meson:setup'
meson_install_list = 'meson:install:list'
module_switch = 'module:switch'
pyrefly = 'pyrefly'
@dataclasses.dataclass
class Settings(
_cli.DistSettings,
):
base_dir: pathlib.Path = pathlib.Path(__file__).parent.parent
build_dir: pathlib.Path = base_dir / 'tmp' / 'build'
wheel_dir: pathlib.Path = base_dir / 'deps' / 'dist'
env_path: pathlib.Path = cli_bootstrap.BootstrapSettings.get().env_path
python_path: pathlib.Path = pathlib.Path(sys.executable)
class CLI(_cli.CLI):
def __init__(self) -> None:
self.settings = Settings()
self._projects: dict[str, _cli.Project] = {
'online.fxreader.pr34': _cli.Project(
source_dir=self.settings.base_dir / 'python',
build_dir=self.settings.base_dir / 'tmp' / 'online' / 'fxreader' / 'pr34' / 'build',
dest_dir=self.settings.base_dir
/ 'tmp'
/ 'online'
/ 'fxreader'
/ 'pr34'
/ 'install',
meson_path=self.settings.base_dir / 'python' / 'meson.build',
),
'online.fxreader.pr34.commands_typed.archlinux': _cli.Project(
source_dir=self.settings.base_dir
/ 'meson'
/ 'online'
/ 'fxreader'
/ 'pr34'
/ 'commands_typed'
/ 'archlinux',
build_dir=self.settings.base_dir
/ 'tmp'
/ 'online'
/ 'fxreader'
/ 'pr34'
/ 'commands_typed'
/ 'archlinux'
/ 'build',
dest_dir=self.settings.base_dir
/ 'tmp'
/ 'online'
/ 'fxreader'
/ 'pr34'
/ 'commands_typed'
/ 'archlinux'
/ 'install',
meson_path=self.settings.base_dir
/ 'meson'
/ 'online'
/ 'fxreader'
/ 'pr34'
/ 'commands_typed'
/ 'archlinux'
/ 'meson.build',
),
}
self._dependencies: dict[str, _cli.Dependency] = dict()
@override
@property
def dist_settings(self) -> _cli.DistSettings:
return self.settings
@override
@property
def projects(self) -> dict[str, _cli.Project]:
return self._projects
def mypy(
self,
argv: list[str],
) -> None:
import online.fxreader.pr34.commands_typed.mypy as _mypy
project = self._projects['online.fxreader.pr34']
_mypy.run(
argv,
settings=_mypy.MypySettings(
paths=[
# Settings.settings().project_root / 'dotfiles/.local/bin/commands',
# project.source_dir / 'm.py',
project.source_dir / '_m.py',
project.source_dir / 'online',
project.source_dir / 'cli.py',
project.source_dir / 'm.py',
# Settings.settings().project_root / 'deps/com.github.aiortc.aiortc/src',
# Settings.settings().project_root / 'm.py',
],
max_errors={
'online/fxreader/pr34/commands_typed': 0,
# 'online/fxreader/pr34/commands': 0,
'cli.py': 0,
'm.py': 0,
'../deps/com.github.aiortc.aiortc/src/online_fxreader': 0,
'../deps/com.github.aiortc.aiortc/src/aiortc/contrib/signaling': 0,
},
),
)
@override
@property
def dependencies(self) -> dict[str, _cli.Dependency]:
return self._dependencies
def run(self, argv: Optional[list[str]] = None) -> None:
if argv is None:
argv = copy.deepcopy(sys.argv)
parser = argparse.ArgumentParser()
parser.add_argument('command', choices=[o.value for o in Command])
parser.add_argument('-p', '--project', choices=[o for o in self.projects])
parser.add_argument(
'-o',
'--output_dir',
default=None,
help='wheel output dir for deploy:wheel',
)
parser.add_argument(
'-f',
'--force',
default=False,
action='store_true',
help='remove install dir, before installing, default = false',
)
options, args = parser.parse_known_args(argv[1:])
default_project: Optional[str] = None
for k, v in self.projects.items():
if cli_bootstrap.paths_equal(
v.source_dir.resolve(),
# pathlib.Path(__file__).parent.resolve(),
pathlib.Path.cwd(),
):
default_project = k
if options.project is None:
if not default_project is None:
options.project = default_project
else:
logger.error(dict(msg='not provided project name'))
raise NotImplementedError
options.command = Command(options.command)
if options.command is Command.deploy_wheel:
assert not options.project is None
self.deploy_wheel(
project_name=options.project,
argv=args,
output_dir=options.output_dir,
# mypy=True,
ruff=True,
pyright=False,
pyrefly=True,
)
elif options.command is Command.pyright:
self.pyright(
project_name=options.project,
argv=args,
)
elif options.command is Command.ruff:
self.ruff(
project_name=options.project,
argv=args,
)
elif options.command is Command.meson_setup:
assert not options.project is None
self.meson_setup(
project_name=options.project,
argv=args,
force=options.force,
)
elif options.command is Command.meson_install_list:
assert not options.project is None
self.meson_install_list(
project_name=options.project,
argv=args,
)
elif options.command is Command.mypy:
self.mypy(
argv=args,
)
elif options.command is Command.tests:
from online.fxreader.pr34.commands_typed import argparse as pr34_argparse
tests_parser = argparse.ArgumentParser()
tests_parser.add_argument(
'--timeout',
default=16,
type=int,
help='test timeout in seconds, default = 16',
)
tests_options, tests_args = pr34_argparse.parse_args(tests_parser, args)
for k, v in self.projects.items():
if len(tests_args) > 0:
cmd = [
sys.executable,
'-m',
'unittest',
*tests_args,
]
else:
cmd = [
sys.executable,
'-m',
'unittest',
'discover',
'-s',
str(v.source_dir),
'-p',
'test_*.py',
'-t',
str(v.source_dir),
]
subprocess.check_call(
cmd,
cwd=str(v.source_dir),
timeout=tests_options.timeout,
)
elif options.command is Command.module_switch:
assert not options.project is None
self.module_switch(
project_name=options.project,
argv=args,
)
elif options.command is Command.pyrefly:
assert not options.project is None
self.pyrefly(
project_name=options.project,
argv=args,
)
else:
raise NotImplementedError
if __name__ == '__main__':
CLI().run()