omdev 0.0.0.dev223__py3-none-any.whl → 0.0.0.dev225__py3-none-any.whl

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.
omdev/scripts/interp.py CHANGED
@@ -87,7 +87,7 @@ InjectorProviderFn = ta.Callable[['Injector'], ta.Any]
87
87
  InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn']
88
88
  InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
89
89
 
90
- # ../../omlish/subprocesses.py
90
+ # ../../omlish/subprocesses/base.py
91
91
  SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
92
92
 
93
93
 
@@ -3369,6 +3369,98 @@ class JsonLogFormatter(logging.Formatter):
3369
3369
  return self._json_dumps(dct)
3370
3370
 
3371
3371
 
3372
+ ########################################
3373
+ # ../../../omlish/subprocesses/run.py
3374
+
3375
+
3376
+ ##
3377
+
3378
+
3379
+ @dc.dataclass(frozen=True)
3380
+ class SubprocessRunOutput(ta.Generic[T]):
3381
+ proc: T
3382
+
3383
+ returncode: int # noqa
3384
+
3385
+ stdout: ta.Optional[bytes] = None
3386
+ stderr: ta.Optional[bytes] = None
3387
+
3388
+
3389
+ ##
3390
+
3391
+
3392
+ @dc.dataclass(frozen=True)
3393
+ class SubprocessRun:
3394
+ cmd: ta.Sequence[str]
3395
+ input: ta.Any = None
3396
+ timeout: ta.Optional[float] = None
3397
+ check: bool = False
3398
+ capture_output: ta.Optional[bool] = None
3399
+ kwargs: ta.Optional[ta.Mapping[str, ta.Any]] = None
3400
+
3401
+ @classmethod
3402
+ def of(
3403
+ cls,
3404
+ *cmd: str,
3405
+ input: ta.Any = None, # noqa
3406
+ timeout: ta.Optional[float] = None,
3407
+ check: bool = False, # noqa
3408
+ capture_output: ta.Optional[bool] = None,
3409
+ **kwargs: ta.Any,
3410
+ ) -> 'SubprocessRun':
3411
+ return cls(
3412
+ cmd=cmd,
3413
+ input=input,
3414
+ timeout=timeout,
3415
+ check=check,
3416
+ capture_output=capture_output,
3417
+ kwargs=kwargs,
3418
+ )
3419
+
3420
+ #
3421
+
3422
+ _DEFAULT_SUBPROCESSES: ta.ClassVar[ta.Optional[ta.Any]] = None # AbstractSubprocesses
3423
+
3424
+ def run(
3425
+ self,
3426
+ subprocesses: ta.Optional[ta.Any] = None, # AbstractSubprocesses
3427
+ ) -> SubprocessRunOutput:
3428
+ if subprocesses is None:
3429
+ subprocesses = self._DEFAULT_SUBPROCESSES
3430
+ return check.not_none(subprocesses).run_(self) # type: ignore[attr-defined]
3431
+
3432
+ _DEFAULT_ASYNC_SUBPROCESSES: ta.ClassVar[ta.Optional[ta.Any]] = None # AbstractAsyncSubprocesses
3433
+
3434
+ async def async_run(
3435
+ self,
3436
+ async_subprocesses: ta.Optional[ta.Any] = None, # AbstractAsyncSubprocesses
3437
+ ) -> SubprocessRunOutput:
3438
+ if async_subprocesses is None:
3439
+ async_subprocesses = self._DEFAULT_ASYNC_SUBPROCESSES
3440
+ return await check.not_none(async_subprocesses).run_(self) # type: ignore[attr-defined]
3441
+
3442
+
3443
+ ##
3444
+
3445
+
3446
+ class SubprocessRunnable(abc.ABC, ta.Generic[T]):
3447
+ @abc.abstractmethod
3448
+ def make_run(self) -> SubprocessRun:
3449
+ raise NotImplementedError
3450
+
3451
+ @abc.abstractmethod
3452
+ def handle_run_output(self, output: SubprocessRunOutput) -> T:
3453
+ raise NotImplementedError
3454
+
3455
+ #
3456
+
3457
+ def run(self, subprocesses: ta.Optional[ta.Any] = None) -> T: # AbstractSubprocesses
3458
+ return self.handle_run_output(self.make_run().run(subprocesses))
3459
+
3460
+ async def async_run(self, async_subprocesses: ta.Optional[ta.Any] = None) -> T: # AbstractAsyncSubprocesses
3461
+ return self.handle_run_output(await self.make_run().async_run(async_subprocesses))
3462
+
3463
+
3372
3464
  ########################################
3373
3465
  # ../types.py
3374
3466
 
@@ -3607,23 +3699,7 @@ def configure_standard_logging(
3607
3699
 
3608
3700
 
3609
3701
  ########################################
3610
- # ../../../omlish/subprocesses.py
3611
-
3612
-
3613
- ##
3614
-
3615
-
3616
- # Valid channel type kwarg values:
3617
- # - A special flag negative int
3618
- # - A positive fd int
3619
- # - A file-like object
3620
- # - None
3621
-
3622
- SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
3623
- 'pipe': subprocess.PIPE,
3624
- 'stdout': subprocess.STDOUT,
3625
- 'devnull': subprocess.DEVNULL,
3626
- }
3702
+ # ../../../omlish/subprocesses/wrap.py
3627
3703
 
3628
3704
 
3629
3705
  ##
@@ -3643,22 +3719,68 @@ def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
3643
3719
  return cmd
3644
3720
 
3645
3721
 
3722
+ ########################################
3723
+ # ../providers/base.py
3724
+ """
3725
+ TODO:
3726
+ - backends
3727
+ - local builds
3728
+ - deadsnakes?
3729
+ - uv
3730
+ - loose versions
3731
+ """
3732
+
3733
+
3646
3734
  ##
3647
3735
 
3648
3736
 
3649
- def subprocess_close(
3650
- proc: subprocess.Popen,
3651
- timeout: ta.Optional[float] = None,
3652
- ) -> None:
3653
- # TODO: terminate, sleep, kill
3654
- if proc.stdout:
3655
- proc.stdout.close()
3656
- if proc.stderr:
3657
- proc.stderr.close()
3658
- if proc.stdin:
3659
- proc.stdin.close()
3737
+ class InterpProvider(abc.ABC):
3738
+ name: ta.ClassVar[str]
3739
+
3740
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
3741
+ super().__init_subclass__(**kwargs)
3742
+ if abc.ABC not in cls.__bases__ and 'name' not in cls.__dict__:
3743
+ sfx = 'InterpProvider'
3744
+ if not cls.__name__.endswith(sfx):
3745
+ raise NameError(cls)
3746
+ setattr(cls, 'name', snake_case(cls.__name__[:-len(sfx)]))
3747
+
3748
+ @abc.abstractmethod
3749
+ def get_installed_versions(self, spec: InterpSpecifier) -> ta.Awaitable[ta.Sequence[InterpVersion]]:
3750
+ raise NotImplementedError
3751
+
3752
+ @abc.abstractmethod
3753
+ def get_installed_version(self, version: InterpVersion) -> ta.Awaitable[Interp]:
3754
+ raise NotImplementedError
3755
+
3756
+ async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
3757
+ return []
3758
+
3759
+ async def install_version(self, version: InterpVersion) -> Interp:
3760
+ raise TypeError
3761
+
3762
+
3763
+ InterpProviders = ta.NewType('InterpProviders', ta.Sequence[InterpProvider])
3764
+
3765
+
3766
+ ########################################
3767
+ # ../../../omlish/subprocesses/base.py
3768
+
3769
+
3770
+ ##
3771
+
3772
+
3773
+ # Valid channel type kwarg values:
3774
+ # - A special flag negative int
3775
+ # - A positive fd int
3776
+ # - A file-like object
3777
+ # - None
3660
3778
 
3661
- proc.wait(timeout)
3779
+ SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
3780
+ 'pipe': subprocess.PIPE,
3781
+ 'stdout': subprocess.STDOUT,
3782
+ 'devnull': subprocess.DEVNULL,
3783
+ }
3662
3784
 
3663
3785
 
3664
3786
  ##
@@ -3845,155 +3967,96 @@ class BaseSubprocesses(abc.ABC): # noqa
3845
3967
  return e
3846
3968
 
3847
3969
 
3848
- ##
3849
-
3850
-
3851
- @dc.dataclass(frozen=True)
3852
- class SubprocessRun:
3853
- cmd: ta.Sequence[str]
3854
- input: ta.Any = None
3855
- timeout: ta.Optional[float] = None
3856
- check: bool = False
3857
- capture_output: ta.Optional[bool] = None
3858
- kwargs: ta.Optional[ta.Mapping[str, ta.Any]] = None
3970
+ ########################################
3971
+ # ../resolvers.py
3859
3972
 
3860
3973
 
3861
3974
  @dc.dataclass(frozen=True)
3862
- class SubprocessRunOutput(ta.Generic[T]):
3863
- proc: T
3864
-
3865
- returncode: int # noqa
3866
-
3867
- stdout: ta.Optional[bytes] = None
3868
- stderr: ta.Optional[bytes] = None
3869
-
3870
-
3871
- class AbstractSubprocesses(BaseSubprocesses, abc.ABC):
3872
- @abc.abstractmethod
3873
- def run_(self, run: SubprocessRun) -> SubprocessRunOutput:
3874
- raise NotImplementedError
3875
-
3876
- def run(
3877
- self,
3878
- *cmd: str,
3879
- input: ta.Any = None, # noqa
3880
- timeout: ta.Optional[float] = None,
3881
- check: bool = False,
3882
- capture_output: ta.Optional[bool] = None,
3883
- **kwargs: ta.Any,
3884
- ) -> SubprocessRunOutput:
3885
- return self.run_(SubprocessRun(
3886
- cmd=cmd,
3887
- input=input,
3888
- timeout=timeout,
3889
- check=check,
3890
- capture_output=capture_output,
3891
- kwargs=kwargs,
3892
- ))
3975
+ class InterpResolverProviders:
3976
+ providers: ta.Sequence[ta.Tuple[str, InterpProvider]]
3893
3977
 
3894
- #
3895
3978
 
3896
- @abc.abstractmethod
3897
- def check_call(
3979
+ class InterpResolver:
3980
+ def __init__(
3898
3981
  self,
3899
- *cmd: str,
3900
- stdout: ta.Any = sys.stderr,
3901
- **kwargs: ta.Any,
3982
+ providers: InterpResolverProviders,
3902
3983
  ) -> None:
3903
- raise NotImplementedError
3904
-
3905
- @abc.abstractmethod
3906
- def check_output(
3907
- self,
3908
- *cmd: str,
3909
- **kwargs: ta.Any,
3910
- ) -> bytes:
3911
- raise NotImplementedError
3984
+ super().__init__()
3912
3985
 
3913
- #
3986
+ self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers.providers)
3914
3987
 
3915
- def check_output_str(
3916
- self,
3917
- *cmd: str,
3918
- **kwargs: ta.Any,
3919
- ) -> str:
3920
- return self.check_output(*cmd, **kwargs).decode().strip()
3988
+ async def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
3989
+ lst = [
3990
+ (i, si)
3991
+ for i, p in enumerate(self._providers.values())
3992
+ for si in await p.get_installed_versions(spec)
3993
+ if spec.contains(si)
3994
+ ]
3921
3995
 
3922
- #
3996
+ slst = sorted(lst, key=lambda t: (-t[0], t[1].version))
3997
+ if not slst:
3998
+ return None
3923
3999
 
3924
- def try_call(
3925
- self,
3926
- *cmd: str,
3927
- **kwargs: ta.Any,
3928
- ) -> bool:
3929
- if isinstance(self.try_fn(self.check_call, *cmd, **kwargs), Exception):
3930
- return False
3931
- else:
3932
- return True
4000
+ bi, bv = slst[-1]
4001
+ bp = list(self._providers.values())[bi]
4002
+ return (bp, bv)
3933
4003
 
3934
- def try_output(
4004
+ async def resolve(
3935
4005
  self,
3936
- *cmd: str,
3937
- **kwargs: ta.Any,
3938
- ) -> ta.Optional[bytes]:
3939
- if isinstance(ret := self.try_fn(self.check_output, *cmd, **kwargs), Exception):
3940
- return None
3941
- else:
3942
- return ret
4006
+ spec: InterpSpecifier,
4007
+ *,
4008
+ install: bool = False,
4009
+ ) -> ta.Optional[Interp]:
4010
+ tup = await self._resolve_installed(spec)
4011
+ if tup is not None:
4012
+ bp, bv = tup
4013
+ return await bp.get_installed_version(bv)
3943
4014
 
3944
- def try_output_str(
3945
- self,
3946
- *cmd: str,
3947
- **kwargs: ta.Any,
3948
- ) -> ta.Optional[str]:
3949
- if (ret := self.try_output(*cmd, **kwargs)) is None:
4015
+ if not install:
3950
4016
  return None
3951
- else:
3952
- return ret.decode().strip()
3953
-
3954
-
3955
- ##
3956
4017
 
