diff --git a/m.py b/m.py deleted file mode 120000 index dfd589e..0000000 --- a/m.py +++ /dev/null @@ -1 +0,0 @@ -python/m.py \ No newline at end of file diff --git a/m.py b/m.py new file mode 100755 index 0000000..bb5a4c8 --- /dev/null +++ b/m.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +import glob +import io +import dataclasses +import pathlib +import sys +import subprocess +import os +import logging +import tomllib + +from typing import (Self, Optional, Any,) + +logger = logging.getLogger(__name__) + +@dataclasses.dataclass +class PyProject: + dependencies: dict[str, list[str]] + early_features: Optional[list[str]] = None + +def pyproject_load( + d: pathlib.Path, +) -> PyProject: + with io.open(d, 'rb') as f: + content = tomllib.load(f) + + assert isinstance(content, dict) + + dependencies : dict[str, list[str]] = dict() + + dependencies['default'] = content['project']['dependencies'] + + if ( + 'optional-dependencies' in content['project'] + ): + assert isinstance( + content['project']['optional-dependencies'], + dict + ) + + for k, v in content['project']['optional-dependencies'].items(): + assert isinstance(v, list) + assert isinstance(k, str) + + dependencies[k] = v + + + res = PyProject( + dependencies=dependencies, + ) + + tool_name = 'online.fxreader.pr34'.replace('.', '-') + + if ( + 'tool' in content and + isinstance( + content['tool'], dict + ) and + tool_name in content['tool'] and + isinstance( + content['tool'][tool_name], + dict + ) + ): + if 'early_features' in content['tool'][tool_name]: + res.early_features = content['tool'][tool_name]['early_features'] + + return res + +@dataclasses.dataclass +class BootstrapSettings: + env_path: pathlib.Path + python_path: pathlib.Path + + @classmethod + def get( + cls, + base_dir: Optional[pathlib.Path] = None, + ) -> Self: + if base_dir is None: + base_dir = pathlib.Path.cwd() + + env_path = base_dir / '.venv' + python_path = env_path / 'bin' / 'python3' + + return cls( + env_path=env_path, + python_path=python_path, + ) + +def env_bootstrap( + bootstrap_settings: BootstrapSettings, + pyproject: PyProject, +) -> None: + subprocess.check_call([ + 'uv', 'venv', '--seed', '--offline', + str(bootstrap_settings.env_path) + ]) + + subprocess.check_call([ + 'uv', + 'pip', + 'install', + '-p', + bootstrap_settings.python_path, + '--offline', + 'uv', + ]) + + subprocess.check_call([ + bootstrap_settings.python_path, + '-m', + 'uv', 'pip', 'install', + '--offline', + 'build', 'setuptools', 'meson-python', 'pybind11', + ]) + + early_wheels = glob.glob( + str( + pathlib.Path(__file__).parent / 'deps' / 'dist' / 'early' / '*.whl' + ) + ) + + if len(early_wheels) > 0: + subprocess.check_call([ + bootstrap_settings.python_path, + '-m', + 'uv', 'pip', 'install', + '--offline', + *early_wheels, + ]) + + if pyproject.early_features: + early_dependencies = sum([ + pyproject.dependencies[o] + for o in pyproject.early_features + ], []) + + logger.info(dict( + early_dependencies=early_dependencies, + )) + if len(early_dependencies) > 0: + subprocess.check_call([ + bootstrap_settings.python_path, + '-m', + 'uv', 'pip', 'install', + '--offline', + *early_dependencies, + ]) + +def paths_equal( + a: pathlib.Path | str, + b: pathlib.Path | str +) -> bool: + return ( + os.path.abspath(str(a)) == + os.path.abspath(str(b)) + ) + +def run( + d: Optional[pathlib.Path] = None, + cli_path: Optional[pathlib.Path] = None, +) -> None: + if cli_path is None: + cli_path = pathlib.Path(__file__).parent / 'cli.py' + + if d is None: + d = pathlib.Path(__file__).parent / 'pyproject.toml' + + bootstrap_settings = BootstrapSettings.get() + + pyproject : PyProject = pyproject_load( + d + ) + + logging.basicConfig(level=logging.INFO) + + if not bootstrap_settings.env_path.exists(): + env_bootstrap( + bootstrap_settings=bootstrap_settings, + pyproject=pyproject, + ) + + logger.info([sys.executable, sys.argv, bootstrap_settings.python_path]) + + if not paths_equal(sys.executable, bootstrap_settings.python_path): + os.execv( + str(bootstrap_settings.python_path), + [ + str(bootstrap_settings.python_path), + *sys.argv, + ] + ) + + os.execv( + str(bootstrap_settings.python_path), + [ + str(bootstrap_settings.python_path), + str( + cli_path + ), + *sys.argv[1:], + ] + ) + +if __name__ == '__main__': + run( + d=pathlib.Path(__file__).parent / 'python' / 'pyproject.toml', + cli_path=pathlib.Path(__file__).parent / 'python' / 'cli.py', + ) \ No newline at end of file diff --git a/python/_m.py b/python/_m.py index 50b67e9..f2a003d 100644 --- a/python/_m.py +++ b/python/_m.py @@ -165,27 +165,12 @@ def inside_env() -> bool: # ruff = 'ruff' # m2 = 'm2' -def mypy(argv: list[str]) -> None: - import online.fxreader.pr34.commands_typed.mypy as _mypy +# def mypy(argv: list[str]) -> None: +# import online.fxreader.pr34.commands_typed.mypy as _mypy - _mypy.run( - argv, - settings=_mypy.MypySettings( - paths=[ - #Settings.settings().project_root / 'dotfiles/.local/bin/commands', - Settings.settings().project_root / 'python' / 'm.py', - Settings.settings().project_root / 'python' / '_m.py', - Settings.settings().project_root / 'python' / 'online', - # Settings.settings().project_root / 'deps/com.github.aiortc.aiortc/src', - #Settings.settings().project_root / 'm.py', - ], - max_errors={ - 'python/online/fxreader/pr34/commands_typed': 0, - 'deps/com.github.aiortc.aiortc/src/online_fxreader': 0, - 'deps/com.github.aiortc.aiortc/src/aiortc/contrib/signaling': 0 - } - ), - ) +# _mypy.run( +# argv, +# ) def host_deps(argv: list[str]) -> None: if sys.platform in ['linux']: @@ -240,17 +225,17 @@ def run(argv: Optional[list[str]] = None) -> None: host_deps(args) elif options.command == 'env': env(args, mode='exec',) - elif options.command == 'mypy': - if not inside_env(): - env( - [ - pathlib.Path(__file__).parent / 'm.py', - *argv[1:], - ], - mode='exec' - ) - else: - mypy(args) + # elif options.command == 'mypy': + # if not inside_env(): + # env( + # [ + # pathlib.Path(__file__).parent / 'm.py', + # *argv[1:], + # ], + # mode='exec' + # ) + # else: + # mypy(args) elif options.command == 'ruff': ruff(args) elif options.command == 'm2': diff --git a/python/cli.py b/python/cli.py index 738b0e8..787a422 100644 --- a/python/cli.py +++ b/python/cli.py @@ -61,6 +61,37 @@ class CLI(_cli.CLI): 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', + self.settings.base_dir / 'm.py', + # Settings.settings().project_root / 'deps/com.github.aiortc.aiortc/src', + #Settings.settings().project_root / 'm.py', + ], + max_errors={ + 'python/online/fxreader/pr34/commands_typed': 0, + 'python/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]: diff --git a/python/m.py b/python/m.py deleted file mode 100755 index bb5a4c8..0000000 --- a/python/m.py +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/env python3 -import glob -import io -import dataclasses -import pathlib -import sys -import subprocess -import os -import logging -import tomllib - -from typing import (Self, Optional, Any,) - -logger = logging.getLogger(__name__) - -@dataclasses.dataclass -class PyProject: - dependencies: dict[str, list[str]] - early_features: Optional[list[str]] = None - -def pyproject_load( - d: pathlib.Path, -) -> PyProject: - with io.open(d, 'rb') as f: - content = tomllib.load(f) - - assert isinstance(content, dict) - - dependencies : dict[str, list[str]] = dict() - - dependencies['default'] = content['project']['dependencies'] - - if ( - 'optional-dependencies' in content['project'] - ): - assert isinstance( - content['project']['optional-dependencies'], - dict - ) - - for k, v in content['project']['optional-dependencies'].items(): - assert isinstance(v, list) - assert isinstance(k, str) - - dependencies[k] = v - - - res = PyProject( - dependencies=dependencies, - ) - - tool_name = 'online.fxreader.pr34'.replace('.', '-') - - if ( - 'tool' in content and - isinstance( - content['tool'], dict - ) and - tool_name in content['tool'] and - isinstance( - content['tool'][tool_name], - dict - ) - ): - if 'early_features' in content['tool'][tool_name]: - res.early_features = content['tool'][tool_name]['early_features'] - - return res - -@dataclasses.dataclass -class BootstrapSettings: - env_path: pathlib.Path - python_path: pathlib.Path - - @classmethod - def get( - cls, - base_dir: Optional[pathlib.Path] = None, - ) -> Self: - if base_dir is None: - base_dir = pathlib.Path.cwd() - - env_path = base_dir / '.venv' - python_path = env_path / 'bin' / 'python3' - - return cls( - env_path=env_path, - python_path=python_path, - ) - -def env_bootstrap( - bootstrap_settings: BootstrapSettings, - pyproject: PyProject, -) -> None: - subprocess.check_call([ - 'uv', 'venv', '--seed', '--offline', - str(bootstrap_settings.env_path) - ]) - - subprocess.check_call([ - 'uv', - 'pip', - 'install', - '-p', - bootstrap_settings.python_path, - '--offline', - 'uv', - ]) - - subprocess.check_call([ - bootstrap_settings.python_path, - '-m', - 'uv', 'pip', 'install', - '--offline', - 'build', 'setuptools', 'meson-python', 'pybind11', - ]) - - early_wheels = glob.glob( - str( - pathlib.Path(__file__).parent / 'deps' / 'dist' / 'early' / '*.whl' - ) - ) - - if len(early_wheels) > 0: - subprocess.check_call([ - bootstrap_settings.python_path, - '-m', - 'uv', 'pip', 'install', - '--offline', - *early_wheels, - ]) - - if pyproject.early_features: - early_dependencies = sum([ - pyproject.dependencies[o] - for o in pyproject.early_features - ], []) - - logger.info(dict( - early_dependencies=early_dependencies, - )) - if len(early_dependencies) > 0: - subprocess.check_call([ - bootstrap_settings.python_path, - '-m', - 'uv', 'pip', 'install', - '--offline', - *early_dependencies, - ]) - -def paths_equal( - a: pathlib.Path | str, - b: pathlib.Path | str -) -> bool: - return ( - os.path.abspath(str(a)) == - os.path.abspath(str(b)) - ) - -def run( - d: Optional[pathlib.Path] = None, - cli_path: Optional[pathlib.Path] = None, -) -> None: - if cli_path is None: - cli_path = pathlib.Path(__file__).parent / 'cli.py' - - if d is None: - d = pathlib.Path(__file__).parent / 'pyproject.toml' - - bootstrap_settings = BootstrapSettings.get() - - pyproject : PyProject = pyproject_load( - d - ) - - logging.basicConfig(level=logging.INFO) - - if not bootstrap_settings.env_path.exists(): - env_bootstrap( - bootstrap_settings=bootstrap_settings, - pyproject=pyproject, - ) - - logger.info([sys.executable, sys.argv, bootstrap_settings.python_path]) - - if not paths_equal(sys.executable, bootstrap_settings.python_path): - os.execv( - str(bootstrap_settings.python_path), - [ - str(bootstrap_settings.python_path), - *sys.argv, - ] - ) - - os.execv( - str(bootstrap_settings.python_path), - [ - str(bootstrap_settings.python_path), - str( - cli_path - ), - *sys.argv[1:], - ] - ) - -if __name__ == '__main__': - run( - d=pathlib.Path(__file__).parent / 'python' / 'pyproject.toml', - cli_path=pathlib.Path(__file__).parent / 'python' / 'cli.py', - ) \ No newline at end of file diff --git a/python/online/fxreader/pr34/commands_typed/cli.py b/python/online/fxreader/pr34/commands_typed/cli.py index 9742ef2..673cbf2 100644 --- a/python/online/fxreader/pr34/commands_typed/cli.py +++ b/python/online/fxreader/pr34/commands_typed/cli.py @@ -163,7 +163,7 @@ class CLI(abc.ABC): ) if mypy: - self.mypy() + self.mypy([]) if env is None: env = dict()