omdev 0.0.0.dev224__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/amalg/typing.py +7 -1
- omdev/ci/requirements.py +1 -1
- omdev/git/revisions.py +2 -2
- omdev/git/shallow.py +1 -1
- omdev/git/status.py +1 -1
- omdev/precheck/lite.py +1 -1
- omdev/pyproject/pkg.py +1 -1
- omdev/scripts/ci.py +324 -271
- omdev/scripts/interp.py +230 -318
- omdev/scripts/pyproject.py +349 -296
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev225.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev225.dist-info}/RECORD +16 -16
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev225.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev225.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev225.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev224.dist-info → omdev-0.0.0.dev225.dist-info}/top_level.txt +0 -0
    
        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 | 
            -
             | 
| 3650 | 
            -
             | 
| 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]
         | 
| 3660 3739 |  | 
| 3661 | 
            -
                 | 
| 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
         | 
| 3778 | 
            +
             | 
| 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,174 +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
         | 
| 3859 | 
            -
             | 
| 3860 | 
            -
                @classmethod
         | 
| 3861 | 
            -
                def of(
         | 
| 3862 | 
            -
                        cls,
         | 
| 3863 | 
            -
                        *cmd: str,
         | 
| 3864 | 
            -
                        input: ta.Any = None,  # noqa
         | 
| 3865 | 
            -
                        timeout: ta.Optional[float] = None,
         | 
| 3866 | 
            -
                        check: bool = False,
         | 
| 3867 | 
            -
                        capture_output: ta.Optional[bool] = None,
         | 
| 3868 | 
            -
                        **kwargs: ta.Any,
         | 
| 3869 | 
            -
                ) -> 'SubprocessRun':
         | 
| 3870 | 
            -
                    return cls(
         | 
| 3871 | 
            -
                        cmd=cmd,
         | 
| 3872 | 
            -
                        input=input,
         | 
| 3873 | 
            -
                        timeout=timeout,
         | 
| 3874 | 
            -
                        check=check,
         | 
| 3875 | 
            -
                        capture_output=capture_output,
         | 
| 3876 | 
            -
                        kwargs=kwargs,
         | 
| 3877 | 
            -
                    )
         | 
| 3970 | 
            +
            ########################################
         | 
| 3971 | 
            +
            # ../resolvers.py
         | 
| 3878 3972 |  | 
| 3879 3973 |  | 
| 3880 3974 | 
             
            @dc.dataclass(frozen=True)
         | 
| 3881 | 
            -
            class  | 
| 3882 | 
            -
                 | 
| 3883 | 
            -
             | 
| 3884 | 
            -
                returncode: int  # noqa
         | 
| 3885 | 
            -
             | 
| 3886 | 
            -
                stdout: ta.Optional[bytes] = None
         | 
| 3887 | 
            -
                stderr: ta.Optional[bytes] = None
         | 
| 3888 | 
            -
             | 
| 3889 | 
            -
             | 
| 3890 | 
            -
            class AbstractSubprocesses(BaseSubprocesses, abc.ABC):
         | 
| 3891 | 
            -
                @abc.abstractmethod
         | 
| 3892 | 
            -
                def run_(self, run: SubprocessRun) -> SubprocessRunOutput:
         | 
| 3893 | 
            -
                    raise NotImplementedError
         | 
| 3894 | 
            -
             | 
| 3895 | 
            -
                def run(
         | 
| 3896 | 
            -
                        self,
         | 
| 3897 | 
            -
                        *cmd: str,
         | 
| 3898 | 
            -
                        input: ta.Any = None,  # noqa
         | 
| 3899 | 
            -
                        timeout: ta.Optional[float] = None,
         | 
| 3900 | 
            -
                        check: bool = False,
         | 
| 3901 | 
            -
                        capture_output: ta.Optional[bool] = None,
         | 
| 3902 | 
            -
                        **kwargs: ta.Any,
         | 
| 3903 | 
            -
                ) -> SubprocessRunOutput:
         | 
| 3904 | 
            -
                    return self.run_(SubprocessRun(
         | 
| 3905 | 
            -
                        cmd=cmd,
         | 
| 3906 | 
            -
                        input=input,
         | 
| 3907 | 
            -
                        timeout=timeout,
         | 
| 3908 | 
            -
                        check=check,
         | 
| 3909 | 
            -
                        capture_output=capture_output,
         | 
| 3910 | 
            -
                        kwargs=kwargs,
         | 
| 3911 | 
            -
                    ))
         | 
| 3975 | 
            +
            class InterpResolverProviders:
         | 
| 3976 | 
            +
                providers: ta.Sequence[ta.Tuple[str, InterpProvider]]
         | 
| 3912 3977 |  | 
| 3913 | 
            -
                #
         | 
| 3914 3978 |  | 
| 3915 | 
            -
             | 
| 3916 | 
            -
                def  | 
| 3979 | 
            +
            class InterpResolver:
         | 
| 3980 | 
            +
                def __init__(
         | 
| 3917 3981 | 
             
                        self,
         | 
| 3918 | 
            -
                         | 
| 3919 | 
            -
                        stdout: ta.Any = sys.stderr,
         | 
| 3920 | 
            -
                        **kwargs: ta.Any,
         | 
| 3982 | 
            +
                        providers: InterpResolverProviders,
         | 
| 3921 3983 | 
             
                ) -> None:
         | 
| 3922 | 
            -
                     | 
| 3923 | 
            -
             | 
| 3924 | 
            -
                @abc.abstractmethod
         | 
| 3925 | 
            -
                def check_output(
         | 
| 3926 | 
            -
                        self,
         | 
| 3927 | 
            -
                        *cmd: str,
         | 
| 3928 | 
            -
                        **kwargs: ta.Any,
         | 
| 3929 | 
            -
                ) -> bytes:
         | 
| 3930 | 
            -
                    raise NotImplementedError
         | 
| 3984 | 
            +
                    super().__init__()
         | 
| 3931 3985 |  | 
| 3932 | 
            -
             | 
| 3986 | 
            +
                    self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers.providers)
         | 
| 3933 3987 |  | 
| 3934 | 
            -
                def  | 
| 3935 | 
            -
             | 
| 3936 | 
            -
                         | 
| 3937 | 
            -
                         | 
| 3938 | 
            -
             | 
| 3939 | 
            -
             | 
| 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 | 
            +
                    ]
         | 
| 3940 3995 |  | 
| 3941 | 
            -
             | 
| 3996 | 
            +
                    slst = sorted(lst, key=lambda t: (-t[0], t[1].version))
         | 
| 3997 | 
            +
                    if not slst:
         | 
| 3998 | 
            +
                        return None
         | 
| 3942 3999 |  | 
| 3943 | 
            -
             | 
| 3944 | 
            -
             | 
| 3945 | 
            -
             | 
| 3946 | 
            -
                        **kwargs: ta.Any,
         | 
| 3947 | 
            -
                ) -> bool:
         | 
| 3948 | 
            -
                    if isinstance(self.try_fn(self.check_call, *cmd, **kwargs), Exception):
         | 
| 3949 | 
            -
                        return False
         | 
| 3950 | 
            -
                    else:
         | 
| 3951 | 
            -
                        return True
         | 
| 4000 | 
            +
                    bi, bv = slst[-1]
         | 
| 4001 | 
            +
                    bp = list(self._providers.values())[bi]
         | 
| 4002 | 
            +
                    return (bp, bv)
         | 
| 3952 4003 |  | 
| 3953 | 
            -
                def  | 
| 4004 | 
            +
                async def resolve(
         | 
| 3954 4005 | 
             
                        self,
         | 
| 3955 | 
            -
                         | 
| 3956 | 
            -
                         | 
| 3957 | 
            -
             | 
| 3958 | 
            -
             | 
| 3959 | 
            -
             | 
| 3960 | 
            -
                     | 
| 3961 | 
            -
                         | 
| 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)
         | 
| 3962 4014 |  | 
| 3963 | 
            -
             | 
| 3964 | 
            -
                        self,
         | 
| 3965 | 
            -
                        *cmd: str,
         | 
| 3966 | 
            -
                        **kwargs: ta.Any,
         | 
| 3967 | 
            -
                ) -> ta.Optional[str]:
         | 
| 3968 | 
            -
                    if (ret := self.try_output(*cmd, **kwargs)) is None:
         | 
| 4015 | 
            +
                    if not install:
         | 
| 3969 4016 | 
             
                        return None
         | 
| 3970 | 
            -
                    else:
         | 
| 3971 | 
            -
                        return ret.decode().strip()
         | 
| 3972 | 
            -
             | 
| 3973 | 
            -
             | 
