[+] update pr34
1. add -U to UV_ARGS, ignore it in venv; 2. generate .whl; 3. update m.py for pr34;
This commit is contained in:
parent
f4f579b8f1
commit
aa6b407fe7
359
python/m.py
359
python/m.py
@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import glob
|
||||
import importlib
|
||||
import json
|
||||
import io
|
||||
import tempfile
|
||||
import dataclasses
|
||||
@ -8,15 +10,21 @@ import sys
|
||||
import subprocess
|
||||
import os
|
||||
import logging
|
||||
import typing
|
||||
|
||||
|
||||
from typing import (
|
||||
Optional,
|
||||
Any,
|
||||
cast,
|
||||
Type,
|
||||
TypeVar,
|
||||
Callable,
|
||||
)
|
||||
from typing_extensions import (
|
||||
Self,
|
||||
BinaryIO,
|
||||
overload,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -24,17 +32,23 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
def toml_load(f: BinaryIO) -> Any:
|
||||
try:
|
||||
import tomllib
|
||||
tomllib = importlib.import_module('tomllib')
|
||||
|
||||
return tomllib.load(f)
|
||||
except:
|
||||
return cast(
|
||||
Callable[[Any], Any],
|
||||
getattr(
|
||||
tomllib,
|
||||
'load',
|
||||
),
|
||||
)(f)
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import tomli
|
||||
|
||||
return tomli.load(f)
|
||||
except:
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
raise NotImplementedError
|
||||
@ -42,14 +56,136 @@ def toml_load(f: BinaryIO) -> Any:
|
||||
|
||||
@dataclasses.dataclass
|
||||
class PyProject:
|
||||
@dataclasses.dataclass
|
||||
class Module:
|
||||
name: str
|
||||
meson: Optional[pathlib.Path] = None
|
||||
tool: dict[str, Any] = dataclasses.field(default_factory=lambda: dict())
|
||||
|
||||
path: pathlib.Path
|
||||
dependencies: dict[str, list[str]]
|
||||
early_features: Optional[list[str]] = None
|
||||
pip_find_links: Optional[list[pathlib.Path]] = None
|
||||
runtime_libdirs: Optional[list[pathlib.Path]] = None
|
||||
runtime_preload: Optional[list[pathlib.Path]] = None
|
||||
|
||||
@dataclasses.dataclass
|
||||
class ThirdPartyRoot:
|
||||
package: Optional[str] = None
|
||||
module_root: Optional[str] = None
|
||||
path: Optional[str] = None
|
||||
|
||||
third_party_roots: list[ThirdPartyRoot] = dataclasses.field(
|
||||
default_factory=lambda: [],
|
||||
)
|
||||
requirements: dict[str, pathlib.Path] = dataclasses.field(default_factory=lambda: dict())
|
||||
|
||||
modules: list[Module] = dataclasses.field(
|
||||
default_factory=lambda: [],
|
||||
)
|
||||
|
||||
tool: dict[str, Any] = dataclasses.field(
|
||||
default_factory=lambda: dict(),
|
||||
)
|
||||
|
||||
|
||||
Key = TypeVar('Key')
|
||||
Value = TypeVar('Value')
|
||||
|
||||
|
||||
@overload
|
||||
def check_dict(
|
||||
value: Any,
|
||||
KT: Type[Key],
|
||||
VT: Type[Value],
|
||||
) -> dict[Key, Value]: ...
|
||||
|
||||
|
||||
@overload
|
||||
def check_dict(
|
||||
value: Any,
|
||||
KT: Type[Key],
|
||||
) -> dict[Key, Any]: ...
|
||||
|
||||
|
||||
def check_dict(
|
||||
value: Any,
|
||||
KT: Type[Key],
|
||||
VT: Optional[Type[Value]] = None,
|
||||
) -> dict[Key, Value]:
|
||||
assert isinstance(value, dict)
|
||||
value2 = cast(dict[Any, Any], value)
|
||||
|
||||
VT_class: Optional[type[Any]] = None
|
||||
|
||||
if not VT is None:
|
||||
if not typing.get_origin(VT) is None:
|
||||
VT_class = cast(type[Any], typing.get_origin(VT))
|
||||
else:
|
||||
VT_class = VT
|
||||
|
||||
assert all([isinstance(k, KT) and (VT_class is None or isinstance(v, VT_class)) for k, v in value2.items()])
|
||||
|
||||
if VT is None:
|
||||
return cast(
|
||||
dict[Key, Any],
|
||||
value,
|
||||
)
|
||||
else:
|
||||
return cast(
|
||||
dict[Key, Value],
|
||||
value,
|
||||
)
|
||||
|
||||
|
||||
@overload
|
||||
def check_list(
|
||||
value: Any,
|
||||
VT: Type[Value],
|
||||
) -> list[Value]: ...
|
||||
|
||||
|
||||
@overload
|
||||
def check_list(
|
||||
value: Any,
|
||||
) -> list[Any]: ...
|
||||
|
||||
|
||||
def check_list(
|
||||
value: Any,
|
||||
VT: Optional[Type[Value]] = None,
|
||||
) -> list[Value] | list[Any]:
|
||||
assert isinstance(value, list)
|
||||
value2 = cast(list[Any], value)
|
||||
|
||||
assert all([(VT is None or isinstance(o, VT)) for o in value2])
|
||||
|
||||
if VT is None:
|
||||
return cast(
|
||||
list[Any],
|
||||
value,
|
||||
)
|
||||
else:
|
||||
return cast(
|
||||
list[Value],
|
||||
value,
|
||||
)
|
||||
|
||||
|
||||
def check_type(
|
||||
value: Any,
|
||||
VT: Type[Value],
|
||||
attribute_name: Optional[str] = None,
|
||||
) -> Value:
|
||||
if attribute_name:
|
||||
attribute_value = getattr(value, attribute_name)
|
||||
assert isinstance(attribute_value, VT)
|
||||
return attribute_value
|
||||
else:
|
||||
assert isinstance(value, VT)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def pyproject_load(
|
||||
d: pathlib.Path,
|
||||
@ -66,9 +202,21 @@ def pyproject_load(
|
||||
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)
|
||||
for k, v in check_dict(
|
||||
check_dict(
|
||||
check_dict(
|
||||
content,
|
||||
str,
|
||||
# Any,
|
||||
)['project'],
|
||||
str,
|
||||
# Any,
|
||||
)['optional-dependencies'],
|
||||
str,
|
||||
list[Any],
|
||||
).items():
|
||||
# assert isinstance(v, list)
|
||||
# assert isinstance(k, str)
|
||||
|
||||
dependencies[k] = v
|
||||
|
||||
@ -79,36 +227,88 @@ def pyproject_load(
|
||||
|
||||
tool_name = 'online.fxreader.pr34'.replace('.', '-')
|
||||
|
||||
if 'tool' in content:
|
||||
res.tool = check_dict(
|
||||
content['tool'],
|
||||
str,
|
||||
)
|
||||
|
||||
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']
|
||||
pr34_tool = check_dict(
|
||||
check_dict(
|
||||
content['tool'],
|
||||
str,
|
||||
)[tool_name],
|
||||
str,
|
||||
)
|
||||
|
||||
if 'pip_find_links' in content['tool'][tool_name]:
|
||||
res.pip_find_links = [d.parent / pathlib.Path(o) for o in content['tool'][tool_name]['pip_find_links']]
|
||||
if 'early_features' in pr34_tool:
|
||||
res.early_features = pr34_tool['early_features']
|
||||
|
||||
if 'runtime_libdirs' in content['tool'][tool_name]:
|
||||
if 'pip_find_links' in pr34_tool:
|
||||
res.pip_find_links = [d.parent / pathlib.Path(o) for o in pr34_tool['pip_find_links']]
|
||||
|
||||
if 'runtime_libdirs' in pr34_tool:
|
||||
res.runtime_libdirs = [
|
||||
d.parent / pathlib.Path(o)
|
||||
# pathlib.Path(o)
|
||||
for o in content['tool'][tool_name]['runtime_libdirs']
|
||||
for o in check_list(pr34_tool['runtime_libdirs'], str)
|
||||
]
|
||||
|
||||
if 'runtime_preload' in content['tool'][tool_name]:
|
||||
if 'runtime_preload' in pr34_tool:
|
||||
res.runtime_preload = [
|
||||
d.parent / pathlib.Path(o)
|
||||
# pathlib.Path(o)
|
||||
for o in content['tool'][tool_name]['runtime_preload']
|
||||
for o in check_list(pr34_tool['runtime_preload'], str)
|
||||
]
|
||||
|
||||
if 'requirements' in content['tool'][tool_name]:
|
||||
assert isinstance(content['tool'][tool_name]['requirements'], dict)
|
||||
if 'third_party_roots' in pr34_tool:
|
||||
for o in check_list(pr34_tool['third_party_roots']):
|
||||
o2 = check_dict(o, str, str)
|
||||
assert all([k in {'package', 'module_root', 'path'} for k in o2])
|
||||
|
||||
res.third_party_roots.append(
|
||||
PyProject.ThirdPartyRoot(
|
||||
package=o2.get('package'),
|
||||
module_root=o2.get('module_root'),
|
||||
path=o2.get('path'),
|
||||
)
|
||||
)
|
||||
|
||||
if 'requirements' in pr34_tool:
|
||||
res.requirements = {
|
||||
k: d.parent / pathlib.Path(v)
|
||||
# pathlib.Path(o)
|
||||
for k, v in content['tool'][tool_name]['requirements'].items()
|
||||
for k, v in check_dict(pr34_tool['requirements'], str, str).items()
|
||||
}
|
||||
|
||||
if 'modules' in pr34_tool:
|
||||
modules = check_list(pr34_tool['modules'])
|
||||
# res.modules = []
|
||||
|
||||
for o in modules:
|
||||
assert isinstance(o, dict)
|
||||
assert 'name' in o and isinstance(o['name'], str)
|
||||
|
||||
module = PyProject.Module(
|
||||
name=o['name'],
|
||||
)
|
||||
|
||||
if 'meson' in o:
|
||||
assert 'meson' in o and isinstance(o['meson'], str)
|
||||
|
||||
module.meson = pathlib.Path(o['meson'])
|
||||
|
||||
if 'tool' in o:
|
||||
module.tool.update(
|
||||
check_dict(
|
||||
o['tool'],
|
||||
str,
|
||||
)
|
||||
)
|
||||
|
||||
res.modules.append(module)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
@ -127,10 +327,13 @@ class BootstrapSettings:
|
||||
),
|
||||
).strip()
|
||||
)
|
||||
pip_check_conflicts: Optional[bool] = dataclasses.field(
|
||||
default_factory=lambda: os.environ.get('PIP_CHECK_CONFLICTS', json.dumps(True)) in [json.dumps(True)],
|
||||
)
|
||||
uv_args: list[str] = dataclasses.field(
|
||||
default_factory=lambda: os.environ.get(
|
||||
'UV_ARGS',
|
||||
'--offline',
|
||||
'--offline -U',
|
||||
).split(),
|
||||
)
|
||||
|
||||
@ -142,7 +345,12 @@ class BootstrapSettings:
|
||||
if base_dir is None:
|
||||
base_dir = pathlib.Path.cwd()
|
||||
|
||||
env_path: Optional[pathlib.Path] = None
|
||||
if 'ENV_PATH' in os.environ:
|
||||
env_path = pathlib.Path(os.environ['ENV_PATH'])
|
||||
else:
|
||||
env_path = base_dir / '.venv'
|
||||
|
||||
python_path = env_path / 'bin' / 'python3'
|
||||
|
||||
return cls(
|
||||
@ -152,6 +360,47 @@ class BootstrapSettings:
|
||||
)
|
||||
|
||||
|
||||
class requirements_name_get_t:
|
||||
@dataclasses.dataclass
|
||||
class res_t:
|
||||
not_compiled: pathlib.Path
|
||||
compiled: pathlib.Path
|
||||
name: str
|
||||
|
||||
|
||||
def requirements_name_get(
|
||||
source_dir: pathlib.Path,
|
||||
python_version: Optional[str],
|
||||
features: list[str],
|
||||
requirements: dict[str, pathlib.Path],
|
||||
) -> requirements_name_get_t.res_t:
|
||||
requirements_python_version: Optional[str] = None
|
||||
if not python_version is None:
|
||||
requirements_python_version = python_version.replace('.', '_')
|
||||
|
||||
requirements_name = '_'.join(sorted(features))
|
||||
|
||||
if requirements_python_version:
|
||||
requirements_name += '_' + requirements_python_version
|
||||
|
||||
requirements_path: Optional[pathlib.Path] = None
|
||||
|
||||
if requirements_name in requirements:
|
||||
requirements_path = requirements[requirements_name]
|
||||
else:
|
||||
requirements_path = source_dir / 'requirements.txt'
|
||||
|
||||
requirements_path_in = requirements_path.parent / (requirements_path.stem + '.in')
|
||||
|
||||
requirements_in: list[str] = []
|
||||
|
||||
return requirements_name_get_t.res_t(
|
||||
not_compiled=requirements_path_in,
|
||||
compiled=requirements_path,
|
||||
name=requirements_name,
|
||||
)
|
||||
|
||||
|
||||
def env_bootstrap(
|
||||
bootstrap_settings: BootstrapSettings,
|
||||
pyproject: PyProject,
|
||||
@ -169,7 +418,7 @@ def env_bootstrap(
|
||||
]
|
||||
for o in pip_find_links
|
||||
],
|
||||
[],
|
||||
cast(list[str], []),
|
||||
)
|
||||
|
||||
features: list[str] = []
|
||||
@ -177,31 +426,24 @@ def env_bootstrap(
|
||||
if pyproject.early_features:
|
||||
features.extend(pyproject.early_features)
|
||||
|
||||
requirements_python_version: Optional[str] = None
|
||||
if not bootstrap_settings.python_version is None:
|
||||
requirements_python_version = bootstrap_settings.python_version.replace('.', '_')
|
||||
|
||||
requirements_name = '_'.join(sorted(features))
|
||||
|
||||
if requirements_python_version:
|
||||
requirements_name += '_' + requirements_python_version
|
||||
|
||||
requirements_path: Optional[pathlib.Path] = None
|
||||
|
||||
if requirements_name in pyproject.requirements:
|
||||
requirements_path = pyproject.requirements[requirements_name]
|
||||
else:
|
||||
requirements_path = pyproject.path.parent / 'requirements.txt'
|
||||
requirements_name_get_res = requirements_name_get(
|
||||
python_version=bootstrap_settings.python_version,
|
||||
features=features,
|
||||
requirements=pyproject.requirements,
|
||||
source_dir=pyproject.path.parent,
|
||||
)
|
||||
requirements_path = requirements_name_get_res.compiled
|
||||
|
||||
requirements_in: list[str] = []
|
||||
|
||||
requirements_in.extend(['uv', 'pip', 'build', 'setuptools', 'meson-python', 'pybind11'])
|
||||
|
||||
if pyproject.early_features:
|
||||
early_dependencies = sum([pyproject.dependencies[o] for o in pyproject.early_features], [])
|
||||
early_dependencies = sum([pyproject.dependencies[o] for o in pyproject.early_features], cast(list[str], []))
|
||||
|
||||
logger.info(
|
||||
dict(
|
||||
requirements_name_get_res=requirements_name_get_res,
|
||||
early_dependencies=early_dependencies,
|
||||
)
|
||||
)
|
||||
@ -218,6 +460,25 @@ def env_bootstrap(
|
||||
# *early_dependencies,
|
||||
# ])
|
||||
|
||||
uv_python_version: list[str] = []
|
||||
venv_python_version: list[str] = []
|
||||
|
||||
if not bootstrap_settings.python_version is None:
|
||||
uv_python_version.extend(
|
||||
[
|
||||
# '-p',
|
||||
'--python-version',
|
||||
bootstrap_settings.python_version,
|
||||
]
|
||||
)
|
||||
venv_python_version.extend(
|
||||
[
|
||||
'-p',
|
||||
# '--python-version',
|
||||
bootstrap_settings.python_version,
|
||||
]
|
||||
)
|
||||
|
||||
if not requirements_path.exists():
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode='w',
|
||||
@ -232,6 +493,7 @@ def env_bootstrap(
|
||||
'uv',
|
||||
'pip',
|
||||
'compile',
|
||||
*uv_python_version,
|
||||
'--generate-hashes',
|
||||
*pip_find_links_args,
|
||||
# '-p',
|
||||
@ -243,24 +505,14 @@ def env_bootstrap(
|
||||
]
|
||||
)
|
||||
|
||||
uv_python_version: list[str] = []
|
||||
|
||||
if not bootstrap_settings.python_version is None:
|
||||
uv_python_version.extend(
|
||||
[
|
||||
'-p',
|
||||
bootstrap_settings.python_version,
|
||||
]
|
||||
)
|
||||
|
||||
subprocess.check_call(
|
||||
[
|
||||
'uv',
|
||||
*[o for o in bootstrap_settings.uv_args if not o in ['-U', '--upgrade']],
|
||||
'venv',
|
||||
*uv_python_version,
|
||||
*venv_python_version,
|
||||
*pip_find_links_args,
|
||||
# '--seed',
|
||||
*bootstrap_settings.uv_args,
|
||||
str(bootstrap_settings.env_path),
|
||||
]
|
||||
)
|
||||
@ -270,6 +522,7 @@ def env_bootstrap(
|
||||
'uv',
|
||||
'pip',
|
||||
'install',
|
||||
*uv_python_version,
|
||||
*pip_find_links_args,
|
||||
'-p',
|
||||
bootstrap_settings.python_path,
|
||||
@ -280,6 +533,16 @@ def env_bootstrap(
|
||||
]
|
||||
)
|
||||
|
||||
if bootstrap_settings.pip_check_conflicts:
|
||||
subprocess.check_call(
|
||||
[
|
||||
bootstrap_settings.python_path,
|
||||
'-m',
|
||||
'online.fxreader.pr34.commands',
|
||||
'pip_check_conflicts',
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def paths_equal(a: pathlib.Path | str, b: pathlib.Path | str) -> bool:
|
||||
return os.path.abspath(str(a)) == os.path.abspath(str(b))
|
||||
|
@ -333,7 +333,7 @@ class BootstrapSettings:
|
||||
uv_args: list[str] = dataclasses.field(
|
||||
default_factory=lambda: os.environ.get(
|
||||
'UV_ARGS',
|
||||
'--offline',
|
||||
'--offline -U',
|
||||
).split(),
|
||||
)
|
||||
|
||||
@ -508,11 +508,11 @@ def env_bootstrap(
|
||||
subprocess.check_call(
|
||||
[
|
||||
'uv',
|
||||
*[o for o in bootstrap_settings.uv_args if not o in ['-U', '--upgrade']],
|
||||
'venv',
|
||||
*venv_python_version,
|
||||
*pip_find_links_args,
|
||||
# '--seed',
|
||||
*bootstrap_settings.uv_args,
|
||||
str(bootstrap_settings.env_path),
|
||||
]
|
||||
)
|
||||
|
BIN
releases/whl/online_fxreader_pr34-0.1.5.28-py3-none-any.whl
(Stored with Git LFS)
Normal file
BIN
releases/whl/online_fxreader_pr34-0.1.5.28-py3-none-any.whl
(Stored with Git LFS)
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user