omdev 0.0.0.dev155__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/interp/inspect.py +2 -2
- omdev/interp/pyenv.py +9 -11
- omdev/pyproject/cli.py +3 -3
- omdev/pyproject/pkg.py +4 -4
- omdev/pyproject/venvs.py +4 -4
- omdev/scripts/interp.py +306 -290
- omdev/scripts/pyproject.py +312 -296
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/RECORD +13 -13
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev155.dist-info → omdev-0.0.0.dev156.dist-info}/top_level.txt +0 -0
omdev/scripts/interp.py
CHANGED
|
@@ -2080,209 +2080,226 @@ SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
|
|
2080
2080
|
_SUBPROCESS_SHELL_WRAP_EXECS = False
|
|
2081
2081
|
|
|
2082
2082
|
|
|
2083
|
-
def subprocess_shell_wrap_exec(*
|
|
2084
|
-
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)))
|
|
2085
2085
|
|
|
2086
2086
|
|
|
2087
|
-
def subprocess_maybe_shell_wrap_exec(*
|
|
2087
|
+
def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
|
2088
2088
|
if _SUBPROCESS_SHELL_WRAP_EXECS or is_debugger_attached():
|
|
2089
|
-
return subprocess_shell_wrap_exec(*
|
|
2089
|
+
return subprocess_shell_wrap_exec(*cmd)
|
|
2090
2090
|
else:
|
|
2091
|
-
return
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
def prepare_subprocess_invocation(
|
|
2095
|
-
*args: str,
|
|
2096
|
-
env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
2097
|
-
extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
|
2098
|
-
quiet: bool = False,
|
|
2099
|
-
shell: bool = False,
|
|
2100
|
-
**kwargs: ta.Any,
|
|
2101
|
-
) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
|
|
2102
|
-
log.debug('prepare_subprocess_invocation: args=%r', args)
|
|
2103
|
-
if extra_env:
|
|
2104
|
-
log.debug('prepare_subprocess_invocation: extra_env=%r', extra_env)
|
|
2105
|
-
|
|
2106
|
-
if extra_env:
|
|
2107
|
-
env = {**(env if env is not None else os.environ), **extra_env}
|
|
2108
|
-
|
|
2109
|
-
if quiet and 'stderr' not in kwargs:
|
|
2110
|
-
if not log.isEnabledFor(logging.DEBUG):
|
|
2111
|
-
kwargs['stderr'] = subprocess.DEVNULL
|
|
2112
|
-
|
|
2113
|
-
if not shell:
|
|
2114
|
-
args = subprocess_maybe_shell_wrap_exec(*args)
|
|
2115
|
-
|
|
2116
|
-
return args, dict(
|
|
2117
|
-
env=env,
|
|
2118
|
-
shell=shell,
|
|
2119
|
-
**kwargs,
|
|
2120
|
-
)
|
|
2091
|
+
return cmd
|
|
2121
2092
|
|
|
2122
2093
|
|
|
2123
2094
|
##
|
|
2124
2095
|
|
|
2125
2096
|
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
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()
|
|
2136
2108
|
|
|
2137
|
-
|
|
2138
|
-
end_time = time.time()
|
|
2139
|
-
elapsed_s = end_time - start_time
|
|
2140
|
-
log.debug('subprocess_common_context.finally: elapsed_s=%f args=%r', elapsed_s, args)
|
|
2109
|
+
proc.wait(timeout)
|
|
2141
2110
|
|
|
2142
2111
|
|
|
2143
2112
|
##
|
|
2144
2113
|
|
|
2145
2114
|
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
stdout: ta.Any = sys.stderr,
|
|
2149
|
-
**kwargs: ta.Any,
|
|
2150
|
-
) -> None:
|
|
2151
|
-
args, kwargs = prepare_subprocess_invocation(*args, stdout=stdout, **kwargs)
|
|
2152
|
-
with subprocess_common_context(*args, **kwargs):
|
|
2153
|
-
return subprocess.check_call(args, **kwargs) # type: ignore
|
|
2115
|
+
class AbstractSubprocesses(abc.ABC): # noqa
|
|
2116
|
+
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = log
|
|
2154
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__()
|
|
2155
2125
|
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
**kwargs: ta.Any,
|
|
2159
|
-
) -> bytes:
|
|
2160
|
-
args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
|
|
2161
|
-
with subprocess_common_context(*args, **kwargs):
|
|
2162
|
-
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
|
|
2163
2128
|
|
|
2129
|
+
#
|
|
2164
2130
|
|
|
2165
|
-
def
|
|
2166
|
-
|
|
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
|
+
)
|
|
2167
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
|
|
2168
2168
|
|
|
2169
|
-
|
|
2169
|
+
except Exception as exc: # noqa
|
|
2170
|
+
if self._log:
|
|
2171
|
+
self._log.debug('Subprocesses.wrap_call.except: exc=%r', exc)
|
|
2172
|
+
raise
|
|
2170
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)
|
|
2171
2179
|
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
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
|
|
2176
2192
|
|
|
2193
|
+
#
|
|
2177
2194
|
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
**kwargs: ta.Any,
|
|
2183
|
-
) -> ta.Union[T, Exception]:
|
|
2184
|
-
try:
|
|
2185
|
-
return fn(*args, **kwargs)
|
|
2186
|
-
except try_exceptions as e: # noqa
|
|
2187
|
-
if log.isEnabledFor(logging.DEBUG):
|
|
2188
|
-
log.exception('command failed')
|
|
2189
|
-
return e
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
def subprocess_try_call(
|
|
2193
|
-
*args: str,
|
|
2194
|
-
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
2195
|
-
**kwargs: ta.Any,
|
|
2196
|
-
) -> bool:
|
|
2197
|
-
if isinstance(_subprocess_try_run(
|
|
2198
|
-
subprocess_check_call,
|
|
2199
|
-
*args,
|
|
2200
|
-
try_exceptions=try_exceptions,
|
|
2201
|
-
**kwargs,
|
|
2202
|
-
), Exception):
|
|
2203
|
-
return False
|
|
2204
|
-
else:
|
|
2205
|
-
return True
|
|
2195
|
+
DEFAULT_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
|
|
2196
|
+
FileNotFoundError,
|
|
2197
|
+
subprocess.CalledProcessError,
|
|
2198
|
+
)
|
|
2206
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
|
|
2207
2209
|
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
*args,
|
|
2216
|
-
try_exceptions=try_exceptions,
|
|
2217
|
-
**kwargs,
|
|
2218
|
-
), Exception):
|
|
2219
|
-
return None
|
|
2220
|
-
else:
|
|
2221
|
-
return ret
|
|
2210
|
+
try:
|
|
2211
|
+
return fn(*cmd, **kwargs)
|
|
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
|
|
2222
2217
|
|
|
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)
|
|
2223
2230
|
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
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
|
|
2227
2235
|
|
|
2228
2236
|
|
|
2229
2237
|
##
|
|
2230
2238
|
|
|
2231
2239
|
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
if proc.stdin:
|
|
2242
|
-
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)
|
|
2243
2249
|
|
|
2244
|
-
|
|
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)
|
|
2245
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()
|
|
2246
2264
|
|
|
2247
|
-
|
|
2248
|
-
# ../../../omlish/lite/asyncio/subprocesses.py
|
|
2265
|
+
#
|
|
2249
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
|
|
2250
2276
|
|
|
2251
|
-
|
|
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
|
|
2252
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()
|
|
2253
2296
|
|
|
2254
|
-
@contextlib.asynccontextmanager
|
|
2255
|
-
async def asyncio_subprocess_popen(
|
|
2256
|
-
*cmd: str,
|
|
2257
|
-
shell: bool = False,
|
|
2258
|
-
timeout: ta.Optional[float] = None,
|
|
2259
|
-
**kwargs: ta.Any,
|
|
2260
|
-
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
|
2261
|
-
fac: ta.Any
|
|
2262
|
-
if shell:
|
|
2263
|
-
fac = functools.partial(
|
|
2264
|
-
asyncio.create_subprocess_shell,
|
|
2265
|
-
check.single(cmd),
|
|
2266
|
-
)
|
|
2267
|
-
else:
|
|
2268
|
-
fac = functools.partial(
|
|
2269
|
-
asyncio.create_subprocess_exec,
|
|
2270
|
-
*cmd,
|
|
2271
|
-
)
|
|
2272
2297
|
|
|
2273
|
-
|
|
2274
|
-
*cmd,
|
|
2275
|
-
shell=shell,
|
|
2276
|
-
timeout=timeout,
|
|
2277
|
-
**kwargs,
|
|
2278
|
-
):
|
|
2279
|
-
proc: asyncio.subprocess.Process
|
|
2280
|
-
proc = await fac(**kwargs)
|
|
2281
|
-
try:
|
|
2282
|
-
yield proc
|
|
2298
|
+
subprocesses = Subprocesses()
|
|
2283
2299
|
|
|
2284
|
-
|
|
2285
|
-
|
|
2300
|
+
|
|
2301
|
+
########################################
|
|
2302
|
+
# ../../../omlish/lite/asyncio/subprocesses.py
|
|
2286
2303
|
|
|
2287
2304
|
|
|
2288
2305
|
##
|
|
@@ -2398,148 +2415,147 @@ class AsyncioProcessCommunicator:
|
|
|
2398
2415
|
return await asyncio_maybe_timeout(self._communicate(input), timeout)
|
|
2399
2416
|
|
|
2400
2417
|
|
|
2401
|
-
|
|
2402
|
-
proc: asyncio.subprocess.Process,
|
|
2403
|
-
input: ta.Any = None, # noqa
|
|
2404
|
-
timeout: ta.Optional[float] = None,
|
|
2405
|
-
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
|
2406
|
-
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
|
2407
|
-
|
|
2418
|
+
##
|
|
2408
2419
|
|
|
2409
|
-
@dc.dataclass(frozen=True)
|
|
2410
|
-
class AsyncioSubprocessOutput:
|
|
2411
|
-
proc: asyncio.subprocess.Process
|
|
2412
|
-
stdout: ta.Optional[bytes]
|
|
2413
|
-
stderr: ta.Optional[bytes]
|
|
2414
2420
|
|
|
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
|
|
2415
2429
|
|
|
2416
|
-
|
|
2417
|
-
*args: str,
|
|
2418
|
-
input: ta.Any = None, # noqa
|
|
2419
|
-
timeout: ta.Optional[float] = None,
|
|
2420
|
-
check: bool = False, # noqa
|
|
2421
|
-
capture_output: ta.Optional[bool] = None,
|
|
2422
|
-
**kwargs: ta.Any,
|
|
2423
|
-
) -> AsyncioSubprocessOutput:
|
|
2424
|
-
if capture_output:
|
|
2425
|
-
kwargs.setdefault('stdout', subprocess.PIPE)
|
|
2426
|
-
kwargs.setdefault('stderr', subprocess.PIPE)
|
|
2427
|
-
|
|
2428
|
-
args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
|
|
2429
|
-
|
|
2430
|
-
proc: asyncio.subprocess.Process
|
|
2431
|
-
async with asyncio_subprocess_popen(*args, **kwargs) as proc:
|
|
2432
|
-
stdout, stderr = await asyncio_subprocess_communicate(proc, input, timeout)
|
|
2433
|
-
|
|
2434
|
-
if check and proc.returncode:
|
|
2435
|
-
raise subprocess.CalledProcessError(
|
|
2436
|
-
proc.returncode,
|
|
2437
|
-
args,
|
|
2438
|
-
output=stdout,
|
|
2439
|
-
stderr=stderr,
|
|
2440
|
-
)
|
|
2430
|
+
#
|
|
2441
2431
|
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
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
|
+
)
|
|
2447
2451
|
|
|
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
|
|
2448
2456
|
|
|
2449
|
-
|
|
2457
|
+
finally:
|
|
2458
|
+
await asyncio_maybe_timeout(proc.wait(), timeout)
|
|
2450
2459
|
|
|
2460
|
+
#
|
|
2451
2461
|
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
**kwargs: ta.Any,
|
|
2458
|
-
) -> None:
|
|
2459
|
-
await asyncio_subprocess_run(
|
|
2460
|
-
*args,
|
|
2461
|
-
stdout=stdout,
|
|
2462
|
-
input=input,
|
|
2463
|
-
timeout=timeout,
|
|
2464
|
-
check=True,
|
|
2465
|
-
**kwargs,
|
|
2466
|
-
)
|
|
2462
|
+
@dc.dataclass(frozen=True)
|
|
2463
|
+
class RunOutput:
|
|
2464
|
+
proc: asyncio.subprocess.Process
|
|
2465
|
+
stdout: ta.Optional[bytes]
|
|
2466
|
+
stderr: ta.Optional[bytes]
|
|
2467
2467
|
|
|
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)
|
|
2468
2480
|
|
|
2469
|
-
|
|
2470
|
-
*
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
check=True,
|
|
2481
|
-
**kwargs,
|
|
2482
|
-
)
|
|
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
|
+
)
|
|
2483
2492
|
|
|
2484
|
-
|
|
2493
|
+
return self.RunOutput(
|
|
2494
|
+
proc,
|
|
2495
|
+
stdout,
|
|
2496
|
+
stderr,
|
|
2497
|
+
)
|
|
2485
2498
|
|
|
2499
|
+
#
|
|
2486
2500
|
|
|
2487
|
-
async def
|
|
2488
|
-
|
|
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)
|
|
2489
2509
|
|
|
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)
|
|
2490
2517
|
|
|
2491
|
-
|
|
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()
|
|
2492
2524
|
|
|
2525
|
+
#
|
|
2493
2526
|
|
|
2494
|
-
async def
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
if log.isEnabledFor(logging.DEBUG):
|
|
2504
|
-
log.exception('command failed')
|
|
2505
|
-
return e
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
async def asyncio_subprocess_try_call(
|
|
2509
|
-
*args: str,
|
|
2510
|
-
try_exceptions: ta.Tuple[ta.Type[Exception], ...] = DEFAULT_SUBPROCESS_TRY_EXCEPTIONS,
|
|
2511
|
-
**kwargs: ta.Any,
|
|
2512
|
-
) -> bool:
|
|
2513
|
-
if isinstance(await _asyncio_subprocess_try_run(
|
|
2514
|
-
asyncio_subprocess_check_call,
|
|
2515
|
-
*args,
|
|
2516
|
-
try_exceptions=try_exceptions,
|
|
2517
|
-
**kwargs,
|
|
2518
|
-
), Exception):
|
|
2519
|
-
return False
|
|
2520
|
-
else:
|
|
2521
|
-
return True
|
|
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
|
|
2522
2536
|
|
|
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
|
|
2523
2546
|
|
|
2524
|
-
async def
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
) -> ta.Optional[
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
**kwargs,
|
|
2534
|
-
), Exception):
|
|
2535
|
-
return None
|
|
2536
|
-
else:
|
|
2537
|
-
return ret
|
|
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()
|
|
2538
2556
|
|
|
2539
2557
|
|
|
2540
|
-
|
|
2541
|
-
out = await asyncio_subprocess_try_output(*args, **kwargs)
|
|
2542
|
-
return out.decode().strip() if out is not None else None
|
|
2558
|
+
asyncio_subprocesses = AsyncioSubprocesses()
|
|
2543
2559
|
|
|
2544
2560
|
|
|
2545
2561
|
########################################
|
|
@@ -2616,7 +2632,7 @@ class InterpInspector:
|
|
|
2616
2632
|
return cls._build_inspection(sys.executable, eval(cls._INSPECTION_CODE)) # noqa
|
|
2617
2633
|
|
|
2618
2634
|
async def _inspect(self, exe: str) -> InterpInspection:
|
|
2619
|
-
output = await
|
|
2635
|
+
output = await asyncio_subprocesses.check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
|
|
2620
2636
|
return self._build_inspection(exe, output.decode())
|
|
2621
2637
|
|
|
2622
2638
|
async def inspect(self, exe: str) -> ta.Optional[InterpInspection]:
|
|
@@ -2735,7 +2751,7 @@ class Pyenv:
|
|
|
2735
2751
|
return self._root_kw
|
|
2736
2752
|
|
|
2737
2753
|
if shutil.which('pyenv'):
|
|
2738
|
-
return await
|
|
2754
|
+
return await asyncio_subprocesses.check_output_str('pyenv', 'root')
|
|
2739
2755
|
|
|
2740
2756
|
d = os.path.expanduser('~/.pyenv')
|
|
2741
2757
|
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
|
@@ -2764,7 +2780,7 @@ class Pyenv:
|
|
|
2764
2780
|
if await self.root() is None:
|
|
2765
2781
|
return []
|
|
2766
2782
|
ret = []
|
|
2767
|
-
s = await
|
|
2783
|
+
s = await asyncio_subprocesses.check_output_str(await self.exe(), 'install', '--list')
|
|
2768
2784
|
for l in s.splitlines():
|
|
2769
2785
|
if not l.startswith(' '):
|
|
2770
2786
|
continue
|
|
@@ -2779,7 +2795,7 @@ class Pyenv:
|
|
|
2779
2795
|
return False
|
|
2780
2796
|
if not os.path.isdir(os.path.join(root, '.git')):
|
|
2781
2797
|
return False
|
|
2782
|
-
await
|
|
2798
|
+
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
|
2783
2799
|
return True
|
|
2784
2800
|
|
|
2785
2801
|
|
|
@@ -2870,7 +2886,7 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
2870
2886
|
cflags = []
|
|
2871
2887
|
ldflags = []
|
|
2872
2888
|
for dep in self.BREW_DEPS:
|
|
2873
|
-
dep_prefix = await
|
|
2889
|
+
dep_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', dep)
|
|
2874
2890
|
cflags.append(f'-I{dep_prefix}/include')
|
|
2875
2891
|
ldflags.append(f'-L{dep_prefix}/lib')
|
|
2876
2892
|
return PyenvInstallOpts(
|
|
@@ -2880,11 +2896,11 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
2880
2896
|
|
|
2881
2897
|
@async_cached_nullary
|
|
2882
2898
|
async def brew_tcl_opts(self) -> PyenvInstallOpts:
|
|
2883
|
-
if await
|
|
2899
|
+
if await asyncio_subprocesses.try_output('brew', '--prefix', 'tcl-tk') is None:
|
|
2884
2900
|
return PyenvInstallOpts()
|
|
2885
2901
|
|
|
2886
|
-
tcl_tk_prefix = await
|
|
2887
|
-
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')
|
|
2888
2904
|
tcl_tk_ver = '.'.join(tcl_tk_ver_str.split()[1].split('.')[:2])
|
|
2889
2905
|
|
|
2890
2906
|
return PyenvInstallOpts(conf_opts=[
|
|
@@ -3005,7 +3021,7 @@ class PyenvVersionInstaller:
|
|
|
3005
3021
|
*conf_args,
|
|
3006
3022
|
]
|
|
3007
3023
|
|
|
3008
|
-
await
|
|
3024
|
+
await asyncio_subprocesses.check_call(
|
|
3009
3025
|
*full_args,
|
|
3010
3026
|
env=env,
|
|
3011
3027
|
)
|