| 3974 | 
            -
            ##
         | 
| 3975 4017 |  | 
| 4018 | 
            +
                    tp = list(self._providers.values())[0]  # noqa
         | 
| 3976 4019 |  | 
| 3977 | 
            -
             | 
| 3978 | 
            -
             | 
| 3979 | 
            -
             | 
| 3980 | 
            -
                        run.cmd,
         | 
| 3981 | 
            -
                        input=run.input,
         | 
| 3982 | 
            -
                        timeout=run.timeout,
         | 
| 3983 | 
            -
                        check=run.check,
         | 
| 3984 | 
            -
                        capture_output=run.capture_output or False,
         | 
| 3985 | 
            -
                        **(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,
         | 
| 3986 4023 | 
             
                    )
         | 
| 4024 | 
            +
                    if not sv:
         | 
| 4025 | 
            +
                        return None
         | 
| 3987 4026 |  | 
| 3988 | 
            -
                     | 
| 3989 | 
            -
             | 
| 3990 | 
            -
             | 
| 3991 | 
            -
                        returncode=proc.returncode,
         | 
| 4027 | 
            +
                    bv = sv[-1]
         | 
| 4028 | 
            +
                    return await tp.install_version(bv)
         | 
| 3992 4029 |  | 
| 3993 | 
            -
             | 
| 3994 | 
            -
             | 
| 3995 | 
            -
                    )
         | 
| 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}')
         | 
| 3996 4042 |  | 
| 3997 | 
            -
             | 
| 3998 | 
            -
                        self,
         | 
| 3999 | 
            -
                        *cmd: str,
         | 
| 4000 | 
            -
                        stdout: ta.Any = sys.stderr,
         | 
| 4001 | 
            -
                        **kwargs: ta.Any,
         | 
| 4002 | 
            -
                ) -> None:
         | 
| 4003 | 
            -
                    with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs):  # noqa
         | 
| 4004 | 
            -
                        subprocess.check_call(cmd, **kwargs)
         | 
| 4043 | 
            +
                    print()
         | 
| 4005 4044 |  | 
| 4006 | 
            -
             | 
| 4007 | 
            -
             | 
| 4008 | 
            -
                         | 
| 4009 | 
            -
             | 
| 4010 | 
            -
             | 
| 4011 | 
            -
             | 
| 4012 | 
            -
                         | 
| 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}')
         | 
| 4013 4056 |  | 
| 4014 4057 |  | 
| 4015 | 
            -
             | 
| 4058 | 
            +
            ########################################
         | 
| 4059 | 
            +
            # ../../../omlish/subprocesses/async_.py
         | 
| 4016 4060 |  | 
| 4017 4061 |  | 
| 4018 4062 | 
             
            ##
         | 
| @@ -4102,50 +4146,6 @@ class AbstractAsyncSubprocesses(BaseSubprocesses): | |
| 4102 4146 | 
             
                        return ret.decode().strip()
         | 
| 4103 4147 |  | 
| 4104 4148 |  | 
| 4105 | 
            -
            ########################################
         | 
| 4106 | 
            -
            # ../providers/base.py
         | 
| 4107 | 
            -
            """
         | 
| 4108 | 
            -
            TODO:
         | 
| 4109 | 
            -
             - backends
         | 
| 4110 | 
            -
              - local builds
         | 
| 4111 | 
            -
              - deadsnakes?
         | 
| 4112 | 
            -
              - uv
         | 
| 4113 | 
            -
             - loose versions
         | 
| 4114 | 
            -
            """
         | 
| 4115 | 
            -
             | 
| 4116 | 
            -
             | 
| 4117 | 
            -
            ##
         | 
| 4118 | 
            -
             | 
| 4119 | 
            -
             | 
| 4120 | 
            -
            class InterpProvider(abc.ABC):
         | 
| 4121 | 
            -
                name: ta.ClassVar[str]
         | 
| 4122 | 
            -
             | 
| 4123 | 
            -
                def __init_subclass__(cls, **kwargs: ta.Any) -> None:
         | 
| 4124 | 
            -
                    super().__init_subclass__(**kwargs)
         | 
| 4125 | 
            -
                    if abc.ABC not in cls.__bases__ and 'name' not in cls.__dict__:
         | 
| 4126 | 
            -
                        sfx = 'InterpProvider'
         | 
| 4127 | 
            -
                        if not cls.__name__.endswith(sfx):
         | 
