omdev 0.0.0.dev150__tar.gz → 0.0.0.dev152__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of omdev might be problematic. Click here for more details.
- {omdev-0.0.0.dev150/omdev.egg-info → omdev-0.0.0.dev152}/PKG-INFO +2 -2
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/data/cache.py +2 -2
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/imgur.py +1 -1
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/pycharm/cli.py +1 -1
- omdev-0.0.0.dev152/omdev/pyproject/cli.py +302 -0
- omdev-0.0.0.dev152/omdev/pyproject/venvs.py +114 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/scripts/interp.py +2 -2
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/scripts/pyproject.py +456 -200
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/doc.py +1 -1
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/docker.py +2 -2
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152/omdev.egg-info}/PKG-INFO +2 -2
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev.egg-info/SOURCES.txt +1 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev.egg-info/requires.txt +1 -1
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/pyproject.toml +2 -2
- omdev-0.0.0.dev150/omdev/pyproject/cli.py +0 -427
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/LICENSE +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/MANIFEST.in +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/README.rst +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/.manifests.json +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/__about__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/amalg/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/amalg/__main__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/amalg/amalg.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/antlr/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/antlr/consts.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/antlr/gen.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/bracepy.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/compute/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/compute/cache.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/compute/contexts.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/compute/currents.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/compute/fns.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/compute/resolvers.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/compute/storage.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/compute/types.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/data/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/data/actions.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/data/consts.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/data/defaults.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/data/manifests.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cache/data/specs.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_boilerplate.cc +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/LICENSE +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/build_ext.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/compilers/options.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/dir_util.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/errors.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/extension.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/file_util.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/modified.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/spawn.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/sysconfig.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/util.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/_distutils/version.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/build.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/cmake.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/importhook.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/magic.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cexts/scan.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/classdot.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cli/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cli/__main__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cli/_pathhack.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cli/clicli.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cli/install.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cli/main.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cli/managers.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cli/types.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/clipboard/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/clipboard/clipboard.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/clipboard/darwin_cf.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/clipboard/linux_x11.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/cmake.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/findimports.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/git.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/interp/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/interp/__main__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/interp/cli.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/interp/inspect.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/interp/providers.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/interp/pyenv.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/interp/resolvers.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/interp/standalone.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/interp/system.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/interp/types.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/magic/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/magic/find.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/magic/magic.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/magic/prepare.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/magic/styles.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/manifests/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/manifests/__main__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/manifests/build.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/manifests/main.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/mypy/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/mypy/debug.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/packaging/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/packaging/marshal.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/packaging/names.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/packaging/requires.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/packaging/specifiers.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/packaging/versions.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/pip.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/precheck/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/precheck/__main__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/precheck/base.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/precheck/git.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/precheck/lite.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/precheck/main.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/precheck/manifests.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/precheck/scripts.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/ptk/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/ptk/apps/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/ptk/apps/ncdu.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/pycharm/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/pycharm/__main__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/pyproject/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/pyproject/__main__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/pyproject/cexts.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/pyproject/configs.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/pyproject/pkg.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/pyproject/reqs.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/revisions.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/scripts/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/scripts/bumpversion.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/scripts/execrss.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/scripts/exectime.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/scripts/importtrace.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/scripts/slowcat.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/scripts/tmpexec.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/secrets.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tokens.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/toml/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/toml/parser.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/toml/writer.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/cloc.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/git.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/importscan.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/json/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/json/__main__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/json/cli.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/json/formats.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/json/io.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/json/parsing.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/json/processing.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/json/rendering.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/mkrelimp.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/notebook.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/pawk/__init__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/pawk/__main__.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/pawk/pawk.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/pip.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/prof.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/qr.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/tools/sqlrepl.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev/wheelfile.py +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev.egg-info/dependency_links.txt +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev.egg-info/entry_points.txt +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/omdev.egg-info/top_level.txt +0 -0
- {omdev-0.0.0.dev150 → omdev-0.0.0.dev152}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: omdev
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev152
|
|
4
4
|
Summary: omdev
|
|
5
5
|
Author: wrmsr
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
|
|
|
12
12
|
Classifier: Operating System :: POSIX
|
|
13
13
|
Requires-Python: >=3.12
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: omlish==0.0.0.
|
|
15
|
+
Requires-Dist: omlish==0.0.0.dev152
|
|
16
16
|
Provides-Extra: all
|
|
17
17
|
Requires-Dist: black~=24.10; extra == "all"
|
|
18
18
|
Requires-Dist: pycparser~=2.22; extra == "all"
|
|
@@ -24,8 +24,8 @@ import urllib.request
|
|
|
24
24
|
from omlish import check
|
|
25
25
|
from omlish import lang
|
|
26
26
|
from omlish import marshal as msh
|
|
27
|
-
from omlish import os as osu
|
|
28
27
|
from omlish.formats import json
|
|
28
|
+
from omlish.os.files import touch
|
|
29
29
|
|
|
30
30
|
from ... import git
|
|
31
31
|
from .actions import Action
|
|
@@ -262,7 +262,7 @@ class Cache:
|
|
|
262
262
|
if not os.path.isdir(item_dir):
|
|
263
263
|
self._fetch_item(spec, item_dir)
|
|
264
264
|
|
|
265
|
-
|
|
265
|
+
touch(os.path.join(item_dir, 'accessed'))
|
|
266
266
|
|
|
267
267
|
data_dir = os.path.join(item_dir, 'data')
|
|
268
268
|
return self._return_val(spec, data_dir)
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# @omlish-amalg ../scripts/pyproject.py
|
|
3
|
+
# ruff: noqa: UP006 UP007
|
|
4
|
+
"""
|
|
5
|
+
TODO:
|
|
6
|
+
- check / tests, src dir sets
|
|
7
|
+
- ci
|
|
8
|
+
- build / package / publish / version roll
|
|
9
|
+
- {pkg_name: [src_dirs]}, default excludes, generate MANIFST.in, ...
|
|
10
|
+
- env vars - PYTHONPATH
|
|
11
|
+
|
|
12
|
+
See:
|
|
13
|
+
- https://pdm-project.org/en/latest/
|
|
14
|
+
- https://rye.astral.sh/philosophy/
|
|
15
|
+
- https://github.com/indygreg/python-build-standalone/blob/main/pythonbuild/cpython.py
|
|
16
|
+
- https://astral.sh/blog/uv
|
|
17
|
+
- https://github.com/jazzband/pip-tools
|
|
18
|
+
- https://github.com/Osiris-Team/1JPM
|
|
19
|
+
- https://github.com/brettcannon/microvenv
|
|
20
|
+
- https://github.com/pypa/pipx
|
|
21
|
+
- https://github.com/tox-dev/tox/
|
|
22
|
+
"""
|
|
23
|
+
import argparse
|
|
24
|
+
import asyncio
|
|
25
|
+
import concurrent.futures as cf
|
|
26
|
+
import dataclasses as dc
|
|
27
|
+
import functools
|
|
28
|
+
import itertools
|
|
29
|
+
import multiprocessing as mp
|
|
30
|
+
import os.path
|
|
31
|
+
import shlex
|
|
32
|
+
import shutil
|
|
33
|
+
import sys
|
|
34
|
+
import typing as ta
|
|
35
|
+
|
|
36
|
+
from omlish.argparse.cli import ArgparseCli
|
|
37
|
+
from omlish.argparse.cli import argparse_arg
|
|
38
|
+
from omlish.argparse.cli import argparse_command
|
|
39
|
+
from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_call
|
|
40
|
+
from omlish.lite.cached import cached_nullary
|
|
41
|
+
from omlish.lite.check import check
|
|
42
|
+
from omlish.lite.logs import configure_standard_logging
|
|
43
|
+
from omlish.lite.runtime import check_runtime_version
|
|
44
|
+
|
|
45
|
+
from ..toml.parser import toml_loads
|
|
46
|
+
from .configs import PyprojectConfig
|
|
47
|
+
from .configs import PyprojectConfigPreparer
|
|
48
|
+
from .pkg import BasePyprojectPackageGenerator
|
|
49
|
+
from .pkg import PyprojectPackageGenerator
|
|
50
|
+
from .venvs import Venv
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dc.dataclass(frozen=True)
|
|
57
|
+
class VersionsFile:
|
|
58
|
+
name: ta.Optional[str] = '.versions'
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def parse(s: str) -> ta.Mapping[str, str]:
|
|
62
|
+
return {
|
|
63
|
+
k: v
|
|
64
|
+
for l in s.splitlines()
|
|
65
|
+
if (sl := l.split('#')[0].strip())
|
|
66
|
+
for k, _, v in (sl.partition('='),)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@cached_nullary
|
|
70
|
+
def contents(self) -> ta.Mapping[str, str]:
|
|
71
|
+
if not self.name or not os.path.exists(self.name):
|
|
72
|
+
return {}
|
|
73
|
+
with open(self.name) as f:
|
|
74
|
+
s = f.read()
|
|
75
|
+
return self.parse(s)
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def get_pythons(d: ta.Mapping[str, str]) -> ta.Mapping[str, str]:
|
|
79
|
+
pfx = 'PYTHON_'
|
|
80
|
+
return {k[len(pfx):].lower(): v for k, v in d.items() if k.startswith(pfx)}
|
|
81
|
+
|
|
82
|
+
@cached_nullary
|
|
83
|
+
def pythons(self) -> ta.Mapping[str, str]:
|
|
84
|
+
return self.get_pythons(self.contents())
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
##
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@cached_nullary
|
|
91
|
+
def _script_rel_path() -> str:
|
|
92
|
+
cwd = os.getcwd()
|
|
93
|
+
if not (f := __file__).startswith(cwd):
|
|
94
|
+
raise OSError(f'file {f} not in {cwd}')
|
|
95
|
+
return f[len(cwd):].lstrip(os.sep)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
##
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class Run:
|
|
102
|
+
def __init__(
|
|
103
|
+
self,
|
|
104
|
+
*,
|
|
105
|
+
raw_cfg: ta.Union[ta.Mapping[str, ta.Any], str, None] = None,
|
|
106
|
+
) -> None:
|
|
107
|
+
super().__init__()
|
|
108
|
+
|
|
109
|
+
self._raw_cfg = raw_cfg
|
|
110
|
+
|
|
111
|
+
@cached_nullary
|
|
112
|
+
def raw_cfg(self) -> ta.Mapping[str, ta.Any]:
|
|
113
|
+
if self._raw_cfg is None:
|
|
114
|
+
with open('pyproject.toml') as f:
|
|
115
|
+
buf = f.read()
|
|
116
|
+
elif isinstance(self._raw_cfg, str):
|
|
117
|
+
buf = self._raw_cfg
|
|
118
|
+
else:
|
|
119
|
+
return self._raw_cfg
|
|
120
|
+
return toml_loads(buf)
|
|
121
|
+
|
|
122
|
+
@cached_nullary
|
|
123
|
+
def cfg(self) -> PyprojectConfig:
|
|
124
|
+
dct = self.raw_cfg()['tool']['omlish']['pyproject']
|
|
125
|
+
return PyprojectConfigPreparer(
|
|
126
|
+
python_versions=VersionsFile().pythons(),
|
|
127
|
+
).prepare_config(dct)
|
|
128
|
+
|
|
129
|
+
@cached_nullary
|
|
130
|
+
def venvs(self) -> ta.Mapping[str, Venv]:
|
|
131
|
+
return {
|
|
132
|
+
n: Venv(n, c)
|
|
133
|
+
for n, c in self.cfg().venvs.items()
|
|
134
|
+
if not n.startswith('_')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
##
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class PyprojectCli(ArgparseCli):
|
|
142
|
+
_docker_container = argparse_arg('--_docker_container', help=argparse.SUPPRESS)
|
|
143
|
+
|
|
144
|
+
@argparse_command(
|
|
145
|
+
argparse_arg('name'),
|
|
146
|
+
argparse_arg('-e', '--docker-env', action='append'),
|
|
147
|
+
argparse_arg('cmd', nargs='?'),
|
|
148
|
+
argparse_arg('args', nargs=argparse.REMAINDER),
|
|
149
|
+
)
|
|
150
|
+
async def venv(self) -> None:
|
|
151
|
+
venv = Run().venvs()[self.args.name]
|
|
152
|
+
if (sd := venv.cfg.docker) is not None and sd != (cd := self.args._docker_container): # noqa
|
|
153
|
+
script = ' '.join([
|
|
154
|
+
'python3',
|
|
155
|
+
shlex.quote(_script_rel_path()),
|
|
156
|
+
f'--_docker_container={shlex.quote(sd)}',
|
|
157
|
+
*map(shlex.quote, sys.argv[1:]),
|
|
158
|
+
])
|
|
159
|
+
|
|
160
|
+
docker_env = {
|
|
161
|
+
'DOCKER_HOST_PLATFORM': os.environ.get('DOCKER_HOST_PLATFORM', sys.platform),
|
|
162
|
+
}
|
|
163
|
+
for e in self.args.docker_env or []:
|
|
164
|
+
if '=' in e:
|
|
165
|
+
k, _, v = e.split('=')
|
|
166
|
+
docker_env[k] = v
|
|
167
|
+
else:
|
|
168
|
+
docker_env[e] = os.environ.get(e, '')
|
|
169
|
+
|
|
170
|
+
await asyncio_subprocess_check_call(
|
|
171
|
+
'docker',
|
|
172
|
+
'compose',
|
|
173
|
+
'-f', 'docker/compose.yml',
|
|
174
|
+
'exec',
|
|
175
|
+
*itertools.chain.from_iterable(
|
|
176
|
+
('-e', f'{k}={v}')
|
|
177
|
+
for k, v in docker_env.items()
|
|
178
|
+
),
|
|
179
|
+
'-it', sd,
|
|
180
|
+
'bash', '--login', '-c', script,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
return
|
|
184
|
+
|
|
185
|
+
cmd = self.args.cmd
|
|
186
|
+
if not cmd:
|
|
187
|
+
await venv.create()
|
|
188
|
+
|
|
189
|
+
elif cmd == 'python':
|
|
190
|
+
await venv.create()
|
|
191
|
+
os.execl(
|
|
192
|
+
(exe := venv.exe()),
|
|
193
|
+
exe,
|
|
194
|
+
*self.args.args,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
elif cmd == 'exe':
|
|
198
|
+
await venv.create()
|
|
199
|
+
check.arg(not self.args.args)
|
|
200
|
+
print(venv.exe())
|
|
201
|
+
|
|
202
|
+
elif cmd == 'run':
|
|
203
|
+
await venv.create()
|
|
204
|
+
sh = check.not_none(shutil.which('bash'))
|
|
205
|
+
script = ' '.join(self.args.args)
|
|
206
|
+
if not script:
|
|
207
|
+
script = sh
|
|
208
|
+
os.execl(
|
|
209
|
+
(bash := check.not_none(sh)),
|
|
210
|
+
bash,
|
|
211
|
+
'-c',
|
|
212
|
+
f'. {venv.dir_name}/bin/activate && ' + script,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
elif cmd == 'srcs':
|
|
216
|
+
check.arg(not self.args.args)
|
|
217
|
+
print('\n'.join(venv.srcs()))
|
|
218
|
+
|
|
219
|
+
elif cmd == 'test':
|
|
220
|
+
await venv.create()
|
|
221
|
+
await asyncio_subprocess_check_call(venv.exe(), '-m', 'pytest', *(self.args.args or []), *venv.srcs())
|
|
222
|
+
|
|
223
|
+
else:
|
|
224
|
+
raise Exception(f'unknown subcommand: {cmd}')
|
|
225
|
+
|
|
226
|
+
@argparse_command(
|
|
227
|
+
argparse_arg('-b', '--build', action='store_true'),
|
|
228
|
+
argparse_arg('-r', '--revision', action='store_true'),
|
|
229
|
+
argparse_arg('-j', '--jobs', type=int),
|
|
230
|
+
argparse_arg('cmd', nargs='?'),
|
|
231
|
+
argparse_arg('args', nargs=argparse.REMAINDER),
|
|
232
|
+
)
|
|
233
|
+
async def pkg(self) -> None:
|
|
234
|
+
run = Run()
|
|
235
|
+
|
|
236
|
+
cmd = self.args.cmd
|
|
237
|
+
if not cmd:
|
|
238
|
+
raise Exception('must specify command')
|
|
239
|
+
|
|
240
|
+
elif cmd == 'gen':
|
|
241
|
+
pkgs_root = os.path.join('.pkg')
|
|
242
|
+
|
|
243
|
+
if os.path.exists(pkgs_root):
|
|
244
|
+
shutil.rmtree(pkgs_root)
|
|
245
|
+
|
|
246
|
+
build_output_dir = 'dist'
|
|
247
|
+
run_build = bool(self.args.build)
|
|
248
|
+
add_revision = bool(self.args.revision)
|
|
249
|
+
|
|
250
|
+
if run_build:
|
|
251
|
+
os.makedirs(build_output_dir, exist_ok=True)
|
|
252
|
+
|
|
253
|
+
pgs: ta.List[BasePyprojectPackageGenerator] = [
|
|
254
|
+
PyprojectPackageGenerator(
|
|
255
|
+
dir_name,
|
|
256
|
+
pkgs_root,
|
|
257
|
+
)
|
|
258
|
+
for dir_name in run.cfg().pkgs
|
|
259
|
+
]
|
|
260
|
+
pgs = list(itertools.chain.from_iterable([pg, *pg.children()] for pg in pgs))
|
|
261
|
+
|
|
262
|
+
num_threads = self.args.jobs or int(max(mp.cpu_count() // 1.5, 1))
|
|
263
|
+
futs: ta.List[cf.Future]
|
|
264
|
+
with cf.ThreadPoolExecutor(num_threads) as ex:
|
|
265
|
+
futs = [ex.submit(pg.gen) for pg in pgs]
|
|
266
|
+
for fut in futs:
|
|
267
|
+
fut.result()
|
|
268
|
+
|
|
269
|
+
if run_build:
|
|
270
|
+
futs = [
|
|
271
|
+
ex.submit(functools.partial(
|
|
272
|
+
pg.build,
|
|
273
|
+
build_output_dir,
|
|
274
|
+
BasePyprojectPackageGenerator.BuildOpts(
|
|
275
|
+
add_revision=add_revision,
|
|
276
|
+
),
|
|
277
|
+
))
|
|
278
|
+
for pg in pgs
|
|
279
|
+
]
|
|
280
|
+
for fut in futs:
|
|
281
|
+
fut.result()
|
|
282
|
+
|
|
283
|
+
else:
|
|
284
|
+
raise Exception(f'unknown subcommand: {cmd}')
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
##
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
async def _async_main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
|
|
291
|
+
check_runtime_version()
|
|
292
|
+
configure_standard_logging()
|
|
293
|
+
|
|
294
|
+
await PyprojectCli(argv).async_cli_run()
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
|
|
298
|
+
asyncio.run(_async_main(argv))
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
if __name__ == '__main__':
|
|
302
|
+
_main()
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
|
2
|
+
import glob
|
|
3
|
+
import os.path
|
|
4
|
+
import typing as ta
|
|
5
|
+
|
|
6
|
+
from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_call
|
|
7
|
+
from omlish.lite.cached import async_cached_nullary
|
|
8
|
+
from omlish.lite.cached import cached_nullary
|
|
9
|
+
from omlish.lite.check import check
|
|
10
|
+
from omlish.lite.logs import log
|
|
11
|
+
|
|
12
|
+
from ..interp.resolvers import DEFAULT_INTERP_RESOLVER
|
|
13
|
+
from ..interp.types import InterpSpecifier
|
|
14
|
+
from .configs import VenvConfig
|
|
15
|
+
from .reqs import RequirementsRewriter
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Venv:
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
name: str,
|
|
25
|
+
cfg: VenvConfig,
|
|
26
|
+
) -> None:
|
|
27
|
+
super().__init__()
|
|
28
|
+
self._name = name
|
|
29
|
+
self._cfg = cfg
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def cfg(self) -> VenvConfig:
|
|
33
|
+
return self._cfg
|
|
34
|
+
|
|
35
|
+
DIR_NAME = '.venvs'
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def dir_name(self) -> str:
|
|
39
|
+
return os.path.join(self.DIR_NAME, self._name)
|
|
40
|
+
|
|
41
|
+
@async_cached_nullary
|
|
42
|
+
async def interp_exe(self) -> str:
|
|
43
|
+
i = InterpSpecifier.parse(check.not_none(self._cfg.interp))
|
|
44
|
+
return check.not_none(await DEFAULT_INTERP_RESOLVER.resolve(i, install=True)).exe
|
|
45
|
+
|
|
46
|
+
@cached_nullary
|
|
47
|
+
def exe(self) -> str:
|
|
48
|
+
ve = os.path.join(self.dir_name, 'bin/python')
|
|
49
|
+
if not os.path.isfile(ve):
|
|
50
|
+
raise Exception(f'venv exe {ve} does not exist or is not a file!')
|
|
51
|
+
return ve
|
|
52
|
+
|
|
53
|
+
@async_cached_nullary
|
|
54
|
+
async def create(self) -> bool:
|
|
55
|
+
if os.path.exists(dn := self.dir_name):
|
|
56
|
+
if not os.path.isdir(dn):
|
|
57
|
+
raise Exception(f'{dn} exists but is not a directory!')
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
log.info('Using interpreter %s', (ie := await self.interp_exe()))
|
|
61
|
+
await asyncio_subprocess_check_call(ie, '-m', 'venv', dn)
|
|
62
|
+
|
|
63
|
+
ve = self.exe()
|
|
64
|
+
uv = self._cfg.use_uv
|
|
65
|
+
|
|
66
|
+
await asyncio_subprocess_check_call(
|
|
67
|
+
ve,
|
|
68
|
+
'-m', 'pip',
|
|
69
|
+
'install', '-v', '--upgrade',
|
|
70
|
+
'pip',
|
|
71
|
+
'setuptools',
|
|
72
|
+
'wheel',
|
|
73
|
+
*(['uv'] if uv else []),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
if sr := self._cfg.requires:
|
|
77
|
+
rr = RequirementsRewriter(self._name)
|
|
78
|
+
reqs = [rr.rewrite(req) for req in sr]
|
|
79
|
+
|
|
80
|
+
# TODO: automatically try slower uv download when it fails? lol
|
|
81
|
+
# Caused by: Failed to download distribution due to network timeout. Try increasing UV_HTTP_TIMEOUT (current value: 30s). # noqa
|
|
82
|
+
# UV_CONCURRENT_DOWNLOADS=4 UV_HTTP_TIMEOUT=3600
|
|
83
|
+
|
|
84
|
+
await asyncio_subprocess_check_call(
|
|
85
|
+
ve,
|
|
86
|
+
'-m',
|
|
87
|
+
*(['uv'] if uv else []),
|
|
88
|
+
'pip',
|
|
89
|
+
'install',
|
|
90
|
+
*([] if uv else ['-v']),
|
|
91
|
+
*reqs,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def _resolve_srcs(raw: ta.List[str]) -> ta.List[str]:
|
|
98
|
+
out: list[str] = []
|
|
99
|
+
seen: ta.Set[str] = set()
|
|
100
|
+
for r in raw:
|
|
101
|
+
es: list[str]
|
|
102
|
+
if any(c in r for c in '*?'):
|
|
103
|
+
es = list(glob.glob(r, recursive=True))
|
|
104
|
+
else:
|
|
105
|
+
es = [r]
|
|
106
|
+
for e in es:
|
|
107
|
+
if e not in seen:
|
|
108
|
+
seen.add(e)
|
|
109
|
+
out.append(e)
|
|
110
|
+
return out
|
|
111
|
+
|
|
112
|
+
@cached_nullary
|
|
113
|
+
def srcs(self) -> ta.Sequence[str]:
|
|
114
|
+
return self._resolve_srcs(self._cfg.srcs or [])
|
|
@@ -65,7 +65,7 @@ CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
|
|
65
65
|
# ../../omlish/lite/check.py
|
|
66
66
|
SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
|
|
67
67
|
CheckMessage = ta.Union[str, ta.Callable[..., ta.Optional[str]], None] # ta.TypeAlias
|
|
68
|
-
CheckLateConfigureFn = ta.Callable[['Checks'], None]
|
|
68
|
+
CheckLateConfigureFn = ta.Callable[['Checks'], None] # ta.TypeAlias
|
|
69
69
|
CheckOnRaiseFn = ta.Callable[[Exception], None] # ta.TypeAlias
|
|
70
70
|
CheckExceptionFactory = ta.Callable[..., Exception] # ta.TypeAlias
|
|
71
71
|
CheckArgsRenderer = ta.Callable[..., ta.Optional[str]] # ta.TypeAlias
|
|
@@ -76,7 +76,7 @@ UnparsedVersionVar = ta.TypeVar('UnparsedVersionVar', bound=UnparsedVersion)
|
|
|
76
76
|
CallableVersionOperator = ta.Callable[['Version', str], bool]
|
|
77
77
|
|
|
78
78
|
# ../../omlish/lite/subprocesses.py
|
|
79
|
-
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull']
|
|
79
|
+
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
########################################
|