omdev 0.0.0.dev179__py3-none-any.whl → 0.0.0.dev181__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
omdev/.manifests.json CHANGED
@@ -96,14 +96,14 @@
96
96
  }
97
97
  },
98
98
  {
99
- "module": ".magic.find",
99
+ "module": ".magic.__main__",
100
100
  "attr": "_CLI_MODULE",
101
- "file": "omdev/magic/find.py",
102
- "line": 230,
101
+ "file": "omdev/magic/__main__.py",
102
+ "line": 4,
103
103
  "value": {
104
104
  "$.cli.types.CliModule": {
105
- "cmd_name": "py/findmagic",
106
- "mod_name": "omdev.magic.find"
105
+ "cmd_name": "magic",
106
+ "mod_name": "omdev.magic.__main__"
107
107
  }
108
108
  }
109
109
  },
omdev/cli/clicli.py CHANGED
@@ -21,15 +21,15 @@ class CliCli(ap.Cli):
21
21
 
22
22
  #
23
23
 
24
- @ap.command(name='version', aliases=['ver'])
24
+ @ap.cmd(name='version', aliases=['ver'])
25
25
  def print_version(self) -> None:
26
26
  print(__about__.__version__)
27
27
 
28
- @ap.command(name='revision', aliases=['rev'])
28
+ @ap.cmd(name='revision', aliases=['rev'])
29
29
  def print_revision(self) -> None:
30
30
  print(__about__.__revision__)
31
31
 
32
- @ap.command(name='home')
32
+ @ap.cmd(name='home')
33
33
  def print_home(self) -> None:
34
34
  print(sys.prefix)
35
35
 
@@ -52,7 +52,7 @@ class CliCli(ap.Cli):
52
52
  ],
53
53
  )
54
54
 