| 4128 | 
            -
                            raise NameError(cls)
         | 
| 4129 | 
            -
                        setattr(cls, 'name', snake_case(cls.__name__[:-len(sfx)]))
         | 
| 4130 | 
            -
             | 
| 4131 | 
            -
                @abc.abstractmethod
         | 
| 4132 | 
            -
                def get_installed_versions(self, spec: InterpSpecifier) -> ta.Awaitable[ta.Sequence[InterpVersion]]:
         | 
| 4133 | 
            -
                    raise NotImplementedError
         | 
| 4134 | 
            -
             | 
| 4135 | 
            -
                @abc.abstractmethod
         | 
| 4136 | 
            -
                def get_installed_version(self, version: InterpVersion) -> ta.Awaitable[Interp]:
         | 
| 4137 | 
            -
                    raise NotImplementedError
         | 
| 4138 | 
            -
             | 
| 4139 | 
            -
                async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
         | 
| 4140 | 
            -
                    return []
         | 
| 4141 | 
            -
             | 
| 4142 | 
            -
                async def install_version(self, version: InterpVersion) -> Interp:
         | 
| 4143 | 
            -
                    raise TypeError
         | 
| 4144 | 
            -
             | 
| 4145 | 
            -
             | 
| 4146 | 
            -
            InterpProviders = ta.NewType('InterpProviders', ta.Sequence[InterpProvider])
         | 
| 4147 | 
            -
             | 
| 4148 | 
            -
             | 
| 4149 4149 | 
             
            ########################################
         | 
| 4150 4150 | 
             
            # ../../../omlish/asyncs/asyncio/subprocesses.py
         | 
| 4151 4151 |  | 
| @@ -4288,19 +4288,19 @@ class AsyncioSubprocesses(AbstractAsyncSubprocesses): | |
| 4288 4288 | 
             
                        timeout: ta.Optional[float] = None,
         | 
| 4289 4289 | 
             
                        **kwargs: ta.Any,
         | 
| 4290 4290 | 
             
                ) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
         | 
| 4291 | 
            -
                    fac: ta.Any
         | 
| 4292 | 
            -
                    if shell:
         | 
| 4293 | 
            -
                        fac = functools.partial(
         | 
| 4294 | 
            -
                            asyncio.create_subprocess_shell,
         | 
| 4295 | 
            -
                            check.single(cmd),
         | 
| 4296 | 
            -
                        )
         | 
| 4297 | 
            -
                    else:
         | 
| 4298 | 
            -
                        fac = functools.partial(
         | 
| 4299 | 
            -
                            asyncio.create_subprocess_exec,
         | 
| 4300 | 
            -
                            *cmd,
         | 
| 4301 | 
            -
                        )
         | 
| 4302 | 
            -
             | 
| 4303 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 | 
            +
             | 
| 4304 4304 | 
             
                        proc: asyncio.subprocess.Process = await fac(**kwargs)
         | 
| 4305 4305 | 
             
                        try:
         | 
| 4306 4306 | 
             
                            yield proc
         | 
| @@ -4541,94 +4541,6 @@ class Pyenv: | |
| 4541 4541 | 
             
                    return True
         | 
| 4542 4542 |  | 
| 4543 4543 |  | 
| 4544 | 
            -
            ########################################
         | 
| 4545 | 
            -
            # ../resolvers.py
         | 
| 4546 | 
            -
             | 
| 4547 | 
            -
             | 
| 4548 | 
            -
            @dc.dataclass(frozen=True)
         | 
| 4549 | 
            -
            class InterpResolverProviders:
         | 
| 4550 | 
            -
                providers: ta.Sequence[ta.Tuple[str, InterpProvider]]
         | 
| 4551 | 
            -
             | 
| 4552 | 
            -
             | 
| 4553 | 
            -
            class InterpResolver:
         | 
| 4554 | 
            -
                def __init__(
         | 
| 4555 | 
            -
                        self,
         | 
| 4556 | 
            -
                        providers: InterpResolverProviders,
         | 
| 4557 | 
            -
                ) -> None:
         | 
| 4558 | 
            -
                    super().__init__()
         | 
| 4559 | 
            -
             | 
| 4560 | 
            -
                    self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers.providers)
         | 
| 4561 | 
            -
             | 
| 4562 | 
            -
                async def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
         | 
| 4563 | 
            -
                    lst = [
         | 
| 4564 | 
            -
                        (i, si)
         | 
| 4565 | 
            -
                        for i, p in enumerate(self._providers.values())
         | 
| 4566 | 
            -
                        for si in await p.get_installed_versions(spec)
         | 
| 4567 | 
            -
                        if spec.contains(si)
         | 
| 4568 | 
            -
                    ]
         | 
| 4569 | 
            -
             | 
| 4570 | 
            -
                    slst = sorted(lst, key=lambda t: (-t[0], t[1].version))
         | 
| 4571 | 
            -
                    if not slst:
         | 
| 4572 | 
            -
                        return None
         | 
| 4573 | 
            -
             | 
| 4574 | 
            -
                    bi, bv = slst[-1]
         | 
| 4575 | 
            -
                    bp = list(self._providers.values())[bi]
         | 
| 4576 | 
            -
                    return (bp, bv)
         | 
| 4577 | 
            -
             | 
| 4578 | 
            -
                async def resolve(
         | 
| 4579 | 
            -
                        self,
         | 
| 4580 | 
            -
                        spec: InterpSpecifier,
         | 
| 4581 | 
            -
                        *,
         | 
| 4582 | 
            -
                        install: bool = False,
         | 
| 4583 | 
            -
                ) -> ta.Optional[Interp]:
         | 
| 4584 | 
            -
                    tup = await self._resolve_installed(spec)
         | 
| 4585 | 
            -
                    if tup is not None:
         | 
| 4586 | 
            -
                        bp, bv = tup
         | 
| 4587 | 
            -
                        return await bp.get_installed_version(bv)
         | 
| 4588 | 
            -
             | 
| 4589 | 
            -
                    if not install:
         | 
| 4590 | 
            -
                        return None
         | 
| 4591 | 
            -
             | 
| 4592 | 
            -
                    tp = list(self._providers.values())[0]  # noqa
         | 
| 4593 | 
            -
             | 
| 4594 | 
            -
                    sv = sorted(
         | 
| 4595 | 
            -
                        [s for s in await tp.get_installable_versions(spec) if s in spec],
         | 
| 4596 | 
            -
                        key=lambda s: s.version,
         | 
| 4597 | 
            -
                    )
         | 
| 4598 | 
            -
                    if not sv:
         | 
| 4599 | 
            -
                        return None
         | 
| 4600 | 
            -
             | 
| 4601 | 
            -
                    bv = sv[-1]
         | 
| 4602 | 
            -
                    return await tp.install_version(bv)
         | 
| 4603 | 
            -
             | 
| 4604 | 
            -
                async def list(self, spec: InterpSpecifier) -> None:
         | 
| 4605 | 
            -
                    print('installed:')
         | 
| 4606 | 
            -
                    for n, p in self._providers.items():
         | 
| 4607 | 
            -
                        lst = [
         | 
| 4608 | 
            -
                            si
         | 
| 4609 | 
            -
                            for si in await p.get_installed_versions(spec)
         | 
| 4610 | 
            -
                            if spec.contains(si)
         | 
| 4611 | 
            -
                        ]
         | 
| 4612 | 
            -
                        if lst:
         | 
| 4613 | 
            -
                            print(f'  {n}')
         | 
| 4614 | 
            -
                            for si in lst:
         | 
| 4615 | 
            -
                                print(f'    {si}')
         | 
| 4616 | 
            -
             | 
| 4617 | 
            -
                    print()
         | 
| 4618 | 
            -
             | 
| 4619 | 
            -
                    print('installable:')
         | 
| 4620 | 
            -
                    for n, p in self._providers.items():
         | 
| 4621 | 
            -
                        lst = [
         | 
| 4622 | 
            -
                            si
         | 
| 4623 | 
            -
                            for si in await p.get_installable_versions(spec)
         | 
| 4624 | 
            -
                            if spec.contains(si)
         | 
| 4625 | 
            -
                        ]
         | 
| 4626 | 
            -
                        if lst:
         | 
| 4627 | 
            -
                            print(f'  {n}')
         | 
| 4628 | 
            -
                            for si in lst:
         | 
| 4629 | 
            -
                                print(f'    {si}')
         | 
| 4630 | 
            -
             | 
| 4631 | 
            -
             | 
| 4632 4544 | 
             
            ########################################
         | 
| 4633 4545 | 
             
            # ../providers/running.py
         | 
| 4634 4546 |  |