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/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
- class _cached_nullary: # noqa
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
- if self._value is self._missing:
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 _cached_nullary(fn)
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 check_non_empty(v: SizedT) -> SizedT:
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 _prepare_subprocess_invocation(
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
- def subprocess_check_call(*args: str, stdout=sys.stderr, **kwargs: ta.Any) -> None:
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
- def subprocess_check_output(*args: str, **kwargs: ta.Any) -> bytes:
1724
- args, kwargs = _prepare_subprocess_invocation(*args, **kwargs)
1725
- return subprocess.check_output(args, **kwargs)
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 subprocess_try_call(
1742
- *args: str,
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
- ) -> bool:
1877
+ ) -> ta.Union[T, Exception]:
1746
1878
  try:
1747
- subprocess_check_call(*args, **kwargs)
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
- try:
1762
- return subprocess_check_output(*args, **kwargs)
1763
- except try_exceptions as e: # noqa
1764
- if log.isEnabledFor(logging.DEBUG):
1765
- log.exception('command failed')
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 = subprocess_check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
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
- @cached_nullary
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 subprocess_check_output_str('pyenv', 'root')
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
- @cached_nullary
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 = subprocess_check_output_str(self.exe(), 'install', '--list')
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
- subprocess_check_call('git', 'pull', cwd=root)
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
- @cached_nullary
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 = subprocess_check_output_str('brew', '--prefix', dep)
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
- @cached_nullary
2132
- def brew_tcl_opts(self) -> PyenvInstallOpts:
2133
- if subprocess_try_output('brew', '--prefix', 'tcl-tk') is None:
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 = subprocess_check_output_str('brew', '--prefix', 'tcl-tk')
2137
- tcl_tk_ver_str = subprocess_check_output_str('brew', 'ls', '--versions', 'tcl-tk')
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._opts = opts
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
- @property
2213
- def opts(self) -> PyenvInstallOpts:
2214
- return self._opts
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
- @cached_nullary
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
- @cached_nullary
2227
- def install(self) -> str:
2228
- env = {**os.environ, **self._opts.env}
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', self._opts.cflags),
2231
- ('LDFLAGS', self._opts.ldflags),
2232
- ('PYTHON_CONFIGURE_OPTS', self._opts.conf_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
- *self._opts.opts,
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
- subprocess_check_call(
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 _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
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__':