omdev 0.0.0.dev147__py3-none-any.whl → 0.0.0.dev148__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
 
@@ -1637,6 +1729,8 @@ class InterpSpecifier:
1637
1729
  s, o = InterpOpts.parse_suffix(s)
1638
1730
  if not any(s.startswith(o) for o in Specifier.OPERATORS):
1639
1731
  s = '~=' + s
1732
+ if s.count('.') < 2:
1733
+ s += '.0'
1640
1734
  return cls(
1641
1735
  specifier=Specifier(s),
1642
1736
  opts=o,
@@ -1686,7 +1780,7 @@ def subprocess_maybe_shell_wrap_exec(*args: str) -> ta.Tuple[str, ...]:
1686
1780
  return args
1687
1781
 
1688
1782
 
1689
- def _prepare_subprocess_invocation(
1783
+ def prepare_subprocess_invocation(
1690
1784
  *args: str,
1691
1785
  env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
1692
1786
  extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
@@ -1694,9 +1788,9 @@ def _prepare_subprocess_invocation(
1694
1788
  shell: bool = False,
1695
1789
  **kwargs: ta.Any,
1696
1790
  ) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
1697
- log.debug(args)
1791
+ log.debug('prepare_subprocess_invocation: args=%r', args)
1698
1792
  if extra_env:
1699
- log.debug(extra_env)
1793
+ log.debug('prepare_subprocess_invocation: extra_env=%r', extra_env)
1700
1794
 
1701
1795
  if extra_env:
1702
1796
  env = {**(env if env is not None else os.environ), **extra_env}
@@ -1715,14 +1809,46 @@ def _prepare_subprocess_invocation(
1715
1809
  )
1716
1810
 
1717
1811
 
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
1812
+ ##
1721
1813
 
1722
1814
 
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)
1815
+ @contextlib.contextmanager
1816
+ def subprocess_common_context(*args: ta.Any, **kwargs: ta.Any) -> ta.Iterator[None]:
1817
+ start_time = time.time()
1818
+ try:
1819
+ log.debug('subprocess_common_context.try: args=%r', args)
1820
+ yield
1821
+
1822
+ except Exception as exc: # noqa
1823
+ log.debug('subprocess_common_context.except: exc=%r', exc)
1824
+ raise
1825
+
1826
+ finally:
1827
+ end_time = time.time()
1828
+ elapsed_s = end_time - start_time
1829
+ log.debug('subprocess_common_context.finally: elapsed_s=%f args=%r', elapsed_s, args)
1830
+
1831
+
1832
+ ##
1833
+
1834
+
1835
+ def subprocess_check_call(
1836
+ *args: str,
1837
+ stdout: ta.Any = sys.stderr,
1838
+ **kwargs: ta.Any,
1839
+ ) -> None:
1840
+ args, kwargs = prepare_subprocess_invocation(*args, stdout=stdout, **kwargs)
1841
+ with subprocess_common_context(*args, **kwargs):
1842
+ return subprocess.check_call(args, **kwargs) # type: ignore
1843
+
1844
+
1845
+ def subprocess_check_output(
1846
+ *args: str,
1847
+ **kwargs: ta.Any,
1848
+ ) -> bytes:
1849
+ args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
1850
+ with subprocess_common_context(*args, **kwargs):
1851
+ return subprocess.check_output(args, **kwargs)
1726
1852
 
1727
1853
 
1728
1854
  def subprocess_check_output_str(*args: str, **kwargs: ta.Any) -> str:
@@ -1738,16 +1864,31 @@ DEFAULT_SUBPROCESS_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
1738
1864
  )
1739
1865
 
1740
1866
 
1741
- def subprocess_try_call(
1742
- *args: str,
1867
+ def _subprocess_try_run(
1868
+ fn: ta.Callable[..., T],
1869
+ *args: ta.Any,
1743
1870
  try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
1744
1871
  **kwargs: ta.Any,
1745
- ) -> bool:
1872
+ ) -> ta.Union[T, Exception]:
1746
1873
  try:
1747
- subprocess_check_call(*args, **kwargs)
1874
+ return fn(*args, **kwargs)
1748
1875
  except try_exceptions as e: # noqa
1749
1876
  if log.isEnabledFor(logging.DEBUG):
1750
1877
  log.exception('command failed')
1878
+ return e
1879
+
1880
+
1881
+ def subprocess_try_call(
1882
+ *args: str,
1883
+ try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
1884
+ **kwargs: ta.Any,
1885
+ ) -> bool:
1886
+ if isinstance(_subprocess_try_run(
1887
+ subprocess_check_call,
1888
+ *args,
1889
+ try_exceptions=try_exceptions,
1890
+ **kwargs,
1891
+ ), Exception):
1751
1892
  return False
1752
1893
  else:
1753
1894
  return True
@@ -1758,12 +1899,15 @@ def subprocess_try_output(
1758
1899
  try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
1759
1900
  **kwargs: ta.Any,
1760
1901
  ) -> 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')
1902
+ if isinstance(ret := _subprocess_try_run(
1903
+ subprocess_check_output,
1904
+ *args,
1905
+ try_exceptions=try_exceptions,
1906
+ **kwargs,
1907
+ ), Exception):
1766
1908
  return None
1909
+ else:
1910
+ return ret
1767
1911
 
1768
1912
 
1769
1913
  def subprocess_try_output_str(*args: str, **kwargs: ta.Any) -> ta.Optional[str]:
@@ -1789,6 +1933,285 @@ def subprocess_close(
1789
1933
  proc.wait(timeout)
1790
1934
 
1791
1935
 
1936
+ ########################################
1937
+ # ../../../omlish/lite/asyncio/subprocesses.py
1938
+
1939
+
1940
+ ##
1941
+
1942
+
1943
+ @contextlib.asynccontextmanager
1944
+ async def asyncio_subprocess_popen(
1945
+ *cmd: str,
1946
+ shell: bool = False,
1947
+ timeout: ta.Optional[float] = None,
1948
+ **kwargs: ta.Any,
1949
+ ) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
1950
+ fac: ta.Any
1951
+ if shell:
1952
+ fac = functools.partial(
1953
+ asyncio.create_subprocess_shell,
1954
+ check_single(cmd),
1955
+ )
1956
+ else:
1957
+ fac = functools.partial(
1958
+ asyncio.create_subprocess_exec,
1959
+ *cmd,
1960
+ )
1961
+
1962
+ with subprocess_common_context(
1963
+ *cmd,
1964
+ shell=shell,
1965
+ timeout=timeout,
1966
+ **kwargs,
1967
+ ):
1968
+ proc: asyncio.subprocess.Process
1969
+ proc = await fac(**kwargs)
1970
+ try:
1971
+ yield proc
1972
+
1973
+ finally:
1974
+ await asyncio_maybe_timeout(proc.wait(), timeout)
1975
+
1976
+
1977
+ ##
1978
+
1979
+
1980
+ class AsyncioProcessCommunicator:
1981
+ def __init__(
1982
+ self,
1983
+ proc: asyncio.subprocess.Process,
1984
+ loop: ta.Optional[ta.Any] = None,
1985
+ ) -> None:
1986
+ super().__init__()
1987
+
1988
+ if loop is None:
1989
+ loop = asyncio.get_running_loop()
1990
+
1991
+ self._proc = proc
1992
+ self._loop = loop
1993
+
1994
+ self._transport: asyncio.base_subprocess.BaseSubprocessTransport = check_isinstance(
1995
+ proc._transport, # type: ignore # noqa
1996
+ asyncio.base_subprocess.BaseSubprocessTransport,
1997
+ )
1998
+
1999
+ @property
2000
+ def _debug(self) -> bool:
2001
+ return self._loop.get_debug()
2002
+
2003
+ async def _feed_stdin(self, input: bytes) -> None: # noqa
2004
+ stdin = check_not_none(self._proc.stdin)
2005
+ try:
2006
+ if input is not None:
2007
+ stdin.write(input)
2008
+ if self._debug:
2009
+ log.debug('%r communicate: feed stdin (%s bytes)', self, len(input))
2010
+
2011
+ await stdin.drain()
2012
+
2013
+ except (BrokenPipeError, ConnectionResetError) as exc:
2014
+ # communicate() ignores BrokenPipeError and ConnectionResetError. write() and drain() can raise these
2015
+ # exceptions.
2016
+ if self._debug:
2017
+ log.debug('%r communicate: stdin got %r', self, exc)
2018
+
2019
+ if self._debug:
2020
+ log.debug('%r communicate: close stdin', self)
2021
+
2022
+ stdin.close()
2023
+
2024
+ async def _noop(self) -> None:
2025
+ return None
2026
+
2027
+ async def _read_stream(self, fd: int) -> bytes:
2028
+ transport: ta.Any = check_not_none(self._transport.get_pipe_transport(fd))
2029
+
2030
+ if fd == 2:
2031
+ stream = check_not_none(self._proc.stderr)
2032
+ else:
2033
+ check_equal(fd, 1)
2034
+ stream = check_not_none(self._proc.stdout)
2035
+
2036
+ if self._debug:
2037
+ name = 'stdout' if fd == 1 else 'stderr'
2038
+ log.debug('%r communicate: read %s', self, name)
2039
+
2040
+ output = await stream.read()
2041
+
2042
+ if self._debug:
2043
+ name = 'stdout' if fd == 1 else 'stderr'
2044
+ log.debug('%r communicate: close %s', self, name)
2045
+
2046
+ transport.close()
2047
+
2048
+ return output
2049
+
2050
+ class Communication(ta.NamedTuple):
2051
+ stdout: ta.Optional[bytes]
2052
+ stderr: ta.Optional[bytes]
2053
+
2054
+ async def _communicate(
2055
+ self,
2056
+ input: ta.Any = None, # noqa
2057
+ ) -> Communication:
2058
+ stdin_fut: ta.Any
2059
+ if self._proc.stdin is not None:
2060
+ stdin_fut = self._feed_stdin(input)
2061
+ else:
2062
+ stdin_fut = self._noop()
2063
+
2064
+ stdout_fut: ta.Any
2065
+ if self._proc.stdout is not None:
2066
+ stdout_fut = self._read_stream(1)
2067
+ else:
2068
+ stdout_fut = self._noop()
2069
+
2070
+ stderr_fut: ta.Any
2071
+ if self._proc.stderr is not None:
2072
+ stderr_fut = self._read_stream(2)
2073
+ else:
2074
+ stderr_fut = self._noop()
2075
+
2076
+ stdin_res, stdout_res, stderr_res = await asyncio.gather(stdin_fut, stdout_fut, stderr_fut)
2077
+
2078
+ await self._proc.wait()
2079
+
2080
+ return AsyncioProcessCommunicator.Communication(stdout_res, stderr_res)
2081
+
2082
+ async def communicate(
2083
+ self,
2084
+ input: ta.Any = None, # noqa
2085
+ timeout: ta.Optional[float] = None,
2086
+ ) -> Communication:
2087
+ return await asyncio_maybe_timeout(self._communicate(input), timeout)
2088
+
2089
+
2090
+ async def asyncio_subprocess_communicate(
2091
+ proc: asyncio.subprocess.Process,
2092
+ input: ta.Any = None, # noqa
2093
+ timeout: ta.Optional[float] = None,
2094
+ ) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
2095
+ return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
2096
+
2097
+
2098
+ ##
2099
+
2100
+
2101
+ async def _asyncio_subprocess_check_run(
2102
+ *args: str,
2103
+ input: ta.Any = None, # noqa
2104
+ timeout: ta.Optional[float] = None,
2105
+ **kwargs: ta.Any,
2106
+ ) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
2107
+ args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
2108
+
2109
+ proc: asyncio.subprocess.Process
2110
+ async with asyncio_subprocess_popen(*args, **kwargs) as proc:
2111
+ stdout, stderr = await asyncio_subprocess_communicate(proc, input, timeout)
2112
+
2113
+ if proc.returncode:
2114
+ raise subprocess.CalledProcessError(
2115
+ proc.returncode,
2116
+ args,
2117
+ output=stdout,
2118
+ stderr=stderr,
2119
+ )
2120
+
2121
+ return stdout, stderr
2122
+
2123
+
2124
+ async def asyncio_subprocess_check_call(
2125
+ *args: str,
2126
+ stdout: ta.Any = sys.stderr,
2127
+ input: ta.Any = None, # noqa
2128
+ timeout: ta.Optional[float] = None,
2129
+ **kwargs: ta.Any,
2130
+ ) -> None:
2131
+ _, _ = await _asyncio_subprocess_check_run(
2132
+ *args,
2133
+ stdout=stdout,
2134
+ input=input,
2135
+ timeout=timeout,
2136
+ **kwargs,
2137
+ )
2138
+
2139
+
2140
+ async def asyncio_subprocess_check_output(
2141
+ *args: str,
2142
+ input: ta.Any = None, # noqa
2143
+ timeout: ta.Optional[float] = None,
2144
+ **kwargs: ta.Any,
2145
+ ) -> bytes:
2146
+ stdout, stderr = await _asyncio_subprocess_check_run(
2147
+ *args,
2148
+ stdout=asyncio.subprocess.PIPE,
2149
+ input=input,
2150
+ timeout=timeout,
2151
+ **kwargs,
2152
+ )
2153
+
2154
+ return check_not_none(stdout)
2155
+
2156
+
2157
+ async def asyncio_subprocess_check_output_str(*args: str, **kwargs: ta.Any) -> str:
2158
+ return (await asyncio_subprocess_check_output(*args, **kwargs)).decode().strip()
2159
+
2160
+
2161
+ ##
2162
+
2163
+
2164
+ async def _asyncio_subprocess_try_run(
2165
+ fn: ta.Callable[..., ta.Awaitable[T]],
2166
+ *args: ta.Any,
2167
+ try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
2168
+ **kwargs: ta.Any,
2169
+ ) -> ta.Union[T, Exception]:
2170
+ try:
2171
+ return await fn(*args, **kwargs)
2172
+ except try_exceptions as e: # noqa
2173
+ if log.isEnabledFor(logging.DEBUG):
2174
+ log.exception('command failed')
2175
+ return e
2176
+
2177
+
2178
+ async def asyncio_subprocess_try_call(
2179
+ *args: str,
2180
+ try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
2181
+ **kwargs: ta.Any,
2182
+ ) -> bool:
2183
+ if isinstance(await _asyncio_subprocess_try_run(
2184
+ asyncio_subprocess_check_call,
2185
+ *args,
2186
+ try_exceptions=try_exceptions,
2187
+ **kwargs,
2188
+ ), Exception):
2189
+ return False
2190
+ else:
2191
+ return True
2192
+
2193
+
2194
+ async def asyncio_subprocess_try_output(
2195
+ *args: str,
2196
+ try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
2197
+ **kwargs: ta.Any,
2198
+ ) -> ta.Optional[bytes]:
2199
+ if isinstance(ret := await _asyncio_subprocess_try_run(
2200
+ asyncio_subprocess_check_output,
2201
+ *args,
2202
+ try_exceptions=try_exceptions,
2203
+ **kwargs,
2204
+ ), Exception):
2205
+ return None
2206
+ else:
2207
+ return ret
2208
+
2209
+
2210
+ async def asyncio_subprocess_try_output_str(*args: str, **kwargs: ta.Any) -> ta.Optional[str]:
2211
+ out = await asyncio_subprocess_try_output(*args, **kwargs)
2212
+ return out.decode().strip() if out is not None else None
2213
+
2214
+
1792
2215
  ########################################
1793
2216
  # ../inspect.py
1794
2217
 
@@ -1823,7 +2246,6 @@ class InterpInspection:
1823
2246
 
1824
2247
 
1825
2248
  class InterpInspector:
1826
-
1827
2249
  def __init__(self) -> None:
1828
2250
  super().__init__()
1829
2251
 
@@ -1863,17 +2285,17 @@ class InterpInspector:
1863
2285
  def running(cls) -> 'InterpInspection':
1864
2286
  return cls._build_inspection(sys.executable, eval(cls._INSPECTION_CODE)) # noqa
1865
2287
 
1866
- def _inspect(self, exe: str) -> InterpInspection:
1867
- output = subprocess_check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
2288
+ async def _inspect(self, exe: str) -> InterpInspection:
2289
+ output = await asyncio_subprocess_check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
1868
2290
  return self._build_inspection(exe, output.decode())
1869
2291
 
1870
- def inspect(self, exe: str) -> ta.Optional[InterpInspection]:
2292
+ async def inspect(self, exe: str) -> ta.Optional[InterpInspection]:
1871
2293
  try:
1872
2294
  return self._cache[exe]
1873
2295
  except KeyError:
1874
2296
  ret: ta.Optional[InterpInspection]
1875
2297
  try:
1876
- ret = self._inspect(exe)
2298
+ ret = await self._inspect(exe)
1877
2299
  except Exception as e: # noqa
1878
2300
  if log.isEnabledFor(logging.DEBUG):
1879
2301
  log.exception('Failed to inspect interp: %s', exe)
@@ -1912,17 +2334,17 @@ class InterpProvider(abc.ABC):
1912
2334
  setattr(cls, 'name', snake_case(cls.__name__[:-len(sfx)]))
1913
2335
 
1914
2336
  @abc.abstractmethod
1915
- def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
2337
+ def get_installed_versions(self, spec: InterpSpecifier) -> ta.Awaitable[ta.Sequence[InterpVersion]]:
1916
2338
  raise NotImplementedError
1917
2339
 
1918
2340
  @abc.abstractmethod
1919
- def get_installed_version(self, version: InterpVersion) -> Interp:
2341
+ def get_installed_version(self, version: InterpVersion) -> ta.Awaitable[Interp]:
1920
2342
  raise NotImplementedError
1921
2343
 
1922
- def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
2344
+ async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
1923
2345
  return []
1924
2346
 
1925
- def install_version(self, version: InterpVersion) -> Interp:
2347
+ async def install_version(self, version: InterpVersion) -> Interp:
1926
2348
  raise TypeError
1927
2349
 
1928
2350
 
@@ -1934,10 +2356,10 @@ class RunningInterpProvider(InterpProvider):
1934
2356
  def version(self) -> InterpVersion:
1935
2357
  return InterpInspector.running().iv
1936
2358
 
1937
- def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
2359
+ async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
1938
2360
  return [self.version()]
1939
2361
 
1940
- def get_installed_version(self, version: InterpVersion) -> Interp:
2362
+ async def get_installed_version(self, version: InterpVersion) -> Interp:
1941
2363
  if version != self.version():
1942
2364
  raise KeyError(version)
1943
2365
  return Interp(
@@ -1965,7 +2387,6 @@ TODO:
1965
2387
 
1966
2388
 
1967
2389
  class Pyenv:
1968
-
1969
2390
  def __init__(
1970
2391
  self,
1971
2392
  *,
@@ -1978,13 +2399,13 @@ class Pyenv:
1978
2399
 
1979
2400
  self._root_kw = root
1980
2401
 
1981
- @cached_nullary
1982
- def root(self) -> ta.Optional[str]:
2402
+ @async_cached_nullary
2403
+ async def root(self) -> ta.Optional[str]:
1983
2404
  if self._root_kw is not None:
1984
2405
  return self._root_kw
1985
2406
 
1986
2407
  if shutil.which('pyenv'):
1987
- return subprocess_check_output_str('pyenv', 'root')
2408
+ return await asyncio_subprocess_check_output_str('pyenv', 'root')
1988
2409
 
1989
2410
  d = os.path.expanduser('~/.pyenv')
1990
2411
  if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
@@ -1992,12 +2413,12 @@ class Pyenv:
1992
2413
 
1993
2414
  return None
1994
2415
 
1995
- @cached_nullary
1996
- def exe(self) -> str:
1997
- return os.path.join(check_not_none(self.root()), 'bin', 'pyenv')
2416
+ @async_cached_nullary
2417
+ async def exe(self) -> str:
2418
+ return os.path.join(check_not_none(await self.root()), 'bin', 'pyenv')
1998
2419
 
1999
- def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
2000
- if (root := self.root()) is None:
2420
+ async def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
2421
+ if (root := await self.root()) is None:
2001
2422
  return []
2002
2423
  ret = []
2003
2424
  vp = os.path.join(root, 'versions')
@@ -2009,11 +2430,11 @@ class Pyenv:
2009
2430
  ret.append((dn, ep))
2010
2431
  return ret
2011
2432
 
2012
- def installable_versions(self) -> ta.List[str]:
2013
- if self.root() is None:
2433
+ async def installable_versions(self) -> ta.List[str]:
2434
+ if await self.root() is None:
2014
2435
  return []
2015
2436
  ret = []
2016
- s = subprocess_check_output_str(self.exe(), 'install', '--list')
2437
+ s = await asyncio_subprocess_check_output_str(await self.exe(), 'install', '--list')
2017
2438
  for l in s.splitlines():
2018
2439
  if not l.startswith(' '):
2019
2440
  continue
@@ -2023,12 +2444,12 @@ class Pyenv:
2023
2444
  ret.append(l)
2024
2445
  return ret
2025
2446
 
2026
- def update(self) -> bool:
2027
- if (root := self.root()) is None:
2447
+ async def update(self) -> bool:
2448
+ if (root := await self.root()) is None:
2028
2449
  return False
2029
2450
  if not os.path.isdir(os.path.join(root, '.git')):
2030
2451
  return False
2031
- subprocess_check_call('git', 'pull', cwd=root)
2452
+ await asyncio_subprocess_check_call('git', 'pull', cwd=root)
2032
2453
  return True
2033
2454
 
2034
2455
 
@@ -2089,17 +2510,16 @@ THREADED_PYENV_INSTALL_OPTS = PyenvInstallOpts(conf_opts=['--disable-gil'])
2089
2510
 
2090
2511
  class PyenvInstallOptsProvider(abc.ABC):
2091
2512
  @abc.abstractmethod
2092
- def opts(self) -> PyenvInstallOpts:
2513
+ def opts(self) -> ta.Awaitable[PyenvInstallOpts]:
2093
2514
  raise NotImplementedError
2094
2515
 
2095
2516
 
2096
2517
  class LinuxPyenvInstallOpts(PyenvInstallOptsProvider):
2097
- def opts(self) -> PyenvInstallOpts:
2518
+ async def opts(self) -> PyenvInstallOpts:
2098
2519
  return PyenvInstallOpts()
2099
2520
 
2100
2521
 
2101
2522
  class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
2102
-
2103
2523
  @cached_nullary
2104
2524
  def framework_opts(self) -> PyenvInstallOpts:
2105
2525
  return PyenvInstallOpts(conf_opts=['--enable-framework'])
@@ -2115,12 +2535,12 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
2115
2535
  'zlib',
2116
2536
  ]
2117
2537
 
2118
- @cached_nullary
2119
- def brew_deps_opts(self) -> PyenvInstallOpts:
2538
+ @async_cached_nullary
2539
+ async def brew_deps_opts(self) -> PyenvInstallOpts:
2120
2540
  cflags = []
2121
2541
  ldflags = []
2122
2542
  for dep in self.BREW_DEPS:
2123
- dep_prefix = subprocess_check_output_str('brew', '--prefix', dep)
2543
+ dep_prefix = await asyncio_subprocess_check_output_str('brew', '--prefix', dep)
2124
2544
  cflags.append(f'-I{dep_prefix}/include')
2125
2545
  ldflags.append(f'-L{dep_prefix}/lib')
2126
2546
  return PyenvInstallOpts(
@@ -2128,13 +2548,13 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
2128
2548
  ldflags=ldflags,
2129
2549
  )
2130
2550
 
2131
- @cached_nullary
2132
- def brew_tcl_opts(self) -> PyenvInstallOpts:
2133
- if subprocess_try_output('brew', '--prefix', 'tcl-tk') is None:
2551
+ @async_cached_nullary
2552
+ async def brew_tcl_opts(self) -> PyenvInstallOpts:
2553
+ if await asyncio_subprocess_try_output('brew', '--prefix', 'tcl-tk') is None:
2134
2554
  return PyenvInstallOpts()
2135
2555
 
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')
2556
+ tcl_tk_prefix = await asyncio_subprocess_check_output_str('brew', '--prefix', 'tcl-tk')
2557
+ tcl_tk_ver_str = await asyncio_subprocess_check_output_str('brew', 'ls', '--versions', 'tcl-tk')
2138
2558
  tcl_tk_ver = '.'.join(tcl_tk_ver_str.split()[1].split('.')[:2])
2139
2559
 
2140
2560
  return PyenvInstallOpts(conf_opts=[
@@ -2149,11 +2569,11 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
2149
2569
  # pkg_config_path += ':' + os.environ['PKG_CONFIG_PATH']
2150
2570
  # return PyenvInstallOpts(env={'PKG_CONFIG_PATH': pkg_config_path})
2151
2571
 
2152
- def opts(self) -> PyenvInstallOpts:
2572
+ async def opts(self) -> PyenvInstallOpts:
2153
2573
  return PyenvInstallOpts().merge(
2154
2574
  self.framework_opts(),
2155
- self.brew_deps_opts(),
2156
- self.brew_tcl_opts(),
2575
+ await self.brew_deps_opts(),
2576
+ await self.brew_tcl_opts(),
2157
2577
  # self.brew_ssl_opts(),
2158
2578
  )
2159
2579
 
@@ -2185,20 +2605,8 @@ class PyenvVersionInstaller:
2185
2605
  ) -> None:
2186
2606
  super().__init__()
2187
2607
 
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
2608
  self._version = version
2201
- self._opts = opts
2609
+ self._given_opts = opts
2202
2610
  self._interp_opts = interp_opts
2203
2611
  self._given_install_name = install_name
2204
2612
 
@@ -2209,9 +2617,21 @@ class PyenvVersionInstaller:
2209
2617
  def version(self) -> str:
2210
2618
  return self._version
2211
2619
 
2212
- @property
2213
- def opts(self) -> PyenvInstallOpts:
2214
- return self._opts
2620
+ @async_cached_nullary
2621
+ async def opts(self) -> PyenvInstallOpts:
2622
+ opts = self._given_opts
2623
+ if self._no_default_opts:
2624
+ if opts is None:
2625
+ opts = PyenvInstallOpts()
2626
+ else:
2627
+ lst = [self._given_opts if self._given_opts is not None else DEFAULT_PYENV_INSTALL_OPTS]
2628
+ if self._interp_opts.debug:
2629
+ lst.append(DEBUG_PYENV_INSTALL_OPTS)
2630
+ if self._interp_opts.threaded:
2631
+ lst.append(THREADED_PYENV_INSTALL_OPTS)
2632
+ lst.append(await PLATFORM_PYENV_INSTALL_OPTS[sys.platform].opts())
2633
+ opts = PyenvInstallOpts().merge(*lst)
2634
+ return opts
2215
2635
 
2216
2636
  @cached_nullary
2217
2637
  def install_name(self) -> str:
@@ -2219,17 +2639,18 @@ class PyenvVersionInstaller:
2219
2639
  return self._given_install_name
2220
2640
  return self._version + ('-debug' if self._interp_opts.debug else '')
2221
2641
 
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()))
2642
+ @async_cached_nullary
2643
+ async def install_dir(self) -> str:
2644
+ return str(os.path.join(check_not_none(await self._pyenv.root()), 'versions', self.install_name()))
2225
2645
 
2226
- @cached_nullary
2227
- def install(self) -> str:
2228
- env = {**os.environ, **self._opts.env}
2646
+ @async_cached_nullary
2647
+ async def install(self) -> str:
2648
+ opts = await self.opts()
2649
+ env = {**os.environ, **opts.env}
2229
2650
  for k, l in [
2230
- ('CFLAGS', self._opts.cflags),
2231
- ('LDFLAGS', self._opts.ldflags),
2232
- ('PYTHON_CONFIGURE_OPTS', self._opts.conf_opts),
2651
+ ('CFLAGS', opts.cflags),
2652
+ ('LDFLAGS', opts.ldflags),
2653
+ ('PYTHON_CONFIGURE_OPTS', opts.conf_opts),
2233
2654
  ]:
2234
2655
  v = ' '.join(l)
2235
2656
  if k in os.environ:
@@ -2237,13 +2658,13 @@ class PyenvVersionInstaller:
2237
2658
  env[k] = v
2238
2659
 
2239
2660
  conf_args = [
2240
- *self._opts.opts,
2661
+ *opts.opts,
2241
2662
  self._version,
2242
2663
  ]
2243
2664
 
2244
2665
  if self._given_install_name is not None:
2245
2666
  full_args = [
2246
- os.path.join(check_not_none(self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'),
2667
+ os.path.join(check_not_none(await self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'), # noqa
2247
2668
  *conf_args,
2248
2669
  self.install_dir(),
2249
2670
  ]
@@ -2254,12 +2675,12 @@ class PyenvVersionInstaller:
2254
2675
  *conf_args,
2255
2676
  ]
2256
2677
 
2257
- subprocess_check_call(
2678
+ await asyncio_subprocess_check_call(
2258
2679
  *full_args,
2259
2680
  env=env,
2260
2681
  )
2261
2682
 
2262
- exe = os.path.join(self.install_dir(), 'bin', 'python')
2683
+ exe = os.path.join(await self.install_dir(), 'bin', 'python')
2263
2684
  if not os.path.isfile(exe):
2264
2685
  raise RuntimeError(f'Interpreter not found: {exe}')
2265
2686
  return exe
@@ -2269,7 +2690,6 @@ class PyenvVersionInstaller:
2269
2690
 
2270
2691
 
2271
2692
  class PyenvInterpProvider(InterpProvider):
2272
-
2273
2693
  def __init__(
2274
2694
  self,
2275
2695
  pyenv: Pyenv = Pyenv(),
@@ -2312,11 +2732,11 @@ class PyenvInterpProvider(InterpProvider):
2312
2732
  exe: str
2313
2733
  version: InterpVersion
2314
2734
 
2315
- def _make_installed(self, vn: str, ep: str) -> ta.Optional[Installed]:
2735
+ async def _make_installed(self, vn: str, ep: str) -> ta.Optional[Installed]:
2316
2736
  iv: ta.Optional[InterpVersion]
2317
2737
  if self._inspect:
2318
2738
  try:
2319
- iv = check_not_none(self._inspector.inspect(ep)).iv
2739
+ iv = check_not_none(await self._inspector.inspect(ep)).iv
2320
2740
  except Exception as e: # noqa
2321
2741
  return None
2322
2742
  else:
@@ -2329,10 +2749,10 @@ class PyenvInterpProvider(InterpProvider):
2329
2749
  version=iv,
2330
2750
  )
2331
2751
 
2332
- def installed(self) -> ta.Sequence[Installed]:
2752
+ async def installed(self) -> ta.Sequence[Installed]:
2333
2753
  ret: ta.List[PyenvInterpProvider.Installed] = []
2334
- for vn, ep in self._pyenv.version_exes():
2335
- if (i := self._make_installed(vn, ep)) is None:
2754
+ for vn, ep in await self._pyenv.version_exes():
2755
+ if (i := await self._make_installed(vn, ep)) is None:
2336
2756
  log.debug('Invalid pyenv version: %s', vn)
2337
2757
  continue
2338
2758
  ret.append(i)
@@ -2340,11 +2760,11 @@ class PyenvInterpProvider(InterpProvider):
2340
2760
 
2341
2761
  #
2342
2762
 
2343
- def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
2344
- return [i.version for i in self.installed()]
2763
+ async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
2764
+ return [i.version for i in await self.installed()]
2345
2765
 
2346
- def get_installed_version(self, version: InterpVersion) -> Interp:
2347
- for i in self.installed():
2766
+ async def get_installed_version(self, version: InterpVersion) -> Interp:
2767
+ for i in await self.installed():
2348
2768
  if i.version == version:
2349
2769
  return Interp(
2350
2770
  exe=i.exe,
@@ -2354,10 +2774,10 @@ class PyenvInterpProvider(InterpProvider):
2354
2774
 
2355
2775
  #
2356
2776
 
2357
- def _get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
2777
+ async def _get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
2358
2778
  lst = []
2359
2779
 
2360
- for vs in self._pyenv.installable_versions():
2780
+ for vs in await self._pyenv.installable_versions():
2361
2781
  if (iv := self.guess_version(vs)) is None:
2362
2782
  continue
2363
2783
  if iv.opts.debug:
@@ -2367,16 +2787,16 @@ class PyenvInterpProvider(InterpProvider):
2367
2787
 
2368
2788
  return lst
2369
2789
 
2370
- def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
2371
- lst = self._get_installable_versions(spec)
2790
+ async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
2791
+ lst = await self._get_installable_versions(spec)
2372
2792
 
2373
2793
  if self._try_update and not any(v in spec for v in lst):
2374
2794
  if self._pyenv.update():
2375
- lst = self._get_installable_versions(spec)
2795
+ lst = await self._get_installable_versions(spec)
2376
2796
 
2377
2797
  return lst
2378
2798
 
2379
- def install_version(self, version: InterpVersion) -> Interp:
2799
+ async def install_version(self, version: InterpVersion) -> Interp:
2380
2800
  inst_version = str(version.version)
2381
2801
  inst_opts = version.opts
2382
2802
  if inst_opts.threaded:
@@ -2388,7 +2808,7 @@ class PyenvInterpProvider(InterpProvider):
2388
2808
  interp_opts=inst_opts,
2389
2809
  )
2390
2810
 
2391
- exe = installer.install()
2811
+ exe = await installer.install()
2392
2812
  return Interp(exe, version)
2393
2813
 
2394
2814
 
@@ -2467,7 +2887,7 @@ class SystemInterpProvider(InterpProvider):
2467
2887
 
2468
2888
  #
2469
2889
 
2470
- def get_exe_version(self, exe: str) -> ta.Optional[InterpVersion]:
2890
+ async def get_exe_version(self, exe: str) -> ta.Optional[InterpVersion]:
2471
2891
  if not self.inspect:
2472
2892
  s = os.path.basename(exe)
2473
2893
  if s.startswith('python'):
@@ -2477,13 +2897,13 @@ class SystemInterpProvider(InterpProvider):
2477
2897
  return InterpVersion.parse(s)
2478
2898
  except InvalidVersion:
2479
2899
  pass
2480
- ii = self.inspector.inspect(exe)
2900
+ ii = await self.inspector.inspect(exe)
2481
2901
  return ii.iv if ii is not None else None
2482
2902
 
2483
- def exe_versions(self) -> ta.Sequence[ta.Tuple[str, InterpVersion]]:
2903
+ async def exe_versions(self) -> ta.Sequence[ta.Tuple[str, InterpVersion]]:
2484
2904
  lst = []
2485
2905
  for e in self.exes():
2486
- if (ev := self.get_exe_version(e)) is None:
2906
+ if (ev := await self.get_exe_version(e)) is None:
2487
2907
  log.debug('Invalid system version: %s', e)
2488
2908
  continue
2489
2909
  lst.append((e, ev))
@@ -2491,11 +2911,11 @@ class SystemInterpProvider(InterpProvider):
2491
2911
 
2492
2912
  #
2493
2913
 
2494
- def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
2495
- return [ev for e, ev in self.exe_versions()]
2914
+ async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
2915
+ return [ev for e, ev in await self.exe_versions()]
2496
2916
 
2497
- def get_installed_version(self, version: InterpVersion) -> Interp:
2498
- for e, ev in self.exe_versions():
2917
+ async def get_installed_version(self, version: InterpVersion) -> Interp:
2918
+ for e, ev in await self.exe_versions():
2499
2919
  if ev != version:
2500
2920
  continue
2501
2921
  return Interp(
@@ -2520,13 +2940,14 @@ class InterpResolver:
2520
2940
  providers: ta.Sequence[ta.Tuple[str, InterpProvider]],
2521
2941
  ) -> None:
2522
2942
  super().__init__()
2943
+
2523
2944
  self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers)
2524
2945
 
2525
- def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
2946
+ async def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
2526
2947
  lst = [
2527
2948
  (i, si)
2528
2949
  for i, p in enumerate(self._providers.values())
2529
- for si in p.get_installed_versions(spec)
2950
+ for si in await p.get_installed_versions(spec)
2530
2951
  if spec.contains(si)
2531
2952
  ]
2532
2953
 
@@ -2538,16 +2959,16 @@ class InterpResolver:
2538
2959
  bp = list(self._providers.values())[bi]
2539
2960
  return (bp, bv)
2540
2961
 
2541
- def resolve(
2962
+ async def resolve(
2542
2963
  self,
2543
2964
  spec: InterpSpecifier,
2544
2965
  *,
2545
2966
  install: bool = False,
2546
2967
  ) -> ta.Optional[Interp]:
2547
- tup = self._resolve_installed(spec)
2968
+ tup = await self._resolve_installed(spec)
2548
2969
  if tup is not None:
2549
2970
  bp, bv = tup
2550
- return bp.get_installed_version(bv)
2971
+ return await bp.get_installed_version(bv)
2551
2972
 
2552
2973
  if not install:
2553
2974
  return None
@@ -2555,21 +2976,21 @@ class InterpResolver:
2555
2976
  tp = list(self._providers.values())[0] # noqa
2556
2977
 
2557
2978
  sv = sorted(
2558
- [s for s in tp.get_installable_versions(spec) if s in spec],
2979
+ [s for s in await tp.get_installable_versions(spec) if s in spec],
2559
2980
  key=lambda s: s.version,
2560
2981
  )
2561
2982
  if not sv:
2562
2983
  return None
2563
2984
 
2564
2985
  bv = sv[-1]
2565
- return tp.install_version(bv)
2986
+ return await tp.install_version(bv)
2566
2987
 
2567
- def list(self, spec: InterpSpecifier) -> None:
2988
+ async def list(self, spec: InterpSpecifier) -> None:
2568
2989
  print('installed:')
2569
2990
  for n, p in self._providers.items():
2570
2991
  lst = [
2571
2992
  si
2572
- for si in p.get_installed_versions(spec)
2993
+ for si in await p.get_installed_versions(spec)
2573
2994
  if spec.contains(si)
2574
2995
  ]
2575
2996
  if lst:
@@ -2583,7 +3004,7 @@ class InterpResolver:
2583
3004
  for n, p in self._providers.items():
2584
3005
  lst = [
2585
3006
  si
2586
- for si in p.get_installable_versions(spec)
3007
+ for si in await p.get_installable_versions(spec)
2587
3008
  if spec.contains(si)
2588
3009
  ]
2589
3010
  if lst:
@@ -2606,20 +3027,20 @@ DEFAULT_INTERP_RESOLVER = InterpResolver([(p.name, p) for p in [
2606
3027
  # cli.py
2607
3028
 
2608
3029
 
2609
- def _list_cmd(args) -> None:
3030
+ async def _list_cmd(args) -> None:
2610
3031
  r = DEFAULT_INTERP_RESOLVER
2611
3032
  s = InterpSpecifier.parse(args.version)
2612
- r.list(s)
3033
+ await r.list(s)
2613
3034
 
2614
3035
 
2615
- def _resolve_cmd(args) -> None:
3036
+ async def _resolve_cmd(args) -> None:
2616
3037
  if args.provider:
2617
3038
  p = INTERP_PROVIDER_TYPES_BY_NAME[args.provider]()
2618
3039
  r = InterpResolver([(p.name, p)])
2619
3040
  else:
2620
3041
  r = DEFAULT_INTERP_RESOLVER
2621
3042
  s = InterpSpecifier.parse(args.version)
2622
- print(check_not_none(r.resolve(s, install=bool(args.install))).exe)
3043
+ print(check_not_none(await r.resolve(s, install=bool(args.install))).exe)
2623
3044
 
2624
3045
 
2625
3046
  def _build_parser() -> argparse.ArgumentParser:
@@ -2642,7 +3063,7 @@ def _build_parser() -> argparse.ArgumentParser:
2642
3063
  return parser
2643
3064
 
2644
3065
 
2645
- def _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
3066
+ async def _async_main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
2646
3067
  check_runtime_version()
2647
3068
  configure_standard_logging()
2648
3069
 
@@ -2651,7 +3072,11 @@ def _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
2651
3072
  if not getattr(args, 'func', None):
2652
3073
  parser.print_help()
2653
3074
  else:
2654
- args.func(args)
3075
+ await args.func(args)
3076
+
3077
+
3078
+ def _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
3079
+ asyncio.run(_async_main(argv))
2655
3080
 
2656
3081
 
2657
3082
  if __name__ == '__main__':