4018
+ tp = list(self._providers.values())[0] # noqa
3957
4019
 
3958
- class Subprocesses(AbstractSubprocesses):
3959
- def run_(self, run: SubprocessRun) -> SubprocessRunOutput[subprocess.CompletedProcess]:
3960
- proc = subprocess.run(
3961
- run.cmd,
3962
- input=run.input,
3963
- timeout=run.timeout,
3964
- check=run.check,
3965
- capture_output=run.capture_output or False,
3966
- **(run.kwargs or {}),
4020
+ sv = sorted(
4021
+ [s for s in await tp.get_installable_versions(spec) if s in spec],
4022
+ key=lambda s: s.version,
3967
4023
  )
4024
+ if not sv:
4025
+ return None
3968
4026
 
3969
- return SubprocessRunOutput(
3970
- proc=proc,
3971
-
3972
- returncode=proc.returncode,
4027
+ bv = sv[-1]
4028
+ return await tp.install_version(bv)
3973
4029
 
3974
- stdout=proc.stdout, # noqa
3975
- stderr=proc.stderr, # noqa
3976
- )
4030
+ async def list(self, spec: InterpSpecifier) -> None:
4031
+ print('installed:')
4032
+ for n, p in self._providers.items():
4033
+ lst = [
4034
+ si
4035
+ for si in await p.get_installed_versions(spec)
4036
+ if spec.contains(si)
4037
+ ]
4038
+ if lst:
4039
+ print(f' {n}')
4040
+ for si in lst:
4041
+ print(f' {si}')
3977
4042
 
3978
- def check_call(
3979
- self,
3980
- *cmd: str,
3981
- stdout: ta.Any = sys.stderr,
3982
- **kwargs: ta.Any,
3983
- ) -> None:
3984
- with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs): # noqa
3985
- subprocess.check_call(cmd, **kwargs)
4043
+ print()
3986
4044
 
3987
- def check_output(
3988
- self,
3989
- *cmd: str,
3990
- **kwargs: ta.Any,
3991
- ) -> bytes:
3992
- with self.prepare_and_wrap(*cmd, **kwargs) as (cmd, kwargs): # noqa
3993
- return subprocess.check_output(cmd, **kwargs)
4045
+ print('installable:')
4046
+ for n, p in self._providers.items():
4047
+ lst = [
4048
+ si
4049
+ for si in await p.get_installable_versions(spec)
4050
+ if spec.contains(si)
4051
+ ]
4052
+ if lst:
4053
+ print(f' {n}')
4054
+ for si in lst:
4055
+ print(f' {si}')
3994
4056
 
3995
4057
 
3996
- subprocesses = Subprocesses()
4058
+ ########################################
4059
+ # ../../../omlish/subprocesses/async_.py
3997
4060
 
3998
4061
 
3999
4062
  ##
@@ -4083,50 +4146,6 @@ class AbstractAsyncSubprocesses(BaseSubprocesses):
4083
4146
  return ret.decode().strip()
4084
4147
 
4085
4148
 
4086
- ########################################
4087
- # ../providers/base.py
4088
- """
4089
- TODO:
4090
- - backends
4091
- - local builds
4092
- - deadsnakes?
4093
- - uv
4094
- - loose versions
4095
- """
4096
-
4097
-
4098
- ##
4099
-
4100
-
4101
- class InterpProvider(abc.ABC):
4102
- name: ta.ClassVar[str]
4103
-
4104
- def __init_subclass__(cls, **kwargs: ta.Any) -> None:
4105
- super().__init_subclass__(**kwargs)
4106
- if abc.ABC not in cls.__bases__ and 'name' not in cls.__dict__:
4107
- sfx = 'InterpProvider'
4108
- if not cls.__name__.endswith(sfx):
4109
- raise NameError(cls)
4110
- setattr(cls, 'name', snake_case(cls.__name__[:-len(sfx)]))
4111
-
4112
- @abc.abstractmethod
4113
- def get_installed_versions(self, spec: InterpSpecifier) -> ta.Awaitable[ta.Sequence[InterpVersion]]:
4114
- raise NotImplementedError
4115
-
4116
- @abc.abstractmethod
4117
- def get_installed_version(self, version: InterpVersion) -> ta.Awaitable[Interp]:
4118
- raise NotImplementedError
4119
-
4120
- async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
4121
- return []
4122
-
4123
- async def install_version(self, version: InterpVersion) -> Interp:
4124
- raise TypeError
4125
-
4126
-
4127
- InterpProviders = ta.NewType('InterpProviders', ta.Sequence[InterpProvider])
4128
-
4129
-
4130
4149
  ########################################
