omdev 0.0.0.dev147__py3-none-any.whl → 0.0.0.dev149__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.
Potentially problematic release.
This version of omdev might be problematic. Click here for more details.
- omdev/.manifests.json +12 -0
- omdev/amalg/amalg.py +1 -0
- omdev/cli/clicli.py +1 -1
- omdev/imgur.py +1 -1
- omdev/interp/cli.py +11 -6
- omdev/interp/inspect.py +5 -6
- omdev/interp/providers.py +6 -6
- omdev/interp/pyenv.py +77 -78
- omdev/interp/resolvers.py +11 -10
- omdev/interp/system.py +8 -8
- omdev/interp/types.py +2 -0
- omdev/manifests/__init__.py +0 -1
- omdev/manifests/__main__.py +11 -0
- omdev/manifests/build.py +2 -76
- omdev/manifests/main.py +84 -0
- omdev/pycharm/cli.py +1 -1
- omdev/pyproject/cli.py +21 -15
- omdev/scripts/interp.py +564 -134
- omdev/scripts/pyproject.py +1404 -975
- omdev/tools/doc.py +1 -1
- omdev/tools/docker.py +1 -1
- omdev/tools/git.py +1 -1
- omdev/tools/json/parsing.py +1 -1
- omdev/tools/notebook.py +1 -1
- omdev/tools/pip.py +1 -1
- omdev/tools/prof.py +1 -1
- omdev/tools/sqlrepl.py +1 -1
- {omdev-0.0.0.dev147.dist-info → omdev-0.0.0.dev149.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev147.dist-info → omdev-0.0.0.dev149.dist-info}/RECORD +33 -31
- {omdev-0.0.0.dev147.dist-info → omdev-0.0.0.dev149.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev147.dist-info → omdev-0.0.0.dev149.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev147.dist-info → omdev-0.0.0.dev149.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev147.dist-info → omdev-0.0.0.dev149.dist-info}/top_level.txt +0 -0
omdev/scripts/interp.py
CHANGED
|
@@ -12,6 +12,9 @@ TODO:
|
|
|
12
12
|
"""
|
|
13
13
|
import abc
|
|
14
14
|
import argparse
|
|
15
|
+
import asyncio
|
|
16
|
+
import asyncio.base_subprocess
|
|
17
|
+
import asyncio.subprocess
|
|
15
18
|
import collections
|
|
16
19
|
import contextlib
|
|
17
20
|
import dataclasses as dc
|
|
@@ -29,6 +32,7 @@ import shutil
|
|
|
29
32
|
import subprocess
|
|
30
33
|
import sys
|
|
31
34
|
import threading
|
|
35
|
+
import time
|
|
32
36
|
import types
|
|
33
37
|
import typing as ta
|
|
34
38
|
|
|
@@ -51,6 +55,9 @@ VersionCmpLocalType = ta.Union['NegativeInfinityVersionType', _VersionCmpLocalTy
|
|
|
51
55
|
VersionCmpKey = ta.Tuple[int, ta.Tuple[int, ...], VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpLocalType] # noqa
|
|
52
56
|
VersionComparisonMethod = ta.Callable[[VersionCmpKey, VersionCmpKey], bool]
|
|
53
57
|
|
|
58
|
+
# ../../omlish/lite/asyncio/asyncio.py
|
|
59
|
+
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
|
60
|
+
|
|
54
61
|
# ../../omlish/lite/cached.py
|
|
55
62
|
T = ta.TypeVar('T')
|
|
56
63
|
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
|
@@ -474,11 +481,74 @@ def canonicalize_version(
|
|
|
474
481
|
return ''.join(parts)
|
|
475
482
|
|
|
476
483
|
|
|
484
|
+
########################################
|
|
485
|
+
# ../../../omlish/lite/asyncio/asyncio.py
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
##
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
ASYNCIO_DEFAULT_BUFFER_LIMIT = 2 ** 16
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
async def asyncio_open_stream_reader(
|
|
495
|
+
f: ta.IO,
|
|
496
|
+
loop: ta.Any = None,
|
|
497
|
+
*,
|
|
498
|
+
limit: int = ASYNCIO_DEFAULT_BUFFER_LIMIT,
|
|
499
|
+
) -> asyncio.StreamReader:
|
|
500
|
+
if loop is None:
|
|
501
|
+
loop = asyncio.get_running_loop()
|
|
502
|
+
|
|
503
|
+
reader = asyncio.StreamReader(limit=limit, loop=loop)
|
|
504
|
+
await loop.connect_read_pipe(
|
|
505
|
+
lambda: asyncio.StreamReaderProtocol(reader, loop=loop),
|
|
506
|
+
f,
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
return reader
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
async def asyncio_open_stream_writer(
|
|
513
|
+
f: ta.IO,
|
|
514
|
+
loop: ta.Any = None,
|
|
515
|
+
) -> asyncio.StreamWriter:
|
|
516
|
+
if loop is None:
|
|
517
|
+
loop = asyncio.get_running_loop()
|
|
518
|
+
|
|
519
|
+
writer_transport, writer_protocol = await loop.connect_write_pipe(
|
|
520
|
+
lambda: asyncio.streams.FlowControlMixin(loop=loop),
|
|
521
|
+
f,
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
return asyncio.streams.StreamWriter(
|
|
525
|
+
writer_transport,
|
|
526
|
+
writer_protocol,
|
|
527
|
+
None,
|
|
528
|
+
loop,
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
##
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def asyncio_maybe_timeout(
|
|
536
|
+
fut: AwaitableT,
|
|
537
|
+
timeout: ta.Optional[float] = None,
|
|
538
|
+
) -> AwaitableT:
|
|
539
|
+
if timeout is not None:
|
|
540
|
+
fut = asyncio.wait_for(fut, timeout) # type: ignore
|
|
541
|
+
return fut
|
|
542
|
+
|
|
543
|
+
|
|
477
544
|
########################################
|
|
478
545
|
# ../../../omlish/lite/cached.py
|
|
479
546
|
|
|
480
547
|
|
|
481
|
-
|
|
548
|
+
##
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
class _AbstractCachedNullary:
|
|
482
552
|
def __init__(self, fn):
|
|
483
553
|
super().__init__()
|
|
484
554
|
self._fn = fn
|
|
@@ -486,17 +556,25 @@ class _cached_nullary: # noqa
|
|
|
486
556
|
functools.update_wrapper(self, fn)
|
|
487
557
|
|
|
488
558
|
def __call__(self, *args, **kwargs): # noqa
|
|
489
|
-
|
|
490
|
-
self._value = self._fn()
|
|
491
|
-
return self._value
|
|
559
|
+
raise TypeError
|
|
492
560
|
|
|
493
561
|
def __get__(self, instance, owner): # noqa
|
|
494
562
|
bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
|
|
495
563
|
return bound
|
|
496
564
|
|
|
497
565
|
|
|
566
|
+
##
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
class _CachedNullary(_AbstractCachedNullary):
|
|
570
|
+
def __call__(self, *args, **kwargs): # noqa
|
|
571
|
+
if self._value is self._missing:
|
|
572
|
+
self._value = self._fn()
|
|
573
|
+
return self._value
|
|
574
|
+
|
|
575
|
+
|
|
498
576
|
def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
499
|
-
return
|
|
577
|
+
return _CachedNullary(fn)
|
|
500
578
|
|
|
501
579
|
|
|
502
580
|
def static_init(fn: CallableT) -> CallableT:
|
|
@@ -505,6 +583,20 @@ def static_init(fn: CallableT) -> CallableT:
|
|
|
505
583
|
return fn
|
|
506
584
|
|
|
507
585
|
|
|
586
|
+
##
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
class _AsyncCachedNullary(_AbstractCachedNullary):
|
|
590
|
+
async def __call__(self, *args, **kwargs):
|
|
591
|
+
if self._value is self._missing:
|
|
592
|
+
self._value = await self._fn()
|
|
593
|
+
return self._value
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
597
|
+
return _AsyncCachedNullary(fn)
|
|
598
|
+
|
|
599
|
+
|
|
508
600
|
########################################
|
|
509
601
|
# ../../../omlish/lite/check.py
|
|
510
602
|
|
|
@@ -544,6 +636,11 @@ def check_non_empty_str(v: ta.Optional[str]) -> str:
|
|
|
544
636
|
return v
|
|
545
637
|
|
|
546
638
|
|
|
639
|
+
def check_arg(v: bool, msg: str = 'Illegal argument') -> None:
|
|
640
|
+
if not v:
|
|
641
|
+
raise ValueError(msg)
|
|
642
|
+
|
|
643
|
+
|
|
547
644
|
def check_state(v: bool, msg: str = 'Illegal state') -> None:
|
|
548
645
|
if not v:
|
|
549
646
|
raise ValueError(msg)
|
|
@@ -596,7 +693,7 @@ def check_empty(v: SizedT) -> SizedT:
|
|
|
596
693
|
return v
|
|
597
694
|
|
|
598
695
|
|
|
599
|
-
def
|
|
696
|
+
def check_not_empty(v: SizedT) -> SizedT:
|
|
600
697
|
if not len(v):
|
|
601
698
|
raise ValueError(v)
|
|
602
699
|
return v
|
|
@@ -1637,6 +1734,8 @@ class InterpSpecifier:
|
|
|
1637
1734
|
s, o = InterpOpts.parse_suffix(s)
|
|
1638
1735
|
if not any(s.startswith(o) for o in Specifier.OPERATORS):
|
|
1639
1736
|
s = '~=' + s
|
|
1737
|
+
if s.count('.') < 2:
|
|
1738
|
+
s += '.0'
|
|
1640
1739
|
return cls(
|
|
1641
1740
|
specifier=Specifier(s),
|
|
1642
1741
|
opts=o,
|
|
@@ -1686,7 +1785,7 @@ def subprocess_maybe_shell_wrap_exec(*args: str) -> ta.Tuple[str, ...]:
|
|
|
1686
1785
|
return args
|
|
1687
1786
|
|
|
1688
1787
|
|
|
1689
|
-
def
|
|
1788
|
+
def prepare_subprocess_invocation(
|
|
1690
1789
|
*args: str,
|
|
1691
1790
|
env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
1692
1791
|
extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
@@ -1694,9 +1793,9 @@ def _prepare_subprocess_invocation(
|
|
|
1694
1793
|
shell: bool = False,
|
|
1695
1794
|
**kwargs: ta.Any,
|
|
1696
1795
|
) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
|
|
1697
|
-
log.debug(args)
|
|
1796
|
+
log.debug('prepare_subprocess_invocation: args=%r', args)
|
|
1698
1797
|
if extra_env:
|
|
1699
|
-
log.debug(extra_env)
|
|
1798
|
+
log.debug('prepare_subprocess_invocation: extra_env=%r', extra_env)
|
|
1700
1799
|
|
|
1701
1800
|
if extra_env:
|
|
1702
1801
|
env = {**(env if env is not None else os.environ), **extra_env}
|
|
@@ -1715,14 +1814,46 @@ def _prepare_subprocess_invocation(
|
|
|
1715
1814
|
)
|
|
1716
1815
|
|
|
1717
1816
|
|
|
1718
|
-
|
|
1719
|
-
args, kwargs = _prepare_subprocess_invocation(*args, stdout=stdout, **kwargs)
|
|
1720
|
-
return subprocess.check_call(args, **kwargs) # type: ignore
|
|
1817
|
+
##
|
|
1721
1818
|
|
|
1722
1819
|
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1820
|
+
@contextlib.contextmanager
|
|
1821
|
+
def subprocess_common_context(*args: ta.Any, **kwargs: ta.Any) -> ta.Iterator[None]:
|
|
1822
|
+
start_time = time.time()
|
|
1823
|
+
try:
|
|
1824
|
+
log.debug('subprocess_common_context.try: args=%r', args)
|
|
1825
|
+
yield
|
|
1826
|
+
|
|
1827
|
+
except Exception as exc: # noqa
|
|
1828
|
+
log.debug('subprocess_common_context.except: exc=%r', exc)
|
|
1829
|
+
raise
|
|
1830
|
+
|
|
1831
|
+
finally:
|
|
1832
|
+
end_time = time.time()
|
|
1833
|
+
elapsed_s = end_time - start_time
|
|
1834
|
+
log.debug('subprocess_common_context.finally: elapsed_s=%f args=%r', elapsed_s, args)
|
|
1835
|
+
|
|
1836
|
+
|
|
1837
|
+
##
|
|
1838
|
+
|
|
1839
|
+
|
|
1840
|
+
def subprocess_check_call(
|
|
1841
|
+
*args: str,
|
|
1842
|
+
stdout: ta.Any = sys.stderr,
|
|
1843
|
+
**kwargs: ta.Any,
|
|
1844
|
+
) -> None:
|
|
1845
|
+
args, kwargs = prepare_subprocess_invocation(*args, stdout=stdout, **kwargs)
|
|
1846
|
+
with subprocess_common_context(*args, **kwargs):
|
|
1847
|
+
return subprocess.check_call(args, **kwargs) # type: ignore
|
|
1848
|
+
|
|
1849
|
+
|
|
1850
|
+
def subprocess_check_output(
|
|
1851
|
+
*args: str,
|
|
1852
|
+
**kwargs: ta.Any,
|
|
1853
|
+
) -> bytes:
|
|
1854
|
+
args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
|
|
1855
|
+
with subprocess_common_context(*args, **kwargs):
|
|
1856
|
+
return subprocess.check_output(args, **kwargs)
|
|
1726
1857
|
|
|
1727
1858
|
|
|
1728
1859
|
def subprocess_check_output_str(*args: str, **kwargs: ta.Any) -> str:
|
|
@@ -1738,16 +1869,31 @@ DEFAULT_SUBPROCESS_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
|
|
|
1738
1869
|
)
|
|
1739
1870
|
|
|
1740
1871
|
|
|
1741
|
-
def
|
|
1742
|
-
|
|
1872
|
+
def _subprocess_try_run(
|
|
1873
|
+
fn: ta.Callable[..., T],
|
|
1874
|
+
*args: ta.Any,
|
|
1743
1875
|
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
1744
1876
|
**kwargs: ta.Any,
|
|
1745
|
-
) ->
|
|
1877
|
+
) -> ta.Union[T, Exception]:
|
|
1746
1878
|
try:
|
|
1747
|
-
|
|
1879
|
+
return fn(*args, **kwargs)
|
|
1748
1880
|
except try_exceptions as e: # noqa
|
|
1749
1881
|
if log.isEnabledFor(logging.DEBUG):
|
|
1750
1882
|
log.exception('command failed')
|
|
1883
|
+
return e
|
|
1884
|
+
|
|
1885
|
+
|
|
1886
|
+
def subprocess_try_call(
|
|
1887
|
+
*args: str,
|
|
1888
|
+
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
1889
|
+
**kwargs: ta.Any,
|
|
1890
|
+
) -> bool:
|
|
1891
|
+
if isinstance(_subprocess_try_run(
|
|
1892
|
+
subprocess_check_call,
|
|
1893
|
+
*args,
|
|
1894
|
+
try_exceptions=try_exceptions,
|
|
1895
|
+
**kwargs,
|
|
1896
|
+
), Exception):
|
|
1751
1897
|
return False
|
|
1752
1898
|
else:
|
|
1753
1899
|
return True
|
|
@@ -1758,12 +1904,15 @@ def subprocess_try_output(
|
|
|
1758
1904
|
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
1759
1905
|
**kwargs: ta.Any,
|
|
1760
1906
|
) -> ta.Optional[bytes]:
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1907
|
+
if isinstance(ret := _subprocess_try_run(
|
|
1908
|
+
subprocess_check_output,
|
|
1909
|
+
*args,
|
|
1910
|
+
try_exceptions=try_exceptions,
|
|
1911
|
+
**kwargs,
|
|
1912
|
+
), Exception):
|
|
1766
1913
|
return None
|
|
1914
|
+
else:
|
|
1915
|
+
return ret
|
|
1767
1916
|
|
|
1768
1917
|
|
|
1769
1918
|
def subprocess_try_output_str(*args: str, **kwargs: ta.Any) -> ta.Optional[str]:
|
|
@@ -1789,6 +1938,285 @@ def subprocess_close(
|
|
|
1789
1938
|
proc.wait(timeout)
|
|
1790
1939
|
|
|
1791
1940
|
|
|
1941
|
+
########################################
|
|
1942
|
+
# ../../../omlish/lite/asyncio/subprocesses.py
|
|
1943
|
+
|
|
1944
|
+
|
|
1945
|
+
##
|
|
1946
|
+
|
|
1947
|
+
|
|
1948
|
+
@contextlib.asynccontextmanager
|
|
1949
|
+
async def asyncio_subprocess_popen(
|
|
1950
|
+
*cmd: str,
|
|
1951
|
+
shell: bool = False,
|
|
1952
|
+
timeout: ta.Optional[float] = None,
|
|
1953
|
+
**kwargs: ta.Any,
|
|
1954
|
+
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
|
1955
|
+
fac: ta.Any
|
|
1956
|
+
if shell:
|
|
1957
|
+
fac = functools.partial(
|
|
1958
|
+
asyncio.create_subprocess_shell,
|
|
1959
|
+
check_single(cmd),
|
|
1960
|
+
)
|
|
1961
|
+
else:
|
|
1962
|
+
fac = functools.partial(
|
|
1963
|
+
asyncio.create_subprocess_exec,
|
|
1964
|
+
*cmd,
|
|
1965
|
+
)
|
|
1966
|
+
|
|
1967
|
+
with subprocess_common_context(
|
|
1968
|
+
*cmd,
|
|
1969
|
+
shell=shell,
|
|
1970
|
+
timeout=timeout,
|
|
1971
|
+
**kwargs,
|
|
1972
|
+
):
|
|
1973
|
+
proc: asyncio.subprocess.Process
|
|
1974
|
+
proc = await fac(**kwargs)
|
|
1975
|
+
try:
|
|
1976
|
+
yield proc
|
|
1977
|
+
|
|
1978
|
+
finally:
|
|
1979
|
+
await asyncio_maybe_timeout(proc.wait(), timeout)
|
|
1980
|
+
|
|
1981
|
+
|
|
1982
|
+
##
|
|
1983
|
+
|
|
1984
|
+
|
|
1985
|
+
class AsyncioProcessCommunicator:
|
|
1986
|
+
def __init__(
|
|
1987
|
+
self,
|
|
1988
|
+
proc: asyncio.subprocess.Process,
|
|
1989
|
+
loop: ta.Optional[ta.Any] = None,
|
|
1990
|
+
) -> None:
|
|
1991
|
+
super().__init__()
|
|
1992
|
+
|
|
1993
|
+
if loop is None:
|
|
1994
|
+
loop = asyncio.get_running_loop()
|
|
1995
|
+
|
|
1996
|
+
self._proc = proc
|
|
1997
|
+
self._loop = loop
|
|
1998
|
+
|
|
1999
|
+
self._transport: asyncio.base_subprocess.BaseSubprocessTransport = check_isinstance(
|
|
2000
|
+
proc._transport, # type: ignore # noqa
|
|
2001
|
+
asyncio.base_subprocess.BaseSubprocessTransport,
|
|
2002
|
+
)
|
|
2003
|
+
|
|
2004
|
+
@property
|
|
2005
|
+
def _debug(self) -> bool:
|
|
2006
|
+
return self._loop.get_debug()
|
|
2007
|
+
|
|
2008
|
+
async def _feed_stdin(self, input: bytes) -> None: # noqa
|
|
2009
|
+
stdin = check_not_none(self._proc.stdin)
|
|
2010
|
+
try:
|
|
2011
|
+
if input is not None:
|
|
2012
|
+
stdin.write(input)
|
|
2013
|
+
if self._debug:
|
|
2014
|
+
log.debug('%r communicate: feed stdin (%s bytes)', self, len(input))
|
|
2015
|
+
|
|
2016
|
+
await stdin.drain()
|
|
2017
|
+
|
|
2018
|
+
except (BrokenPipeError, ConnectionResetError) as exc:
|
|
2019
|
+
# communicate() ignores BrokenPipeError and ConnectionResetError. write() and drain() can raise these
|
|
2020
|
+
# exceptions.
|
|
2021
|
+
if self._debug:
|
|
2022
|
+
log.debug('%r communicate: stdin got %r', self, exc)
|
|
2023
|
+
|
|
2024
|
+
if self._debug:
|
|
2025
|
+
log.debug('%r communicate: close stdin', self)
|
|
2026
|
+
|
|
2027
|
+
stdin.close()
|
|
2028
|
+
|
|
2029
|
+
async def _noop(self) -> None:
|
|
2030
|
+
return None
|
|
2031
|
+
|
|
2032
|
+
async def _read_stream(self, fd: int) -> bytes:
|
|
2033
|
+
transport: ta.Any = check_not_none(self._transport.get_pipe_transport(fd))
|
|
2034
|
+
|
|
2035
|
+
if fd == 2:
|
|
2036
|
+
stream = check_not_none(self._proc.stderr)
|
|
2037
|
+
else:
|
|
2038
|
+
check_equal(fd, 1)
|
|
2039
|
+
stream = check_not_none(self._proc.stdout)
|
|
2040
|
+
|
|
2041
|
+
if self._debug:
|
|
2042
|
+
name = 'stdout' if fd == 1 else 'stderr'
|
|
2043
|
+
log.debug('%r communicate: read %s', self, name)
|
|
2044
|
+
|
|
2045
|
+
output = await stream.read()
|
|
2046
|
+
|
|
2047
|
+
if self._debug:
|
|
2048
|
+
name = 'stdout' if fd == 1 else 'stderr'
|
|
2049
|
+
log.debug('%r communicate: close %s', self, name)
|
|
2050
|
+
|
|
2051
|
+
transport.close()
|
|
2052
|
+
|
|
2053
|
+
return output
|
|
2054
|
+
|
|
2055
|
+
class Communication(ta.NamedTuple):
|
|
2056
|
+
stdout: ta.Optional[bytes]
|
|
2057
|
+
stderr: ta.Optional[bytes]
|
|
2058
|
+
|
|
2059
|
+
async def _communicate(
|
|
2060
|
+
self,
|
|
2061
|
+
input: ta.Any = None, # noqa
|
|
2062
|
+
) -> Communication:
|
|
2063
|
+
stdin_fut: ta.Any
|
|
2064
|
+
if self._proc.stdin is not None:
|
|
2065
|
+
stdin_fut = self._feed_stdin(input)
|
|
2066
|
+
else:
|
|
2067
|
+
stdin_fut = self._noop()
|
|
2068
|
+
|
|
2069
|
+
stdout_fut: ta.Any
|
|
2070
|
+
if self._proc.stdout is not None:
|
|
2071
|
+
stdout_fut = self._read_stream(1)
|
|
2072
|
+
else:
|
|
2073
|
+
stdout_fut = self._noop()
|
|
2074
|
+
|
|
2075
|
+
stderr_fut: ta.Any
|
|
2076
|
+
if self._proc.stderr is not None:
|
|
2077
|
+
stderr_fut = self._read_stream(2)
|
|
2078
|
+
else:
|
|
2079
|
+
stderr_fut = self._noop()
|
|
2080
|
+
|
|
2081
|
+
stdin_res, stdout_res, stderr_res = await asyncio.gather(stdin_fut, stdout_fut, stderr_fut)
|
|
2082
|
+
|
|
2083
|
+
await self._proc.wait()
|
|
2084
|
+
|
|
2085
|
+
return AsyncioProcessCommunicator.Communication(stdout_res, stderr_res)
|
|
2086
|
+
|
|
2087
|
+
async def communicate(
|
|
2088
|
+
self,
|
|
2089
|
+
input: ta.Any = None, # noqa
|
|
2090
|
+
timeout: ta.Optional[float] = None,
|
|
2091
|
+
) -> Communication:
|
|
2092
|
+
return await asyncio_maybe_timeout(self._communicate(input), timeout)
|
|
2093
|
+
|
|
2094
|
+
|
|
2095
|
+
async def asyncio_subprocess_communicate(
|
|
2096
|
+
proc: asyncio.subprocess.Process,
|
|
2097
|
+
input: ta.Any = None, # noqa
|
|
2098
|
+
timeout: ta.Optional[float] = None,
|
|
2099
|
+
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
|
2100
|
+
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
|
2101
|
+
|
|
2102
|
+
|
|
2103
|
+
##
|
|
2104
|
+
|
|
2105
|
+
|
|
2106
|
+
async def _asyncio_subprocess_check_run(
|
|
2107
|
+
*args: str,
|
|
2108
|
+
input: ta.Any = None, # noqa
|
|
2109
|
+
timeout: ta.Optional[float] = None,
|
|
2110
|
+
**kwargs: ta.Any,
|
|
2111
|
+
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
|
2112
|
+
args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
|
|
2113
|
+
|
|
2114
|
+
proc: asyncio.subprocess.Process
|
|
2115
|
+
async with asyncio_subprocess_popen(*args, **kwargs) as proc:
|
|
2116
|
+
stdout, stderr = await asyncio_subprocess_communicate(proc, input, timeout)
|
|
2117
|
+
|
|
2118
|
+
if proc.returncode:
|
|
2119
|
+
raise subprocess.CalledProcessError(
|
|
2120
|
+
proc.returncode,
|
|
2121
|
+
args,
|
|
2122
|
+
output=stdout,
|
|
2123
|
+
stderr=stderr,
|
|
2124
|
+
)
|
|
2125
|
+
|
|
2126
|
+
return stdout, stderr
|
|
2127
|
+
|
|
2128
|
+
|
|
2129
|
+
async def asyncio_subprocess_check_call(
|
|
2130
|
+
*args: str,
|
|
2131
|
+
stdout: ta.Any = sys.stderr,
|
|
2132
|
+
input: ta.Any = None, # noqa
|
|
2133
|
+
timeout: ta.Optional[float] = None,
|
|
2134
|
+
**kwargs: ta.Any,
|
|
2135
|
+
) -> None:
|
|
2136
|
+
_, _ = await _asyncio_subprocess_check_run(
|
|
2137
|
+
*args,
|
|
2138
|
+
stdout=stdout,
|
|
2139
|
+
input=input,
|
|
2140
|
+
timeout=timeout,
|
|
2141
|
+
**kwargs,
|
|
2142
|
+
)
|
|
2143
|
+
|
|
2144
|
+
|
|
2145
|
+
async def asyncio_subprocess_check_output(
|
|
2146
|
+
*args: str,
|
|
2147
|
+
input: ta.Any = None, # noqa
|
|
2148
|
+
timeout: ta.Optional[float] = None,
|
|
2149
|
+
**kwargs: ta.Any,
|
|
2150
|
+
) -> bytes:
|
|
2151
|
+
stdout, stderr = await _asyncio_subprocess_check_run(
|
|
2152
|
+
*args,
|
|
2153
|
+
stdout=asyncio.subprocess.PIPE,
|
|
2154
|
+
input=input,
|
|
2155
|
+
timeout=timeout,
|
|
2156
|
+
**kwargs,
|
|
2157
|
+
)
|
|
2158
|
+
|
|
2159
|
+
return check_not_none(stdout)
|
|
2160
|
+
|
|
2161
|
+
|
|
2162
|
+
async def asyncio_subprocess_check_output_str(*args: str, **kwargs: ta.Any) -> str:
|
|
2163
|
+
return (await asyncio_subprocess_check_output(*args, **kwargs)).decode().strip()
|
|
2164
|
+
|
|
2165
|
+
|
|
2166
|
+
##
|
|
2167
|
+
|
|
2168
|
+
|
|
2169
|
+
async def _asyncio_subprocess_try_run(
|
|
2170
|
+
fn: ta.Callable[..., ta.Awaitable[T]],
|
|
2171
|
+
*args: ta.Any,
|
|
2172
|
+
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
2173
|
+
**kwargs: ta.Any,
|
|
2174
|
+
) -> ta.Union[T, Exception]:
|
|
2175
|
+
try:
|
|
2176
|
+
return await fn(*args, **kwargs)
|
|
2177
|
+
except try_exceptions as e: # noqa
|
|
2178
|
+
if log.isEnabledFor(logging.DEBUG):
|
|
2179
|
+
log.exception('command failed')
|
|
2180
|
+
return e
|
|
2181
|
+
|
|
2182
|
+
|
|
2183
|
+
async def asyncio_subprocess_try_call(
|
|
2184
|
+
*args: str,
|
|
2185
|
+
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
2186
|
+
**kwargs: ta.Any,
|
|
2187
|
+
) -> bool:
|
|
2188
|
+
if isinstance(await _asyncio_subprocess_try_run(
|
|
2189
|
+
asyncio_subprocess_check_call,
|
|
2190
|
+
*args,
|
|
2191
|
+
try_exceptions=try_exceptions,
|
|
2192
|
+
**kwargs,
|
|
2193
|
+
), Exception):
|
|
2194
|
+
return False
|
|
2195
|
+
else:
|
|
2196
|
+
return True
|
|
2197
|
+
|
|
2198
|
+
|
|
2199
|
+
async def asyncio_subprocess_try_output(
|
|
2200
|
+
*args: str,
|
|
2201
|
+
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
2202
|
+
**kwargs: ta.Any,
|
|
2203
|
+
) -> ta.Optional[bytes]:
|
|
2204
|
+
if isinstance(ret := await _asyncio_subprocess_try_run(
|
|
2205
|
+
asyncio_subprocess_check_output,
|
|
2206
|
+
*args,
|
|
2207
|
+
try_exceptions=try_exceptions,
|
|
2208
|
+
**kwargs,
|
|
2209
|
+
), Exception):
|
|
2210
|
+
return None
|
|
2211
|
+
else:
|
|
2212
|
+
return ret
|
|
2213
|
+
|
|
2214
|
+
|
|
2215
|
+
async def asyncio_subprocess_try_output_str(*args: str, **kwargs: ta.Any) -> ta.Optional[str]:
|
|
2216
|
+
out = await asyncio_subprocess_try_output(*args, **kwargs)
|
|
2217
|
+
return out.decode().strip() if out is not None else None
|
|
2218
|
+
|
|
2219
|
+
|
|
1792
2220
|
########################################
|
|
1793
2221
|
# ../inspect.py
|
|
1794
2222
|
|
|
@@ -1823,7 +2251,6 @@ class InterpInspection:
|
|
|
1823
2251
|
|
|
1824
2252
|
|
|
1825
2253
|
class InterpInspector:
|
|
1826
|
-
|
|
1827
2254
|
def __init__(self) -> None:
|
|
1828
2255
|
super().__init__()
|
|
1829
2256
|
|
|
@@ -1863,17 +2290,17 @@ class InterpInspector:
|
|
|
1863
2290
|
def running(cls) -> 'InterpInspection':
|
|
1864
2291
|
return cls._build_inspection(sys.executable, eval(cls._INSPECTION_CODE)) # noqa
|
|
1865
2292
|
|
|
1866
|
-
def _inspect(self, exe: str) -> InterpInspection:
|
|
1867
|
-
output =
|
|
2293
|
+
async def _inspect(self, exe: str) -> InterpInspection:
|
|
2294
|
+
output = await asyncio_subprocess_check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
|
|
1868
2295
|
return self._build_inspection(exe, output.decode())
|
|
1869
2296
|
|
|
1870
|
-
def inspect(self, exe: str) -> ta.Optional[InterpInspection]:
|
|
2297
|
+
async def inspect(self, exe: str) -> ta.Optional[InterpInspection]:
|
|
1871
2298
|
try:
|
|
1872
2299
|
return self._cache[exe]
|
|
1873
2300
|
except KeyError:
|
|
1874
2301
|
ret: ta.Optional[InterpInspection]
|
|
1875
2302
|
try:
|
|
1876
|
-
ret = self._inspect(exe)
|
|
2303
|
+
ret = await self._inspect(exe)
|
|
1877
2304
|
except Exception as e: # noqa
|
|
1878
2305
|
if log.isEnabledFor(logging.DEBUG):
|
|
1879
2306
|
log.exception('Failed to inspect interp: %s', exe)
|
|
@@ -1912,17 +2339,17 @@ class InterpProvider(abc.ABC):
|
|
|
1912
2339
|
setattr(cls, 'name', snake_case(cls.__name__[:-len(sfx)]))
|
|
1913
2340
|
|
|
1914
2341
|
@abc.abstractmethod
|
|
1915
|
-
def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
2342
|
+
def get_installed_versions(self, spec: InterpSpecifier) -> ta.Awaitable[ta.Sequence[InterpVersion]]:
|
|
1916
2343
|
raise NotImplementedError
|
|
1917
2344
|
|
|
1918
2345
|
@abc.abstractmethod
|
|
1919
|
-
def get_installed_version(self, version: InterpVersion) -> Interp:
|
|
2346
|
+
def get_installed_version(self, version: InterpVersion) -> ta.Awaitable[Interp]:
|
|
1920
2347
|
raise NotImplementedError
|
|
1921
2348
|
|
|
1922
|
-
def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
2349
|
+
async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
1923
2350
|
return []
|
|
1924
2351
|
|
|
1925
|
-
def install_version(self, version: InterpVersion) -> Interp:
|
|
2352
|
+
async def install_version(self, version: InterpVersion) -> Interp:
|
|
1926
2353
|
raise TypeError
|
|
1927
2354
|
|
|
1928
2355
|
|
|
@@ -1934,10 +2361,10 @@ class RunningInterpProvider(InterpProvider):
|
|
|
1934
2361
|
def version(self) -> InterpVersion:
|
|
1935
2362
|
return InterpInspector.running().iv
|
|
1936
2363
|
|
|
1937
|
-
def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
2364
|
+
async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
1938
2365
|
return [self.version()]
|
|
1939
2366
|
|
|
1940
|
-
def get_installed_version(self, version: InterpVersion) -> Interp:
|
|
2367
|
+
async def get_installed_version(self, version: InterpVersion) -> Interp:
|
|
1941
2368
|
if version != self.version():
|
|
1942
2369
|
raise KeyError(version)
|
|
1943
2370
|
return Interp(
|
|
@@ -1965,7 +2392,6 @@ TODO:
|
|
|
1965
2392
|
|
|
1966
2393
|
|
|
1967
2394
|
class Pyenv:
|
|
1968
|
-
|
|
1969
2395
|
def __init__(
|
|
1970
2396
|
self,
|
|
1971
2397
|
*,
|
|
@@ -1978,13 +2404,13 @@ class Pyenv:
|
|
|
1978
2404
|
|
|
1979
2405
|
self._root_kw = root
|
|
1980
2406
|
|
|
1981
|
-
@
|
|
1982
|
-
def root(self) -> ta.Optional[str]:
|
|
2407
|
+
@async_cached_nullary
|
|
2408
|
+
async def root(self) -> ta.Optional[str]:
|
|
1983
2409
|
if self._root_kw is not None:
|
|
1984
2410
|
return self._root_kw
|
|
1985
2411
|
|
|
1986
2412
|
if shutil.which('pyenv'):
|
|
1987
|
-
return
|
|
2413
|
+
return await asyncio_subprocess_check_output_str('pyenv', 'root')
|
|
1988
2414
|
|
|
1989
2415
|
d = os.path.expanduser('~/.pyenv')
|
|
1990
2416
|
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
|
@@ -1992,12 +2418,12 @@ class Pyenv:
|
|
|
1992
2418
|
|
|
1993
2419
|
return None
|
|
1994
2420
|
|
|
1995
|
-
@
|
|
1996
|
-
def exe(self) -> str:
|
|
1997
|
-
return os.path.join(check_not_none(self.root()), 'bin', 'pyenv')
|
|
2421
|
+
@async_cached_nullary
|
|
2422
|
+
async def exe(self) -> str:
|
|
2423
|
+
return os.path.join(check_not_none(await self.root()), 'bin', 'pyenv')
|
|
1998
2424
|
|
|
1999
|
-
def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
|
|
2000
|
-
if (root := self.root()) is None:
|
|
2425
|
+
async def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
|
|
2426
|
+
if (root := await self.root()) is None:
|
|
2001
2427
|
return []
|
|
2002
2428
|
ret = []
|
|
2003
2429
|
vp = os.path.join(root, 'versions')
|
|
@@ -2009,11 +2435,11 @@ class Pyenv:
|
|
|
2009
2435
|
ret.append((dn, ep))
|
|
2010
2436
|
return ret
|
|
2011
2437
|
|
|
2012
|
-
def installable_versions(self) -> ta.List[str]:
|
|
2013
|
-
if self.root() is None:
|
|
2438
|
+
async def installable_versions(self) -> ta.List[str]:
|
|
2439
|
+
if await self.root() is None:
|
|
2014
2440
|
return []
|
|
2015
2441
|
ret = []
|
|
2016
|
-
s =
|
|
2442
|
+
s = await asyncio_subprocess_check_output_str(await self.exe(), 'install', '--list')
|
|
2017
2443
|
for l in s.splitlines():
|
|
2018
2444
|
if not l.startswith(' '):
|
|
2019
2445
|
continue
|
|
@@ -2023,12 +2449,12 @@ class Pyenv:
|
|
|
2023
2449
|
ret.append(l)
|
|
2024
2450
|
return ret
|
|
2025
2451
|
|
|
2026
|
-
def update(self) -> bool:
|
|
2027
|
-
if (root := self.root()) is None:
|
|
2452
|
+
async def update(self) -> bool:
|
|
2453
|
+
if (root := await self.root()) is None:
|
|
2028
2454
|
return False
|
|
2029
2455
|
if not os.path.isdir(os.path.join(root, '.git')):
|
|
2030
2456
|
return False
|
|
2031
|
-
|
|
2457
|
+
await asyncio_subprocess_check_call('git', 'pull', cwd=root)
|
|
2032
2458
|
return True
|
|
2033
2459
|
|
|
2034
2460
|
|
|
@@ -2089,17 +2515,16 @@ THREADED_PYENV_INSTALL_OPTS = PyenvInstallOpts(conf_opts=['--disable-gil'])
|
|
|
2089
2515
|
|
|
2090
2516
|
class PyenvInstallOptsProvider(abc.ABC):
|
|
2091
2517
|
@abc.abstractmethod
|
|
2092
|
-
def opts(self) -> PyenvInstallOpts:
|
|
2518
|
+
def opts(self) -> ta.Awaitable[PyenvInstallOpts]:
|
|
2093
2519
|
raise NotImplementedError
|
|
2094
2520
|
|
|
2095
2521
|
|
|
2096
2522
|
class LinuxPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
2097
|
-
def opts(self) -> PyenvInstallOpts:
|
|
2523
|
+
async def opts(self) -> PyenvInstallOpts:
|
|
2098
2524
|
return PyenvInstallOpts()
|
|
2099
2525
|
|
|
2100
2526
|
|
|
2101
2527
|
class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
2102
|
-
|
|
2103
2528
|
@cached_nullary
|
|
2104
2529
|
def framework_opts(self) -> PyenvInstallOpts:
|
|
2105
2530
|
return PyenvInstallOpts(conf_opts=['--enable-framework'])
|
|
@@ -2115,12 +2540,12 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
2115
2540
|
'zlib',
|
|
2116
2541
|
]
|
|
2117
2542
|
|
|
2118
|
-
@
|
|
2119
|
-
def brew_deps_opts(self) -> PyenvInstallOpts:
|
|
2543
|
+
@async_cached_nullary
|
|
2544
|
+
async def brew_deps_opts(self) -> PyenvInstallOpts:
|
|
2120
2545
|
cflags = []
|
|
2121
2546
|
ldflags = []
|
|
2122
2547
|
for dep in self.BREW_DEPS:
|
|
2123
|
-
dep_prefix =
|
|
2548
|
+
dep_prefix = await asyncio_subprocess_check_output_str('brew', '--prefix', dep)
|
|
2124
2549
|
cflags.append(f'-I{dep_prefix}/include')
|
|
2125
2550
|
ldflags.append(f'-L{dep_prefix}/lib')
|
|
2126
2551
|
return PyenvInstallOpts(
|
|
@@ -2128,13 +2553,13 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
2128
2553
|
ldflags=ldflags,
|
|
2129
2554
|
)
|
|
2130
2555
|
|
|
2131
|
-
@
|
|
2132
|
-
def brew_tcl_opts(self) -> PyenvInstallOpts:
|
|
2133
|
-
if
|
|
2556
|
+
@async_cached_nullary
|
|
2557
|
+
async def brew_tcl_opts(self) -> PyenvInstallOpts:
|
|
2558
|
+
if await asyncio_subprocess_try_output('brew', '--prefix', 'tcl-tk') is None:
|
|
2134
2559
|
return PyenvInstallOpts()
|
|
2135
2560
|
|
|
2136
|
-
tcl_tk_prefix =
|
|
2137
|
-
tcl_tk_ver_str =
|
|
2561
|
+
tcl_tk_prefix = await asyncio_subprocess_check_output_str('brew', '--prefix', 'tcl-tk')
|
|
2562
|
+
tcl_tk_ver_str = await asyncio_subprocess_check_output_str('brew', 'ls', '--versions', 'tcl-tk')
|
|
2138
2563
|
tcl_tk_ver = '.'.join(tcl_tk_ver_str.split()[1].split('.')[:2])
|
|
2139
2564
|
|
|
2140
2565
|
return PyenvInstallOpts(conf_opts=[
|
|
@@ -2149,11 +2574,11 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
2149
2574
|
# pkg_config_path += ':' + os.environ['PKG_CONFIG_PATH']
|
|
2150
2575
|
# return PyenvInstallOpts(env={'PKG_CONFIG_PATH': pkg_config_path})
|
|
2151
2576
|
|
|
2152
|
-
def opts(self) -> PyenvInstallOpts:
|
|
2577
|
+
async def opts(self) -> PyenvInstallOpts:
|
|
2153
2578
|
return PyenvInstallOpts().merge(
|
|
2154
2579
|
self.framework_opts(),
|
|
2155
|
-
self.brew_deps_opts(),
|
|
2156
|
-
self.brew_tcl_opts(),
|
|
2580
|
+
await self.brew_deps_opts(),
|
|
2581
|
+
await self.brew_tcl_opts(),
|
|
2157
2582
|
# self.brew_ssl_opts(),
|
|
2158
2583
|
)
|
|
2159
2584
|
|
|
@@ -2185,20 +2610,8 @@ class PyenvVersionInstaller:
|
|
|
2185
2610
|
) -> None:
|
|
2186
2611
|
super().__init__()
|
|
2187
2612
|
|
|
2188
|
-
if no_default_opts:
|
|
2189
|
-
if opts is None:
|
|
2190
|
-
opts = PyenvInstallOpts()
|
|
2191
|
-
else:
|
|
2192
|
-
lst = [opts if opts is not None else DEFAULT_PYENV_INSTALL_OPTS]
|
|
2193
|
-
if interp_opts.debug:
|
|
2194
|
-
lst.append(DEBUG_PYENV_INSTALL_OPTS)
|
|
2195
|
-
if interp_opts.threaded:
|
|
2196
|
-
lst.append(THREADED_PYENV_INSTALL_OPTS)
|
|
2197
|
-
lst.append(PLATFORM_PYENV_INSTALL_OPTS[sys.platform].opts())
|
|
2198
|
-
opts = PyenvInstallOpts().merge(*lst)
|
|
2199
|
-
|
|
2200
2613
|
self._version = version
|
|
2201
|
-
self.
|
|
2614
|
+
self._given_opts = opts
|
|
2202
2615
|
self._interp_opts = interp_opts
|
|
2203
2616
|
self._given_install_name = install_name
|
|
2204
2617
|
|
|
@@ -2209,9 +2622,21 @@ class PyenvVersionInstaller:
|
|
|
2209
2622
|
def version(self) -> str:
|
|
2210
2623
|
return self._version
|
|
2211
2624
|
|
|
2212
|
-
@
|
|
2213
|
-
def opts(self) -> PyenvInstallOpts:
|
|
2214
|
-
|
|
2625
|
+
@async_cached_nullary
|
|
2626
|
+
async def opts(self) -> PyenvInstallOpts:
|
|
2627
|
+
opts = self._given_opts
|
|
2628
|
+
if self._no_default_opts:
|
|
2629
|
+
if opts is None:
|
|
2630
|
+
opts = PyenvInstallOpts()
|
|
2631
|
+
else:
|
|
2632
|
+
lst = [self._given_opts if self._given_opts is not None else DEFAULT_PYENV_INSTALL_OPTS]
|
|
2633
|
+
if self._interp_opts.debug:
|
|
2634
|
+
lst.append(DEBUG_PYENV_INSTALL_OPTS)
|
|
2635
|
+
if self._interp_opts.threaded:
|
|
2636
|
+
lst.append(THREADED_PYENV_INSTALL_OPTS)
|
|
2637
|
+
lst.append(await PLATFORM_PYENV_INSTALL_OPTS[sys.platform].opts())
|
|
2638
|
+
opts = PyenvInstallOpts().merge(*lst)
|
|
2639
|
+
return opts
|
|
2215
2640
|
|
|
2216
2641
|
@cached_nullary
|
|
2217
2642
|
def install_name(self) -> str:
|
|
@@ -2219,17 +2644,18 @@ class PyenvVersionInstaller:
|
|
|
2219
2644
|
return self._given_install_name
|
|
2220
2645
|
return self._version + ('-debug' if self._interp_opts.debug else '')
|
|
2221
2646
|
|
|
2222
|
-
@
|
|
2223
|
-
def install_dir(self) -> str:
|
|
2224
|
-
return str(os.path.join(check_not_none(self._pyenv.root()), 'versions', self.install_name()))
|
|
2647
|
+
@async_cached_nullary
|
|
2648
|
+
async def install_dir(self) -> str:
|
|
2649
|
+
return str(os.path.join(check_not_none(await self._pyenv.root()), 'versions', self.install_name()))
|
|
2225
2650
|
|
|
2226
|
-
@
|
|
2227
|
-
def install(self) -> str:
|
|
2228
|
-
|
|
2651
|
+
@async_cached_nullary
|
|
2652
|
+
async def install(self) -> str:
|
|
2653
|
+
opts = await self.opts()
|
|
2654
|
+
env = {**os.environ, **opts.env}
|
|
2229
2655
|
for k, l in [
|
|
2230
|
-
('CFLAGS',
|
|
2231
|
-
('LDFLAGS',
|
|
2232
|
-
('PYTHON_CONFIGURE_OPTS',
|
|
2656
|
+
('CFLAGS', opts.cflags),
|
|
2657
|
+
('LDFLAGS', opts.ldflags),
|
|
2658
|
+
('PYTHON_CONFIGURE_OPTS', opts.conf_opts),
|
|
2233
2659
|
]:
|
|
2234
2660
|
v = ' '.join(l)
|
|
2235
2661
|
if k in os.environ:
|
|
@@ -2237,13 +2663,13 @@ class PyenvVersionInstaller:
|
|
|
2237
2663
|
env[k] = v
|
|
2238
2664
|
|
|
2239
2665
|
conf_args = [
|
|
2240
|
-
*
|
|
2666
|
+
*opts.opts,
|
|
2241
2667
|
self._version,
|
|
2242
2668
|
]
|
|
2243
2669
|
|
|
2244
2670
|
if self._given_install_name is not None:
|
|
2245
2671
|
full_args = [
|
|
2246
|
-
os.path.join(check_not_none(self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'),
|
|
2672
|
+
os.path.join(check_not_none(await self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'), # noqa
|
|
2247
2673
|
*conf_args,
|
|
2248
2674
|
self.install_dir(),
|
|
2249
2675
|
]
|
|
@@ -2254,12 +2680,12 @@ class PyenvVersionInstaller:
|
|
|
2254
2680
|
*conf_args,
|
|
2255
2681
|
]
|
|
2256
2682
|
|
|
2257
|
-
|
|
2683
|
+
await asyncio_subprocess_check_call(
|
|
2258
2684
|
*full_args,
|
|
2259
2685
|
env=env,
|
|
2260
2686
|
)
|
|
2261
2687
|
|
|
2262
|
-
exe = os.path.join(self.install_dir(), 'bin', 'python')
|
|
2688
|
+
exe = os.path.join(await self.install_dir(), 'bin', 'python')
|
|
2263
2689
|
if not os.path.isfile(exe):
|
|
2264
2690
|
raise RuntimeError(f'Interpreter not found: {exe}')
|
|
2265
2691
|
return exe
|
|
@@ -2269,7 +2695,6 @@ class PyenvVersionInstaller:
|
|
|
2269
2695
|
|
|
2270
2696
|
|
|
2271
2697
|
class PyenvInterpProvider(InterpProvider):
|
|
2272
|
-
|
|
2273
2698
|
def __init__(
|
|
2274
2699
|
self,
|
|
2275
2700
|
pyenv: Pyenv = Pyenv(),
|
|
@@ -2312,11 +2737,11 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
2312
2737
|
exe: str
|
|
2313
2738
|
version: InterpVersion
|
|
2314
2739
|
|
|
2315
|
-
def _make_installed(self, vn: str, ep: str) -> ta.Optional[Installed]:
|
|
2740
|
+
async def _make_installed(self, vn: str, ep: str) -> ta.Optional[Installed]:
|
|
2316
2741
|
iv: ta.Optional[InterpVersion]
|
|
2317
2742
|
if self._inspect:
|
|
2318
2743
|
try:
|
|
2319
|
-
iv = check_not_none(self._inspector.inspect(ep)).iv
|
|
2744
|
+
iv = check_not_none(await self._inspector.inspect(ep)).iv
|
|
2320
2745
|
except Exception as e: # noqa
|
|
2321
2746
|
return None
|
|
2322
2747
|
else:
|
|
@@ -2329,10 +2754,10 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
2329
2754
|
version=iv,
|
|
2330
2755
|
)
|
|
2331
2756
|
|
|
2332
|
-
def installed(self) -> ta.Sequence[Installed]:
|
|
2757
|
+
async def installed(self) -> ta.Sequence[Installed]:
|
|
2333
2758
|
ret: ta.List[PyenvInterpProvider.Installed] = []
|
|
2334
|
-
for vn, ep in self._pyenv.version_exes():
|
|
2335
|
-
if (i := self._make_installed(vn, ep)) is None:
|
|
2759
|
+
for vn, ep in await self._pyenv.version_exes():
|
|
2760
|
+
if (i := await self._make_installed(vn, ep)) is None:
|
|
2336
2761
|
log.debug('Invalid pyenv version: %s', vn)
|
|
2337
2762
|
continue
|
|
2338
2763
|
ret.append(i)
|
|
@@ -2340,11 +2765,11 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
2340
2765
|
|
|
2341
2766
|
#
|
|
2342
2767
|
|
|
2343
|
-
def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
2344
|
-
return [i.version for i in self.installed()]
|
|
2768
|
+
async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
2769
|
+
return [i.version for i in await self.installed()]
|
|
2345
2770
|
|
|
2346
|
-
def get_installed_version(self, version: InterpVersion) -> Interp:
|
|
2347
|
-
for i in self.installed():
|
|
2771
|
+
async def get_installed_version(self, version: InterpVersion) -> Interp:
|
|
2772
|
+
for i in await self.installed():
|
|
2348
2773
|
if i.version == version:
|
|
2349
2774
|
return Interp(
|
|
2350
2775
|
exe=i.exe,
|
|
@@ -2354,10 +2779,10 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
2354
2779
|
|
|
2355
2780
|
#
|
|
2356
2781
|
|
|
2357
|
-
def _get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
2782
|
+
async def _get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
2358
2783
|
lst = []
|
|
2359
2784
|
|
|
2360
|
-
for vs in self._pyenv.installable_versions():
|
|
2785
|
+
for vs in await self._pyenv.installable_versions():
|
|
2361
2786
|
if (iv := self.guess_version(vs)) is None:
|
|
2362
2787
|
continue
|
|
2363
2788
|
if iv.opts.debug:
|
|
@@ -2367,16 +2792,16 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
2367
2792
|
|
|
2368
2793
|
return lst
|
|
2369
2794
|
|
|
2370
|
-
def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
2371
|
-
lst = self._get_installable_versions(spec)
|
|
2795
|
+
async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
2796
|
+
lst = await self._get_installable_versions(spec)
|
|
2372
2797
|
|
|
2373
2798
|
if self._try_update and not any(v in spec for v in lst):
|
|
2374
2799
|
if self._pyenv.update():
|
|
2375
|
-
lst = self._get_installable_versions(spec)
|
|
2800
|
+
lst = await self._get_installable_versions(spec)
|
|
2376
2801
|
|
|
2377
2802
|
return lst
|
|
2378
2803
|
|
|
2379
|
-
def install_version(self, version: InterpVersion) -> Interp:
|
|
2804
|
+
async def install_version(self, version: InterpVersion) -> Interp:
|
|
2380
2805
|
inst_version = str(version.version)
|
|
2381
2806
|
inst_opts = version.opts
|
|
2382
2807
|
if inst_opts.threaded:
|
|
@@ -2388,7 +2813,7 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
2388
2813
|
interp_opts=inst_opts,
|
|
2389
2814
|
)
|
|
2390
2815
|
|
|
2391
|
-
exe = installer.install()
|
|
2816
|
+
exe = await installer.install()
|
|
2392
2817
|
return Interp(exe, version)
|
|
2393
2818
|
|
|
2394
2819
|
|
|
@@ -2467,7 +2892,7 @@ class SystemInterpProvider(InterpProvider):
|
|
|
2467
2892
|
|
|
2468
2893
|
#
|
|
2469
2894
|
|
|
2470
|
-
def get_exe_version(self, exe: str) -> ta.Optional[InterpVersion]:
|
|
2895
|
+
async def get_exe_version(self, exe: str) -> ta.Optional[InterpVersion]:
|
|
2471
2896
|
if not self.inspect:
|
|
2472
2897
|
s = os.path.basename(exe)
|
|
2473
2898
|
if s.startswith('python'):
|
|
@@ -2477,13 +2902,13 @@ class SystemInterpProvider(InterpProvider):
|
|
|
2477
2902
|
return InterpVersion.parse(s)
|
|
2478
2903
|
except InvalidVersion:
|
|
2479
2904
|
pass
|
|
2480
|
-
ii = self.inspector.inspect(exe)
|
|
2905
|
+
ii = await self.inspector.inspect(exe)
|
|
2481
2906
|
return ii.iv if ii is not None else None
|
|
2482
2907
|
|
|
2483
|
-
def exe_versions(self) -> ta.Sequence[ta.Tuple[str, InterpVersion]]:
|
|
2908
|
+
async def exe_versions(self) -> ta.Sequence[ta.Tuple[str, InterpVersion]]:
|
|
2484
2909
|
lst = []
|
|
2485
2910
|
for e in self.exes():
|
|
2486
|
-
if (ev := self.get_exe_version(e)) is None:
|
|
2911
|
+
if (ev := await self.get_exe_version(e)) is None:
|
|
2487
2912
|
log.debug('Invalid system version: %s', e)
|
|
2488
2913
|
continue
|
|
2489
2914
|
lst.append((e, ev))
|
|
@@ -2491,11 +2916,11 @@ class SystemInterpProvider(InterpProvider):
|
|
|
2491
2916
|
|
|
2492
2917
|
#
|
|
2493
2918
|
|
|
2494
|
-
def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
2495
|
-
return [ev for e, ev in self.exe_versions()]
|
|
2919
|
+
async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
2920
|
+
return [ev for e, ev in await self.exe_versions()]
|
|
2496
2921
|
|
|
2497
|
-
def get_installed_version(self, version: InterpVersion) -> Interp:
|
|
2498
|
-
for e, ev in self.exe_versions():
|
|
2922
|
+
async def get_installed_version(self, version: InterpVersion) -> Interp:
|
|
2923
|
+
for e, ev in await self.exe_versions():
|
|
2499
2924
|
if ev != version:
|
|
2500
2925
|
continue
|
|
2501
2926
|
return Interp(
|
|
@@ -2520,13 +2945,14 @@ class InterpResolver:
|
|
|
2520
2945
|
providers: ta.Sequence[ta.Tuple[str, InterpProvider]],
|
|
2521
2946
|
) -> None:
|
|
2522
2947
|
super().__init__()
|
|
2948
|
+
|
|
2523
2949
|
self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers)
|
|
2524
2950
|
|
|
2525
|
-
def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
|
|
2951
|
+
async def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
|
|
2526
2952
|
lst = [
|
|
2527
2953
|
(i, si)
|
|
2528
2954
|
for i, p in enumerate(self._providers.values())
|
|
2529
|
-
for si in p.get_installed_versions(spec)
|
|
2955
|
+
for si in await p.get_installed_versions(spec)
|
|
2530
2956
|
if spec.contains(si)
|
|
2531
2957
|
]
|
|
2532
2958
|
|
|
@@ -2538,16 +2964,16 @@ class InterpResolver:
|
|
|
2538
2964
|
bp = list(self._providers.values())[bi]
|
|
2539
2965
|
return (bp, bv)
|
|
2540
2966
|
|
|
2541
|
-
def resolve(
|
|
2967
|
+
async def resolve(
|
|
2542
2968
|
self,
|
|
2543
2969
|
spec: InterpSpecifier,
|
|
2544
2970
|
*,
|
|
2545
2971
|
install: bool = False,
|
|
2546
2972
|
) -> ta.Optional[Interp]:
|
|
2547
|
-
tup = self._resolve_installed(spec)
|
|
2973
|
+
tup = await self._resolve_installed(spec)
|
|
2548
2974
|
if tup is not None:
|
|
2549
2975
|
bp, bv = tup
|
|
2550
|
-
return bp.get_installed_version(bv)
|
|
2976
|
+
return await bp.get_installed_version(bv)
|
|
2551
2977
|
|
|
2552
2978
|
if not install:
|
|
2553
2979
|
return None
|
|
@@ -2555,21 +2981,21 @@ class InterpResolver:
|
|
|
2555
2981
|
tp = list(self._providers.values())[0] # noqa
|
|
2556
2982
|
|
|
2557
2983
|
sv = sorted(
|
|
2558
|
-
[s for s in tp.get_installable_versions(spec) if s in spec],
|
|
2984
|
+
[s for s in await tp.get_installable_versions(spec) if s in spec],
|
|
2559
2985
|
key=lambda s: s.version,
|
|
2560
2986
|
)
|
|
2561
2987
|
if not sv:
|
|
2562
2988
|
return None
|
|
2563
2989
|
|
|
2564
2990
|
bv = sv[-1]
|
|
2565
|
-
return tp.install_version(bv)
|
|
2991
|
+
return await tp.install_version(bv)
|
|
2566
2992
|
|
|
2567
|
-
def list(self, spec: InterpSpecifier) -> None:
|
|
2993
|
+
async def list(self, spec: InterpSpecifier) -> None:
|
|
2568
2994
|
print('installed:')
|
|
2569
2995
|
for n, p in self._providers.items():
|
|
2570
2996
|
lst = [
|
|
2571
2997
|
si
|
|
2572
|
-
for si in p.get_installed_versions(spec)
|
|
2998
|
+
for si in await p.get_installed_versions(spec)
|
|
2573
2999
|
if spec.contains(si)
|
|
2574
3000
|
]
|
|
2575
3001
|
if lst:
|
|
@@ -2583,7 +3009,7 @@ class InterpResolver:
|
|
|
2583
3009
|
for n, p in self._providers.items():
|
|
2584
3010
|
lst = [
|
|
2585
3011
|
si
|
|
2586
|
-
for si in p.get_installable_versions(spec)
|
|
3012
|
+
for si in await p.get_installable_versions(spec)
|
|
2587
3013
|
if spec.contains(si)
|
|
2588
3014
|
]
|
|
2589
3015
|
if lst:
|
|
@@ -2606,20 +3032,20 @@ DEFAULT_INTERP_RESOLVER = InterpResolver([(p.name, p) for p in [
|
|
|
2606
3032
|
# cli.py
|
|
2607
3033
|
|
|
2608
3034
|
|
|
2609
|
-
def _list_cmd(args) -> None:
|
|
3035
|
+
async def _list_cmd(args) -> None:
|
|
2610
3036
|
r = DEFAULT_INTERP_RESOLVER
|
|
2611
3037
|
s = InterpSpecifier.parse(args.version)
|
|
2612
|
-
r.list(s)
|
|
3038
|
+
await r.list(s)
|
|
2613
3039
|
|
|
2614
3040
|
|
|
2615
|
-
def _resolve_cmd(args) -> None:
|
|
3041
|
+
async def _resolve_cmd(args) -> None:
|
|
2616
3042
|
if args.provider:
|
|
2617
3043
|
p = INTERP_PROVIDER_TYPES_BY_NAME[args.provider]()
|
|
2618
3044
|
r = InterpResolver([(p.name, p)])
|
|
2619
3045
|
else:
|
|
2620
3046
|
r = DEFAULT_INTERP_RESOLVER
|
|
2621
3047
|
s = InterpSpecifier.parse(args.version)
|
|
2622
|
-
print(check_not_none(r.resolve(s, install=bool(args.install))).exe)
|
|
3048
|
+
print(check_not_none(await r.resolve(s, install=bool(args.install))).exe)
|
|
2623
3049
|
|
|
2624
3050
|
|
|
2625
3051
|
def _build_parser() -> argparse.ArgumentParser:
|
|
@@ -2642,7 +3068,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
2642
3068
|
return parser
|
|
2643
3069
|
|
|
2644
3070
|
|
|
2645
|
-
def
|
|
3071
|
+
async def _async_main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
|
|
2646
3072
|
check_runtime_version()
|
|
2647
3073
|
configure_standard_logging()
|
|
2648
3074
|
|
|
@@ -2651,7 +3077,11 @@ def _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
|
|
|
2651
3077
|
if not getattr(args, 'func', None):
|
|
2652
3078
|
parser.print_help()
|
|
2653
3079
|
else:
|
|
2654
|
-
args.func(args)
|
|
3080
|
+
await args.func(args)
|
|
3081
|
+
|
|
3082
|
+
|
|
3083
|
+
def _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
|
|
3084
|
+
asyncio.run(_async_main(argv))
|
|
2655
3085
|
|
|
2656
3086
|
|
|
2657
3087
|
if __name__ == '__main__':
|