55
- @ap.command(
55
+ @ap.cmd(
56
56
  ap.arg('args', nargs=ap.REMAINDER),
57
57
  name='python',
58
58
  accepts_unknown=True,
@@ -60,7 +60,7 @@ class CliCli(ap.Cli):
60
60
  def python_cmd(self) -> None:
61
61
  self._passthrough_args_cmd(sys.executable)
62
62
 
63
- @ap.command(
63
+ @ap.cmd(
64
64
  ap.arg('args', nargs=ap.REMAINDER),
65
65
  name='pip',
66
66
  accepts_unknown=True,
@@ -70,7 +70,7 @@ class CliCli(ap.Cli):
70
70
 
71
71
  #
72
72
 
73
- @ap.command(
73
+ @ap.cmd(
74
74
  ap.arg('--url', default=DEFAULT_REINSTALL_URL),
75
75
  ap.arg('--local', action='store_true'),
76
76
  ap.arg('extra_deps', nargs='*'),
omdev/imgur.py CHANGED
@@ -107,7 +107,7 @@ def _main() -> None:
107
107
  from omlish.argparse import all as ap
108
108
 
109
109
  class Cli(ap.Cli):
110
- @ap.command(
110
+ @ap.cmd(
111
111
  ap.arg('file'),
112
112
  )
113
113
  def upload(self) -> None:
omdev/interp/cli.py CHANGED
@@ -12,7 +12,7 @@ import typing as ta
12
12
 
13
13
  from omlish.argparse.cli import ArgparseCli
14
14
  from omlish.argparse.cli import argparse_arg
15
- from omlish.argparse.cli import argparse_command
15
+ from omlish.argparse.cli import argparse_cmd
16
16
  from omlish.lite.cached import cached_nullary
17
17
  from omlish.lite.check import check
18
18
  from omlish.lite.inject import Injector
@@ -37,7 +37,7 @@ class InterpCli(ArgparseCli):
37
37
 
38
38
  #
39
39
 
40
- @argparse_command(
40
+ @argparse_cmd(
41
41
  argparse_arg('version'),
42
42
  argparse_arg('-d', '--debug', action='store_true'),
43
43
  )
@@ -46,7 +46,7 @@ class InterpCli(ArgparseCli):
46
46
  s = InterpSpecifier.parse(self.args.version)
47
47
  await r.list(s)
48
48
 
49
- @argparse_command(
49
+ @argparse_cmd(
50
50
  argparse_arg('version'),
51
51
  argparse_arg('-p', '--provider'),
52
52
  argparse_arg('-d', '--debug', action='store_true'),
omdev/interp/inspect.py CHANGED
@@ -6,7 +6,6 @@ import sys
6
6
  import typing as ta
7
7
 
8
8
  from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
9
- from omlish.lite.logs import log
10
9
 
11
10
  from ..packaging.versions import Version
12
11
  from .types import InterpOpts
@@ -43,9 +42,15 @@ class InterpInspection:
43
42
 
44
43
 
45
44
  class InterpInspector:
46
- def __init__(self) -> None:
45
+ def __init__(
46
+ self,
47
+ *,
48
+ log: ta.Optional[logging.Logger] = None,
49
+ ) -> None:
47
50
  super().__init__()
48
51
 
52
+ self._log = log
53
+
49
54
  self._cache: ta.Dict[str, ta.Optional[InterpInspection]] = {}
50
55
 
51
56
  _RAW_INSPECTION_CODE = """
@@ -94,8 +99,8 @@ class InterpInspector:
94
99
  try:
95
100
  ret = await self._inspect(exe)
96
101
  except Exception as e: # noqa
97
- if log.isEnabledFor(logging.DEBUG):
98
- log.exception('Failed to inspect interp: %s', exe)
102
+ if self._log is not None and self._log.isEnabledFor(logging.DEBUG):
103
+ self._log.exception('Failed to inspect interp: %s', exe)
99
104
  ret = None
100
105
  self._cache[exe] = ret
101
106
  return ret
@@ -5,13 +5,13 @@ TODO:
5
5
  - check if path py's are venvs: sys.prefix != sys.base_prefix
6
6
  """
7
7
  import dataclasses as dc
8
+ import logging
8
9
  import os
9
10
  import re
10
11
  import typing as ta
11
12
 
12
13
  from omlish.lite.cached import cached_nullary
13
14
  from omlish.lite.check import check
14
- from omlish.lite.logs import log
15
15
 
16
16
  from ...packaging.versions import InvalidVersion
17
17
  from ..inspect import InterpInspector
@@ -37,12 +37,14 @@ class SystemInterpProvider(InterpProvider):
37
37
  options: Options = Options(),
38
38
  *,
39
39
  inspector: ta.Optional[InterpInspector] = None,
40
+ log: ta.Optional[logging.Logger] = None,
40
41
  ) -> None:
41
42
  super().__init__()
42
43
 
43
44
  self._options = options
44
45
 
45
46
  self._inspector = inspector
47
+ self._log = log
46
48
 
47
49
  #
48
50
 
@@ -116,7 +118,8 @@ class SystemInterpProvider(InterpProvider):
116
118
  lst = []
117
119
  for e in self.exes():
118
120
  if (ev := await self.get_exe_version(e)) is None:
119
- log.debug('Invalid system version: %s', e)
121
+ if self._log is not None:
122
+ self._log.debug('Invalid system version: %s', e)
120
123
  continue
121
124
  lst.append((e, ev))
122
125
  return lst
@@ -13,6 +13,7 @@ TODO:
13
13
  import abc
14
14
  import dataclasses as dc
15
15
  import itertools
16
+ import logging
16
17
  import os.path
17
18
  import shutil
18
19
  import sys
@@ -22,7 +23,6 @@ from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
22
23
  from omlish.lite.cached import async_cached_nullary
23
24
  from omlish.lite.cached import cached_nullary
24
25
  from omlish.lite.check import check
25
- from omlish.lite.logs import log
26
26
 
27
27
  from ...packaging.versions import InvalidVersion
28
28
  from ...packaging.versions import Version
@@ -355,6 +355,7 @@ class PyenvInterpProvider(InterpProvider):
355
355
  *,
356
356
  pyenv: Pyenv,
357
357
  inspector: InterpInspector,
358
+ log: ta.Optional[logging.Logger] = None,
358
359
  ) -> None:
359
360
  super().__init__()
360
361
 
@@ -362,6 +363,7 @@ class PyenvInterpProvider(InterpProvider):
362
363
 
363
364
  self._pyenv = pyenv
364
365
  self._inspector = inspector
366
+ self._log = log
365
367
 
366
368
  #
367
369
 
@@ -406,7 +408,8 @@ class PyenvInterpProvider(InterpProvider):
406
408
  ret: ta.List[PyenvInterpProvider.Installed] = []
407
409
  for vn, ep in await self._pyenv.version_exes():
408
410
  if (i := await self._make_installed(vn, ep)) is None:
409
- log.debug('Invalid pyenv version: %s', vn)
411
+ if self._log is not None:
412
+ self._log.debug('Invalid pyenv version: %s', vn)
410
413
  continue
411
414
  ret.append(i)
412
415
  return ret
omdev/interp/venvs.py ADDED
@@ -0,0 +1,114 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import dataclasses as dc
3
+ import logging
4
+ import os.path
5
+ import typing as ta
6
+
7
+ from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
8
+ from omlish.lite.cached import async_cached_nullary
9
+ from omlish.lite.cached import cached_nullary
10
+ from omlish.lite.check import check
11
+ from omlish.lite.typing import Func2
12
+
13
+ from .default import get_default_interp_resolver
14
+ from .types import InterpSpecifier
15
+
16
+
17
+ ##
18
+
19
+
20
+ @dc.dataclass(frozen=True)
21
+ class InterpVenvConfig:
22
+ interp: ta.Optional[str] = None
23
+ requires: ta.Optional[ta.Sequence[str]] = None
24
+ use_uv: ta.Optional[bool] = None
25
+
26
+
27
+ class InterpVenvRequirementsProcessor(Func2['InterpVenv', ta.Sequence[str], ta.Sequence[str]]):
28
+ pass
29
+
30
+
31
+ class InterpVenv:
32
+ def __init__(
33
+ self,
34
+ path: str,
35
+ cfg: InterpVenvConfig,
36
+ *,
37
+ requirements_processor: ta.Optional[InterpVenvRequirementsProcessor] = None,
38
+ log: ta.Optional[logging.Logger] = None,
39
+ ) -> None:
40
+ super().__init__()
41
+
42
+ self._path = path
43
+ self._cfg = cfg
44
+
45
+ self._requirements_processor = requirements_processor
46
+ self._log = log
47
+
48
+ @property
49
+ def path(self) -> str:
50
+ return self._path
51
+
52
+ @property
53
+ def cfg(self) -> InterpVenvConfig:
54
+ return self._cfg
55
+
56
+ @async_cached_nullary
57
+ async def interp_exe(self) -> str:
58
+ i = InterpSpecifier.parse(check.not_none(self._cfg.interp))
59
+ return check.not_none(await get_default_interp_resolver().resolve(i, install=True)).exe
60
+
61
+ @cached_nullary
62
+ def exe(self) -> str:
63
+ ve = os.path.join(self._path, 'bin/python')
64
+ if not os.path.isfile(ve):
65
+ raise Exception(f'venv exe {ve} does not exist or is not a file!')
66
+ return ve
67
+
68
+ @async_cached_nullary
69
+ async def create(self) -> bool:
70
+ if os.path.exists(dn := self._path):
71
+ if not os.path.isdir(dn):
72
+ raise Exception(f'{dn} exists but is not a directory!')
73
+ return False
74
+
75
+ ie = await self.interp_exe()
76
+
77
+ if self._log is not None:
78
+ self._log.info('Using interpreter %s', ie)
79
+
80
+ await asyncio_subprocesses.check_call(ie, '-m', 'venv', dn)
81
+
82
+ ve = self.exe()
83
+ uv = self._cfg.use_uv
84
+
85
+ await asyncio_subprocesses.check_call(
86
+ ve,
87
+ '-m', 'pip',
88
+ 'install', '-v', '--upgrade',
89
+ 'pip',
90
+ 'setuptools',
91
+ 'wheel',
92
+ *(['uv'] if uv else []),
93
+ )
94
+
95
+ if sr := self._cfg.requires:
96
+ reqs = list(sr)
97
+ if self._requirements_processor is not None:
98
+ reqs = list(self._requirements_processor(self, reqs))
99
+
100
+ # TODO: automatically try slower uv download when it fails? lol
101
+ # Caused by: Failed to download distribution due to network timeout. Try increasing UV_HTTP_TIMEOUT (current value: 30s). # noqa
102
+ # UV_CONCURRENT_DOWNLOADS=4 UV_HTTP_TIMEOUT=3600
103
+
104
+ await asyncio_subprocesses.check_call(
105
+ ve,
106
+ '-m',
107
+ *(['uv'] if uv else []),
108
+ 'pip',
109
+ 'install',
110
+ *([] if uv else ['-v']),
111
+ *reqs,
112
+ )
113
+
114
+ return True
@@ -0,0 +1,11 @@
1
+ from ..cli import CliModule
2
+
3
+
4
+ # @omlish-manifest
5
+ _CLI_MODULE = CliModule('magic', __name__)
6
+
7
+
8
+ if __name__ == '__main__':
9
+ from .cli import _main
10
+
11
+ _main()
omdev/magic/cli.py ADDED
@@ -0,0 +1,54 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import typing as ta
3
+
4
+ from omlish.argparse.cli import ArgparseCli
5
+ from omlish.argparse.cli import argparse_arg
6
+ from omlish.argparse.cli import argparse_cmd
7
+
8
+ from .find import find_magic_files
9
+ from .find import find_magic_py_modules
10
+ from .styles import C_MAGIC_STYLE
11
+ from .styles import PY_MAGIC_STYLE
12
+
13
+
14
+ ##
15
+
16
+
17
+ class MagicCli(ArgparseCli):
18
+ @argparse_cmd(
19
+ argparse_arg('--style', '-s', default='py'),
20
+ argparse_arg('--key', '-k', dest='keys', action='append'),
21
+ argparse_arg('--modules', action='store_true'),
22
+ argparse_arg('roots', nargs='*'),
23
+ )
24
+ def find(self) -> None:
25
+ style = {
26
+ 'py': PY_MAGIC_STYLE,
27
+ 'c': C_MAGIC_STYLE,
28
+ }[self.args.style]
29
+
30
+ kw: dict = dict(
31
+ roots=self.args.roots,
32
+ style=style,
33
+ keys=self.args.keys,
34
+ )
35
+
36
+ fn: ta.Callable
37
+ if self.args.modules:
38
+ fn = find_magic_py_modules
39
+ else:
40
+ fn = find_magic_files
41
+
42
+ for out in fn(**kw):
43
+ print(out)
44
+
45
+
46
+ ##
47
+
48
+
49
+ def _main(argv=None) -> None:
50
+ MagicCli(argv).cli_run_and_exit()
51
+
52
+
53
+ if __name__ == '__main__':
54
+ _main()
omdev/magic/find.py CHANGED
@@ -7,7 +7,6 @@ import typing as ta
7
7
  from .magic import Magic
8
8
  from .prepare import MagicPrepareError
9
9
  from .prepare import py_compile_magic_preparer
10
- from .styles import C_MAGIC_STYLE
11
10
  from .styles import PY_MAGIC_STYLE
12
11
  from .styles import MagicStyle
13
12
 
@@ -222,47 +221,3 @@ def find_magic_py_modules(
222
221
  yield fp[:-3].replace(os.sep, '.')
223
222
  else:
224
223
  yield fp
225
-
226
-
227
- ##
228
-
229
-
230
- # @omlish-manifest
231
- _CLI_MODULE = {'$omdev.cli.types.CliModule': {
232
- 'cmd_name': 'py/findmagic',
233
- 'mod_name': __name__,
234
- }}
235
-
236
-
237
- if __name__ == '__main__':
238
- def _main(argv=None) -> None:
239
- import argparse
240
-
241
- arg_parser = argparse.ArgumentParser()
242
- arg_parser.add_argument('--style', '-s', default='py')
243
- arg_parser.add_argument('--key', '-k', dest='keys', action='append')
244
- arg_parser.add_argument('--modules', action='store_true')
245
- arg_parser.add_argument('roots', nargs='*')
246
- args = arg_parser.parse_args(argv)
247
-
248
- style = {
249
- 'py': PY_MAGIC_STYLE,
250
- 'c': C_MAGIC_STYLE,
251
- }[args.style]
252
-
253
- kw: dict = dict(
254
- roots=args.roots,
255
- style=style,
256
- keys=args.keys,
257
- )
258
-
259
- fn: ta.Callable
260
- if args.modules:
261
- fn = find_magic_py_modules
262
- else:
263
- fn = find_magic_files
264
-
265
- for out in fn(**kw):
266
- print(out)
267
-
268
- _main()
omdev/pycharm/cli.py CHANGED
@@ -77,11 +77,11 @@ def parse_wmctrl_lxp_line(l: str) -> WmctrlLine:
77
77
 
78
78
 
79
79
  class Cli(ap.Cli):
80
- @ap.command()
80
+ @ap.cmd()
81
81
  def version(self) -> None:
82
82
  print(get_pycharm_version())
83
83
 
84
- @ap.command(
84
+ @ap.cmd(
85
85
  ap.arg('python-exe'),
86
86
  ap.arg('args', nargs=ap.REMAINDER),
87
87
  )
@@ -99,7 +99,7 @@ class Cli(ap.Cli):
99
99
  proc = subprocess.run([exe, src_file, *self.args.args], check=False)
100
100
  return proc.returncode
101
101
 
102
- @ap.command(
102
+ @ap.cmd(
103
103
  ap.arg('dir', nargs='?'),
104
104
  ap.arg('--clion', action='store_true'),
105
105
  )
omdev/pyproject/cli.py CHANGED
@@ -35,7 +35,7 @@ import typing as ta
35
35
 
36
36
  from omlish.argparse.cli import ArgparseCli
37
37
  from omlish.argparse.cli import argparse_arg
38
- from omlish.argparse.cli import argparse_command
38
+ from omlish.argparse.cli import argparse_cmd
39
39
  from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
40
40
  from omlish.lite.cached import cached_nullary
41
41
  from omlish.lite.check import check
@@ -141,7 +141,7 @@ class Run:
141
141
  class PyprojectCli(ArgparseCli):
142
142
  _docker_container = argparse_arg('--_docker_container', help=argparse.SUPPRESS)
143
143
 
144
- @argparse_command(
144
+ @argparse_cmd(
145
145
  argparse_arg('name'),
146
146
  argparse_arg('-e', '--docker-env', action='append'),
147
147
  argparse_arg('cmd', nargs='?'),
@@ -223,7 +223,7 @@ class PyprojectCli(ArgparseCli):
223
223
  else:
224
224
  raise Exception(f'unknown subcommand: {cmd}')
225
225
 
226
- @argparse_command(
226
+ @argparse_cmd(
227
227
  argparse_arg('-b', '--build', action='store_true'),
228
228
  argparse_arg('-r', '--revision', action='store_true'),
229
229
  argparse_arg('-j', '--jobs', type=int),
@@ -4,15 +4,14 @@ import typing as ta
4
4
 
5
5
  from omlish.lite.marshal import unmarshal_obj
6
6
 
7
+ from ..interp.venvs import InterpVenvConfig
8
+
7
9
 
8
10
  @dc.dataclass(frozen=True)
9
- class VenvConfig:
11
+ class VenvConfig(InterpVenvConfig):
10
12
  inherits: ta.Optional[ta.Sequence[str]] = None
11
- interp: ta.Optional[str] = None
12
- requires: ta.Optional[ta.List[str]] = None
13
13
  docker: ta.Optional[str] = None
14
14
  srcs: ta.Optional[ta.List[str]] = None
15
- use_uv: ta.Optional[bool] = None
16
15
 
17
16
 
18
17
  @dc.dataclass(frozen=True)
@@ -0,0 +1,12 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import typing as ta
3
+
4
+ from omlish.lite.inject import InjectorBindingOrBindings
5
+ from omlish.lite.inject import InjectorBindings
6
+ from omlish.lite.inject import inj
7
+
8
+
9
+ def bind_pyproject() -> InjectorBindings:
10
+ lst: ta.List[InjectorBindingOrBindings] = []
11
+
12
+ return inj.as_bindings(*lst)
omdev/pyproject/venvs.py CHANGED
@@ -3,14 +3,12 @@ import glob
3
3
  import os.path
4
4
  import typing as ta
5
5
 
6
- from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
7
6
  from omlish.lite.cached import async_cached_nullary
8
7
  from omlish.lite.cached import cached_nullary
9
- from omlish.lite.check import check
10
8
  from omlish.lite.logs import log
11
9
 
12
- from ..interp.default import get_default_interp_resolver
13
- from ..interp.types import InterpSpecifier
10
+ from ..interp.venvs import InterpVenv
11
+ from ..interp.venvs import InterpVenvRequirementsProcessor
14
12
  from .configs import VenvConfig
15
13
  from .reqs import RequirementsRewriter
16
14
 
@@ -38,60 +36,26 @@ class Venv:
38
36
  def dir_name(self) -> str:
39
37
  return os.path.join(self.DIR_NAME, self._name)
40
38
 
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 get_default_interp_resolver().resolve(i, install=True)).exe
39
+ @cached_nullary
40
+ def _iv(self) -> InterpVenv:
41
+ rr = RequirementsRewriter(self._name)
42
+
43
+ return InterpVenv(
44
+ self.dir_name,
45
+ self._cfg,
46
+ requirements_processor=InterpVenvRequirementsProcessor(
47
+ lambda iv, reqs: [rr.rewrite(req) for req in reqs] # noqa
48
+ ),
49
+ log=log,
50
+ )
45
51
 
46
52
  @cached_nullary
47
53
  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
54
+ return self._iv().exe()
52
55
 
53
56
  @async_cached_nullary
54
57
  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_subprocesses.check_call(ie, '-m', 'venv', dn)
62
-
63
- ve = self.exe()
64
- uv = self._cfg.use_uv
65
-
66
- await asyncio_subprocesses.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_subprocesses.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
58
+ return await self._iv().create()
95
59
 
96
60
  @staticmethod
97
61
  def _resolve_srcs(raw: ta.List[str]) -> ta.List[str]: