omdev 0.0.0.dev154__py3-none-any.whl → 0.0.0.dev156__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 +1 -1
- omdev/interp/inspect.py +2 -2
- omdev/interp/pyenv.py +9 -11
- omdev/manifests/__init__.py +1 -0
- omdev/manifests/build.py +0 -1
- omdev/manifests/main.py +1 -0
- omdev/pyproject/cli.py +3 -3
- omdev/pyproject/pkg.py +4 -4
- omdev/pyproject/venvs.py +4 -4
- omdev/scripts/interp.py +307 -282
- omdev/scripts/pyproject.py +322 -292
- omdev/tools/docker.py +14 -5
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/RECORD +18 -18
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev154.dist-info → omdev-0.0.0.dev156.dist-info}/top_level.txt +0 -0
omdev/scripts/interp.py
CHANGED
|
@@ -560,8 +560,6 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
|
560
560
|
"""
|
|
561
561
|
TODO:
|
|
562
562
|
- def maybe(v: lang.Maybe[T])
|
|
563
|
-
- patch / override lite.check ?
|
|
564
|
-
- checker interface?
|
|
565
563
|
"""
|
|
566
564
|
|
|
567
565
|
|
|
@@ -2082,209 +2080,226 @@ SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
|
|
2082
2080
|
_SUBPROCESS_SHELL_WRAP_EXECS = False
|
|
2083
2081
|
|
|
2084
2082
|
|
|
2085
|
-
def subprocess_shell_wrap_exec(*
|
|
2086
|
-
return ('sh', '-c', ' '.join(map(shlex.quote,
|
|
2083
|
+
def subprocess_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
|
2084
|
+
return ('sh', '-c', ' '.join(map(shlex.quote, cmd)))
|
|
2087
2085
|
|
|
2088
2086
|
|
|
2089
|
-
def subprocess_maybe_shell_wrap_exec(*
|
|
2087
|
+
def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
|
2090
2088
|
if _SUBPROCESS_SHELL_WRAP_EXECS or is_debugger_attached():
|
|
2091
|
-
return subprocess_shell_wrap_exec(*
|
|
2089
|
+
return subprocess_shell_wrap_exec(*cmd)
|
|
2092
2090
|
else:
|
|
2093
|
-
return
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
def prepare_subprocess_invocation(
|
|
2097
|
-
*args: str,
|
|
2098
|
-
env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
2099
|
-
extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
2100
|
-
quiet: bool = False,
|
|
2101
|
-
shell: bool = False,
|
|
2102
|
-
**kwargs: ta.Any,
|
|
2103
|
-
) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
|
|
2104
|
-
log.debug('prepare_subprocess_invocation: args=%r', args)
|
|
2105
|
-
if extra_env:
|
|
2106
|
-
log.debug('prepare_subprocess_invocation: extra_env=%r', extra_env)
|
|
2107
|
-
|
|
2108
|
-
if extra_env:
|
|
2109
|
-
env = {**(env if env is not None else os.environ), **extra_env}
|
|
2110
|
-
|
|
2111
|
-
if quiet and 'stderr' not in kwargs:
|
|
2112
|
-
if not log.isEnabledFor(logging.DEBUG):
|
|
2113
|
-
kwargs['stderr'] = subprocess.DEVNULL
|
|
2114
|
-
|
|
2115
|
-
if not shell:
|
|
2116
|
-
args = subprocess_maybe_shell_wrap_exec(*args)
|
|
2117
|
-
|
|
2118
|
-
return args, dict(
|
|
2119
|
-
env=env,
|
|
2120
|
-
shell=shell,
|
|
2121
|
-
**kwargs,
|
|
2122
|
-
)
|
|
2091
|
+
return cmd
|
|
2123
2092
|
|
|
2124
2093
|
|
|
2125
2094
|
##
|
|
2126
2095
|
|
|
2127
2096
|
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2097
|
+
def subprocess_close(
|
|
2098
|
+
proc: subprocess.Popen,
|
|
2099
|
+
timeout: ta.Optional[float] = None,
|
|
2100
|
+
) -> None:
|
|
2101
|
+
# TODO: terminate, sleep, kill
|
|
2102
|
+
if proc.stdout:
|
|
2103
|
+
proc.stdout.close()
|
|
2104
|
+
if proc.stderr:
|
|
2105
|
+
proc.stderr.close()
|
|
2106
|
+
if proc.stdin:
|
|
2107
|
+
proc.stdin.close()
|
|
2138
2108
|
|
|
2139
|
-
|
|
2140
|
-
end_time = time.time()
|
|
2141
|
-
elapsed_s = end_time - start_time
|
|
2142
|
-
log.debug('subprocess_common_context.finally: elapsed_s=%f args=%r', elapsed_s, args)
|
|
2109
|
+
proc.wait(timeout)
|
|
2143
2110
|
|
|
2144
2111
|
|
|
2145
2112
|
##
|
|
2146
2113
|
|
|
2147
2114
|
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
stdout: ta.Any = sys.stderr,
|
|
2151
|
-
**kwargs: ta.Any,
|
|
2152
|
-
) -> None:
|
|
2153
|
-
args, kwargs = prepare_subprocess_invocation(*args, stdout=stdout, **kwargs)
|
|
2154
|
-
with subprocess_common_context(*args, **kwargs):
|
|
2155
|
-
return subprocess.check_call(args, **kwargs) # type: ignore
|
|
2115
|
+
class AbstractSubprocesses(abc.ABC): # noqa
|
|
2116
|
+
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = log
|
|
2156
2117
|
|
|
2118
|
+
def __init__(
|
|
2119
|
+
self,
|
|
2120
|
+
*,
|
|
2121
|
+
log: ta.Optional[logging.Logger] = None,
|
|
2122
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
|
2123
|
+
) -> None:
|
|
2124
|
+
super().__init__()
|
|
2157
2125
|
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
**kwargs: ta.Any,
|
|
2161
|
-
) -> bytes:
|
|
2162
|
-
args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
|
|
2163
|
-
with subprocess_common_context(*args, **kwargs):
|
|
2164
|
-
return subprocess.check_output(args, **kwargs)
|
|
2126
|
+
self._log = log if log is not None else self.DEFAULT_LOGGER
|
|
2127
|
+
self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
|
|
2165
2128
|
|
|
2129
|
+
#
|
|
2166
2130
|
|
|
2167
|
-
def
|
|
2168
|
-
|
|
2131
|
+
def prepare_args(
|
|
2132
|
+
self,
|
|
2133
|
+
*cmd: str,
|
|
2134
|
+
env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
2135
|
+
extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
2136
|
+
quiet: bool = False,
|
|
2137
|
+
shell: bool = False,
|
|
2138
|
+
**kwargs: ta.Any,
|
|
2139
|
+
) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
|
|
2140
|
+
if self._log:
|
|
2141
|
+
self._log.debug('Subprocesses.prepare_args: cmd=%r', cmd)
|
|
2142
|
+
if extra_env:
|
|
2143
|
+
self._log.debug('Subprocesses.prepare_args: extra_env=%r', extra_env)
|
|
2144
|
+
|
|
2145
|
+
if extra_env:
|
|
2146
|
+
env = {**(env if env is not None else os.environ), **extra_env}
|
|
2147
|
+
|
|
2148
|
+
if quiet and 'stderr' not in kwargs:
|
|
2149
|
+
if self._log and not self._log.isEnabledFor(logging.DEBUG):
|
|
2150
|
+
kwargs['stderr'] = subprocess.DEVNULL
|
|
2151
|
+
|
|
2152
|
+
if not shell:
|
|
2153
|
+
cmd = subprocess_maybe_shell_wrap_exec(*cmd)
|
|
2154
|
+
|
|
2155
|
+
return cmd, dict(
|
|
2156
|
+
env=env,
|
|
2157
|
+
shell=shell,
|
|
2158
|
+
**kwargs,
|
|
2159
|
+
)
|
|
2169
2160
|
|
|
2161
|
+
@contextlib.contextmanager
|
|
2162
|
+
def wrap_call(self, *cmd: ta.Any, **kwargs: ta.Any) -> ta.Iterator[None]:
|
|
2163
|
+
start_time = time.time()
|
|
2164
|
+
try:
|
|
2165
|
+
if self._log:
|
|
2166
|
+
self._log.debug('Subprocesses.wrap_call.try: cmd=%r', cmd)
|
|
2167
|
+
yield
|
|
2170
2168
|
|
|
2171
|
-
|
|
2169
|
+
except Exception as exc: # noqa
|
|
2170
|
+
if self._log:
|
|
2171
|
+
self._log.debug('Subprocesses.wrap_call.except: exc=%r', exc)
|
|
2172
|
+
raise
|
|
2172
2173
|
|
|
2174
|
+
finally:
|
|
2175
|
+
end_time = time.time()
|
|
2176
|
+
elapsed_s = end_time - start_time
|
|
2177
|
+
if self._log:
|
|
2178
|
+
self._log.debug('sSubprocesses.wrap_call.finally: elapsed_s=%f cmd=%r', elapsed_s, cmd)
|
|
2173
2179
|
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2180
|
+
@contextlib.contextmanager
|
|
2181
|
+
def prepare_and_wrap(
|
|
2182
|
+
self,
|
|
2183
|
+
*cmd: ta.Any,
|
|
2184
|
+
**kwargs: ta.Any,
|
|
2185
|
+
) -> ta.Iterator[ta.Tuple[
|
|
2186
|
+
ta.Tuple[ta.Any, ...],
|
|
2187
|
+
ta.Dict[str, ta.Any],
|
|
2188
|
+
]]:
|
|
2189
|
+
cmd, kwargs = self.prepare_args(*cmd, **kwargs)
|
|
2190
|
+
with self.wrap_call(*cmd, **kwargs):
|
|
2191
|
+
yield cmd, kwargs
|
|
2178
2192
|
|
|
2193
|
+
#
|
|
2179
2194
|
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
**kwargs: ta.Any,
|
|
2185
|
-
) -> ta.Union[T, Exception]:
|
|
2186
|
-
try:
|
|
2187
|
-
return fn(*args, **kwargs)
|
|
2188
|
-
except try_exceptions as e: # noqa
|
|
2189
|
-
if log.isEnabledFor(logging.DEBUG):
|
|
2190
|
-
log.exception('command failed')
|
|
2191
|
-
return e
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
def subprocess_try_call(
|
|
2195
|
-
*args: str,
|
|
2196
|
-
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
2197
|
-
**kwargs: ta.Any,
|
|
2198
|
-
) -> bool:
|
|
2199
|
-
if isinstance(_subprocess_try_run(
|
|
2200
|
-
subprocess_check_call,
|
|
2201
|
-
*args,
|
|
2202
|
-
try_exceptions=try_exceptions,
|
|
2203
|
-
**kwargs,
|
|
2204
|
-
), Exception):
|
|
2205
|
-
return False
|
|
2206
|
-
else:
|
|
2207
|
-
return True
|
|
2195
|
+
DEFAULT_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
|
|
2196
|
+
FileNotFoundError,
|
|
2197
|
+
subprocess.CalledProcessError,
|
|
2198
|
+
)
|
|
2208
2199
|
|
|
2200
|
+
def try_fn(
|
|
2201
|
+
self,
|
|
2202
|
+
fn: ta.Callable[..., T],
|
|
2203
|
+
*cmd: str,
|
|
2204
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
|
2205
|
+
**kwargs: ta.Any,
|
|
2206
|
+
) -> ta.Union[T, Exception]:
|
|
2207
|
+
if try_exceptions is None:
|
|
2208
|
+
try_exceptions = self._try_exceptions
|
|
2209
2209
|
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
2213
|
-
**kwargs: ta.Any,
|
|
2214
|
-
) -> ta.Optional[bytes]:
|
|
2215
|
-
if isinstance(ret := _subprocess_try_run(
|
|
2216
|
-
subprocess_check_output,
|
|
2217
|
-
*args,
|
|
2218
|
-
try_exceptions=try_exceptions,
|
|
2219
|
-
**kwargs,
|
|
2220
|
-
), Exception):
|
|
2221
|
-
return None
|
|
2222
|
-
else:
|
|
2223
|
-
return ret
|
|
2210
|
+
try:
|
|
2211
|
+
return fn(*cmd, **kwargs)
|
|
2224
2212
|
|
|
2213
|
+
except try_exceptions as e: # noqa
|
|
2214
|
+
if self._log and self._log.isEnabledFor(logging.DEBUG):
|
|
2215
|
+
self._log.exception('command failed')
|
|
2216
|
+
return e
|
|
2225
2217
|
|
|
2226
|
-
def
|
|
2227
|
-
|
|
2228
|
-
|
|
2218
|
+
async def async_try_fn(
|
|
2219
|
+
self,
|
|
2220
|
+
fn: ta.Callable[..., ta.Awaitable[T]],
|
|
2221
|
+
*cmd: ta.Any,
|
|
2222
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
|
2223
|
+
**kwargs: ta.Any,
|
|
2224
|
+
) -> ta.Union[T, Exception]:
|
|
2225
|
+
if try_exceptions is None:
|
|
2226
|
+
try_exceptions = self._try_exceptions
|
|
2227
|
+
|
|
2228
|
+
try:
|
|
2229
|
+
return await fn(*cmd, **kwargs)
|
|
2230
|
+
|
|
2231
|
+
except try_exceptions as e: # noqa
|
|
2232
|
+
if self._log and self._log.isEnabledFor(logging.DEBUG):
|
|
2233
|
+
self._log.exception('command failed')
|
|
2234
|
+
return e
|
|
2229
2235
|
|
|
2230
2236
|
|
|
2231
2237
|
##
|
|
2232
2238
|
|
|
2233
2239
|
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
if proc.stdin:
|
|
2244
|
-
proc.stdin.close()
|
|
2240
|
+
class Subprocesses(AbstractSubprocesses):
|
|
2241
|
+
def check_call(
|
|
2242
|
+
self,
|
|
2243
|
+
*cmd: str,
|
|
2244
|
+
stdout: ta.Any = sys.stderr,
|
|
2245
|
+
**kwargs: ta.Any,
|
|
2246
|
+
) -> None:
|
|
2247
|
+
with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs): # noqa
|
|
2248
|
+
subprocess.check_call(cmd, **kwargs)
|
|
2245
2249
|
|
|
2246
|
-
|
|
2250
|
+
def check_output(
|
|
2251
|
+
self,
|
|
2252
|
+
*cmd: str,
|
|
2253
|
+
**kwargs: ta.Any,
|
|
2254
|
+
) -> bytes:
|
|
2255
|
+
with self.prepare_and_wrap(*cmd, **kwargs) as (cmd, kwargs): # noqa
|
|
2256
|
+
return subprocess.check_output(cmd, **kwargs)
|
|
2247
2257
|
|
|
2258
|
+
def check_output_str(
|
|
2259
|
+
self,
|
|
2260
|
+
*cmd: str,
|
|
2261
|
+
**kwargs: ta.Any,
|
|
2262
|
+
) -> str:
|
|
2263
|
+
return self.check_output(*cmd, **kwargs).decode().strip()
|
|
2248
2264
|
|
|
2249
|
-
|
|
2250
|
-
# ../../../omlish/lite/asyncio/subprocesses.py
|
|
2265
|
+
#
|
|
2251
2266
|
|
|
2267
|
+
def try_call(
|
|
2268
|
+
self,
|
|
2269
|
+
*cmd: str,
|
|
2270
|
+
**kwargs: ta.Any,
|
|
2271
|
+
) -> bool:
|
|
2272
|
+
if isinstance(self.try_fn(self.check_call, *cmd, **kwargs), Exception):
|
|
2273
|
+
return False
|
|
2274
|
+
else:
|
|
2275
|
+
return True
|
|
2252
2276
|
|
|
2253
|
-
|
|
2277
|
+
def try_output(
|
|
2278
|
+
self,
|
|
2279
|
+
*cmd: str,
|
|
2280
|
+
**kwargs: ta.Any,
|
|
2281
|
+
) -> ta.Optional[bytes]:
|
|
2282
|
+
if isinstance(ret := self.try_fn(self.check_output, *cmd, **kwargs), Exception):
|
|
2283
|
+
return None
|
|
2284
|
+
else:
|
|
2285
|
+
return ret
|
|
2254
2286
|
|
|
2287
|
+
def try_output_str(
|
|
2288
|
+
self,
|
|
2289
|
+
*cmd: str,
|
|
2290
|
+
**kwargs: ta.Any,
|
|
2291
|
+
) -> ta.Optional[str]:
|
|
2292
|
+
if (ret := self.try_output(*cmd, **kwargs)) is None:
|
|
2293
|
+
return None
|
|
2294
|
+
else:
|
|
2295
|
+
return ret.decode().strip()
|
|
2255
2296
|
|
|
2256
|
-
@contextlib.asynccontextmanager
|
|
2257
|
-
async def asyncio_subprocess_popen(
|
|
2258
|
-
*cmd: str,
|
|
2259
|
-
shell: bool = False,
|
|
2260
|
-
timeout: ta.Optional[float] = None,
|
|
2261
|
-
**kwargs: ta.Any,
|
|
2262
|
-
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
|
2263
|
-
fac: ta.Any
|
|
2264
|
-
if shell:
|
|
2265
|
-
fac = functools.partial(
|
|
2266
|
-
asyncio.create_subprocess_shell,
|
|
2267
|
-
check.single(cmd),
|
|
2268
|
-
)
|
|
2269
|
-
else:
|
|
2270
|
-
fac = functools.partial(
|
|
2271
|
-
asyncio.create_subprocess_exec,
|
|
2272
|
-
*cmd,
|
|
2273
|
-
)
|
|
2274
2297
|
|
|
2275
|
-
|
|
2276
|
-
*cmd,
|
|
2277
|
-
shell=shell,
|
|
2278
|
-
timeout=timeout,
|
|
2279
|
-
**kwargs,
|
|
2280
|
-
):
|
|
2281
|
-
proc: asyncio.subprocess.Process
|
|
2282
|
-
proc = await fac(**kwargs)
|
|
2283
|
-
try:
|
|
2284
|
-
yield proc
|
|
2298
|
+
subprocesses = Subprocesses()
|
|
2285
2299
|
|
|
2286
|
-
|
|
2287
|
-
|
|
2300
|
+
|
|
2301
|
+
########################################
|
|
2302
|
+
# ../../../omlish/lite/asyncio/subprocesses.py
|
|
2288
2303
|
|
|
2289
2304
|
|
|
2290
2305
|
##
|
|
@@ -2400,137 +2415,147 @@ class AsyncioProcessCommunicator:
|
|
|
2400
2415
|
return await asyncio_maybe_timeout(self._communicate(input), timeout)
|
|
2401
2416
|
|
|
2402
2417
|
|
|
2403
|
-
|
|
2404
|
-
proc: asyncio.subprocess.Process,
|
|
2405
|
-
input: ta.Any = None, # noqa
|
|
2406
|
-
timeout: ta.Optional[float] = None,
|
|
2407
|
-
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
|
2408
|
-
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
|
2418
|
+
##
|
|
2409
2419
|
|
|
2410
2420
|
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
if capture_output:
|
|
2420
|
-
kwargs.setdefault('stdout', subprocess.PIPE)
|
|
2421
|
-
kwargs.setdefault('stderr', subprocess.PIPE)
|
|
2422
|
-
|
|
2423
|
-
args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
|
|
2424
|
-
|
|
2425
|
-
proc: asyncio.subprocess.Process
|
|
2426
|
-
async with asyncio_subprocess_popen(*args, **kwargs) as proc:
|
|
2427
|
-
stdout, stderr = await asyncio_subprocess_communicate(proc, input, timeout)
|
|
2428
|
-
|
|
2429
|
-
if check and proc.returncode:
|
|
2430
|
-
raise subprocess.CalledProcessError(
|
|
2431
|
-
proc.returncode,
|
|
2432
|
-
args,
|
|
2433
|
-
output=stdout,
|
|
2434
|
-
stderr=stderr,
|
|
2435
|
-
)
|
|
2421
|
+
class AsyncioSubprocesses(AbstractSubprocesses):
|
|
2422
|
+
async def communicate(
|
|
2423
|
+
self,
|
|
2424
|
+
proc: asyncio.subprocess.Process,
|
|
2425
|
+
input: ta.Any = None, # noqa
|
|
2426
|
+
timeout: ta.Optional[float] = None,
|
|
2427
|
+
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
|
2428
|
+
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
|
2436
2429
|
|
|
2437
|
-
|
|
2430
|
+
#
|
|
2438
2431
|
|
|
2432
|
+
@contextlib.asynccontextmanager
|
|
2433
|
+
async def popen(
|
|
2434
|
+
self,
|
|
2435
|
+
*cmd: str,
|
|
2436
|
+
shell: bool = False,
|
|
2437
|
+
timeout: ta.Optional[float] = None,
|
|
2438
|
+
**kwargs: ta.Any,
|
|
2439
|
+
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
|
2440
|
+
fac: ta.Any
|
|
2441
|
+
if shell:
|
|
2442
|
+
fac = functools.partial(
|
|
2443
|
+
asyncio.create_subprocess_shell,
|
|
2444
|
+
check.single(cmd),
|
|
2445
|
+
)
|
|
2446
|
+
else:
|
|
2447
|
+
fac = functools.partial(
|
|
2448
|
+
asyncio.create_subprocess_exec,
|
|
2449
|
+
*cmd,
|
|
2450
|
+
)
|
|
2439
2451
|
|
|
2440
|
-
|
|
2452
|
+
with self.prepare_and_wrap( *cmd, shell=shell, **kwargs) as (cmd, kwargs): # noqa
|
|
2453
|
+
proc: asyncio.subprocess.Process = await fac(**kwargs)
|
|
2454
|
+
try:
|
|
2455
|
+
yield proc
|
|
2441
2456
|
|
|
2457
|
+
finally:
|
|
2458
|
+
await asyncio_maybe_timeout(proc.wait(), timeout)
|
|
2442
2459
|
|
|
2443
|
-
|
|
2444
|
-
*args: str,
|
|
2445
|
-
stdout: ta.Any = sys.stderr,
|
|
2446
|
-
input: ta.Any = None, # noqa
|
|
2447
|
-
timeout: ta.Optional[float] = None,
|
|
2448
|
-
**kwargs: ta.Any,
|
|
2449
|
-
) -> None:
|
|
2450
|
-
_, _ = await asyncio_subprocess_run(
|
|
2451
|
-
*args,
|
|
2452
|
-
stdout=stdout,
|
|
2453
|
-
input=input,
|
|
2454
|
-
timeout=timeout,
|
|
2455
|
-
check=True,
|
|
2456
|
-
**kwargs,
|
|
2457
|
-
)
|
|
2460
|
+
#
|
|
2458
2461
|
|
|
2462
|
+
@dc.dataclass(frozen=True)
|
|
2463
|
+
class RunOutput:
|
|
2464
|
+
proc: asyncio.subprocess.Process
|
|
2465
|
+
stdout: ta.Optional[bytes]
|
|
2466
|
+
stderr: ta.Optional[bytes]
|
|
2459
2467
|
|
|
2460
|
-
async def
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
**kwargs,
|
|
2473
|
-
)
|
|
2468
|
+
async def run(
|
|
2469
|
+
self,
|
|
2470
|
+
*cmd: str,
|
|
2471
|
+
input: ta.Any = None, # noqa
|
|
2472
|
+
timeout: ta.Optional[float] = None,
|
|
2473
|
+
check: bool = False, # noqa
|
|
2474
|
+
capture_output: ta.Optional[bool] = None,
|
|
2475
|
+
**kwargs: ta.Any,
|
|
2476
|
+
) -> RunOutput:
|
|
2477
|
+
if capture_output:
|
|
2478
|
+
kwargs.setdefault('stdout', subprocess.PIPE)
|
|
2479
|
+
kwargs.setdefault('stderr', subprocess.PIPE)
|
|
2474
2480
|
|
|
2475
|
-
|
|
2481
|
+
proc: asyncio.subprocess.Process
|
|
2482
|
+
async with self.popen(*cmd, **kwargs) as proc:
|
|
2483
|
+
stdout, stderr = await self.communicate(proc, input, timeout)
|
|
2484
|
+
|
|
2485
|
+
if check and proc.returncode:
|
|
2486
|
+
raise subprocess.CalledProcessError(
|
|
2487
|
+
proc.returncode,
|
|
2488
|
+
cmd,
|
|
2489
|
+
output=stdout,
|
|
2490
|
+
stderr=stderr,
|
|
2491
|
+
)
|
|
2476
2492
|
|
|
2493
|
+
return self.RunOutput(
|
|
2494
|
+
proc,
|
|
2495
|
+
stdout,
|
|
2496
|
+
stderr,
|
|
2497
|
+
)
|
|
2477
2498
|
|
|
2478
|
-
|
|
2479
|
-
return (await asyncio_subprocess_check_output(*args, **kwargs)).decode().strip()
|
|
2499
|
+
#
|
|
2480
2500
|
|
|
2501
|
+
async def check_call(
|
|
2502
|
+
self,
|
|
2503
|
+
*cmd: str,
|
|
2504
|
+
stdout: ta.Any = sys.stderr,
|
|
2505
|
+
**kwargs: ta.Any,
|
|
2506
|
+
) -> None:
|
|
2507
|
+
with self.prepare_and_wrap(*cmd, stdout=stdout, check=True, **kwargs) as (cmd, kwargs): # noqa
|
|
2508
|
+
await self.run(*cmd, **kwargs)
|
|
2481
2509
|
|
|
2482
|
-
|
|
2510
|
+
async def check_output(
|
|
2511
|
+
self,
|
|
2512
|
+
*cmd: str,
|
|
2513
|
+
**kwargs: ta.Any,
|
|
2514
|
+
) -> bytes:
|
|
2515
|
+
with self.prepare_and_wrap(*cmd, stdout=subprocess.PIPE, check=True, **kwargs) as (cmd, kwargs): # noqa
|
|
2516
|
+
return check.not_none((await self.run(*cmd, **kwargs)).stdout)
|
|
2483
2517
|
|
|
2518
|
+
async def check_output_str(
|
|
2519
|
+
self,
|
|
2520
|
+
*cmd: str,
|
|
2521
|
+
**kwargs: ta.Any,
|
|
2522
|
+
) -> str:
|
|
2523
|
+
return (await self.check_output(*cmd, **kwargs)).decode().strip()
|
|
2484
2524
|
|
|
2485
|
-
|
|
2486
|
-
fn: ta.Callable[..., ta.Awaitable[T]],
|
|
2487
|
-
*args: ta.Any,
|
|
2488
|
-
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
2489
|
-
**kwargs: ta.Any,
|
|
2490
|
-
) -> ta.Union[T, Exception]:
|
|
2491
|
-
try:
|
|
2492
|
-
return await fn(*args, **kwargs)
|
|
2493
|
-
except try_exceptions as e: # noqa
|
|
2494
|
-
if log.isEnabledFor(logging.DEBUG):
|
|
2495
|
-
log.exception('command failed')
|
|
2496
|
-
return e
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
async def asyncio_subprocess_try_call(
|
|
2500
|
-
*args: str,
|
|
2501
|
-
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
2502
|
-
**kwargs: ta.Any,
|
|
2503
|
-
) -> bool:
|
|
2504
|
-
if isinstance(await _asyncio_subprocess_try_run(
|
|
2505
|
-
asyncio_subprocess_check_call,
|
|
2506
|
-
*args,
|
|
2507
|
-
try_exceptions=try_exceptions,
|
|
2508
|
-
**kwargs,
|
|
2509
|
-
), Exception):
|
|
2510
|
-
return False
|
|
2511
|
-
else:
|
|
2512
|
-
return True
|
|
2525
|
+
#
|
|
2513
2526
|
|
|
2527
|
+
async def try_call(
|
|
2528
|
+
self,
|
|
2529
|
+
*cmd: str,
|
|
2530
|
+
**kwargs: ta.Any,
|
|
2531
|
+
) -> bool:
|
|
2532
|
+
if isinstance(await self.async_try_fn(self.check_call, *cmd, **kwargs), Exception):
|
|
2533
|
+
return False
|
|
2534
|
+
else:
|
|
2535
|
+
return True
|
|
2514
2536
|
|
|
2515
|
-
async def
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
) -> ta.Optional[bytes]:
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2537
|
+
async def try_output(
|
|
2538
|
+
self,
|
|
2539
|
+
*cmd: str,
|
|
2540
|
+
**kwargs: ta.Any,
|
|
2541
|
+
) -> ta.Optional[bytes]:
|
|
2542
|
+
if isinstance(ret := await self.async_try_fn(self.check_output, *cmd, **kwargs), Exception):
|
|
2543
|
+
return None
|
|
2544
|
+
else:
|
|
2545
|
+
return ret
|
|
2546
|
+
|
|
2547
|
+
async def try_output_str(
|
|
2548
|
+
self,
|
|
2549
|
+
*cmd: str,
|
|
2550
|
+
**kwargs: ta.Any,
|
|
2551
|
+
) -> ta.Optional[str]:
|
|
2552
|
+
if (ret := await self.try_output(*cmd, **kwargs)) is None:
|
|
2553
|
+
return None
|
|
2554
|
+
else:
|
|
2555
|
+
return ret.decode().strip()
|
|
2529
2556
|
|
|
2530
2557
|
|
|
2531
|
-
|
|
2532
|
-
out = await asyncio_subprocess_try_output(*args, **kwargs)
|
|
2533
|
-
return out.decode().strip() if out is not None else None
|
|
2558
|
+
asyncio_subprocesses = AsyncioSubprocesses()
|
|
2534
2559
|
|
|
2535
2560
|
|
|
2536
2561
|
########################################
|
|
@@ -2607,7 +2632,7 @@ class InterpInspector:
|
|
|
2607
2632
|
return cls._build_inspection(sys.executable, eval(cls._INSPECTION_CODE)) # noqa
|
|
2608
2633
|
|
|
2609
2634
|
async def _inspect(self, exe: str) -> InterpInspection:
|
|
2610
|
-
output = await
|
|
2635
|
+
output = await asyncio_subprocesses.check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
|
|
2611
2636
|
return self._build_inspection(exe, output.decode())
|
|
2612
2637
|
|
|
2613
2638
|
async def inspect(self, exe: str) -> ta.Optional[InterpInspection]:
|
|
@@ -2726,7 +2751,7 @@ class Pyenv:
|
|
|
2726
2751
|
return self._root_kw
|
|
2727
2752
|
|
|
2728
2753
|
if shutil.which('pyenv'):
|
|
2729
|
-
return await
|
|
2754
|
+
return await asyncio_subprocesses.check_output_str('pyenv', 'root')
|
|
2730
2755
|
|
|
2731
2756
|
d = os.path.expanduser('~/.pyenv')
|
|
2732
2757
|
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
|
@@ -2755,7 +2780,7 @@ class Pyenv:
|
|
|
2755
2780
|
if await self.root() is None:
|
|
2756
2781
|
return []
|
|
2757
2782
|
ret = []
|
|
2758
|
-
s = await
|
|
2783
|
+
s = await asyncio_subprocesses.check_output_str(await self.exe(), 'install', '--list')
|
|
2759
2784
|
for l in s.splitlines():
|
|
2760
2785
|
if not l.startswith(' '):
|
|
2761
2786
|
continue
|
|
@@ -2770,7 +2795,7 @@ class Pyenv:
|
|
|
2770
2795
|
return False
|
|
2771
2796
|
if not os.path.isdir(os.path.join(root, '.git')):
|
|
2772
2797
|
return False
|
|
2773
|
-
await
|
|
2798
|
+
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
|
2774
2799
|
return True
|
|
2775
2800
|
|
|
2776
2801
|
|
|
@@ -2861,7 +2886,7 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
2861
2886
|
cflags = []
|
|
2862
2887
|
ldflags = []
|
|
2863
2888
|
for dep in self.BREW_DEPS:
|
|
2864
|
-
dep_prefix = await
|
|
2889
|
+
dep_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', dep)
|
|
2865
2890
|
cflags.append(f'-I{dep_prefix}/include')
|
|
2866
2891
|
ldflags.append(f'-L{dep_prefix}/lib')
|
|
2867
2892
|
return PyenvInstallOpts(
|
|
@@ -2871,11 +2896,11 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
2871
2896
|
|
|
2872
2897
|
@async_cached_nullary
|
|
2873
2898
|
async def brew_tcl_opts(self) -> PyenvInstallOpts:
|
|
2874
|
-
if await
|
|
2899
|
+
if await asyncio_subprocesses.try_output('brew', '--prefix', 'tcl-tk') is None:
|
|
2875
2900
|
return PyenvInstallOpts()
|
|
2876
2901
|
|
|
2877
|
-
tcl_tk_prefix = await
|
|
2878
|
-
tcl_tk_ver_str = await
|
|
2902
|
+
tcl_tk_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', 'tcl-tk')
|
|
2903
|
+
tcl_tk_ver_str = await asyncio_subprocesses.check_output_str('brew', 'ls', '--versions', 'tcl-tk')
|
|
2879
2904
|
tcl_tk_ver = '.'.join(tcl_tk_ver_str.split()[1].split('.')[:2])
|
|
2880
2905
|
|
|
2881
2906
|
return PyenvInstallOpts(conf_opts=[
|
|
@@ -2996,7 +3021,7 @@ class PyenvVersionInstaller:
|
|
|
2996
3021
|
*conf_args,
|
|
2997
3022
|
]
|
|
2998
3023
|
|
|
2999
|
-
await
|
|
3024
|
+
await asyncio_subprocesses.check_call(
|
|
3000
3025
|
*full_args,
|
|
3001
3026
|
env=env,
|
|
3002
3027
|
)
|