4131
4150
  # ../../../omlish/asyncs/asyncio/subprocesses.py
4132
4151
 
@@ -4269,19 +4288,19 @@ class AsyncioSubprocesses(AbstractAsyncSubprocesses):
4269
4288
  timeout: ta.Optional[float] = None,
4270
4289
  **kwargs: ta.Any,
4271
4290
  ) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
4272
- fac: ta.Any
4273
- if shell:
4274
- fac = functools.partial(
4275
- asyncio.create_subprocess_shell,
4276
- check.single(cmd),
4277
- )
4278
- else:
4279
- fac = functools.partial(
4280
- asyncio.create_subprocess_exec,
4281
- *cmd,
4282
- )
4283
-
4284
4291
  with self.prepare_and_wrap( *cmd, shell=shell, **kwargs) as (cmd, kwargs): # noqa
4292
+ fac: ta.Any
4293
+ if shell:
4294
+ fac = functools.partial(
4295
+ asyncio.create_subprocess_shell,
4296
+ check.single(cmd),
4297
+ )
4298
+ else:
4299
+ fac = functools.partial(
4300
+ asyncio.create_subprocess_exec,
4301
+ *cmd,
4302
+ )
4303
+
4285
4304
  proc: asyncio.subprocess.Process = await fac(**kwargs)
4286
4305
  try:
4287
4306
  yield proc
@@ -4522,94 +4541,6 @@ class Pyenv:
4522
4541
  return True
4523
4542
 
4524
4543
 
4525
- ########################################
4526
- # ../resolvers.py
4527
-
4528
-
4529
- @dc.dataclass(frozen=True)
4530
- class InterpResolverProviders:
4531
- providers: ta.Sequence[ta.Tuple[str, InterpProvider]]
4532
-
4533
-
4534
- class InterpResolver:
4535
- def __init__(
4536
- self,
4537
- providers: InterpResolverProviders,
4538
- ) -> None:
4539
- super().__init__()
4540
-
4541
- self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers.providers)
4542
-
4543
- async def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
4544
- lst = [
4545
- (i, si)
4546
- for i, p in enumerate(self._providers.values())
4547
- for si in await p.get_installed_versions(spec)
4548
- if spec.contains(si)
4549
- ]
4550
-
4551
- slst = sorted(lst, key=lambda t: (-t[0], t[1].version))
4552
- if not slst:
4553
- return None
4554
-
4555
- bi, bv = slst[-1]
4556
- bp = list(self._providers.values())[bi]
4557
- return (bp, bv)
4558
-
4559
- async def resolve(
4560
- self,
4561
- spec: InterpSpecifier,
4562
- *,
4563
- install: bool = False,
4564
- ) -> ta.Optional[Interp]:
4565
- tup = await self._resolve_installed(spec)
4566
- if tup is not None:
4567
- bp, bv = tup
4568
- return await bp.get_installed_version(bv)
4569
-
4570
- if not install:
4571
- return None
4572
-
4573
- tp = list(self._providers.values())[0] # noqa
4574
-
4575
- sv = sorted(
4576
- [s for s in await tp.get_installable_versions(spec) if s in spec],
4577
- key=lambda s: s.version,
4578
- )
4579
- if not sv:
4580
- return None
4581
-
4582
- bv = sv[-1]
4583
- return await tp.install_version(bv)
4584
-
4585
- async def list(self, spec: InterpSpecifier) -> None:
4586
- print('installed:')
4587
- for n, p in self._providers.items():
4588
- lst = [
4589
- si
4590
- for si in await p.get_installed_versions(spec)
4591
- if spec.contains(si)
4592
- ]
4593
- if lst:
4594
- print(f' {n}')
4595
- for si in lst:
4596
- print(f' {si}')
4597
-
4598
- print()
4599
-
4600
- print('installable:')
4601
- for n, p in self._providers.items():
4602
- lst = [
4603
- si
4604
- for si in await p.get_installable_versions(spec)
4605
- if spec.contains(si)
4606
- ]
4607
- if lst:
4608
- print(f' {n}')
4609
- for si in lst:
4610
- print(f' {si}')
4611
-
4612
-
4613
4544
  ########################################
4614
4545
  # ../providers/running.py
4615
4546